1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Panasonic HotKey and LCD brightness control driver
4 * (C) 2004 Hiroshi Miura <miura@da-cha.org>
5 * (C) 2004 NTT DATA Intellilink Co. http://www.intellilink.co.jp/
6 * (C) YOKOTA Hiroshi <yokota (at) netlab. is. tsukuba. ac. jp>
7 * (C) 2004 David Bronaugh <dbronaugh>
8 * (C) 2006-2008 Harald Welte <laforge@gnumonks.org>
9 *
10 * derived from toshiba_acpi.c, Copyright (C) 2002-2004 John Belmonte
11 *
12 *---------------------------------------------------------------------------
13 *
14 * ChangeLog:
15 * Aug.18, 2020 Kenneth Chan <kenneth.t.chan@gmail.com>
16 * -v0.98 add platform devices for firmware brightness registers
17 * add support for battery charging threshold (eco mode)
18 * resolve hotkey double trigger
19 * add write support to mute
20 * fix sticky_key init bug
21 * fix naming of platform files for consistency with other
22 * modules
23 * split MODULE_AUTHOR() by one author per macro call
24 * replace ACPI prints with pr_*() macros
25 * -v0.97 add support for cdpower hardware switch
26 * -v0.96 merge Lucina's enhancement
27 * Jan.13, 2009 Martin Lucina <mato@kotelna.sk>
28 * - add support for optical driver power in
29 * Y and W series
30 *
31 * Sep.23, 2008 Harald Welte <laforge@gnumonks.org>
32 * -v0.95 rename driver from drivers/acpi/pcc_acpi.c to
33 * drivers/misc/panasonic-laptop.c
34 *
35 * Jul.04, 2008 Harald Welte <laforge@gnumonks.org>
36 * -v0.94 replace /proc interface with device attributes
37 * support {set,get}keycode on th input device
38 *
39 * Jun.27, 2008 Harald Welte <laforge@gnumonks.org>
40 * -v0.92 merge with 2.6.26-rc6 input API changes
41 * remove broken <= 2.6.15 kernel support
42 * resolve all compiler warnings
43 * various coding style fixes (checkpatch.pl)
44 * add support for backlight api
45 * major code restructuring
46 *
47 * Dac.28, 2007 Harald Welte <laforge@gnumonks.org>
48 * -v0.91 merge with 2.6.24-rc6 ACPI changes
49 *
50 * Nov.04, 2006 Hiroshi Miura <miura@da-cha.org>
51 * -v0.9 remove warning about section reference.
52 * remove acpi_os_free
53 * add /proc/acpi/pcc/brightness interface for HAL access
54 * merge dbronaugh's enhancement
55 * Aug.17, 2004 David Bronaugh (dbronaugh)
56 * - Added screen brightness setting interface
57 * Thanks to FreeBSD crew (acpi_panasonic.c)
58 * for the ideas I needed to accomplish it
59 *
60 * May.29, 2006 Hiroshi Miura <miura@da-cha.org>
61 * -v0.8.4 follow to change keyinput structure
62 * thanks Fabian Yamaguchi <fabs@cs.tu-berlin.de>,
63 * Jacob Bower <jacob.bower@ic.ac.uk> and
64 * Hiroshi Yokota for providing solutions.
65 *
66 * Oct.02, 2004 Hiroshi Miura <miura@da-cha.org>
67 * -v0.8.2 merge code of YOKOTA Hiroshi
68 * <yokota@netlab.is.tsukuba.ac.jp>.
69 * Add sticky key mode interface.
70 * Refactoring acpi_pcc_generate_keyinput().
71 *
72 * Sep.15, 2004 Hiroshi Miura <miura@da-cha.org>
73 * -v0.8 Generate key input event on input subsystem.
74 * This is based on yet another driver written by
75 * Ryuta Nakanishi.
76 *
77 * Sep.10, 2004 Hiroshi Miura <miura@da-cha.org>
78 * -v0.7 Change proc interface functions using seq_file
79 * facility as same as other ACPI drivers.
80 *
81 * Aug.28, 2004 Hiroshi Miura <miura@da-cha.org>
82 * -v0.6.4 Fix a silly error with status checking
83 *
84 * Aug.25, 2004 Hiroshi Miura <miura@da-cha.org>
85 * -v0.6.3 replace read_acpi_int by standard function
86 * acpi_evaluate_integer
87 * some clean up and make smart copyright notice.
88 * fix return value of pcc_acpi_get_key()
89 * fix checking return value of acpi_bus_register_driver()
90 *
91 * Aug.22, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
92 * -v0.6.2 Add check on ACPI data (num_sifr)
93 * Coding style cleanups, better error messages/handling
94 * Fixed an off-by-one error in memory allocation
95 *
96 * Aug.21, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
97 * -v0.6.1 Fix a silly error with status checking
98 *
99 * Aug.20, 2004 David Bronaugh <dbronaugh@linuxboxen.org>
100 * - v0.6 Correct brightness controls to reflect reality
101 * based on information gleaned by Hiroshi Miura
102 * and discussions with Hiroshi Miura
103 *
104 * Aug.10, 2004 Hiroshi Miura <miura@da-cha.org>
105 * - v0.5 support LCD brightness control
106 * based on the disclosed information by MEI.
107 *
108 * Jul.25, 2004 Hiroshi Miura <miura@da-cha.org>
109 * - v0.4 first post version
110 * add function to retrive SIFR
111 *
112 * Jul.24, 2004 Hiroshi Miura <miura@da-cha.org>
113 * - v0.3 get proper status of hotkey
114 *
115 * Jul.22, 2004 Hiroshi Miura <miura@da-cha.org>
116 * - v0.2 add HotKey handler
117 *
118 * Jul.17, 2004 Hiroshi Miura <miura@da-cha.org>
119 * - v0.1 start from toshiba_acpi driver written by John Belmonte
120 */
121
122 #include <linux/acpi.h>
123 #include <linux/backlight.h>
124 #include <linux/bits.h>
125 #include <linux/ctype.h>
126 #include <linux/i8042.h>
127 #include <linux/init.h>
128 #include <linux/input.h>
129 #include <linux/input/sparse-keymap.h>
130 #include <linux/kernel.h>
131 #include <linux/module.h>
132 #include <linux/platform_device.h>
133 #include <linux/seq_file.h>
134 #include <linux/serio.h>
135 #include <linux/slab.h>
136 #include <linux/types.h>
137 #include <linux/uaccess.h>
138 #include <acpi/video.h>
139
140 MODULE_AUTHOR("Hiroshi Miura <miura@da-cha.org>");
141 MODULE_AUTHOR("David Bronaugh <dbronaugh@linuxboxen.org>");
142 MODULE_AUTHOR("Harald Welte <laforge@gnumonks.org>");
143 MODULE_AUTHOR("Martin Lucina <mato@kotelna.sk>");
144 MODULE_AUTHOR("Kenneth Chan <kenneth.t.chan@gmail.com>");
145 MODULE_DESCRIPTION("ACPI HotKey driver for Panasonic Let's Note laptops");
146 MODULE_LICENSE("GPL");
147
148 #define LOGPREFIX "pcc_acpi: "
149
150 /* Define ACPI PATHs */
151 /* Lets note hotkeys */
152 #define METHOD_HKEY_QUERY "HINF"
153 #define METHOD_HKEY_SQTY "SQTY"
154 #define METHOD_HKEY_SINF "SINF"
155 #define METHOD_HKEY_SSET "SSET"
156 #define METHOD_ECWR "\\_SB.ECWR"
157 #define HKEY_NOTIFY 0x80
158 #define ECO_MODE_OFF 0x00
159 #define ECO_MODE_ON 0x80
160
161 #define ACPI_PCC_DRIVER_NAME "Panasonic Laptop Support"
162 #define ACPI_PCC_DEVICE_NAME "Hotkey"
163 #define ACPI_PCC_CLASS "pcc"
164
165 #define ACPI_PCC_INPUT_PHYS "panasonic/hkey0"
166
167 /* LCD_TYPEs: 0 = Normal, 1 = Semi-transparent
168 ECO_MODEs: 0x03 = off, 0x83 = on
169 */
170 enum SINF_BITS { SINF_NUM_BATTERIES = 0,
171 SINF_LCD_TYPE,
172 SINF_AC_MAX_BRIGHT,
173 SINF_AC_MIN_BRIGHT,
174 SINF_AC_CUR_BRIGHT,
175 SINF_DC_MAX_BRIGHT,
176 SINF_DC_MIN_BRIGHT,
177 SINF_DC_CUR_BRIGHT,
178 SINF_MUTE,
179 SINF_RESERVED,
180 SINF_ECO_MODE = 0x0A,
181 SINF_CUR_BRIGHT = 0x0D,
182 SINF_STICKY_KEY = 0x80,
183 };
184 /* R1 handles SINF_AC_CUR_BRIGHT as SINF_CUR_BRIGHT, doesn't know AC state */
185
186 static int acpi_pcc_hotkey_probe(struct platform_device *pdev);
187 static void acpi_pcc_hotkey_remove(struct platform_device *pdev);
188 static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data);
189
190 static const struct acpi_device_id pcc_device_ids[] = {
191 { "MAT0012", 0},
192 { "MAT0013", 0},
193 { "MAT0018", 0},
194 { "MAT0019", 0},
195 { "", 0},
196 };
197 MODULE_DEVICE_TABLE(acpi, pcc_device_ids);
198
199 #ifdef CONFIG_PM_SLEEP
200 static int acpi_pcc_hotkey_resume(struct device *dev);
201 #endif
202 static SIMPLE_DEV_PM_OPS(acpi_pcc_hotkey_pm, NULL, acpi_pcc_hotkey_resume);
203
204 static struct platform_driver acpi_pcc_driver = {
205 .probe = acpi_pcc_hotkey_probe,
206 .remove = acpi_pcc_hotkey_remove,
207 .driver = {
208 .name = ACPI_PCC_DRIVER_NAME,
209 .acpi_match_table = pcc_device_ids,
210 .pm = &acpi_pcc_hotkey_pm,
211 },
212 };
213
214 static const struct key_entry panasonic_keymap[] = {
215 { KE_KEY, 0, { KEY_RESERVED } },
216 { KE_KEY, 1, { KEY_BRIGHTNESSDOWN } },
217 { KE_KEY, 2, { KEY_BRIGHTNESSUP } },
218 { KE_KEY, 3, { KEY_DISPLAYTOGGLE } },
219 { KE_KEY, 4, { KEY_MUTE } },
220 { KE_KEY, 5, { KEY_VOLUMEDOWN } },
221 { KE_KEY, 6, { KEY_VOLUMEUP } },
222 { KE_KEY, 7, { KEY_SLEEP } },
223 { KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
224 { KE_KEY, 9, { KEY_BATTERY } },
225 { KE_KEY, 10, { KEY_SUSPEND } },
226 { KE_KEY, 21, { KEY_MACRO1 } },
227 { KE_KEY, 22, { KEY_MACRO2 } },
228 { KE_KEY, 24, { KEY_MACRO3 } },
229 { KE_KEY, 25, { KEY_MACRO4 } },
230 { KE_KEY, 34, { KEY_MACRO5 } },
231 { KE_KEY, 35, { KEY_MACRO6 } },
232 { KE_KEY, 36, { KEY_MACRO7 } },
233 { KE_KEY, 37, { KEY_MACRO8 } },
234 { KE_KEY, 41, { KEY_MACRO9 } },
235 { KE_KEY, 42, { KEY_MACRO10 } },
236 { KE_KEY, 43, { KEY_MACRO11 } },
237 { KE_END, 0 }
238 };
239
240 struct pcc_acpi {
241 acpi_handle handle;
242 unsigned long num_sifr;
243 int sticky_key;
244 int eco_mode;
245 int mute;
246 int ac_brightness;
247 int dc_brightness;
248 int current_brightness;
249 u32 *sinf;
250 struct acpi_device *device;
251 struct input_dev *input_dev;
252 struct backlight_device *backlight;
253 struct platform_device *platform;
254 };
255
256 /*
257 * On some Panasonic models the volume up / down / mute keys send duplicate
258 * keypress events over the PS/2 kbd interface, filter these out.
259 */
panasonic_i8042_filter(unsigned char data,unsigned char str,struct serio * port,void * context)260 static bool panasonic_i8042_filter(unsigned char data, unsigned char str,
261 struct serio *port, void *context)
262 {
263 static bool extended;
264
265 if (str & I8042_STR_AUXDATA)
266 return false;
267
268 if (data == 0xe0) {
269 extended = true;
270 return true;
271 } else if (extended) {
272 extended = false;
273
274 switch (data & 0x7f) {
275 case 0x20: /* e0 20 / e0 a0, Volume Mute press / release */
276 case 0x2e: /* e0 2e / e0 ae, Volume Down press / release */
277 case 0x30: /* e0 30 / e0 b0, Volume Up press / release */
278 return true;
279 default:
280 /*
281 * Report the previously filtered e0 before continuing
282 * with the next non-filtered byte.
283 */
284 serio_interrupt(port, 0xe0, 0);
285 return false;
286 }
287 }
288
289 return false;
290 }
291
292 /* method access functions */
acpi_pcc_write_sset(struct pcc_acpi * pcc,int func,int val)293 static int acpi_pcc_write_sset(struct pcc_acpi *pcc, int func, int val)
294 {
295 union acpi_object in_objs[] = {
296 { .integer.type = ACPI_TYPE_INTEGER,
297 .integer.value = func, },
298 { .integer.type = ACPI_TYPE_INTEGER,
299 .integer.value = val, },
300 };
301 struct acpi_object_list params = {
302 .count = ARRAY_SIZE(in_objs),
303 .pointer = in_objs,
304 };
305 acpi_status status = AE_OK;
306
307 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SSET,
308 ¶ms, NULL);
309
310 return (status == AE_OK) ? 0 : -EIO;
311 }
312
acpi_pcc_get_sqty(struct acpi_device * device)313 static inline int acpi_pcc_get_sqty(struct acpi_device *device)
314 {
315 unsigned long long s;
316 acpi_status status;
317
318 status = acpi_evaluate_integer(device->handle, METHOD_HKEY_SQTY,
319 NULL, &s);
320 if (ACPI_SUCCESS(status))
321 return s;
322 else {
323 pr_err("evaluation error HKEY.SQTY\n");
324 return -EINVAL;
325 }
326 }
327
acpi_pcc_retrieve_biosdata(struct pcc_acpi * pcc)328 static int acpi_pcc_retrieve_biosdata(struct pcc_acpi *pcc)
329 {
330 acpi_status status;
331 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
332 union acpi_object *hkey = NULL;
333 int i;
334
335 status = acpi_evaluate_object(pcc->handle, METHOD_HKEY_SINF, NULL,
336 &buffer);
337 if (ACPI_FAILURE(status)) {
338 pr_err("evaluation error HKEY.SINF\n");
339 return 0;
340 }
341
342 hkey = buffer.pointer;
343 if (!hkey || (hkey->type != ACPI_TYPE_PACKAGE)) {
344 pr_err("Invalid HKEY.SINF\n");
345 status = AE_ERROR;
346 goto end;
347 }
348
349 if (pcc->num_sifr < hkey->package.count) {
350 pr_err("SQTY reports bad SINF length SQTY: %lu SINF-pkg-count: %u\n",
351 pcc->num_sifr, hkey->package.count);
352 status = AE_ERROR;
353 goto end;
354 }
355
356 for (i = 0; i < hkey->package.count; i++) {
357 union acpi_object *element = &(hkey->package.elements[i]);
358 if (likely(element->type == ACPI_TYPE_INTEGER)) {
359 pcc->sinf[i] = element->integer.value;
360 } else
361 pr_err("Invalid HKEY.SINF data\n");
362 }
363 pcc->sinf[hkey->package.count] = -1;
364
365 end:
366 kfree(buffer.pointer);
367 return status == AE_OK;
368 }
369
370 /* backlight API interface functions */
371
372 /* This driver currently treats AC and DC brightness identical,
373 * since we don't need to invent an interface to the core ACPI
374 * logic to receive events in case a power supply is plugged in
375 * or removed */
376
bl_get(struct backlight_device * bd)377 static int bl_get(struct backlight_device *bd)
378 {
379 struct pcc_acpi *pcc = bl_get_data(bd);
380
381 if (!acpi_pcc_retrieve_biosdata(pcc))
382 return -EIO;
383
384 return pcc->sinf[SINF_AC_CUR_BRIGHT];
385 }
386
bl_set_status(struct backlight_device * bd)387 static int bl_set_status(struct backlight_device *bd)
388 {
389 struct pcc_acpi *pcc = bl_get_data(bd);
390 int bright = bd->props.brightness;
391 int rc;
392
393 if (!acpi_pcc_retrieve_biosdata(pcc))
394 return -EIO;
395
396 if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT])
397 bright = pcc->sinf[SINF_AC_MIN_BRIGHT];
398
399 if (bright < pcc->sinf[SINF_DC_MIN_BRIGHT])
400 bright = pcc->sinf[SINF_DC_MIN_BRIGHT];
401
402 if (bright < pcc->sinf[SINF_AC_MIN_BRIGHT] ||
403 bright > pcc->sinf[SINF_AC_MAX_BRIGHT])
404 return -EINVAL;
405
406 rc = acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, bright);
407 if (rc < 0)
408 return rc;
409
410 return acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, bright);
411 }
412
413 static const struct backlight_ops pcc_backlight_ops = {
414 .get_brightness = bl_get,
415 .update_status = bl_set_status,
416 };
417
418
419 /* returns ACPI_SUCCESS if methods to control optical drive are present */
420
check_optd_present(void)421 static acpi_status check_optd_present(void)
422 {
423 acpi_status status = AE_OK;
424 acpi_handle handle;
425
426 status = acpi_get_handle(NULL, "\\_SB.STAT", &handle);
427 if (ACPI_FAILURE(status))
428 goto out;
429 status = acpi_get_handle(NULL, "\\_SB.FBAY", &handle);
430 if (ACPI_FAILURE(status))
431 goto out;
432 status = acpi_get_handle(NULL, "\\_SB.CDDI", &handle);
433 if (ACPI_FAILURE(status))
434 goto out;
435
436 out:
437 return status;
438 }
439
440 /* get optical driver power state */
441
get_optd_power_state(void)442 static int get_optd_power_state(void)
443 {
444 acpi_status status;
445 unsigned long long state;
446 int result;
447
448 status = acpi_evaluate_integer(NULL, "\\_SB.STAT", NULL, &state);
449 if (ACPI_FAILURE(status)) {
450 pr_err("evaluation error _SB.STAT\n");
451 result = -EIO;
452 goto out;
453 }
454 switch (state) {
455 case 0: /* power off */
456 result = 0;
457 break;
458 case 0x0f: /* power on */
459 result = 1;
460 break;
461 default:
462 result = -EIO;
463 break;
464 }
465
466 out:
467 return result;
468 }
469
470 /* set optical drive power state */
471
set_optd_power_state(int new_state)472 static int set_optd_power_state(int new_state)
473 {
474 int result;
475 acpi_status status;
476
477 result = get_optd_power_state();
478 if (result < 0)
479 goto out;
480 if (new_state == result)
481 goto out;
482
483 switch (new_state) {
484 case 0: /* power off */
485 /* Call CDDR instead, since they both call the same method
486 * while CDDI takes 1 arg and we are not quite sure what it is.
487 */
488 status = acpi_evaluate_object(NULL, "\\_SB.CDDR", NULL, NULL);
489 if (ACPI_FAILURE(status)) {
490 pr_err("evaluation error _SB.CDDR\n");
491 result = -EIO;
492 }
493 break;
494 case 1: /* power on */
495 status = acpi_evaluate_object(NULL, "\\_SB.FBAY", NULL, NULL);
496 if (ACPI_FAILURE(status)) {
497 pr_err("evaluation error _SB.FBAY\n");
498 result = -EIO;
499 }
500 break;
501 default:
502 result = -EINVAL;
503 break;
504 }
505
506 out:
507 return result;
508 }
509
510
511 /* sysfs user interface functions */
512
numbatt_show(struct device * dev,struct device_attribute * attr,char * buf)513 static ssize_t numbatt_show(struct device *dev, struct device_attribute *attr,
514 char *buf)
515 {
516 struct acpi_device *acpi = to_acpi_device(dev);
517 struct pcc_acpi *pcc = acpi_driver_data(acpi);
518
519 if (!acpi_pcc_retrieve_biosdata(pcc))
520 return -EIO;
521
522 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_NUM_BATTERIES]);
523 }
524
lcdtype_show(struct device * dev,struct device_attribute * attr,char * buf)525 static ssize_t lcdtype_show(struct device *dev, struct device_attribute *attr,
526 char *buf)
527 {
528 struct acpi_device *acpi = to_acpi_device(dev);
529 struct pcc_acpi *pcc = acpi_driver_data(acpi);
530
531 if (!acpi_pcc_retrieve_biosdata(pcc))
532 return -EIO;
533
534 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_LCD_TYPE]);
535 }
536
mute_show(struct device * dev,struct device_attribute * attr,char * buf)537 static ssize_t mute_show(struct device *dev, struct device_attribute *attr,
538 char *buf)
539 {
540 struct acpi_device *acpi = to_acpi_device(dev);
541 struct pcc_acpi *pcc = acpi_driver_data(acpi);
542
543 if (!acpi_pcc_retrieve_biosdata(pcc))
544 return -EIO;
545
546 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_MUTE]);
547 }
548
mute_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)549 static ssize_t mute_store(struct device *dev, struct device_attribute *attr,
550 const char *buf, size_t count)
551 {
552 struct acpi_device *acpi = to_acpi_device(dev);
553 struct pcc_acpi *pcc = acpi_driver_data(acpi);
554 int err, val;
555
556 err = kstrtoint(buf, 0, &val);
557 if (err)
558 return err;
559 if (val == 0 || val == 1) {
560 acpi_pcc_write_sset(pcc, SINF_MUTE, val);
561 pcc->mute = val;
562 }
563
564 return count;
565 }
566
sticky_key_show(struct device * dev,struct device_attribute * attr,char * buf)567 static ssize_t sticky_key_show(struct device *dev, struct device_attribute *attr,
568 char *buf)
569 {
570 struct acpi_device *acpi = to_acpi_device(dev);
571 struct pcc_acpi *pcc = acpi_driver_data(acpi);
572
573 if (!acpi_pcc_retrieve_biosdata(pcc))
574 return -EIO;
575
576 return sysfs_emit(buf, "%u\n", pcc->sticky_key);
577 }
578
sticky_key_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)579 static ssize_t sticky_key_store(struct device *dev, struct device_attribute *attr,
580 const char *buf, size_t count)
581 {
582 struct acpi_device *acpi = to_acpi_device(dev);
583 struct pcc_acpi *pcc = acpi_driver_data(acpi);
584 int err, val;
585
586 err = kstrtoint(buf, 0, &val);
587 if (err)
588 return err;
589 if (val == 0 || val == 1) {
590 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, val);
591 pcc->sticky_key = val;
592 }
593
594 return count;
595 }
596
eco_mode_show(struct device * dev,struct device_attribute * attr,char * buf)597 static ssize_t eco_mode_show(struct device *dev, struct device_attribute *attr,
598 char *buf)
599 {
600 struct acpi_device *acpi = to_acpi_device(dev);
601 struct pcc_acpi *pcc = acpi_driver_data(acpi);
602 int result;
603
604 if (!acpi_pcc_retrieve_biosdata(pcc))
605 return -EIO;
606
607 switch (pcc->sinf[SINF_ECO_MODE]) {
608 case (ECO_MODE_OFF + 3):
609 result = 0;
610 break;
611 case (ECO_MODE_ON + 3):
612 result = 1;
613 break;
614 default:
615 return -EIO;
616 }
617 return sysfs_emit(buf, "%u\n", result);
618 }
619
eco_mode_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)620 static ssize_t eco_mode_store(struct device *dev, struct device_attribute *attr,
621 const char *buf, size_t count)
622 {
623 struct acpi_device *acpi = to_acpi_device(dev);
624 struct pcc_acpi *pcc = acpi_driver_data(acpi);
625 int err, state;
626
627 union acpi_object param[2];
628 struct acpi_object_list input;
629 acpi_status status;
630
631 param[0].type = ACPI_TYPE_INTEGER;
632 param[0].integer.value = 0x15;
633 param[1].type = ACPI_TYPE_INTEGER;
634 input.count = 2;
635 input.pointer = param;
636
637 err = kstrtoint(buf, 0, &state);
638 if (err)
639 return err;
640
641 switch (state) {
642 case 0:
643 param[1].integer.value = ECO_MODE_OFF;
644 pcc->sinf[SINF_ECO_MODE] = 0;
645 pcc->eco_mode = 0;
646 break;
647 case 1:
648 param[1].integer.value = ECO_MODE_ON;
649 pcc->sinf[SINF_ECO_MODE] = 1;
650 pcc->eco_mode = 1;
651 break;
652 default:
653 /* nothing to do */
654 return count;
655 }
656
657 status = acpi_evaluate_object(NULL, METHOD_ECWR,
658 &input, NULL);
659 if (ACPI_FAILURE(status)) {
660 pr_err("%s evaluation failed\n", METHOD_ECWR);
661 return -EINVAL;
662 }
663
664 return count;
665 }
666
ac_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)667 static ssize_t ac_brightness_show(struct device *dev, struct device_attribute *attr,
668 char *buf)
669 {
670 struct acpi_device *acpi = to_acpi_device(dev);
671 struct pcc_acpi *pcc = acpi_driver_data(acpi);
672
673 if (!acpi_pcc_retrieve_biosdata(pcc))
674 return -EIO;
675
676 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_AC_CUR_BRIGHT]);
677 }
678
ac_brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)679 static ssize_t ac_brightness_store(struct device *dev, struct device_attribute *attr,
680 const char *buf, size_t count)
681 {
682 struct acpi_device *acpi = to_acpi_device(dev);
683 struct pcc_acpi *pcc = acpi_driver_data(acpi);
684 int err, val;
685
686 err = kstrtoint(buf, 0, &val);
687 if (err)
688 return err;
689 if (val >= 0 && val <= 255) {
690 acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, val);
691 pcc->ac_brightness = val;
692 }
693
694 return count;
695 }
696
dc_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)697 static ssize_t dc_brightness_show(struct device *dev, struct device_attribute *attr,
698 char *buf)
699 {
700 struct acpi_device *acpi = to_acpi_device(dev);
701 struct pcc_acpi *pcc = acpi_driver_data(acpi);
702
703 if (!acpi_pcc_retrieve_biosdata(pcc))
704 return -EIO;
705
706 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_DC_CUR_BRIGHT]);
707 }
708
dc_brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)709 static ssize_t dc_brightness_store(struct device *dev, struct device_attribute *attr,
710 const char *buf, size_t count)
711 {
712 struct acpi_device *acpi = to_acpi_device(dev);
713 struct pcc_acpi *pcc = acpi_driver_data(acpi);
714 int err, val;
715
716 err = kstrtoint(buf, 0, &val);
717 if (err)
718 return err;
719 if (val >= 0 && val <= 255) {
720 acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, val);
721 pcc->dc_brightness = val;
722 }
723
724 return count;
725 }
726
current_brightness_show(struct device * dev,struct device_attribute * attr,char * buf)727 static ssize_t current_brightness_show(struct device *dev, struct device_attribute *attr,
728 char *buf)
729 {
730 struct acpi_device *acpi = to_acpi_device(dev);
731 struct pcc_acpi *pcc = acpi_driver_data(acpi);
732
733 if (!acpi_pcc_retrieve_biosdata(pcc))
734 return -EIO;
735
736 return sysfs_emit(buf, "%u\n", pcc->sinf[SINF_CUR_BRIGHT]);
737 }
738
current_brightness_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)739 static ssize_t current_brightness_store(struct device *dev, struct device_attribute *attr,
740 const char *buf, size_t count)
741 {
742 struct acpi_device *acpi = to_acpi_device(dev);
743 struct pcc_acpi *pcc = acpi_driver_data(acpi);
744 int err, val;
745
746 err = kstrtoint(buf, 0, &val);
747 if (err)
748 return err;
749
750 if (val >= 0 && val <= 255) {
751 err = acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, val);
752 pcc->current_brightness = val;
753 }
754
755 return count;
756 }
757
cdpower_show(struct device * dev,struct device_attribute * attr,char * buf)758 static ssize_t cdpower_show(struct device *dev, struct device_attribute *attr,
759 char *buf)
760 {
761 int state = get_optd_power_state();
762
763 if (state < 0)
764 return state;
765
766 return sysfs_emit(buf, "%d\n", state);
767 }
768
cdpower_store(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)769 static ssize_t cdpower_store(struct device *dev, struct device_attribute *attr,
770 const char *buf, size_t count)
771 {
772 int err, val;
773
774 err = kstrtoint(buf, 10, &val);
775 if (err)
776 return err;
777 set_optd_power_state(val);
778 return count;
779 }
780
781 static DEVICE_ATTR_RO(numbatt);
782 static DEVICE_ATTR_RO(lcdtype);
783 static DEVICE_ATTR_RW(mute);
784 static DEVICE_ATTR_RW(sticky_key);
785 static DEVICE_ATTR_RW(eco_mode);
786 static DEVICE_ATTR_RW(ac_brightness);
787 static DEVICE_ATTR_RW(dc_brightness);
788 static DEVICE_ATTR_RW(current_brightness);
789 static DEVICE_ATTR_RW(cdpower);
790
pcc_sysfs_is_visible(struct kobject * kobj,struct attribute * attr,int idx)791 static umode_t pcc_sysfs_is_visible(struct kobject *kobj, struct attribute *attr, int idx)
792 {
793 struct device *dev = kobj_to_dev(kobj);
794 struct acpi_device *acpi = to_acpi_device(dev);
795 struct pcc_acpi *pcc = acpi_driver_data(acpi);
796
797 if (attr == &dev_attr_mute.attr)
798 return (pcc->num_sifr > SINF_MUTE) ? attr->mode : 0;
799
800 if (attr == &dev_attr_eco_mode.attr)
801 return (pcc->num_sifr > SINF_ECO_MODE) ? attr->mode : 0;
802
803 if (attr == &dev_attr_current_brightness.attr)
804 return (pcc->num_sifr > SINF_CUR_BRIGHT) ? attr->mode : 0;
805
806 return attr->mode;
807 }
808
809 static struct attribute *pcc_sysfs_entries[] = {
810 &dev_attr_numbatt.attr,
811 &dev_attr_lcdtype.attr,
812 &dev_attr_mute.attr,
813 &dev_attr_sticky_key.attr,
814 &dev_attr_eco_mode.attr,
815 &dev_attr_ac_brightness.attr,
816 &dev_attr_dc_brightness.attr,
817 &dev_attr_current_brightness.attr,
818 &dev_attr_cdpower.attr,
819 NULL,
820 };
821
822 static const struct attribute_group pcc_attr_group = {
823 .name = NULL, /* put in device directory */
824 .attrs = pcc_sysfs_entries,
825 .is_visible = pcc_sysfs_is_visible,
826 };
827
828
829 /* hotkey input device driver */
830
831 static int sleep_keydown_seen;
acpi_pcc_generate_keyinput(struct pcc_acpi * pcc)832 static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
833 {
834 struct input_dev *hotk_input_dev = pcc->input_dev;
835 int rc;
836 unsigned long long result;
837 unsigned int key;
838 unsigned int updown;
839
840 rc = acpi_evaluate_integer(pcc->handle, METHOD_HKEY_QUERY,
841 NULL, &result);
842 if (ACPI_FAILURE(rc)) {
843 pr_err("error getting hotkey status\n");
844 return;
845 }
846
847 key = result & GENMASK(6, 0);
848 updown = result & BIT(7); /* 0x80 == key down; 0x00 = key up */
849
850 /* hack: some firmware sends no key down for sleep / hibernate */
851 if (key == 7 || key == 10) {
852 if (updown)
853 sleep_keydown_seen = 1;
854 if (!sleep_keydown_seen)
855 sparse_keymap_report_event(hotk_input_dev,
856 key, 0x80, false);
857 }
858
859 /*
860 * Don't report brightness key-presses if they are also reported
861 * by the ACPI video bus.
862 */
863 if ((key == 1 || key == 2) && acpi_video_handles_brightness_key_presses())
864 return;
865
866 if (!sparse_keymap_report_event(hotk_input_dev, key, updown, false))
867 pr_err("Unknown hotkey event: 0x%04llx\n", result);
868 }
869
acpi_pcc_hotkey_notify(acpi_handle handle,u32 event,void * data)870 static void acpi_pcc_hotkey_notify(acpi_handle handle, u32 event, void *data)
871 {
872 struct pcc_acpi *pcc = data;
873
874 switch (event) {
875 case HKEY_NOTIFY:
876 acpi_pcc_generate_keyinput(pcc);
877 break;
878 default:
879 /* nothing to do */
880 break;
881 }
882 }
883
pcc_optd_notify(acpi_handle handle,u32 event,void * data)884 static void pcc_optd_notify(acpi_handle handle, u32 event, void *data)
885 {
886 if (event != ACPI_NOTIFY_EJECT_REQUEST)
887 return;
888
889 set_optd_power_state(0);
890 }
891
pcc_register_optd_notifier(struct pcc_acpi * pcc,char * node)892 static void pcc_register_optd_notifier(struct pcc_acpi *pcc, char *node)
893 {
894 acpi_status status;
895 acpi_handle handle;
896
897 status = acpi_get_handle(NULL, node, &handle);
898
899 if (ACPI_SUCCESS(status)) {
900 status = acpi_install_notify_handler(handle,
901 ACPI_SYSTEM_NOTIFY,
902 pcc_optd_notify, pcc);
903 if (ACPI_FAILURE(status))
904 pr_err("Failed to register notify on %s\n", node);
905 }
906 }
907
pcc_unregister_optd_notifier(struct pcc_acpi * pcc,char * node)908 static void pcc_unregister_optd_notifier(struct pcc_acpi *pcc, char *node)
909 {
910 acpi_status status = AE_OK;
911 acpi_handle handle;
912
913 status = acpi_get_handle(NULL, node, &handle);
914
915 if (ACPI_SUCCESS(status)) {
916 status = acpi_remove_notify_handler(handle,
917 ACPI_SYSTEM_NOTIFY,
918 pcc_optd_notify);
919 if (ACPI_FAILURE(status))
920 pr_err("Error removing optd notify handler %s\n",
921 node);
922 }
923 }
924
acpi_pcc_init_input(struct pcc_acpi * pcc)925 static int acpi_pcc_init_input(struct pcc_acpi *pcc)
926 {
927 struct input_dev *input_dev;
928 int error;
929
930 input_dev = input_allocate_device();
931 if (!input_dev)
932 return -ENOMEM;
933
934 input_dev->name = ACPI_PCC_DRIVER_NAME;
935 input_dev->phys = ACPI_PCC_INPUT_PHYS;
936 input_dev->id.bustype = BUS_HOST;
937 input_dev->id.vendor = 0x0001;
938 input_dev->id.product = 0x0001;
939 input_dev->id.version = 0x0100;
940
941 error = sparse_keymap_setup(input_dev, panasonic_keymap, NULL);
942 if (error) {
943 pr_err("Unable to setup input device keymap\n");
944 goto err_free_dev;
945 }
946
947 error = input_register_device(input_dev);
948 if (error) {
949 pr_err("Unable to register input device\n");
950 goto err_free_dev;
951 }
952
953 pcc->input_dev = input_dev;
954 return 0;
955
956 err_free_dev:
957 input_free_device(input_dev);
958 return error;
959 }
960
961 /* kernel module interface */
962
963 #ifdef CONFIG_PM_SLEEP
acpi_pcc_hotkey_resume(struct device * dev)964 static int acpi_pcc_hotkey_resume(struct device *dev)
965 {
966 struct pcc_acpi *pcc = acpi_driver_data(ACPI_COMPANION(dev));
967
968 if (pcc->num_sifr > SINF_MUTE)
969 acpi_pcc_write_sset(pcc, SINF_MUTE, pcc->mute);
970 if (pcc->num_sifr > SINF_ECO_MODE)
971 acpi_pcc_write_sset(pcc, SINF_ECO_MODE, pcc->eco_mode);
972 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, pcc->sticky_key);
973 acpi_pcc_write_sset(pcc, SINF_AC_CUR_BRIGHT, pcc->ac_brightness);
974 acpi_pcc_write_sset(pcc, SINF_DC_CUR_BRIGHT, pcc->dc_brightness);
975 if (pcc->num_sifr > SINF_CUR_BRIGHT)
976 acpi_pcc_write_sset(pcc, SINF_CUR_BRIGHT, pcc->current_brightness);
977
978 return 0;
979 }
980 #endif
981
acpi_pcc_hotkey_probe(struct platform_device * pdev)982 static int acpi_pcc_hotkey_probe(struct platform_device *pdev)
983 {
984 struct backlight_properties props;
985 struct acpi_device *device;
986 struct pcc_acpi *pcc;
987 int num_sifr, result;
988
989 device = ACPI_COMPANION(&pdev->dev);
990 if (!device)
991 return -ENODEV;
992
993 num_sifr = acpi_pcc_get_sqty(device);
994
995 /*
996 * pcc->sinf is expected to at least have the AC+DC brightness entries.
997 * Accesses to higher SINF entries are checked against num_sifr.
998 */
999 if (num_sifr <= SINF_DC_CUR_BRIGHT || num_sifr > 255) {
1000 pr_err("num_sifr %d out of range %d - 255\n", num_sifr, SINF_DC_CUR_BRIGHT + 1);
1001 return -ENODEV;
1002 }
1003
1004 /*
1005 * Some DSDT-s have an off-by-one bug where the SINF package count is
1006 * one higher than the SQTY reported value, allocate 1 entry extra.
1007 */
1008 num_sifr++;
1009
1010 pcc = kzalloc_obj(struct pcc_acpi);
1011 if (!pcc) {
1012 pr_err("Couldn't allocate mem for pcc");
1013 return -ENOMEM;
1014 }
1015
1016 pcc->sinf = kcalloc(num_sifr + 1, sizeof(u32), GFP_KERNEL);
1017 if (!pcc->sinf) {
1018 result = -ENOMEM;
1019 goto out_hotkey;
1020 }
1021
1022 pcc->device = device;
1023 pcc->handle = device->handle;
1024 pcc->num_sifr = num_sifr;
1025 device->driver_data = pcc;
1026 strscpy(acpi_device_name(device), ACPI_PCC_DEVICE_NAME);
1027 strscpy(acpi_device_class(device), ACPI_PCC_CLASS);
1028
1029 result = acpi_pcc_init_input(pcc);
1030 if (result) {
1031 pr_err("Error installing keyinput handler\n");
1032 goto out_sinf;
1033 }
1034
1035 if (!acpi_pcc_retrieve_biosdata(pcc)) {
1036 result = -EIO;
1037 pr_err("Couldn't retrieve BIOS data\n");
1038 goto out_input;
1039 }
1040
1041 if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
1042 /* initialize backlight */
1043 memset(&props, 0, sizeof(struct backlight_properties));
1044 props.type = BACKLIGHT_PLATFORM;
1045 props.max_brightness = pcc->sinf[SINF_AC_MAX_BRIGHT];
1046
1047 pcc->backlight = backlight_device_register("panasonic", NULL, pcc,
1048 &pcc_backlight_ops, &props);
1049 if (IS_ERR(pcc->backlight)) {
1050 result = PTR_ERR(pcc->backlight);
1051 goto out_input;
1052 }
1053
1054 /* read the initial brightness setting from the hardware */
1055 pcc->backlight->props.brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1056 }
1057
1058 /* Reset initial sticky key mode since the hardware register state is not consistent */
1059 acpi_pcc_write_sset(pcc, SINF_STICKY_KEY, 0);
1060 pcc->sticky_key = 0;
1061
1062 pcc->ac_brightness = pcc->sinf[SINF_AC_CUR_BRIGHT];
1063 pcc->dc_brightness = pcc->sinf[SINF_DC_CUR_BRIGHT];
1064 if (pcc->num_sifr > SINF_MUTE)
1065 pcc->mute = pcc->sinf[SINF_MUTE];
1066 if (pcc->num_sifr > SINF_ECO_MODE)
1067 pcc->eco_mode = pcc->sinf[SINF_ECO_MODE];
1068 if (pcc->num_sifr > SINF_CUR_BRIGHT)
1069 pcc->current_brightness = pcc->sinf[SINF_CUR_BRIGHT];
1070
1071 /* add sysfs attributes */
1072 result = sysfs_create_group(&device->dev.kobj, &pcc_attr_group);
1073 if (result)
1074 goto out_backlight;
1075
1076 result = acpi_dev_install_notify_handler(device, ACPI_DEVICE_NOTIFY,
1077 acpi_pcc_hotkey_notify, pcc);
1078 if (result)
1079 goto out_sysfs;
1080
1081 /* optical drive initialization */
1082 if (ACPI_SUCCESS(check_optd_present())) {
1083 pcc->platform = platform_device_register_simple("panasonic",
1084 PLATFORM_DEVID_NONE, NULL, 0);
1085 if (IS_ERR(pcc->platform)) {
1086 result = PTR_ERR(pcc->platform);
1087 goto out_notify_handler;
1088 }
1089 result = device_create_file(&pcc->platform->dev,
1090 &dev_attr_cdpower);
1091 if (result)
1092 goto out_platform;
1093
1094 pcc_register_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
1095 } else {
1096 pcc->platform = NULL;
1097 }
1098
1099 i8042_install_filter(panasonic_i8042_filter, NULL);
1100 return 0;
1101
1102 out_platform:
1103 platform_device_unregister(pcc->platform);
1104 out_notify_handler:
1105 acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
1106 acpi_pcc_hotkey_notify);
1107 out_sysfs:
1108 sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
1109 out_backlight:
1110 backlight_device_unregister(pcc->backlight);
1111 out_input:
1112 input_unregister_device(pcc->input_dev);
1113 out_sinf:
1114 device->driver_data = NULL;
1115 kfree(pcc->sinf);
1116 out_hotkey:
1117 kfree(pcc);
1118
1119 return result;
1120 }
1121
acpi_pcc_hotkey_remove(struct platform_device * pdev)1122 static void acpi_pcc_hotkey_remove(struct platform_device *pdev)
1123 {
1124 struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
1125 struct pcc_acpi *pcc = acpi_driver_data(device);
1126
1127 i8042_remove_filter(panasonic_i8042_filter);
1128
1129 if (pcc->platform) {
1130 pcc_unregister_optd_notifier(pcc, "\\_SB.PCI0.EHCI.ERHB.OPTD");
1131 device_remove_file(&pcc->platform->dev, &dev_attr_cdpower);
1132 platform_device_unregister(pcc->platform);
1133 }
1134
1135 acpi_dev_remove_notify_handler(device, ACPI_DEVICE_NOTIFY,
1136 acpi_pcc_hotkey_notify);
1137
1138 sysfs_remove_group(&device->dev.kobj, &pcc_attr_group);
1139
1140 backlight_device_unregister(pcc->backlight);
1141
1142 input_unregister_device(pcc->input_dev);
1143
1144 device->driver_data = NULL;
1145
1146 kfree(pcc->sinf);
1147 kfree(pcc);
1148 }
1149
1150 module_platform_driver(acpi_pcc_driver);
1151