Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * acerhdf - A driver which monitors the temperature
0004  *           of the aspire one netbook, turns on/off the fan
0005  *           as soon as the upper/lower threshold is reached.
0006  *
0007  * (C) 2009 - Peter Kaestle     peter (a) piie.net
0008  *                              https://piie.net
0009  *     2009 Borislav Petkov bp (a) alien8.de
0010  *
0011  * Inspired by and many thanks to:
0012  *  o acerfand   - Rachel Greenham
0013  *  o acer_ec.pl - Michael Kurz     michi.kurz (at) googlemail.com
0014  *               - Petr Tomasek     tomasek (#) etf,cuni,cz
0015  *               - Carlos Corbacho  cathectic (at) gmail.com
0016  *  o lkml       - Matthew Garrett
0017  *               - Borislav Petkov
0018  *               - Andreas Mohr
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  * The driver is started with "kernel mode off" by default. That means, the BIOS
0032  * is still in control of the fan. In this mode the driver allows to read the
0033  * temperature of the cpu and a userspace tool may take over control of the fan.
0034  * If the driver is switched to "kernel mode" (e.g. via module parameter) the
0035  * driver is in full control of the fan. If you want the module to be started in
0036  * kernel mode by default, define the following:
0037  */
0038 #undef START_IN_KERNEL_MODE
0039 
0040 #define DRV_VER "0.7.0"
0041 
0042 /*
0043  * According to the Atom N270 datasheet,
0044  * (http://download.intel.com/design/processor/datashts/320032.pdf) the
0045  * CPU's optimal operating limits denoted in junction temperature as
0046  * measured by the on-die thermal monitor are within 0 <= Tj <= 90. So,
0047  * assume 89°C is critical temperature.
0048  */
0049 #define ACERHDF_TEMP_CRIT 89000
0050 #define ACERHDF_FAN_OFF 0
0051 #define ACERHDF_FAN_AUTO 1
0052 
0053 /*
0054  * No matter what value the user puts into the fanon variable, turn on the fan
0055  * at 80 degree Celsius to prevent hardware damage
0056  */
0057 #define ACERHDF_MAX_FANON 80000
0058 
0059 /*
0060  * Maximum interval between two temperature checks is 15 seconds, as the die
0061  * can get hot really fast under heavy load (plus we shouldn't forget about
0062  * possible impact of _external_ aggressive sources such as heaters, sun etc.)
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  * cmd_off: to switch the fan completely off and check if the fan is off
0102  *  cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then
0103  *      the fan speed depending on the temperature
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 /* default register and command to disable fan in manual mode */
0116 static const struct manualcmd mcmd = {
0117     .mreg = 0x94,
0118     .moff = 0xff,
0119 };
0120 
0121 /* BIOS settings - only used during probe */
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 /* This could be a daughter struct in the above, but not worth the redirect */
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 /* Register addresses and values for different BIOS versions */
0143 static const struct bios_settings bios_tbl[] __initconst = {
0144     /* AOA110 */
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     /* AOA150 */
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     /* LT1005u */
0164     {"Acer", "LT-10Q", "v0.3310", 0x55, 0x58, {0x20, 0x00}, 0},
0165     /* Acer 1410 */
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     /* Acer 1810xx */
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     /* Acer 5755G */
0201     {"Acer", "Aspire 5755G",  "V1.20",   0xab, 0xb4, {0x00, 0x08}, 0},
0202     {"Acer", "Aspire 5755G",  "V1.21",   0xab, 0xb3, {0x00, 0x08}, 0},
0203     /* Acer 521 */
0204     {"Acer", "AO521", "V1.11", 0x55, 0x58, {0x1f, 0x00}, 0},
0205     /* Acer 531 */
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     /* Acer 751 */
0210     {"Acer", "AO751h", "V0.3206", 0x55, 0x58, {0x21, 0x00}, 0},
0211     {"Acer", "AO751h", "V0.3212", 0x55, 0x58, {0x21, 0x00}, 0},
0212     /* Acer 753 */
0213     {"Acer", "Aspire One 753", "V1.24", 0x93, 0xac, {0x14, 0x04}, 1},
0214     /* Acer 1825 */
0215     {"Acer", "Aspire 1825PTZ", "V1.3118", 0x55, 0x58, {0x9e, 0x00}, 0},
0216     {"Acer", "Aspire 1825PTZ", "V1.3127", 0x55, 0x58, {0x9e, 0x00}, 0},
0217     /* Acer Extensa 5420 */
0218     {"Acer", "Extensa 5420", "V1.17", 0x93, 0xac, {0x14, 0x04}, 1},
0219     /* Acer Aspire 5315 */
0220     {"Acer", "Aspire 5315", "V1.19", 0x93, 0xac, {0x14, 0x04}, 1},
0221     /* Acer Aspire 5739 */
0222     {"Acer", "Aspire 5739G", "V1.3311", 0x55, 0x58, {0x20, 0x00}, 0},
0223     /* Acer TravelMate 7730 */
0224     {"Acer", "TravelMate 7730G", "v0.3509", 0x55, 0x58, {0xaf, 0x00}, 0},
0225     /* Acer Aspire 7551 */
0226     {"Acer", "Aspire 7551", "V1.18", 0x93, 0xa8, {0x14, 0x04}, 1},
0227     /* Acer TravelMate TM8573T */
0228     {"Acer", "TM8573T", "V1.13", 0x93, 0xa8, {0x14, 0x04}, 1},
0229     /* Gateway */
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     /* Packard Bell */
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     /* pewpew-terminator */
0257     {"", "", "", 0, 0, {0, 0}, 0}
0258 };
0259 
0260 /*
0261  * this struct is used to instruct thermal layer to use bang_bang instead of
0262  * default governor for acerhdf
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  * This is the thermal zone callback which does the delayed polling of the fan
0348  * state. We do check /sysfs-originating settings here in acerhdf_check_param()
0349  * as late as the polling interval is since we can't do that in the respective
0350  * accessors of the module parameters.
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     /* if the cooling device is the one from acerhdf bind it */
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  * set operation mode;
0412  * enabled: the thermal layer of the kernel takes care about
0413  *          the temperature and the fan.
0414  * disabled: the BIOS takes control of the fan.
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 /* bind callback functions to thermalzone */
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  * cooling device callback functions
0486  * get maximal fan cooling state
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 /* change current fan state - is overwritten when running in kernel mode */
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 /* bind fan callbacks to fan device */
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 /* suspend / resume functionality */
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 /* check hardware */
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     /* get BIOS data */
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     /* search BIOS version and vendor in BIOS settings table */
0634     for (bt = bios_tbl; bt->vendor[0]; bt++) {
0635         /*
0636          * check if actual hardware BIOS vendor, product and version
0637          * IDs start with the strings of BIOS table entry
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     /* Copy control settings from BIOS table before we free it. */
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      * if started with kernel mode off, prevent the kernel from switching
0661      * off the fan
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");