]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blame - drivers/platform/x86/eeepc-laptop.c
eeepc-laptop: document fan_pwm conversions
[mirror_ubuntu-hirsute-kernel.git] / drivers / platform / x86 / eeepc-laptop.c
CommitLineData
e59f8796 1/*
a7624b63 2 * eeepc-laptop.c - Asus Eee PC extras
e59f8796
EC
3 *
4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
6 * Based on eee.c from eeepc-linux
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19b53289
JP
19#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
20
e59f8796
EC
21#include <linux/kernel.h>
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/types.h>
25#include <linux/platform_device.h>
a5fa429b
CC
26#include <linux/backlight.h>
27#include <linux/fb.h>
e1faa9da
CC
28#include <linux/hwmon.h>
29#include <linux/hwmon-sysfs.h>
5a0e3ad6 30#include <linux/slab.h>
8b48463f 31#include <linux/acpi.h>
e59f8796 32#include <linux/uaccess.h>
a195dcdc 33#include <linux/input.h>
642e0447 34#include <linux/input/sparse-keymap.h>
a195dcdc 35#include <linux/rfkill.h>
5740294c 36#include <linux/pci.h>
2b121bc2 37#include <linux/pci_hotplug.h>
3c0eb510 38#include <linux/leds.h>
da8ba01d 39#include <linux/dmi.h>
e59f8796
EC
40
41#define EEEPC_LAPTOP_VERSION "0.1"
a7624b63
AJ
42#define EEEPC_LAPTOP_NAME "Eee PC Hotkey Driver"
43#define EEEPC_LAPTOP_FILE "eeepc"
e59f8796 44
a7624b63
AJ
45#define EEEPC_ACPI_CLASS "hotkey"
46#define EEEPC_ACPI_DEVICE_NAME "Hotkey"
47#define EEEPC_ACPI_HID "ASUS010"
e59f8796 48
52bbe3c7 49MODULE_AUTHOR("Corentin Chary, Eric Cooper");
a7624b63 50MODULE_DESCRIPTION(EEEPC_LAPTOP_NAME);
52bbe3c7 51MODULE_LICENSE("GPL");
e59f8796 52
322a1356
CC
53static bool hotplug_disabled;
54
bfa47960 55module_param(hotplug_disabled, bool, 0444);
322a1356
CC
56MODULE_PARM_DESC(hotplug_disabled,
57 "Disable hotplug for wireless device. "
58 "If your laptop need that, please report to "
59 "acpi4asus-user@lists.sourceforge.net.");
60
e59f8796
EC
61/*
62 * Definitions for Asus EeePC
63 */
a5fa429b
CC
64#define NOTIFY_BRN_MIN 0x20
65#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
66
67enum {
68 DISABLE_ASL_WLAN = 0x0001,
69 DISABLE_ASL_BLUETOOTH = 0x0002,
70 DISABLE_ASL_IRDA = 0x0004,
71 DISABLE_ASL_CAMERA = 0x0008,
72 DISABLE_ASL_TV = 0x0010,
73 DISABLE_ASL_GPS = 0x0020,
74 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
75 DISABLE_ASL_MODEM = 0x0080,
b7b700d4
CC
76 DISABLE_ASL_CARDREADER = 0x0100,
77 DISABLE_ASL_3G = 0x0200,
78 DISABLE_ASL_WIMAX = 0x0400,
79 DISABLE_ASL_HWCF = 0x0800
e59f8796
EC
80};
81
82enum {
83 CM_ASL_WLAN = 0,
84 CM_ASL_BLUETOOTH,
85 CM_ASL_IRDA,
86 CM_ASL_1394,
87 CM_ASL_CAMERA,
88 CM_ASL_TV,
89 CM_ASL_GPS,
90 CM_ASL_DVDROM,
91 CM_ASL_DISPLAYSWITCH,
92 CM_ASL_PANELBRIGHT,
93 CM_ASL_BIOSFLASH,
94 CM_ASL_ACPIFLASH,
95 CM_ASL_CPUFV,
96 CM_ASL_CPUTEMPERATURE,
97 CM_ASL_FANCPU,
98 CM_ASL_FANCHASSIS,
99 CM_ASL_USBPORT1,
100 CM_ASL_USBPORT2,
101 CM_ASL_USBPORT3,
102 CM_ASL_MODEM,
103 CM_ASL_CARDREADER,
b7b700d4
CC
104 CM_ASL_3G,
105 CM_ASL_WIMAX,
106 CM_ASL_HWCF,
107 CM_ASL_LID,
108 CM_ASL_TYPE,
109 CM_ASL_PANELPOWER, /*P901*/
110 CM_ASL_TPD
e59f8796
EC
111};
112
14109461 113static const char *cm_getv[] = {
3af9bfcb 114 "WLDG", "BTHG", NULL, NULL,
e59f8796
EC
115 "CAMG", NULL, NULL, NULL,
116 NULL, "PBLG", NULL, NULL,
117 "CFVG", NULL, NULL, NULL,
118 "USBG", NULL, NULL, "MODG",
b7b700d4
CC
119 "CRDG", "M3GG", "WIMG", "HWCF",
120 "LIDG", "TYPE", "PBPG", "TPDG"
e59f8796
EC
121};
122
14109461 123static const char *cm_setv[] = {
3af9bfcb 124 "WLDS", "BTHS", NULL, NULL,
e59f8796
EC
125 "CAMS", NULL, NULL, NULL,
126 "SDSP", "PBLS", "HDPS", NULL,
127 "CFVS", NULL, NULL, NULL,
128 "USBG", NULL, NULL, "MODS",
b7b700d4
CC
129 "CRDS", "M3GS", "WIMS", NULL,
130 NULL, NULL, "PBPS", "TPDS"
e59f8796
EC
131};
132
854c7836 133static const struct key_entry eeepc_keymap[] = {
642e0447
DT
134 { KE_KEY, 0x10, { KEY_WLAN } },
135 { KE_KEY, 0x11, { KEY_WLAN } },
136 { KE_KEY, 0x12, { KEY_PROG1 } },
137 { KE_KEY, 0x13, { KEY_MUTE } },
138 { KE_KEY, 0x14, { KEY_VOLUMEDOWN } },
139 { KE_KEY, 0x15, { KEY_VOLUMEUP } },
140 { KE_KEY, 0x16, { KEY_DISPLAY_OFF } },
141 { KE_KEY, 0x1a, { KEY_COFFEE } },
142 { KE_KEY, 0x1b, { KEY_ZOOM } },
143 { KE_KEY, 0x1c, { KEY_PROG2 } },
144 { KE_KEY, 0x1d, { KEY_PROG3 } },
145 { KE_KEY, NOTIFY_BRN_MIN, { KEY_BRIGHTNESSDOWN } },
146 { KE_KEY, NOTIFY_BRN_MAX, { KEY_BRIGHTNESSUP } },
147 { KE_KEY, 0x30, { KEY_SWITCHVIDEOMODE } },
148 { KE_KEY, 0x31, { KEY_SWITCHVIDEOMODE } },
149 { KE_KEY, 0x32, { KEY_SWITCHVIDEOMODE } },
150 { KE_KEY, 0x37, { KEY_F13 } }, /* Disable Touchpad */
151 { KE_KEY, 0x38, { KEY_F14 } },
152 { KE_END, 0 },
a195dcdc
MG
153};
154
e59f8796 155/*
52bbe3c7 156 * This is the main structure, we can use it to store useful information
e59f8796 157 */
a7624b63 158struct eeepc_laptop {
854c7836 159 acpi_handle handle; /* the handle of the acpi device */
52bbe3c7
AJ
160 u32 cm_supported; /* the control methods supported
161 by this BIOS */
da8ba01d 162 bool cpufv_disabled;
10ae4b56 163 bool hotplug_disabled;
52bbe3c7 164 u16 event_count[128]; /* count for each event */
e59f8796 165
854c7836 166 struct platform_device *platform_device;
71e687dc 167 struct acpi_device *device; /* the device we are in */
854c7836 168 struct backlight_device *backlight_device;
2b121bc2 169
52bbe3c7 170 struct input_dev *inputdev;
2b121bc2 171
52bbe3c7
AJ
172 struct rfkill *wlan_rfkill;
173 struct rfkill *bluetooth_rfkill;
174 struct rfkill *wwan3g_rfkill;
175 struct rfkill *wimax_rfkill;
a5fa429b 176
52bbe3c7
AJ
177 struct hotplug_slot *hotplug_slot;
178 struct mutex hotplug_lock;
e1faa9da 179
854c7836
AJ
180 struct led_classdev tpd_led;
181 int tpd_led_wk;
182 struct workqueue_struct *led_workqueue;
183 struct work_struct tpd_led_work;
a5fa429b
CC
184};
185
e59f8796
EC
186/*
187 * ACPI Helpers
188 */
6b188a7b 189static int write_acpi_int(acpi_handle handle, const char *method, int val)
e59f8796 190{
e59f8796
EC
191 acpi_status status;
192
fca41991 193 status = acpi_execute_simple_method(handle, (char *)method, val);
e59f8796 194
e59f8796
EC
195 return (status == AE_OK ? 0 : -1);
196}
197
198static int read_acpi_int(acpi_handle handle, const char *method, int *val)
199{
200 acpi_status status;
27663c58 201 unsigned long long result;
e59f8796
EC
202
203 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
204 if (ACPI_FAILURE(status)) {
205 *val = -1;
206 return -1;
207 } else {
208 *val = result;
209 return 0;
210 }
211}
212
854c7836 213static int set_acpi(struct eeepc_laptop *eeepc, int cm, int value)
e59f8796 214{
13f70029 215 const char *method = cm_setv[cm];
e59f8796 216
13f70029
AJ
217 if (method == NULL)
218 return -ENODEV;
a7624b63 219 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
13f70029 220 return -ENODEV;
a5fa429b 221
a7624b63 222 if (write_acpi_int(eeepc->handle, method, value))
22441ffe 223 pr_warn("Error writing %s\n", method);
e59f8796 224 return 0;
a5fa429b
CC
225}
226
854c7836 227static int get_acpi(struct eeepc_laptop *eeepc, int cm)
a5fa429b 228{
13f70029
AJ
229 const char *method = cm_getv[cm];
230 int value;
a5fa429b 231
13f70029
AJ
232 if (method == NULL)
233 return -ENODEV;
a7624b63 234 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
13f70029 235 return -ENODEV;
a195dcdc 236
a7624b63 237 if (read_acpi_int(eeepc->handle, method, &value))
22441ffe 238 pr_warn("Error reading %s\n", method);
e59f8796 239 return value;
a195dcdc
MG
240}
241
f90be874
CC
242static int acpi_setter_handle(struct eeepc_laptop *eeepc, int cm,
243 acpi_handle *handle)
a195dcdc 244{
854c7836
AJ
245 const char *method = cm_setv[cm];
246 acpi_status status;
a195dcdc 247
854c7836
AJ
248 if (method == NULL)
249 return -ENODEV;
250 if ((eeepc->cm_supported & (0x1 << cm)) == 0)
251 return -ENODEV;
a195dcdc 252
854c7836 253 status = acpi_get_handle(eeepc->handle, (char *)method,
f90be874 254 handle);
854c7836 255 if (status != AE_OK) {
22441ffe 256 pr_warn("Error finding %s\n", method);
854c7836
AJ
257 return -ENODEV;
258 }
259 return 0;
cede2cb6
PE
260}
261
854c7836 262
e59f8796
EC
263/*
264 * Sys helpers
265 */
95369a73 266static int parse_arg(const char *buf, int *val)
e59f8796 267{
e59f8796
EC
268 if (sscanf(buf, "%i", val) != 1)
269 return -EINVAL;
95369a73 270 return 0;
e59f8796
EC
271}
272
854c7836
AJ
273static ssize_t store_sys_acpi(struct device *dev, int cm,
274 const char *buf, size_t count)
e59f8796 275{
854c7836 276 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
e59f8796
EC
277 int rv, value;
278
95369a73
PB
279 rv = parse_arg(buf, &value);
280 if (rv < 0)
281 return rv;
282 rv = set_acpi(eeepc, cm, value);
283 if (rv < 0)
6dff29b6 284 return -EIO;
95369a73 285 return count;
e59f8796
EC
286}
287
854c7836 288static ssize_t show_sys_acpi(struct device *dev, int cm, char *buf)
e59f8796 289{
854c7836
AJ
290 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
291 int value = get_acpi(eeepc, cm);
f36509e7
CC
292
293 if (value < 0)
6dff29b6 294 return -EIO;
f36509e7 295 return sprintf(buf, "%d\n", value);
e59f8796
EC
296}
297
97971325 298#define EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
8c72fc8b 299 static ssize_t _name##_show(struct device *dev, \
e59f8796
EC
300 struct device_attribute *attr, \
301 char *buf) \
302 { \
854c7836 303 return show_sys_acpi(dev, _cm, buf); \
97971325
FK
304 }
305
306#define EEEPC_ACPI_STORE_FUNC(_name, _cm) \
8c72fc8b 307 static ssize_t _name##_store(struct device *dev, \
e59f8796
EC
308 struct device_attribute *attr, \
309 const char *buf, size_t count) \
310 { \
854c7836 311 return store_sys_acpi(dev, _cm, buf, count); \
97971325
FK
312 }
313
6fe3a77f 314#define EEEPC_CREATE_DEVICE_ATTR_RW(_name, _cm) \
97971325
FK
315 EEEPC_ACPI_SHOW_FUNC(_name, _cm) \
316 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
6fe3a77f 317 static DEVICE_ATTR_RW(_name)
e59f8796 318
6fe3a77f
FK
319#define EEEPC_CREATE_DEVICE_ATTR_WO(_name, _cm) \
320 EEEPC_ACPI_STORE_FUNC(_name, _cm) \
321 static DEVICE_ATTR_WO(_name)
322
323EEEPC_CREATE_DEVICE_ATTR_RW(camera, CM_ASL_CAMERA);
324EEEPC_CREATE_DEVICE_ATTR_RW(cardr, CM_ASL_CARDREADER);
325EEEPC_CREATE_DEVICE_ATTR_WO(disp, CM_ASL_DISPLAYSWITCH);
b31d0fde
CC
326
327struct eeepc_cpufv {
328 int num;
329 int cur;
330};
331
854c7836 332static int get_cpufv(struct eeepc_laptop *eeepc, struct eeepc_cpufv *c)
b31d0fde 333{
854c7836 334 c->cur = get_acpi(eeepc, CM_ASL_CPUFV);
a5c155b1
FK
335 if (c->cur < 0)
336 return -ENODEV;
337
b31d0fde
CC
338 c->num = (c->cur >> 8) & 0xff;
339 c->cur &= 0xff;
a5c155b1 340 if (c->num == 0 || c->num > 12)
b31d0fde
CC
341 return -ENODEV;
342 return 0;
343}
344
8c72fc8b 345static ssize_t available_cpufv_show(struct device *dev,
b31d0fde
CC
346 struct device_attribute *attr,
347 char *buf)
348{
854c7836 349 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
350 struct eeepc_cpufv c;
351 int i;
352 ssize_t len = 0;
353
854c7836 354 if (get_cpufv(eeepc, &c))
b31d0fde
CC
355 return -ENODEV;
356 for (i = 0; i < c.num; i++)
357 len += sprintf(buf + len, "%d ", i);
358 len += sprintf(buf + len, "\n");
359 return len;
360}
361
8c72fc8b 362static ssize_t cpufv_show(struct device *dev,
b31d0fde
CC
363 struct device_attribute *attr,
364 char *buf)
365{
854c7836 366 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
367 struct eeepc_cpufv c;
368
854c7836 369 if (get_cpufv(eeepc, &c))
b31d0fde
CC
370 return -ENODEV;
371 return sprintf(buf, "%#x\n", (c.num << 8) | c.cur);
372}
373
8c72fc8b 374static ssize_t cpufv_store(struct device *dev,
b31d0fde
CC
375 struct device_attribute *attr,
376 const char *buf, size_t count)
377{
854c7836 378 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
b31d0fde
CC
379 struct eeepc_cpufv c;
380 int rv, value;
381
da8ba01d
AJ
382 if (eeepc->cpufv_disabled)
383 return -EPERM;
854c7836 384 if (get_cpufv(eeepc, &c))
b31d0fde 385 return -ENODEV;
95369a73 386 rv = parse_arg(buf, &value);
b31d0fde
CC
387 if (rv < 0)
388 return rv;
95369a73 389 if (value < 0 || value >= c.num)
b31d0fde 390 return -EINVAL;
d4869038
FK
391 rv = set_acpi(eeepc, CM_ASL_CPUFV, value);
392 if (rv)
393 return rv;
95369a73 394 return count;
b31d0fde
CC
395}
396
8c72fc8b 397static ssize_t cpufv_disabled_show(struct device *dev,
da8ba01d
AJ
398 struct device_attribute *attr,
399 char *buf)
400{
401 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
402
403 return sprintf(buf, "%d\n", eeepc->cpufv_disabled);
404}
405
8c72fc8b 406static ssize_t cpufv_disabled_store(struct device *dev,
da8ba01d
AJ
407 struct device_attribute *attr,
408 const char *buf, size_t count)
409{
410 struct eeepc_laptop *eeepc = dev_get_drvdata(dev);
411 int rv, value;
412
95369a73 413 rv = parse_arg(buf, &value);
da8ba01d
AJ
414 if (rv < 0)
415 return rv;
416
417 switch (value) {
418 case 0:
419 if (eeepc->cpufv_disabled)
9f662b20 420 pr_warn("cpufv enabled (not officially supported on this model)\n");
da8ba01d 421 eeepc->cpufv_disabled = false;
95369a73 422 return count;
da8ba01d
AJ
423 case 1:
424 return -EPERM;
425 default:
426 return -EINVAL;
427 }
428}
429
430
bb382dba
FK
431static DEVICE_ATTR_RW(cpufv);
432static DEVICE_ATTR_RO(available_cpufv);
433static DEVICE_ATTR_RW(cpufv_disabled);
da8ba01d 434
e59f8796
EC
435static struct attribute *platform_attributes[] = {
436 &dev_attr_camera.attr,
437 &dev_attr_cardr.attr,
438 &dev_attr_disp.attr,
158ca1d7 439 &dev_attr_cpufv.attr,
b31d0fde 440 &dev_attr_available_cpufv.attr,
da8ba01d 441 &dev_attr_cpufv_disabled.attr,
e59f8796
EC
442 NULL
443};
444
445static struct attribute_group platform_attribute_group = {
446 .attrs = platform_attributes
447};
448
854c7836 449static int eeepc_platform_init(struct eeepc_laptop *eeepc)
a195dcdc 450{
9db106be 451 int result;
a195dcdc 452
854c7836
AJ
453 eeepc->platform_device = platform_device_alloc(EEEPC_LAPTOP_FILE, -1);
454 if (!eeepc->platform_device)
9db106be 455 return -ENOMEM;
854c7836 456 platform_set_drvdata(eeepc->platform_device, eeepc);
a195dcdc 457
854c7836 458 result = platform_device_add(eeepc->platform_device);
9db106be
AJ
459 if (result)
460 goto fail_platform_device;
a195dcdc 461
854c7836 462 result = sysfs_create_group(&eeepc->platform_device->dev.kobj,
9db106be
AJ
463 &platform_attribute_group);
464 if (result)
465 goto fail_sysfs;
466 return 0;
a195dcdc 467
9db106be 468fail_sysfs:
854c7836 469 platform_device_del(eeepc->platform_device);
9db106be 470fail_platform_device:
854c7836 471 platform_device_put(eeepc->platform_device);
9db106be 472 return result;
a195dcdc
MG
473}
474
854c7836 475static void eeepc_platform_exit(struct eeepc_laptop *eeepc)
a195dcdc 476{
854c7836 477 sysfs_remove_group(&eeepc->platform_device->dev.kobj,
9db106be 478 &platform_attribute_group);
854c7836 479 platform_device_unregister(eeepc->platform_device);
9db106be 480}
a195dcdc 481
3c0eb510
CC
482/*
483 * LEDs
484 */
485/*
486 * These functions actually update the LED's, and are called from a
487 * workqueue. By doing this as separate work rather than when the LED
488 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
489 * potentially bad time, such as a timer interrupt.
490 */
854c7836
AJ
491static void tpd_led_update(struct work_struct *work)
492 {
493 struct eeepc_laptop *eeepc;
a195dcdc 494
854c7836 495 eeepc = container_of(work, struct eeepc_laptop, tpd_led_work);
3c0eb510 496
854c7836 497 set_acpi(eeepc, CM_ASL_TPD, eeepc->tpd_led_wk);
a195dcdc
MG
498}
499
3c0eb510
CC
500static void tpd_led_set(struct led_classdev *led_cdev,
501 enum led_brightness value)
a195dcdc 502{
854c7836 503 struct eeepc_laptop *eeepc;
a195dcdc 504
854c7836 505 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
a195dcdc 506
854c7836
AJ
507 eeepc->tpd_led_wk = (value > 0) ? 1 : 0;
508 queue_work(eeepc->led_workqueue, &eeepc->tpd_led_work);
a195dcdc
MG
509}
510
62a75d83
CC
511static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
512{
513 struct eeepc_laptop *eeepc;
514
515 eeepc = container_of(led_cdev, struct eeepc_laptop, tpd_led);
516
517 return get_acpi(eeepc, CM_ASL_TPD);
518}
519
854c7836 520static int eeepc_led_init(struct eeepc_laptop *eeepc)
dbfa3ba9 521{
52bbe3c7 522 int rv;
dbfa3ba9 523
854c7836 524 if (get_acpi(eeepc, CM_ASL_TPD) == -ENODEV)
52bbe3c7 525 return 0;
dbfa3ba9 526
854c7836
AJ
527 eeepc->led_workqueue = create_singlethread_workqueue("led_workqueue");
528 if (!eeepc->led_workqueue)
52bbe3c7 529 return -ENOMEM;
854c7836 530 INIT_WORK(&eeepc->tpd_led_work, tpd_led_update);
dbfa3ba9 531
854c7836
AJ
532 eeepc->tpd_led.name = "eeepc::touchpad";
533 eeepc->tpd_led.brightness_set = tpd_led_set;
62a75d83 534 if (get_acpi(eeepc, CM_ASL_TPD) >= 0) /* if method is available */
39a3e17e 535 eeepc->tpd_led.brightness_get = tpd_led_get;
854c7836 536 eeepc->tpd_led.max_brightness = 1;
e59f8796 537
854c7836
AJ
538 rv = led_classdev_register(&eeepc->platform_device->dev,
539 &eeepc->tpd_led);
52bbe3c7 540 if (rv) {
854c7836 541 destroy_workqueue(eeepc->led_workqueue);
52bbe3c7 542 return rv;
e59f8796 543 }
a195dcdc 544
e59f8796
EC
545 return 0;
546}
547
854c7836 548static void eeepc_led_exit(struct eeepc_laptop *eeepc)
a5fa429b 549{
5d6afd15 550 if (!IS_ERR_OR_NULL(eeepc->tpd_led.dev))
854c7836
AJ
551 led_classdev_unregister(&eeepc->tpd_led);
552 if (eeepc->led_workqueue)
553 destroy_workqueue(eeepc->led_workqueue);
a5fa429b
CC
554}
555
2b121bc2 556
52bbe3c7
AJ
557/*
558 * PCI hotplug (for wlan rfkill)
559 */
854c7836 560static bool eeepc_wlan_rfkill_blocked(struct eeepc_laptop *eeepc)
52bbe3c7 561{
854c7836 562 if (get_acpi(eeepc, CM_ASL_WLAN) == 1)
52bbe3c7
AJ
563 return false;
564 return true;
2b121bc2
CC
565}
566
14fdb152 567static void eeepc_rfkill_hotplug(struct eeepc_laptop *eeepc, acpi_handle handle)
5740294c 568{
14fdb152 569 struct pci_dev *port;
5740294c 570 struct pci_dev *dev;
6d41839e 571 struct pci_bus *bus;
854c7836 572 bool blocked = eeepc_wlan_rfkill_blocked(eeepc);
bc9d24a3
AJ
573 bool absent;
574 u32 l;
5740294c 575
a7624b63
AJ
576 if (eeepc->wlan_rfkill)
577 rfkill_set_sw_state(eeepc->wlan_rfkill, blocked);
6d41839e 578
a7624b63 579 mutex_lock(&eeepc->hotplug_lock);
8b9ec1da 580 pci_lock_rescan_remove();
dcf443b5 581
248d4903
FK
582 if (!eeepc->hotplug_slot)
583 goto out_unlock;
14fdb152 584
248d4903
FK
585 port = acpi_get_pci_dev(handle);
586 if (!port) {
587 pr_warning("Unable to find port\n");
588 goto out_unlock;
589 }
14fdb152 590
248d4903 591 bus = port->subordinate;
07e84aa9 592
248d4903
FK
593 if (!bus) {
594 pr_warn("Unable to find PCI bus 1?\n");
595 goto out_put_dev;
596 }
597
598 if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
599 pr_err("Unable to read PCI config space?\n");
600 goto out_put_dev;
601 }
602
603 absent = (l == 0xffffffff);
14fdb152 604
248d4903 605 if (blocked != absent) {
9f662b20 606 pr_warn("BIOS says wireless lan is %s, but the pci device is %s\n",
248d4903
FK
607 blocked ? "blocked" : "unblocked",
608 absent ? "absent" : "present");
9f662b20 609 pr_warn("skipped wireless hotplug as probably inappropriate for this model\n");
248d4903
FK
610 goto out_put_dev;
611 }
bc9d24a3 612
248d4903
FK
613 if (!blocked) {
614 dev = pci_get_slot(bus, 0);
615 if (dev) {
616 /* Device already present */
617 pci_dev_put(dev);
f661848b 618 goto out_put_dev;
bc9d24a3 619 }
248d4903
FK
620 dev = pci_scan_single_device(bus, 0);
621 if (dev) {
622 pci_bus_assign_resources(bus);
623 pci_bus_add_device(dev);
624 }
625 } else {
626 dev = pci_get_slot(bus, 0);
627 if (dev) {
628 pci_stop_and_remove_bus_device(dev);
629 pci_dev_put(dev);
5740294c
MG
630 }
631 }
248d4903
FK
632out_put_dev:
633 pci_dev_put(port);
dcf443b5
AJ
634
635out_unlock:
8b9ec1da 636 pci_unlock_rescan_remove();
a7624b63 637 mutex_unlock(&eeepc->hotplug_lock);
5740294c
MG
638}
639
14fdb152
MG
640static void eeepc_rfkill_hotplug_update(struct eeepc_laptop *eeepc, char *node)
641{
642 acpi_status status = AE_OK;
643 acpi_handle handle;
644
645 status = acpi_get_handle(NULL, node, &handle);
646
647 if (ACPI_SUCCESS(status))
648 eeepc_rfkill_hotplug(eeepc, handle);
649}
650
96e9cfeb
AJ
651static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
652{
854c7836
AJ
653 struct eeepc_laptop *eeepc = data;
654
96e9cfeb
AJ
655 if (event != ACPI_NOTIFY_BUS_CHECK)
656 return;
657
14fdb152 658 eeepc_rfkill_hotplug(eeepc, handle);
e59f8796
EC
659}
660
854c7836
AJ
661static int eeepc_register_rfkill_notifier(struct eeepc_laptop *eeepc,
662 char *node)
5740294c 663{
854c7836 664 acpi_status status;
5740294c
MG
665 acpi_handle handle;
666
667 status = acpi_get_handle(NULL, node, &handle);
668
557b4549 669 if (ACPI_FAILURE(status))
5740294c
MG
670 return -ENODEV;
671
557b4549
FK
672 status = acpi_install_notify_handler(handle,
673 ACPI_SYSTEM_NOTIFY,
674 eeepc_rfkill_notify,
675 eeepc);
676 if (ACPI_FAILURE(status))
677 pr_warn("Failed to register notify on %s\n", node);
678
679 /*
680 * Refresh pci hotplug in case the rfkill state was
681 * changed during setup.
682 */
683 eeepc_rfkill_hotplug(eeepc, handle);
5740294c
MG
684 return 0;
685}
686
854c7836
AJ
687static void eeepc_unregister_rfkill_notifier(struct eeepc_laptop *eeepc,
688 char *node)
5740294c
MG
689{
690 acpi_status status = AE_OK;
691 acpi_handle handle;
692
693 status = acpi_get_handle(NULL, node, &handle);
694
557b4549
FK
695 if (ACPI_FAILURE(status))
696 return;
697
698 status = acpi_remove_notify_handler(handle,
699 ACPI_SYSTEM_NOTIFY,
700 eeepc_rfkill_notify);
701 if (ACPI_FAILURE(status))
702 pr_err("Error removing rfkill notify handler %s\n",
703 node);
704 /*
705 * Refresh pci hotplug in case the rfkill
706 * state was changed after
707 * eeepc_unregister_rfkill_notifier()
708 */
709 eeepc_rfkill_hotplug(eeepc, handle);
5740294c
MG
710}
711
52bbe3c7
AJ
712static int eeepc_get_adapter_status(struct hotplug_slot *hotplug_slot,
713 u8 *value)
714{
854c7836
AJ
715 struct eeepc_laptop *eeepc = hotplug_slot->private;
716 int val = get_acpi(eeepc, CM_ASL_WLAN);
52bbe3c7
AJ
717
718 if (val == 1 || val == 0)
719 *value = val;
720 else
721 return -EINVAL;
722
723 return 0;
724}
725
2b121bc2
CC
726static void eeepc_cleanup_pci_hotplug(struct hotplug_slot *hotplug_slot)
727{
728 kfree(hotplug_slot->info);
729 kfree(hotplug_slot);
730}
731
52bbe3c7
AJ
732static struct hotplug_slot_ops eeepc_hotplug_slot_ops = {
733 .owner = THIS_MODULE,
734 .get_adapter_status = eeepc_get_adapter_status,
735 .get_power_status = eeepc_get_adapter_status,
736};
737
854c7836 738static int eeepc_setup_pci_hotplug(struct eeepc_laptop *eeepc)
2b121bc2
CC
739{
740 int ret = -ENOMEM;
741 struct pci_bus *bus = pci_find_bus(0, 1);
742
743 if (!bus) {
19b53289 744 pr_err("Unable to find wifi PCI bus\n");
2b121bc2
CC
745 return -ENODEV;
746 }
747
a7624b63
AJ
748 eeepc->hotplug_slot = kzalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
749 if (!eeepc->hotplug_slot)
2b121bc2
CC
750 goto error_slot;
751
a7624b63 752 eeepc->hotplug_slot->info = kzalloc(sizeof(struct hotplug_slot_info),
2b121bc2 753 GFP_KERNEL);
a7624b63 754 if (!eeepc->hotplug_slot->info)
2b121bc2
CC
755 goto error_info;
756
a7624b63
AJ
757 eeepc->hotplug_slot->private = eeepc;
758 eeepc->hotplug_slot->release = &eeepc_cleanup_pci_hotplug;
759 eeepc->hotplug_slot->ops = &eeepc_hotplug_slot_ops;
760 eeepc_get_adapter_status(eeepc->hotplug_slot,
761 &eeepc->hotplug_slot->info->adapter_status);
2b121bc2 762
a7624b63 763 ret = pci_hp_register(eeepc->hotplug_slot, bus, 0, "eeepc-wifi");
2b121bc2 764 if (ret) {
19b53289 765 pr_err("Unable to register hotplug slot - %d\n", ret);
2b121bc2
CC
766 goto error_register;
767 }
768
769 return 0;
770
771error_register:
a7624b63 772 kfree(eeepc->hotplug_slot->info);
2b121bc2 773error_info:
a7624b63
AJ
774 kfree(eeepc->hotplug_slot);
775 eeepc->hotplug_slot = NULL;
2b121bc2
CC
776error_slot:
777 return ret;
778}
779
52bbe3c7
AJ
780/*
781 * Rfkill devices
782 */
783static int eeepc_rfkill_set(void *data, bool blocked)
96e9cfeb 784{
854c7836 785 acpi_handle handle = data;
c200da5d 786
854c7836 787 return write_acpi_int(handle, NULL, !blocked);
c200da5d 788}
96e9cfeb 789
52bbe3c7
AJ
790static const struct rfkill_ops eeepc_rfkill_ops = {
791 .set_block = eeepc_rfkill_set,
792};
793
854c7836
AJ
794static int eeepc_new_rfkill(struct eeepc_laptop *eeepc,
795 struct rfkill **rfkill,
796 const char *name,
52bbe3c7
AJ
797 enum rfkill_type type, int cm)
798{
854c7836 799 acpi_handle handle;
52bbe3c7
AJ
800 int result;
801
854c7836 802 result = acpi_setter_handle(eeepc, cm, &handle);
52bbe3c7
AJ
803 if (result < 0)
804 return result;
805
854c7836
AJ
806 *rfkill = rfkill_alloc(name, &eeepc->platform_device->dev, type,
807 &eeepc_rfkill_ops, handle);
96e9cfeb 808
52bbe3c7
AJ
809 if (!*rfkill)
810 return -EINVAL;
811
854c7836 812 rfkill_init_sw_state(*rfkill, get_acpi(eeepc, cm) != 1);
52bbe3c7
AJ
813 result = rfkill_register(*rfkill);
814 if (result) {
815 rfkill_destroy(*rfkill);
816 *rfkill = NULL;
817 return result;
818 }
96e9cfeb
AJ
819 return 0;
820}
821
792bd2a5
FK
822static char EEEPC_RFKILL_NODE_1[] = "\\_SB.PCI0.P0P5";
823static char EEEPC_RFKILL_NODE_2[] = "\\_SB.PCI0.P0P6";
824static char EEEPC_RFKILL_NODE_3[] = "\\_SB.PCI0.P0P7";
825
854c7836 826static void eeepc_rfkill_exit(struct eeepc_laptop *eeepc)
52bbe3c7 827{
792bd2a5
FK
828 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
829 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
830 eeepc_unregister_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
a7624b63
AJ
831 if (eeepc->wlan_rfkill) {
832 rfkill_unregister(eeepc->wlan_rfkill);
833 rfkill_destroy(eeepc->wlan_rfkill);
834 eeepc->wlan_rfkill = NULL;
52bbe3c7 835 }
14fdb152 836
a7624b63
AJ
837 if (eeepc->hotplug_slot)
838 pci_hp_deregister(eeepc->hotplug_slot);
52bbe3c7 839
a7624b63
AJ
840 if (eeepc->bluetooth_rfkill) {
841 rfkill_unregister(eeepc->bluetooth_rfkill);
842 rfkill_destroy(eeepc->bluetooth_rfkill);
843 eeepc->bluetooth_rfkill = NULL;
52bbe3c7 844 }
a7624b63
AJ
845 if (eeepc->wwan3g_rfkill) {
846 rfkill_unregister(eeepc->wwan3g_rfkill);
847 rfkill_destroy(eeepc->wwan3g_rfkill);
848 eeepc->wwan3g_rfkill = NULL;
52bbe3c7 849 }
a7624b63
AJ
850 if (eeepc->wimax_rfkill) {
851 rfkill_unregister(eeepc->wimax_rfkill);
852 rfkill_destroy(eeepc->wimax_rfkill);
853 eeepc->wimax_rfkill = NULL;
52bbe3c7
AJ
854 }
855}
856
854c7836 857static int eeepc_rfkill_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
858{
859 int result = 0;
860
a7624b63 861 mutex_init(&eeepc->hotplug_lock);
52bbe3c7 862
854c7836
AJ
863 result = eeepc_new_rfkill(eeepc, &eeepc->wlan_rfkill,
864 "eeepc-wlan", RFKILL_TYPE_WLAN,
865 CM_ASL_WLAN);
52bbe3c7
AJ
866
867 if (result && result != -ENODEV)
868 goto exit;
869
854c7836
AJ
870 result = eeepc_new_rfkill(eeepc, &eeepc->bluetooth_rfkill,
871 "eeepc-bluetooth", RFKILL_TYPE_BLUETOOTH,
872 CM_ASL_BLUETOOTH);
52bbe3c7
AJ
873
874 if (result && result != -ENODEV)
875 goto exit;
876
854c7836
AJ
877 result = eeepc_new_rfkill(eeepc, &eeepc->wwan3g_rfkill,
878 "eeepc-wwan3g", RFKILL_TYPE_WWAN,
879 CM_ASL_3G);
52bbe3c7
AJ
880
881 if (result && result != -ENODEV)
882 goto exit;
883
854c7836
AJ
884 result = eeepc_new_rfkill(eeepc, &eeepc->wimax_rfkill,
885 "eeepc-wimax", RFKILL_TYPE_WIMAX,
886 CM_ASL_WIMAX);
52bbe3c7
AJ
887
888 if (result && result != -ENODEV)
889 goto exit;
890
10ae4b56
CC
891 if (eeepc->hotplug_disabled)
892 return 0;
893
854c7836 894 result = eeepc_setup_pci_hotplug(eeepc);
52bbe3c7
AJ
895 /*
896 * If we get -EBUSY then something else is handling the PCI hotplug -
897 * don't fail in this case
898 */
899 if (result == -EBUSY)
900 result = 0;
901
792bd2a5
FK
902 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_1);
903 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_2);
904 eeepc_register_rfkill_notifier(eeepc, EEEPC_RFKILL_NODE_3);
52bbe3c7
AJ
905
906exit:
907 if (result && result != -ENODEV)
854c7836 908 eeepc_rfkill_exit(eeepc);
52bbe3c7
AJ
909 return result;
910}
911
e1faa9da 912/*
52bbe3c7 913 * Platform driver - hibernate/resume callbacks
e1faa9da 914 */
854c7836 915static int eeepc_hotk_thaw(struct device *device)
96e9cfeb 916{
854c7836
AJ
917 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
918
a7624b63 919 if (eeepc->wlan_rfkill) {
96e9cfeb
AJ
920 bool wlan;
921
c1edd99f
AJ
922 /*
923 * Work around bios bug - acpi _PTS turns off the wireless led
924 * during suspend. Normally it restores it on resume, but
c200da5d 925 * we should kick it ourselves in case hibernation is aborted.
96e9cfeb 926 */
854c7836
AJ
927 wlan = get_acpi(eeepc, CM_ASL_WLAN);
928 set_acpi(eeepc, CM_ASL_WLAN, wlan);
c200da5d
AJ
929 }
930
931 return 0;
932}
96e9cfeb 933
854c7836 934static int eeepc_hotk_restore(struct device *device)
c200da5d 935{
854c7836
AJ
936 struct eeepc_laptop *eeepc = dev_get_drvdata(device);
937
c200da5d 938 /* Refresh both wlan rfkill state and pci hotplug */
14fdb152 939 if (eeepc->wlan_rfkill) {
792bd2a5
FK
940 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_1);
941 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_2);
942 eeepc_rfkill_hotplug_update(eeepc, EEEPC_RFKILL_NODE_3);
14fdb152 943 }
96e9cfeb 944
a7624b63
AJ
945 if (eeepc->bluetooth_rfkill)
946 rfkill_set_sw_state(eeepc->bluetooth_rfkill,
854c7836 947 get_acpi(eeepc, CM_ASL_BLUETOOTH) != 1);
a7624b63
AJ
948 if (eeepc->wwan3g_rfkill)
949 rfkill_set_sw_state(eeepc->wwan3g_rfkill,
854c7836 950 get_acpi(eeepc, CM_ASL_3G) != 1);
a7624b63
AJ
951 if (eeepc->wimax_rfkill)
952 rfkill_set_sw_state(eeepc->wimax_rfkill,
854c7836 953 get_acpi(eeepc, CM_ASL_WIMAX) != 1);
96e9cfeb
AJ
954
955 return 0;
956}
957
9a3bff23 958static const struct dev_pm_ops eeepc_pm_ops = {
854c7836
AJ
959 .thaw = eeepc_hotk_thaw,
960 .restore = eeepc_hotk_restore,
52bbe3c7
AJ
961};
962
963static struct platform_driver platform_driver = {
964 .driver = {
a7624b63 965 .name = EEEPC_LAPTOP_FILE,
52bbe3c7
AJ
966 .owner = THIS_MODULE,
967 .pm = &eeepc_pm_ops,
968 }
969};
970
e1faa9da 971/*
52bbe3c7 972 * Hwmon device
e1faa9da 973 */
52bbe3c7
AJ
974
975#define EEEPC_EC_SC00 0x61
976#define EEEPC_EC_FAN_PWM (EEEPC_EC_SC00 + 2) /* Fan PWM duty cycle (%) */
977#define EEEPC_EC_FAN_HRPM (EEEPC_EC_SC00 + 5) /* High byte, fan speed (RPM) */
978#define EEEPC_EC_FAN_LRPM (EEEPC_EC_SC00 + 6) /* Low byte, fan speed (RPM) */
979
980#define EEEPC_EC_SFB0 0xD0
981#define EEEPC_EC_FAN_CTRL (EEEPC_EC_SFB0 + 3) /* Byte containing SF25 */
982
148a5dd5
FK
983static inline int eeepc_pwm_to_lmsensors(int value)
984{
985 return value * 255 / 100;
986}
987
988static inline int eeepc_lmsensors_to_pwm(int value)
989{
990 value = clamp_val(value, 0, 255);
991 return value * 100 / 255;
992}
993
e1faa9da
CC
994static int eeepc_get_fan_pwm(void)
995{
463b4e47 996 u8 value = 0;
e1faa9da 997
463b4e47 998 ec_read(EEEPC_EC_FAN_PWM, &value);
148a5dd5 999 return eeepc_pwm_to_lmsensors(value);
e1faa9da
CC
1000}
1001
1002static void eeepc_set_fan_pwm(int value)
1003{
148a5dd5 1004 value = eeepc_lmsensors_to_pwm(value);
463b4e47 1005 ec_write(EEEPC_EC_FAN_PWM, value);
e1faa9da
CC
1006}
1007
1008static int eeepc_get_fan_rpm(void)
1009{
463b4e47
AJ
1010 u8 high = 0;
1011 u8 low = 0;
e1faa9da 1012
463b4e47
AJ
1013 ec_read(EEEPC_EC_FAN_HRPM, &high);
1014 ec_read(EEEPC_EC_FAN_LRPM, &low);
1015 return high << 8 | low;
e1faa9da
CC
1016}
1017
a5de681c
FK
1018#define EEEPC_EC_FAN_CTRL_BIT 0x02
1019#define EEEPC_FAN_CTRL_MANUAL 1
1020#define EEEPC_FAN_CTRL_AUTO 2
1021
e1faa9da
CC
1022static int eeepc_get_fan_ctrl(void)
1023{
463b4e47 1024 u8 value = 0;
e1faa9da 1025
463b4e47 1026 ec_read(EEEPC_EC_FAN_CTRL, &value);
a5de681c
FK
1027 if (value & EEEPC_EC_FAN_CTRL_BIT)
1028 return EEEPC_FAN_CTRL_MANUAL;
48718688 1029 else
a5de681c 1030 return EEEPC_FAN_CTRL_AUTO;
e1faa9da
CC
1031}
1032
1033static void eeepc_set_fan_ctrl(int manual)
1034{
463b4e47 1035 u8 value = 0;
e1faa9da 1036
463b4e47 1037 ec_read(EEEPC_EC_FAN_CTRL, &value);
a5de681c
FK
1038 if (manual == EEEPC_FAN_CTRL_MANUAL)
1039 value |= EEEPC_EC_FAN_CTRL_BIT;
e1faa9da 1040 else
a5de681c 1041 value &= ~EEEPC_EC_FAN_CTRL_BIT;
463b4e47 1042 ec_write(EEEPC_EC_FAN_CTRL, value);
e1faa9da
CC
1043}
1044
1045static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
1046{
1047 int rv, value;
1048
95369a73
PB
1049 rv = parse_arg(buf, &value);
1050 if (rv < 0)
1051 return rv;
1052 set(value);
1053 return count;
e1faa9da
CC
1054}
1055
1056static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
1057{
1058 return sprintf(buf, "%d\n", get());
1059}
1060
28ac85f7 1061#define EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
48d4a5b2 1062 static ssize_t _name##_show(struct device *dev, \
e1faa9da
CC
1063 struct device_attribute *attr, \
1064 char *buf) \
1065 { \
1ec9d399 1066 return show_sys_hwmon(_get, buf); \
28ac85f7
FK
1067 }
1068
1069#define EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2 1070 static ssize_t _name##_store(struct device *dev, \
e1faa9da
CC
1071 struct device_attribute *attr, \
1072 const char *buf, size_t count) \
1073 { \
1ec9d399 1074 return store_sys_hwmon(_set, buf, count); \
28ac85f7
FK
1075 }
1076
48d4a5b2 1077#define EEEPC_CREATE_SENSOR_ATTR_RW(_name, _get, _set) \
28ac85f7
FK
1078 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1079 EEEPC_SENSOR_STORE_FUNC(_name, _set) \
48d4a5b2
FK
1080 static DEVICE_ATTR_RW(_name)
1081
1082#define EEEPC_CREATE_SENSOR_ATTR_RO(_name, _get) \
1083 EEEPC_SENSOR_SHOW_FUNC(_name, _get) \
1084 static DEVICE_ATTR_RO(_name)
e1faa9da 1085
48d4a5b2
FK
1086EEEPC_CREATE_SENSOR_ATTR_RO(fan1_input, eeepc_get_fan_rpm);
1087EEEPC_CREATE_SENSOR_ATTR_RW(pwm1, eeepc_get_fan_pwm,
1088 eeepc_set_fan_pwm);
1089EEEPC_CREATE_SENSOR_ATTR_RW(pwm1_enable, eeepc_get_fan_ctrl,
1090 eeepc_set_fan_ctrl);
e1faa9da 1091
f0c34c97
GR
1092static struct attribute *hwmon_attrs[] = {
1093 &dev_attr_pwm1.attr,
1094 &dev_attr_fan1_input.attr,
1095 &dev_attr_pwm1_enable.attr,
e1faa9da
CC
1096 NULL
1097};
f0c34c97 1098ATTRIBUTE_GROUPS(hwmon);
a9df80c5 1099
854c7836 1100static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
a9df80c5 1101{
f0c34c97 1102 struct device *dev = &eeepc->platform_device->dev;
52bbe3c7 1103 struct device *hwmon;
7de39389 1104
f0c34c97
GR
1105 hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,
1106 hwmon_groups);
52bbe3c7
AJ
1107 if (IS_ERR(hwmon)) {
1108 pr_err("Could not register eeepc hwmon device\n");
52bbe3c7 1109 return PTR_ERR(hwmon);
a8258069 1110 }
f0c34c97 1111 return 0;
a9df80c5
CC
1112}
1113
52bbe3c7
AJ
1114/*
1115 * Backlight device
1116 */
1117static int read_brightness(struct backlight_device *bd)
a9df80c5 1118{
854c7836
AJ
1119 struct eeepc_laptop *eeepc = bl_get_data(bd);
1120
1121 return get_acpi(eeepc, CM_ASL_PANELBRIGHT);
a5fa429b
CC
1122}
1123
52bbe3c7 1124static int set_brightness(struct backlight_device *bd, int value)
e1faa9da 1125{
854c7836 1126 struct eeepc_laptop *eeepc = bl_get_data(bd);
e1faa9da 1127
854c7836 1128 return set_acpi(eeepc, CM_ASL_PANELBRIGHT, value);
e1faa9da
CC
1129}
1130
52bbe3c7 1131static int update_bl_status(struct backlight_device *bd)
7de39389 1132{
52bbe3c7
AJ
1133 return set_brightness(bd, bd->props.brightness);
1134}
7de39389 1135
acc2472e 1136static const struct backlight_ops eeepcbl_ops = {
52bbe3c7
AJ
1137 .get_brightness = read_brightness,
1138 .update_status = update_bl_status,
1139};
7de39389 1140
854c7836 1141static int eeepc_backlight_notify(struct eeepc_laptop *eeepc)
52bbe3c7 1142{
854c7836 1143 struct backlight_device *bd = eeepc->backlight_device;
52bbe3c7 1144 int old = bd->props.brightness;
7de39389 1145
52bbe3c7 1146 backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
7de39389 1147
52bbe3c7 1148 return old;
7de39389
CC
1149}
1150
854c7836 1151static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
7de39389 1152{
a19a6ee6 1153 struct backlight_properties props;
a5fa429b 1154 struct backlight_device *bd;
7334546a 1155
a19a6ee6 1156 memset(&props, 0, sizeof(struct backlight_properties));
bb7ca747 1157 props.type = BACKLIGHT_PLATFORM;
a19a6ee6 1158 props.max_brightness = 15;
854c7836 1159 bd = backlight_device_register(EEEPC_LAPTOP_FILE,
a19a6ee6
MG
1160 &eeepc->platform_device->dev, eeepc,
1161 &eeepcbl_ops, &props);
a5fa429b 1162 if (IS_ERR(bd)) {
19b53289 1163 pr_err("Could not register eeepc backlight device\n");
854c7836 1164 eeepc->backlight_device = NULL;
a5fa429b
CC
1165 return PTR_ERR(bd);
1166 }
854c7836 1167 eeepc->backlight_device = bd;
854c7836 1168 bd->props.brightness = read_brightness(bd);
a5fa429b
CC
1169 bd->props.power = FB_BLANK_UNBLANK;
1170 backlight_update_status(bd);
1171 return 0;
1172}
7de39389 1173
854c7836 1174static void eeepc_backlight_exit(struct eeepc_laptop *eeepc)
e1faa9da 1175{
854c7836
AJ
1176 if (eeepc->backlight_device)
1177 backlight_device_unregister(eeepc->backlight_device);
1178 eeepc->backlight_device = NULL;
52bbe3c7 1179}
7de39389 1180
7de39389 1181
52bbe3c7
AJ
1182/*
1183 * Input device (i.e. hotkeys)
1184 */
642e0447 1185static int eeepc_input_init(struct eeepc_laptop *eeepc)
52bbe3c7 1186{
642e0447
DT
1187 struct input_dev *input;
1188 int error;
3cd530b5 1189
642e0447 1190 input = input_allocate_device();
b222cca6 1191 if (!input)
642e0447 1192 return -ENOMEM;
07e84aa9 1193
642e0447
DT
1194 input->name = "Asus EeePC extra buttons";
1195 input->phys = EEEPC_LAPTOP_FILE "/input0";
1196 input->id.bustype = BUS_HOST;
1197 input->dev.parent = &eeepc->platform_device->dev;
7de39389 1198
642e0447
DT
1199 error = sparse_keymap_setup(input, eeepc_keymap, NULL);
1200 if (error) {
1201 pr_err("Unable to setup input device keymap\n");
1202 goto err_free_dev;
a5fa429b 1203 }
52bbe3c7 1204
642e0447
DT
1205 error = input_register_device(input);
1206 if (error) {
1207 pr_err("Unable to register input device\n");
1208 goto err_free_keymap;
e1faa9da 1209 }
52bbe3c7 1210
642e0447 1211 eeepc->inputdev = input;
f2a9d5e8 1212 return 0;
642e0447 1213
71e687dc 1214err_free_keymap:
642e0447 1215 sparse_keymap_free(input);
71e687dc 1216err_free_dev:
642e0447
DT
1217 input_free_device(input);
1218 return error;
f2a9d5e8
AJ
1219}
1220
854c7836 1221static void eeepc_input_exit(struct eeepc_laptop *eeepc)
e59f8796 1222{
854c7836 1223 if (eeepc->inputdev) {
c9db3efe 1224 sparse_keymap_free(eeepc->inputdev);
a7624b63 1225 input_unregister_device(eeepc->inputdev);
854c7836 1226 }
71e687dc 1227 eeepc->inputdev = NULL;
52bbe3c7 1228}
3c0eb510 1229
52bbe3c7
AJ
1230/*
1231 * ACPI driver
1232 */
ce6c468f
CC
1233static void eeepc_input_notify(struct eeepc_laptop *eeepc, int event)
1234{
1235 if (!eeepc->inputdev)
1236 return ;
1237 if (!sparse_keymap_report_event(eeepc->inputdev, event, 1, true))
1238 pr_info("Unknown key %x pressed\n", event);
1239}
1240
a7624b63 1241static void eeepc_acpi_notify(struct acpi_device *device, u32 event)
52bbe3c7 1242{
854c7836 1243 struct eeepc_laptop *eeepc = acpi_driver_data(device);
52bbe3c7 1244 u16 count;
3c0eb510 1245
52bbe3c7
AJ
1246 if (event > ACPI_MAX_SYS_NOTIFY)
1247 return;
a7624b63 1248 count = eeepc->event_count[event % 128]++;
854c7836
AJ
1249 acpi_bus_generate_netlink_event(device->pnp.device_class,
1250 dev_name(&device->dev), event,
52bbe3c7 1251 count);
3c0eb510 1252
325fb8e9 1253 /* Brightness events are special */
52bbe3c7 1254 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX) {
52bbe3c7 1255
325fb8e9
AJ
1256 /* Ignore them completely if the acpi video driver is used */
1257 if (eeepc->backlight_device != NULL) {
1258 int old_brightness, new_brightness;
1259
1260 /* Update the backlight device. */
1261 old_brightness = eeepc_backlight_notify(eeepc);
1262
1263 /* Convert event to keypress (obsolescent hack) */
1264 new_brightness = event - NOTIFY_BRN_MIN;
1265
1266 if (new_brightness < old_brightness) {
1267 event = NOTIFY_BRN_MIN; /* brightness down */
1268 } else if (new_brightness > old_brightness) {
1269 event = NOTIFY_BRN_MAX; /* brightness up */
1270 } else {
1271 /*
1272 * no change in brightness - already at min/max,
1273 * event will be desired value (or else ignored)
1274 */
1275 }
ce6c468f 1276 eeepc_input_notify(eeepc, event);
52bbe3c7 1277 }
325fb8e9
AJ
1278 } else {
1279 /* Everything else is a bona-fide keypress event */
ce6c468f 1280 eeepc_input_notify(eeepc, event);
52bbe3c7 1281 }
52bbe3c7
AJ
1282}
1283
da8ba01d
AJ
1284static void eeepc_dmi_check(struct eeepc_laptop *eeepc)
1285{
1286 const char *model;
1287
10ae4b56
CC
1288 model = dmi_get_system_info(DMI_PRODUCT_NAME);
1289 if (!model)
1290 return;
1291
da8ba01d
AJ
1292 /*
1293 * Blacklist for setting cpufv (cpu speed).
1294 *
1295 * EeePC 4G ("701") implements CFVS, but it is not supported
1296 * by the pre-installed OS, and the original option to change it
1297 * in the BIOS setup screen was removed in later versions.
1298 *
1299 * Judging by the lack of "Super Hybrid Engine" on Asus product pages,
1300 * this applies to all "701" models (4G/4G Surf/2G Surf).
1301 *
1302 * So Asus made a deliberate decision not to support it on this model.
1303 * We have several reports that using it can cause the system to hang
1304 *
1305 * The hang has also been reported on a "702" (Model name "8G"?).
1306 *
1307 * We avoid dmi_check_system() / dmi_match(), because they use
1308 * substring matching. We don't want to affect the "701SD"
1309 * and "701SDX" models, because they do support S.H.E.
1310 */
da8ba01d
AJ
1311 if (strcmp(model, "701") == 0 || strcmp(model, "702") == 0) {
1312 eeepc->cpufv_disabled = true;
9f662b20
FK
1313 pr_info("model %s does not officially support setting cpu speed\n",
1314 model);
da8ba01d
AJ
1315 pr_info("cpufv disabled to avoid instability\n");
1316 }
10ae4b56
CC
1317
1318 /*
1319 * Blacklist for wlan hotplug
1320 *
1321 * Eeepc 1005HA doesn't work like others models and don't need the
1322 * hotplug code. In fact, current hotplug code seems to unplug another
1323 * device...
1324 */
ced69c59
AJ
1325 if (strcmp(model, "1005HA") == 0 || strcmp(model, "1201N") == 0 ||
1326 strcmp(model, "1005PE") == 0) {
10ae4b56
CC
1327 eeepc->hotplug_disabled = true;
1328 pr_info("wlan hotplug disabled\n");
1329 }
da8ba01d
AJ
1330}
1331
854c7836 1332static void cmsg_quirk(struct eeepc_laptop *eeepc, int cm, const char *name)
52bbe3c7
AJ
1333{
1334 int dummy;
1335
c8440336 1336 /* Some BIOSes do not report cm although it is available.
52bbe3c7 1337 Check if cm_getv[cm] works and, if yes, assume cm should be set. */
a7624b63
AJ
1338 if (!(eeepc->cm_supported & (1 << cm))
1339 && !read_acpi_int(eeepc->handle, cm_getv[cm], &dummy)) {
9f662b20
FK
1340 pr_info("%s (%x) not reported by BIOS, enabling anyway\n",
1341 name, 1 << cm);
a7624b63 1342 eeepc->cm_supported |= 1 << cm;
52bbe3c7
AJ
1343 }
1344}
1345
854c7836 1346static void cmsg_quirks(struct eeepc_laptop *eeepc)
52bbe3c7 1347{
854c7836
AJ
1348 cmsg_quirk(eeepc, CM_ASL_LID, "LID");
1349 cmsg_quirk(eeepc, CM_ASL_TYPE, "TYPE");
1350 cmsg_quirk(eeepc, CM_ASL_PANELPOWER, "PANELPOWER");
1351 cmsg_quirk(eeepc, CM_ASL_TPD, "TPD");
52bbe3c7
AJ
1352}
1353
b859f159 1354static int eeepc_acpi_init(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1355{
1356 unsigned int init_flags;
e59f8796
EC
1357 int result;
1358
71e687dc 1359 result = acpi_bus_get_status(eeepc->device);
1e779854 1360 if (result)
52bbe3c7 1361 return result;
71e687dc 1362 if (!eeepc->device->status.present) {
52bbe3c7
AJ
1363 pr_err("Hotkey device not present, aborting\n");
1364 return -ENODEV;
1365 }
cede2cb6 1366
52bbe3c7
AJ
1367 init_flags = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
1368 pr_notice("Hotkey init flags 0x%x\n", init_flags);
1369
a7624b63 1370 if (write_acpi_int(eeepc->handle, "INIT", init_flags)) {
52bbe3c7
AJ
1371 pr_err("Hotkey initialization failed\n");
1372 return -ENODEV;
e59f8796 1373 }
52bbe3c7
AJ
1374
1375 /* get control methods supported */
a7624b63 1376 if (read_acpi_int(eeepc->handle, "CMSG", &eeepc->cm_supported)) {
52bbe3c7
AJ
1377 pr_err("Get control methods supported failed\n");
1378 return -ENODEV;
dc56ad9b 1379 }
854c7836 1380 cmsg_quirks(eeepc);
a7624b63 1381 pr_info("Get control methods supported: 0x%x\n", eeepc->cm_supported);
2b56f1c1 1382
3c0eb510
CC
1383 return 0;
1384}
1385
b859f159 1386static void eeepc_enable_camera(struct eeepc_laptop *eeepc)
52bbe3c7
AJ
1387{
1388 /*
1389 * If the following call to set_acpi() fails, it's because there's no
1390 * camera so we can ignore the error.
1391 */
854c7836
AJ
1392 if (get_acpi(eeepc, CM_ASL_CAMERA) == 0)
1393 set_acpi(eeepc, CM_ASL_CAMERA, 1);
52bbe3c7
AJ
1394}
1395
854c7836
AJ
1396static bool eeepc_device_present;
1397
b859f159 1398static int eeepc_acpi_add(struct acpi_device *device)
e59f8796 1399{
854c7836 1400 struct eeepc_laptop *eeepc;
e59f8796
EC
1401 int result;
1402
a7624b63
AJ
1403 pr_notice(EEEPC_LAPTOP_NAME "\n");
1404 eeepc = kzalloc(sizeof(struct eeepc_laptop), GFP_KERNEL);
1405 if (!eeepc)
1e779854 1406 return -ENOMEM;
a7624b63
AJ
1407 eeepc->handle = device->handle;
1408 strcpy(acpi_device_name(device), EEEPC_ACPI_DEVICE_NAME);
1409 strcpy(acpi_device_class(device), EEEPC_ACPI_CLASS);
1410 device->driver_data = eeepc;
71e687dc 1411 eeepc->device = device;
cede2cb6 1412
322a1356
CC
1413 eeepc->hotplug_disabled = hotplug_disabled;
1414
da8ba01d
AJ
1415 eeepc_dmi_check(eeepc);
1416
71e687dc 1417 result = eeepc_acpi_init(eeepc);
e59f8796 1418 if (result)
9db106be 1419 goto fail_platform;
854c7836 1420 eeepc_enable_camera(eeepc);
7de39389 1421
854c7836
AJ
1422 /*
1423 * Register the platform device first. It is used as a parent for the
1424 * sub-devices below.
1425 *
1426 * Note that if there are multiple instances of this ACPI device it
1427 * will bail out, because the platform device is registered with a
1428 * fixed name. Of course it doesn't make sense to have more than one,
1429 * and machine-specific scripts find the fixed name convenient. But
1430 * It's also good for us to exclude multiple instances because both
1431 * our hwmon and our wlan rfkill subdevice use global ACPI objects
1432 * (the EC and the wlan PCI slot respectively).
1433 */
1434 result = eeepc_platform_init(eeepc);
e59f8796 1435 if (result)
9db106be 1436 goto fail_platform;
1ddec2f9
CC
1437
1438 if (!acpi_video_backlight_support()) {
854c7836 1439 result = eeepc_backlight_init(eeepc);
1ddec2f9
CC
1440 if (result)
1441 goto fail_backlight;
39a3e17e 1442 } else {
9db106be 1443 pr_info("Backlight controlled by ACPI video driver\n");
39a3e17e 1444 }
1ddec2f9 1445
854c7836 1446 result = eeepc_input_init(eeepc);
f2a9d5e8
AJ
1447 if (result)
1448 goto fail_input;
1449
854c7836 1450 result = eeepc_hwmon_init(eeepc);
1ddec2f9
CC
1451 if (result)
1452 goto fail_hwmon;
1453
854c7836 1454 result = eeepc_led_init(eeepc);
3c0eb510
CC
1455 if (result)
1456 goto fail_led;
1457
854c7836 1458 result = eeepc_rfkill_init(eeepc);
7de39389
CC
1459 if (result)
1460 goto fail_rfkill;
1461
854c7836 1462 eeepc_device_present = true;
e59f8796 1463 return 0;
1e779854 1464
7de39389 1465fail_rfkill:
854c7836 1466 eeepc_led_exit(eeepc);
3c0eb510 1467fail_led:
1ddec2f9 1468fail_hwmon:
854c7836 1469 eeepc_input_exit(eeepc);
f2a9d5e8 1470fail_input:
854c7836 1471 eeepc_backlight_exit(eeepc);
1ddec2f9 1472fail_backlight:
854c7836 1473 eeepc_platform_exit(eeepc);
9db106be 1474fail_platform:
a7624b63 1475 kfree(eeepc);
1e779854 1476
e59f8796
EC
1477 return result;
1478}
1479
51fac838 1480static int eeepc_acpi_remove(struct acpi_device *device)
1e779854 1481{
854c7836 1482 struct eeepc_laptop *eeepc = acpi_driver_data(device);
1e779854 1483
854c7836
AJ
1484 eeepc_backlight_exit(eeepc);
1485 eeepc_rfkill_exit(eeepc);
1486 eeepc_input_exit(eeepc);
854c7836
AJ
1487 eeepc_led_exit(eeepc);
1488 eeepc_platform_exit(eeepc);
1e779854 1489
a7624b63 1490 kfree(eeepc);
1e779854
AJ
1491 return 0;
1492}
1493
52bbe3c7
AJ
1494
1495static const struct acpi_device_id eeepc_device_ids[] = {
a7624b63 1496 {EEEPC_ACPI_HID, 0},
52bbe3c7
AJ
1497 {"", 0},
1498};
1499MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
1500
a7624b63
AJ
1501static struct acpi_driver eeepc_acpi_driver = {
1502 .name = EEEPC_LAPTOP_NAME,
1503 .class = EEEPC_ACPI_CLASS,
52bbe3c7
AJ
1504 .owner = THIS_MODULE,
1505 .ids = eeepc_device_ids,
1506 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
1507 .ops = {
a7624b63
AJ
1508 .add = eeepc_acpi_add,
1509 .remove = eeepc_acpi_remove,
1510 .notify = eeepc_acpi_notify,
52bbe3c7
AJ
1511 },
1512};
1513
1514
1e779854
AJ
1515static int __init eeepc_laptop_init(void)
1516{
1517 int result;
1518
22072e92 1519 result = platform_driver_register(&platform_driver);
1e779854
AJ
1520 if (result < 0)
1521 return result;
22072e92 1522
a7624b63 1523 result = acpi_bus_register_driver(&eeepc_acpi_driver);
22072e92
AJ
1524 if (result < 0)
1525 goto fail_acpi_driver;
642e0447 1526
854c7836 1527 if (!eeepc_device_present) {
22072e92
AJ
1528 result = -ENODEV;
1529 goto fail_no_device;
1e779854 1530 }
642e0447 1531
1e779854 1532 return 0;
22072e92
AJ
1533
1534fail_no_device:
a7624b63 1535 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92
AJ
1536fail_acpi_driver:
1537 platform_driver_unregister(&platform_driver);
1538 return result;
1e779854
AJ
1539}
1540
1541static void __exit eeepc_laptop_exit(void)
1542{
a7624b63 1543 acpi_bus_unregister_driver(&eeepc_acpi_driver);
22072e92 1544 platform_driver_unregister(&platform_driver);
1e779854
AJ
1545}
1546
e59f8796
EC
1547module_init(eeepc_laptop_init);
1548module_exit(eeepc_laptop_exit);