11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 29b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * lm78.c - Part of lm_sensors, Linux kernel modules for hardware 39b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * monitoring 49b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Copyright (c) 1998, 1999 Frodo Looijaard <frodol@dds.nl> 59b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Copyright (c) 2007, 2011 Jean Delvare <khali@linux-fr.org> 69b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * 79b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * This program is free software; you can redistribute it and/or modify 89b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * it under the terms of the GNU General Public License as published by 99b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * the Free Software Foundation; either version 2 of the License, or 109b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * (at your option) any later version. 119b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * 129b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * This program is distributed in the hope that it will be useful, 139b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * but WITHOUT ANY WARRANTY; without even the implied warranty of 149b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 159b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * GNU General Public License for more details. 169b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * 179b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * You should have received a copy of the GNU General Public License 189b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * along with this program; if not, write to the Free Software 199b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 209b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/jiffies.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/i2c.h> 29943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/hwmon.h> 3019f673eddb5a406be72989fb57b7f286772b8cf4Jean Delvare#include <linux/hwmon-vid.h> 31247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare#include <linux/hwmon-sysfs.h> 32943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman#include <linux/err.h> 339a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar#include <linux/mutex.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#ifdef CONFIG_ISA 3690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#include <linux/platform_device.h> 3790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#include <linux/ioport.h> 3890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#include <linux/io.h> 3990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#endif 40c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Addresses to scan */ 4225e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffmanstatic const unsigned short normal_i2c[] = { 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 4325e9c86d5a6d82ea45eb680fc66bf73ac5e50dffMark M. Hoffman 0x2e, 0x2f, I2C_CLIENT_END }; 44e5e9f44c246fbafe723e579e9fe887677beb40e4Jean Delvareenum chips { lm78, lm79 }; 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Many LM78 constants specified below */ 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Length of ISA address segment */ 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_EXTENT 8 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Where are the ISA address/data registers relative to the base address */ 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_ADDR_REG_OFFSET 5 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_DATA_REG_OFFSET 6 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The LM78 registers */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_IN_MAX(nr) (0x2b + (nr) * 2) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_IN_MIN(nr) (0x2c + (nr) * 2) 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_IN(nr) (0x20 + (nr)) 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_FAN_MIN(nr) (0x3b + (nr)) 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_FAN(nr) (0x28 + (nr)) 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_TEMP 0x27 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_TEMP_OVER 0x39 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_TEMP_HYST 0x3a 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_ALARM1 0x41 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_ALARM2 0x42 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_VID_FANDIV 0x47 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_CONFIG 0x40 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_CHIPID 0x49 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define LM78_REG_I2C_ADDR 0x48 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 779b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 789b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Conversions. Rounding and limit checking is only done on the TO_REG 799b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * variants. 809b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 829b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 839b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * IN: mV (0V to 4.08V) 849b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * REG: 16mV/bit 859b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 IN_TO_REG(unsigned long val) 871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long nval = SENSORS_LIMIT(val, 0, 4080); 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (nval + 8) / 16; 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IN_FROM_REG(val) ((val) * 16) 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline u8 FAN_TO_REG(long rpm, int div) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (rpm <= 0) 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 255; 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return SENSORS_LIMIT((1350000 + rpm * div / 2) / (rpm * div), 1, 254); 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int FAN_FROM_REG(u8 val, int div) 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1029b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return val == 0 ? -1 : val == 255 ? 0 : 1350000 / (val * div); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1059b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 1069b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * TEMP: mC (-128C to +127C) 1079b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * REG: 1C/bit, two's complement 1089b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline s8 TEMP_TO_REG(int val) 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nval = SENSORS_LIMIT(val, -128000, 127000) ; 1129b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return nval < 0 ? (nval - 500) / 1000 : (nval + 500) / 1000; 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline int TEMP_FROM_REG(s8 val) 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return val * 1000; 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DIV_FROM_REG(val) (1 << (val)) 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct lm78_data { 1230c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct i2c_client *client; 1241beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones struct device *hwmon_dev; 1259a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar struct mutex lock; 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds enum chips type; 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1286e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare /* For ISA device only */ 1296e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare const char *name; 1306e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare int isa_addr; 1316e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare 1329a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar struct mutex update_lock; 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char valid; /* !=0 if following fields are valid */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long last_updated; /* In jiffies */ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in[7]; /* Register value */ 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_max[7]; /* Register value */ 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 in_min[7]; /* Register value */ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan[3]; /* Register value */ 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_min[3]; /* Register value */ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp; /* Register value */ 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp_over; /* Register value */ 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s8 temp_hyst; /* Register value */ 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 fan_div[3]; /* Register encoding, shifted right */ 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 vid; /* Register encoding, combined */ 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u16 alarms; /* Register encoding, combined */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 150c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic int lm78_read_value(struct lm78_data *data, u8 reg); 151c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic int lm78_write_value(struct lm78_data *data, u8 reg, u8 value); 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct lm78_data *lm78_update_device(struct device *dev); 153c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic void lm78_init_device(struct lm78_data *data); 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 7 Voltages */ 157247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_in(struct device *dev, struct device_attribute *da, 158247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 160247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 162247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare return sprintf(buf, "%d\n", IN_FROM_REG(data->in[attr->index])); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 165247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_in_min(struct device *dev, struct device_attribute *da, 166247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 168247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 170247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[attr->index])); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 173247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_in_max(struct device *dev, struct device_attribute *da, 174247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 176247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 178247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[attr->index])); 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 181247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_in_min(struct device *dev, struct device_attribute *da, 182247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 184247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 185c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 186247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 1879b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck unsigned long val; 1889b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 1899b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 1909b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtoul(buf, 10, &val); 1919b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 1929b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1949a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[nr] = IN_TO_REG(val); 196c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_IN_MIN(nr), data->in_min[nr]); 1979a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 201247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_in_max(struct device *dev, struct device_attribute *da, 202247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 204247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 205c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 206247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 2079b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck unsigned long val; 2089b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 2099b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 2109b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtoul(buf, 10, &val); 2119b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 2129b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2149a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[nr] = IN_TO_REG(val); 216c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_IN_MAX(nr), data->in_max[nr]); 2179a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2209b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define show_in_offset(offset) \ 222247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_input, S_IRUGO, \ 223247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_in, NULL, offset); \ 224247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_min, S_IRUGO | S_IWUSR, \ 225247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_in_min, set_in_min, offset); \ 226247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(in##offset##_max, S_IRUGO | S_IWUSR, \ 227247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_in_max, set_in_max, offset); 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(0); 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(1); 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(2); 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(3); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(4); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(5); 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_in_offset(6); 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Temperature */ 238247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_temp(struct device *dev, struct device_attribute *da, 239247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp)); 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 245247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_temp_over(struct device *dev, struct device_attribute *da, 246247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_over)); 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 252247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_temp_over(struct device *dev, struct device_attribute *da, 253247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 255c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 2569b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck long val; 2579b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 2589b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 2599b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtol(buf, 10, &val); 2609b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 2619b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2639a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_over = TEMP_TO_REG(val); 265c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_TEMP_OVER, data->temp_over); 2669a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 270247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_temp_hyst(struct device *dev, struct device_attribute *da, 271247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_hyst)); 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 277247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_temp_hyst(struct device *dev, struct device_attribute *da, 278247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 280c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 2819b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck long val; 2829b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 2839b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 2849b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtol(buf, 10, &val); 2859b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 2869b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2889a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_hyst = TEMP_TO_REG(val); 290c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_TEMP_HYST, data->temp_hyst); 2919a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL); 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_max, S_IRUGO | S_IWUSR, 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_temp_over, set_temp_over); 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(temp1_max_hyst, S_IRUGO | S_IWUSR, 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds show_temp_hyst, set_temp_hyst); 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3 Fans */ 302247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_fan(struct device *dev, struct device_attribute *da, 303247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 305247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 307247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[nr], 3099b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck DIV_FROM_REG(data->fan_div[nr]))); 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 312247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_fan_min(struct device *dev, struct device_attribute *da, 313247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 315247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 317247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 3189b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan_min[nr], 3199b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck DIV_FROM_REG(data->fan_div[nr]))); 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 322247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_fan_min(struct device *dev, struct device_attribute *da, 323247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 325247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 326c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 327247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 3289b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck unsigned long val; 3299b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 3309b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 3319b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtoul(buf, 10, &val); 3329b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 3339b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3359a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr])); 337c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); 3389a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 342247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_fan_div(struct device *dev, struct device_attribute *da, 343247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 345247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 347247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare return sprintf(buf, "%d\n", DIV_FROM_REG(data->fan_div[attr->index])); 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3509b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 3519b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Note: we save and restore the fan minimum here, because its value is 3529b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * determined in part by the fan divisor. This follows the principle of 3539b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * least surprise; the user doesn't expect the fan minimum to change just 3549b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * because the divisor changed. 3559b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 356247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t set_fan_div(struct device *dev, struct device_attribute *da, 357247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare const char *buf, size_t count) 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 359247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare struct sensor_device_attribute *attr = to_sensor_dev_attr(da); 360c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 361247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare int nr = attr->index; 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned long min; 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u8 reg; 3649b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck unsigned long val; 3659b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck int err; 3669b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck 3679b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = kstrtoul(buf, 10, &val); 3689b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 3699b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck return err; 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3719a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds min = FAN_FROM_REG(data->fan_min[nr], 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds DIV_FROM_REG(data->fan_div[nr])); 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (val) { 3769b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck case 1: 3779b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck data->fan_div[nr] = 0; 3789b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck break; 3799b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck case 2: 3809b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck data->fan_div[nr] = 1; 3819b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck break; 3829b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck case 4: 3839b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck data->fan_div[nr] = 2; 3849b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck break; 3859b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck case 8: 3869b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck data->fan_div[nr] = 3; 3879b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck break; 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 389c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare dev_err(dev, "fan_div value %ld not " 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "supported. Choose one of 1, 2, 4 or 8!\n", val); 3919a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EINVAL; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 395c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare reg = lm78_read_value(data, LM78_REG_VID_FANDIV); 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (nr) { 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 0: 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = (reg & 0xcf) | (data->fan_div[nr] << 4); 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds reg = (reg & 0x3f) | (data->fan_div[nr] << 6); 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 404c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_VID_FANDIV, reg); 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[nr] = 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FAN_TO_REG(min, DIV_FROM_REG(data->fan_div[nr])); 408c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_FAN_MIN(nr), data->fan_min[nr]); 4099a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return count; 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 414247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare#define show_fan_offset(offset) \ 415247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_input, S_IRUGO, \ 416247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_fan, NULL, offset - 1); \ 417247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(fan##offset##_min, S_IRUGO | S_IWUSR, \ 418247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_fan_min, set_fan_min, offset - 1); 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_offset(1); 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_offset(2); 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsshow_fan_offset(3); 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Fan 3 divisor is locked in H/W */ 425247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(fan1_div, S_IRUGO | S_IWUSR, 426247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_fan_div, set_fan_div, 0); 427247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(fan2_div, S_IRUGO | S_IWUSR, 428247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare show_fan_div, set_fan_div, 1); 429247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic SENSOR_DEVICE_ATTR(fan3_div, S_IRUGO, show_fan_div, NULL, 2); 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* VID */ 432247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_vid(struct device *dev, struct device_attribute *da, 433247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 436d0d3cd6965d8e957764663cbb5aaa5ff486a2616Jean Delvare return sprintf(buf, "%d\n", vid_from_reg(data->vid, 82)); 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(cpu0_vid, S_IRUGO, show_vid, NULL); 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Alarms */ 441247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvarestatic ssize_t show_alarms(struct device *dev, struct device_attribute *da, 442247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare char *buf) 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct lm78_data *data = lm78_update_device(dev); 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sprintf(buf, "%u\n", data->alarms); 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL); 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 449428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic ssize_t show_alarm(struct device *dev, struct device_attribute *da, 450428a7039c5717695935b946af9413e59f68928a4Jean Delvare char *buf) 451428a7039c5717695935b946af9413e59f68928a4Jean Delvare{ 452428a7039c5717695935b946af9413e59f68928a4Jean Delvare struct lm78_data *data = lm78_update_device(dev); 453428a7039c5717695935b946af9413e59f68928a4Jean Delvare int nr = to_sensor_dev_attr(da)->index; 454428a7039c5717695935b946af9413e59f68928a4Jean Delvare return sprintf(buf, "%u\n", (data->alarms >> nr) & 1); 455428a7039c5717695935b946af9413e59f68928a4Jean Delvare} 456428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in0_alarm, S_IRUGO, show_alarm, NULL, 0); 457428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in1_alarm, S_IRUGO, show_alarm, NULL, 1); 458428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in2_alarm, S_IRUGO, show_alarm, NULL, 2); 459428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in3_alarm, S_IRUGO, show_alarm, NULL, 3); 460428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in4_alarm, S_IRUGO, show_alarm, NULL, 8); 461428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in5_alarm, S_IRUGO, show_alarm, NULL, 9); 462428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(in6_alarm, S_IRUGO, show_alarm, NULL, 10); 463428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(fan1_alarm, S_IRUGO, show_alarm, NULL, 6); 464428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(fan2_alarm, S_IRUGO, show_alarm, NULL, 7); 465428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(fan3_alarm, S_IRUGO, show_alarm, NULL, 11); 466428a7039c5717695935b946af9413e59f68928a4Jean Delvarestatic SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 4); 467428a7039c5717695935b946af9413e59f68928a4Jean Delvare 468c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic struct attribute *lm78_attributes[] = { 469247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in0_input.dev_attr.attr, 470247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in0_min.dev_attr.attr, 471247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in0_max.dev_attr.attr, 472428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in0_alarm.dev_attr.attr, 473247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in1_input.dev_attr.attr, 474247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in1_min.dev_attr.attr, 475247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in1_max.dev_attr.attr, 476428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in1_alarm.dev_attr.attr, 477247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in2_input.dev_attr.attr, 478247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in2_min.dev_attr.attr, 479247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in2_max.dev_attr.attr, 480428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in2_alarm.dev_attr.attr, 481247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in3_input.dev_attr.attr, 482247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in3_min.dev_attr.attr, 483247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in3_max.dev_attr.attr, 484428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in3_alarm.dev_attr.attr, 485247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in4_input.dev_attr.attr, 486247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in4_min.dev_attr.attr, 487247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in4_max.dev_attr.attr, 488428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in4_alarm.dev_attr.attr, 489247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in5_input.dev_attr.attr, 490247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in5_min.dev_attr.attr, 491247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in5_max.dev_attr.attr, 492428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in5_alarm.dev_attr.attr, 493247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in6_input.dev_attr.attr, 494247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in6_min.dev_attr.attr, 495247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_in6_max.dev_attr.attr, 496428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_in6_alarm.dev_attr.attr, 497c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman &dev_attr_temp1_input.attr, 498c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman &dev_attr_temp1_max.attr, 499c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman &dev_attr_temp1_max_hyst.attr, 500428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_temp1_alarm.dev_attr.attr, 501247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan1_input.dev_attr.attr, 502247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan1_min.dev_attr.attr, 503247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan1_div.dev_attr.attr, 504428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_fan1_alarm.dev_attr.attr, 505247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan2_input.dev_attr.attr, 506247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan2_min.dev_attr.attr, 507247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan2_div.dev_attr.attr, 508428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_fan2_alarm.dev_attr.attr, 509247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan3_input.dev_attr.attr, 510247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan3_min.dev_attr.attr, 511247dde4cdded4e4c332622b7c2860254e61cf5ceJean Delvare &sensor_dev_attr_fan3_div.dev_attr.attr, 512428a7039c5717695935b946af9413e59f68928a4Jean Delvare &sensor_dev_attr_fan3_alarm.dev_attr.attr, 513c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman &dev_attr_alarms.attr, 514c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman &dev_attr_cpu0_vid.attr, 515c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman 516c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman NULL 517c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman}; 518c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman 519c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffmanstatic const struct attribute_group lm78_group = { 520c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman .attrs = lm78_attributes, 521c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman}; 522c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman 52390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare/* 52490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare * ISA related code 52590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare */ 52690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#ifdef CONFIG_ISA 52790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 52890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare/* ISA device, if found */ 52990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic struct platform_device *pdev; 53090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 53190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic unsigned short isa_address = 0x290; 53290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 5339b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 5349b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * I2C devices get this name attribute automatically, but for ISA devices 5359b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * we must create it by ourselves. 5369b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 537c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvarestatic ssize_t show_name(struct device *dev, struct device_attribute 538c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare *devattr, char *buf) 539c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare{ 540c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 541c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 5426e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare return sprintf(buf, "%s\n", data->name); 543c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare} 544c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvarestatic DEVICE_ATTR(name, S_IRUGO, show_name, NULL); 545c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 54690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic struct lm78_data *lm78_data_if_isa(void) 54790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 54890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return pdev ? platform_get_drvdata(pdev) : NULL; 54990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 55090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 55118c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare/* Returns 1 if the I2C chip appears to be an alias of the ISA chip */ 55218c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvarestatic int lm78_alias_detect(struct i2c_client *client, u8 chipid) 55318c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare{ 5540c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct lm78_data *isa; 55518c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare int i; 55618c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare 55718c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare if (!pdev) /* No ISA chip */ 55818c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; 55918c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare isa = platform_get_drvdata(pdev); 56018c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare 56118c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare if (lm78_read_value(isa, LM78_REG_I2C_ADDR) != client->addr) 56218c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; /* Address doesn't match */ 56318c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare if ((lm78_read_value(isa, LM78_REG_CHIPID) & 0xfe) != (chipid & 0xfe)) 56418c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; /* Chip type doesn't match */ 56518c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare 5669b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 5679b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We compare all the limit registers, the config register and the 5689b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * interrupt mask registers 5699b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 57018c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare for (i = 0x2b; i <= 0x3d; i++) { 5710c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (lm78_read_value(isa, i) != 5720c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare i2c_smbus_read_byte_data(client, i)) 57318c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; 57418c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare } 57518c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare if (lm78_read_value(isa, LM78_REG_CONFIG) != 5760c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare i2c_smbus_read_byte_data(client, LM78_REG_CONFIG)) 57718c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; 57818c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare for (i = 0x43; i <= 0x46; i++) { 5790c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (lm78_read_value(isa, i) != 5800c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare i2c_smbus_read_byte_data(client, i)) 58118c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 0; 58218c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare } 58318c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare 58418c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare return 1; 58518c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare} 58690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#else /* !CONFIG_ISA */ 58790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 58890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic int lm78_alias_detect(struct i2c_client *client, u8 chipid) 58990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 59090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return 0; 59190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 59290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 59390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic struct lm78_data *lm78_data_if_isa(void) 59490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 59590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return NULL; 59690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 59790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#endif /* CONFIG_ISA */ 59818c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare 599310ec79210d754afe51e2e4a983e846b60179abdJean Delvarestatic int lm78_i2c_detect(struct i2c_client *client, 6000c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct i2c_board_info *info) 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6020c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare int i; 60390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare struct lm78_data *isa = lm78_data_if_isa(); 6040c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare const char *client_name; 6050c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct i2c_adapter *adapter = client->adapter; 6060c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare int address = client->addr; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6080c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 6090c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare return -ENODEV; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6119b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 6129b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We block updates of the ISA device to minimize the risk of 6139b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * concurrent access to the same LM78 chip through different 6149b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * interfaces. 6159b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 6160c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (isa) 6170c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare mutex_lock(&isa->update_lock); 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if ((i2c_smbus_read_byte_data(client, LM78_REG_CONFIG) & 0x80) 62052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare || i2c_smbus_read_byte_data(client, LM78_REG_I2C_ADDR) != address) 62152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare goto err_nodev; 62252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare 62352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare /* Explicitly prevent the misdetection of Winbond chips */ 62452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare i = i2c_smbus_read_byte_data(client, 0x4f); 62552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (i == 0xa3 || i == 0x5c) 62652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare goto err_nodev; 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Determine the chip type. */ 62952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare i = i2c_smbus_read_byte_data(client, LM78_REG_CHIPID); 63052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (i == 0x00 || i == 0x20 /* LM78 */ 63152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare || i == 0x40) /* LM78-J */ 63252df6440a29123eed912183fe785bbe174ef14b9Jean Delvare client_name = "lm78"; 63352df6440a29123eed912183fe785bbe174ef14b9Jean Delvare else if ((i & 0xfe) == 0xc0) 63452df6440a29123eed912183fe785bbe174ef14b9Jean Delvare client_name = "lm79"; 63552df6440a29123eed912183fe785bbe174ef14b9Jean Delvare else 63652df6440a29123eed912183fe785bbe174ef14b9Jean Delvare goto err_nodev; 63752df6440a29123eed912183fe785bbe174ef14b9Jean Delvare 63852df6440a29123eed912183fe785bbe174ef14b9Jean Delvare if (lm78_alias_detect(client, i)) { 63952df6440a29123eed912183fe785bbe174ef14b9Jean Delvare dev_dbg(&adapter->dev, "Device at 0x%02x appears to " 64052df6440a29123eed912183fe785bbe174ef14b9Jean Delvare "be the same as ISA device\n", address); 64152df6440a29123eed912183fe785bbe174ef14b9Jean Delvare goto err_nodev; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6440c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (isa) 6450c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare mutex_unlock(&isa->update_lock); 6460c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare 6470c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare strlcpy(info->type, client_name, I2C_NAME_SIZE); 6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6490c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare return 0; 6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6510c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare err_nodev: 6520c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (isa) 6530c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare mutex_unlock(&isa->update_lock); 6540c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare return -ENODEV; 6550c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare} 6560c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare 6570c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvarestatic int lm78_i2c_probe(struct i2c_client *client, 6580c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare const struct i2c_device_id *id) 6590c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare{ 6600c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct lm78_data *data; 6610c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare int err; 6620c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare 6630c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL); 6640c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (!data) 6650c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare return -ENOMEM; 6660c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare 6670c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare i2c_set_clientdata(client, data); 6680c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare data->client = client; 6690c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare data->type = id->driver_data; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the LM78 chip */ 672c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_init_device(data); 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Register sysfs hooks */ 6750c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare err = sysfs_create_group(&client->dev.kobj, &lm78_group); 6760c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (err) 677c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman goto ERROR3; 678c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman 6790c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare data->hwmon_dev = hwmon_device_register(&client->dev); 6801beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones if (IS_ERR(data->hwmon_dev)) { 6811beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones err = PTR_ERR(data->hwmon_dev); 682c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman goto ERROR4; 683943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman } 684943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 687c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. HoffmanERROR4: 6880c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare sysfs_remove_group(&client->dev.kobj, &lm78_group); 689943b0830cebe4711354945ed3cb44e84152aaca0Mark M. HoffmanERROR3: 6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(data); 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6940c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvarestatic int lm78_i2c_remove(struct i2c_client *client) 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 696943b0830cebe4711354945ed3cb44e84152aaca0Mark M. Hoffman struct lm78_data *data = i2c_get_clientdata(client); 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6981beeffe43311f64df8dd0ab08ff6b1858c58363fTony Jones hwmon_device_unregister(data->hwmon_dev); 699c1685f61b0a3110b701d09b84a9f9a3d4e9ef2e2Mark M. Hoffman sysfs_remove_group(&client->dev.kobj, &lm78_group); 700c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare kfree(data); 701c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 702c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare return 0; 703c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare} 704c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 705ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvarestatic const struct i2c_device_id lm78_i2c_id[] = { 706ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare { "lm78", lm78 }, 707ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare { "lm79", lm79 }, 708ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare { } 709ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare}; 710ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean DelvareMODULE_DEVICE_TABLE(i2c, lm78_i2c_id); 7116e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare 712ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvarestatic struct i2c_driver lm78_driver = { 713ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .class = I2C_CLASS_HWMON, 714ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .driver = { 715ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .name = "lm78", 716ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare }, 717ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .probe = lm78_i2c_probe, 718ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .remove = lm78_i2c_remove, 719ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .id_table = lm78_i2c_id, 720ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .detect = lm78_i2c_detect, 721ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .address_list = normal_i2c, 722ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare}; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7249b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck/* 7259b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * The SMBus locks itself, but ISA access must be locked explicitly! 7269b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We don't want to lock the whole ISA bus, so we lock each client 7279b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * separately. 7289b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We ignore the LM78 BUSY flag at this moment - it could lead to deadlocks, 7299b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * would slow down the LM78 access and should not be necessary. 7309b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 731c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic int lm78_read_value(struct lm78_data *data, u8 reg) 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7330c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct i2c_client *client = data->client; 734c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare 73590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#ifdef CONFIG_ISA 7360c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (!client) { /* ISA device */ 737c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare int res; 7389a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->lock); 7396e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); 7406e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare res = inb_p(data->isa_addr + LM78_DATA_REG_OFFSET); 7419a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->lock); 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return res; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 74490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#endif 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i2c_smbus_read_byte_data(client, reg); 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 748c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic int lm78_write_value(struct lm78_data *data, u8 reg, u8 value) 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 7500c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare struct i2c_client *client = data->client; 751c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare 75290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#ifdef CONFIG_ISA 7530c6e97317102a8f480bdfb418f19fe989ad1c047Jean Delvare if (!client) { /* ISA device */ 7549a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->lock); 7556e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare outb_p(reg, data->isa_addr + LM78_ADDR_REG_OFFSET); 7566e1b5029dc0e4cfa765309312ebdc88711e37a20Jean Delvare outb_p(value, data->isa_addr + LM78_DATA_REG_OFFSET); 7579a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->lock); 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 76090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#endif 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i2c_smbus_write_byte_data(client, reg, value); 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 764c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvarestatic void lm78_init_device(struct lm78_data *data) 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 766c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare u8 config; 767c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare int i; 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Start monitoring */ 770c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare config = lm78_read_value(data, LM78_REG_CONFIG); 771c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if ((config & 0x09) != 0x01) 772c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_write_value(data, LM78_REG_CONFIG, 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (config & 0xf7) | 0x01); 774c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 775c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* A few vars need to be filled upon startup */ 776c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare for (i = 0; i < 3; i++) { 777c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare data->fan_min[i] = lm78_read_value(data, 778c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare LM78_REG_FAN_MIN(i)); 779c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 780c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 781c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare mutex_init(&data->update_lock); 7821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct lm78_data *lm78_update_device(struct device *dev) 7851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 786c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct lm78_data *data = dev_get_drvdata(dev); 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7899a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_lock(&data->update_lock); 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (time_after(jiffies, data->last_updated + HZ + HZ / 2) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds || !data->valid) { 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 794c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare dev_dbg(dev, "Starting lm78 update\n"); 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i <= 6; i++) { 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in[i] = 798c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_IN(i)); 7991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_min[i] = 800c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_IN_MIN(i)); 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->in_max[i] = 802c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_IN_MAX(i)); 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < 3; i++) { 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan[i] = 806c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_FAN(i)); 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_min[i] = 808c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_FAN_MIN(i)); 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 810c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare data->temp = lm78_read_value(data, LM78_REG_TEMP); 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_over = 812c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_TEMP_OVER); 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->temp_hyst = 814c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare lm78_read_value(data, LM78_REG_TEMP_HYST); 815c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare i = lm78_read_value(data, LM78_REG_VID_FANDIV); 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid = i & 0x0f; 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data->type == lm79) 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid |= 819c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare (lm78_read_value(data, LM78_REG_CHIPID) & 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 0x01) << 4; 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->vid |= 0x10; 8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[0] = (i >> 4) & 0x03; 8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[1] = i >> 6; 825c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare data->alarms = lm78_read_value(data, LM78_REG_ALARM1) + 826c59cc301ee4589b096d2364af7cf91a2e46b5b1dJean Delvare (lm78_read_value(data, LM78_REG_ALARM2) << 8); 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->last_updated = jiffies; 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->valid = 1; 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data->fan_div[2] = 1; 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8339a61bf6300533d3b64d7ff29adfec00e596de67dIngo Molnar mutex_unlock(&data->update_lock); 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return data; 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 83890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#ifdef CONFIG_ISA 839ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvarestatic int __devinit lm78_isa_probe(struct platform_device *pdev) 840ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare{ 841ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare int err; 842ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare struct lm78_data *data; 843ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare struct resource *res; 844ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 845ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare /* Reserve the ISA region */ 846ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, 0); 847ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare if (!request_region(res->start + LM78_ADDR_REG_OFFSET, 2, "lm78")) { 848ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare err = -EBUSY; 849ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare goto exit; 850ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare } 851ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 852ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data = kzalloc(sizeof(struct lm78_data), GFP_KERNEL); 853ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare if (!data) { 854ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare err = -ENOMEM; 855ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare goto exit_release_region; 856ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare } 857ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare mutex_init(&data->lock); 858ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->isa_addr = res->start; 859ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare platform_set_drvdata(pdev, data); 860ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 861ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare if (lm78_read_value(data, LM78_REG_CHIPID) & 0x80) { 862ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->type = lm79; 863ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->name = "lm79"; 864ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare } else { 865ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->type = lm78; 866ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->name = "lm78"; 867ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare } 868ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 869ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare /* Initialize the LM78 chip */ 870ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare lm78_init_device(data); 871ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 872ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare /* Register sysfs hooks */ 8739b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = sysfs_create_group(&pdev->dev.kobj, &lm78_group); 8749b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 8759b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck goto exit_remove_files; 8769b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck err = device_create_file(&pdev->dev, &dev_attr_name); 8779b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck if (err) 878ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare goto exit_remove_files; 879ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 880ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare data->hwmon_dev = hwmon_device_register(&pdev->dev); 881ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare if (IS_ERR(data->hwmon_dev)) { 882ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare err = PTR_ERR(data->hwmon_dev); 883ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare goto exit_remove_files; 884ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare } 885ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 886ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare return 0; 887ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 888ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare exit_remove_files: 889ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare sysfs_remove_group(&pdev->dev.kobj, &lm78_group); 890ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare device_remove_file(&pdev->dev, &dev_attr_name); 891ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare kfree(data); 892ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare exit_release_region: 893ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare release_region(res->start + LM78_ADDR_REG_OFFSET, 2); 894ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare exit: 895ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare return err; 896ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare} 897ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 898ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvarestatic int __devexit lm78_isa_remove(struct platform_device *pdev) 899ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare{ 900ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare struct lm78_data *data = platform_get_drvdata(pdev); 901ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare struct resource *res; 902ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 903ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare hwmon_device_unregister(data->hwmon_dev); 904ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare sysfs_remove_group(&pdev->dev.kobj, &lm78_group); 905ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare device_remove_file(&pdev->dev, &dev_attr_name); 906ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare kfree(data); 907ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 908ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare res = platform_get_resource(pdev, IORESOURCE_IO, 0); 909ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare release_region(res->start + LM78_ADDR_REG_OFFSET, 2); 910ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 911ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare return 0; 912ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare} 913ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 914ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvarestatic struct platform_driver lm78_isa_driver = { 915ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .driver = { 916ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .owner = THIS_MODULE, 917ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .name = "lm78", 918ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare }, 919ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .probe = lm78_isa_probe, 920ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare .remove = __devexit_p(lm78_isa_remove), 921ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare}; 922ed4cebdf9cfbf5f97f388ae7f2ac2b24fc362a39Jean Delvare 923c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare/* return 1 if a supported chip is found, 0 otherwise */ 924c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvarestatic int __init lm78_isa_found(unsigned short address) 925c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare{ 926c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare int val, save, found = 0; 927197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare int port; 928197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare 9299b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 9309b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * Some boards declare base+0 to base+7 as a PNP device, some base+4 931197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare * to base+7 and some base+5 to base+6. So we better request each port 9329b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * individually for the probing phase. 9339b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 934197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare for (port = address; port < address + LM78_EXTENT; port++) { 935197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare if (!request_region(port, 1, "lm78")) { 936ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches pr_debug("Failed to request port 0x%x\n", port); 937197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare goto release; 938197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare } 93947c15532ddcd6818f51cb15f914d63864b3ee9abJean Delvare } 940c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 941c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare#define REALLY_SLOW_IO 9429b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 9439b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We need the timeouts for at least some LM78-like 9449b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * chips. But only if we read 'undefined' registers. 9459b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 946c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + 1); 947c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (inb_p(address + 2) != val 948c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare || inb_p(address + 3) != val 949c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare || inb_p(address + 7) != val) 950c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 951c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare#undef REALLY_SLOW_IO 952c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 9539b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 9549b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We should be able to change the 7 LSB of the address port. The 9559b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * MSB (busy flag) should be clear initially, set after the write. 9569b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 957c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare save = inb_p(address + LM78_ADDR_REG_OFFSET); 958c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (save & 0x80) 959c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 960c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = ~save & 0x7f; 961c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(val, address + LM78_ADDR_REG_OFFSET); 962c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (inb_p(address + LM78_ADDR_REG_OFFSET) != (val | 0x80)) { 963c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(save, address + LM78_ADDR_REG_OFFSET); 964c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 965c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 966c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 967c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* We found a device, now see if it could be an LM78 */ 968c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(LM78_REG_CONFIG, address + LM78_ADDR_REG_OFFSET); 969c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + LM78_DATA_REG_OFFSET); 970c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (val & 0x80) 971c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 972c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(LM78_REG_I2C_ADDR, address + LM78_ADDR_REG_OFFSET); 973c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + LM78_DATA_REG_OFFSET); 974c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (val < 0x03 || val > 0x77) /* Not a valid I2C address */ 975c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 976c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 977c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* The busy flag should be clear again */ 978c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (inb_p(address + LM78_ADDR_REG_OFFSET) & 0x80) 979c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 980c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 981c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* Explicitly prevent the misdetection of Winbond chips */ 982c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(0x4f, address + LM78_ADDR_REG_OFFSET); 983c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + LM78_DATA_REG_OFFSET); 984c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (val == 0xa3 || val == 0x5c) 985c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 986c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 987c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* Explicitly prevent the misdetection of ITE chips */ 988c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(0x58, address + LM78_ADDR_REG_OFFSET); 989c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + LM78_DATA_REG_OFFSET); 990c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (val == 0x90) 991c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto release; 992c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 993c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* Determine the chip type */ 994c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare outb_p(LM78_REG_CHIPID, address + LM78_ADDR_REG_OFFSET); 995c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val = inb_p(address + LM78_DATA_REG_OFFSET); 996acf346a311588e4cb659c183b9e312fa313dbb7fHans de Goede if (val == 0x00 || val == 0x20 /* LM78 */ 997c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare || val == 0x40 /* LM78-J */ 998c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare || (val & 0xfe) == 0xc0) /* LM79 */ 999c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare found = 1; 1000c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1001c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (found) 1002ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches pr_info("Found an %s chip at %#x\n", 1003c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare val & 0x80 ? "LM79" : "LM78", (int)address); 1004c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1005c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare release: 1006197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare for (port--; port >= address; port--) 1007197027e6ef830d60e10f76efc8d12bf3b6c35db5Jean Delvare release_region(port, 1); 1008c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare return found; 1009c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare} 1010c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1011c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvarestatic int __init lm78_isa_device_add(unsigned short address) 1012c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare{ 1013c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare struct resource res = { 1014c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare .start = address, 101515bde2f1a8e819213f54314505a5a0509673109bJean Delvare .end = address + LM78_EXTENT - 1, 1016c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare .name = "lm78", 1017c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare .flags = IORESOURCE_IO, 1018c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare }; 1019c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare int err; 1020c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1021c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare pdev = platform_device_alloc("lm78", address); 1022c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (!pdev) { 1023c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare err = -ENOMEM; 1024ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches pr_err("Device allocation failed\n"); 1025c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto exit; 1026c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 1027c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1028c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare err = platform_device_add_resources(pdev, &res, 1); 1029c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (err) { 1030ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches pr_err("Device resource addition failed (%d)\n", err); 1031c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto exit_device_put; 1032c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 1033c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1034c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare err = platform_device_add(pdev); 1035c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (err) { 1036ce47da742ddd950197c29df6f9f89cf8adb5a0a1Joe Perches pr_err("Device addition failed (%d)\n", err); 1037c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto exit_device_put; 1038c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 1039c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1040c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare return 0; 1041c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1042c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare exit_device_put: 1043c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare platform_device_put(pdev); 1044c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare exit: 1045c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare pdev = NULL; 1046c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare return err; 1047c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare} 1048c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 104990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic int __init lm78_isa_register(void) 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1051fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare int res; 1052fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare 1053c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (lm78_isa_found(isa_address)) { 1054c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare res = platform_driver_register(&lm78_isa_driver); 1055c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (res) 105618c73f90421f9a87a0f6bc3a08880d0f1f9b2a74Jean Delvare goto exit; 1057fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare 1058c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare /* Sets global pdev as a side effect */ 1059c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare res = lm78_isa_device_add(isa_address); 1060c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (res) 1061c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare goto exit_unreg_isa_driver; 1062c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 1063fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare 1064fde0950903ce8cc38a91dd095280decceda2ff82Jean Delvare return 0; 1065c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare 1066c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare exit_unreg_isa_driver: 1067c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare platform_driver_unregister(&lm78_isa_driver); 1068c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare exit: 1069c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare return res; 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 107290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic void lm78_isa_unregister(void) 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1074c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare if (pdev) { 1075c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare platform_device_unregister(pdev); 1076c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare platform_driver_unregister(&lm78_isa_driver); 1077c40769fee13c1ab43e1fb10320d6fbc29f582d8eJean Delvare } 107890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 107990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#else /* !CONFIG_ISA */ 108090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 108190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic int __init lm78_isa_register(void) 108290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 108390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return 0; 108490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 108590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 108690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic void lm78_isa_unregister(void) 108790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 108890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 108990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare#endif /* CONFIG_ISA */ 109090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 109190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic int __init sm_lm78_init(void) 109290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 109390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare int res; 109490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 10959b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck /* 10969b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * We register the ISA device first, so that we can skip the 10979b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck * registration of an I2C interface to the same device. 10989b03079fca96a5815f197f02e09b9ac20d67b71eGuenter Roeck */ 109990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare res = lm78_isa_register(); 110090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare if (res) 110190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare goto exit; 110290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 110390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare res = i2c_add_driver(&lm78_driver); 110490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare if (res) 110590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare goto exit_unreg_isa_device; 110690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 110790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return 0; 110890534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 110990534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare exit_unreg_isa_device: 111090534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare lm78_isa_unregister(); 111190534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare exit: 111290534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare return res; 111390534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare} 111490534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare 111590534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvarestatic void __exit sm_lm78_exit(void) 111690534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare{ 111790534c5c5e535d7bf78a4efdbd0999e04b57d6e3Jean Delvare lm78_isa_unregister(); 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i2c_del_driver(&lm78_driver); 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121156e2d1adc03e17f18f98d297f7757fc6d93a589Jean DelvareMODULE_AUTHOR("Frodo Looijaard, Jean Delvare <khali@linux-fr.org>"); 112227fe048eb3787d29bf9cf9d6d12077bb8af869a6Jean DelvareMODULE_DESCRIPTION("LM78/LM79 driver"); 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sm_lm78_init); 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sm_lm78_exit); 1127