0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #define pr_fmt(fmt) "acerhdf: " fmt
0022
0023 #include <linux/kernel.h>
0024 #include <linux/module.h>
0025 #include <linux/dmi.h>
0026 #include <linux/acpi.h>
0027 #include <linux/thermal.h>
0028 #include <linux/platform_device.h>
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 #undef START_IN_KERNEL_MODE
0039
0040 #define DRV_VER "0.7.0"
0041
0042
0043
0044
0045
0046
0047
0048
0049 #define ACERHDF_TEMP_CRIT 89000
0050 #define ACERHDF_FAN_OFF 0
0051 #define ACERHDF_FAN_AUTO 1
0052
0053
0054
0055
0056
0057 #define ACERHDF_MAX_FANON 80000
0058
0059
0060
0061
0062
0063
0064 #define ACERHDF_MAX_INTERVAL 15
0065
0066 #ifdef START_IN_KERNEL_MODE
0067 static int kernelmode = 1;
0068 #else
0069 static int kernelmode;
0070 #endif
0071
0072 static unsigned int interval = 10;
0073 static unsigned int fanon = 60000;
0074 static unsigned int fanoff = 53000;
0075 static unsigned int verbose;
0076 static unsigned int list_supported;
0077 static unsigned int fanstate = ACERHDF_FAN_AUTO;
0078 static char force_bios[16];
0079 static char force_product[16];
0080 static unsigned int prev_interval;
0081 static struct thermal_zone_device *thz_dev;
0082 static struct thermal_cooling_device *cl_dev;
0083 static struct platform_device *acerhdf_dev;
0084
0085 module_param(kernelmode, uint, 0);
0086 MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
0087 module_param(fanon, uint, 0600);
0088 MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature");
0089 module_param(fanoff, uint, 0600);
0090 MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature");
0091 module_param(verbose, uint, 0600);
0092 MODULE_PARM_DESC(verbose, "Enable verbose dmesg output");
0093 module_param(list_supported, uint, 0600);
0094 MODULE_PARM_DESC(list_supported, "List supported models and BIOS versions");
0095 module_param_string(force_bios, force_bios, 16, 0);
0096 MODULE_PARM_DESC(force_bios, "Pretend system has this known supported BIOS version");
0097 module_param_string(force_product, force_product, 16, 0);
0098 MODULE_PARM_DESC(force_product, "Pretend system is this known supported model");
0099
0100
0101
0102
0103
0104
0105 struct fancmd {
0106 u8 cmd_off;
0107 u8 cmd_auto;
0108 };
0109
0110 struct manualcmd {
0111 u8 mreg;
0112 u8 moff;
0113 };
0114
0115
0116 static const struct manualcmd mcmd = {
0117 .mreg = 0x94,
0118 .moff = 0xff,
0119 };
0120
0121
0122 struct bios_settings {
0123 const char *vendor;
0124 const char *product;
0125 const char *version;
0126 u8 fanreg;
0127 u8 tempreg;
0128 struct fancmd cmd;
0129 int mcmd_enable;
0130 };
0131
0132
0133 struct ctrl_settings {
0134 u8 fanreg;
0135 u8 tempreg;
0136 struct fancmd cmd;
0137 int mcmd_enable;
0138 };
0139
0140 static struct ctrl_settings ctrl_cfg __read_mostly;
0141
0142
0143 static const struct bios_settings bios_tbl[] __initconst = {
0144
0145 {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0},
0146 {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0},
0147 {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00}, 0},
0148 {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00}, 0},
0149 {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00}, 0},
0150 {"Acer", "AOA110", "v0.3307", 0x55, 0x58, {0xaf, 0x00}, 0},
0151 {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00}, 0},
0152 {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00}, 0},
0153 {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00}, 0},
0154
0155 {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0},
0156 {"Acer", "AOA150", "v0.3301", 0x55, 0x58, {0x20, 0x00}, 0},
0157 {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0},
0158 {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00}, 0},
0159 {"Acer", "AOA150", "v0.3307", 0x55, 0x58, {0x20, 0x00}, 0},
0160 {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00}, 0},
0161 {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00}, 0},
0162 {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0},
0163
0164 {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0},
0165
0166 {"Acer", "Aspire 1410", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
0167 {"Acer", "Aspire 1410", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
0168 {"Acer", "Aspire 1410", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
0169 {"Acer", "Aspire 1410", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
0170 {"Acer", "Aspire 1410", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
0171 {"Acer", "Aspire 1410", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
0172 {"Acer", "Aspire 1410", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
0173 {"Acer", "Aspire 1410", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
0174 {"Acer", "Aspire 1410", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
0175 {"Acer", "Aspire 1410", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
0176 {"Acer", "Aspire 1410", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
0177
0178 {"Acer", "Aspire 1810TZ", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
0179 {"Acer", "Aspire 1810T", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
0180 {"Acer", "Aspire 1810TZ", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
0181 {"Acer", "Aspire 1810T", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
0182 {"Acer", "Aspire 1810TZ", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
0183 {"Acer", "Aspire 1810T", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
0184 {"Acer", "Aspire 1810TZ", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
0185 {"Acer", "Aspire 1810T", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
0186 {"Acer", "Aspire 1810TZ", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
0187 {"Acer", "Aspire 1810T", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
0188 {"Acer", "Aspire 1810TZ", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
0189 {"Acer", "Aspire 1810T", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
0190 {"Acer", "Aspire 1810TZ", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
0191 {"Acer", "Aspire 1810T", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
0192 {"Acer", "Aspire 1810TZ", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
0193 {"Acer", "Aspire 1810T", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
0194 {"Acer", "Aspire 1810TZ", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
0195 {"Acer", "Aspire 1810T", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
0196 {"Acer", "Aspire 1810TZ", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
0197 {"Acer", "Aspire 1810T", "v1.3310", 0x55, 0x58, {0x9e, 0x00}, 0},
0198 {"Acer", "Aspire 1810TZ", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
0199 {"Acer", "Aspire 1810T", "v1.3314", 0x55, 0x58, {0x9e, 0x00}, 0},
0200
0201 {"Acer", "Aspire 5755G", "V1.20", 0xab, 0xb4, {0x00, 0x08}, 0},
0202 {"Acer", "Aspire 5755G", "V1.21", 0xab, 0xb3, {0x00, 0x08}, 0},
0203
0204 {"Acer", "AO521", "V1.11", 0x55, 0x58, {0x1f, 0x00}, 0},
0205
0206 {"Acer", "AO531h", "v0.3104", 0x55, 0x58, {0x20, 0x00}, 0},
0207 {"Acer", "AO531h", "v0.3201", 0x55, 0x58, {0x20, 0x00}, 0},
0208 {"Acer", "AO531h", "v0.3304", 0x55, 0x58, {0x20, 0x00}, 0},
0209
0210 {"Acer", "AO751h", "V0.3206", 0x55, 0x58, {0x21, 0x00}, 0},
0211 {"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00}, 0},
0212
0213 {"Acer", "Aspire One 753", "V1.24", 0x93, 0xac, {0x14, 0x04}, 1},
0214
0215 {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0},
0216 {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0},
0217
0218 {"Acer", "Extensa 5420", "V1.17", 0x93, 0xac, {0x14, 0x04}, 1},
0219
0220 {"Acer", "Aspire 5315", "V1.19", 0x93, 0xac, {0x14, 0x04}, 1},
0221
0222 {"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0},
0223
0224 {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0},
0225
0226 {"Acer", "Aspire 7551", "V1.18", 0x93, 0xa8, {0x14, 0x04}, 1},
0227
0228 {"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1},
0229
0230 {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00}, 0},
0231 {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00}, 0},
0232 {"Gateway", "LT31", "v1.3103", 0x55, 0x58, {0x9e, 0x00}, 0},
0233 {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0},
0234 {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0},
0235 {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
0236 {"Gateway", "LT31", "v1.3307", 0x55, 0x58, {0x9e, 0x00}, 0},
0237
0238 {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0},
0239 {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0},
0240 {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00}, 0},
0241 {"Packard Bell", "AOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0},
0242 {"Packard Bell", "ENBFT", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0},
0243 {"Packard Bell", "ENBFT", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0},
0244 {"Packard Bell", "DOTMU", "v1.3303", 0x55, 0x58, {0x9e, 0x00}, 0},
0245 {"Packard Bell", "DOTMU", "v0.3120", 0x55, 0x58, {0x9e, 0x00}, 0},
0246 {"Packard Bell", "DOTMU", "v0.3108", 0x55, 0x58, {0x9e, 0x00}, 0},
0247 {"Packard Bell", "DOTMU", "v0.3113", 0x55, 0x58, {0x9e, 0x00}, 0},
0248 {"Packard Bell", "DOTMU", "v0.3115", 0x55, 0x58, {0x9e, 0x00}, 0},
0249 {"Packard Bell", "DOTMU", "v0.3117", 0x55, 0x58, {0x9e, 0x00}, 0},
0250 {"Packard Bell", "DOTMU", "v0.3119", 0x55, 0x58, {0x9e, 0x00}, 0},
0251 {"Packard Bell", "DOTMU", "v1.3204", 0x55, 0x58, {0x9e, 0x00}, 0},
0252 {"Packard Bell", "DOTMA", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0},
0253 {"Packard Bell", "DOTMA", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0},
0254 {"Packard Bell", "DOTMA", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0},
0255 {"Packard Bell", "DOTVR46", "v1.3308", 0x55, 0x58, {0x9e, 0x00}, 0},
0256
0257 {"", "", "", 0, 0, {0, 0}, 0}
0258 };
0259
0260
0261
0262
0263
0264 static struct thermal_zone_params acerhdf_zone_params = {
0265 .governor_name = "bang_bang",
0266 };
0267
0268 static int acerhdf_get_temp(int *temp)
0269 {
0270 u8 read_temp;
0271
0272 if (ec_read(ctrl_cfg.tempreg, &read_temp))
0273 return -EINVAL;
0274
0275 *temp = read_temp * 1000;
0276
0277 return 0;
0278 }
0279
0280 static int acerhdf_get_fanstate(int *state)
0281 {
0282 u8 fan;
0283
0284 if (ec_read(ctrl_cfg.fanreg, &fan))
0285 return -EINVAL;
0286
0287 if (fan != ctrl_cfg.cmd.cmd_off)
0288 *state = ACERHDF_FAN_AUTO;
0289 else
0290 *state = ACERHDF_FAN_OFF;
0291
0292 return 0;
0293 }
0294
0295 static void acerhdf_change_fanstate(int state)
0296 {
0297 unsigned char cmd;
0298
0299 if (verbose)
0300 pr_notice("fan %s\n", state == ACERHDF_FAN_OFF ? "OFF" : "ON");
0301
0302 if ((state != ACERHDF_FAN_OFF) && (state != ACERHDF_FAN_AUTO)) {
0303 pr_err("invalid fan state %d requested, setting to auto!\n",
0304 state);
0305 state = ACERHDF_FAN_AUTO;
0306 }
0307
0308 cmd = (state == ACERHDF_FAN_OFF) ? ctrl_cfg.cmd.cmd_off
0309 : ctrl_cfg.cmd.cmd_auto;
0310 fanstate = state;
0311
0312 ec_write(ctrl_cfg.fanreg, cmd);
0313
0314 if (ctrl_cfg.mcmd_enable && state == ACERHDF_FAN_OFF) {
0315 if (verbose)
0316 pr_notice("turning off fan manually\n");
0317 ec_write(mcmd.mreg, mcmd.moff);
0318 }
0319 }
0320
0321 static void acerhdf_check_param(struct thermal_zone_device *thermal)
0322 {
0323 if (fanon > ACERHDF_MAX_FANON) {
0324 pr_err("fanon temperature too high, set to %d\n",
0325 ACERHDF_MAX_FANON);
0326 fanon = ACERHDF_MAX_FANON;
0327 }
0328
0329 if (kernelmode && prev_interval != interval) {
0330 if (interval > ACERHDF_MAX_INTERVAL) {
0331 pr_err("interval too high, set to %d\n",
0332 ACERHDF_MAX_INTERVAL);
0333 interval = ACERHDF_MAX_INTERVAL;
0334 }
0335 if (verbose)
0336 pr_notice("interval changed to: %d\n", interval);
0337
0338 if (thermal)
0339 thermal->polling_delay_jiffies =
0340 round_jiffies(msecs_to_jiffies(interval * 1000));
0341
0342 prev_interval = interval;
0343 }
0344 }
0345
0346
0347
0348
0349
0350
0351
0352 static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t)
0353 {
0354 int temp, err = 0;
0355
0356 err = acerhdf_get_temp(&temp);
0357 if (err)
0358 return err;
0359
0360 if (verbose)
0361 pr_notice("temp %d\n", temp);
0362
0363 *t = temp;
0364 return 0;
0365 }
0366
0367 static int acerhdf_bind(struct thermal_zone_device *thermal,
0368 struct thermal_cooling_device *cdev)
0369 {
0370
0371 if (cdev != cl_dev)
0372 return 0;
0373
0374 if (thermal_zone_bind_cooling_device(thermal, 0, cdev,
0375 THERMAL_NO_LIMIT, THERMAL_NO_LIMIT,
0376 THERMAL_WEIGHT_DEFAULT)) {
0377 pr_err("error binding cooling dev\n");
0378 return -EINVAL;
0379 }
0380 return 0;
0381 }
0382
0383 static int acerhdf_unbind(struct thermal_zone_device *thermal,
0384 struct thermal_cooling_device *cdev)
0385 {
0386 if (cdev != cl_dev)
0387 return 0;
0388
0389 if (thermal_zone_unbind_cooling_device(thermal, 0, cdev)) {
0390 pr_err("error unbinding cooling dev\n");
0391 return -EINVAL;
0392 }
0393 return 0;
0394 }
0395
0396 static inline void acerhdf_revert_to_bios_mode(void)
0397 {
0398 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
0399 kernelmode = 0;
0400
0401 pr_notice("kernel mode fan control OFF\n");
0402 }
0403 static inline void acerhdf_enable_kernelmode(void)
0404 {
0405 kernelmode = 1;
0406
0407 pr_notice("kernel mode fan control ON\n");
0408 }
0409
0410
0411
0412
0413
0414
0415
0416 static int acerhdf_change_mode(struct thermal_zone_device *thermal,
0417 enum thermal_device_mode mode)
0418 {
0419 if (mode == THERMAL_DEVICE_DISABLED && kernelmode)
0420 acerhdf_revert_to_bios_mode();
0421 else if (mode == THERMAL_DEVICE_ENABLED && !kernelmode)
0422 acerhdf_enable_kernelmode();
0423
0424 return 0;
0425 }
0426
0427 static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
0428 enum thermal_trip_type *type)
0429 {
0430 if (trip == 0)
0431 *type = THERMAL_TRIP_ACTIVE;
0432 else if (trip == 1)
0433 *type = THERMAL_TRIP_CRITICAL;
0434 else
0435 return -EINVAL;
0436
0437 return 0;
0438 }
0439
0440 static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
0441 int *temp)
0442 {
0443 if (trip != 0)
0444 return -EINVAL;
0445
0446 *temp = fanon - fanoff;
0447
0448 return 0;
0449 }
0450
0451 static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
0452 int *temp)
0453 {
0454 if (trip == 0)
0455 *temp = fanon;
0456 else if (trip == 1)
0457 *temp = ACERHDF_TEMP_CRIT;
0458 else
0459 return -EINVAL;
0460
0461 return 0;
0462 }
0463
0464 static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
0465 int *temperature)
0466 {
0467 *temperature = ACERHDF_TEMP_CRIT;
0468 return 0;
0469 }
0470
0471
0472 static struct thermal_zone_device_ops acerhdf_dev_ops = {
0473 .bind = acerhdf_bind,
0474 .unbind = acerhdf_unbind,
0475 .get_temp = acerhdf_get_ec_temp,
0476 .change_mode = acerhdf_change_mode,
0477 .get_trip_type = acerhdf_get_trip_type,
0478 .get_trip_hyst = acerhdf_get_trip_hyst,
0479 .get_trip_temp = acerhdf_get_trip_temp,
0480 .get_crit_temp = acerhdf_get_crit_temp,
0481 };
0482
0483
0484
0485
0486
0487
0488 static int acerhdf_get_max_state(struct thermal_cooling_device *cdev,
0489 unsigned long *state)
0490 {
0491 *state = 1;
0492
0493 return 0;
0494 }
0495
0496 static int acerhdf_get_cur_state(struct thermal_cooling_device *cdev,
0497 unsigned long *state)
0498 {
0499 int err = 0, tmp;
0500
0501 err = acerhdf_get_fanstate(&tmp);
0502 if (err)
0503 return err;
0504
0505 *state = (tmp == ACERHDF_FAN_AUTO) ? 1 : 0;
0506 return 0;
0507 }
0508
0509
0510 static int acerhdf_set_cur_state(struct thermal_cooling_device *cdev,
0511 unsigned long state)
0512 {
0513 int cur_temp, cur_state, err = 0;
0514
0515 if (!kernelmode)
0516 return 0;
0517
0518 err = acerhdf_get_temp(&cur_temp);
0519 if (err) {
0520 pr_err("error reading temperature, hand off control to BIOS\n");
0521 goto err_out;
0522 }
0523
0524 err = acerhdf_get_fanstate(&cur_state);
0525 if (err) {
0526 pr_err("error reading fan state, hand off control to BIOS\n");
0527 goto err_out;
0528 }
0529
0530 if (state == 0) {
0531 if (cur_state == ACERHDF_FAN_AUTO)
0532 acerhdf_change_fanstate(ACERHDF_FAN_OFF);
0533 } else {
0534 if (cur_state == ACERHDF_FAN_OFF)
0535 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
0536 }
0537 return 0;
0538
0539 err_out:
0540 acerhdf_revert_to_bios_mode();
0541 return -EINVAL;
0542 }
0543
0544
0545 static const struct thermal_cooling_device_ops acerhdf_cooling_ops = {
0546 .get_max_state = acerhdf_get_max_state,
0547 .get_cur_state = acerhdf_get_cur_state,
0548 .set_cur_state = acerhdf_set_cur_state,
0549 };
0550
0551
0552 static int acerhdf_suspend(struct device *dev)
0553 {
0554 if (kernelmode)
0555 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
0556
0557 if (verbose)
0558 pr_notice("going suspend\n");
0559
0560 return 0;
0561 }
0562
0563 static int acerhdf_probe(struct platform_device *device)
0564 {
0565 return 0;
0566 }
0567
0568 static int acerhdf_remove(struct platform_device *device)
0569 {
0570 return 0;
0571 }
0572
0573 static const struct dev_pm_ops acerhdf_pm_ops = {
0574 .suspend = acerhdf_suspend,
0575 .freeze = acerhdf_suspend,
0576 };
0577
0578 static struct platform_driver acerhdf_driver = {
0579 .driver = {
0580 .name = "acerhdf",
0581 .pm = &acerhdf_pm_ops,
0582 },
0583 .probe = acerhdf_probe,
0584 .remove = acerhdf_remove,
0585 };
0586
0587
0588 static int __init acerhdf_check_hardware(void)
0589 {
0590 char const *vendor, *version, *product;
0591 const struct bios_settings *bt = NULL;
0592 int found = 0;
0593
0594
0595 vendor = dmi_get_system_info(DMI_SYS_VENDOR);
0596 version = dmi_get_system_info(DMI_BIOS_VERSION);
0597 product = dmi_get_system_info(DMI_PRODUCT_NAME);
0598
0599 if (!vendor || !version || !product) {
0600 pr_err("error getting hardware information\n");
0601 return -EINVAL;
0602 }
0603
0604 pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER);
0605
0606 if (list_supported) {
0607 pr_info("List of supported Manufacturer/Model/BIOS:\n");
0608 pr_info("---------------------------------------------------\n");
0609 for (bt = bios_tbl; bt->vendor[0]; bt++) {
0610 pr_info("%-13s | %-17s | %-10s\n", bt->vendor,
0611 bt->product, bt->version);
0612 }
0613 pr_info("---------------------------------------------------\n");
0614 return -ECANCELED;
0615 }
0616
0617 if (force_bios[0]) {
0618 version = force_bios;
0619 pr_info("forcing BIOS version: %s\n", version);
0620 kernelmode = 0;
0621 }
0622
0623 if (force_product[0]) {
0624 product = force_product;
0625 pr_info("forcing BIOS product: %s\n", product);
0626 kernelmode = 0;
0627 }
0628
0629 if (verbose)
0630 pr_info("BIOS info: %s %s, product: %s\n",
0631 vendor, version, product);
0632
0633
0634 for (bt = bios_tbl; bt->vendor[0]; bt++) {
0635
0636
0637
0638
0639 if (strstarts(vendor, bt->vendor) &&
0640 strstarts(product, bt->product) &&
0641 strstarts(version, bt->version)) {
0642 found = 1;
0643 break;
0644 }
0645 }
0646
0647 if (!found) {
0648 pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n",
0649 vendor, product, version);
0650 return -EINVAL;
0651 }
0652
0653
0654 ctrl_cfg.fanreg = bt->fanreg;
0655 ctrl_cfg.tempreg = bt->tempreg;
0656 memcpy(&ctrl_cfg.cmd, &bt->cmd, sizeof(struct fancmd));
0657 ctrl_cfg.mcmd_enable = bt->mcmd_enable;
0658
0659
0660
0661
0662
0663 if (!kernelmode) {
0664 pr_notice("Fan control off, to enable do:\n");
0665 pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zoneN/mode # N=0,1,2...\n");
0666 }
0667
0668 return 0;
0669 }
0670
0671 static int __init acerhdf_register_platform(void)
0672 {
0673 int err = 0;
0674
0675 err = platform_driver_register(&acerhdf_driver);
0676 if (err)
0677 return err;
0678
0679 acerhdf_dev = platform_device_alloc("acerhdf", -1);
0680 if (!acerhdf_dev) {
0681 err = -ENOMEM;
0682 goto err_device_alloc;
0683 }
0684 err = platform_device_add(acerhdf_dev);
0685 if (err)
0686 goto err_device_add;
0687
0688 return 0;
0689
0690 err_device_add:
0691 platform_device_put(acerhdf_dev);
0692 err_device_alloc:
0693 platform_driver_unregister(&acerhdf_driver);
0694 return err;
0695 }
0696
0697 static void acerhdf_unregister_platform(void)
0698 {
0699 platform_device_unregister(acerhdf_dev);
0700 platform_driver_unregister(&acerhdf_driver);
0701 }
0702
0703 static int __init acerhdf_register_thermal(void)
0704 {
0705 int ret;
0706
0707 cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL,
0708 &acerhdf_cooling_ops);
0709
0710 if (IS_ERR(cl_dev))
0711 return -EINVAL;
0712
0713 thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
0714 &acerhdf_dev_ops,
0715 &acerhdf_zone_params, 0,
0716 (kernelmode) ? interval*1000 : 0);
0717 if (IS_ERR(thz_dev))
0718 return -EINVAL;
0719
0720 if (kernelmode)
0721 ret = thermal_zone_device_enable(thz_dev);
0722 else
0723 ret = thermal_zone_device_disable(thz_dev);
0724 if (ret)
0725 return ret;
0726
0727 if (strcmp(thz_dev->governor->name,
0728 acerhdf_zone_params.governor_name)) {
0729 pr_err("Didn't get thermal governor %s, perhaps not compiled into thermal subsystem.\n",
0730 acerhdf_zone_params.governor_name);
0731 return -EINVAL;
0732 }
0733
0734 return 0;
0735 }
0736
0737 static void acerhdf_unregister_thermal(void)
0738 {
0739 if (cl_dev) {
0740 thermal_cooling_device_unregister(cl_dev);
0741 cl_dev = NULL;
0742 }
0743
0744 if (thz_dev) {
0745 thermal_zone_device_unregister(thz_dev);
0746 thz_dev = NULL;
0747 }
0748 }
0749
0750 static int __init acerhdf_init(void)
0751 {
0752 int err = 0;
0753
0754 err = acerhdf_check_hardware();
0755 if (err)
0756 goto out_err;
0757
0758 err = acerhdf_register_platform();
0759 if (err)
0760 goto out_err;
0761
0762 err = acerhdf_register_thermal();
0763 if (err)
0764 goto err_unreg;
0765
0766 return 0;
0767
0768 err_unreg:
0769 acerhdf_unregister_thermal();
0770 acerhdf_unregister_platform();
0771
0772 out_err:
0773 return err;
0774 }
0775
0776 static void __exit acerhdf_exit(void)
0777 {
0778 acerhdf_change_fanstate(ACERHDF_FAN_AUTO);
0779 acerhdf_unregister_thermal();
0780 acerhdf_unregister_platform();
0781 }
0782
0783 MODULE_LICENSE("GPL");
0784 MODULE_AUTHOR("Peter Kaestle");
0785 MODULE_DESCRIPTION("Aspire One temperature and fan driver");
0786 MODULE_ALIAS("dmi:*:*Acer*:pnAOA*:");
0787 MODULE_ALIAS("dmi:*:*Acer*:pnAO751h*:");
0788 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1410*:");
0789 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1810*:");
0790 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5755G:");
0791 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*1825PTZ:");
0792 MODULE_ALIAS("dmi:*:*Acer*:pnAO521*:");
0793 MODULE_ALIAS("dmi:*:*Acer*:pnAO531*:");
0794 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5739G:");
0795 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*One*753:");
0796 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*5315:");
0797 MODULE_ALIAS("dmi:*:*Acer*:TravelMate*7730G:");
0798 MODULE_ALIAS("dmi:*:*Acer*:pnAspire*7551:");
0799 MODULE_ALIAS("dmi:*:*Acer*:TM8573T:");
0800 MODULE_ALIAS("dmi:*:*Gateway*:pnAOA*:");
0801 MODULE_ALIAS("dmi:*:*Gateway*:pnLT31*:");
0802 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnAOA*:");
0803 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOA*:");
0804 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMU*:");
0805 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnENBFT*:");
0806 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTMA*:");
0807 MODULE_ALIAS("dmi:*:*Packard*Bell*:pnDOTVR46*:");
0808 MODULE_ALIAS("dmi:*:*Acer*:pnExtensa*5420*:");
0809
0810 module_init(acerhdf_init);
0811 module_exit(acerhdf_exit);
0812
0813 static int interval_set_uint(const char *val, const struct kernel_param *kp)
0814 {
0815 int ret;
0816
0817 ret = param_set_uint(val, kp);
0818 if (ret)
0819 return ret;
0820
0821 acerhdf_check_param(thz_dev);
0822
0823 return 0;
0824 }
0825
0826 static const struct kernel_param_ops interval_ops = {
0827 .set = interval_set_uint,
0828 .get = param_get_uint,
0829 };
0830
0831 module_param_cb(interval, &interval_ops, &interval, 0600);
0832 MODULE_PARM_DESC(interval, "Polling interval of temperature check");