diff options
Diffstat (limited to 'drivers/platform/x86/acerhdf.c')
-rw-r--r-- | drivers/platform/x86/acerhdf.c | 68 |
1 files changed, 49 insertions, 19 deletions
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c index ea22591ee66f..505224225378 100644 --- a/drivers/platform/x86/acerhdf.c +++ b/drivers/platform/x86/acerhdf.c | |||
@@ -86,6 +86,7 @@ static unsigned int interval = 10; | |||
86 | static unsigned int fanon = 60000; | 86 | static unsigned int fanon = 60000; |
87 | static unsigned int fanoff = 53000; | 87 | static unsigned int fanoff = 53000; |
88 | static unsigned int verbose; | 88 | static unsigned int verbose; |
89 | static unsigned int list_supported; | ||
89 | static unsigned int fanstate = ACERHDF_FAN_AUTO; | 90 | static unsigned int fanstate = ACERHDF_FAN_AUTO; |
90 | static char force_bios[16]; | 91 | static char force_bios[16]; |
91 | static char force_product[16]; | 92 | static char force_product[16]; |
@@ -104,10 +105,12 @@ module_param(fanoff, uint, 0600); | |||
104 | MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature"); | 105 | MODULE_PARM_DESC(fanoff, "Turn the fan off below this temperature"); |
105 | module_param(verbose, uint, 0600); | 106 | module_param(verbose, uint, 0600); |
106 | MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); | 107 | MODULE_PARM_DESC(verbose, "Enable verbose dmesg output"); |
108 | module_param(list_supported, uint, 0600); | ||
109 | MODULE_PARM_DESC(list_supported, "List supported models and BIOS versions"); | ||
107 | module_param_string(force_bios, force_bios, 16, 0); | 110 | module_param_string(force_bios, force_bios, 16, 0); |
108 | MODULE_PARM_DESC(force_bios, "Force BIOS version and omit BIOS check"); | 111 | MODULE_PARM_DESC(force_bios, "Pretend system has this known supported BIOS version"); |
109 | module_param_string(force_product, force_product, 16, 0); | 112 | module_param_string(force_product, force_product, 16, 0); |
110 | MODULE_PARM_DESC(force_product, "Force BIOS product and omit BIOS check"); | 113 | MODULE_PARM_DESC(force_product, "Pretend system is this known supported model"); |
111 | 114 | ||
112 | /* | 115 | /* |
113 | * cmd_off: to switch the fan completely off and check if the fan is off | 116 | * cmd_off: to switch the fan completely off and check if the fan is off |
@@ -130,7 +133,7 @@ static const struct manualcmd mcmd = { | |||
130 | .moff = 0xff, | 133 | .moff = 0xff, |
131 | }; | 134 | }; |
132 | 135 | ||
133 | /* BIOS settings */ | 136 | /* BIOS settings - only used during probe */ |
134 | struct bios_settings { | 137 | struct bios_settings { |
135 | const char *vendor; | 138 | const char *vendor; |
136 | const char *product; | 139 | const char *product; |
@@ -141,8 +144,18 @@ struct bios_settings { | |||
141 | int mcmd_enable; | 144 | int mcmd_enable; |
142 | }; | 145 | }; |
143 | 146 | ||
147 | /* This could be a daughter struct in the above, but not worth the redirect */ | ||
148 | struct ctrl_settings { | ||
149 | u8 fanreg; | ||
150 | u8 tempreg; | ||
151 | struct fancmd cmd; | ||
152 | int mcmd_enable; | ||
153 | }; | ||
154 | |||
155 | static struct ctrl_settings ctrl_cfg __read_mostly; | ||
156 | |||
144 | /* Register addresses and values for different BIOS versions */ | 157 | /* Register addresses and values for different BIOS versions */ |
145 | static const struct bios_settings bios_tbl[] = { | 158 | static const struct bios_settings bios_tbl[] __initconst = { |
146 | /* AOA110 */ | 159 | /* AOA110 */ |
147 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0}, | 160 | {"Acer", "AOA110", "v0.3109", 0x55, 0x58, {0x1f, 0x00}, 0}, |
148 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, | 161 | {"Acer", "AOA110", "v0.3114", 0x55, 0x58, {0x1f, 0x00}, 0}, |
@@ -233,6 +246,7 @@ static const struct bios_settings bios_tbl[] = { | |||
233 | {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, | 246 | {"Gateway", "LT31", "v1.3201", 0x55, 0x58, {0x9e, 0x00}, 0}, |
234 | {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, | 247 | {"Gateway", "LT31", "v1.3302", 0x55, 0x58, {0x9e, 0x00}, 0}, |
235 | {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, | 248 | {"Gateway", "LT31", "v1.3303t", 0x55, 0x58, {0x9e, 0x00}, 0}, |
249 | {"Gateway", "LT31", "v1.3307", 0x55, 0x58, {0x9e, 0x00}, 0}, | ||
236 | /* Packard Bell */ | 250 | /* Packard Bell */ |
237 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0}, | 251 | {"Packard Bell", "DOA150", "v0.3104", 0x55, 0x58, {0x21, 0x00}, 0}, |
238 | {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, | 252 | {"Packard Bell", "DOA150", "v0.3105", 0x55, 0x58, {0x20, 0x00}, 0}, |
@@ -256,8 +270,6 @@ static const struct bios_settings bios_tbl[] = { | |||
256 | {"", "", "", 0, 0, {0, 0}, 0} | 270 | {"", "", "", 0, 0, {0, 0}, 0} |
257 | }; | 271 | }; |
258 | 272 | ||
259 | static const struct bios_settings *bios_cfg __read_mostly; | ||
260 | |||
261 | /* | 273 | /* |
262 | * this struct is used to instruct thermal layer to use bang_bang instead of | 274 | * this struct is used to instruct thermal layer to use bang_bang instead of |
263 | * default governor for acerhdf | 275 | * default governor for acerhdf |
@@ -270,7 +282,7 @@ static int acerhdf_get_temp(int *temp) | |||
270 | { | 282 | { |
271 | u8 read_temp; | 283 | u8 read_temp; |
272 | 284 | ||
273 | if (ec_read(bios_cfg->tempreg, &read_temp)) | 285 | if (ec_read(ctrl_cfg.tempreg, &read_temp)) |
274 | return -EINVAL; | 286 | return -EINVAL; |
275 | 287 | ||
276 | *temp = read_temp * 1000; | 288 | *temp = read_temp * 1000; |
@@ -282,10 +294,10 @@ static int acerhdf_get_fanstate(int *state) | |||
282 | { | 294 | { |
283 | u8 fan; | 295 | u8 fan; |
284 | 296 | ||
285 | if (ec_read(bios_cfg->fanreg, &fan)) | 297 | if (ec_read(ctrl_cfg.fanreg, &fan)) |
286 | return -EINVAL; | 298 | return -EINVAL; |
287 | 299 | ||
288 | if (fan != bios_cfg->cmd.cmd_off) | 300 | if (fan != ctrl_cfg.cmd.cmd_off) |
289 | *state = ACERHDF_FAN_AUTO; | 301 | *state = ACERHDF_FAN_AUTO; |
290 | else | 302 | else |
291 | *state = ACERHDF_FAN_OFF; | 303 | *state = ACERHDF_FAN_OFF; |
@@ -306,13 +318,13 @@ static void acerhdf_change_fanstate(int state) | |||
306 | state = ACERHDF_FAN_AUTO; | 318 | state = ACERHDF_FAN_AUTO; |
307 | } | 319 | } |
308 | 320 | ||
309 | cmd = (state == ACERHDF_FAN_OFF) ? bios_cfg->cmd.cmd_off | 321 | cmd = (state == ACERHDF_FAN_OFF) ? ctrl_cfg.cmd.cmd_off |
310 | : bios_cfg->cmd.cmd_auto; | 322 | : ctrl_cfg.cmd.cmd_auto; |
311 | fanstate = state; | 323 | fanstate = state; |
312 | 324 | ||
313 | ec_write(bios_cfg->fanreg, cmd); | 325 | ec_write(ctrl_cfg.fanreg, cmd); |
314 | 326 | ||
315 | if (bios_cfg->mcmd_enable && state == ACERHDF_FAN_OFF) { | 327 | if (ctrl_cfg.mcmd_enable && state == ACERHDF_FAN_OFF) { |
316 | if (verbose) | 328 | if (verbose) |
317 | pr_notice("turning off fan manually\n"); | 329 | pr_notice("turning off fan manually\n"); |
318 | ec_write(mcmd.mreg, mcmd.moff); | 330 | ec_write(mcmd.mreg, mcmd.moff); |
@@ -615,10 +627,11 @@ static int str_starts_with(const char *str, const char *start) | |||
615 | } | 627 | } |
616 | 628 | ||
617 | /* check hardware */ | 629 | /* check hardware */ |
618 | static int acerhdf_check_hardware(void) | 630 | static int __init acerhdf_check_hardware(void) |
619 | { | 631 | { |
620 | char const *vendor, *version, *product; | 632 | char const *vendor, *version, *product; |
621 | const struct bios_settings *bt = NULL; | 633 | const struct bios_settings *bt = NULL; |
634 | int found = 0; | ||
622 | 635 | ||
623 | /* get BIOS data */ | 636 | /* get BIOS data */ |
624 | vendor = dmi_get_system_info(DMI_SYS_VENDOR); | 637 | vendor = dmi_get_system_info(DMI_SYS_VENDOR); |
@@ -632,6 +645,17 @@ static int acerhdf_check_hardware(void) | |||
632 | 645 | ||
633 | pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); | 646 | pr_info("Acer Aspire One Fan driver, v.%s\n", DRV_VER); |
634 | 647 | ||
648 | if (list_supported) { | ||
649 | pr_info("List of supported Manufacturer/Model/BIOS:\n"); | ||
650 | pr_info("---------------------------------------------------\n"); | ||
651 | for (bt = bios_tbl; bt->vendor[0]; bt++) { | ||
652 | pr_info("%-13s | %-17s | %-10s\n", bt->vendor, | ||
653 | bt->product, bt->version); | ||
654 | } | ||
655 | pr_info("---------------------------------------------------\n"); | ||
656 | return -ECANCELED; | ||
657 | } | ||
658 | |||
635 | if (force_bios[0]) { | 659 | if (force_bios[0]) { |
636 | version = force_bios; | 660 | version = force_bios; |
637 | pr_info("forcing BIOS version: %s\n", version); | 661 | pr_info("forcing BIOS version: %s\n", version); |
@@ -657,30 +681,36 @@ static int acerhdf_check_hardware(void) | |||
657 | if (str_starts_with(vendor, bt->vendor) && | 681 | if (str_starts_with(vendor, bt->vendor) && |
658 | str_starts_with(product, bt->product) && | 682 | str_starts_with(product, bt->product) && |
659 | str_starts_with(version, bt->version)) { | 683 | str_starts_with(version, bt->version)) { |
660 | bios_cfg = bt; | 684 | found = 1; |
661 | break; | 685 | break; |
662 | } | 686 | } |
663 | } | 687 | } |
664 | 688 | ||
665 | if (!bios_cfg) { | 689 | if (!found) { |
666 | pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n", | 690 | pr_err("unknown (unsupported) BIOS version %s/%s/%s, please report, aborting!\n", |
667 | vendor, product, version); | 691 | vendor, product, version); |
668 | return -EINVAL; | 692 | return -EINVAL; |
669 | } | 693 | } |
670 | 694 | ||
695 | /* Copy control settings from BIOS table before we free it. */ | ||
696 | ctrl_cfg.fanreg = bt->fanreg; | ||
697 | ctrl_cfg.tempreg = bt->tempreg; | ||
698 | memcpy(&ctrl_cfg.cmd, &bt->cmd, sizeof(struct fancmd)); | ||
699 | ctrl_cfg.mcmd_enable = bt->mcmd_enable; | ||
700 | |||
671 | /* | 701 | /* |
672 | * if started with kernel mode off, prevent the kernel from switching | 702 | * if started with kernel mode off, prevent the kernel from switching |
673 | * off the fan | 703 | * off the fan |
674 | */ | 704 | */ |
675 | if (!kernelmode) { | 705 | if (!kernelmode) { |
676 | pr_notice("Fan control off, to enable do:\n"); | 706 | pr_notice("Fan control off, to enable do:\n"); |
677 | pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zone0/mode\n"); | 707 | pr_notice("echo -n \"enabled\" > /sys/class/thermal/thermal_zoneN/mode # N=0,1,2...\n"); |
678 | } | 708 | } |
679 | 709 | ||
680 | return 0; | 710 | return 0; |
681 | } | 711 | } |
682 | 712 | ||
683 | static int acerhdf_register_platform(void) | 713 | static int __init acerhdf_register_platform(void) |
684 | { | 714 | { |
685 | int err = 0; | 715 | int err = 0; |
686 | 716 | ||
@@ -712,7 +742,7 @@ static void acerhdf_unregister_platform(void) | |||
712 | platform_driver_unregister(&acerhdf_driver); | 742 | platform_driver_unregister(&acerhdf_driver); |
713 | } | 743 | } |
714 | 744 | ||
715 | static int acerhdf_register_thermal(void) | 745 | static int __init acerhdf_register_thermal(void) |
716 | { | 746 | { |
717 | cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, | 747 | cl_dev = thermal_cooling_device_register("acerhdf-fan", NULL, |
718 | &acerhdf_cooling_ops); | 748 | &acerhdf_cooling_ops); |