1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * acerhdf - A driver which monitors the temperature 4 * of the aspire one netbook, turns on/off the fan 5 * as soon as the upper/lower threshold is reached. 6 * 7 * (C) 2009 - Peter Kaestle peter (a) piie.net 8 * https://piie.net 9 * 2009 Borislav Petkov bp (a) alien8.de 10 * 11 * Inspired by and many thanks to: 12 * o acerfand - Rachel Greenham 13 * o acer_ec.pl - Michael Kurz michi.kurz (at) googlemail.com 14 * - Petr Tomasek tomasek (#) etf,cuni,cz 15 * - Carlos Corbacho cathectic (at) gmail.com 16 * o lkml - Matthew Garrett 17 * - Borislav Petkov 18 * - Andreas Mohr 19 */ 20 21 #define pr_fmt(fmt) "acerhdf: " fmt 22 23 #include <linux/kernel.h> 24 #include <linux/module.h> 25 #include <linux/dmi.h> 26 #include <linux/acpi.h> 27 #include <linux/thermal.h> 28 #include <linux/platform_device.h> 29 30 /* 31 * The driver is started with "kernel mode off" by default. That means, the BIOS 32 * is still in control of the fan. In this mode the driver allows to read the 33 * temperature of the cpu and a userspace tool may take over control of the fan. 34 * If the driver is switched to "kernel mode" (e.g. via module parameter) the 35 * driver is in full control of the fan. If you want the module to be started in 36 * kernel mode by default, define the following: 37 */ 38 #undef START_IN_KERNEL_MODE 39 40 #define DRV_VER "0.7.0" 41 42 /* 43 * According to the Atom N270 datasheet, 44 * (http://download.intel.com/design/processor/datashts/320032.pdf) the 45 * CPU's optimal operating limits denoted in junction temperature as 46 * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So, 47 * assume 89°C is critical temperature. 48 */ 49 #define ACERHDF_DEFAULT_TEMP_FANON 60000 50 #define ACERHDF_DEFAULT_TEMP_FANOFF 53000 51 #define ACERHDF_TEMP_CRIT 89000 52 #define ACERHDF_FAN_OFF 0 53 #define ACERHDF_FAN_AUTO 1 54 55 /* 56 * No matter what value the user puts into the fanon variable, turn on the fan 57 * at 80 degree Celsius to prevent hardware damage 58 */ 59 #define ACERHDF_MAX_FANON 80000 60 61 /* 62 * Maximum interval between two temperature checks is 15 seconds, as the die 63 * can get hot really fast under heavy load (plus we shouldn't forget about 64 * possible impact of _external_ aggressive sources such as heaters, sun etc.) 65 */ 66 #define ACERHDF_MAX_INTERVAL 15 67 68 #ifdef START_IN_KERNEL_MODE 69 static int kernelmode = 1; 70 #else 71 static int kernelmode; 72 #endif 73 74 static unsigned int interval = 10; 75 static unsigned int fanon = ACERHDF_DEFAULT_TEMP_FANON; 76 static unsigned int fanoff = ACERHDF_DEFAULT_TEMP_FANOFF; 77 static unsigned int verbose; 78 static unsigned int list_supported; 79 static unsigned int fanstate = ACERHDF_FAN_AUTO; 80 static char force_bios[16]; 81 static char force_product[16]; 82 static unsigned int prev_interval; 83 static struct thermal_zone_device *thz_dev; 84 static struct thermal_cooling_device *cl_dev; 85 static struct platform_device *acerhdf_dev; 86 87 module_param(kernelmode, uint, 0); 88 MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off"); 89 module_param(fanon, uint, 0600); 90 MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature"); 91 module_param(fanoff, uint, 0600); 92 MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature"); 93 module_param(verbose, uint, 0600); 94 MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); 95 module_param(list_supported, uint, 0600); 96 MODULE_PARM_DESC(list_supported, "List supported models and BIOS versions"); 97 module_param_string(force_bios, force_bios, 16, 0); 98 MODULE_PARM_DESC(force_bios, "Pretend system has this known supported BIOS version"); 99 module_param_string(force_product, force_product, 16, 0); 100 MODULE_PARM_DESC(force_product, "Pretend system is this known supported model"); 101 102 /* 103 * cmd_off: to switch the fan completely off and check if the fan is off 104 * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then 105 * the fan speed depending on the temperature 106 */ 107 struct fancmd { 108 u8 cmd_off; 109 u8 cmd_auto; 110 }; 111 112 struct manualcmd { 113 u8 mreg; 114 u8 moff; 115 }; 116 117 /* default register and command to disable fan in manual mode */ 118 static const struct manualcmd mcmd = { 119 .mreg = 0x94, 120 .moff = 0xff, 121 }; 122 123 /* BIOS settings - only used during probe */ 124 struct bios_settings { 125 const char *vendor; 126 const char *product; 127 const char *version; 128 u8 fanreg; 129 u8 tempreg; 130 struct fancmd cmd; 131 int mcmd_enable; 132 }; 133 134 /* This could be a daughter struct in the above, but not worth the redirect */ 135 struct ctrl_settings { 136 u8 fanreg; 137 u8 tempreg; 138 struct fancmd cmd; 139 int mcmd_enable; 140 }; 141 142 static struct thermal_trip trips[] = { 143 [0] = { .temperature = ACERHDF_DEFAULT_TEMP_FANON, 144 .hysteresis = ACERHDF_DEFAULT_TEMP_FANON - ACERHDF_DEFAULT_TEMP_FANOFF, 145 .type = THERMAL_TRIP_ACTIVE }, 146 147 [1] = { .temperature = ACERHDF_TEMP_CRIT, 148 .type = THERMAL_TRIP_CRITICAL } 149 }; 150 151 static struct ctrl_settings ctrl_cfg __read_mostly; 152 153 /* Register addresses and values for different BIOS versions */ 154 static const struct bios_settings bios_tbl[] __initconst = { 155 /* AOA110 */ 156 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0}, 157 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, 158 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00}, 0}, 159 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00}, 0}, 160 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00}, 0}, 161 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00}, 0}, 162 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00}, 0}, 163 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00}, 0}, 164 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00}, 0}, 165 /* AOA150 */ 166 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, 167 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00}, 0}, 168 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0}, 169 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00}, 0}, 170 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00}, 0}, 171 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00}, 0}, 172 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00}, 0}, 173 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0}, 174 /* LT1005u */ 175 {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0}, 176 /* Acer 1410 */ 177 {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 178 {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 179 {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 180 {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 181 {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 182 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 183 {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 184 {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 185 {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 186 {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 187 {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 188 /* Acer 1810xx */ 189 {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 190 {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 191 {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 192 {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 193 {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 194 {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 195 {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 196 {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 197 {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 198 {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 199 {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 200 {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 201 {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 202 {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 203 {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 204 {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 205 {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 206 {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 207 {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 208 {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0}, 209 {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 210 {"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0}, 211 /* Acer 5755G */ 212 {"Acer", "Aspire 5755G", "V1.20", 0xab, 0xb4, {0x00, 0x08}, 0}, 213 {"Acer", "Aspire 5755G", "V1.21", 0xab, 0xb3, {0x00, 0x08}, 0}, 214 /* Acer 521 */ 215 {"Acer", "AO521", "V1.11", 0x55, 0x58, {0x1f, 0x00}, 0}, 216 /* Acer 531 */ 217 {"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00}, 0}, 218 {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00}, 0}, 219 {"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0}, 220 /* Acer 751 */ 221 {"Acer", "AO751h", "V0.3206", 0x55, 0x58, {0x21, 0x00}, 0}, 222 {"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00}, 0}, 223 /* Acer 753 */ 224 {"Acer", "Aspire One 753", "V1.24", 0x93, 0xac, {0x14, 0x04}, 1}, 225 /* Acer 1825 */ 226 {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0}, 227 {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0}, 228 /* Acer Extensa 5420 */ 229 {"Acer", "Extensa 5420", "V1.17", 0x93, 0xac, {0x14, 0x04}, 1}, 230 /* Acer Aspire 5315 */ 231 {"Acer", "Aspire 5315", "V1.19", 0x93, 0xac, {0x14, 0x04}, 1}, 232 /* Acer Aspire 5739 */ 233 {"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0}, 234 /* Acer TravelMate 7730 */ 235 {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0}, 236 /* Acer Aspire 7551 */ 237 {"Acer", "Aspire 7551", "V1.18", 0x93, 0xa8, {0x14, 0x04}, 1}, 238 /* Acer TravelMate TM8573T */ 239 {"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1}, 240 /* Gateway */ 241 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00}, 0}, 242 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00}, 0}, 243 {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00}, 0}, 244 {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, 245 {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, 246 {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, 247 {"Gateway", "LT31", "v1.3307", 0x55, 0x58, {0x9e, 0x00}, 0}, 248 /* Packard Bell */ 249 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0}, 250 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, 251 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00}, 0}, 252 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, 253 {"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0}, 254 {"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0}, 255 {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0}, 256 {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0}, 257 {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0}, 258 {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0}, 259 {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0}, 260 {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0}, 261 {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0}, 262 {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0}, 263 {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, 264 {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, 265 {"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, 266 {"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0}, 267 /* pewpew-terminator */ 268 {"", "", "", 0, 0, {0, 0}, 0} 269 }; 270 271 /* 272 * this struct is used to instruct thermal layer to use bang_bang instead of 273 * default governor for acerhdf 274 */ 275 static struct thermal_zone_params acerhdf_zone_params = { 276 .governor_name = "bang_bang", 277 }; 278 279 static int acerhdf_get_temp(int *temp) 280 { 281 u8 read_temp; 282 283 if (ec_read(ctrl_cfg.tempreg, &read_temp)) 284 return -EINVAL; 285 286 *temp = read_temp * 1000; 287 288 return 0; 289 } 290 291 static int acerhdf_get_fanstate(int *state) 292 { 293 u8 fan; 294 295 if (ec_read(ctrl_cfg.fanreg, &fan)) 296 return -EINVAL; 297 298 if (fan != ctrl_cfg.cmd.cmd_off) 299 *state = ACERHDF_FAN_AUTO; 300 else 301 *state = ACERHDF_FAN_OFF; 302 303 return 0; 304 } 305 306 static void acerhdf_change_fanstate(int state) 307 { 308 unsigned char cmd; 309 310 if (verbose) 311 pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON"); 312 313 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) { 314 pr_err("invalid fan state %d requested, setting to auto!\n", 315 state); 316 state = ACERHDF_FAN_AUTO; 317 } 318 319 cmd = (state == ACERHDF_FAN_OFF) ? ctrl_cfg.cmd.cmd_off 320 : ctrl_cfg.cmd.cmd_auto; 321 fanstate = state; 322 323 ec_write(ctrl_cfg.fanreg, cmd); 324 325 if (ctrl_cfg.mcmd_enable && state == ACERHDF_FAN_OFF) { 326 if (verbose) 327 pr_notice("turning off fan manually\n"); 328 ec_write(mcmd.mreg, mcmd.moff); 329 } 330 } 331 332 static void acerhdf_check_param(struct thermal_zone_device *thermal) 333 { 334 if (fanon > ACERHDF_MAX_FANON) { 335 pr_err("fanon temperature too high, set to %d\n", 336 ACERHDF_MAX_FANON); 337 fanon = ACERHDF_MAX_FANON; 338 } 339 340 if (fanon < fanoff) { 341 pr_err("fanoff temperature (%d) is above fanon temperature (%d), clamping to %d\n", 342 fanoff, fanon, fanon); 343 fanoff = fanon; 344 }; 345 346 trips[0].temperature = fanon; 347 trips[0].hysteresis = fanon - fanoff; 348 349 if (kernelmode && prev_interval != interval) { 350 if (interval > ACERHDF_MAX_INTERVAL) { 351 pr_err("interval too high, set to %d\n", 352 ACERHDF_MAX_INTERVAL); 353 interval = ACERHDF_MAX_INTERVAL; 354 } 355 if (verbose) 356 pr_notice("interval changed to: %d\n", interval); 357 358 if (thermal) 359 thermal->polling_delay_jiffies = 360 round_jiffies(msecs_to_jiffies(interval * 1000)); 361 362 prev_interval = interval; 363 } 364 } 365 366 /* 367 * This is the thermal zone callback which does the delayed polling of the fan 368 * state. We do check /sysfs-originating settings here in acerhdf_check_param() 369 * as late as the polling interval is since we can't do that in the respective 370 * accessors of the module parameters. 371 */ 372 static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t) 373 { 374 int temp, err = 0; 375 376 err = acerhdf_get_temp(&temp); 377 if (err) 378 return err; 379 380 if (verbose) 381 pr_notice("temp %d\n", temp); 382 383 *t = temp; 384 return 0; 385 } 386 387 static int acerhdf_bind(struct thermal_zone_device *thermal, 388 struct thermal_cooling_device *cdev) 389 { 390 /* if the cooling device is the one from acerhdf bind it */ 391 if (cdev != cl_dev) 392 return 0; 393 394 if (thermal_zone_bind_cooling_device(thermal, 0, cdev, 395 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT, 396 THERMAL_WEIGHT_DEFAULT)) { 397 pr_err("error binding cooling dev\n"); 398 return -EINVAL; 399 } 400 return 0; 401 } 402 403 static int acerhdf_unbind(struct thermal_zone_device *thermal, 404 struct thermal_cooling_device *cdev) 405 { 406 if (cdev != cl_dev) 407 return 0; 408 409 if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) { 410 pr_err("error unbinding cooling dev\n"); 411 return -EINVAL; 412 } 413 return 0; 414 } 415 416 static inline void acerhdf_revert_to_bios_mode(void) 417 { 418 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 419 kernelmode = 0; 420 421 pr_notice("kernel mode fan control OFF\n"); 422 } 423 static inline void acerhdf_enable_kernelmode(void) 424 { 425 kernelmode = 1; 426 427 pr_notice("kernel mode fan control ON\n"); 428 } 429 430 /* 431 * set operation mode; 432 * enabled: the thermal layer of the kernel takes care about 433 * the temperature and the fan. 434 * disabled: the BIOS takes control of the fan. 435 */ 436 static int acerhdf_change_mode(struct thermal_zone_device *thermal, 437 enum thermal_device_mode mode) 438 { 439 if (mode == THERMAL_DEVICE_DISABLED && kernelmode) 440 acerhdf_revert_to_bios_mode(); 441 else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode) 442 acerhdf_enable_kernelmode(); 443 444 return 0; 445 } 446 447 static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal, 448 int *temperature) 449 { 450 *temperature = ACERHDF_TEMP_CRIT; 451 return 0; 452 } 453 454 /* bind callback functions to thermalzone */ 455 static struct thermal_zone_device_ops acerhdf_dev_ops = { 456 .bind = acerhdf_bind, 457 .unbind = acerhdf_unbind, 458 .get_temp = acerhdf_get_ec_temp, 459 .change_mode = acerhdf_change_mode, 460 .get_crit_temp = acerhdf_get_crit_temp, 461 }; 462 463 /* 464 * cooling device callback functions 465 * get maximal fan cooling state 466 */ 467 static int acerhdf_get_max_state(struct thermal_cooling_device *cdev, 468 unsigned long *state) 469 { 470 *state = 1; 471 472 return 0; 473 } 474 475 static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev, 476 unsigned long *state) 477 { 478 int err = 0, tmp; 479 480 err = acerhdf_get_fanstate(&tmp); 481 if (err) 482 return err; 483 484 *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0; 485 return 0; 486 } 487 488 /* change current fan state - is overwritten when running in kernel mode */ 489 static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev, 490 unsigned long state) 491 { 492 int cur_temp, cur_state, err = 0; 493 494 if (!kernelmode) 495 return 0; 496 497 err = acerhdf_get_temp(&cur_temp); 498 if (err) { 499 pr_err("error reading temperature, hand off control to BIOS\n"); 500 goto err_out; 501 } 502 503 err = acerhdf_get_fanstate(&cur_state); 504 if (err) { 505 pr_err("error reading fan state, hand off control to BIOS\n"); 506 goto err_out; 507 } 508 509 if (state == 0) { 510 if (cur_state == ACERHDF_FAN_AUTO) 511 acerhdf_change_fanstate(ACERHDF_FAN_OFF); 512 } else { 513 if (cur_state == ACERHDF_FAN_OFF) 514 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 515 } 516 return 0; 517 518 err_out: 519 acerhdf_revert_to_bios_mode(); 520 return -EINVAL; 521 } 522 523 /* bind fan callbacks to fan device */ 524 static const struct thermal_cooling_device_ops acerhdf_cooling_ops = { 525 .get_max_state = acerhdf_get_max_state, 526 .get_cur_state = acerhdf_get_cur_state, 527 .set_cur_state = acerhdf_set_cur_state, 528 }; 529 530 /* suspend / resume functionality */ 531 static int acerhdf_suspend(struct device *dev) 532 { 533 if (kernelmode) 534 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 535 536 if (verbose) 537 pr_notice("going suspend\n"); 538 539 return 0; 540 } 541 542 static int acerhdf_probe(struct platform_device *device) 543 { 544 return 0; 545 } 546 547 static const struct dev_pm_ops acerhdf_pm_ops = { 548 .suspend = acerhdf_suspend, 549 .freeze = acerhdf_suspend, 550 }; 551 552 static struct platform_driver acerhdf_driver = { 553 .driver = { 554 .name = "acerhdf", 555 .pm = &acerhdf_pm_ops, 556 }, 557 .probe = acerhdf_probe, 558 }; 559 560 /* check hardware */ 561 static int __init acerhdf_check_hardware(void) 562 { 563 char const *vendor, *version, *product; 564 const struct bios_settings *bt = NULL; 565 int found = 0; 566 567 /* get BIOS data */ 568 vendor = dmi_get_system_info(DMI_SYS_VENDOR); 569 version = dmi_get_system_info(DMI_BIOS_VERSION); 570 product = dmi_get_system_info(DMI_PRODUCT_NAME); 571 572 if (!vendor || !version || !product) { 573 pr_err("error getting hardware information\n"); 574 return -EINVAL; 575 } 576 577 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); 578 579 if (list_supported) { 580 pr_info("List of supported Manufacturer/Model/BIOS:\n"); 581 pr_info("---------------------------------------------------\n"); 582 for (bt = bios_tbl; bt->vendor[0]; bt++) { 583 pr_info("%-13s | %-17s | %-10s\n", bt->vendor, 584 bt->product, bt->version); 585 } 586 pr_info("---------------------------------------------------\n"); 587 return -ECANCELED; 588 } 589 590 if (force_bios[0]) { 591 version = force_bios; 592 pr_info("forcing BIOS version: %s\n", version); 593 kernelmode = 0; 594 } 595 596 if (force_product[0]) { 597 product = force_product; 598 pr_info("forcing BIOS product: %s\n", product); 599 kernelmode = 0; 600 } 601 602 if (verbose) 603 pr_info("BIOS info: %s %s, product: %s\n", 604 vendor, version, product); 605 606 /* search BIOS version and vendor in BIOS settings table */ 607 for (bt = bios_tbl; bt->vendor[0]; bt++) { 608 /* 609 * check if actual hardware BIOS vendor, product and version 610 * IDs start with the strings of BIOS table entry 611 */ 612 if (strstarts(vendor, bt->vendor) && 613 strstarts(product, bt->product) && 614 strstarts(version, bt->version)) { 615 found = 1; 616 break; 617 } 618 } 619 620 if (!found) { 621 pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n", 622 vendor, product, version); 623 return -EINVAL; 624 } 625 626 /* Copy control settings from BIOS table before we free it. */ 627 ctrl_cfg.fanreg = bt->fanreg; 628 ctrl_cfg.tempreg = bt->tempreg; 629 memcpy(&ctrl_cfg.cmd, &bt->cmd, sizeof(struct fancmd)); 630 ctrl_cfg.mcmd_enable = bt->mcmd_enable; 631 632 /* 633 * if started with kernel mode off, prevent the kernel from switching 634 * off the fan 635 */ 636 if (!kernelmode) { 637 pr_notice("Fan control off, to enable do:\n"); 638 pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zoneN/mode # N=0,1,2...\n"); 639 } 640 641 return 0; 642 } 643 644 static int __init acerhdf_register_platform(void) 645 { 646 int err = 0; 647 648 err = platform_driver_register(&acerhdf_driver); 649 if (err) 650 return err; 651 652 acerhdf_dev = platform_device_alloc("acerhdf", PLATFORM_DEVID_NONE); 653 if (!acerhdf_dev) { 654 err = -ENOMEM; 655 goto err_device_alloc; 656 } 657 err = platform_device_add(acerhdf_dev); 658 if (err) 659 goto err_device_add; 660 661 return 0; 662 663 err_device_add: 664 platform_device_put(acerhdf_dev); 665 err_device_alloc: 666 platform_driver_unregister(&acerhdf_driver); 667 return err; 668 } 669 670 static void acerhdf_unregister_platform(void) 671 { 672 platform_device_unregister(acerhdf_dev); 673 platform_driver_unregister(&acerhdf_driver); 674 } 675 676 static int __init acerhdf_register_thermal(void) 677 { 678 int ret; 679 680 cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, 681 &acerhdf_cooling_ops); 682 683 if (IS_ERR(cl_dev)) 684 return -EINVAL; 685 686 thz_dev = thermal_zone_device_register_with_trips("acerhdf", trips, ARRAY_SIZE(trips), 687 0, NULL, &acerhdf_dev_ops, 688 &acerhdf_zone_params, 0, 689 (kernelmode) ? interval*1000 : 0); 690 if (IS_ERR(thz_dev)) 691 return -EINVAL; 692 693 if (kernelmode) 694 ret = thermal_zone_device_enable(thz_dev); 695 else 696 ret = thermal_zone_device_disable(thz_dev); 697 if (ret) 698 return ret; 699 700 if (strcmp(thz_dev->governor->name, 701 acerhdf_zone_params.governor_name)) { 702 pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n", 703 acerhdf_zone_params.governor_name); 704 return -EINVAL; 705 } 706 707 return 0; 708 } 709 710 static void acerhdf_unregister_thermal(void) 711 { 712 if (cl_dev) { 713 thermal_cooling_device_unregister(cl_dev); 714 cl_dev = NULL; 715 } 716 717 if (thz_dev) { 718 thermal_zone_device_unregister(thz_dev); 719 thz_dev = NULL; 720 } 721 } 722 723 static int __init acerhdf_init(void) 724 { 725 int err = 0; 726 727 err = acerhdf_check_hardware(); 728 if (err) 729 goto out_err; 730 731 err = acerhdf_register_platform(); 732 if (err) 733 goto out_err; 734 735 err = acerhdf_register_thermal(); 736 if (err) 737 goto err_unreg; 738 739 return 0; 740 741 err_unreg: 742 acerhdf_unregister_thermal(); 743 acerhdf_unregister_platform(); 744 745 out_err: 746 return err; 747 } 748 749 static void __exit acerhdf_exit(void) 750 { 751 acerhdf_change_fanstate(ACERHDF_FAN_AUTO); 752 acerhdf_unregister_thermal(); 753 acerhdf_unregister_platform(); 754 } 755 756 MODULE_LICENSE("GPL"); 757 MODULE_AUTHOR("Peter Kaestle"); 758 MODULE_DESCRIPTION("Aspire One temperature and fan driver"); 759 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:"); 760 MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:"); 761 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:"); 762 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:"); 763 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5755G:"); 764 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1825PTZ:"); 765 MODULE_ALIAS("dmi:*:*Acer*:pnAO521*:"); 766 MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:"); 767 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5739G:"); 768 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*One*753:"); 769 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5315:"); 770 MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:"); 771 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*7551:"); 772 MODULE_ALIAS("dmi:*:*Acer*:TM8573T:"); 773 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:"); 774 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:"); 775 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:"); 776 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:"); 777 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:"); 778 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnENBFT*:"); 779 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:"); 780 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTVR46*:"); 781 MODULE_ALIAS("dmi:*:*Acer*:pnExtensa*5420*:"); 782 783 module_init(acerhdf_init); 784 module_exit(acerhdf_exit); 785 786 static int interval_set_uint(const char *val, const struct kernel_param *kp) 787 { 788 int ret; 789 790 ret = param_set_uint(val, kp); 791 if (ret) 792 return ret; 793 794 acerhdf_check_param(thz_dev); 795 796 return 0; 797 } 798 799 static const struct kernel_param_ops interval_ops = { 800 .set = interval_set_uint, 801 .get = param_get_uint, 802 }; 803 804 module_param_cb(interval, &interval_ops, &interval, 0600); 805 MODULE_PARM_DESC(interval, "Polling interval of temperature check"); 806