| 1 | /* |
|---|
| 2 | * max1619.c - Part of lm_sensors, Linux kernel modules for hardware |
|---|
| 3 | * monitoring |
|---|
| 4 | * Copyright (C) 2004 Alexey Fisher <fishor@mail.ru> |
|---|
| 5 | * Jean Delvare <khali@linux-fr.org> |
|---|
| 6 | * |
|---|
| 7 | * Copied from lm90.c: |
|---|
| 8 | * Copyright (C) 2003-2004 Jean Delvare <khali@linux-fr.org> |
|---|
| 9 | * |
|---|
| 10 | * The MAX1619 is a sensor chip made by Maxim. It reports up to two |
|---|
| 11 | * temperatures (its own plus up to one external one). |
|---|
| 12 | * Complete datasheet can be obtained from Maxim's website at: |
|---|
| 13 | * http://pdfserv.maxim-ic.com/en/ds/MAX1619.pdf |
|---|
| 14 | * |
|---|
| 15 | * This program is free software; you can redistribute it and/or modify |
|---|
| 16 | * it under the terms of the GNU General Public License as published by |
|---|
| 17 | * the Free Software Foundation; either version 2 of the License, or |
|---|
| 18 | * (at your option) any later version. |
|---|
| 19 | * |
|---|
| 20 | * This program is distributed in the hope that it will be useful, |
|---|
| 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 23 | * GNU General Public License for more details. |
|---|
| 24 | * |
|---|
| 25 | * You should have received a copy of the GNU General Public License |
|---|
| 26 | * along with this program; if not, write to the Free Software |
|---|
| 27 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
|---|
| 28 | */ |
|---|
| 29 | |
|---|
| 30 | #include <linux/module.h> |
|---|
| 31 | #include <linux/slab.h> |
|---|
| 32 | #include <linux/i2c.h> |
|---|
| 33 | #include <linux/i2c-proc.h> |
|---|
| 34 | #include <linux/init.h> |
|---|
| 35 | #include "version.h" |
|---|
| 36 | |
|---|
| 37 | /* |
|---|
| 38 | * Addresses to scan |
|---|
| 39 | */ |
|---|
| 40 | |
|---|
| 41 | static unsigned short normal_i2c[] = { SENSORS_I2C_END }; |
|---|
| 42 | static unsigned short normal_i2c_range[] = {0x18, 0x1a, 0x29, 0x2b, |
|---|
| 43 | 0x4c, 0x4e, SENSORS_I2C_END }; |
|---|
| 44 | static unsigned int normal_isa[] = { SENSORS_ISA_END }; |
|---|
| 45 | static unsigned int normal_isa_range[] = { SENSORS_ISA_END }; |
|---|
| 46 | |
|---|
| 47 | /* |
|---|
| 48 | * Insmod parameters |
|---|
| 49 | */ |
|---|
| 50 | |
|---|
| 51 | SENSORS_INSMOD_1(max1619); |
|---|
| 52 | |
|---|
| 53 | /* |
|---|
| 54 | * The max1619 registers |
|---|
| 55 | */ |
|---|
| 56 | |
|---|
| 57 | #define MAX1619_REG_R_CONFIG 0x03 |
|---|
| 58 | #define MAX1619_REG_W_CONFIG 0x09 |
|---|
| 59 | #define MAX1619_REG_R_CONVRATE 0x04 |
|---|
| 60 | #define MAX1619_REG_W_CONVRATE 0x0A |
|---|
| 61 | #define MAX1619_REG_R_STATUS 0x02 |
|---|
| 62 | #define MAX1619_REG_R_LOCAL_TEMP 0x00 |
|---|
| 63 | #define MAX1619_REG_R_REMOTE_TEMP 0x01 |
|---|
| 64 | #define MAX1619_REG_R_REMOTE_THIGH 0x07 |
|---|
| 65 | #define MAX1619_REG_W_REMOTE_THIGH 0x0d |
|---|
| 66 | #define MAX1619_REG_R_REMOTE_TLOW 0x08 |
|---|
| 67 | #define MAX1619_REG_W_REMOTE_TLOW 0x0E |
|---|
| 68 | #define MAX1619_REG_R_REMOTE_TMAX 0x10 |
|---|
| 69 | #define MAX1619_REG_W_REMOTE_TMAX 0x12 |
|---|
| 70 | #define MAX1619_REG_R_REMOTE_THYST 0x11 |
|---|
| 71 | #define MAX1619_REG_W_REMOTE_THYST 0x13 |
|---|
| 72 | #define MAX1619_REG_R_MAN_ID 0xFE |
|---|
| 73 | #define MAX1619_REG_R_CHIP_ID 0xFF |
|---|
| 74 | |
|---|
| 75 | /* |
|---|
| 76 | * Conversions and various macros |
|---|
| 77 | */ |
|---|
| 78 | |
|---|
| 79 | #define TEMP_FROM_REG(val) ((val) & 0x80 ? (val)-0x100 : (val)) |
|---|
| 80 | #define TEMP_TO_REG(val) ((val) < 0 ? (val)+0x100 : (val)) |
|---|
| 81 | |
|---|
| 82 | /* |
|---|
| 83 | * Functions declaration |
|---|
| 84 | */ |
|---|
| 85 | |
|---|
| 86 | static int max1619_attach_adapter(struct i2c_adapter *adapter); |
|---|
| 87 | static int max1619_detect(struct i2c_adapter *adapter, int address, |
|---|
| 88 | unsigned short flags, int kind); |
|---|
| 89 | static void max1619_init_client(struct i2c_client *client); |
|---|
| 90 | static int max1619_detach_client(struct i2c_client *client); |
|---|
| 91 | static void max1619_local_temp(struct i2c_client *client, int operation, |
|---|
| 92 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 93 | static void max1619_remote_temp(struct i2c_client *client, int operation, |
|---|
| 94 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 95 | static void max1619_remote_crit(struct i2c_client *client, int operation, |
|---|
| 96 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 97 | static void max1619_alarms(struct i2c_client *client, int operation, |
|---|
| 98 | int ctl_name, int *nrels_mag, long *results); |
|---|
| 99 | |
|---|
| 100 | /* |
|---|
| 101 | * Driver data (common to all clients) |
|---|
| 102 | */ |
|---|
| 103 | |
|---|
| 104 | static struct i2c_driver max1619_driver = { |
|---|
| 105 | .name = "MAX1619 sensor driver", |
|---|
| 106 | .flags = I2C_DF_NOTIFY, |
|---|
| 107 | .attach_adapter = max1619_attach_adapter, |
|---|
| 108 | .detach_client = max1619_detach_client |
|---|
| 109 | }; |
|---|
| 110 | |
|---|
| 111 | /* |
|---|
| 112 | * Client data (each client gets its own) |
|---|
| 113 | */ |
|---|
| 114 | |
|---|
| 115 | struct max1619_data { |
|---|
| 116 | struct i2c_client client; |
|---|
| 117 | int sysctl_id; |
|---|
| 118 | |
|---|
| 119 | struct semaphore update_lock; |
|---|
| 120 | char valid; /* zero until following fields are valid */ |
|---|
| 121 | unsigned long last_updated; /* in jiffies */ |
|---|
| 122 | |
|---|
| 123 | /* register values */ |
|---|
| 124 | u8 local_temp; |
|---|
| 125 | u8 remote_temp, remote_high, remote_low; |
|---|
| 126 | u8 remote_hyst, remote_max; |
|---|
| 127 | u8 alarms; |
|---|
| 128 | }; |
|---|
| 129 | |
|---|
| 130 | /* |
|---|
| 131 | * Proc entries |
|---|
| 132 | * These files are created for each detected max1619. |
|---|
| 133 | */ |
|---|
| 134 | |
|---|
| 135 | /* -- SENSORS SYSCTL START -- */ |
|---|
| 136 | |
|---|
| 137 | #define MAX1619_SYSCTL_LOCAL_TEMP 1200 |
|---|
| 138 | #define MAX1619_SYSCTL_REMOTE_TEMP 1201 |
|---|
| 139 | #define MAX1619_SYSCTL_REMOTE_CRIT 1202 |
|---|
| 140 | #define MAX1619_SYSCTL_ALARMS 1203 |
|---|
| 141 | |
|---|
| 142 | #define MAX1619_ALARM_REMOTE_THIGH 0x10 |
|---|
| 143 | #define MAX1619_ALARM_REMOTE_TLOW 0x08 |
|---|
| 144 | #define MAX1619_ALARM_REMOTE_OPEN 0x04 |
|---|
| 145 | #define MAX1619_ALARM_REMOTE_OVERT 0x02 |
|---|
| 146 | |
|---|
| 147 | /* -- SENSORS SYSCTL END -- */ |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | static ctl_table max1619_dir_table_template[] = |
|---|
| 151 | { |
|---|
| 152 | {MAX1619_SYSCTL_LOCAL_TEMP, "temp1", NULL, 0, 0444, NULL, |
|---|
| 153 | &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_local_temp}, |
|---|
| 154 | {MAX1619_SYSCTL_REMOTE_TEMP, "temp2", NULL, 0, 0644, NULL, |
|---|
| 155 | &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_temp}, |
|---|
| 156 | {MAX1619_SYSCTL_REMOTE_CRIT,"temp2_crit", NULL, 0, 0644, NULL, |
|---|
| 157 | &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_remote_crit}, |
|---|
| 158 | {MAX1619_SYSCTL_ALARMS, "alarms", NULL, 0, 0444, NULL, |
|---|
| 159 | &i2c_proc_real, &i2c_sysctl_real, NULL, &max1619_alarms}, |
|---|
| 160 | {0} |
|---|
| 161 | }; |
|---|
| 162 | |
|---|
| 163 | /* |
|---|
| 164 | * Internal variables |
|---|
| 165 | */ |
|---|
| 166 | |
|---|
| 167 | static int max1619_id = 0; |
|---|
| 168 | |
|---|
| 169 | /* |
|---|
| 170 | * Real code |
|---|
| 171 | */ |
|---|
| 172 | |
|---|
| 173 | static int max1619_attach_adapter(struct i2c_adapter *adapter) |
|---|
| 174 | { |
|---|
| 175 | return i2c_detect(adapter, &addr_data, max1619_detect); |
|---|
| 176 | } |
|---|
| 177 | |
|---|
| 178 | /* |
|---|
| 179 | * The following function does more than just detection. If detection |
|---|
| 180 | * succeeds, it also registers the new chip. |
|---|
| 181 | */ |
|---|
| 182 | static int max1619_detect(struct i2c_adapter *adapter, int address, |
|---|
| 183 | unsigned short flags, int kind) |
|---|
| 184 | { |
|---|
| 185 | struct i2c_client *new_client; |
|---|
| 186 | struct max1619_data *data; |
|---|
| 187 | int err = 0; |
|---|
| 188 | const char *type_name = ""; |
|---|
| 189 | const char *client_name = ""; |
|---|
| 190 | |
|---|
| 191 | #ifdef DEBUG |
|---|
| 192 | if (i2c_is_isa_adapter(adapter)) { |
|---|
| 193 | printk(KERN_DEBUG "max1619.o: Called for an ISA bus " |
|---|
| 194 | "adapter, aborting.\n"); |
|---|
| 195 | return 0; |
|---|
| 196 | } |
|---|
| 197 | #endif |
|---|
| 198 | |
|---|
| 199 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { |
|---|
| 200 | #ifdef DEBUG |
|---|
| 201 | printk(KERN_DEBUG "max1619.o: I2C bus doesn't support " |
|---|
| 202 | "byte read mode, skipping.\n"); |
|---|
| 203 | #endif |
|---|
| 204 | return 0; |
|---|
| 205 | } |
|---|
| 206 | |
|---|
| 207 | if (!(data = kmalloc(sizeof(struct max1619_data), GFP_KERNEL))) { |
|---|
| 208 | printk(KERN_ERR "max1619.o: Out of memory in " |
|---|
| 209 | "max1619_detect (new_client).\n"); |
|---|
| 210 | return -ENOMEM; |
|---|
| 211 | } |
|---|
| 212 | |
|---|
| 213 | /* |
|---|
| 214 | * The common I2C client data is placed right before the |
|---|
| 215 | * MAX1619-specific data. The MAX1619-specific data is pointed to |
|---|
| 216 | * by the data field from the I2C client da1ta. |
|---|
| 217 | */ |
|---|
| 218 | |
|---|
| 219 | new_client = &data->client; |
|---|
| 220 | new_client->addr = address; |
|---|
| 221 | new_client->data = data; |
|---|
| 222 | new_client->adapter = adapter; |
|---|
| 223 | new_client->driver = &max1619_driver; |
|---|
| 224 | new_client->flags = 0; |
|---|
| 225 | |
|---|
| 226 | /* |
|---|
| 227 | * Now we do the remaining detection. A negative kind means that |
|---|
| 228 | * the driver was loaded with no force parameter (default), so we |
|---|
| 229 | * must both detect and identify the chip. A zero kind means that |
|---|
| 230 | * the driver was loaded with the force parameter, the detection |
|---|
| 231 | * step shall be skipped. A positive kind means that the driver |
|---|
| 232 | * was loaded with the force parameter and a given kind of chip is |
|---|
| 233 | * requested, so both the detection and the identification steps |
|---|
| 234 | * are skipped. |
|---|
| 235 | */ |
|---|
| 236 | |
|---|
| 237 | if (kind < 0) { |
|---|
| 238 | u8 reg_config, reg_convrate, reg_status; |
|---|
| 239 | |
|---|
| 240 | reg_config = i2c_smbus_read_byte_data(new_client, |
|---|
| 241 | MAX1619_REG_R_CONFIG); |
|---|
| 242 | reg_convrate = i2c_smbus_read_byte_data(new_client, |
|---|
| 243 | MAX1619_REG_R_CONVRATE); |
|---|
| 244 | reg_status = i2c_smbus_read_byte_data(new_client, |
|---|
| 245 | MAX1619_REG_R_STATUS); |
|---|
| 246 | |
|---|
| 247 | if ((reg_config & 0x03) != 0x00 |
|---|
| 248 | || reg_convrate > 0x07 |
|---|
| 249 | || (reg_status & 0x61) != 0x00) { |
|---|
| 250 | #ifdef DEBUG |
|---|
| 251 | printk(KERN_DEBUG "max1619.o: Detection failed at " |
|---|
| 252 | "0x%02x.\n", address); |
|---|
| 253 | #endif |
|---|
| 254 | goto ERROR1; |
|---|
| 255 | } |
|---|
| 256 | } |
|---|
| 257 | |
|---|
| 258 | if (kind <= 0) { |
|---|
| 259 | u8 man_id, chip_id; |
|---|
| 260 | |
|---|
| 261 | man_id = i2c_smbus_read_byte_data(new_client, |
|---|
| 262 | MAX1619_REG_R_MAN_ID); |
|---|
| 263 | chip_id = i2c_smbus_read_byte_data(new_client, |
|---|
| 264 | MAX1619_REG_R_CHIP_ID); |
|---|
| 265 | |
|---|
| 266 | if ((man_id == 0x4D) && (chip_id == 0x04)) { |
|---|
| 267 | kind = max1619; |
|---|
| 268 | } |
|---|
| 269 | } |
|---|
| 270 | |
|---|
| 271 | if (kind <= 0) { |
|---|
| 272 | printk(KERN_INFO "max1619.o: Unsupported chip.\n"); |
|---|
| 273 | goto ERROR1; |
|---|
| 274 | } |
|---|
| 275 | |
|---|
| 276 | if (kind == max1619) { |
|---|
| 277 | type_name = "max1619"; |
|---|
| 278 | client_name = "MAX1619 chip"; |
|---|
| 279 | } else { |
|---|
| 280 | printk(KERN_ERR "max1619.o: Unknown kind %d.\n", kind); |
|---|
| 281 | goto ERROR1; |
|---|
| 282 | } |
|---|
| 283 | |
|---|
| 284 | /* |
|---|
| 285 | * OK, we got a valid chip so we can fill in the remaining client |
|---|
| 286 | * fields. |
|---|
| 287 | */ |
|---|
| 288 | |
|---|
| 289 | strcpy(new_client->name, client_name); |
|---|
| 290 | new_client->id = max1619_id++; |
|---|
| 291 | data->valid = 0; |
|---|
| 292 | init_MUTEX(&data->update_lock); |
|---|
| 293 | |
|---|
| 294 | /* |
|---|
| 295 | * Tell the I2C layer a new client has arrived. |
|---|
| 296 | */ |
|---|
| 297 | |
|---|
| 298 | if ((err = i2c_attach_client(new_client))) { |
|---|
| 299 | printk(KERN_ERR "max1619.o: Failed attaching client.\n"); |
|---|
| 300 | goto ERROR1; |
|---|
| 301 | } |
|---|
| 302 | |
|---|
| 303 | /* |
|---|
| 304 | * Register a new directory entry. |
|---|
| 305 | */ |
|---|
| 306 | |
|---|
| 307 | if ((err = i2c_register_entry(new_client, type_name, |
|---|
| 308 | max1619_dir_table_template, THIS_MODULE)) < 0) { |
|---|
| 309 | printk(KERN_ERR "max1619.o: Failed registering directory " |
|---|
| 310 | "entry.\n"); |
|---|
| 311 | goto ERROR2; |
|---|
| 312 | } |
|---|
| 313 | data->sysctl_id = err; |
|---|
| 314 | |
|---|
| 315 | /* |
|---|
| 316 | * Initialize the MAX1619 chip. |
|---|
| 317 | */ |
|---|
| 318 | |
|---|
| 319 | max1619_init_client(new_client); |
|---|
| 320 | return 0; |
|---|
| 321 | |
|---|
| 322 | ERROR2: |
|---|
| 323 | i2c_detach_client(new_client); |
|---|
| 324 | ERROR1: |
|---|
| 325 | kfree(data); |
|---|
| 326 | return err; |
|---|
| 327 | } |
|---|
| 328 | |
|---|
| 329 | static void max1619_init_client(struct i2c_client *client) |
|---|
| 330 | { |
|---|
| 331 | u8 config; |
|---|
| 332 | |
|---|
| 333 | /* |
|---|
| 334 | * Start the conversions. |
|---|
| 335 | */ |
|---|
| 336 | |
|---|
| 337 | /* Set conversion rate to 2 Hz */ |
|---|
| 338 | i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONVRATE, 5); |
|---|
| 339 | |
|---|
| 340 | /* Start monitoring */ |
|---|
| 341 | config = i2c_smbus_read_byte_data(client, MAX1619_REG_R_CONFIG); |
|---|
| 342 | if (config & 0x40) |
|---|
| 343 | i2c_smbus_write_byte_data(client, MAX1619_REG_W_CONFIG, |
|---|
| 344 | config & 0xBF); |
|---|
| 345 | } |
|---|
| 346 | |
|---|
| 347 | |
|---|
| 348 | static int max1619_detach_client(struct i2c_client *client) |
|---|
| 349 | { |
|---|
| 350 | int err; |
|---|
| 351 | |
|---|
| 352 | i2c_deregister_entry(((struct max1619_data *) |
|---|
| 353 | (client->data))->sysctl_id); |
|---|
| 354 | if ((err = i2c_detach_client(client))) { |
|---|
| 355 | printk(KERN_ERR "max1619.o: Client deregistration failed, " |
|---|
| 356 | "client not detached.\n"); |
|---|
| 357 | return err; |
|---|
| 358 | } |
|---|
| 359 | |
|---|
| 360 | kfree(client->data); |
|---|
| 361 | return 0; |
|---|
| 362 | } |
|---|
| 363 | |
|---|
| 364 | static void max1619_update_client(struct i2c_client *client) |
|---|
| 365 | { |
|---|
| 366 | struct max1619_data *data = client->data; |
|---|
| 367 | |
|---|
| 368 | down(&data->update_lock); |
|---|
| 369 | |
|---|
| 370 | if ((jiffies - data->last_updated > HZ * 2) || |
|---|
| 371 | (jiffies < data->last_updated) || !data->valid) { |
|---|
| 372 | #ifdef DEBUG |
|---|
| 373 | printk(KERN_DEBUG "max1619.o: Updating data.\n"); |
|---|
| 374 | #endif |
|---|
| 375 | |
|---|
| 376 | data->local_temp = i2c_smbus_read_byte_data(client, |
|---|
| 377 | MAX1619_REG_R_LOCAL_TEMP); |
|---|
| 378 | data->remote_temp = i2c_smbus_read_byte_data(client, |
|---|
| 379 | MAX1619_REG_R_REMOTE_TEMP); |
|---|
| 380 | data->remote_high = i2c_smbus_read_byte_data(client, |
|---|
| 381 | MAX1619_REG_R_REMOTE_THIGH); |
|---|
| 382 | data->remote_low = i2c_smbus_read_byte_data(client, |
|---|
| 383 | MAX1619_REG_R_REMOTE_TLOW); |
|---|
| 384 | data->remote_max = i2c_smbus_read_byte_data(client, |
|---|
| 385 | MAX1619_REG_R_REMOTE_TMAX); |
|---|
| 386 | data->remote_hyst = i2c_smbus_read_byte_data(client, |
|---|
| 387 | MAX1619_REG_R_REMOTE_THYST); |
|---|
| 388 | data->alarms = i2c_smbus_read_byte_data(client, |
|---|
| 389 | MAX1619_REG_R_STATUS); |
|---|
| 390 | |
|---|
| 391 | data->last_updated = jiffies; |
|---|
| 392 | data->valid = 1; |
|---|
| 393 | } |
|---|
| 394 | |
|---|
| 395 | up(&data->update_lock); |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static void max1619_local_temp(struct i2c_client *client, int operation, |
|---|
| 399 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 400 | { |
|---|
| 401 | struct max1619_data *data = client->data; |
|---|
| 402 | |
|---|
| 403 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 404 | *nrels_mag = 0; /* magnitude */ |
|---|
| 405 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 406 | max1619_update_client(client); |
|---|
| 407 | results[0] = TEMP_FROM_REG(data->local_temp); |
|---|
| 408 | *nrels_mag = 1; |
|---|
| 409 | } |
|---|
| 410 | |
|---|
| 411 | } |
|---|
| 412 | |
|---|
| 413 | static void max1619_remote_temp(struct i2c_client *client, int operation, |
|---|
| 414 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 415 | { |
|---|
| 416 | struct max1619_data *data = client->data; |
|---|
| 417 | |
|---|
| 418 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 419 | *nrels_mag = 0; /* magnitude */ |
|---|
| 420 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 421 | max1619_update_client(client); |
|---|
| 422 | results[0] = TEMP_FROM_REG(data->remote_high); |
|---|
| 423 | results[1] = TEMP_FROM_REG(data->remote_low); |
|---|
| 424 | results[2] = TEMP_FROM_REG(data->remote_temp); |
|---|
| 425 | *nrels_mag = 3; |
|---|
| 426 | } else if (operation == SENSORS_PROC_REAL_WRITE) { |
|---|
| 427 | if (*nrels_mag >= 1) { |
|---|
| 428 | data->remote_high = TEMP_TO_REG(results[0]); |
|---|
| 429 | i2c_smbus_write_byte_data(client, |
|---|
| 430 | MAX1619_REG_W_REMOTE_THIGH, data->remote_high); |
|---|
| 431 | } |
|---|
| 432 | if (*nrels_mag >= 2) { |
|---|
| 433 | data->remote_low = TEMP_TO_REG(results[1]); |
|---|
| 434 | i2c_smbus_write_byte_data(client, |
|---|
| 435 | MAX1619_REG_W_REMOTE_TLOW, data->remote_low); |
|---|
| 436 | |
|---|
| 437 | } |
|---|
| 438 | } |
|---|
| 439 | } |
|---|
| 440 | |
|---|
| 441 | static void max1619_remote_crit(struct i2c_client *client, int operation, |
|---|
| 442 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 443 | { |
|---|
| 444 | struct max1619_data *data = client->data; |
|---|
| 445 | |
|---|
| 446 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 447 | *nrels_mag = 0; /* magnitude */ |
|---|
| 448 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 449 | max1619_update_client(client); |
|---|
| 450 | results[0] = TEMP_FROM_REG(data->remote_max); |
|---|
| 451 | results[1] = TEMP_FROM_REG(data->remote_hyst); |
|---|
| 452 | *nrels_mag = 2; |
|---|
| 453 | } else if (operation == SENSORS_PROC_REAL_WRITE) { |
|---|
| 454 | if (*nrels_mag >= 1) { |
|---|
| 455 | data->remote_max = TEMP_TO_REG(results[0]); |
|---|
| 456 | i2c_smbus_write_byte_data(client, |
|---|
| 457 | MAX1619_REG_W_REMOTE_TMAX, data->remote_max); |
|---|
| 458 | } |
|---|
| 459 | if (*nrels_mag >= 2) { |
|---|
| 460 | data->remote_hyst = TEMP_TO_REG(results[1]); |
|---|
| 461 | i2c_smbus_write_byte_data(client, |
|---|
| 462 | MAX1619_REG_W_REMOTE_THYST, data->remote_hyst); |
|---|
| 463 | } |
|---|
| 464 | } |
|---|
| 465 | } |
|---|
| 466 | |
|---|
| 467 | static void max1619_alarms(struct i2c_client *client, int operation, |
|---|
| 468 | int ctl_name, int *nrels_mag, long *results) |
|---|
| 469 | { |
|---|
| 470 | struct max1619_data *data = client->data; |
|---|
| 471 | |
|---|
| 472 | if (operation == SENSORS_PROC_REAL_INFO) |
|---|
| 473 | *nrels_mag = 0; /* magnitude */ |
|---|
| 474 | else if (operation == SENSORS_PROC_REAL_READ) { |
|---|
| 475 | max1619_update_client(client); |
|---|
| 476 | results[0] = data->alarms; |
|---|
| 477 | *nrels_mag = 1; |
|---|
| 478 | } |
|---|
| 479 | } |
|---|
| 480 | |
|---|
| 481 | |
|---|
| 482 | static int __init sm_max1619_init(void) |
|---|
| 483 | { |
|---|
| 484 | printk(KERN_INFO "max1619.o version %s (%s)\n", LM_VERSION, LM_DATE); |
|---|
| 485 | return i2c_add_driver(&max1619_driver); |
|---|
| 486 | } |
|---|
| 487 | |
|---|
| 488 | static void __exit sm_max1619_exit(void) |
|---|
| 489 | { |
|---|
| 490 | i2c_del_driver(&max1619_driver); |
|---|
| 491 | } |
|---|
| 492 | |
|---|
| 493 | MODULE_AUTHOR("Alexey Fisher <fishor@mail.ru>"); |
|---|
| 494 | MODULE_DESCRIPTION("MAX1619 sensor driver"); |
|---|
| 495 | MODULE_LICENSE("GPL"); |
|---|
| 496 | |
|---|
| 497 | module_init(sm_max1619_init); |
|---|
| 498 | module_exit(sm_max1619_exit); |
|---|