Commit 7a4b15cdf3d607152ba23fa4aa2bf072c6810924
1 parent
81e5d8646f
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
powerpc/pmac: Convert therm_adt746x to new i2c probing
This simplifies the driver to stop using the deprecated attach interface, Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Showing 1 changed file with 204 additions and 276 deletions Side-by-side Diff
drivers/macintosh/therm_adt746x.c
... | ... | @@ -47,7 +47,7 @@ |
47 | 47 | |
48 | 48 | static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ |
49 | 49 | static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ |
50 | -static const char *sensor_location[3]; | |
50 | +static const char *sensor_location[3] = { "?", "?", "?" }; | |
51 | 51 | |
52 | 52 | static int limit_adjust; |
53 | 53 | static int fan_speed = -1; |
54 | 54 | |
55 | 55 | |
... | ... | @@ -79,18 +79,16 @@ |
79 | 79 | int last_speed[2]; |
80 | 80 | int last_var[2]; |
81 | 81 | int pwm_inv[2]; |
82 | + struct task_struct *thread; | |
83 | + struct platform_device *pdev; | |
84 | + enum { | |
85 | + ADT7460, | |
86 | + ADT7467 | |
87 | + } type; | |
82 | 88 | }; |
83 | 89 | |
84 | -static enum {ADT7460, ADT7467} therm_type; | |
85 | -static int therm_bus, therm_address; | |
86 | -static struct platform_device * of_dev; | |
87 | -static struct thermostat* thermostat; | |
88 | -static struct task_struct *thread_therm = NULL; | |
89 | - | |
90 | 90 | static void write_both_fan_speed(struct thermostat *th, int speed); |
91 | 91 | static void write_fan_speed(struct thermostat *th, int speed, int fan); |
92 | -static void thermostat_create_files(void); | |
93 | -static void thermostat_remove_files(void); | |
94 | 92 | |
95 | 93 | static int |
96 | 94 | write_reg(struct thermostat* th, int reg, u8 data) |
... | ... | @@ -126,66 +124,6 @@ |
126 | 124 | return data; |
127 | 125 | } |
128 | 126 | |
129 | -static struct i2c_driver thermostat_driver; | |
130 | - | |
131 | -static int | |
132 | -attach_thermostat(struct i2c_adapter *adapter) | |
133 | -{ | |
134 | - unsigned long bus_no; | |
135 | - struct i2c_board_info info; | |
136 | - struct i2c_client *client; | |
137 | - | |
138 | - if (strncmp(adapter->name, "uni-n", 5)) | |
139 | - return -ENODEV; | |
140 | - bus_no = simple_strtoul(adapter->name + 6, NULL, 10); | |
141 | - if (bus_no != therm_bus) | |
142 | - return -ENODEV; | |
143 | - | |
144 | - memset(&info, 0, sizeof(struct i2c_board_info)); | |
145 | - strlcpy(info.type, "therm_adt746x", I2C_NAME_SIZE); | |
146 | - info.addr = therm_address; | |
147 | - client = i2c_new_device(adapter, &info); | |
148 | - if (!client) | |
149 | - return -ENODEV; | |
150 | - | |
151 | - /* | |
152 | - * Let i2c-core delete that device on driver removal. | |
153 | - * This is safe because i2c-core holds the core_lock mutex for us. | |
154 | - */ | |
155 | - list_add_tail(&client->detected, &thermostat_driver.clients); | |
156 | - return 0; | |
157 | -} | |
158 | - | |
159 | -static int | |
160 | -remove_thermostat(struct i2c_client *client) | |
161 | -{ | |
162 | - struct thermostat *th = i2c_get_clientdata(client); | |
163 | - int i; | |
164 | - | |
165 | - thermostat_remove_files(); | |
166 | - | |
167 | - if (thread_therm != NULL) { | |
168 | - kthread_stop(thread_therm); | |
169 | - } | |
170 | - | |
171 | - printk(KERN_INFO "adt746x: Putting max temperatures back from " | |
172 | - "%d, %d, %d to %d, %d, %d\n", | |
173 | - th->limits[0], th->limits[1], th->limits[2], | |
174 | - th->initial_limits[0], th->initial_limits[1], | |
175 | - th->initial_limits[2]); | |
176 | - | |
177 | - for (i = 0; i < 3; i++) | |
178 | - write_reg(th, LIMIT_REG[i], th->initial_limits[i]); | |
179 | - | |
180 | - write_both_fan_speed(th, -1); | |
181 | - | |
182 | - thermostat = NULL; | |
183 | - | |
184 | - kfree(th); | |
185 | - | |
186 | - return 0; | |
187 | -} | |
188 | - | |
189 | 127 | static int read_fan_speed(struct thermostat *th, u8 addr) |
190 | 128 | { |
191 | 129 | u8 tmp[2]; |
... | ... | @@ -203,7 +141,7 @@ |
203 | 141 | static void write_both_fan_speed(struct thermostat *th, int speed) |
204 | 142 | { |
205 | 143 | write_fan_speed(th, speed, 0); |
206 | - if (therm_type == ADT7460) | |
144 | + if (th->type == ADT7460) | |
207 | 145 | write_fan_speed(th, speed, 1); |
208 | 146 | } |
209 | 147 | |
... | ... | @@ -216,7 +154,7 @@ |
216 | 154 | else if (speed < -1) |
217 | 155 | speed = 0; |
218 | 156 | |
219 | - if (therm_type == ADT7467 && fan == 1) | |
157 | + if (th->type == ADT7467 && fan == 1) | |
220 | 158 | return; |
221 | 159 | |
222 | 160 | if (th->last_speed[fan] != speed) { |
... | ... | @@ -239,7 +177,7 @@ |
239 | 177 | write_reg(th, FAN_SPD_SET[fan], speed); |
240 | 178 | } else { |
241 | 179 | /* back to automatic */ |
242 | - if(therm_type == ADT7460) { | |
180 | + if(th->type == ADT7460) { | |
243 | 181 | manual = read_reg(th, |
244 | 182 | MANUAL_MODE[fan]) & (~MANUAL_MASK); |
245 | 183 | manual &= ~INVERT_MASK; |
... | ... | @@ -293,7 +231,7 @@ |
293 | 231 | /* we don't care about local sensor, so we start at sensor 1 */ |
294 | 232 | for (i = 1; i < 3; i++) { |
295 | 233 | int started = 0; |
296 | - int fan_number = (therm_type == ADT7460 && i == 2); | |
234 | + int fan_number = (th->type == ADT7460 && i == 2); | |
297 | 235 | int var = th->temps[i] - th->limits[i]; |
298 | 236 | |
299 | 237 | if (var > -1) { |
300 | 238 | |
301 | 239 | |
302 | 240 | |
... | ... | @@ -370,116 +308,22 @@ |
370 | 308 | |
371 | 309 | static void set_limit(struct thermostat *th, int i) |
372 | 310 | { |
373 | - /* Set sensor1 limit higher to avoid powerdowns */ | |
374 | - th->limits[i] = default_limits_chip[i] + limit_adjust; | |
375 | - write_reg(th, LIMIT_REG[i], th->limits[i]); | |
311 | + /* Set sensor1 limit higher to avoid powerdowns */ | |
312 | + th->limits[i] = default_limits_chip[i] + limit_adjust; | |
313 | + write_reg(th, LIMIT_REG[i], th->limits[i]); | |
376 | 314 | |
377 | - /* set our limits to normal */ | |
378 | - th->limits[i] = default_limits_local[i] + limit_adjust; | |
315 | + /* set our limits to normal */ | |
316 | + th->limits[i] = default_limits_local[i] + limit_adjust; | |
379 | 317 | } |
380 | 318 | |
381 | -static int probe_thermostat(struct i2c_client *client, | |
382 | - const struct i2c_device_id *id) | |
383 | -{ | |
384 | - struct thermostat* th; | |
385 | - int rc; | |
386 | - int i; | |
387 | - | |
388 | - if (thermostat) | |
389 | - return 0; | |
390 | - | |
391 | - th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); | |
392 | - if (!th) | |
393 | - return -ENOMEM; | |
394 | - | |
395 | - i2c_set_clientdata(client, th); | |
396 | - th->clt = client; | |
397 | - | |
398 | - rc = read_reg(th, CONFIG_REG); | |
399 | - if (rc < 0) { | |
400 | - dev_err(&client->dev, "Thermostat failed to read config!\n"); | |
401 | - kfree(th); | |
402 | - return -ENODEV; | |
403 | - } | |
404 | - | |
405 | - /* force manual control to start the fan quieter */ | |
406 | - if (fan_speed == -1) | |
407 | - fan_speed = 64; | |
408 | - | |
409 | - if(therm_type == ADT7460) { | |
410 | - printk(KERN_INFO "adt746x: ADT7460 initializing\n"); | |
411 | - /* The 7460 needs to be started explicitly */ | |
412 | - write_reg(th, CONFIG_REG, 1); | |
413 | - } else | |
414 | - printk(KERN_INFO "adt746x: ADT7467 initializing\n"); | |
415 | - | |
416 | - for (i = 0; i < 3; i++) { | |
417 | - th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); | |
418 | - set_limit(th, i); | |
419 | - } | |
420 | - | |
421 | - printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" | |
422 | - " to %d, %d, %d\n", | |
423 | - th->initial_limits[0], th->initial_limits[1], | |
424 | - th->initial_limits[2], th->limits[0], th->limits[1], | |
425 | - th->limits[2]); | |
426 | - | |
427 | - thermostat = th; | |
428 | - | |
429 | - /* record invert bit status because fw can corrupt it after suspend */ | |
430 | - th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK; | |
431 | - th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK; | |
432 | - | |
433 | - /* be sure to really write fan speed the first time */ | |
434 | - th->last_speed[0] = -2; | |
435 | - th->last_speed[1] = -2; | |
436 | - th->last_var[0] = -80; | |
437 | - th->last_var[1] = -80; | |
438 | - | |
439 | - if (fan_speed != -1) { | |
440 | - /* manual mode, stop fans */ | |
441 | - write_both_fan_speed(th, 0); | |
442 | - } else { | |
443 | - /* automatic mode */ | |
444 | - write_both_fan_speed(th, -1); | |
445 | - } | |
446 | - | |
447 | - thread_therm = kthread_run(monitor_task, th, "kfand"); | |
448 | - | |
449 | - if (thread_therm == ERR_PTR(-ENOMEM)) { | |
450 | - printk(KERN_INFO "adt746x: Kthread creation failed\n"); | |
451 | - thread_therm = NULL; | |
452 | - return -ENOMEM; | |
453 | - } | |
454 | - | |
455 | - thermostat_create_files(); | |
456 | - | |
457 | - return 0; | |
319 | +#define BUILD_SHOW_FUNC_INT(name, data) \ | |
320 | +static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ | |
321 | +{ \ | |
322 | + struct thermostat *th = dev_get_drvdata(dev); \ | |
323 | + return sprintf(buf, "%d\n", data); \ | |
458 | 324 | } |
459 | 325 | |
460 | -static const struct i2c_device_id therm_adt746x_id[] = { | |
461 | - { "therm_adt746x", 0 }, | |
462 | - { } | |
463 | -}; | |
464 | - | |
465 | -static struct i2c_driver thermostat_driver = { | |
466 | - .driver = { | |
467 | - .name = "therm_adt746x", | |
468 | - }, | |
469 | - .attach_adapter = attach_thermostat, | |
470 | - .probe = probe_thermostat, | |
471 | - .remove = remove_thermostat, | |
472 | - .id_table = therm_adt746x_id, | |
473 | -}; | |
474 | - | |
475 | -/* | |
476 | - * Now, unfortunately, sysfs doesn't give us a nice void * we could | |
477 | - * pass around to the attribute functions, so we don't really have | |
478 | - * choice but implement a bunch of them... | |
479 | - * | |
480 | - * FIXME, it does now... | |
481 | - */ | |
482 | -#define BUILD_SHOW_FUNC_INT(name, data) \ | |
326 | +#define BUILD_SHOW_FUNC_INT_LITE(name, data) \ | |
483 | 327 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ |
484 | 328 | { \ |
485 | 329 | return sprintf(buf, "%d\n", data); \ |
486 | 330 | |
487 | 331 | |
488 | 332 | |
... | ... | @@ -494,22 +338,24 @@ |
494 | 338 | #define BUILD_SHOW_FUNC_FAN(name, data) \ |
495 | 339 | static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ |
496 | 340 | { \ |
341 | + struct thermostat *th = dev_get_drvdata(dev); \ | |
497 | 342 | return sprintf(buf, "%d (%d rpm)\n", \ |
498 | - thermostat->last_speed[data], \ | |
499 | - read_fan_speed(thermostat, FAN_SPEED[data]) \ | |
343 | + th->last_speed[data], \ | |
344 | + read_fan_speed(th, FAN_SPEED[data]) \ | |
500 | 345 | ); \ |
501 | 346 | } |
502 | 347 | |
503 | 348 | #define BUILD_STORE_FUNC_DEG(name, data) \ |
504 | 349 | static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ |
505 | 350 | { \ |
351 | + struct thermostat *th = dev_get_drvdata(dev); \ | |
506 | 352 | int val; \ |
507 | 353 | int i; \ |
508 | 354 | val = simple_strtol(buf, NULL, 10); \ |
509 | 355 | printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \ |
510 | 356 | limit_adjust = val; \ |
511 | 357 | for (i=0; i < 3; i++) \ |
512 | - set_limit(thermostat, i); \ | |
358 | + set_limit(th, i); \ | |
513 | 359 | return n; \ |
514 | 360 | } |
515 | 361 | |
516 | 362 | |
517 | 363 | |
... | ... | @@ -525,20 +371,21 @@ |
525 | 371 | return n; \ |
526 | 372 | } |
527 | 373 | |
528 | -BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(thermostat, TEMP_REG[1]))) | |
529 | -BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(thermostat, TEMP_REG[2]))) | |
530 | -BUILD_SHOW_FUNC_INT(sensor1_limit, thermostat->limits[1]) | |
531 | -BUILD_SHOW_FUNC_INT(sensor2_limit, thermostat->limits[2]) | |
374 | +BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(th, TEMP_REG[1]))) | |
375 | +BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(th, TEMP_REG[2]))) | |
376 | +BUILD_SHOW_FUNC_INT(sensor1_limit, th->limits[1]) | |
377 | +BUILD_SHOW_FUNC_INT(sensor2_limit, th->limits[2]) | |
532 | 378 | BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1]) |
533 | 379 | BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2]) |
534 | 380 | |
535 | -BUILD_SHOW_FUNC_INT(specified_fan_speed, fan_speed) | |
381 | +BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed) | |
382 | +BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) | |
383 | + | |
536 | 384 | BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0) |
537 | 385 | BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1) |
538 | 386 | |
539 | -BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) | |
540 | -BUILD_SHOW_FUNC_INT(limit_adjust, limit_adjust) | |
541 | -BUILD_STORE_FUNC_DEG(limit_adjust, thermostat) | |
387 | +BUILD_SHOW_FUNC_INT_LITE(limit_adjust, limit_adjust) | |
388 | +BUILD_STORE_FUNC_DEG(limit_adjust, th) | |
542 | 389 | |
543 | 390 | static DEVICE_ATTR(sensor1_temperature, S_IRUGO, |
544 | 391 | show_sensor1_temperature,NULL); |
545 | 392 | |
546 | 393 | |
547 | 394 | |
548 | 395 | |
549 | 396 | |
550 | 397 | |
551 | 398 | |
... | ... | @@ -564,53 +411,77 @@ |
564 | 411 | static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, |
565 | 412 | show_limit_adjust, store_limit_adjust); |
566 | 413 | |
567 | - | |
568 | -static int __init | |
569 | -thermostat_init(void) | |
414 | +static void thermostat_create_files(struct thermostat *th) | |
570 | 415 | { |
571 | - struct device_node* np; | |
572 | - const u32 *prop; | |
573 | - int i = 0, offset = 0; | |
416 | + struct device_node *np = th->clt->dev.of_node; | |
417 | + struct device *dev; | |
418 | + int err; | |
574 | 419 | |
575 | - np = of_find_node_by_name(NULL, "fan"); | |
576 | - if (!np) | |
577 | - return -ENODEV; | |
578 | - if (of_device_is_compatible(np, "adt7460")) | |
579 | - therm_type = ADT7460; | |
580 | - else if (of_device_is_compatible(np, "adt7467")) | |
581 | - therm_type = ADT7467; | |
582 | - else { | |
583 | - of_node_put(np); | |
584 | - return -ENODEV; | |
585 | - } | |
420 | + /* To maintain ABI compatibility with userspace, create | |
421 | + * the old style platform driver and attach the attributes | |
422 | + * to it here | |
423 | + */ | |
424 | + th->pdev = of_platform_device_create(np, "temperatures", NULL); | |
425 | + if (!th->pdev) | |
426 | + return; | |
427 | + dev = &th->pdev->dev; | |
428 | + dev_set_drvdata(dev, th); | |
429 | + err = device_create_file(dev, &dev_attr_sensor1_temperature); | |
430 | + err |= device_create_file(dev, &dev_attr_sensor2_temperature); | |
431 | + err |= device_create_file(dev, &dev_attr_sensor1_limit); | |
432 | + err |= device_create_file(dev, &dev_attr_sensor2_limit); | |
433 | + err |= device_create_file(dev, &dev_attr_sensor1_location); | |
434 | + err |= device_create_file(dev, &dev_attr_sensor2_location); | |
435 | + err |= device_create_file(dev, &dev_attr_limit_adjust); | |
436 | + err |= device_create_file(dev, &dev_attr_specified_fan_speed); | |
437 | + err |= device_create_file(dev, &dev_attr_sensor1_fan_speed); | |
438 | + if(th->type == ADT7460) | |
439 | + err |= device_create_file(dev, &dev_attr_sensor2_fan_speed); | |
440 | + if (err) | |
441 | + printk(KERN_WARNING | |
442 | + "Failed to create temperature attribute file(s).\n"); | |
443 | +} | |
586 | 444 | |
587 | - prop = of_get_property(np, "hwsensor-params-version", NULL); | |
588 | - printk(KERN_INFO "adt746x: version %d (%ssupported)\n", *prop, | |
589 | - (*prop == 1)?"":"un"); | |
590 | - if (*prop != 1) { | |
591 | - of_node_put(np); | |
592 | - return -ENODEV; | |
593 | - } | |
445 | +static void thermostat_remove_files(struct thermostat *th) | |
446 | +{ | |
447 | + struct device *dev; | |
594 | 448 | |
595 | - prop = of_get_property(np, "reg", NULL); | |
596 | - if (!prop) { | |
597 | - of_node_put(np); | |
598 | - return -ENODEV; | |
599 | - } | |
449 | + if (!th->pdev) | |
450 | + return; | |
451 | + dev = &th->pdev->dev; | |
452 | + device_remove_file(dev, &dev_attr_sensor1_temperature); | |
453 | + device_remove_file(dev, &dev_attr_sensor2_temperature); | |
454 | + device_remove_file(dev, &dev_attr_sensor1_limit); | |
455 | + device_remove_file(dev, &dev_attr_sensor2_limit); | |
456 | + device_remove_file(dev, &dev_attr_sensor1_location); | |
457 | + device_remove_file(dev, &dev_attr_sensor2_location); | |
458 | + device_remove_file(dev, &dev_attr_limit_adjust); | |
459 | + device_remove_file(dev, &dev_attr_specified_fan_speed); | |
460 | + device_remove_file(dev, &dev_attr_sensor1_fan_speed); | |
461 | + if (th->type == ADT7460) | |
462 | + device_remove_file(dev, &dev_attr_sensor2_fan_speed); | |
463 | + of_device_unregister(th->pdev); | |
600 | 464 | |
601 | - /* look for bus either by path or using "reg" */ | |
602 | - if (strstr(np->full_name, "/i2c-bus@") != NULL) { | |
603 | - const char *tmp_bus = (strstr(np->full_name, "/i2c-bus@") + 9); | |
604 | - therm_bus = tmp_bus[0]-'0'; | |
605 | - } else { | |
606 | - therm_bus = ((*prop) >> 8) & 0x0f; | |
607 | - } | |
465 | +} | |
608 | 466 | |
609 | - therm_address = ((*prop) & 0xff) >> 1; | |
467 | +static int probe_thermostat(struct i2c_client *client, | |
468 | + const struct i2c_device_id *id) | |
469 | +{ | |
470 | + struct device_node *np = client->dev.of_node; | |
471 | + struct thermostat* th; | |
472 | + const __be32 *prop; | |
473 | + int i, rc, vers, offset = 0; | |
610 | 474 | |
611 | - printk(KERN_INFO "adt746x: Thermostat bus: %d, address: 0x%02x, " | |
612 | - "limit_adjust: %d, fan_speed: %d\n", | |
613 | - therm_bus, therm_address, limit_adjust, fan_speed); | |
475 | + if (!np) | |
476 | + return -ENXIO; | |
477 | + prop = of_get_property(np, "hwsensor-params-version", NULL); | |
478 | + if (!prop) | |
479 | + return -ENXIO; | |
480 | + vers = be32_to_cpup(prop); | |
481 | + printk(KERN_INFO "adt746x: version %d (%ssupported)\n", | |
482 | + vers, vers == 1 ? "" : "un"); | |
483 | + if (vers != 1) | |
484 | + return -ENXIO; | |
614 | 485 | |
615 | 486 | if (of_get_property(np, "hwsensor-location", NULL)) { |
616 | 487 | for (i = 0; i < 3; i++) { |
617 | 488 | |
618 | 489 | |
619 | 490 | |
620 | 491 | |
621 | 492 | |
622 | 493 | |
623 | 494 | |
624 | 495 | |
625 | 496 | |
626 | 497 | |
627 | 498 | |
628 | 499 | |
... | ... | @@ -623,72 +494,129 @@ |
623 | 494 | printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]); |
624 | 495 | offset += strlen(sensor_location[i]) + 1; |
625 | 496 | } |
626 | - } else { | |
627 | - sensor_location[0] = "?"; | |
628 | - sensor_location[1] = "?"; | |
629 | - sensor_location[2] = "?"; | |
630 | 497 | } |
631 | 498 | |
632 | - of_dev = of_platform_device_create(np, "temperatures", NULL); | |
633 | - of_node_put(np); | |
499 | + th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); | |
500 | + if (!th) | |
501 | + return -ENOMEM; | |
634 | 502 | |
635 | - if (of_dev == NULL) { | |
636 | - printk(KERN_ERR "Can't register temperatures device !\n"); | |
503 | + i2c_set_clientdata(client, th); | |
504 | + th->clt = client; | |
505 | + th->type = id->driver_data; | |
506 | + | |
507 | + rc = read_reg(th, CONFIG_REG); | |
508 | + if (rc < 0) { | |
509 | + dev_err(&client->dev, "Thermostat failed to read config!\n"); | |
510 | + kfree(th); | |
637 | 511 | return -ENODEV; |
638 | 512 | } |
639 | 513 | |
640 | -#ifndef CONFIG_I2C_POWERMAC | |
641 | - request_module("i2c-powermac"); | |
642 | -#endif | |
514 | + /* force manual control to start the fan quieter */ | |
515 | + if (fan_speed == -1) | |
516 | + fan_speed = 64; | |
517 | + | |
518 | + if (th->type == ADT7460) { | |
519 | + printk(KERN_INFO "adt746x: ADT7460 initializing\n"); | |
520 | + /* The 7460 needs to be started explicitly */ | |
521 | + write_reg(th, CONFIG_REG, 1); | |
522 | + } else | |
523 | + printk(KERN_INFO "adt746x: ADT7467 initializing\n"); | |
643 | 524 | |
644 | - return i2c_add_driver(&thermostat_driver); | |
525 | + for (i = 0; i < 3; i++) { | |
526 | + th->initial_limits[i] = read_reg(th, LIMIT_REG[i]); | |
527 | + set_limit(th, i); | |
528 | + } | |
529 | + | |
530 | + printk(KERN_INFO "adt746x: Lowering max temperatures from %d, %d, %d" | |
531 | + " to %d, %d, %d\n", | |
532 | + th->initial_limits[0], th->initial_limits[1], | |
533 | + th->initial_limits[2], th->limits[0], th->limits[1], | |
534 | + th->limits[2]); | |
535 | + | |
536 | + /* record invert bit status because fw can corrupt it after suspend */ | |
537 | + th->pwm_inv[0] = read_reg(th, MANUAL_MODE[0]) & INVERT_MASK; | |
538 | + th->pwm_inv[1] = read_reg(th, MANUAL_MODE[1]) & INVERT_MASK; | |
539 | + | |
540 | + /* be sure to really write fan speed the first time */ | |
541 | + th->last_speed[0] = -2; | |
542 | + th->last_speed[1] = -2; | |
543 | + th->last_var[0] = -80; | |
544 | + th->last_var[1] = -80; | |
545 | + | |
546 | + if (fan_speed != -1) { | |
547 | + /* manual mode, stop fans */ | |
548 | + write_both_fan_speed(th, 0); | |
549 | + } else { | |
550 | + /* automatic mode */ | |
551 | + write_both_fan_speed(th, -1); | |
552 | + } | |
553 | + | |
554 | + th->thread = kthread_run(monitor_task, th, "kfand"); | |
555 | + if (th->thread == ERR_PTR(-ENOMEM)) { | |
556 | + printk(KERN_INFO "adt746x: Kthread creation failed\n"); | |
557 | + th->thread = NULL; | |
558 | + return -ENOMEM; | |
559 | + } | |
560 | + | |
561 | + thermostat_create_files(th); | |
562 | + | |
563 | + return 0; | |
645 | 564 | } |
646 | 565 | |
647 | -static void thermostat_create_files(void) | |
566 | +static int remove_thermostat(struct i2c_client *client) | |
648 | 567 | { |
649 | - int err; | |
568 | + struct thermostat *th = i2c_get_clientdata(client); | |
569 | + int i; | |
570 | + | |
571 | + thermostat_remove_files(th); | |
650 | 572 | |
651 | - err = device_create_file(&of_dev->dev, &dev_attr_sensor1_temperature); | |
652 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_temperature); | |
653 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_limit); | |
654 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_limit); | |
655 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_location); | |
656 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_location); | |
657 | - err |= device_create_file(&of_dev->dev, &dev_attr_limit_adjust); | |
658 | - err |= device_create_file(&of_dev->dev, &dev_attr_specified_fan_speed); | |
659 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); | |
660 | - if(therm_type == ADT7460) | |
661 | - err |= device_create_file(&of_dev->dev, &dev_attr_sensor2_fan_speed); | |
662 | - if (err) | |
663 | - printk(KERN_WARNING | |
664 | - "Failed to create temperature attribute file(s).\n"); | |
573 | + if (th->thread != NULL) | |
574 | + kthread_stop(th->thread); | |
575 | + | |
576 | + printk(KERN_INFO "adt746x: Putting max temperatures back from " | |
577 | + "%d, %d, %d to %d, %d, %d\n", | |
578 | + th->limits[0], th->limits[1], th->limits[2], | |
579 | + th->initial_limits[0], th->initial_limits[1], | |
580 | + th->initial_limits[2]); | |
581 | + | |
582 | + for (i = 0; i < 3; i++) | |
583 | + write_reg(th, LIMIT_REG[i], th->initial_limits[i]); | |
584 | + | |
585 | + write_both_fan_speed(th, -1); | |
586 | + | |
587 | + kfree(th); | |
588 | + | |
589 | + return 0; | |
665 | 590 | } |
666 | 591 | |
667 | -static void thermostat_remove_files(void) | |
668 | -{ | |
669 | - if (of_dev) { | |
670 | - device_remove_file(&of_dev->dev, &dev_attr_sensor1_temperature); | |
671 | - device_remove_file(&of_dev->dev, &dev_attr_sensor2_temperature); | |
672 | - device_remove_file(&of_dev->dev, &dev_attr_sensor1_limit); | |
673 | - device_remove_file(&of_dev->dev, &dev_attr_sensor2_limit); | |
674 | - device_remove_file(&of_dev->dev, &dev_attr_sensor1_location); | |
675 | - device_remove_file(&of_dev->dev, &dev_attr_sensor2_location); | |
676 | - device_remove_file(&of_dev->dev, &dev_attr_limit_adjust); | |
677 | - device_remove_file(&of_dev->dev, &dev_attr_specified_fan_speed); | |
678 | - device_remove_file(&of_dev->dev, &dev_attr_sensor1_fan_speed); | |
592 | +static const struct i2c_device_id therm_adt746x_id[] = { | |
593 | + { "MAC,adt7460", ADT7460 }, | |
594 | + { "MAC,adt7467", ADT7467 }, | |
595 | + { } | |
596 | +}; | |
597 | +MODULE_DEVICE_TABLE(i2c, therm_adt746x_id); | |
679 | 598 | |
680 | - if(therm_type == ADT7460) | |
681 | - device_remove_file(&of_dev->dev, | |
682 | - &dev_attr_sensor2_fan_speed); | |
599 | +static struct i2c_driver thermostat_driver = { | |
600 | + .driver = { | |
601 | + .name = "therm_adt746x", | |
602 | + }, | |
603 | + .probe = probe_thermostat, | |
604 | + .remove = remove_thermostat, | |
605 | + .id_table = therm_adt746x_id, | |
606 | +}; | |
683 | 607 | |
684 | - } | |
608 | +static int __init thermostat_init(void) | |
609 | +{ | |
610 | +#ifndef CONFIG_I2C_POWERMAC | |
611 | + request_module("i2c-powermac"); | |
612 | +#endif | |
613 | + | |
614 | + return i2c_add_driver(&thermostat_driver); | |
685 | 615 | } |
686 | 616 | |
687 | -static void __exit | |
688 | -thermostat_exit(void) | |
617 | +static void __exit thermostat_exit(void) | |
689 | 618 | { |
690 | 619 | i2c_del_driver(&thermostat_driver); |
691 | - of_device_unregister(of_dev); | |
692 | 620 | } |
693 | 621 | |
694 | 622 | module_init(thermostat_init); |