| 1 | /* |
|---|
| 2 | adm1031.c - Part of lm_sensors, Linux kernel modules for hardware |
|---|
| 3 | monitoring |
|---|
| 4 | Based on lm75.c and lm85.c |
|---|
| 5 | Supports Analog Devices ADM1030 and ADM1031 |
|---|
| 6 | Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org> |
|---|
| 7 | |
|---|
| 8 | This program is free software; you can redistribute it and/or modify |
|---|
| 9 | it under the terms of the GNU General Public License as published by |
|---|
| 10 | the Free Software Foundation; either version 2 of the License, or |
|---|
| 11 | (at your option) any later version. |
|---|
| 12 | |
|---|
| 13 | This program is distributed in the hope that it will be useful, |
|---|
| 14 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 16 | GNU General Public License for more details. |
|---|
| 17 | |
|---|
| 18 | You should have received a copy of the GNU General Public License |
|---|
| 19 | along with this program; if not, write to the Free Software |
|---|
| 20 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 21 | */ |
|---|
| 22 | |
|---|
| 23 | #include <linux/module.h> |
|---|
| 24 | #include <linux/init.h> |
|---|
| 25 | #include <linux/slab.h> |
|---|
| 26 | #include <linux/i2c.h> |
|---|
| 27 | #include <linux/i2c-proc.h> |
|---|
| 28 | #include "version.h" |
|---|
| 29 | |
|---|
| 30 | /* Following macros take channel parameter starting from 0 */ |
|---|
| 31 | #define ADM1031_REG_FAN_SPEED(nr) (0x08 + (nr)) |
|---|
| 32 | |
|---|
| 33 | #define ADM1031_REG_FAN_DIV(nr) (0x20 + (nr)) |
|---|
| 34 | #define ADM1031_REG_FAN_MIN(nr) (0x10 + (nr)) |
|---|
| 35 | |
|---|
| 36 | #define ADM1031_REG_TEMP_MAX(nr) (0x14 + 4 * (nr)) |
|---|
| 37 | #define ADM1031_REG_TEMP_MIN(nr) (0x15 + 4 * (nr)) |
|---|
| 38 | #define ADM1031_REG_TEMP_CRIT(nr) (0x16 + 4 * (nr)) |
|---|
| 39 | |
|---|
| 40 | #define ADM1031_REG_TEMP(nr) (0x0a + (nr)) |
|---|
| 41 | #define ADM1031_REG_AUTO_TEMP(nr) (0x24 + (nr)) |
|---|
| 42 | |
|---|
| 43 | #define ADM1031_REG_STATUS(nr) (0x02 + (nr)) |
|---|
| 44 | #define ADM1031_REG_FAN_PWM 0x22 |
|---|
| 45 | |
|---|
| 46 | #define ADM1031_REG_CONF1 0x00 |
|---|
| 47 | #define ADM1031_REG_CONF2 0x01 |
|---|
| 48 | #define ADM1031_REG_EXT_TEMP 0x06 |
|---|
| 49 | |
|---|
| 50 | #define ADM1031_CONF1_MONITOR_ENABLE 0x01 /* Monitoring enable */ |
|---|
| 51 | #define ADM1031_CONF1_PWM_INVERT 0x08 /* PWM Invert (unused) */ |
|---|
| 52 | #define ADM1031_CONF1_AUTO_MODE 0x80 /* Auto fan mode */ |
|---|
| 53 | |
|---|
| 54 | #define ADM1031_CONF2_PWM1_ENABLE 0x01 |
|---|
| 55 | #define ADM1031_CONF2_PWM2_ENABLE 0x02 |
|---|
| 56 | #define ADM1031_CONF2_TACH1_ENABLE 0x04 |
|---|
| 57 | #define ADM1031_CONF2_TACH2_ENABLE 0x08 |
|---|
| 58 | #define ADM1031_CONF2_TEMP_ENABLE(chan) (0x10 << (chan)) |
|---|
| 59 | |
|---|
| 60 | /* Addresses to scan */ |
|---|
| 61 | static unsigned short normal_i2c[] = { SENSORS_I2C_END }; |
|---|
| 62 | static unsigned short normal_i2c_range[] = { 0x2c, 0x2e, SENSORS_I2C_END }; |
|---|
| 63 | static unsigned int normal_isa[] = { SENSORS_ISA_END }; |
|---|
| 64 | static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; |
|---|
| 65 | |
|---|
| 66 | /* Insmod parameters */ |
|---|
| 67 | SENSORS_INSMOD_2(adm1030, adm1031); |
|---|
| 68 | |
|---|
| 69 | /* |
|---|
| 70 | * Proc entries |
|---|
| 71 | * These files are created for each detected ADM1031. |
|---|
| 72 | */ |
|---|
| 73 | |
|---|
| 74 | /* -- SENSORS SYSCTL START -- */ |
|---|
| 75 | |
|---|
| 76 | #define ADM1031_SYSCTL_TEMP1 1200 |
|---|
| 77 | #define ADM1031_SYSCTL_TEMP2 1201 |
|---|
| 78 | #define ADM1031_SYSCTL_TEMP3 1202 |
|---|
| 79 | |
|---|
| 80 | #define ADM1031_SYSCTL_FAN1 1210 |
|---|
| 81 | #define ADM1031_SYSCTL_FAN2 1211 |
|---|
| 82 | |
|---|
| 83 | #define ADM1031_SYSCTL_FAN_DIV 1220 |
|---|
| 84 | |
|---|
| 85 | #define ADM1031_SYSCTL_ALARMS 1250 |
|---|
| 86 | |
|---|
| 87 | #define ADM1031_ALARM_FAN1_MIN 0x0001 |
|---|
| 88 | #define ADM1031_ALARM_FAN1_FLT 0x0002 |
|---|
| 89 | #define ADM1031_ALARM_TEMP2_HIGH 0x0004 |
|---|
| 90 | #define ADM1031_ALARM_TEMP2_LOW 0x0008 |
|---|
| 91 | #define ADM1031_ALARM_TEMP2_CRIT 0x0010 |
|---|
| 92 | #define ADM1031_ALARM_TEMP2_DIODE 0x0020 |
|---|
| 93 | #define ADM1031_ALARM_TEMP1_HIGH 0x0040 |
|---|
| 94 | #define ADM1031_ALARM_TEMP1_LOW 0x0080 |
|---|
| 95 | #define ADM1031_ALARM_FAN2_MIN 0x0100 |
|---|
| 96 | #define ADM1031_ALARM_FAN2_FLT 0x0200 |
|---|
| 97 | #define ADM1031_ALARM_TEMP3_HIGH 0x0400 |
|---|
| 98 | #define ADM1031_ALARM_TEMP3_LOW 0x0800 |
|---|
| 99 | #define ADM1031_ALARM_TEMP3_CRIT 0x1000 |
|---|
| 100 | #define ADM1031_ALARM_TEMP3_DIODE 0x2000 |
|---|
| 101 | #define ADM1031_ALARM_TEMP1_CRIT 0x4000 |
|---|
| 102 | #define ADM1031_ALARM_THERMAL 0x8000 |
|---|
| 103 | |
|---|
| 104 | |
|---|
| 105 | /* -- SENSORS SYSCTL END -- */ |
|---|
| 106 | static void adm1031_alarms(struct i2c_client *client, int operation, |
|---|
| 107 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 108 | static void adm1031_temp(struct i2c_client *client, int operation, |
|---|
| 109 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 110 | static void adm1031_fan(struct i2c_client *client, int operation, |
|---|
| 111 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 112 | static void adm1031_fan_div(struct i2c_client *client, int operation, |
|---|
| 113 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 114 | |
|---|
| 115 | static ctl_table adm1031_dir_table_template[] = { |
|---|
| 116 | {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, |
|---|
| 117 | &i2c_proc_real, |
|---|
| 118 | &i2c_sysctl_real, NULL, &adm1031_temp}, |
|---|
| 119 | {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, |
|---|
| 120 | &i2c_proc_real, |
|---|
| 121 | &i2c_sysctl_real, NULL, &adm1031_temp}, |
|---|
| 122 | {ADM1031_SYSCTL_TEMP3, "temp3", NULL, 0, 0644, NULL, |
|---|
| 123 | &i2c_proc_real, |
|---|
| 124 | &i2c_sysctl_real, NULL, &adm1031_temp}, |
|---|
| 125 | {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, |
|---|
| 126 | &i2c_proc_real, |
|---|
| 127 | &i2c_sysctl_real, NULL, &adm1031_fan}, |
|---|
| 128 | {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, |
|---|
| 129 | &i2c_proc_real, |
|---|
| 130 | &i2c_sysctl_real, NULL, &adm1031_fan_div}, |
|---|
| 131 | {ADM1031_SYSCTL_FAN2, "fan2", NULL, 0, 0644, NULL, |
|---|
| 132 | &i2c_proc_real, |
|---|
| 133 | &i2c_sysctl_real, NULL, &adm1031_fan}, |
|---|
| 134 | {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, |
|---|
| 135 | &i2c_proc_real, |
|---|
| 136 | &i2c_sysctl_real, NULL, &adm1031_alarms}, |
|---|
| 137 | {0} |
|---|
| 138 | }; |
|---|
| 139 | |
|---|
| 140 | static ctl_table adm1030_dir_table_template[] = { |
|---|
| 141 | {ADM1031_SYSCTL_TEMP1, "temp1", NULL, 0, 0644, NULL, |
|---|
| 142 | &i2c_proc_real, |
|---|
| 143 | &i2c_sysctl_real, NULL, &adm1031_temp}, |
|---|
| 144 | {ADM1031_SYSCTL_TEMP2, "temp2", NULL, 0, 0644, NULL, |
|---|
| 145 | &i2c_proc_real, |
|---|
| 146 | &i2c_sysctl_real, NULL, &adm1031_temp}, |
|---|
| 147 | {ADM1031_SYSCTL_FAN1, "fan1", NULL, 0, 0644, NULL, |
|---|
| 148 | &i2c_proc_real, |
|---|
| 149 | &i2c_sysctl_real, NULL, &adm1031_fan}, |
|---|
| 150 | {ADM1031_SYSCTL_FAN_DIV, "fan_div", NULL, 0, 0644, NULL, |
|---|
| 151 | &i2c_proc_real, |
|---|
| 152 | &i2c_sysctl_real, NULL, &adm1031_fan_div}, |
|---|
| 153 | {ADM1031_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, |
|---|
| 154 | &i2c_proc_real, |
|---|
| 155 | &i2c_sysctl_real, NULL, &adm1031_alarms}, |
|---|
| 156 | {0} |
|---|
| 157 | }; |
|---|
| 158 | |
|---|
| 159 | |
|---|
| 160 | /* Each client has this additional data */ |
|---|
| 161 | struct adm1031_data { |
|---|
| 162 | struct i2c_client client; |
|---|
| 163 | int sysctl_id; |
|---|
| 164 | struct semaphore update_lock; |
|---|
| 165 | int chip_type; |
|---|
| 166 | char valid; /* !=0 if following fields are valid */ |
|---|
| 167 | unsigned long last_updated; /* In jiffies */ |
|---|
| 168 | |
|---|
| 169 | u16 alarms; |
|---|
| 170 | u8 conf1; |
|---|
| 171 | u8 conf2; |
|---|
| 172 | u8 fan[2]; |
|---|
| 173 | u8 fan_min[2]; |
|---|
| 174 | u8 fan_pwm[2]; |
|---|
| 175 | u8 fan_div[2]; |
|---|
| 176 | s8 temp[3]; |
|---|
| 177 | u8 auto_temp[3]; |
|---|
| 178 | u8 ext_temp[3]; |
|---|
| 179 | s8 temp_min[3]; |
|---|
| 180 | s8 temp_max[3]; |
|---|
| 181 | s8 temp_crit[3]; |
|---|
| 182 | }; |
|---|
| 183 | |
|---|
| 184 | static int adm1031_attach_adapter(struct i2c_adapter *adapter); |
|---|
| 185 | static int adm1031_detect(struct i2c_adapter *adapter, int address, |
|---|
| 186 | unsigned short flags, int kind); |
|---|
| 187 | static void adm1031_init_client(struct i2c_client *client); |
|---|
| 188 | static int adm1031_detach_client(struct i2c_client *client); |
|---|
| 189 | |
|---|
| 190 | static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg); |
|---|
| 191 | static inline int adm1031_write_value(struct i2c_client *client, u8 reg, |
|---|
| 192 | unsigned int value); |
|---|
| 193 | |
|---|
| 194 | static void adm1031_update_client(struct i2c_client *client); |
|---|
| 195 | |
|---|
| 196 | /* This is the driver that will be inserted */ |
|---|
| 197 | static struct i2c_driver adm1031_driver = { |
|---|
| 198 | .owner = THIS_MODULE, |
|---|
| 199 | .name = "ADM1031/ADM1030 sensor driver", |
|---|
| 200 | .flags = I2C_DF_NOTIFY, |
|---|
| 201 | .attach_adapter = adm1031_attach_adapter, |
|---|
| 202 | .detach_client = adm1031_detach_client, |
|---|
| 203 | }; |
|---|
| 204 | |
|---|
| 205 | static int adm1031_id = 0; |
|---|
| 206 | |
|---|
| 207 | #define TEMP_TO_REG(val) ((val) < 0 ? (((val) - 500) / 1000) : \ |
|---|
| 208 | (((val) + 500) / 1000)) |
|---|
| 209 | |
|---|
| 210 | #define TEMP_FROM_REG(val) ((val) * 1000) |
|---|
| 211 | |
|---|
| 212 | #define TEMP_FROM_REG_EXT(val,ext) (TEMP_FROM_REG(val) + (ext) * 125) |
|---|
| 213 | |
|---|
| 214 | #define FAN_FROM_REG(reg,div) ((reg) ? \ |
|---|
| 215 | (11250 * 60) / ((reg) * (div)) : 0) |
|---|
| 216 | |
|---|
| 217 | #define FAN_TO_REG(reg,div) FAN_FROM_REG(SENSORS_LIMIT(reg, 0, \ |
|---|
| 218 | 65535), div) |
|---|
| 219 | |
|---|
| 220 | #define FAN_DIV_TO_REG(val) ((val) == 8 ? 0xc0 : \ |
|---|
| 221 | (val) == 4 ? 0x80 : \ |
|---|
| 222 | (val) == 1 ? 0x00 : 0x40) |
|---|
| 223 | |
|---|
| 224 | #define FAN_DIV_FROM_REG(reg) (1 << (((reg)&0xc0) >> 6)) |
|---|
| 225 | |
|---|
| 226 | #define AUTO_TEMP_OFF_FROM_REG(reg) (((((reg) >> 3) & 0x1f) << 2) - 5) |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | static int adm1031_attach_adapter(struct i2c_adapter *adapter) |
|---|
| 230 | { |
|---|
| 231 | return i2c_detect(adapter, &addr_data, adm1031_detect); |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | /* This function is called by i2c_detect */ |
|---|
| 235 | static int |
|---|
| 236 | adm1031_detect(struct i2c_adapter *adapter, int address, |
|---|
| 237 | unsigned short flags, int kind) |
|---|
| 238 | { |
|---|
| 239 | struct i2c_client *new_client; |
|---|
| 240 | struct adm1031_data *data; |
|---|
| 241 | int err = 0; |
|---|
| 242 | const char *type_name = ""; |
|---|
| 243 | const char *client_name = ""; |
|---|
| 244 | |
|---|
| 245 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) |
|---|
| 246 | goto exit; |
|---|
| 247 | |
|---|
| 248 | if (!(data = kmalloc(sizeof(struct adm1031_data), GFP_KERNEL))) { |
|---|
| 249 | err = -ENOMEM; |
|---|
| 250 | goto exit; |
|---|
| 251 | } |
|---|
| 252 | memset(data, 0, sizeof(struct adm1031_data)); |
|---|
| 253 | |
|---|
| 254 | new_client = &data->client; |
|---|
| 255 | new_client->data = data; |
|---|
| 256 | new_client->addr = address; |
|---|
| 257 | new_client->adapter = adapter; |
|---|
| 258 | new_client->driver = &adm1031_driver; |
|---|
| 259 | new_client->flags = 0; |
|---|
| 260 | |
|---|
| 261 | if (kind < 0) { |
|---|
| 262 | int id, co; |
|---|
| 263 | id = i2c_smbus_read_byte_data(new_client, 0x3d); |
|---|
| 264 | co = i2c_smbus_read_byte_data(new_client, 0x3e); |
|---|
| 265 | |
|---|
| 266 | if (((id != 0x31) || (id != 0x30)) && (co != 0x41)) |
|---|
| 267 | goto exit_free; |
|---|
| 268 | kind = (id == 0x30) ? adm1030 : adm1031; |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | if (kind <= 0) |
|---|
| 272 | kind = adm1031; |
|---|
| 273 | |
|---|
| 274 | /* Given the detected chip type, set the chip name and the |
|---|
| 275 | * auto fan control helper table. */ |
|---|
| 276 | if (kind == adm1030) { |
|---|
| 277 | type_name = "adm1030"; |
|---|
| 278 | client_name = "ADM1030 chip"; |
|---|
| 279 | |
|---|
| 280 | } else if (kind == adm1031) { |
|---|
| 281 | type_name = "adm1031"; |
|---|
| 282 | client_name = "ADM1031 chip"; |
|---|
| 283 | } |
|---|
| 284 | data->chip_type = kind; |
|---|
| 285 | |
|---|
| 286 | strcpy(new_client->name, client_name); |
|---|
| 287 | |
|---|
| 288 | new_client->id = adm1031_id++; |
|---|
| 289 | data->valid = 0; |
|---|
| 290 | init_MUTEX(&data->update_lock); |
|---|
| 291 | |
|---|
| 292 | /* Tell the I2C layer a new client has arrived */ |
|---|
| 293 | if ((err = i2c_attach_client(new_client))) |
|---|
| 294 | goto exit_free; |
|---|
| 295 | |
|---|
| 296 | |
|---|
| 297 | if (kind == adm1030) { |
|---|
| 298 | if ((err = i2c_register_entry(new_client, type_name, |
|---|
| 299 | adm1030_dir_table_template)) < 0) |
|---|
| 300 | goto exit_detach; |
|---|
| 301 | } else if (kind == adm1031) { |
|---|
| 302 | if ((err = i2c_register_entry(new_client, type_name, |
|---|
| 303 | adm1031_dir_table_template)) < 0) |
|---|
| 304 | goto exit_detach; |
|---|
| 305 | } |
|---|
| 306 | |
|---|
| 307 | data->sysctl_id = err; |
|---|
| 308 | |
|---|
| 309 | /* Initialize the ADM1031 chip */ |
|---|
| 310 | adm1031_init_client(new_client); |
|---|
| 311 | |
|---|
| 312 | return 0; |
|---|
| 313 | |
|---|
| 314 | exit_detach: |
|---|
| 315 | i2c_detach_client(new_client); |
|---|
| 316 | exit_free: |
|---|
| 317 | kfree(new_client); |
|---|
| 318 | exit: |
|---|
| 319 | return err; |
|---|
| 320 | } |
|---|
| 321 | |
|---|
| 322 | static int adm1031_detach_client(struct i2c_client *client) |
|---|
| 323 | { |
|---|
| 324 | int ret; |
|---|
| 325 | struct adm1031_data *data = client->data; |
|---|
| 326 | |
|---|
| 327 | i2c_deregister_entry(data->sysctl_id); |
|---|
| 328 | if ((ret = i2c_detach_client(client)) != 0) { |
|---|
| 329 | return ret; |
|---|
| 330 | } |
|---|
| 331 | |
|---|
| 332 | kfree(client); |
|---|
| 333 | return 0; |
|---|
| 334 | } |
|---|
| 335 | |
|---|
| 336 | static inline u8 adm1031_read_value(struct i2c_client *client, u8 reg) |
|---|
| 337 | { |
|---|
| 338 | return i2c_smbus_read_byte_data(client, reg); |
|---|
| 339 | } |
|---|
| 340 | |
|---|
| 341 | static inline int adm1031_write_value(struct i2c_client *client, u8 reg, |
|---|
| 342 | unsigned int value) |
|---|
| 343 | { |
|---|
| 344 | return i2c_smbus_write_byte_data(client, reg, value); |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | static void adm1031_init_client(struct i2c_client *client) |
|---|
| 348 | { |
|---|
| 349 | unsigned int read_val; |
|---|
| 350 | unsigned int mask; |
|---|
| 351 | struct adm1031_data *data = client->data; |
|---|
| 352 | |
|---|
| 353 | mask = (ADM1031_CONF2_PWM1_ENABLE | ADM1031_CONF2_TACH1_ENABLE); |
|---|
| 354 | if (data->chip_type == adm1031) { |
|---|
| 355 | mask |= (ADM1031_CONF2_PWM2_ENABLE | |
|---|
| 356 | ADM1031_CONF2_TACH2_ENABLE); |
|---|
| 357 | } |
|---|
| 358 | /* Initialize the ADM1031 chip (enable fan speed reading) */ |
|---|
| 359 | read_val = adm1031_read_value(client, ADM1031_REG_CONF2); |
|---|
| 360 | if ((read_val | mask) != read_val) { |
|---|
| 361 | adm1031_write_value(client, ADM1031_REG_CONF2, |
|---|
| 362 | read_val | mask); |
|---|
| 363 | } |
|---|
| 364 | |
|---|
| 365 | read_val = adm1031_read_value(client, ADM1031_REG_CONF1); |
|---|
| 366 | if ((read_val | ADM1031_CONF1_MONITOR_ENABLE) != read_val) { |
|---|
| 367 | adm1031_write_value(client, ADM1031_REG_CONF1, read_val | |
|---|
| 368 | ADM1031_CONF1_MONITOR_ENABLE); |
|---|
| 369 | } |
|---|
| 370 | } |
|---|
| 371 | |
|---|
| 372 | static void adm1031_update_client(struct i2c_client *client) |
|---|
| 373 | { |
|---|
| 374 | struct adm1031_data *data = client->data; |
|---|
| 375 | int chan; |
|---|
| 376 | |
|---|
| 377 | down(&data->update_lock); |
|---|
| 378 | |
|---|
| 379 | if ((jiffies - data->last_updated > HZ + HZ / 2) || |
|---|
| 380 | (jiffies < data->last_updated) || !data->valid) { |
|---|
| 381 | #ifdef DEBUG |
|---|
| 382 | printk(KERN_INFO "adm1031.o: Starting chip update\n"); |
|---|
| 383 | #endif |
|---|
| 384 | for (chan = 0; |
|---|
| 385 | chan < ((data->chip_type == adm1031) ? 3 : 2); |
|---|
| 386 | chan++) { |
|---|
| 387 | u8 oldh, newh; |
|---|
| 388 | |
|---|
| 389 | oldh = adm1031_read_value(client, |
|---|
| 390 | ADM1031_REG_TEMP(chan)); |
|---|
| 391 | data->ext_temp[chan] = adm1031_read_value(client, |
|---|
| 392 | ADM1031_REG_EXT_TEMP); |
|---|
| 393 | newh = adm1031_read_value(client, |
|---|
| 394 | ADM1031_REG_TEMP(chan)); |
|---|
| 395 | if (newh != oldh) { |
|---|
| 396 | data->ext_temp[chan] = adm1031_read_value(client, |
|---|
| 397 | ADM1031_REG_EXT_TEMP); |
|---|
| 398 | #ifdef DEBUG |
|---|
| 399 | oldh = adm1031_read_value(client, |
|---|
| 400 | ADM1031_REG_TEMP(chan)); |
|---|
| 401 | |
|---|
| 402 | /* oldh is actually newer */ |
|---|
| 403 | if (newh != oldh) |
|---|
| 404 | printk(KERN_INFO "adm1031.o: Remote " |
|---|
| 405 | "temperature may be wrong.\n"); |
|---|
| 406 | #endif |
|---|
| 407 | } |
|---|
| 408 | data->temp[chan] = newh; |
|---|
| 409 | |
|---|
| 410 | data->temp_min[chan] = adm1031_read_value(client, |
|---|
| 411 | ADM1031_REG_TEMP_MIN(chan)); |
|---|
| 412 | data->temp_max[chan] = adm1031_read_value(client, |
|---|
| 413 | ADM1031_REG_TEMP_MAX(chan)); |
|---|
| 414 | data->temp_crit[chan] = adm1031_read_value(client, |
|---|
| 415 | ADM1031_REG_TEMP_CRIT(chan)); |
|---|
| 416 | data->auto_temp[chan] = adm1031_read_value(client, |
|---|
| 417 | ADM1031_REG_AUTO_TEMP(chan)); |
|---|
| 418 | } |
|---|
| 419 | |
|---|
| 420 | data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); |
|---|
| 421 | |
|---|
| 422 | data->alarms = adm1031_read_value(client, ADM1031_REG_STATUS(0)) |
|---|
| 423 | | (adm1031_read_value(client, ADM1031_REG_STATUS(1)) |
|---|
| 424 | << 8); |
|---|
| 425 | if (data->chip_type == adm1030) { |
|---|
| 426 | data->alarms &= 0xc0ff; |
|---|
| 427 | } |
|---|
| 428 | |
|---|
| 429 | for (chan = 0; |
|---|
| 430 | chan < (data->chip_type == adm1030 ? 1 : 2); |
|---|
| 431 | chan++) { |
|---|
| 432 | data->fan_div[chan] = adm1031_read_value(client, |
|---|
| 433 | ADM1031_REG_FAN_DIV(chan)); |
|---|
| 434 | data->fan_min[chan] = adm1031_read_value(client, |
|---|
| 435 | ADM1031_REG_FAN_MIN(chan)); |
|---|
| 436 | data->fan[chan] = adm1031_read_value(client, |
|---|
| 437 | ADM1031_REG_FAN_SPEED(chan)); |
|---|
| 438 | data->fan_pwm[chan] = (adm1031_read_value(client, |
|---|
| 439 | ADM1031_REG_FAN_PWM) >> (4 * chan)) |
|---|
| 440 | & 0x0f; |
|---|
| 441 | } |
|---|
| 442 | |
|---|
| 443 | data->conf1 = adm1031_read_value(client, ADM1031_REG_CONF1); |
|---|
| 444 | data->conf2 = adm1031_read_value(client, ADM1031_REG_CONF2); |
|---|
| 445 | |
|---|
| 446 | data->last_updated = jiffies; |
|---|
| 447 | data->valid = 1; |
|---|
| 448 | } |
|---|
| 449 | |
|---|
| 450 | up(&data->update_lock); |
|---|
| 451 | } |
|---|
| 452 | |
|---|
| 453 | static int __init sensors_adm1031_init(void) |
|---|
| 454 | { |
|---|
| 455 | printk(KERN_INFO "adm1031.o version %s (%s)\n", LM_VERSION, LM_DATE); |
|---|
| 456 | return i2c_add_driver(&adm1031_driver); |
|---|
| 457 | } |
|---|
| 458 | |
|---|
| 459 | static void __exit sensors_adm1031_exit(void) |
|---|
| 460 | { |
|---|
| 461 | i2c_del_driver(&adm1031_driver); |
|---|
| 462 | } |
|---|
| 463 | |
|---|
| 464 | |
|---|
| 465 | static void |
|---|
| 466 | adm1031_temp(struct i2c_client *client, int operation, int ctl_name, |
|---|
| 467 | int *nrels_mag, long *results) |
|---|
| 468 | { |
|---|
| 469 | int ext; |
|---|
| 470 | struct adm1031_data *data = client->data; |
|---|
| 471 | int tmp; |
|---|
| 472 | int nr = ctl_name - ADM1031_SYSCTL_TEMP1; |
|---|
| 473 | |
|---|
| 474 | ext = nr == 0 ? |
|---|
| 475 | ((data->ext_temp[nr] >> 6) & 0x3) * 2 : |
|---|
| 476 | (((data->ext_temp[nr] >> ((nr - 1) * 3)) & 7)); |
|---|
| 477 | |
|---|
| 478 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 479 | *nrels_mag = 3; |
|---|
| 480 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 481 | adm1031_update_client(client); |
|---|
| 482 | results[0] = TEMP_FROM_REG(data->temp_max[nr]); |
|---|
| 483 | results[1] = TEMP_FROM_REG(data->temp_min[nr]); |
|---|
| 484 | results[2] = TEMP_FROM_REG(data->temp_crit[nr]); |
|---|
| 485 | results[3] = TEMP_FROM_REG_EXT(data->temp[nr], ext); |
|---|
| 486 | *nrels_mag = 4; |
|---|
| 487 | } else if (operation == SENSORS_PROC_REAL_WRITE) { |
|---|
| 488 | if (*nrels_mag >= 1) { |
|---|
| 489 | tmp = SENSORS_LIMIT(results[0], -55000, 127000); |
|---|
| 490 | data->temp_max[nr] = TEMP_TO_REG(tmp); |
|---|
| 491 | adm1031_write_value(client, |
|---|
| 492 | ADM1031_REG_TEMP_MAX(nr), |
|---|
| 493 | data->temp_max[nr]); |
|---|
| 494 | } |
|---|
| 495 | if (*nrels_mag >= 2) { |
|---|
| 496 | tmp = SENSORS_LIMIT(results[1], -55000, 127000); |
|---|
| 497 | data->temp_min[nr] = TEMP_TO_REG(tmp); |
|---|
| 498 | adm1031_write_value(client, |
|---|
| 499 | ADM1031_REG_TEMP_MIN(nr), |
|---|
| 500 | data->temp_min[nr]); |
|---|
| 501 | } |
|---|
| 502 | if (*nrels_mag >= 3) { |
|---|
| 503 | tmp = SENSORS_LIMIT(results[2], -55000, 127000); |
|---|
| 504 | data->temp_crit[nr] = TEMP_TO_REG(tmp); |
|---|
| 505 | adm1031_write_value(client, |
|---|
| 506 | ADM1031_REG_TEMP_CRIT(nr), |
|---|
| 507 | data->temp_crit[nr]); |
|---|
| 508 | } |
|---|
| 509 | } |
|---|
| 510 | } |
|---|
| 511 | |
|---|
| 512 | /* |
|---|
| 513 | * That function checks the cases where the fan reading is not |
|---|
| 514 | * relevant. It is used to provide 0 as fan reading when the fan is |
|---|
| 515 | * not supposed to run. |
|---|
| 516 | */ |
|---|
| 517 | static int trust_fan_readings(struct adm1031_data * data, int chan) |
|---|
| 518 | { |
|---|
| 519 | int res = 0; |
|---|
| 520 | |
|---|
| 521 | if (data->conf1 & ADM1031_CONF1_AUTO_MODE) { |
|---|
| 522 | switch(data->conf1 & 0x60) { |
|---|
| 523 | case 0x00: /* remote temp1 controls fan1 remote temp2 |
|---|
| 524 | controls fan2 */ |
|---|
| 525 | res = chan == 0 ? data->temp[1] > |
|---|
| 526 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[1]) : |
|---|
| 527 | data->temp[2] > |
|---|
| 528 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[2]); |
|---|
| 529 | break; |
|---|
| 530 | case 0x20: /* remote temp1 controls both fans*/ |
|---|
| 531 | if (data->chip_type == adm1030) |
|---|
| 532 | res = 0; |
|---|
| 533 | else |
|---|
| 534 | res = data->temp[1] > |
|---|
| 535 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[1]); |
|---|
| 536 | break; |
|---|
| 537 | case 0x40: /* remote temp2 controls both fans*/ |
|---|
| 538 | if (data->chip_type == adm1030) |
|---|
| 539 | res = 0; |
|---|
| 540 | else |
|---|
| 541 | res = data->temp[2] > |
|---|
| 542 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[2]); |
|---|
| 543 | break; |
|---|
| 544 | case 0x60: /* max controls both fans */ |
|---|
| 545 | if (data->chip_type == adm1030){ |
|---|
| 546 | res = data->temp[0] > |
|---|
| 547 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[0]) |
|---|
| 548 | || data->temp[1] > |
|---|
| 549 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[1]); |
|---|
| 550 | } else { |
|---|
| 551 | res = data->temp[0] > |
|---|
| 552 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[0]) |
|---|
| 553 | || data->temp[1] > |
|---|
| 554 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[1]) |
|---|
| 555 | || data->temp[2] > |
|---|
| 556 | AUTO_TEMP_OFF_FROM_REG(data->auto_temp[2]); |
|---|
| 557 | } |
|---|
| 558 | break; |
|---|
| 559 | default: |
|---|
| 560 | res = 0; |
|---|
| 561 | break; |
|---|
| 562 | } |
|---|
| 563 | } else { |
|---|
| 564 | res = data->fan_pwm[chan] > 0; |
|---|
| 565 | } |
|---|
| 566 | |
|---|
| 567 | return res; |
|---|
| 568 | } |
|---|
| 569 | |
|---|
| 570 | static void adm1031_fan(struct i2c_client *client, int operation, |
|---|
| 571 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 572 | { |
|---|
| 573 | struct adm1031_data *data = client->data; |
|---|
| 574 | int nr = ctl_name - ADM1031_SYSCTL_FAN1; |
|---|
| 575 | |
|---|
| 576 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 577 | *nrels_mag = 0; |
|---|
| 578 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 579 | adm1031_update_client(client); |
|---|
| 580 | results[0] = FAN_FROM_REG(data->fan_min[nr], |
|---|
| 581 | FAN_DIV_FROM_REG(data->fan_div[nr])); |
|---|
| 582 | results[1] = trust_fan_readings(data, nr) ? |
|---|
| 583 | FAN_FROM_REG(data->fan[nr], |
|---|
| 584 | FAN_DIV_FROM_REG(data->fan_div[nr])) : 0; |
|---|
| 585 | *nrels_mag = 2; |
|---|
| 586 | } else if (operation == SENSORS_PROC_REAL_WRITE) { |
|---|
| 587 | if (*nrels_mag >= 1) { |
|---|
| 588 | data->fan_min[nr] = FAN_TO_REG(results[0], |
|---|
| 589 | FAN_DIV_FROM_REG(data->fan_div[nr])); |
|---|
| 590 | adm1031_write_value(client, |
|---|
| 591 | ADM1031_REG_FAN_MIN(nr), |
|---|
| 592 | data->fan_min[nr]); |
|---|
| 593 | } |
|---|
| 594 | } |
|---|
| 595 | } |
|---|
| 596 | |
|---|
| 597 | static void adm1031_fan_div(struct i2c_client *client, int operation, |
|---|
| 598 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 599 | { |
|---|
| 600 | struct adm1031_data *data = client->data; |
|---|
| 601 | |
|---|
| 602 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 603 | *nrels_mag = 0; |
|---|
| 604 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 605 | adm1031_update_client(client); |
|---|
| 606 | results[0] = FAN_DIV_FROM_REG(data->fan_div[0]); |
|---|
| 607 | *nrels_mag = 1; |
|---|
| 608 | if(data->chip_type == adm1031) { |
|---|
| 609 | results[1] = FAN_DIV_FROM_REG(data->fan_div[1]); |
|---|
| 610 | *nrels_mag = 2; |
|---|
| 611 | } |
|---|
| 612 | } else if (operation == SENSORS_PROC_REAL_WRITE) { |
|---|
| 613 | int old_div, new_min; |
|---|
| 614 | if (*nrels_mag >= 1) { |
|---|
| 615 | old_div = FAN_DIV_FROM_REG(data->fan_div[0]); |
|---|
| 616 | data->fan_div[0] = FAN_DIV_TO_REG(results[0]); |
|---|
| 617 | adm1031_write_value(client, |
|---|
| 618 | ADM1031_REG_FAN_DIV(0), |
|---|
| 619 | data->fan_div[0]); |
|---|
| 620 | new_min = data->fan_min[0] * old_div / |
|---|
| 621 | FAN_DIV_FROM_REG(data->fan_div[0]); |
|---|
| 622 | data->fan_min[0] = new_min > 0xff ? 0xff : new_min; |
|---|
| 623 | adm1031_write_value(client, |
|---|
| 624 | ADM1031_REG_FAN_MIN(0), |
|---|
| 625 | data->fan_min[0]); |
|---|
| 626 | } |
|---|
| 627 | if (*nrels_mag >= 2) { |
|---|
| 628 | old_div = FAN_DIV_FROM_REG(data->fan_div[1]); |
|---|
| 629 | data->fan_div[1] = FAN_DIV_TO_REG(results[1]); |
|---|
| 630 | adm1031_write_value(client, |
|---|
| 631 | ADM1031_REG_FAN_DIV(1), |
|---|
| 632 | data->fan_div[1]); |
|---|
| 633 | new_min = data->fan_min[1] * old_div / |
|---|
| 634 | FAN_DIV_FROM_REG(data->fan_div[1]); |
|---|
| 635 | data->fan_min[1] = new_min > 0xff ? 0xff : new_min; |
|---|
| 636 | adm1031_write_value(client, |
|---|
| 637 | ADM1031_REG_FAN_MIN(1), |
|---|
| 638 | data->fan_min[1]); |
|---|
| 639 | } |
|---|
| 640 | } |
|---|
| 641 | } |
|---|
| 642 | |
|---|
| 643 | static void adm1031_alarms(struct i2c_client *client, int operation, |
|---|
| 644 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 645 | { |
|---|
| 646 | struct adm1031_data *data = client->data; |
|---|
| 647 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 648 | *nrels_mag = 0; |
|---|
| 649 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 650 | adm1031_update_client(client); |
|---|
| 651 | results[0] = data->alarms; |
|---|
| 652 | *nrels_mag = 1; |
|---|
| 653 | } |
|---|
| 654 | } |
|---|
| 655 | |
|---|
| 656 | MODULE_AUTHOR("Alexandre d'Alton <alex@alexdalton.org>"); |
|---|
| 657 | MODULE_DESCRIPTION("ADM1031/ADM1030 driver"); |
|---|
| 658 | MODULE_LICENSE("GPL"); |
|---|
| 659 | |
|---|
| 660 | module_init(sensors_adm1031_init); |
|---|
| 661 | module_exit(sensors_adm1031_exit); |
|---|