diff options
author | Peter Feuerer <peter@piie.net> | 2009-08-06 18:57:52 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-09-19 01:49:25 -0400 |
commit | ded0cdfc6a7673916b0878c32fa8ba566b4f8cdb (patch) | |
tree | f9c8703d05fa95c56147fe11ec81207990c9d5b0 /drivers/platform/x86/acerhdf.c | |
parent | 1e23502cc57cef33455ac7cb9111e3c6d991a894 (diff) |
acerhdf: fix fan control for AOA150 model
- Apply Borislav Petkov's patch (convert the fancmd[] array to a real
struct thus disambiguating command handling and making code more
readable.)
- Add BIOS product to BIOS table as AOA110 and AOA150 have different
register values
- Add force_product parameter to allow forcing different product
- fix linker warning caused by "acerhdf_drv" not being named
"acerhdf_driver"
Signed-off-by: Peter Feuerer <peter@piie.net>
Cc: Andreas Mohr <andi@lisas.de>
Acked-by: Borislav Petkov <petkovbb@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/platform/x86/acerhdf.c')
-rw-r--r-- | drivers/platform/x86/acerhdf.c | 97 |
1 files changed, 66 insertions, 31 deletions
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index bdfee177eefb..aa298d6ea371 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c | |||
@@ -52,7 +52,7 @@ | |||
52 | */ | 52 | */ |
53 | #undef START_IN_KERNEL_MODE | 53 | #undef START_IN_KERNEL_MODE |
54 | 54 | ||
55 | #define DRV_VER "0.5.13" | 55 | #define DRV_VER "0.5.16" |
56 | 56 | ||
57 | /* | 57 | /* |
58 | * According to the Atom N270 datasheet, | 58 | * According to the Atom N270 datasheet, |
@@ -90,6 +90,7 @@ static unsigned int fanoff = 58; | |||
90 | static unsigned int verbose; | 90 | static unsigned int verbose; |
91 | static unsigned int fanstate = ACERHDF_FAN_AUTO; | 91 | static unsigned int fanstate = ACERHDF_FAN_AUTO; |
92 | static char force_bios[16]; | 92 | static char force_bios[16]; |
93 | static char force_product[16]; | ||
93 | static unsigned int prev_interval; | 94 | static unsigned int prev_interval; |
94 | struct thermal_zone_device *thz_dev; | 95 | struct thermal_zone_device *thz_dev; |
95 | struct thermal_cooling_device *cl_dev; | 96 | struct thermal_cooling_device *cl_dev; |
@@ -107,34 +108,58 @@ module_param(verbose, uint, 0600); | |||
107 | MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); | 108 | MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); |
108 | module_param_string(force_bios, force_bios, 16, 0); | 109 | module_param_string(force_bios, force_bios, 16, 0); |
109 | MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); | 110 | MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); |
111 | module_param_string(force_product, force_product, 16, 0); | ||
112 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); | ||
113 | |||
114 | /* | ||
115 | * cmd_off: to switch the fan completely off / to check if the fan is off | ||
116 | * cmd_auto: to set the BIOS in control of the fan. The BIOS regulates then | ||
117 | * the fan speed depending on the temperature | ||
118 | */ | ||
119 | struct fancmd { | ||
120 | u8 cmd_off; | ||
121 | u8 cmd_auto; | ||
122 | }; | ||
110 | 123 | ||
111 | /* BIOS settings */ | 124 | /* BIOS settings */ |
112 | struct bios_settings_t { | 125 | struct bios_settings_t { |
113 | const char *vendor; | 126 | const char *vendor; |
127 | const char *product; | ||
114 | const char *version; | 128 | const char *version; |
115 | unsigned char fanreg; | 129 | unsigned char fanreg; |
116 | unsigned char tempreg; | 130 | unsigned char tempreg; |
117 | unsigned char fancmd[2]; /* fan off and auto commands */ | 131 | struct fancmd cmd; |
118 | }; | 132 | }; |
119 | 133 | ||
120 | /* Register addresses and values for different BIOS versions */ | 134 | /* Register addresses and values for different BIOS versions */ |
121 | static const struct bios_settings_t bios_tbl[] = { | 135 | static const struct bios_settings_t bios_tbl[] = { |
122 | {"Acer", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, | 136 | /* AOA110 */ |
123 | {"Acer", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, | 137 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00} }, |
124 | {"Acer", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, | 138 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00} }, |
125 | {"Acer", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, | 139 | {"Acer", "AOA110", "v0.3301", 0x55, 0x58, {0xaf, 0x00} }, |
126 | {"Acer", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, | 140 | {"Acer", "AOA110", "v0.3304", 0x55, 0x58, {0xaf, 0x00} }, |
127 | {"Acer", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, | 141 | {"Acer", "AOA110", "v0.3305", 0x55, 0x58, {0xaf, 0x00} }, |
128 | {"Acer", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, | 142 | {"Acer", "AOA110", "v0.3308", 0x55, 0x58, {0x21, 0x00} }, |
129 | {"Acer", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, | 143 | {"Acer", "AOA110", "v0.3309", 0x55, 0x58, {0x21, 0x00} }, |
130 | {"Gateway", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, | 144 | {"Acer", "AOA110", "v0.3310", 0x55, 0x58, {0x21, 0x00} }, |
131 | {"Packard Bell", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, | 145 | /* AOA150 */ |
132 | {"", "", 0, 0, {0, 0} } | 146 | {"Acer", "AOA150", "v0.3114", 0x55, 0x58, {0x20, 0x00} }, |
147 | {"Acer", "AOA150", "v0.3304", 0x55, 0x58, {0x20, 0x00} }, | ||
148 | {"Acer", "AOA150", "v0.3305", 0x55, 0x58, {0x20, 0x00} }, | ||
149 | {"Acer", "AOA150", "v0.3308", 0x55, 0x58, {0x20, 0x00} }, | ||
150 | {"Acer", "AOA150", "v0.3309", 0x55, 0x58, {0x20, 0x00} }, | ||
151 | {"Acer", "AOA150", "v0.3310", 0x55, 0x58, {0x20, 0x00} }, | ||
152 | /* special BIOS / other */ | ||
153 | {"Gateway", "AOA110", "v0.3103", 0x55, 0x58, {0x21, 0x00} }, | ||
154 | {"Gateway", "AOA150", "v0.3103", 0x55, 0x58, {0x20, 0x00} }, | ||
155 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00} }, | ||
156 | {"Packard Bell", "AOA110", "v0.3105", 0x55, 0x58, {0x21, 0x00} }, | ||
157 | /* pewpew-terminator */ | ||
158 | {"", "", "", 0, 0, {0, 0} } | ||
133 | }; | 159 | }; |
134 | 160 | ||
135 | static const struct bios_settings_t *bios_cfg __read_mostly; | 161 | static const struct bios_settings_t *bios_cfg __read_mostly; |
136 | 162 | ||
137 | |||
138 | static int acerhdf_get_temp(int *temp) | 163 | static int acerhdf_get_temp(int *temp) |
139 | { | 164 | { |
140 | u8 read_temp; | 165 | u8 read_temp; |
@@ -150,13 +175,14 @@ static int acerhdf_get_temp(int *temp) | |||
150 | static int acerhdf_get_fanstate(int *state) | 175 | static int acerhdf_get_fanstate(int *state) |
151 | { | 176 | { |
152 | u8 fan; | 177 | u8 fan; |
153 | bool tmp; | ||
154 | 178 | ||
155 | if (ec_read(bios_cfg->fanreg, &fan)) | 179 | if (ec_read(bios_cfg->fanreg, &fan)) |
156 | return -EINVAL; | 180 | return -EINVAL; |
157 | 181 | ||
158 | tmp = (fan == bios_cfg->fancmd[ACERHDF_FAN_OFF]); | 182 | if (fan != bios_cfg->cmd.cmd_off) |
159 | *state = tmp ? ACERHDF_FAN_OFF : ACERHDF_FAN_AUTO; | 183 | *state = ACERHDF_FAN_AUTO; |
184 | else | ||
185 | *state = ACERHDF_FAN_OFF; | ||
160 | 186 | ||
161 | return 0; | 187 | return 0; |
162 | } | 188 | } |
@@ -175,7 +201,8 @@ static void acerhdf_change_fanstate(int state) | |||
175 | state = ACERHDF_FAN_AUTO; | 201 | state = ACERHDF_FAN_AUTO; |
176 | } | 202 | } |
177 | 203 | ||
178 | cmd = bios_cfg->fancmd[state]; | 204 | cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off |
205 | : bios_cfg->cmd.cmd_auto; | ||
179 | fanstate = state; | 206 | fanstate = state; |
180 | 207 | ||
181 | ec_write(bios_cfg->fanreg, cmd); | 208 | ec_write(bios_cfg->fanreg, cmd); |
@@ -437,7 +464,7 @@ static int acerhdf_remove(struct platform_device *device) | |||
437 | return 0; | 464 | return 0; |
438 | } | 465 | } |
439 | 466 | ||
440 | struct platform_driver acerhdf_drv = { | 467 | static struct platform_driver acerhdf_driver = { |
441 | .driver = { | 468 | .driver = { |
442 | .name = "acerhdf", | 469 | .name = "acerhdf", |
443 | .owner = THIS_MODULE, | 470 | .owner = THIS_MODULE, |
@@ -454,32 +481,40 @@ static int acerhdf_check_hardware(void) | |||
454 | { | 481 | { |
455 | char const *vendor, *version, *product; | 482 | char const *vendor, *version, *product; |
456 | int i; | 483 | int i; |
484 | unsigned long prod_len = 0; | ||
457 | 485 | ||
458 | /* get BIOS data */ | 486 | /* get BIOS data */ |
459 | vendor = dmi_get_system_info(DMI_SYS_VENDOR); | 487 | vendor = dmi_get_system_info(DMI_SYS_VENDOR); |
460 | version = dmi_get_system_info(DMI_BIOS_VERSION); | 488 | version = dmi_get_system_info(DMI_BIOS_VERSION); |
461 | product = dmi_get_system_info(DMI_PRODUCT_NAME); | 489 | product = dmi_get_system_info(DMI_PRODUCT_NAME); |
462 | 490 | ||
491 | |||
463 | pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); | 492 | pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); |
464 | 493 | ||
465 | if (!force_bios[0]) { | 494 | if (force_bios[0]) { |
466 | if (strncmp(product, "AO", 2)) { | ||
467 | pr_err("no Aspire One hardware found\n"); | ||
468 | return -EINVAL; | ||
469 | } | ||
470 | } else { | ||
471 | pr_info("forcing BIOS version: %s\n", version); | ||
472 | version = force_bios; | 495 | version = force_bios; |
496 | pr_info("forcing BIOS version: %s\n", version); | ||
473 | kernelmode = 0; | 497 | kernelmode = 0; |
474 | } | 498 | } |
475 | 499 | ||
500 | if (force_product[0]) { | ||
501 | product = force_product; | ||
502 | pr_info("forcing BIOS product: %s\n", product); | ||
503 | kernelmode = 0; | ||
504 | } | ||
505 | |||
506 | prod_len = strlen(product); | ||
507 | |||
476 | if (verbose) | 508 | if (verbose) |
477 | pr_info("BIOS info: %s %s, product: %s\n", | 509 | pr_info("BIOS info: %s %s, product: %s\n", |
478 | vendor, version, product); | 510 | vendor, version, product); |
479 | 511 | ||
480 | /* search BIOS version and vendor in BIOS settings table */ | 512 | /* search BIOS version and vendor in BIOS settings table */ |
481 | for (i = 0; bios_tbl[i].version[0]; i++) { | 513 | for (i = 0; bios_tbl[i].version[0]; i++) { |
482 | if (!strcmp(bios_tbl[i].vendor, vendor) && | 514 | if (strlen(bios_tbl[i].product) >= prod_len && |
515 | !strncmp(bios_tbl[i].product, product, | ||
516 | strlen(bios_tbl[i].product)) && | ||
517 | !strcmp(bios_tbl[i].vendor, vendor) && | ||
483 | !strcmp(bios_tbl[i].version, version)) { | 518 | !strcmp(bios_tbl[i].version, version)) { |
484 | bios_cfg = &bios_tbl[i]; | 519 | bios_cfg = &bios_tbl[i]; |
485 | break; | 520 | break; |
@@ -487,8 +522,8 @@ static int acerhdf_check_hardware(void) | |||
487 | } | 522 | } |
488 | 523 | ||
489 | if (!bios_cfg) { | 524 | if (!bios_cfg) { |
490 | pr_err("unknown (unsupported) BIOS version %s/%s, " | 525 | pr_err("unknown (unsupported) BIOS version %s/%s/%s, " |
491 | "please report, aborting!\n", vendor, version); | 526 | "please report, aborting!\n", vendor, product, version); |
492 | return -EINVAL; | 527 | return -EINVAL; |
493 | } | 528 | } |
494 | 529 | ||
@@ -509,7 +544,7 @@ static int acerhdf_register_platform(void) | |||
509 | { | 544 | { |
510 | int err = 0; | 545 | int err = 0; |
511 | 546 | ||
512 | err = platform_driver_register(&acerhdf_drv); | 547 | err = platform_driver_register(&acerhdf_driver); |
513 | if (err) | 548 | if (err) |
514 | return err; | 549 | return err; |
515 | 550 | ||
@@ -525,7 +560,7 @@ static void acerhdf_unregister_platform(void) | |||
525 | return; | 560 | return; |
526 | 561 | ||
527 | platform_device_del(acerhdf_dev); | 562 | platform_device_del(acerhdf_dev); |
528 | platform_driver_unregister(&acerhdf_drv); | 563 | platform_driver_unregister(&acerhdf_driver); |
529 | } | 564 | } |
530 | 565 | ||
531 | static int acerhdf_register_thermal(void) | 566 | static int acerhdf_register_thermal(void) |