1 From 4fa6811b8ade1b7839342824939817a8fc751539 Mon Sep 17 00:00:00 2001
2 From: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
3 Date: Sat, 26 Apr 2008 01:02:23 -0300
4 Subject: ACPI: thinkpad-acpi: prepare light and LED for sysfs support
6 Do some preparatory work to add sysfs support to the thinklight and
9 Signed-off-by: Henrique de Moraes Holschuh <hmh@hmh.eng.br>
10 Signed-off-by: Len Brown <len.brown@intel.com>
12 drivers/misc/Kconfig | 2 +
13 drivers/misc/thinkpad_acpi.c | 191 ++++++++++++++++++++++++++++++------------
14 2 files changed, 138 insertions(+), 55 deletions(-)
16 diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
17 index 297a48f..3a5d769 100644
18 --- a/drivers/misc/Kconfig
19 +++ b/drivers/misc/Kconfig
20 @@ -245,6 +245,8 @@ config THINKPAD_ACPI
27 This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
28 support for Fn-Fx key combinations, Bluetooth control, video
29 diff --git a/drivers/misc/thinkpad_acpi.c b/drivers/misc/thinkpad_acpi.c
30 index 2b73dfa..5a3fb09 100644
31 --- a/drivers/misc/thinkpad_acpi.c
32 +++ b/drivers/misc/thinkpad_acpi.c
34 #include <linux/hwmon.h>
35 #include <linux/hwmon-sysfs.h>
36 #include <linux/input.h>
37 +#include <linux/leds.h>
38 #include <asm/uaccess.h>
40 #include <linux/dmi.h>
42 #define TP_CMOS_VOLUME_MUTE 2
43 #define TP_CMOS_BRIGHTNESS_UP 4
44 #define TP_CMOS_BRIGHTNESS_DOWN 5
45 +#define TP_CMOS_THINKLIGHT_ON 12
46 +#define TP_CMOS_THINKLIGHT_OFF 13
50 @@ -269,6 +272,13 @@ static enum {
51 static int experimental;
54 +/* Special LED class that can defer work */
55 +struct tpacpi_led_classdev {
56 + struct led_classdev led_classdev;
57 + struct work_struct work;
58 + enum led_brightness new_brightness;
61 /****************************************************************************
62 ****************************************************************************
64 @@ -3237,6 +3247,39 @@ static struct ibm_struct video_driver_data = {
65 TPACPI_HANDLE(lght, root, "\\LGHT"); /* A21e, A2xm/p, T20-22, X20-21 */
66 TPACPI_HANDLE(ledb, ec, "LEDB"); /* G4x */
68 +static int light_get_status(void)
72 + if (tp_features.light_status) {
73 + if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
81 +static int light_set_status(int status)
85 + if (tp_features.light) {
87 + rc = acpi_evalf(cmos_handle, NULL, NULL, "vd",
89 + TP_CMOS_THINKLIGHT_ON :
90 + TP_CMOS_THINKLIGHT_OFF);
92 + rc = acpi_evalf(lght_handle, NULL, NULL, "vd",
95 + return (rc)? 0 : -EIO;
101 static int __init light_init(struct ibm_init_struct *iibm)
103 vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");
104 @@ -3263,7 +3306,7 @@ static int __init light_init(struct ibm_init_struct *iibm)
105 static int light_read(char *p)
111 if (!tp_features.light) {
112 len += sprintf(p + len, "status:\t\tnot supported\n");
113 @@ -3271,8 +3314,9 @@ static int light_read(char *p)
114 len += sprintf(p + len, "status:\t\tunknown\n");
115 len += sprintf(p + len, "commands:\ton, off\n");
117 - if (!acpi_evalf(ec_handle, &status, "KBLT", "d"))
119 + status = light_get_status();
122 len += sprintf(p + len, "status:\t\t%s\n", onoff(status, 0));
123 len += sprintf(p + len, "commands:\ton, off\n");
125 @@ -3282,31 +3326,22 @@ static int light_read(char *p)
127 static int light_write(char *buf)
129 - int cmos_cmd, lght_cmd;
134 if (!tp_features.light)
137 while ((cmd = next_cmd(&buf))) {
138 if (strlencmp(cmd, "on") == 0) {
142 } else if (strlencmp(cmd, "off") == 0) {
149 - success = cmos_handle ?
150 - acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd) :
151 - acpi_evalf(lght_handle, NULL, NULL, "vd", lght_cmd);
157 + return light_set_status(newstatus);
160 static struct ibm_struct light_driver_data = {
161 @@ -3710,6 +3745,12 @@ enum { /* For TPACPI_LED_OLD */
162 TPACPI_LED_EC_HLMS = 0x0e, /* EC reg to select led to command */
166 + TPACPI_LED_OFF = 0,
171 static enum led_access_mode led_supported;
173 TPACPI_HANDLE(led, ec, "SLED", /* 570 */
174 @@ -3718,6 +3759,69 @@ TPACPI_HANDLE(led, ec, "SLED", /* 570 */
175 "LED", /* all others */
178 +static int led_get_status(unsigned int led)
182 + switch (led_supported) {
183 + case TPACPI_LED_570:
184 + if (!acpi_evalf(ec_handle,
185 + &status, "GLED", "dd", 1 << led))
187 + return (status == 0)?
199 +static int led_set_status(unsigned int led, enum led_status_t ledstatus)
201 + /* off, on, blink. Index is led_status_t */
202 + static const int const led_sled_arg1[] = { 0, 1, 3 };
203 + static const int const led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
204 + static const int const led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
205 + static const int const led_led_arg1[] = { 0, 0x80, 0xc0 };
209 + switch (led_supported) {
210 + case TPACPI_LED_570:
213 + if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
214 + led, led_sled_arg1[ledstatus]))
217 + case TPACPI_LED_OLD:
218 + /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
220 + rc = ec_write(TPACPI_LED_EC_HLMS, led);
222 + rc = ec_write(TPACPI_LED_EC_HLBL,
223 + led * led_exp_hlbl[ledstatus]);
225 + rc = ec_write(TPACPI_LED_EC_HLCL,
226 + led * led_exp_hlcl[ledstatus]);
228 + case TPACPI_LED_NEW:
230 + if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
231 + led, led_led_arg1[ledstatus]))
241 static int __init led_init(struct ibm_init_struct *iibm)
243 vdbg_printk(TPACPI_DBG_INIT, "initializing LED subdriver\n");
244 @@ -3743,7 +3847,9 @@ static int __init led_init(struct ibm_init_struct *iibm)
245 return (led_supported != TPACPI_LED_NONE)? 0 : 1;
248 -#define led_status(s) ((s) == 0 ? "off" : ((s) == 1 ? "on" : "blinking"))
249 +#define str_led_status(s) \
250 + ((s) == TPACPI_LED_OFF ? "off" : \
251 + ((s) == TPACPI_LED_ON ? "on" : "blinking"))
253 static int led_read(char *p)
255 @@ -3759,11 +3865,11 @@ static int led_read(char *p)
258 for (i = 0; i < 8; i++) {
259 - if (!acpi_evalf(ec_handle,
260 - &status, "GLED", "dd", 1 << i))
261 + status = led_get_status(i);
264 len += sprintf(p + len, "%d:\t\t%s\n",
265 - i, led_status(status));
266 + i, str_led_status(status));
270 @@ -3773,16 +3879,11 @@ static int led_read(char *p)
274 -/* off, on, blink */
275 -static const int led_sled_arg1[] = { 0, 1, 3 };
276 -static const int led_exp_hlbl[] = { 0, 0, 1 }; /* led# * */
277 -static const int led_exp_hlcl[] = { 0, 1, 1 }; /* led# * */
278 -static const int led_led_arg1[] = { 0, 0x80, 0xc0 };
280 static int led_write(char *buf)
285 + enum led_status_t s;
289 @@ -3792,38 +3893,18 @@ static int led_write(char *buf)
292 if (strstr(cmd, "off")) {
294 + s = TPACPI_LED_OFF;
295 } else if (strstr(cmd, "on")) {
298 } else if (strstr(cmd, "blink")) {
303 - if (led_supported == TPACPI_LED_570) {
306 - if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
307 - led, led_sled_arg1[ind]))
309 - } else if (led_supported == TPACPI_LED_OLD) {
310 - /* 600e/x, 770e, 770x, A21e, A2xm/p, T20-22, X20 */
312 - ret = ec_write(TPACPI_LED_EC_HLMS, led);
314 - ret = ec_write(TPACPI_LED_EC_HLBL,
315 - led * led_exp_hlbl[ind]);
317 - ret = ec_write(TPACPI_LED_EC_HLCL,
318 - led * led_exp_hlcl[ind]);
321 + s = TPACPI_LED_BLINK;
324 - if (!acpi_evalf(led_handle, NULL, NULL, "vdd",
325 - led, led_led_arg1[ind]))
330 + rc = led_set_status(led, s);