therm_adt746x.c (16691B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Device driver for the i2c thermostat found on the iBook G4, Albook G4 4 * 5 * Copyright (C) 2003, 2004 Colin Leroy, Rasmus Rohde, Benjamin Herrenschmidt 6 * 7 * Documentation from 115254175ADT7467_pra.pdf and 3686221171167ADT7460_b.pdf 8 * https://www.onsemi.com/PowerSolutions/product.do?id=ADT7467 9 * https://www.onsemi.com/PowerSolutions/product.do?id=ADT7460 10 * 11 */ 12 13#include <linux/types.h> 14#include <linux/module.h> 15#include <linux/errno.h> 16#include <linux/kernel.h> 17#include <linux/delay.h> 18#include <linux/sched.h> 19#include <linux/i2c.h> 20#include <linux/slab.h> 21#include <linux/init.h> 22#include <linux/spinlock.h> 23#include <linux/wait.h> 24#include <linux/suspend.h> 25#include <linux/kthread.h> 26#include <linux/moduleparam.h> 27#include <linux/freezer.h> 28#include <linux/of_platform.h> 29 30#include <asm/machdep.h> 31#include <asm/io.h> 32#include <asm/sections.h> 33 34#undef DEBUG 35 36#define CONFIG_REG 0x40 37#define MANUAL_MASK 0xe0 38#define AUTO_MASK 0x20 39#define INVERT_MASK 0x10 40 41static u8 TEMP_REG[3] = {0x26, 0x25, 0x27}; /* local, sensor1, sensor2 */ 42static u8 LIMIT_REG[3] = {0x6b, 0x6a, 0x6c}; /* local, sensor1, sensor2 */ 43static u8 MANUAL_MODE[2] = {0x5c, 0x5d}; 44static u8 REM_CONTROL[2] = {0x00, 0x40}; 45static u8 FAN_SPEED[2] = {0x28, 0x2a}; 46static u8 FAN_SPD_SET[2] = {0x30, 0x31}; 47 48static u8 default_limits_local[3] = {70, 50, 70}; /* local, sensor1, sensor2 */ 49static u8 default_limits_chip[3] = {80, 65, 80}; /* local, sensor1, sensor2 */ 50static const char *sensor_location[3] = { "?", "?", "?" }; 51 52static int limit_adjust; 53static int fan_speed = -1; 54static bool verbose; 55 56MODULE_AUTHOR("Colin Leroy <colin@colino.net>"); 57MODULE_DESCRIPTION("Driver for ADT746x thermostat in iBook G4 and " 58 "Powerbook G4 Alu"); 59MODULE_LICENSE("GPL"); 60 61module_param(limit_adjust, int, 0644); 62MODULE_PARM_DESC(limit_adjust,"Adjust maximum temperatures (50 sensor1, 70 sensor2) " 63 "by N degrees."); 64 65module_param(fan_speed, int, 0644); 66MODULE_PARM_DESC(fan_speed,"Specify starting fan speed (0-255) " 67 "(default 64)"); 68 69module_param(verbose, bool, 0); 70MODULE_PARM_DESC(verbose,"Verbose log operations " 71 "(default 0)"); 72 73struct thermostat { 74 struct i2c_client *clt; 75 u8 temps[3]; 76 u8 cached_temp[3]; 77 u8 initial_limits[3]; 78 u8 limits[3]; 79 int last_speed[2]; 80 int last_var[2]; 81 int pwm_inv[2]; 82 struct task_struct *thread; 83 struct platform_device *pdev; 84 enum { 85 ADT7460, 86 ADT7467 87 } type; 88}; 89 90static void write_both_fan_speed(struct thermostat *th, int speed); 91static void write_fan_speed(struct thermostat *th, int speed, int fan); 92 93static int 94write_reg(struct thermostat* th, int reg, u8 data) 95{ 96 u8 tmp[2]; 97 int rc; 98 99 tmp[0] = reg; 100 tmp[1] = data; 101 rc = i2c_master_send(th->clt, (const char *)tmp, 2); 102 if (rc < 0) 103 return rc; 104 if (rc != 2) 105 return -ENODEV; 106 return 0; 107} 108 109static int 110read_reg(struct thermostat* th, int reg) 111{ 112 u8 reg_addr, data; 113 int rc; 114 115 reg_addr = (u8)reg; 116 rc = i2c_master_send(th->clt, ®_addr, 1); 117 if (rc < 0) 118 return rc; 119 if (rc != 1) 120 return -ENODEV; 121 rc = i2c_master_recv(th->clt, (char *)&data, 1); 122 if (rc < 0) 123 return rc; 124 return data; 125} 126 127static int read_fan_speed(struct thermostat *th, u8 addr) 128{ 129 u8 tmp[2]; 130 u16 res; 131 132 /* should start with low byte */ 133 tmp[1] = read_reg(th, addr); 134 tmp[0] = read_reg(th, addr + 1); 135 136 res = tmp[1] + (tmp[0] << 8); 137 /* "a value of 0xffff means that the fan has stopped" */ 138 return (res == 0xffff ? 0 : (90000*60)/res); 139} 140 141static void write_both_fan_speed(struct thermostat *th, int speed) 142{ 143 write_fan_speed(th, speed, 0); 144 if (th->type == ADT7460) 145 write_fan_speed(th, speed, 1); 146} 147 148static void write_fan_speed(struct thermostat *th, int speed, int fan) 149{ 150 u8 manual; 151 152 if (speed > 0xff) 153 speed = 0xff; 154 else if (speed < -1) 155 speed = 0; 156 157 if (th->type == ADT7467 && fan == 1) 158 return; 159 160 if (th->last_speed[fan] != speed) { 161 if (verbose) { 162 if (speed == -1) 163 printk(KERN_DEBUG "adt746x: Setting speed to automatic " 164 "for %s fan.\n", sensor_location[fan+1]); 165 else 166 printk(KERN_DEBUG "adt746x: Setting speed to %d " 167 "for %s fan.\n", speed, sensor_location[fan+1]); 168 } 169 } else 170 return; 171 172 if (speed >= 0) { 173 manual = read_reg(th, MANUAL_MODE[fan]); 174 manual &= ~INVERT_MASK; 175 write_reg(th, MANUAL_MODE[fan], 176 manual | MANUAL_MASK | th->pwm_inv[fan]); 177 write_reg(th, FAN_SPD_SET[fan], speed); 178 } else { 179 /* back to automatic */ 180 if(th->type == ADT7460) { 181 manual = read_reg(th, 182 MANUAL_MODE[fan]) & (~MANUAL_MASK); 183 manual &= ~INVERT_MASK; 184 manual |= th->pwm_inv[fan]; 185 write_reg(th, 186 MANUAL_MODE[fan], manual|REM_CONTROL[fan]); 187 } else { 188 manual = read_reg(th, MANUAL_MODE[fan]); 189 manual &= ~INVERT_MASK; 190 manual |= th->pwm_inv[fan]; 191 write_reg(th, MANUAL_MODE[fan], manual&(~AUTO_MASK)); 192 } 193 } 194 195 th->last_speed[fan] = speed; 196} 197 198static void read_sensors(struct thermostat *th) 199{ 200 int i = 0; 201 202 for (i = 0; i < 3; i++) 203 th->temps[i] = read_reg(th, TEMP_REG[i]); 204} 205 206#ifdef DEBUG 207static void display_stats(struct thermostat *th) 208{ 209 if (th->temps[0] != th->cached_temp[0] 210 || th->temps[1] != th->cached_temp[1] 211 || th->temps[2] != th->cached_temp[2]) { 212 printk(KERN_INFO "adt746x: Temperature infos:" 213 " thermostats: %d,%d,%d;" 214 " limits: %d,%d,%d;" 215 " fan speed: %d RPM\n", 216 th->temps[0], th->temps[1], th->temps[2], 217 th->limits[0], th->limits[1], th->limits[2], 218 read_fan_speed(th, FAN_SPEED[0])); 219 } 220 th->cached_temp[0] = th->temps[0]; 221 th->cached_temp[1] = th->temps[1]; 222 th->cached_temp[2] = th->temps[2]; 223} 224#endif 225 226static void update_fans_speed (struct thermostat *th) 227{ 228 int lastvar = 0; /* last variation, for iBook */ 229 int i = 0; 230 231 /* we don't care about local sensor, so we start at sensor 1 */ 232 for (i = 1; i < 3; i++) { 233 bool started = false; 234 int fan_number = (th->type == ADT7460 && i == 2); 235 int var = th->temps[i] - th->limits[i]; 236 237 if (var > -1) { 238 int step = (255 - fan_speed) / 7; 239 int new_speed = 0; 240 241 /* hysteresis : change fan speed only if variation is 242 * more than two degrees */ 243 if (abs(var - th->last_var[fan_number]) < 2) 244 continue; 245 246 started = true; 247 new_speed = fan_speed + ((var-1)*step); 248 249 if (new_speed < fan_speed) 250 new_speed = fan_speed; 251 if (new_speed > 255) 252 new_speed = 255; 253 254 if (verbose) 255 printk(KERN_DEBUG "adt746x: Setting fans speed to %d " 256 "(limit exceeded by %d on %s)\n", 257 new_speed, var, 258 sensor_location[fan_number+1]); 259 write_both_fan_speed(th, new_speed); 260 th->last_var[fan_number] = var; 261 } else if (var < -2) { 262 /* don't stop fan if sensor2 is cold and sensor1 is not 263 * so cold (lastvar >= -1) */ 264 if (i == 2 && lastvar < -1) { 265 if (th->last_speed[fan_number] != 0) 266 if (verbose) 267 printk(KERN_DEBUG "adt746x: Stopping " 268 "fans.\n"); 269 write_both_fan_speed(th, 0); 270 } 271 } 272 273 lastvar = var; 274 275 if (started) 276 return; /* we don't want to re-stop the fan 277 * if sensor1 is heating and sensor2 is not */ 278 } 279} 280 281static int monitor_task(void *arg) 282{ 283 struct thermostat* th = arg; 284 285 set_freezable(); 286 while(!kthread_should_stop()) { 287 try_to_freeze(); 288 msleep_interruptible(2000); 289 290#ifndef DEBUG 291 if (fan_speed != -1) 292 read_sensors(th); 293#else 294 read_sensors(th); 295#endif 296 297 if (fan_speed != -1) 298 update_fans_speed(th); 299 300#ifdef DEBUG 301 display_stats(th); 302#endif 303 304 } 305 306 return 0; 307} 308 309static void set_limit(struct thermostat *th, int i) 310{ 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]); 314 315 /* set our limits to normal */ 316 th->limits[i] = default_limits_local[i] + limit_adjust; 317} 318 319#define BUILD_SHOW_FUNC_INT(name, data) \ 320static 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); \ 324} 325 326#define BUILD_SHOW_FUNC_INT_LITE(name, data) \ 327static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ 328{ \ 329 return sprintf(buf, "%d\n", data); \ 330} 331 332#define BUILD_SHOW_FUNC_STR(name, data) \ 333static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ 334{ \ 335 return sprintf(buf, "%s\n", data); \ 336} 337 338#define BUILD_SHOW_FUNC_FAN(name, data) \ 339static ssize_t show_##name(struct device *dev, struct device_attribute *attr, char *buf) \ 340{ \ 341 struct thermostat *th = dev_get_drvdata(dev); \ 342 return sprintf(buf, "%d (%d rpm)\n", \ 343 th->last_speed[data], \ 344 read_fan_speed(th, FAN_SPEED[data]) \ 345 ); \ 346} 347 348#define BUILD_STORE_FUNC_DEG(name, data) \ 349static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ 350{ \ 351 struct thermostat *th = dev_get_drvdata(dev); \ 352 int val; \ 353 int i; \ 354 val = simple_strtol(buf, NULL, 10); \ 355 printk(KERN_INFO "Adjusting limits by %d degrees\n", val); \ 356 limit_adjust = val; \ 357 for (i=0; i < 3; i++) \ 358 set_limit(th, i); \ 359 return n; \ 360} 361 362#define BUILD_STORE_FUNC_INT(name, data) \ 363static ssize_t store_##name(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) \ 364{ \ 365 int val; \ 366 val = simple_strtol(buf, NULL, 10); \ 367 if (val < 0 || val > 255) \ 368 return -EINVAL; \ 369 printk(KERN_INFO "Setting specified fan speed to %d\n", val); \ 370 data = val; \ 371 return n; \ 372} 373 374BUILD_SHOW_FUNC_INT(sensor1_temperature, (read_reg(th, TEMP_REG[1]))) 375BUILD_SHOW_FUNC_INT(sensor2_temperature, (read_reg(th, TEMP_REG[2]))) 376BUILD_SHOW_FUNC_INT(sensor1_limit, th->limits[1]) 377BUILD_SHOW_FUNC_INT(sensor2_limit, th->limits[2]) 378BUILD_SHOW_FUNC_STR(sensor1_location, sensor_location[1]) 379BUILD_SHOW_FUNC_STR(sensor2_location, sensor_location[2]) 380 381BUILD_SHOW_FUNC_INT_LITE(specified_fan_speed, fan_speed) 382BUILD_STORE_FUNC_INT(specified_fan_speed,fan_speed) 383 384BUILD_SHOW_FUNC_FAN(sensor1_fan_speed, 0) 385BUILD_SHOW_FUNC_FAN(sensor2_fan_speed, 1) 386 387BUILD_SHOW_FUNC_INT_LITE(limit_adjust, limit_adjust) 388BUILD_STORE_FUNC_DEG(limit_adjust, th) 389 390static DEVICE_ATTR(sensor1_temperature, S_IRUGO, 391 show_sensor1_temperature,NULL); 392static DEVICE_ATTR(sensor2_temperature, S_IRUGO, 393 show_sensor2_temperature,NULL); 394static DEVICE_ATTR(sensor1_limit, S_IRUGO, 395 show_sensor1_limit, NULL); 396static DEVICE_ATTR(sensor2_limit, S_IRUGO, 397 show_sensor2_limit, NULL); 398static DEVICE_ATTR(sensor1_location, S_IRUGO, 399 show_sensor1_location, NULL); 400static DEVICE_ATTR(sensor2_location, S_IRUGO, 401 show_sensor2_location, NULL); 402 403static DEVICE_ATTR(specified_fan_speed, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 404 show_specified_fan_speed,store_specified_fan_speed); 405 406static DEVICE_ATTR(sensor1_fan_speed, S_IRUGO, 407 show_sensor1_fan_speed, NULL); 408static DEVICE_ATTR(sensor2_fan_speed, S_IRUGO, 409 show_sensor2_fan_speed, NULL); 410 411static DEVICE_ATTR(limit_adjust, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH, 412 show_limit_adjust, store_limit_adjust); 413 414static void thermostat_create_files(struct thermostat *th) 415{ 416 struct device_node *np = th->clt->dev.of_node; 417 struct device *dev; 418 int err; 419 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} 444 445static void thermostat_remove_files(struct thermostat *th) 446{ 447 struct device *dev; 448 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); 464 465} 466 467static 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; 474 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; 485 486 if (of_get_property(np, "hwsensor-location", NULL)) { 487 for (i = 0; i < 3; i++) { 488 sensor_location[i] = of_get_property(np, 489 "hwsensor-location", NULL) + offset; 490 491 if (sensor_location[i] == NULL) 492 sensor_location[i] = ""; 493 494 printk(KERN_INFO "sensor %d: %s\n", i, sensor_location[i]); 495 offset += strlen(sensor_location[i]) + 1; 496 } 497 } 498 499 th = kzalloc(sizeof(struct thermostat), GFP_KERNEL); 500 if (!th) 501 return -ENOMEM; 502 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); 511 return -ENODEV; 512 } 513 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"); 524 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; 564} 565 566static int remove_thermostat(struct i2c_client *client) 567{ 568 struct thermostat *th = i2c_get_clientdata(client); 569 int i; 570 571 thermostat_remove_files(th); 572 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; 590} 591 592static const struct i2c_device_id therm_adt746x_id[] = { 593 { "MAC,adt7460", ADT7460 }, 594 { "MAC,adt7467", ADT7467 }, 595 { } 596}; 597MODULE_DEVICE_TABLE(i2c, therm_adt746x_id); 598 599static 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}; 607 608static 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); 615} 616 617static void __exit thermostat_exit(void) 618{ 619 i2c_del_driver(&thermostat_driver); 620} 621 622module_init(thermostat_init); 623module_exit(thermostat_exit);