1*6f9703d0SDarrick J. Wong /* 2*6f9703d0SDarrick J. Wong * A hwmon driver for the Analog Devices ADT7470 3*6f9703d0SDarrick J. Wong * Copyright (C) 2007 IBM 4*6f9703d0SDarrick J. Wong * 5*6f9703d0SDarrick J. Wong * Author: Darrick J. Wong <djwong@us.ibm.com> 6*6f9703d0SDarrick J. Wong * 7*6f9703d0SDarrick J. Wong * This program is free software; you can redistribute it and/or modify 8*6f9703d0SDarrick J. Wong * it under the terms of the GNU General Public License as published by 9*6f9703d0SDarrick J. Wong * the Free Software Foundation; either version 2 of the License, or 10*6f9703d0SDarrick J. Wong * (at your option) any later version. 11*6f9703d0SDarrick J. Wong * 12*6f9703d0SDarrick J. Wong * This program is distributed in the hope that it will be useful, 13*6f9703d0SDarrick J. Wong * but WITHOUT ANY WARRANTY; without even the implied warranty of 14*6f9703d0SDarrick J. Wong * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15*6f9703d0SDarrick J. Wong * GNU General Public License for more details. 16*6f9703d0SDarrick J. Wong * 17*6f9703d0SDarrick J. Wong * You should have received a copy of the GNU General Public License 18*6f9703d0SDarrick J. Wong * along with this program; if not, write to the Free Software 19*6f9703d0SDarrick J. Wong * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20*6f9703d0SDarrick J. Wong */ 21*6f9703d0SDarrick J. Wong 22*6f9703d0SDarrick J. Wong #include <linux/module.h> 23*6f9703d0SDarrick J. Wong #include <linux/jiffies.h> 24*6f9703d0SDarrick J. Wong #include <linux/i2c.h> 25*6f9703d0SDarrick J. Wong #include <linux/hwmon.h> 26*6f9703d0SDarrick J. Wong #include <linux/hwmon-sysfs.h> 27*6f9703d0SDarrick J. Wong #include <linux/err.h> 28*6f9703d0SDarrick J. Wong #include <linux/mutex.h> 29*6f9703d0SDarrick J. Wong #include <linux/delay.h> 30*6f9703d0SDarrick J. Wong #include <linux/log2.h> 31*6f9703d0SDarrick J. Wong 32*6f9703d0SDarrick J. Wong /* Addresses to scan */ 33*6f9703d0SDarrick J. Wong static unsigned short normal_i2c[] = { 0x2C, 0x2E, 0x2F, I2C_CLIENT_END }; 34*6f9703d0SDarrick J. Wong 35*6f9703d0SDarrick J. Wong /* Insmod parameters */ 36*6f9703d0SDarrick J. Wong I2C_CLIENT_INSMOD_1(adt7470); 37*6f9703d0SDarrick J. Wong 38*6f9703d0SDarrick J. Wong /* ADT7470 registers */ 39*6f9703d0SDarrick J. Wong #define ADT7470_REG_BASE_ADDR 0x20 40*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_BASE_ADDR 0x20 41*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_MAX_ADDR 0x29 42*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_BASE_ADDR 0x2A 43*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_ADDR 0x31 44*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_BASE_ADDR 0x32 45*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_ADDR 0x35 46*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_BASE_ADDR 0x38 47*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX_MAX_ADDR 0x3B 48*6f9703d0SDarrick J. Wong #define ADT7470_REG_CFG 0x40 49*6f9703d0SDarrick J. Wong #define ADT7470_FSPD_MASK 0x04 50*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM1 0x41 51*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM2 0x42 52*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_LIMITS_BASE_ADDR 0x44 53*6f9703d0SDarrick J. Wong #define ADT7470_REG_TEMP_LIMITS_MAX_ADDR 0x57 54*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN_BASE_ADDR 0x58 55*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN_MAX_ADDR 0x5F 56*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_BASE_ADDR 0x60 57*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX_MAX_ADDR 0x67 58*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_CFG_BASE_ADDR 0x68 59*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM12_CFG 0x68 60*6f9703d0SDarrick J. Wong #define ADT7470_PWM2_AUTO_MASK 0x40 61*6f9703d0SDarrick J. Wong #define ADT7470_PWM1_AUTO_MASK 0x80 62*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM34_CFG 0x69 63*6f9703d0SDarrick J. Wong #define ADT7470_PWM3_AUTO_MASK 0x40 64*6f9703d0SDarrick J. Wong #define ADT7470_PWM4_AUTO_MASK 0x80 65*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MIN_BASE_ADDR 0x6A 66*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MIN_MAX_ADDR 0x6D 67*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR 0x6E 68*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TEMP_MIN_MAX_ADDR 0x71 69*6f9703d0SDarrick J. Wong #define ADT7470_REG_ACOUSTICS12 0x75 70*6f9703d0SDarrick J. Wong #define ADT7470_REG_ACOUSTICS34 0x76 71*6f9703d0SDarrick J. Wong #define ADT7470_REG_DEVICE 0x3D 72*6f9703d0SDarrick J. Wong #define ADT7470_REG_VENDOR 0x3E 73*6f9703d0SDarrick J. Wong #define ADT7470_REG_REVISION 0x3F 74*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM1_MASK 0x72 75*6f9703d0SDarrick J. Wong #define ADT7470_REG_ALARM2_MASK 0x73 76*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR 0x7C 77*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP_MAX_ADDR 0x7D 78*6f9703d0SDarrick J. Wong #define ADT7470_REG_MAX_ADDR 0x81 79*6f9703d0SDarrick J. Wong 80*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_COUNT 10 81*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_REG(x) (ADT7470_REG_TEMP_BASE_ADDR + (x)) 82*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_MIN_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + ((x) * 2)) 83*6f9703d0SDarrick J. Wong #define ADT7470_TEMP_MAX_REG(x) (ADT7470_REG_TEMP_LIMITS_BASE_ADDR + \ 84*6f9703d0SDarrick J. Wong ((x) * 2) + 1) 85*6f9703d0SDarrick J. Wong 86*6f9703d0SDarrick J. Wong #define ADT7470_FAN_COUNT 4 87*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN(x) (ADT7470_REG_FAN_BASE_ADDR + ((x) * 2)) 88*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MIN(x) (ADT7470_REG_FAN_MIN_BASE_ADDR + ((x) * 2)) 89*6f9703d0SDarrick J. Wong #define ADT7470_REG_FAN_MAX(x) (ADT7470_REG_FAN_MAX_BASE_ADDR + ((x) * 2)) 90*6f9703d0SDarrick J. Wong 91*6f9703d0SDarrick J. Wong #define ADT7470_PWM_COUNT 4 92*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM(x) (ADT7470_REG_PWM_BASE_ADDR + (x)) 93*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MAX(x) (ADT7470_REG_PWM_MAX_BASE_ADDR + (x)) 94*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_MIN(x) (ADT7470_REG_PWM_MIN_BASE_ADDR + (x)) 95*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_TMIN(x) (ADT7470_REG_PWM_TEMP_MIN_BASE_ADDR + (x)) 96*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_CFG(x) (ADT7470_REG_PWM_CFG_BASE_ADDR + ((x) / 2)) 97*6f9703d0SDarrick J. Wong #define ADT7470_REG_PWM_AUTO_TEMP(x) (ADT7470_REG_PWM_AUTO_TEMP_BASE_ADDR + \ 98*6f9703d0SDarrick J. Wong ((x) / 2)) 99*6f9703d0SDarrick J. Wong 100*6f9703d0SDarrick J. Wong #define ADT7470_VENDOR 0x41 101*6f9703d0SDarrick J. Wong #define ADT7470_DEVICE 0x70 102*6f9703d0SDarrick J. Wong /* datasheet only mentions a revision 2 */ 103*6f9703d0SDarrick J. Wong #define ADT7470_REVISION 0x02 104*6f9703d0SDarrick J. Wong 105*6f9703d0SDarrick J. Wong /* "all temps" according to hwmon sysfs interface spec */ 106*6f9703d0SDarrick J. Wong #define ADT7470_PWM_ALL_TEMPS 0x3FF 107*6f9703d0SDarrick J. Wong 108*6f9703d0SDarrick J. Wong /* How often do we reread sensors values? (In jiffies) */ 109*6f9703d0SDarrick J. Wong #define SENSOR_REFRESH_INTERVAL (5 * HZ) 110*6f9703d0SDarrick J. Wong 111*6f9703d0SDarrick J. Wong /* How often do we reread sensor limit values? (In jiffies) */ 112*6f9703d0SDarrick J. Wong #define LIMIT_REFRESH_INTERVAL (60 * HZ) 113*6f9703d0SDarrick J. Wong 114*6f9703d0SDarrick J. Wong /* sleep 1s while gathering temperature data */ 115*6f9703d0SDarrick J. Wong #define TEMP_COLLECTION_TIME 1000 116*6f9703d0SDarrick J. Wong 117*6f9703d0SDarrick J. Wong #define power_of_2(x) (((x) & ((x) - 1)) == 0) 118*6f9703d0SDarrick J. Wong 119*6f9703d0SDarrick J. Wong /* datasheet says to divide this number by the fan reading to get fan rpm */ 120*6f9703d0SDarrick J. Wong #define FAN_PERIOD_TO_RPM(x) ((90000 * 60) / (x)) 121*6f9703d0SDarrick J. Wong #define FAN_RPM_TO_PERIOD FAN_PERIOD_TO_RPM 122*6f9703d0SDarrick J. Wong #define FAN_PERIOD_INVALID 65535 123*6f9703d0SDarrick J. Wong #define FAN_DATA_VALID(x) ((x) && (x) != FAN_PERIOD_INVALID) 124*6f9703d0SDarrick J. Wong 125*6f9703d0SDarrick J. Wong struct adt7470_data { 126*6f9703d0SDarrick J. Wong struct i2c_client client; 127*6f9703d0SDarrick J. Wong struct class_device *class_dev; 128*6f9703d0SDarrick J. Wong struct attribute_group attrs; 129*6f9703d0SDarrick J. Wong struct mutex lock; 130*6f9703d0SDarrick J. Wong char sensors_valid; 131*6f9703d0SDarrick J. Wong char limits_valid; 132*6f9703d0SDarrick J. Wong unsigned long sensors_last_updated; /* In jiffies */ 133*6f9703d0SDarrick J. Wong unsigned long limits_last_updated; /* In jiffies */ 134*6f9703d0SDarrick J. Wong 135*6f9703d0SDarrick J. Wong s8 temp[ADT7470_TEMP_COUNT]; 136*6f9703d0SDarrick J. Wong s8 temp_min[ADT7470_TEMP_COUNT]; 137*6f9703d0SDarrick J. Wong s8 temp_max[ADT7470_TEMP_COUNT]; 138*6f9703d0SDarrick J. Wong u16 fan[ADT7470_FAN_COUNT]; 139*6f9703d0SDarrick J. Wong u16 fan_min[ADT7470_FAN_COUNT]; 140*6f9703d0SDarrick J. Wong u16 fan_max[ADT7470_FAN_COUNT]; 141*6f9703d0SDarrick J. Wong u16 alarms, alarms_mask; 142*6f9703d0SDarrick J. Wong u8 force_pwm_max; 143*6f9703d0SDarrick J. Wong u8 pwm[ADT7470_PWM_COUNT]; 144*6f9703d0SDarrick J. Wong u8 pwm_max[ADT7470_PWM_COUNT]; 145*6f9703d0SDarrick J. Wong u8 pwm_automatic[ADT7470_PWM_COUNT]; 146*6f9703d0SDarrick J. Wong u8 pwm_min[ADT7470_PWM_COUNT]; 147*6f9703d0SDarrick J. Wong s8 pwm_tmin[ADT7470_PWM_COUNT]; 148*6f9703d0SDarrick J. Wong u8 pwm_auto_temp[ADT7470_PWM_COUNT]; 149*6f9703d0SDarrick J. Wong }; 150*6f9703d0SDarrick J. Wong 151*6f9703d0SDarrick J. Wong static int adt7470_attach_adapter(struct i2c_adapter *adapter); 152*6f9703d0SDarrick J. Wong static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind); 153*6f9703d0SDarrick J. Wong static int adt7470_detach_client(struct i2c_client *client); 154*6f9703d0SDarrick J. Wong 155*6f9703d0SDarrick J. Wong static struct i2c_driver adt7470_driver = { 156*6f9703d0SDarrick J. Wong .driver = { 157*6f9703d0SDarrick J. Wong .name = "adt7470", 158*6f9703d0SDarrick J. Wong }, 159*6f9703d0SDarrick J. Wong .attach_adapter = adt7470_attach_adapter, 160*6f9703d0SDarrick J. Wong .detach_client = adt7470_detach_client, 161*6f9703d0SDarrick J. Wong }; 162*6f9703d0SDarrick J. Wong 163*6f9703d0SDarrick J. Wong /* 164*6f9703d0SDarrick J. Wong * 16-bit registers on the ADT7470 are low-byte first. The data sheet says 165*6f9703d0SDarrick J. Wong * that the low byte must be read before the high byte. 166*6f9703d0SDarrick J. Wong */ 167*6f9703d0SDarrick J. Wong static inline int adt7470_read_word_data(struct i2c_client *client, u8 reg) 168*6f9703d0SDarrick J. Wong { 169*6f9703d0SDarrick J. Wong u16 foo; 170*6f9703d0SDarrick J. Wong foo = i2c_smbus_read_byte_data(client, reg); 171*6f9703d0SDarrick J. Wong foo |= ((u16)i2c_smbus_read_byte_data(client, reg + 1) << 8); 172*6f9703d0SDarrick J. Wong return foo; 173*6f9703d0SDarrick J. Wong } 174*6f9703d0SDarrick J. Wong 175*6f9703d0SDarrick J. Wong static inline int adt7470_write_word_data(struct i2c_client *client, u8 reg, 176*6f9703d0SDarrick J. Wong u16 value) 177*6f9703d0SDarrick J. Wong { 178*6f9703d0SDarrick J. Wong return i2c_smbus_write_byte_data(client, reg, value & 0xFF) 179*6f9703d0SDarrick J. Wong && i2c_smbus_write_byte_data(client, reg + 1, value >> 8); 180*6f9703d0SDarrick J. Wong } 181*6f9703d0SDarrick J. Wong 182*6f9703d0SDarrick J. Wong static void adt7470_init_client(struct i2c_client *client) 183*6f9703d0SDarrick J. Wong { 184*6f9703d0SDarrick J. Wong int reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); 185*6f9703d0SDarrick J. Wong 186*6f9703d0SDarrick J. Wong if (reg < 0) { 187*6f9703d0SDarrick J. Wong dev_err(&client->dev, "cannot read configuration register\n"); 188*6f9703d0SDarrick J. Wong } else { 189*6f9703d0SDarrick J. Wong /* start monitoring (and do a self-test) */ 190*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg | 3); 191*6f9703d0SDarrick J. Wong } 192*6f9703d0SDarrick J. Wong } 193*6f9703d0SDarrick J. Wong 194*6f9703d0SDarrick J. Wong static struct adt7470_data *adt7470_update_device(struct device *dev) 195*6f9703d0SDarrick J. Wong { 196*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 197*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 198*6f9703d0SDarrick J. Wong unsigned long local_jiffies = jiffies; 199*6f9703d0SDarrick J. Wong u8 cfg; 200*6f9703d0SDarrick J. Wong int i; 201*6f9703d0SDarrick J. Wong 202*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 203*6f9703d0SDarrick J. Wong if (time_before(local_jiffies, data->sensors_last_updated + 204*6f9703d0SDarrick J. Wong SENSOR_REFRESH_INTERVAL) 205*6f9703d0SDarrick J. Wong && data->sensors_valid) 206*6f9703d0SDarrick J. Wong goto no_sensor_update; 207*6f9703d0SDarrick J. Wong 208*6f9703d0SDarrick J. Wong /* start reading temperature sensors */ 209*6f9703d0SDarrick J. Wong cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); 210*6f9703d0SDarrick J. Wong cfg |= 0x80; 211*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); 212*6f9703d0SDarrick J. Wong 213*6f9703d0SDarrick J. Wong /* 214*6f9703d0SDarrick J. Wong * Delay is 200ms * number of tmp05 sensors. Too bad 215*6f9703d0SDarrick J. Wong * there's no way to figure out how many are connected. 216*6f9703d0SDarrick J. Wong * For now, assume 1s will work. 217*6f9703d0SDarrick J. Wong */ 218*6f9703d0SDarrick J. Wong msleep(TEMP_COLLECTION_TIME); 219*6f9703d0SDarrick J. Wong 220*6f9703d0SDarrick J. Wong /* done reading temperature sensors */ 221*6f9703d0SDarrick J. Wong cfg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); 222*6f9703d0SDarrick J. Wong cfg &= ~0x80; 223*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, cfg); 224*6f9703d0SDarrick J. Wong 225*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_TEMP_COUNT; i++) 226*6f9703d0SDarrick J. Wong data->temp[i] = i2c_smbus_read_byte_data(client, 227*6f9703d0SDarrick J. Wong ADT7470_TEMP_REG(i)); 228*6f9703d0SDarrick J. Wong 229*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_FAN_COUNT; i++) 230*6f9703d0SDarrick J. Wong data->fan[i] = adt7470_read_word_data(client, 231*6f9703d0SDarrick J. Wong ADT7470_REG_FAN(i)); 232*6f9703d0SDarrick J. Wong 233*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_PWM_COUNT; i++) { 234*6f9703d0SDarrick J. Wong int reg; 235*6f9703d0SDarrick J. Wong int reg_mask; 236*6f9703d0SDarrick J. Wong 237*6f9703d0SDarrick J. Wong data->pwm[i] = i2c_smbus_read_byte_data(client, 238*6f9703d0SDarrick J. Wong ADT7470_REG_PWM(i)); 239*6f9703d0SDarrick J. Wong 240*6f9703d0SDarrick J. Wong if (i % 2) 241*6f9703d0SDarrick J. Wong reg_mask = ADT7470_PWM2_AUTO_MASK; 242*6f9703d0SDarrick J. Wong else 243*6f9703d0SDarrick J. Wong reg_mask = ADT7470_PWM1_AUTO_MASK; 244*6f9703d0SDarrick J. Wong 245*6f9703d0SDarrick J. Wong reg = ADT7470_REG_PWM_CFG(i); 246*6f9703d0SDarrick J. Wong if (i2c_smbus_read_byte_data(client, reg) & reg_mask) 247*6f9703d0SDarrick J. Wong data->pwm_automatic[i] = 1; 248*6f9703d0SDarrick J. Wong else 249*6f9703d0SDarrick J. Wong data->pwm_automatic[i] = 0; 250*6f9703d0SDarrick J. Wong 251*6f9703d0SDarrick J. Wong reg = ADT7470_REG_PWM_AUTO_TEMP(i); 252*6f9703d0SDarrick J. Wong cfg = i2c_smbus_read_byte_data(client, reg); 253*6f9703d0SDarrick J. Wong if (!(i % 2)) 254*6f9703d0SDarrick J. Wong data->pwm_auto_temp[i] = cfg >> 4; 255*6f9703d0SDarrick J. Wong else 256*6f9703d0SDarrick J. Wong data->pwm_auto_temp[i] = cfg & 0xF; 257*6f9703d0SDarrick J. Wong } 258*6f9703d0SDarrick J. Wong 259*6f9703d0SDarrick J. Wong if (i2c_smbus_read_byte_data(client, ADT7470_REG_CFG) & 260*6f9703d0SDarrick J. Wong ADT7470_FSPD_MASK) 261*6f9703d0SDarrick J. Wong data->force_pwm_max = 1; 262*6f9703d0SDarrick J. Wong else 263*6f9703d0SDarrick J. Wong data->force_pwm_max = 0; 264*6f9703d0SDarrick J. Wong 265*6f9703d0SDarrick J. Wong data->alarms = adt7470_read_word_data(client, ADT7470_REG_ALARM1); 266*6f9703d0SDarrick J. Wong data->alarms_mask = adt7470_read_word_data(client, 267*6f9703d0SDarrick J. Wong ADT7470_REG_ALARM1_MASK); 268*6f9703d0SDarrick J. Wong 269*6f9703d0SDarrick J. Wong data->sensors_last_updated = local_jiffies; 270*6f9703d0SDarrick J. Wong data->sensors_valid = 1; 271*6f9703d0SDarrick J. Wong 272*6f9703d0SDarrick J. Wong no_sensor_update: 273*6f9703d0SDarrick J. Wong if (time_before(local_jiffies, data->limits_last_updated + 274*6f9703d0SDarrick J. Wong LIMIT_REFRESH_INTERVAL) 275*6f9703d0SDarrick J. Wong && data->limits_valid) 276*6f9703d0SDarrick J. Wong goto out; 277*6f9703d0SDarrick J. Wong 278*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_TEMP_COUNT; i++) { 279*6f9703d0SDarrick J. Wong data->temp_min[i] = i2c_smbus_read_byte_data(client, 280*6f9703d0SDarrick J. Wong ADT7470_TEMP_MIN_REG(i)); 281*6f9703d0SDarrick J. Wong data->temp_max[i] = i2c_smbus_read_byte_data(client, 282*6f9703d0SDarrick J. Wong ADT7470_TEMP_MAX_REG(i)); 283*6f9703d0SDarrick J. Wong } 284*6f9703d0SDarrick J. Wong 285*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_FAN_COUNT; i++) { 286*6f9703d0SDarrick J. Wong data->fan_min[i] = adt7470_read_word_data(client, 287*6f9703d0SDarrick J. Wong ADT7470_REG_FAN_MIN(i)); 288*6f9703d0SDarrick J. Wong data->fan_max[i] = adt7470_read_word_data(client, 289*6f9703d0SDarrick J. Wong ADT7470_REG_FAN_MAX(i)); 290*6f9703d0SDarrick J. Wong } 291*6f9703d0SDarrick J. Wong 292*6f9703d0SDarrick J. Wong for (i = 0; i < ADT7470_PWM_COUNT; i++) { 293*6f9703d0SDarrick J. Wong data->pwm_max[i] = i2c_smbus_read_byte_data(client, 294*6f9703d0SDarrick J. Wong ADT7470_REG_PWM_MAX(i)); 295*6f9703d0SDarrick J. Wong data->pwm_min[i] = i2c_smbus_read_byte_data(client, 296*6f9703d0SDarrick J. Wong ADT7470_REG_PWM_MIN(i)); 297*6f9703d0SDarrick J. Wong data->pwm_tmin[i] = i2c_smbus_read_byte_data(client, 298*6f9703d0SDarrick J. Wong ADT7470_REG_PWM_TMIN(i)); 299*6f9703d0SDarrick J. Wong } 300*6f9703d0SDarrick J. Wong 301*6f9703d0SDarrick J. Wong data->limits_last_updated = local_jiffies; 302*6f9703d0SDarrick J. Wong data->limits_valid = 1; 303*6f9703d0SDarrick J. Wong 304*6f9703d0SDarrick J. Wong out: 305*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 306*6f9703d0SDarrick J. Wong return data; 307*6f9703d0SDarrick J. Wong } 308*6f9703d0SDarrick J. Wong 309*6f9703d0SDarrick J. Wong static ssize_t show_temp_min(struct device *dev, 310*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 311*6f9703d0SDarrick J. Wong char *buf) 312*6f9703d0SDarrick J. Wong { 313*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 314*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 315*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1000 * data->temp_min[attr->index]); 316*6f9703d0SDarrick J. Wong } 317*6f9703d0SDarrick J. Wong 318*6f9703d0SDarrick J. Wong static ssize_t set_temp_min(struct device *dev, 319*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 320*6f9703d0SDarrick J. Wong const char *buf, 321*6f9703d0SDarrick J. Wong size_t count) 322*6f9703d0SDarrick J. Wong { 323*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 324*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 325*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 326*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10) / 1000; 327*6f9703d0SDarrick J. Wong 328*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 329*6f9703d0SDarrick J. Wong data->temp_min[attr->index] = temp; 330*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_TEMP_MIN_REG(attr->index), 331*6f9703d0SDarrick J. Wong temp); 332*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 333*6f9703d0SDarrick J. Wong 334*6f9703d0SDarrick J. Wong return count; 335*6f9703d0SDarrick J. Wong } 336*6f9703d0SDarrick J. Wong 337*6f9703d0SDarrick J. Wong static ssize_t show_temp_max(struct device *dev, 338*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 339*6f9703d0SDarrick J. Wong char *buf) 340*6f9703d0SDarrick J. Wong { 341*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 342*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 343*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1000 * data->temp_max[attr->index]); 344*6f9703d0SDarrick J. Wong } 345*6f9703d0SDarrick J. Wong 346*6f9703d0SDarrick J. Wong static ssize_t set_temp_max(struct device *dev, 347*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 348*6f9703d0SDarrick J. Wong const char *buf, 349*6f9703d0SDarrick J. Wong size_t count) 350*6f9703d0SDarrick J. Wong { 351*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 352*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 353*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 354*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10) / 1000; 355*6f9703d0SDarrick J. Wong 356*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 357*6f9703d0SDarrick J. Wong data->temp_max[attr->index] = temp; 358*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_TEMP_MAX_REG(attr->index), 359*6f9703d0SDarrick J. Wong temp); 360*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 361*6f9703d0SDarrick J. Wong 362*6f9703d0SDarrick J. Wong return count; 363*6f9703d0SDarrick J. Wong } 364*6f9703d0SDarrick J. Wong 365*6f9703d0SDarrick J. Wong static ssize_t show_temp(struct device *dev, struct device_attribute *devattr, 366*6f9703d0SDarrick J. Wong char *buf) 367*6f9703d0SDarrick J. Wong { 368*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 369*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 370*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1000 * data->temp[attr->index]); 371*6f9703d0SDarrick J. Wong } 372*6f9703d0SDarrick J. Wong 373*6f9703d0SDarrick J. Wong static ssize_t show_alarms(struct device *dev, 374*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 375*6f9703d0SDarrick J. Wong char *buf) 376*6f9703d0SDarrick J. Wong { 377*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 378*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 379*6f9703d0SDarrick J. Wong 380*6f9703d0SDarrick J. Wong if (attr->index) 381*6f9703d0SDarrick J. Wong return sprintf(buf, "%x\n", data->alarms); 382*6f9703d0SDarrick J. Wong else 383*6f9703d0SDarrick J. Wong return sprintf(buf, "%x\n", data->alarms_mask); 384*6f9703d0SDarrick J. Wong } 385*6f9703d0SDarrick J. Wong 386*6f9703d0SDarrick J. Wong static ssize_t show_fan_max(struct device *dev, 387*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 388*6f9703d0SDarrick J. Wong char *buf) 389*6f9703d0SDarrick J. Wong { 390*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 391*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 392*6f9703d0SDarrick J. Wong 393*6f9703d0SDarrick J. Wong if (FAN_DATA_VALID(data->fan_max[attr->index])) 394*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 395*6f9703d0SDarrick J. Wong FAN_PERIOD_TO_RPM(data->fan_max[attr->index])); 396*6f9703d0SDarrick J. Wong else 397*6f9703d0SDarrick J. Wong return sprintf(buf, "0\n"); 398*6f9703d0SDarrick J. Wong } 399*6f9703d0SDarrick J. Wong 400*6f9703d0SDarrick J. Wong static ssize_t set_fan_max(struct device *dev, 401*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 402*6f9703d0SDarrick J. Wong const char *buf, size_t count) 403*6f9703d0SDarrick J. Wong { 404*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 405*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 406*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 407*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 408*6f9703d0SDarrick J. Wong 409*6f9703d0SDarrick J. Wong if (!temp) 410*6f9703d0SDarrick J. Wong return -EINVAL; 411*6f9703d0SDarrick J. Wong temp = FAN_RPM_TO_PERIOD(temp); 412*6f9703d0SDarrick J. Wong 413*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 414*6f9703d0SDarrick J. Wong data->fan_max[attr->index] = temp; 415*6f9703d0SDarrick J. Wong adt7470_write_word_data(client, ADT7470_REG_FAN_MAX(attr->index), temp); 416*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 417*6f9703d0SDarrick J. Wong 418*6f9703d0SDarrick J. Wong return count; 419*6f9703d0SDarrick J. Wong } 420*6f9703d0SDarrick J. Wong 421*6f9703d0SDarrick J. Wong static ssize_t show_fan_min(struct device *dev, 422*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 423*6f9703d0SDarrick J. Wong char *buf) 424*6f9703d0SDarrick J. Wong { 425*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 426*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 427*6f9703d0SDarrick J. Wong 428*6f9703d0SDarrick J. Wong if (FAN_DATA_VALID(data->fan_min[attr->index])) 429*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 430*6f9703d0SDarrick J. Wong FAN_PERIOD_TO_RPM(data->fan_min[attr->index])); 431*6f9703d0SDarrick J. Wong else 432*6f9703d0SDarrick J. Wong return sprintf(buf, "0\n"); 433*6f9703d0SDarrick J. Wong } 434*6f9703d0SDarrick J. Wong 435*6f9703d0SDarrick J. Wong static ssize_t set_fan_min(struct device *dev, 436*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 437*6f9703d0SDarrick J. Wong const char *buf, size_t count) 438*6f9703d0SDarrick J. Wong { 439*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 440*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 441*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 442*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 443*6f9703d0SDarrick J. Wong 444*6f9703d0SDarrick J. Wong if (!temp) 445*6f9703d0SDarrick J. Wong return -EINVAL; 446*6f9703d0SDarrick J. Wong temp = FAN_RPM_TO_PERIOD(temp); 447*6f9703d0SDarrick J. Wong 448*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 449*6f9703d0SDarrick J. Wong data->fan_min[attr->index] = temp; 450*6f9703d0SDarrick J. Wong adt7470_write_word_data(client, ADT7470_REG_FAN_MIN(attr->index), temp); 451*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 452*6f9703d0SDarrick J. Wong 453*6f9703d0SDarrick J. Wong return count; 454*6f9703d0SDarrick J. Wong } 455*6f9703d0SDarrick J. Wong 456*6f9703d0SDarrick J. Wong static ssize_t show_fan(struct device *dev, struct device_attribute *devattr, 457*6f9703d0SDarrick J. Wong char *buf) 458*6f9703d0SDarrick J. Wong { 459*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 460*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 461*6f9703d0SDarrick J. Wong 462*6f9703d0SDarrick J. Wong if (FAN_DATA_VALID(data->fan[attr->index])) 463*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 464*6f9703d0SDarrick J. Wong FAN_PERIOD_TO_RPM(data->fan[attr->index])); 465*6f9703d0SDarrick J. Wong else 466*6f9703d0SDarrick J. Wong return sprintf(buf, "0\n"); 467*6f9703d0SDarrick J. Wong } 468*6f9703d0SDarrick J. Wong 469*6f9703d0SDarrick J. Wong static ssize_t show_force_pwm_max(struct device *dev, 470*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 471*6f9703d0SDarrick J. Wong char *buf) 472*6f9703d0SDarrick J. Wong { 473*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 474*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", data->force_pwm_max); 475*6f9703d0SDarrick J. Wong } 476*6f9703d0SDarrick J. Wong 477*6f9703d0SDarrick J. Wong static ssize_t set_force_pwm_max(struct device *dev, 478*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 479*6f9703d0SDarrick J. Wong const char *buf, 480*6f9703d0SDarrick J. Wong size_t count) 481*6f9703d0SDarrick J. Wong { 482*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 483*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 484*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 485*6f9703d0SDarrick J. Wong u8 reg; 486*6f9703d0SDarrick J. Wong 487*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 488*6f9703d0SDarrick J. Wong data->force_pwm_max = temp; 489*6f9703d0SDarrick J. Wong reg = i2c_smbus_read_byte_data(client, ADT7470_REG_CFG); 490*6f9703d0SDarrick J. Wong if (temp) 491*6f9703d0SDarrick J. Wong reg |= ADT7470_FSPD_MASK; 492*6f9703d0SDarrick J. Wong else 493*6f9703d0SDarrick J. Wong reg &= ~ADT7470_FSPD_MASK; 494*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_CFG, reg); 495*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 496*6f9703d0SDarrick J. Wong 497*6f9703d0SDarrick J. Wong return count; 498*6f9703d0SDarrick J. Wong } 499*6f9703d0SDarrick J. Wong 500*6f9703d0SDarrick J. Wong static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, 501*6f9703d0SDarrick J. Wong char *buf) 502*6f9703d0SDarrick J. Wong { 503*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 504*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 505*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", data->pwm[attr->index]); 506*6f9703d0SDarrick J. Wong } 507*6f9703d0SDarrick J. Wong 508*6f9703d0SDarrick J. Wong static ssize_t set_pwm(struct device *dev, struct device_attribute *devattr, 509*6f9703d0SDarrick J. Wong const char *buf, size_t count) 510*6f9703d0SDarrick J. Wong { 511*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 512*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 513*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 514*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 515*6f9703d0SDarrick J. Wong 516*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 517*6f9703d0SDarrick J. Wong data->pwm[attr->index] = temp; 518*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_PWM(attr->index), temp); 519*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 520*6f9703d0SDarrick J. Wong 521*6f9703d0SDarrick J. Wong return count; 522*6f9703d0SDarrick J. Wong } 523*6f9703d0SDarrick J. Wong 524*6f9703d0SDarrick J. Wong static ssize_t show_pwm_max(struct device *dev, 525*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 526*6f9703d0SDarrick J. Wong char *buf) 527*6f9703d0SDarrick J. Wong { 528*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 529*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 530*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", data->pwm_max[attr->index]); 531*6f9703d0SDarrick J. Wong } 532*6f9703d0SDarrick J. Wong 533*6f9703d0SDarrick J. Wong static ssize_t set_pwm_max(struct device *dev, 534*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 535*6f9703d0SDarrick J. Wong const char *buf, 536*6f9703d0SDarrick J. Wong size_t count) 537*6f9703d0SDarrick J. Wong { 538*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 539*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 540*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 541*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 542*6f9703d0SDarrick J. Wong 543*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 544*6f9703d0SDarrick J. Wong data->pwm_max[attr->index] = temp; 545*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MAX(attr->index), 546*6f9703d0SDarrick J. Wong temp); 547*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 548*6f9703d0SDarrick J. Wong 549*6f9703d0SDarrick J. Wong return count; 550*6f9703d0SDarrick J. Wong } 551*6f9703d0SDarrick J. Wong 552*6f9703d0SDarrick J. Wong static ssize_t show_pwm_min(struct device *dev, 553*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 554*6f9703d0SDarrick J. Wong char *buf) 555*6f9703d0SDarrick J. Wong { 556*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 557*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 558*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", data->pwm_min[attr->index]); 559*6f9703d0SDarrick J. Wong } 560*6f9703d0SDarrick J. Wong 561*6f9703d0SDarrick J. Wong static ssize_t set_pwm_min(struct device *dev, 562*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 563*6f9703d0SDarrick J. Wong const char *buf, 564*6f9703d0SDarrick J. Wong size_t count) 565*6f9703d0SDarrick J. Wong { 566*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 567*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 568*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 569*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 570*6f9703d0SDarrick J. Wong 571*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 572*6f9703d0SDarrick J. Wong data->pwm_min[attr->index] = temp; 573*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_MIN(attr->index), 574*6f9703d0SDarrick J. Wong temp); 575*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 576*6f9703d0SDarrick J. Wong 577*6f9703d0SDarrick J. Wong return count; 578*6f9703d0SDarrick J. Wong } 579*6f9703d0SDarrick J. Wong 580*6f9703d0SDarrick J. Wong static ssize_t show_pwm_tmax(struct device *dev, 581*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 582*6f9703d0SDarrick J. Wong char *buf) 583*6f9703d0SDarrick J. Wong { 584*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 585*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 586*6f9703d0SDarrick J. Wong /* the datasheet says that tmax = tmin + 20C */ 587*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1000 * (20 + data->pwm_tmin[attr->index])); 588*6f9703d0SDarrick J. Wong } 589*6f9703d0SDarrick J. Wong 590*6f9703d0SDarrick J. Wong static ssize_t show_pwm_tmin(struct device *dev, 591*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 592*6f9703d0SDarrick J. Wong char *buf) 593*6f9703d0SDarrick J. Wong { 594*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 595*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 596*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1000 * data->pwm_tmin[attr->index]); 597*6f9703d0SDarrick J. Wong } 598*6f9703d0SDarrick J. Wong 599*6f9703d0SDarrick J. Wong static ssize_t set_pwm_tmin(struct device *dev, 600*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 601*6f9703d0SDarrick J. Wong const char *buf, 602*6f9703d0SDarrick J. Wong size_t count) 603*6f9703d0SDarrick J. Wong { 604*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 605*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 606*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 607*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10) / 1000; 608*6f9703d0SDarrick J. Wong 609*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 610*6f9703d0SDarrick J. Wong data->pwm_tmin[attr->index] = temp; 611*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, ADT7470_REG_PWM_TMIN(attr->index), 612*6f9703d0SDarrick J. Wong temp); 613*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 614*6f9703d0SDarrick J. Wong 615*6f9703d0SDarrick J. Wong return count; 616*6f9703d0SDarrick J. Wong } 617*6f9703d0SDarrick J. Wong 618*6f9703d0SDarrick J. Wong static ssize_t show_pwm_auto(struct device *dev, 619*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 620*6f9703d0SDarrick J. Wong char *buf) 621*6f9703d0SDarrick J. Wong { 622*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 623*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 624*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1 + data->pwm_automatic[attr->index]); 625*6f9703d0SDarrick J. Wong } 626*6f9703d0SDarrick J. Wong 627*6f9703d0SDarrick J. Wong static ssize_t set_pwm_auto(struct device *dev, 628*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 629*6f9703d0SDarrick J. Wong const char *buf, 630*6f9703d0SDarrick J. Wong size_t count) 631*6f9703d0SDarrick J. Wong { 632*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 633*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 634*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 635*6f9703d0SDarrick J. Wong int temp = simple_strtol(buf, NULL, 10); 636*6f9703d0SDarrick J. Wong int pwm_auto_reg = ADT7470_REG_PWM_CFG(attr->index); 637*6f9703d0SDarrick J. Wong int pwm_auto_reg_mask; 638*6f9703d0SDarrick J. Wong u8 reg; 639*6f9703d0SDarrick J. Wong 640*6f9703d0SDarrick J. Wong if (attr->index % 2) 641*6f9703d0SDarrick J. Wong pwm_auto_reg_mask = ADT7470_PWM2_AUTO_MASK; 642*6f9703d0SDarrick J. Wong else 643*6f9703d0SDarrick J. Wong pwm_auto_reg_mask = ADT7470_PWM1_AUTO_MASK; 644*6f9703d0SDarrick J. Wong 645*6f9703d0SDarrick J. Wong if (temp != 2 && temp != 1) 646*6f9703d0SDarrick J. Wong return -EINVAL; 647*6f9703d0SDarrick J. Wong temp--; 648*6f9703d0SDarrick J. Wong 649*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 650*6f9703d0SDarrick J. Wong data->pwm_automatic[attr->index] = temp; 651*6f9703d0SDarrick J. Wong reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); 652*6f9703d0SDarrick J. Wong if (temp) 653*6f9703d0SDarrick J. Wong reg |= pwm_auto_reg_mask; 654*6f9703d0SDarrick J. Wong else 655*6f9703d0SDarrick J. Wong reg &= ~pwm_auto_reg_mask; 656*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); 657*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 658*6f9703d0SDarrick J. Wong 659*6f9703d0SDarrick J. Wong return count; 660*6f9703d0SDarrick J. Wong } 661*6f9703d0SDarrick J. Wong 662*6f9703d0SDarrick J. Wong static ssize_t show_pwm_auto_temp(struct device *dev, 663*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 664*6f9703d0SDarrick J. Wong char *buf) 665*6f9703d0SDarrick J. Wong { 666*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 667*6f9703d0SDarrick J. Wong struct adt7470_data *data = adt7470_update_device(dev); 668*6f9703d0SDarrick J. Wong u8 ctrl = data->pwm_auto_temp[attr->index]; 669*6f9703d0SDarrick J. Wong 670*6f9703d0SDarrick J. Wong if (ctrl) 671*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", 1 << (ctrl - 1)); 672*6f9703d0SDarrick J. Wong else 673*6f9703d0SDarrick J. Wong return sprintf(buf, "%d\n", ADT7470_PWM_ALL_TEMPS); 674*6f9703d0SDarrick J. Wong } 675*6f9703d0SDarrick J. Wong 676*6f9703d0SDarrick J. Wong static int cvt_auto_temp(int input) 677*6f9703d0SDarrick J. Wong { 678*6f9703d0SDarrick J. Wong if (input == ADT7470_PWM_ALL_TEMPS) 679*6f9703d0SDarrick J. Wong return 0; 680*6f9703d0SDarrick J. Wong if (input < 1 || !power_of_2(input)) 681*6f9703d0SDarrick J. Wong return -EINVAL; 682*6f9703d0SDarrick J. Wong return ilog2(input) + 1; 683*6f9703d0SDarrick J. Wong } 684*6f9703d0SDarrick J. Wong 685*6f9703d0SDarrick J. Wong static ssize_t set_pwm_auto_temp(struct device *dev, 686*6f9703d0SDarrick J. Wong struct device_attribute *devattr, 687*6f9703d0SDarrick J. Wong const char *buf, 688*6f9703d0SDarrick J. Wong size_t count) 689*6f9703d0SDarrick J. Wong { 690*6f9703d0SDarrick J. Wong struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 691*6f9703d0SDarrick J. Wong struct i2c_client *client = to_i2c_client(dev); 692*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 693*6f9703d0SDarrick J. Wong int temp = cvt_auto_temp(simple_strtol(buf, NULL, 10)); 694*6f9703d0SDarrick J. Wong int pwm_auto_reg = ADT7470_REG_PWM_AUTO_TEMP(attr->index); 695*6f9703d0SDarrick J. Wong u8 reg; 696*6f9703d0SDarrick J. Wong 697*6f9703d0SDarrick J. Wong if (temp < 0) 698*6f9703d0SDarrick J. Wong return temp; 699*6f9703d0SDarrick J. Wong 700*6f9703d0SDarrick J. Wong mutex_lock(&data->lock); 701*6f9703d0SDarrick J. Wong data->pwm_automatic[attr->index] = temp; 702*6f9703d0SDarrick J. Wong reg = i2c_smbus_read_byte_data(client, pwm_auto_reg); 703*6f9703d0SDarrick J. Wong 704*6f9703d0SDarrick J. Wong if (!(attr->index % 2)) { 705*6f9703d0SDarrick J. Wong reg &= 0xF; 706*6f9703d0SDarrick J. Wong reg |= (temp << 4) & 0xF0; 707*6f9703d0SDarrick J. Wong } else { 708*6f9703d0SDarrick J. Wong reg &= 0xF0; 709*6f9703d0SDarrick J. Wong reg |= temp & 0xF; 710*6f9703d0SDarrick J. Wong } 711*6f9703d0SDarrick J. Wong 712*6f9703d0SDarrick J. Wong i2c_smbus_write_byte_data(client, pwm_auto_reg, reg); 713*6f9703d0SDarrick J. Wong mutex_unlock(&data->lock); 714*6f9703d0SDarrick J. Wong 715*6f9703d0SDarrick J. Wong return count; 716*6f9703d0SDarrick J. Wong } 717*6f9703d0SDarrick J. Wong 718*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(alarms, S_IRUGO, show_alarms, NULL, 0); 719*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(alarm_mask, S_IRUGO, show_alarms, NULL, 1); 720*6f9703d0SDarrick J. Wong 721*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, 722*6f9703d0SDarrick J. Wong set_temp_max, 0); 723*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_temp_max, 724*6f9703d0SDarrick J. Wong set_temp_max, 1); 725*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_temp_max, 726*6f9703d0SDarrick J. Wong set_temp_max, 2); 727*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_temp_max, 728*6f9703d0SDarrick J. Wong set_temp_max, 3); 729*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_max, S_IWUSR | S_IRUGO, show_temp_max, 730*6f9703d0SDarrick J. Wong set_temp_max, 4); 731*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_max, S_IWUSR | S_IRUGO, show_temp_max, 732*6f9703d0SDarrick J. Wong set_temp_max, 5); 733*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_max, S_IWUSR | S_IRUGO, show_temp_max, 734*6f9703d0SDarrick J. Wong set_temp_max, 6); 735*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_max, S_IWUSR | S_IRUGO, show_temp_max, 736*6f9703d0SDarrick J. Wong set_temp_max, 7); 737*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_max, S_IWUSR | S_IRUGO, show_temp_max, 738*6f9703d0SDarrick J. Wong set_temp_max, 8); 739*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_max, S_IWUSR | S_IRUGO, show_temp_max, 740*6f9703d0SDarrick J. Wong set_temp_max, 9); 741*6f9703d0SDarrick J. Wong 742*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, 743*6f9703d0SDarrick J. Wong set_temp_min, 0); 744*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_temp_min, 745*6f9703d0SDarrick J. Wong set_temp_min, 1); 746*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_temp_min, 747*6f9703d0SDarrick J. Wong set_temp_min, 2); 748*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_temp_min, 749*6f9703d0SDarrick J. Wong set_temp_min, 3); 750*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_min, S_IWUSR | S_IRUGO, show_temp_min, 751*6f9703d0SDarrick J. Wong set_temp_min, 4); 752*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_min, S_IWUSR | S_IRUGO, show_temp_min, 753*6f9703d0SDarrick J. Wong set_temp_min, 5); 754*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_min, S_IWUSR | S_IRUGO, show_temp_min, 755*6f9703d0SDarrick J. Wong set_temp_min, 6); 756*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_min, S_IWUSR | S_IRUGO, show_temp_min, 757*6f9703d0SDarrick J. Wong set_temp_min, 7); 758*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_min, S_IWUSR | S_IRUGO, show_temp_min, 759*6f9703d0SDarrick J. Wong set_temp_min, 8); 760*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_min, S_IWUSR | S_IRUGO, show_temp_min, 761*6f9703d0SDarrick J. Wong set_temp_min, 9); 762*6f9703d0SDarrick J. Wong 763*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp, NULL, 0); 764*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp, NULL, 1); 765*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_temp, NULL, 2); 766*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_temp, NULL, 3); 767*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, show_temp, NULL, 4); 768*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, show_temp, NULL, 5); 769*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp7_input, S_IRUGO, show_temp, NULL, 6); 770*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp8_input, S_IRUGO, show_temp, NULL, 7); 771*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp9_input, S_IRUGO, show_temp, NULL, 8); 772*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(temp10_input, S_IRUGO, show_temp, NULL, 9); 773*6f9703d0SDarrick J. Wong 774*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_max, S_IWUSR | S_IRUGO, show_fan_max, 775*6f9703d0SDarrick J. Wong set_fan_max, 0); 776*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_max, S_IWUSR | S_IRUGO, show_fan_max, 777*6f9703d0SDarrick J. Wong set_fan_max, 1); 778*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_max, S_IWUSR | S_IRUGO, show_fan_max, 779*6f9703d0SDarrick J. Wong set_fan_max, 2); 780*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_max, S_IWUSR | S_IRUGO, show_fan_max, 781*6f9703d0SDarrick J. Wong set_fan_max, 3); 782*6f9703d0SDarrick J. Wong 783*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_min, S_IWUSR | S_IRUGO, show_fan_min, 784*6f9703d0SDarrick J. Wong set_fan_min, 0); 785*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_min, S_IWUSR | S_IRUGO, show_fan_min, 786*6f9703d0SDarrick J. Wong set_fan_min, 1); 787*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_min, S_IWUSR | S_IRUGO, show_fan_min, 788*6f9703d0SDarrick J. Wong set_fan_min, 2); 789*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_min, S_IWUSR | S_IRUGO, show_fan_min, 790*6f9703d0SDarrick J. Wong set_fan_min, 3); 791*6f9703d0SDarrick J. Wong 792*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0); 793*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 1); 794*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 2); 795*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(fan4_input, S_IRUGO, show_fan, NULL, 3); 796*6f9703d0SDarrick J. Wong 797*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(force_pwm_max, S_IWUSR | S_IRUGO, 798*6f9703d0SDarrick J. Wong show_force_pwm_max, set_force_pwm_max, 0); 799*6f9703d0SDarrick J. Wong 800*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 0); 801*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 1); 802*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 2); 803*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4, S_IWUSR | S_IRUGO, show_pwm, set_pwm, 3); 804*6f9703d0SDarrick J. Wong 805*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point1_pwm, S_IWUSR | S_IRUGO, 806*6f9703d0SDarrick J. Wong show_pwm_min, set_pwm_min, 0); 807*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point1_pwm, S_IWUSR | S_IRUGO, 808*6f9703d0SDarrick J. Wong show_pwm_min, set_pwm_min, 1); 809*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point1_pwm, S_IWUSR | S_IRUGO, 810*6f9703d0SDarrick J. Wong show_pwm_min, set_pwm_min, 2); 811*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point1_pwm, S_IWUSR | S_IRUGO, 812*6f9703d0SDarrick J. Wong show_pwm_min, set_pwm_min, 3); 813*6f9703d0SDarrick J. Wong 814*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point2_pwm, S_IWUSR | S_IRUGO, 815*6f9703d0SDarrick J. Wong show_pwm_max, set_pwm_max, 0); 816*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point2_pwm, S_IWUSR | S_IRUGO, 817*6f9703d0SDarrick J. Wong show_pwm_max, set_pwm_max, 1); 818*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point2_pwm, S_IWUSR | S_IRUGO, 819*6f9703d0SDarrick J. Wong show_pwm_max, set_pwm_max, 2); 820*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point2_pwm, S_IWUSR | S_IRUGO, 821*6f9703d0SDarrick J. Wong show_pwm_max, set_pwm_max, 3); 822*6f9703d0SDarrick J. Wong 823*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point1_temp, S_IWUSR | S_IRUGO, 824*6f9703d0SDarrick J. Wong show_pwm_tmin, set_pwm_tmin, 0); 825*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point1_temp, S_IWUSR | S_IRUGO, 826*6f9703d0SDarrick J. Wong show_pwm_tmin, set_pwm_tmin, 1); 827*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point1_temp, S_IWUSR | S_IRUGO, 828*6f9703d0SDarrick J. Wong show_pwm_tmin, set_pwm_tmin, 2); 829*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point1_temp, S_IWUSR | S_IRUGO, 830*6f9703d0SDarrick J. Wong show_pwm_tmin, set_pwm_tmin, 3); 831*6f9703d0SDarrick J. Wong 832*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_point2_temp, S_IRUGO, show_pwm_tmax, 833*6f9703d0SDarrick J. Wong NULL, 0); 834*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_point2_temp, S_IRUGO, show_pwm_tmax, 835*6f9703d0SDarrick J. Wong NULL, 1); 836*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_point2_temp, S_IRUGO, show_pwm_tmax, 837*6f9703d0SDarrick J. Wong NULL, 2); 838*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_point2_temp, S_IRUGO, show_pwm_tmax, 839*6f9703d0SDarrick J. Wong NULL, 3); 840*6f9703d0SDarrick J. Wong 841*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_enable, S_IWUSR | S_IRUGO, show_pwm_auto, 842*6f9703d0SDarrick J. Wong set_pwm_auto, 0); 843*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_enable, S_IWUSR | S_IRUGO, show_pwm_auto, 844*6f9703d0SDarrick J. Wong set_pwm_auto, 1); 845*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_enable, S_IWUSR | S_IRUGO, show_pwm_auto, 846*6f9703d0SDarrick J. Wong set_pwm_auto, 2); 847*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_enable, S_IWUSR | S_IRUGO, show_pwm_auto, 848*6f9703d0SDarrick J. Wong set_pwm_auto, 3); 849*6f9703d0SDarrick J. Wong 850*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm1_auto_channels_temp, S_IWUSR | S_IRUGO, 851*6f9703d0SDarrick J. Wong show_pwm_auto_temp, set_pwm_auto_temp, 0); 852*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm2_auto_channels_temp, S_IWUSR | S_IRUGO, 853*6f9703d0SDarrick J. Wong show_pwm_auto_temp, set_pwm_auto_temp, 1); 854*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm3_auto_channels_temp, S_IWUSR | S_IRUGO, 855*6f9703d0SDarrick J. Wong show_pwm_auto_temp, set_pwm_auto_temp, 2); 856*6f9703d0SDarrick J. Wong static SENSOR_DEVICE_ATTR(pwm4_auto_channels_temp, S_IWUSR | S_IRUGO, 857*6f9703d0SDarrick J. Wong show_pwm_auto_temp, set_pwm_auto_temp, 3); 858*6f9703d0SDarrick J. Wong 859*6f9703d0SDarrick J. Wong static struct attribute *adt7470_attr[] = 860*6f9703d0SDarrick J. Wong { 861*6f9703d0SDarrick J. Wong &sensor_dev_attr_alarms.dev_attr.attr, 862*6f9703d0SDarrick J. Wong &sensor_dev_attr_alarm_mask.dev_attr.attr, 863*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp1_max.dev_attr.attr, 864*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp2_max.dev_attr.attr, 865*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp3_max.dev_attr.attr, 866*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp4_max.dev_attr.attr, 867*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp5_max.dev_attr.attr, 868*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp6_max.dev_attr.attr, 869*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp7_max.dev_attr.attr, 870*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp8_max.dev_attr.attr, 871*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp9_max.dev_attr.attr, 872*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp10_max.dev_attr.attr, 873*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp1_min.dev_attr.attr, 874*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp2_min.dev_attr.attr, 875*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp3_min.dev_attr.attr, 876*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp4_min.dev_attr.attr, 877*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp5_min.dev_attr.attr, 878*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp6_min.dev_attr.attr, 879*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp7_min.dev_attr.attr, 880*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp8_min.dev_attr.attr, 881*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp9_min.dev_attr.attr, 882*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp10_min.dev_attr.attr, 883*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp1_input.dev_attr.attr, 884*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp2_input.dev_attr.attr, 885*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp3_input.dev_attr.attr, 886*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp4_input.dev_attr.attr, 887*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp5_input.dev_attr.attr, 888*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp6_input.dev_attr.attr, 889*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp7_input.dev_attr.attr, 890*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp8_input.dev_attr.attr, 891*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp9_input.dev_attr.attr, 892*6f9703d0SDarrick J. Wong &sensor_dev_attr_temp10_input.dev_attr.attr, 893*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan1_max.dev_attr.attr, 894*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan2_max.dev_attr.attr, 895*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan3_max.dev_attr.attr, 896*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan4_max.dev_attr.attr, 897*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan1_min.dev_attr.attr, 898*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan2_min.dev_attr.attr, 899*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan3_min.dev_attr.attr, 900*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan4_min.dev_attr.attr, 901*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan1_input.dev_attr.attr, 902*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan2_input.dev_attr.attr, 903*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan3_input.dev_attr.attr, 904*6f9703d0SDarrick J. Wong &sensor_dev_attr_fan4_input.dev_attr.attr, 905*6f9703d0SDarrick J. Wong &sensor_dev_attr_force_pwm_max.dev_attr.attr, 906*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1.dev_attr.attr, 907*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2.dev_attr.attr, 908*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3.dev_attr.attr, 909*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4.dev_attr.attr, 910*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_auto_point1_pwm.dev_attr.attr, 911*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_auto_point1_pwm.dev_attr.attr, 912*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr, 913*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_auto_point1_pwm.dev_attr.attr, 914*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_auto_point2_pwm.dev_attr.attr, 915*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_auto_point2_pwm.dev_attr.attr, 916*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr, 917*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_auto_point2_pwm.dev_attr.attr, 918*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_auto_point1_temp.dev_attr.attr, 919*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_auto_point1_temp.dev_attr.attr, 920*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr, 921*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_auto_point1_temp.dev_attr.attr, 922*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_auto_point2_temp.dev_attr.attr, 923*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_auto_point2_temp.dev_attr.attr, 924*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr, 925*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_auto_point2_temp.dev_attr.attr, 926*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_enable.dev_attr.attr, 927*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_enable.dev_attr.attr, 928*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_enable.dev_attr.attr, 929*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_enable.dev_attr.attr, 930*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm1_auto_channels_temp.dev_attr.attr, 931*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm2_auto_channels_temp.dev_attr.attr, 932*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm3_auto_channels_temp.dev_attr.attr, 933*6f9703d0SDarrick J. Wong &sensor_dev_attr_pwm4_auto_channels_temp.dev_attr.attr, 934*6f9703d0SDarrick J. Wong NULL 935*6f9703d0SDarrick J. Wong }; 936*6f9703d0SDarrick J. Wong 937*6f9703d0SDarrick J. Wong static int adt7470_attach_adapter(struct i2c_adapter *adapter) 938*6f9703d0SDarrick J. Wong { 939*6f9703d0SDarrick J. Wong if (!(adapter->class & I2C_CLASS_HWMON)) 940*6f9703d0SDarrick J. Wong return 0; 941*6f9703d0SDarrick J. Wong return i2c_probe(adapter, &addr_data, adt7470_detect); 942*6f9703d0SDarrick J. Wong } 943*6f9703d0SDarrick J. Wong 944*6f9703d0SDarrick J. Wong static int adt7470_detect(struct i2c_adapter *adapter, int address, int kind) 945*6f9703d0SDarrick J. Wong { 946*6f9703d0SDarrick J. Wong struct i2c_client *client; 947*6f9703d0SDarrick J. Wong struct adt7470_data *data; 948*6f9703d0SDarrick J. Wong int err = 0; 949*6f9703d0SDarrick J. Wong 950*6f9703d0SDarrick J. Wong if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) 951*6f9703d0SDarrick J. Wong goto exit; 952*6f9703d0SDarrick J. Wong 953*6f9703d0SDarrick J. Wong if (!(data = kzalloc(sizeof(struct adt7470_data), GFP_KERNEL))) { 954*6f9703d0SDarrick J. Wong err = -ENOMEM; 955*6f9703d0SDarrick J. Wong goto exit; 956*6f9703d0SDarrick J. Wong } 957*6f9703d0SDarrick J. Wong 958*6f9703d0SDarrick J. Wong client = &data->client; 959*6f9703d0SDarrick J. Wong client->addr = address; 960*6f9703d0SDarrick J. Wong client->adapter = adapter; 961*6f9703d0SDarrick J. Wong client->driver = &adt7470_driver; 962*6f9703d0SDarrick J. Wong 963*6f9703d0SDarrick J. Wong i2c_set_clientdata(client, data); 964*6f9703d0SDarrick J. Wong 965*6f9703d0SDarrick J. Wong mutex_init(&data->lock); 966*6f9703d0SDarrick J. Wong 967*6f9703d0SDarrick J. Wong if (kind <= 0) { 968*6f9703d0SDarrick J. Wong int vendor, device, revision; 969*6f9703d0SDarrick J. Wong 970*6f9703d0SDarrick J. Wong vendor = i2c_smbus_read_byte_data(client, ADT7470_REG_VENDOR); 971*6f9703d0SDarrick J. Wong if (vendor != ADT7470_VENDOR) { 972*6f9703d0SDarrick J. Wong err = -ENODEV; 973*6f9703d0SDarrick J. Wong goto exit_free; 974*6f9703d0SDarrick J. Wong } 975*6f9703d0SDarrick J. Wong 976*6f9703d0SDarrick J. Wong device = i2c_smbus_read_byte_data(client, ADT7470_REG_DEVICE); 977*6f9703d0SDarrick J. Wong if (device != ADT7470_DEVICE) { 978*6f9703d0SDarrick J. Wong err = -ENODEV; 979*6f9703d0SDarrick J. Wong goto exit_free; 980*6f9703d0SDarrick J. Wong } 981*6f9703d0SDarrick J. Wong 982*6f9703d0SDarrick J. Wong revision = i2c_smbus_read_byte_data(client, 983*6f9703d0SDarrick J. Wong ADT7470_REG_REVISION); 984*6f9703d0SDarrick J. Wong if (revision != ADT7470_REVISION) { 985*6f9703d0SDarrick J. Wong err = -ENODEV; 986*6f9703d0SDarrick J. Wong goto exit_free; 987*6f9703d0SDarrick J. Wong } 988*6f9703d0SDarrick J. Wong } else 989*6f9703d0SDarrick J. Wong dev_dbg(&adapter->dev, "detection forced\n"); 990*6f9703d0SDarrick J. Wong 991*6f9703d0SDarrick J. Wong strlcpy(client->name, "adt7470", I2C_NAME_SIZE); 992*6f9703d0SDarrick J. Wong 993*6f9703d0SDarrick J. Wong if ((err = i2c_attach_client(client))) 994*6f9703d0SDarrick J. Wong goto exit_free; 995*6f9703d0SDarrick J. Wong 996*6f9703d0SDarrick J. Wong dev_info(&client->dev, "%s chip found\n", client->name); 997*6f9703d0SDarrick J. Wong 998*6f9703d0SDarrick J. Wong /* Initialize the ADT7470 chip */ 999*6f9703d0SDarrick J. Wong adt7470_init_client(client); 1000*6f9703d0SDarrick J. Wong 1001*6f9703d0SDarrick J. Wong /* Register sysfs hooks */ 1002*6f9703d0SDarrick J. Wong data->attrs.attrs = adt7470_attr; 1003*6f9703d0SDarrick J. Wong if ((err = sysfs_create_group(&client->dev.kobj, &data->attrs))) 1004*6f9703d0SDarrick J. Wong goto exit_detach; 1005*6f9703d0SDarrick J. Wong 1006*6f9703d0SDarrick J. Wong data->class_dev = hwmon_device_register(&client->dev); 1007*6f9703d0SDarrick J. Wong if (IS_ERR(data->class_dev)) { 1008*6f9703d0SDarrick J. Wong err = PTR_ERR(data->class_dev); 1009*6f9703d0SDarrick J. Wong goto exit_remove; 1010*6f9703d0SDarrick J. Wong } 1011*6f9703d0SDarrick J. Wong 1012*6f9703d0SDarrick J. Wong return 0; 1013*6f9703d0SDarrick J. Wong 1014*6f9703d0SDarrick J. Wong exit_remove: 1015*6f9703d0SDarrick J. Wong sysfs_remove_group(&client->dev.kobj, &data->attrs); 1016*6f9703d0SDarrick J. Wong exit_detach: 1017*6f9703d0SDarrick J. Wong i2c_detach_client(client); 1018*6f9703d0SDarrick J. Wong exit_free: 1019*6f9703d0SDarrick J. Wong kfree(data); 1020*6f9703d0SDarrick J. Wong exit: 1021*6f9703d0SDarrick J. Wong return err; 1022*6f9703d0SDarrick J. Wong } 1023*6f9703d0SDarrick J. Wong 1024*6f9703d0SDarrick J. Wong static int adt7470_detach_client(struct i2c_client *client) 1025*6f9703d0SDarrick J. Wong { 1026*6f9703d0SDarrick J. Wong struct adt7470_data *data = i2c_get_clientdata(client); 1027*6f9703d0SDarrick J. Wong 1028*6f9703d0SDarrick J. Wong hwmon_device_unregister(data->class_dev); 1029*6f9703d0SDarrick J. Wong sysfs_remove_group(&client->dev.kobj, &data->attrs); 1030*6f9703d0SDarrick J. Wong i2c_detach_client(client); 1031*6f9703d0SDarrick J. Wong kfree(data); 1032*6f9703d0SDarrick J. Wong return 0; 1033*6f9703d0SDarrick J. Wong } 1034*6f9703d0SDarrick J. Wong 1035*6f9703d0SDarrick J. Wong static int __init adt7470_init(void) 1036*6f9703d0SDarrick J. Wong { 1037*6f9703d0SDarrick J. Wong return i2c_add_driver(&adt7470_driver); 1038*6f9703d0SDarrick J. Wong } 1039*6f9703d0SDarrick J. Wong 1040*6f9703d0SDarrick J. Wong static void __exit adt7470_exit(void) 1041*6f9703d0SDarrick J. Wong { 1042*6f9703d0SDarrick J. Wong i2c_del_driver(&adt7470_driver); 1043*6f9703d0SDarrick J. Wong } 1044*6f9703d0SDarrick J. Wong 1045*6f9703d0SDarrick J. Wong MODULE_AUTHOR("Darrick J. Wong <djwong@us.ibm.com>"); 1046*6f9703d0SDarrick J. Wong MODULE_DESCRIPTION("ADT7470 driver"); 1047*6f9703d0SDarrick J. Wong MODULE_LICENSE("GPL"); 1048*6f9703d0SDarrick J. Wong 1049*6f9703d0SDarrick J. Wong module_init(adt7470_init); 1050*6f9703d0SDarrick J. Wong module_exit(adt7470_exit); 1051