1 Signed-off-by: Marco Chiappero <marco@absence.it>
3 --- a/drivers/acpi/video_detect.c
4 +++ b/drivers/acpi/video_detect.c
5 @@ -45,6 +45,24 @@ ACPI_MODULE_NAME("video");
6 static long acpi_video_support;
7 static bool acpi_video_caps_checked;
9 +static const struct dmi_system_id vendor_dmi_table[] = {
11 + .ident = "Sony Vaio S1",
13 + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
14 + DMI_MATCH(DMI_PRODUCT_NAME, "VPCS1"),
18 + .ident = "Sony Vaio TT",
20 + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
21 + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TT"),
28 acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
30 @@ -163,6 +181,9 @@ long acpi_video_get_capabilities(acpi_ha
31 * ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
34 + if (dmi_check_system(vendor_dmi_table))
35 + acpi_video_support |= ACPI_VIDEO_BACKLIGHT_DMI_VENDOR;
38 status = acpi_bus_get_device(graphics_handle, &tmp_dev);
39 if (ACPI_FAILURE(status)) {
41 --- a/drivers/platform/x86/sony-laptop.c
42 +++ b/drivers/platform/x86/sony-laptop.c
45 * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
46 * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
47 + * Copyright (C) 2011 Marco Chiappero <marco@absence.it>
48 + * Copyright (C) 2011 Javier Achirica <jachirica@gmail.com>
50 * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
51 * which are copyrighted by their respective authors.
53 #include <linux/slab.h>
54 #include <acpi/acpi_drivers.h>
55 #include <acpi/acpi_bus.h>
56 -#include <asm/uaccess.h>
57 +#include <linux/uaccess.h>
58 #include <linux/sonypi.h>
59 #include <linux/sony-laptop.h>
60 #include <linux/rfkill.h>
61 @@ -127,7 +129,7 @@ MODULE_PARM_DESC(minor,
62 "default is -1 (automatic)");
65 -static int kbd_backlight; /* = 1 */
66 +static int kbd_backlight; /* = 0 */
67 module_param(kbd_backlight, int, 0444);
68 MODULE_PARM_DESC(kbd_backlight,
69 "set this to 0 to disable keyboard backlight, "
70 @@ -140,20 +142,13 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
71 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
74 -static void sony_nc_kbd_backlight_resume(void);
75 +static int force_shock_notifications; /* = 0 */
76 +module_param(force_shock_notifications, int, 0);
77 +MODULE_PARM_DESC(force_shock_notifications,
78 + "set this to 1 to force the generation of shock protection "
79 + "events, even though the notebook do not support head "
80 + "unloading for the installed drive drive");
82 -enum sony_nc_rfkill {
90 -static int sony_rfkill_handle;
91 -static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
92 -static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
93 -static void sony_nc_rfkill_update(void);
95 /*********** Input Devices ***********/
97 @@ -253,7 +248,7 @@ static int sony_laptop_input_index[] = {
98 57, /* 70 SONYPI_EVENT_VOLUME_DEC_PRESSED */
99 -1, /* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
100 58, /* 72 SONYPI_EVENT_MEDIA_PRESSED */
101 - 59, /* 72 SONYPI_EVENT_VENDOR_PRESSED */
102 + 59, /* 73 SONYPI_EVENT_VENDOR_PRESSED */
105 static int sony_laptop_input_keycode_map[] = {
106 @@ -377,7 +372,8 @@ static void sony_laptop_report_input_eve
109 if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
110 - dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
111 + dprintk("sony_laptop_report_input_event, "
112 + "event not known: %d\n", event);
115 if (sony_laptop_input_index[event] != -1) {
116 @@ -565,12 +561,12 @@ static int sony_pf_add(void)
120 - out_platform_alloced:
121 +out_platform_alloced:
122 platform_device_put(sony_pf_device);
123 sony_pf_device = NULL;
124 - out_platform_registered:
125 +out_platform_registered:
126 platform_driver_unregister(&sony_pf_driver);
129 atomic_dec(&sony_pf_users);
132 @@ -664,7 +660,8 @@ static struct sony_nc_value sony_nc_valu
133 SNC_HANDLE(brightness_default, snc_brightness_def_get,
134 snc_brightness_def_set, brightness_default_validate, 0),
135 SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
136 - SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
137 + SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set,
138 + boolean_validate, 0),
139 SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
140 boolean_validate, 0),
141 SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
142 @@ -684,12 +681,13 @@ static struct sony_nc_value sony_nc_valu
145 static acpi_handle sony_nc_acpi_handle;
146 -static struct acpi_device *sony_nc_acpi_device = NULL;
147 +static struct acpi_device *sony_nc_acpi_device;
150 * acpi_evaluate_object wrappers
152 -static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
153 +static int acpi_callgetfunc(acpi_handle handle, char *name,
154 + unsigned int *result)
156 struct acpi_buffer output;
157 union acpi_object out_obj;
158 @@ -709,8 +707,8 @@ static int acpi_callgetfunc(acpi_handle
162 -static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
164 +static int acpi_callsetfunc(acpi_handle handle, char *name, u32 value,
165 + unsigned int *result)
167 struct acpi_object_list params;
168 union acpi_object in_obj;
169 @@ -730,7 +728,8 @@ static int acpi_callsetfunc(acpi_handle
170 if (status == AE_OK) {
171 if (result != NULL) {
172 if (out_obj.type != ACPI_TYPE_INTEGER) {
173 - pr_warn("acpi_evaluate_object bad return type\n");
174 + pr_warn("acpi_evaluate_object bad "
178 *result = out_obj.integer.value;
179 @@ -743,6 +742,72 @@ static int acpi_callsetfunc(acpi_handle
183 +static int acpi_callsetfunc_buffer(acpi_handle handle, u64 value,
184 + u8 array[], unsigned int size)
186 + u8 buffer[sizeof(value)];
188 + struct acpi_object_list params;
189 + union acpi_object in_obj;
190 + union acpi_object *values;
191 + struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
192 + acpi_status status;
194 + if (!array || !size)
197 + /* use a buffer type as parameter to overcome any 32 bits ACPI limit */
198 + memcpy(buffer, &value, sizeof(buffer));
201 + params.pointer = &in_obj;
202 + in_obj.type = ACPI_TYPE_BUFFER;
203 + in_obj.buffer.length = sizeof(buffer);
204 + in_obj.buffer.pointer = buffer;
206 + /* since SN06 is the only known method returning a buffer we
207 + * can hard code it, it is not necessary to have a parameter
209 + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms,
211 + values = (union acpi_object *) output.pointer;
212 + if (ACPI_FAILURE(status) || !values) {
213 + dprintk("acpi_evaluate_object failed\n");
217 + /* some buggy DSDTs return integer when the output does
218 + not execede the 4 bytes size
220 + if (values->type == ACPI_TYPE_BUFFER) {
221 + if (values->buffer.length <= 0)
224 + length = size > values->buffer.length ?
225 + values->buffer.length : size;
227 + memcpy(array, values->buffer.pointer, length);
228 + } else if (values->type == ACPI_TYPE_INTEGER) {
229 + u32 result = values->integer.value;
234 + while (length != 4) {
235 + array[length] = result & 0xff;
240 + pr_err("Invalid return object 0x%.2x\n", values->type);
245 + kfree(output.pointer);
249 struct sony_nc_handles {
251 struct device_attribute devattr;
252 @@ -767,8 +832,7 @@ static ssize_t sony_nc_handles_show(stru
254 static int sony_nc_handles_setup(struct platform_device *pd)
258 + unsigned int i, result;
260 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
262 @@ -811,12 +875,12 @@ static int sony_nc_handles_cleanup(struc
266 -static int sony_find_snc_handle(int handle)
267 +static int sony_find_snc_handle(unsigned int handle)
271 - /* not initialized yet, return early */
273 + /* not initialized yet or invalid handle, return early */
274 + if (!handles || !handle)
277 for (i = 0; i < 0x10; i++) {
278 @@ -830,7 +894,9 @@ static int sony_find_snc_handle(int hand
282 -static int sony_call_snc_handle(int handle, int argument, int *result)
283 +/* call command method SN07, accepts a 32 bit integer, returns a integer */
284 +static int sony_call_snc_handle(unsigned int handle, unsigned int argument,
285 + unsigned int *result)
288 int offset = sony_find_snc_handle(handle);
289 @@ -838,6 +904,7 @@ static int sony_call_snc_handle(int hand
293 + /* max 32 bit wide argument, for wider input use SN06 */
294 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
296 dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
297 @@ -845,6 +912,24 @@ static int sony_call_snc_handle(int hand
301 +/* call command method SN06, accepts a wide input buffer, returns a buffer */
302 +static int sony_call_snc_handle_buffer(unsigned int handle, u64 argument,
303 + u8 result[], unsigned int size)
306 + int offset = sony_find_snc_handle(handle);
311 + ret = acpi_callsetfunc_buffer(sony_nc_acpi_handle,
312 + offset | argument, result, size);
313 + dprintk("called SN06 with 0x%.4llx (%u bytes read)\n",
314 + offset | argument, ret);
320 * sony_nc_values input/output validate functions
322 @@ -857,11 +942,11 @@ static int sony_call_snc_handle(int hand
323 static int brightness_default_validate(const int direction, const int value)
326 - case SNC_VALIDATE_OUT:
328 - case SNC_VALIDATE_IN:
329 - if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
331 + case SNC_VALIDATE_OUT:
333 + case SNC_VALIDATE_IN:
334 + if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
339 @@ -883,10 +968,11 @@ static int boolean_validate(const int di
341 * Sysfs show/store common to all sony_nc_values
343 -static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
345 +static ssize_t sony_nc_sysfs_show(struct device *dev,
346 + struct device_attribute *attr,
350 + unsigned int value;
351 struct sony_nc_value *item =
352 container_of(attr, struct sony_nc_value, devattr);
354 @@ -906,7 +992,7 @@ static ssize_t sony_nc_sysfs_store(struc
355 struct device_attribute *attr,
356 const char *buffer, size_t count)
359 + unsigned long value;
360 struct sony_nc_value *item =
361 container_of(attr, struct sony_nc_value, devattr);
363 @@ -916,7 +1002,8 @@ static ssize_t sony_nc_sysfs_store(struc
367 - value = simple_strtoul(buffer, NULL, 10);
368 + if (strict_strtoul(buffer, 10, &value))
372 value = item->validate(SNC_VALIDATE_IN, value);
373 @@ -924,76 +1011,14 @@ static ssize_t sony_nc_sysfs_store(struc
377 - if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
378 + if (acpi_callsetfunc(sony_nc_acpi_handle,
379 + *item->acpiset, value, NULL) < 0)
390 -struct sony_backlight_props {
391 - struct backlight_device *dev;
396 -struct sony_backlight_props sony_bl_props;
398 -static int sony_backlight_update_status(struct backlight_device *bd)
400 - return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
401 - bd->props.brightness + 1, NULL);
404 -static int sony_backlight_get_brightness(struct backlight_device *bd)
408 - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
410 - /* brightness levels are 1-based, while backlight ones are 0-based */
414 -static int sony_nc_get_brightness_ng(struct backlight_device *bd)
417 - struct sony_backlight_props *sdev =
418 - (struct sony_backlight_props *)bl_get_data(bd);
420 - sony_call_snc_handle(sdev->handle, 0x0200, &result);
422 - return (result & 0xff) - sdev->offset;
425 -static int sony_nc_update_status_ng(struct backlight_device *bd)
428 - struct sony_backlight_props *sdev =
429 - (struct sony_backlight_props *)bl_get_data(bd);
431 - value = bd->props.brightness + sdev->offset;
432 - if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
438 -static const struct backlight_ops sony_backlight_ops = {
439 - .options = BL_CORE_SUSPENDRESUME,
440 - .update_status = sony_backlight_update_status,
441 - .get_brightness = sony_backlight_get_brightness,
443 -static const struct backlight_ops sony_backlight_ng_ops = {
444 - .options = BL_CORE_SUSPENDRESUME,
445 - .update_status = sony_nc_update_status_ng,
446 - .get_brightness = sony_nc_get_brightness_ng,
450 * New SNC-only Vaios event mapping to driver known keys
452 @@ -1003,10 +1028,6 @@ struct sony_nc_event {
455 static struct sony_nc_event sony_100_events[] = {
456 - { 0x90, SONYPI_EVENT_PKEY_P1 },
457 - { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
458 - { 0x91, SONYPI_EVENT_PKEY_P2 },
459 - { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
460 { 0x81, SONYPI_EVENT_FNKEY_F1 },
461 { 0x01, SONYPI_EVENT_FNKEY_RELEASED },
462 { 0x82, SONYPI_EVENT_FNKEY_F2 },
463 @@ -1021,12 +1042,20 @@ static struct sony_nc_event sony_100_eve
464 { 0x06, SONYPI_EVENT_FNKEY_RELEASED },
465 { 0x87, SONYPI_EVENT_FNKEY_F7 },
466 { 0x07, SONYPI_EVENT_FNKEY_RELEASED },
467 + { 0x88, SONYPI_EVENT_FNKEY_F8 },
468 + { 0x08, SONYPI_EVENT_FNKEY_RELEASED },
469 { 0x89, SONYPI_EVENT_FNKEY_F9 },
470 { 0x09, SONYPI_EVENT_FNKEY_RELEASED },
471 { 0x8A, SONYPI_EVENT_FNKEY_F10 },
472 { 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
473 + { 0x8B, SONYPI_EVENT_FNKEY_F11 },
474 + { 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
475 { 0x8C, SONYPI_EVENT_FNKEY_F12 },
476 { 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
477 + { 0x90, SONYPI_EVENT_PKEY_P1 },
478 + { 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
479 + { 0x91, SONYPI_EVENT_PKEY_P2 },
480 + { 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
481 { 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
482 { 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
483 { 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
484 @@ -1061,158 +1090,159 @@ static struct sony_nc_event sony_127_eve
491 -static void sony_nc_notify(struct acpi_device *device, u32 event)
492 +static int sony_nc_function_setup(unsigned int handle)
497 - /* New-style event */
499 - int key_handle = 0;
502 - if (sony_find_snc_handle(0x100) == ev)
503 - key_handle = 0x100;
504 - if (sony_find_snc_handle(0x127) == ev)
505 - key_handle = 0x127;
508 - struct sony_nc_event *key_event;
510 - if (sony_call_snc_handle(key_handle, 0x200, &result)) {
511 - dprintk("sony_nc_notify, unable to decode"
512 - " event 0x%.2x 0x%.2x\n", key_handle,
514 - /* restore the original event */
517 - ev = result & 0xFF;
518 + unsigned int result;
520 - if (key_handle == 0x100)
521 - key_event = sony_100_events;
523 - key_event = sony_127_events;
525 - for (; key_event->data; key_event++) {
526 - if (key_event->data == ev) {
527 - ev = key_event->event;
532 - if (!key_event->data)
533 - pr_info("Unknown event: 0x%x 0x%x\n",
536 - sony_laptop_report_input_event(ev);
538 - } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
539 - sony_nc_rfkill_update();
543 - sony_laptop_report_input_event(ev);
544 + if (handle == 0x0102)
545 + sony_call_snc_handle(0x0102, 0x100, &result);
547 + sony_call_snc_handle(handle, 0, &result);
549 - dprintk("sony_nc_notify, event: 0x%.2x\n", ev);
550 - acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
554 -static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
555 - void *context, void **return_value)
556 +static int sony_nc_hotkeys_decode(unsigned int handle)
558 - struct acpi_device_info *info;
560 + unsigned int result = 0;
561 + struct sony_nc_event *key_event;
563 + if (sony_call_snc_handle(handle, 0x200, &result)) {
564 + dprintk("sony_nc_hotkeys_decode,"
565 + " unable to retrieve the hotkey\n");
569 - if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
570 - pr_warn("method: name: %4.4s, args %X\n",
571 - (char *)&info->name, info->param_count);
572 + if (handle == 0x100)
573 + key_event = sony_100_events;
575 + key_event = sony_127_events;
578 + for (; key_event->data; key_event++) {
579 + if (key_event->data == result) {
580 + ret = key_event->event;
585 + if (!key_event->data)
586 + pr_info("Unknown hotkey 0x%.2x (handle 0x%.2x)\n",
589 + dprintk("sony_nc_hotkeys_decode, hotkey 0x%.2x decoded "
590 + "to event 0x%.2x\n", result, ret);
600 -static int sony_nc_function_setup(struct acpi_device *device)
604 - /* Enable all events */
605 - acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result);
607 - /* Setup hotkeys */
608 - sony_call_snc_handle(0x0100, 0, &result);
609 - sony_call_snc_handle(0x0101, 0, &result);
610 - sony_call_snc_handle(0x0102, 0x100, &result);
611 - sony_call_snc_handle(0x0127, 0, &result);
615 +enum sony_nc_rfkill {
622 +struct sony_rfkill_data {
623 + struct rfkill *devices[N_SONY_RFKILL];
624 + const unsigned int address[N_SONY_RFKILL];
625 + unsigned int handle;
627 +static struct sony_rfkill_data sony_rfkill = {
628 + {NULL}, {0x300, 0x500, 0x700, 0x900}, 0};
630 -static int sony_nc_resume(struct acpi_device *device)
631 +static int sony_nc_rfkill_update_wwan(void)
633 - struct sony_nc_value *item;
634 - acpi_handle handle;
635 + unsigned int result, cmd;
639 - for (item = sony_nc_values; item->name; item++) {
641 + if (sony_call_snc_handle(sony_rfkill.handle, 0x0200, &result))
643 + battery = !!(result & 0x2);
647 - ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
648 - item->value, NULL);
650 - pr_err("%s: %d\n", __func__, ret);
654 + /* retrieve the device block state */
655 + if (sony_call_snc_handle(sony_rfkill.handle,
656 + sony_rfkill.address[SONY_WWAN], &result))
658 + swblock = !(result & 0x02);
660 - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
662 - if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
663 - dprintk("ECON Method failed\n");
664 + if (battery && !swblock) {
665 + /* set the power state according with swblock */
667 + } else if (!battery && !swblock) {
674 - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
676 - dprintk("Doing SNC setup\n");
677 - sony_nc_function_setup(device);
679 + cmd |= sony_rfkill.address[SONY_WWAN] + 0x100;
681 - /* re-read rfkill state */
682 - sony_nc_rfkill_update();
683 + /* set the power state */
684 + sony_call_snc_handle(sony_rfkill.handle, cmd, &result);
686 - /* restore kbd backlight states */
687 - sony_nc_kbd_backlight_resume();
688 + /* update the rfkill sw state */
689 + rfkill_set_sw_state(sony_rfkill.devices[SONY_WWAN], swblock);
694 +static int sony_nc_get_rfkill_hwblock(void)
696 + unsigned int result;
698 + if (sony_call_snc_handle(sony_rfkill.handle, 0x200, &result))
701 + return result & 0x1;
704 static void sony_nc_rfkill_cleanup(void)
708 for (i = 0; i < N_SONY_RFKILL; i++) {
709 - if (sony_rfkill_devices[i]) {
710 - rfkill_unregister(sony_rfkill_devices[i]);
711 - rfkill_destroy(sony_rfkill_devices[i]);
712 + if (sony_rfkill.devices[i]) {
713 + rfkill_unregister(sony_rfkill.devices[i]);
714 + rfkill_destroy(sony_rfkill.devices[i]);
719 static int sony_nc_rfkill_set(void *data, bool blocked)
722 - int argument = sony_rfkill_address[(long) data] + 0x100;
723 + unsigned int result, argument = sony_rfkill.address[(long) data];
725 + /* wwan state change not allowed when the battery is not present */
726 + sony_call_snc_handle(sony_rfkill.handle, 0x0200, &result);
727 + if (((long) data == SONY_WWAN) && !(result & 0x2)) {
729 + /* notify user space: the battery must be present */
730 + acpi_bus_generate_proc_event(sony_nc_acpi_device,
732 + acpi_bus_generate_netlink_event(
733 + sony_nc_acpi_device->pnp.device_class,
734 + dev_name(&sony_nc_acpi_device->dev),
741 + /* do not force an already set state */
742 + sony_call_snc_handle(sony_rfkill.handle, argument, &result);
743 + if ((result & 0x1) == !blocked)
748 argument |= 0xff0000;
750 - return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
751 + return sony_call_snc_handle(sony_rfkill.handle, argument, &result);
754 static const struct rfkill_ops sony_rfkill_ops = {
755 @@ -1226,8 +1256,8 @@ static int sony_nc_setup_rfkill(struct a
757 enum rfkill_type type;
761 + unsigned int result;
762 + bool hwblock, swblock, wwblock;
766 @@ -1255,8 +1285,20 @@ static int sony_nc_setup_rfkill(struct a
770 - sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
771 + sony_call_snc_handle(sony_rfkill.handle, 0x200, &result);
772 hwblock = !(result & 0x1);
773 + wwblock = !(result & 0x2);
776 + sony_call_snc_handle(sony_rfkill.handle, sony_rfkill.address[nc_type],
778 + swblock = !(result & 0x2);
780 + /* hard block the WWAN module if no battery is present */
781 + if ((nc_type == SONY_WWAN) && wwblock)
784 + rfkill_init_sw_state(rfk, swblock);
785 rfkill_set_hw_state(rfk, hwblock);
787 err = rfkill_register(rfk);
788 @@ -1264,412 +1306,3030 @@ static int sony_nc_setup_rfkill(struct a
792 - sony_rfkill_devices[nc_type] = rfk;
793 + sony_rfkill.devices[nc_type] = rfk;
797 static void sony_nc_rfkill_update(void)
799 enum sony_nc_rfkill i;
802 + unsigned int result;
803 + bool hwblock, swblock, wwblock;
805 - sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
806 + sony_call_snc_handle(sony_rfkill.handle, 0x200, &result);
807 hwblock = !(result & 0x1);
808 + wwblock = !(result & 0x2);
810 for (i = 0; i < N_SONY_RFKILL; i++) {
811 - int argument = sony_rfkill_address[i];
812 + unsigned int argument = sony_rfkill.address[i];
814 - if (!sony_rfkill_devices[i])
815 + if (!sony_rfkill.devices[i])
819 - if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
820 - /* we already know we're blocked */
824 + sony_call_snc_handle(sony_rfkill.handle, argument, &result);
825 + /* block wwan when no battery is present */
826 + if ((i == SONY_WWAN) && wwblock)
829 + swblock = !(result & 0x2);
831 - sony_call_snc_handle(sony_rfkill_handle, argument, &result);
832 - rfkill_set_states(sony_rfkill_devices[i],
833 - !(result & 0xf), false);
834 + rfkill_set_states(sony_rfkill.devices[i],
839 -static void sony_nc_rfkill_setup(struct acpi_device *device)
840 +static int sony_nc_rfkill_setup(struct acpi_device *device, unsigned int handle)
844 - acpi_status status;
845 - struct acpi_object_list params;
846 - union acpi_object in_obj;
847 - union acpi_object *device_enum;
848 - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
849 +#define RFKILL_BUFF_SIZE 8
850 + u8 dev_code, i, buff[RFKILL_BUFF_SIZE] = { 0 };
852 - offset = sony_find_snc_handle(0x124);
853 - if (offset == -1) {
854 - offset = sony_find_snc_handle(0x135);
858 - sony_rfkill_handle = 0x135;
860 - sony_rfkill_handle = 0x124;
861 - dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
862 + sony_rfkill.handle = handle;
864 /* need to read the whole buffer returned by the acpi call to SN06
865 * here otherwise we may miss some features
868 - params.pointer = &in_obj;
869 - in_obj.type = ACPI_TYPE_INTEGER;
870 - in_obj.integer.value = offset;
871 - status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms,
873 - if (ACPI_FAILURE(status)) {
874 - dprintk("Radio device enumeration failed\n");
878 - device_enum = (union acpi_object *) buffer.pointer;
879 - if (!device_enum) {
880 - pr_err("No SN06 return object\n");
883 - if (device_enum->type != ACPI_TYPE_BUFFER) {
884 - pr_err("Invalid SN06 return object 0x%.2x\n",
885 - device_enum->type);
888 + if (sony_call_snc_handle_buffer(sony_rfkill.handle, 0x000,
889 + buff, RFKILL_BUFF_SIZE) < 0)
892 /* the buffer is filled with magic numbers describing the devices
893 * available, 0xff terminates the enumeration
895 - for (i = 0; i < device_enum->buffer.length; i++) {
896 + for (i = 0; i < RFKILL_BUFF_SIZE; i++) {
898 - dev_code = *(device_enum->buffer.pointer + i);
899 + dev_code = buff[i];
900 if (dev_code == 0xff)
908 + 0x20 WWAN GPRS-EDGE
912 + 0x25 Gobi WWAN no GPS
913 + 0x26 Gobi WWAN + GPS
914 + 0x28 Gobi WWAN no GPS
915 + 0x29 Gobi WWAN + GPS
916 + 0x50 Gobi WWAN no GPS
917 + 0x51 Gobi WWAN + GPS
919 + 0x70 no SIM card slot
922 dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
924 - if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
925 + if (dev_code == 0 && !sony_rfkill.devices[SONY_WIFI])
926 sony_nc_setup_rfkill(device, SONY_WIFI);
928 - if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
929 + if (dev_code == 0x10 && !sony_rfkill.devices[SONY_BLUETOOTH])
930 sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
932 - if ((0xf0 & dev_code) == 0x20 &&
933 - !sony_rfkill_devices[SONY_WWAN])
934 + if (((0xf0 & dev_code) == 0x20 || (0xf0 & dev_code) == 0x50) &&
935 + !sony_rfkill.devices[SONY_WWAN])
936 sony_nc_setup_rfkill(device, SONY_WWAN);
938 - if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
939 - sony_nc_setup_rfkill(device, SONY_WIMAX);
940 + if (dev_code == 0x30 && !sony_rfkill.devices[SONY_WIMAX])
941 + sony_nc_setup_rfkill(device, SONY_WIMAX);
947 +/* ALS controlled backlight feature */
948 +/* generic ALS data and interface */
949 +#define ALS_TABLE_SIZE 25
951 +struct als_device_ops {
952 + int (*init)(const u8 defaults[]);
954 + int (*event_handler)(void);
955 + int (*set_power)(unsigned int);
956 + int (*get_power)(unsigned int *);
957 + int (*get_lux)(unsigned int *, unsigned int *);
958 + int (*get_kelvin)(unsigned int *);
961 +static struct sony_als_device {
962 + unsigned int handle;
964 + unsigned int power;
965 + unsigned int managed;
967 + unsigned int levels_num;
969 + unsigned int defaults_num;
971 + u8 parameters[ALS_TABLE_SIZE];
973 + /* common device operations */
974 + const struct als_device_ops *ops;
976 + /* basic ALS sys interface */
977 + unsigned int attrs_num;
978 + struct device_attribute attrs[7];
982 + model specific ALS data and controls
983 + TAOS TSL256x device data
985 +#define LUX_SHIFT_BITS 16 /* for non-floating point math */
986 +/* scale 100000 multiplied fractional coefficients rounding the values */
987 +#define SCALE(u) ((((((u64) u) << LUX_SHIFT_BITS) / 10000) + 5) / 10)
989 +#define TSL256X_REG_CTRL 0x00
990 +#define TSL256X_REG_TIMING 0x01
991 +#define TSL256X_REG_TLOW 0x02
992 +#define TSL256X_REG_THIGH 0x04
993 +#define TSL256X_REG_INT 0x06
994 +#define TSL256X_REG_ID 0x0a
995 +#define TSL256X_REG_DATA0 0x0c
996 +#define TSL256X_REG_DATA1 0x0e
998 +#define TSL256X_POWER_ON 0x03
999 +#define TSL256X_POWER_OFF 0x00
1001 +#define TSL256X_POWER_MASK 0x03
1002 +#define TSL256X_INT_MASK 0x10
1004 +struct tsl256x_coeff {
1012 +struct tsl256x_data {
1013 + unsigned int gaintime;
1014 + unsigned int periods;
1016 + struct tsl256x_coeff const *coeff_table;
1018 +static struct tsl256x_data *tsl256x_handle;
1020 +static const struct tsl256x_coeff tsl256x_coeff_fn[] = {
1022 + .ratio = SCALE(12500), /* 0.125 * 2^LUX_SHIFT_BITS */
1023 + .ch0 = SCALE(3040), /* 0.0304 * 2^LUX_SHIFT_BITS */
1024 + .ch1 = SCALE(2720), /* 0.0272 * 2^LUX_SHIFT_BITS */
1025 + .ka = SCALE(313550000),
1028 + .ratio = SCALE(25000), /* 0.250 * 2^LUX_SHIFT_BITS */
1029 + .ch0 = SCALE(3250), /* 0.0325 * 2^LUX_SHIFT_BITS */
1030 + .ch1 = SCALE(4400), /* 0.0440 * 2^LUX_SHIFT_BITS */
1031 + .ka = SCALE(203390000),
1034 + .ratio = SCALE(37500), /* 0.375 * 2^LUX_SHIFT_BITS */
1035 + .ch0 = SCALE(3510), /* 0.0351 * 2^LUX_SHIFT_BITS */
1036 + .ch1 = SCALE(5440), /* 0.0544 * 2^LUX_SHIFT_BITS */
1037 + .ka = SCALE(152180000),
1040 + .ratio = SCALE(50000), /* 0.50 * 2^LUX_SHIFT_BITS */
1041 + .ch0 = SCALE(3810), /* 0.0381 * 2^LUX_SHIFT_BITS */
1042 + .ch1 = SCALE(6240), /* 0.0624 * 2^LUX_SHIFT_BITS */
1043 + .ka = SCALE(163580000),
1046 + .ratio = SCALE(61000), /* 0.61 * 2^LUX_SHIFT_BITS */
1047 + .ch0 = SCALE(2240), /* 0.0224 * 2^LUX_SHIFT_BITS */
1048 + .ch1 = SCALE(3100), /* 0.0310 * 2^LUX_SHIFT_BITS */
1049 + .ka = SCALE(180800000),
1052 + .ratio = SCALE(80000), /* 0.80 * 2^LUX_SHIFT_BITS */
1053 + .ch0 = SCALE(1280), /* 0.0128 * 2^LUX_SHIFT_BITS */
1054 + .ch1 = SCALE(1530), /* 0.0153 * 2^LUX_SHIFT_BITS */
1055 + .ka = SCALE(197340000),
1058 + .ratio = SCALE(130000),/* 1.3 * 2^LUX_SHIFT_BITS */
1059 + .ch0 = SCALE(146), /* 0.00146 * 2^LUX_SHIFT_BITS */
1060 + .ch1 = SCALE(112), /* 0.00112 * 2^LUX_SHIFT_BITS */
1061 + .ka = SCALE(182900000),
1064 + .ratio = UINT_MAX, /* for higher ratios */
1072 +static const struct tsl256x_coeff tsl256x_coeff_cs[] = {
1074 + .ratio = SCALE(13000), /* 0.130 * 2^LUX_SHIFT_BITS */
1075 + .ch0 = SCALE(3150), /* 0.0315 * 2^LUX_SHIFT_BITS */
1076 + .ch1 = SCALE(2620), /* 0.0262 * 2^LUX_SHIFT_BITS */
1077 + .ka = SCALE(300370000),
1080 + .ratio = SCALE(26000), /* 0.260 * 2^LUX_SHIFT_BITS */
1081 + .ch0 = SCALE(3370), /* 0.0337 * 2^LUX_SHIFT_BITS */
1082 + .ch1 = SCALE(4300), /* 0.0430 * 2^LUX_SHIFT_BITS */
1083 + .ka = SCALE(194270000),
1086 + .ratio = SCALE(39000), /* 0.390 * 2^LUX_SHIFT_BITS */
1087 + .ch0 = SCALE(3630), /* 0.0363 * 2^LUX_SHIFT_BITS */
1088 + .ch1 = SCALE(5290), /* 0.0529 * 2^LUX_SHIFT_BITS */
1089 + .ka = SCALE(152520000),
1092 + .ratio = SCALE(52000), /* 0.520 * 2^LUX_SHIFT_BITS */
1093 + .ch0 = SCALE(3920), /* 0.0392 * 2^LUX_SHIFT_BITS */
1094 + .ch1 = SCALE(6050), /* 0.0605 * 2^LUX_SHIFT_BITS */
1095 + .ka = SCALE(165960000),
1098 + .ratio = SCALE(65000), /* 0.650 * 2^LUX_SHIFT_BITS */
1099 + .ch0 = SCALE(2290), /* 0.0229 * 2^LUX_SHIFT_BITS */
1100 + .ch1 = SCALE(2910), /* 0.0291 * 2^LUX_SHIFT_BITS */
1101 + .ka = SCALE(184800000),
1104 + .ratio = SCALE(80000), /* 0.800 * 2^LUX_SHIFT_BITS */
1105 + .ch0 = SCALE(1570), /* 0.0157 * 2^LUX_SHIFT_BITS */
1106 + .ch1 = SCALE(1800), /* 0.0180 * 2^LUX_SHIFT_BITS */
1107 + .ka = SCALE(199220000),
1110 + .ratio = SCALE(130000),/* 0.130 * 2^LUX_SHIFT_BITS */
1111 + .ch0 = SCALE(338), /* 0.00338 * 2^LUX_SHIFT_BITS */
1112 + .ch1 = SCALE(260), /* 0.00260 * 2^LUX_SHIFT_BITS */
1113 + .ka = SCALE(182900000),
1116 + .ratio = UINT_MAX, /* for higher ratios */
1124 +/* TAOS helper & control functions */
1125 +static inline int tsl256x_exec_writebyte(unsigned int reg,
1126 + unsigned int const *value)
1128 + unsigned int result;
1130 + return (sony_call_snc_handle(sony_als->handle, (*value << 0x18) |
1131 + (reg << 0x10) | 0x800500, &result) || !(result & 0x01))
1135 +static inline int tsl256x_exec_writeword(unsigned int reg,
1136 + unsigned int const *value)
1141 + /* using sony_call_snc_handle_buffer due to possible input overflows */
1142 + return ((sony_call_snc_handle_buffer(sony_als->handle, (arg << 0x18) |
1143 + (reg << 0x10) | 0xA00700, result, 1) < 0) ||
1144 + !(result[0] & 0x01)) ? -EIO : 0;
1147 +static inline int tsl256x_exec_readbyte(unsigned int reg, unsigned int *result)
1149 + if (sony_call_snc_handle(sony_als->handle, (reg << 0x10)
1150 + | 0x800400, result) || !(*result & 0x01))
1152 + *result = (*result >> 0x08) & 0xFF;
1157 +static inline int tsl256x_exec_readword(unsigned int reg, unsigned int *result)
1159 + if (sony_call_snc_handle(sony_als->handle, (reg << 0x10)
1160 + | 0xA00600, result) || !(*result & 0x01))
1162 + *result = (*result >> 0x08) & 0xFFFF;
1167 +static int tsl256x_interrupt_ctrls(unsigned int *interrupt,
1168 + unsigned int *periods)
1170 + unsigned int value, result;
1172 + /* if no interrupt parameter, retrieve interrupt status */
1174 + if (tsl256x_exec_readbyte(TSL256X_REG_INT, &result))
1177 + value = (result & TSL256X_INT_MASK);
1179 + value = *interrupt << 0x04;
1182 + /* if no periods provided use the last one set */
1183 + value |= (periods ? *periods : tsl256x_handle->periods);
1185 + if (tsl256x_exec_writebyte(TSL256X_REG_INT, &value))
1189 + tsl256x_handle->periods = *periods;
1194 +static int tsl256x_setup(void)
1196 + unsigned int interr = 1, zero = 0;
1199 + * reset the threshold settings to trigger an event as soon
1200 + * as the event goes on, forcing a backlight adaptation to
1201 + * the current lighting conditions
1203 + tsl256x_exec_writeword(TSL256X_REG_TLOW, &zero);
1204 + tsl256x_exec_writeword(TSL256X_REG_THIGH, &zero);
1206 + /* set gain and time */
1207 + if (tsl256x_exec_writebyte(TSL256X_REG_TIMING,
1208 + &tsl256x_handle->gaintime))
1211 + /* restore persistence value and enable the interrupt generation */
1212 + if (tsl256x_interrupt_ctrls(&interr, &tsl256x_handle->periods))
1218 +static int tsl256x_set_power(unsigned int status)
1223 + ret = tsl256x_setup();
1228 + status = status ? TSL256X_POWER_ON : TSL256X_POWER_OFF;
1229 + ret = tsl256x_exec_writebyte(TSL256X_REG_CTRL, &status);
1234 +static int tsl256x_get_power(unsigned int *status)
1236 + if (tsl256x_exec_readbyte(TSL256X_REG_CTRL, status))
1239 + *status = ((*status & TSL256X_POWER_MASK) == TSL256X_POWER_ON) ? 1 : 0;
1244 +static int tsl256x_get_raw_data(unsigned int *ch0, unsigned int *ch1)
1249 + if (tsl256x_exec_readword(TSL256X_REG_DATA0, ch0))
1253 + if (tsl256x_exec_readword(TSL256X_REG_DATA1, ch1))
1260 +static int tsl256x_set_thresholds(const unsigned int *ch0)
1262 + unsigned int tlow, thigh;
1264 + tlow = (*ch0 * tsl256x_handle->defaults[0]) / 100;
1265 + thigh = ((*ch0 * tsl256x_handle->defaults[1]) / 100) + 1;
1267 + if (thigh > 0xffff)
1270 + if (tsl256x_exec_writeword(TSL256X_REG_TLOW, &tlow) ||
1271 + tsl256x_exec_writeword(TSL256X_REG_THIGH, &thigh))
1277 +#define MAX_LUX 1500
1278 +static void tsl256x_calculate_lux(const u32 ch0, const u32 ch1,
1279 + unsigned int *integ, unsigned int *fract)
1281 + /* the raw output from the sensor is just a "count" value, as
1282 + it is the result of the integration of the analog sensor
1283 + signal, the counts-to-lux curve (and its approximation can
1284 + be found on the datasheet.
1286 + const struct tsl256x_coeff *coeff = tsl256x_handle->coeff_table;
1287 + u32 ratio, temp, integer, fractional;
1289 + if (ch0 >= 65535 || ch1 >= 65535)
1292 + /* STEP 1: ratio calculation, for ch0 & ch1 coeff selection */
1294 + /* protect against division by 0 */
1295 + ratio = ch0 ? ((ch1 << (LUX_SHIFT_BITS + 1)) / ch0) : UINT_MAX;
1296 + /* round the ratio value */
1297 + ratio = ratio == UINT_MAX ? ratio : (ratio + 1) >> 1;
1299 + /* coeff selection rule */
1300 + while (coeff->ratio < ratio)
1303 + /* STEP 2: lux calculation formula using the right coeffcients */
1304 + temp = (ch0 * coeff->ch0) - (ch1 * coeff->ch1);
1305 + /* the sensor is placed under a plastic or glass cover which filters
1306 + a certain ammount of light (depending on that particular material).
1307 + To have an accurate reading, we need to compensate for this loss,
1308 + multiplying for compensation parameter, taken from the DSDT.
1310 + temp *= tsl256x_handle->defaults[3] / 10;
1312 + /* STEP 3: separate integer and fractional part */
1313 + /* remove the integer part and multiply for the 10^N, N decimals */
1314 + fractional = (temp % (1 << LUX_SHIFT_BITS)) * 100; /* two decimals */
1315 + /* scale down the value */
1316 + fractional >>= LUX_SHIFT_BITS;
1318 + /* strip off fractional portion to obtain the integer part */
1319 + integer = temp >> LUX_SHIFT_BITS;
1321 + if (integer > MAX_LUX)
1325 + *fract = fractional;
1334 +static void tsl256x_calculate_kelvin(const u32 *ch0, const u32 *ch1,
1335 + unsigned int *temperature)
1337 + const struct tsl256x_coeff *coeff = tsl256x_handle->coeff_table;
1340 + /* protect against division by 0 */
1341 + ratio = *ch0 ? ((*ch1 << (LUX_SHIFT_BITS + 1)) / *ch0) : UINT_MAX;
1342 + /* round the ratio value */
1343 + ratio = (ratio + 1) >> 1;
1345 + /* coeff selection rule */
1346 + while (coeff->ratio < ratio)
1349 + *temperature = ratio ? coeff->ka / ratio + coeff->kb : 0;
1352 +static int tsl256x_get_lux(unsigned int *integ, unsigned int *fract)
1355 + unsigned int ch0, ch1;
1357 + if (!integ || !fract)
1360 + ret = tsl256x_get_raw_data(&ch0, &ch1);
1362 + tsl256x_calculate_lux(ch0, ch1, integ, fract);
1367 +static int tsl256x_get_kelvin(unsigned int *temperature)
1370 + unsigned int ch0, ch1;
1375 + ret = tsl256x_get_raw_data(&ch0, &ch1);
1377 + tsl256x_calculate_kelvin(&ch0, &ch1, temperature);
1382 +static int tsl256x_get_id(char *model, unsigned int *id, bool *cs)
1385 + unsigned int result;
1386 + char *name = NULL;
1387 + bool unknown = false;
1388 + bool type_cs = false;
1390 + ret = tsl256x_exec_readbyte(TSL256X_REG_ID, &result);
1394 + switch ((result >> 0x04) & 0x0F) {
1396 + name = "TAOS TSL2561";
1399 + name = "TAOS TSL2560";
1402 + name = "TAOS TSL2563";
1405 + name = "TAOS TSL2562";
1409 + name = "TAOS TSL2561CS";
1413 + name = "TAOS TSL2560CS";
1424 + if (model && name)
1425 + strcpy(model, name);
1430 +static int tsl256x_event_handler(void)
1432 + unsigned int ch0, interr = 1;
1434 + /* wait for the EC to clear the interrupt */
1435 +/* schedule_timeout_interruptible(msecs_to_jiffies(100)); */
1436 + /* ...or force the interrupt clear immediately */
1437 + sony_call_snc_handle(sony_als->handle, 0x04C60500, &interr);
1439 + /* read the raw data */
1440 + tsl256x_get_raw_data(&ch0, NULL);
1442 + /* set the thresholds */
1443 + tsl256x_set_thresholds(&ch0);
1445 + /* enable interrupt */
1446 + tsl256x_interrupt_ctrls(&interr, NULL);
1451 +static int tsl256x_init(const u8 defaults[])
1455 + bool cs; /* if CS package choose CS coefficients */
1458 + /* detect the device */
1459 + ret = tsl256x_get_id(model, &id, &cs);
1463 + dprintk("unsupported ALS found (unknown model "
1464 + "number %u rev. %u\n", id >> 4, id & 0x0F);
1467 + dprintk("found ALS model number %u rev. %u (%s)\n",
1468 + id >> 4, id & 0x0F, model);
1471 + tsl256x_handle = kzalloc(sizeof(struct tsl256x_data), GFP_KERNEL);
1472 + if (!tsl256x_handle)
1475 + tsl256x_handle->defaults = kzalloc(sizeof(u8) * 4, GFP_KERNEL);
1476 + if (!tsl256x_handle->defaults) {
1477 + kfree(tsl256x_handle);
1481 + /* populate the device data */
1482 + tsl256x_handle->defaults[0] = defaults[3]; /* low threshold % */
1483 + tsl256x_handle->defaults[1] = defaults[4]; /* high threshold % */
1484 + tsl256x_handle->defaults[2] = defaults[9]; /* sensor interrupt rate */
1485 + tsl256x_handle->defaults[3] = defaults[10]; /* light compensat. rate */
1486 + tsl256x_handle->gaintime = 0x12;
1487 + tsl256x_handle->periods = defaults[9];
1488 + tsl256x_handle->coeff_table = cs ? tsl256x_coeff_cs : tsl256x_coeff_fn;
1490 + ret = tsl256x_setup();
1495 +static int tsl256x_exit(void)
1497 + unsigned int interr = 0, periods = tsl256x_handle->defaults[2];
1499 + /* disable the interrupt generation, restore defaults */
1500 + tsl256x_interrupt_ctrls(&interr, &periods);
1502 + tsl256x_handle->coeff_table = NULL;
1503 + kfree(tsl256x_handle->defaults);
1504 + tsl256x_handle->defaults = NULL;
1505 + kfree(tsl256x_handle);
1510 +/* TAOS TSL256x specific ops */
1511 +static const struct als_device_ops tsl256x_ops = {
1512 + .init = tsl256x_init,
1513 + .exit = tsl256x_exit,
1514 + .event_handler = tsl256x_event_handler,
1515 + .set_power = tsl256x_set_power,
1516 + .get_power = tsl256x_get_power,
1517 + .get_lux = tsl256x_get_lux,
1518 + .get_kelvin = tsl256x_get_kelvin,
1521 +/* unknown ALS sensors controlled by the EC present on newer Vaios */
1522 +static inline int ngals_get_raw_data(unsigned int *data)
1524 + if (sony_call_snc_handle(sony_als->handle, 0x1000, data))
1530 +static int ngals_get_lux(unsigned int *integ, unsigned int *fract)
1532 + unsigned int data;
1534 + if (sony_call_snc_handle(sony_als->handle, 0x1000, &data))
1537 + /* if we have a valid lux data */
1538 + if (!!(data & 0xff0000) == 0x01) {
1539 + *integ = 0xffff & data;
1548 +static const struct als_device_ops ngals_ops = {
1551 + .event_handler = NULL,
1552 + .set_power = NULL,
1553 + .get_power = NULL,
1554 + .get_lux = ngals_get_lux,
1555 + .get_kelvin = NULL,
1558 +/* ALS common data and functions */
1559 +static int sony_nc_als_event_handler(void)
1561 + /* call the device handler */
1562 + if (sony_als->ops->event_handler)
1563 + sony_als->ops->event_handler();
1568 +static int sony_nc_als_power_set(unsigned int status)
1570 + if (!sony_als->ops->set_power)
1573 + if (sony_als->ops->set_power(status))
1576 + sony_als->power = status;
1581 +static int sony_nc_als_managed_set(unsigned int status)
1584 + unsigned int result, cmd;
1585 + static bool was_on;
1587 + /* turn on/off the event notification
1588 + * (and enable als_backlight writes)
1590 + cmd = sony_als->handle == 0x0143 ? 0x2200 : 0x0900;
1591 + if (sony_call_snc_handle(sony_als->handle,
1592 + (status << 0x10) | cmd, &result))
1595 + sony_als->managed = status;
1597 + /* turn on the ALS; this will also enable the interrupt generation */
1598 + if (status) /* store the power state else check the previous state */
1599 + was_on = sony_als->power;
1603 + ret = sony_nc_als_power_set(status);
1604 + if (ret == -EPERM) /* new models do not allow power control */
1610 +static unsigned int level;
1611 +static int sony_nc_als_get_brightness(struct backlight_device *bd)
1613 + if (bd->props.brightness != level)
1614 + dprintk("bd->props.brightness != level\n");
1619 +static int sony_nc_als_update_status(struct backlight_device *bd)
1621 + unsigned int value, result;
1623 + if (sony_als->managed) {
1624 + if (bd->props.brightness != level) {
1625 + char *env[2] = { "ALS=2", NULL};
1626 + kobject_uevent_env(&sony_nc_acpi_device->dev.kobj,
1627 + KOBJ_CHANGE, env);
1629 + dprintk("generating ALS event 3 (reason: 2)\n");
1630 + acpi_bus_generate_proc_event(sony_nc_acpi_device,
1632 + acpi_bus_generate_netlink_event(
1633 + sony_nc_acpi_device->pnp.device_class,
1634 + dev_name(&sony_nc_acpi_device->dev),
1640 + value = sony_als->levels[bd->props.brightness];
1641 + cmd = sony_als->handle == 0x0143 ? 0x3000 : 0x0100;
1642 + if (sony_call_snc_handle(sony_als->handle,
1643 + (value << 0x10) | cmd, &result))
1647 + level = bd->props.brightness;
1652 +/* ALS sys interface */
1653 +static ssize_t sony_nc_als_power_show(struct device *dev,
1654 + struct device_attribute *attr, char *buffer)
1656 + ssize_t count = 0;
1659 + if (!sony_als->ops->get_power)
1662 + if (sony_als->ops->get_power(&status))
1665 + count = snprintf(buffer, PAGE_SIZE, "%d\n", status);
1670 +static ssize_t sony_nc_als_power_store(struct device *dev,
1671 + struct device_attribute *attr,
1672 + const char *buffer, size_t count)
1675 + unsigned long value;
1680 + if (strict_strtoul(buffer, 10, &value) || value > 1)
1683 + /* no action if already set */
1684 + if (value == sony_als->power)
1687 + ret = sony_nc_als_power_set(value);
1694 +static ssize_t sony_nc_als_managed_show(struct device *dev,
1695 + struct device_attribute *attr, char *buffer)
1697 + ssize_t count = 0;
1698 + unsigned int status, cmd;
1700 + cmd = sony_als->handle == 0x0143 ? 0x2100 : 0x0A00;
1701 + if (sony_call_snc_handle(sony_als->handle, cmd, &status))
1704 + count = snprintf(buffer, PAGE_SIZE, "%d\n", status & 0x01);
1709 +static ssize_t sony_nc_als_managed_store(struct device *dev,
1710 + struct device_attribute *attr,
1711 + const char *buffer, size_t count)
1713 + unsigned long value;
1718 + if (strict_strtoul(buffer, 10, &value) || value > 1)
1721 + if (sony_als->managed != value) {
1722 + int ret = sony_nc_als_managed_set(value);
1730 +static ssize_t sony_nc_als_lux_show(struct device *dev,
1731 + struct device_attribute *attr, char *buffer)
1733 + ssize_t count = 0;
1734 + unsigned int integ = 0, fract = 0;
1736 + if (sony_als->power)
1737 + /* sony_als->ops->get_lux is mandatory, no check */
1738 + sony_als->ops->get_lux(&integ, &fract);
1740 + count = snprintf(buffer, PAGE_SIZE, "%u.%.2u\n", integ, fract);
1745 +static ssize_t sony_nc_als_parameters_show(struct device *dev,
1746 + struct device_attribute *attr, char *buffer)
1748 + ssize_t count = 0;
1749 + unsigned int i, num;
1752 + if (!strcmp(attr->attr.name, "als_defaults")) {
1753 + list = sony_als->defaults;
1754 + num = sony_als->defaults_num;
1755 + } else { /* als_backlight_levels */
1756 + list = sony_als->levels;
1757 + num = sony_als->levels_num;
1760 + for (i = 0; i < num; i++)
1761 + count += snprintf(buffer + count, PAGE_SIZE - count,
1762 + "0x%.2x ", list[i]);
1764 + count += snprintf(buffer + count, PAGE_SIZE - count, "\n");
1769 +static ssize_t sony_nc_als_backlight_show(struct device *dev,
1770 + struct device_attribute *attr, char *buffer)
1772 + ssize_t count = 0;
1773 + unsigned int result, cmd;
1775 + cmd = sony_als->handle == 0x0143 ? 0x3100 : 0x0200;
1776 + if (sony_call_snc_handle(sony_als->handle, cmd, &result))
1779 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
1784 +static ssize_t sony_nc_als_backlight_store(struct device *dev,
1785 + struct device_attribute *attr,
1786 + const char *buffer, size_t count)
1788 + unsigned long value;
1789 + unsigned int result, cmd, max = sony_als->levels_num - 1;
1794 + if (strict_strtoul(buffer, 10, &value))
1797 + if (!sony_als->managed)
1800 + /* verify that the provided value falls inside the model
1801 + specific backlight range */
1802 + if ((value < sony_als->levels[0])
1803 + || (value > sony_als->levels[max]))
1806 + cmd = sony_als->handle == 0x0143 ? 0x3000 : 0x0100;
1807 + if (sony_call_snc_handle(sony_als->handle, (value << 0x10) | cmd,
1814 +static ssize_t sony_nc_als_kelvin_show(struct device *dev,
1815 + struct device_attribute *attr, char *buffer)
1817 + ssize_t count = 0;
1818 + unsigned int kelvin = 0;
1820 + if (sony_als->ops->get_kelvin && sony_als->power)
1821 + sony_als->ops->get_kelvin(&kelvin);
1823 + count = snprintf(buffer, PAGE_SIZE, "%d\n", kelvin);
1828 +/* ALS attach/detach functions */
1829 +static int sony_nc_als_setup(struct platform_device *pd, unsigned int handle)
1833 + /* check the device presence */
1834 + if (handle == 0x0137) {
1835 + unsigned int result;
1837 + if (sony_call_snc_handle(handle, 0xB00, &result))
1840 + if (!(result & 0x01)) {
1841 + pr_info("no ALS present\n");
1846 + sony_als = kzalloc(sizeof(struct sony_als_device), GFP_KERNEL);
1850 + /* set model specific data */
1851 + /* if handle 0x012f or 0x0137 use tsl256x_ops, else new als controls */
1852 + if (handle == 0x0143) {
1853 + sony_als->ops = &ngals_ops;
1854 + sony_als->levels_num = 16;
1855 + sony_als->defaults_num = 9;
1857 + sony_als->ops = &tsl256x_ops;
1858 + sony_als->levels_num = 9;
1859 + sony_als->defaults_num = 13;
1861 + /* backlight levels are the first levels_num values, the remaining
1862 + defaults_num values are default settings for als regulation
1864 + sony_als->levels = sony_als->parameters;
1865 + sony_als->defaults = sony_als->parameters + sony_als->levels_num;
1867 + sony_als->handle = handle;
1869 + /* get power state */
1870 + if (sony_als->ops->get_power) {
1871 + if (sony_als->ops->get_power(&sony_als->power))
1872 + pr_warn("unable to retrieve the power status\n");
1875 + /* set managed to 0, userspace daemon should enable it */
1876 + sony_nc_als_managed_set(0);
1878 + /* get ALS parameters */
1879 + if (sony_call_snc_handle_buffer(sony_als->handle, 0x0000,
1880 + sony_als->parameters, ALS_TABLE_SIZE) < 0)
1883 + /* initial device configuration */
1884 + if (sony_als->ops->init)
1885 + if (sony_als->ops->init(sony_als->defaults)) {
1886 + pr_warn("ALS setup failed\n");
1890 + /* set up the sys interface */
1892 + /* notifications and backlight enable control file */
1893 + sysfs_attr_init(&sony_als->attrs[0].attr);
1894 + sony_als->attrs[0].attr.name = "als_managed";
1895 + sony_als->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
1896 + sony_als->attrs[0].show = sony_nc_als_managed_show;
1897 + sony_als->attrs[0].store = sony_nc_als_managed_store;
1898 + /* lux equivalent value */
1899 + sysfs_attr_init(&sony_als->attrs[1].attr);
1900 + sony_als->attrs[1].attr.name = "als_lux";
1901 + sony_als->attrs[1].attr.mode = S_IRUGO;
1902 + sony_als->attrs[1].show = sony_nc_als_lux_show;
1903 + /* ALS default parameters */
1904 + sysfs_attr_init(&sony_als->attrs[2].attr);
1905 + sony_als->attrs[2].attr.name = "als_defaults";
1906 + sony_als->attrs[2].attr.mode = S_IRUGO;
1907 + sony_als->attrs[2].show = sony_nc_als_parameters_show;
1908 + /* ALS default backlight levels */
1909 + sysfs_attr_init(&sony_als->attrs[3].attr);
1910 + sony_als->attrs[3].attr.name = "als_backlight_levels";
1911 + sony_als->attrs[3].attr.mode = S_IRUGO;
1912 + sony_als->attrs[3].show = sony_nc_als_parameters_show;
1913 + /* als backlight control */
1914 + sysfs_attr_init(&sony_als->attrs[4].attr);
1915 + sony_als->attrs[4].attr.name = "als_backlight";
1916 + sony_als->attrs[4].attr.mode = S_IRUGO | S_IWUSR;
1917 + sony_als->attrs[4].show = sony_nc_als_backlight_show;
1918 + sony_als->attrs[4].store = sony_nc_als_backlight_store;
1920 + sony_als->attrs_num = 5;
1921 + /* end mandatory sys interface */
1923 + if (sony_als->ops->get_power || sony_als->ops->set_power) {
1924 + int i = sony_als->attrs_num++;
1926 + /* als power control */
1927 + sysfs_attr_init(&sony_als->attrs[i].attr);
1928 + sony_als->attrs[i].attr.name = "als_power";
1929 + sony_als->attrs[i].attr.mode = S_IRUGO | S_IWUSR;
1930 + sony_als->attrs[i].show = sony_nc_als_power_show;
1931 + sony_als->attrs[i].store = sony_nc_als_power_store;
1934 + if (sony_als->ops->get_kelvin) {
1935 + int i = sony_als->attrs_num++;
1937 + /* light temperature */
1938 + sysfs_attr_init(&sony_als->attrs[i].attr);
1939 + sony_als->attrs[i].attr.name = "als_kelvin";
1940 + sony_als->attrs[i].attr.mode = S_IRUGO;
1941 + sony_als->attrs[i].show = sony_nc_als_kelvin_show;
1944 + /* everything or nothing, otherwise unable to control the ALS */
1945 + for (; i < sony_als->attrs_num; i++) {
1946 + if (device_create_file(&pd->dev, &sony_als->attrs[i]))
1953 + for (; i > 0; i--)
1954 + device_remove_file(&pd->dev, &sony_als->attrs[i]);
1962 +static void sony_nc_als_resume(void)
1964 + if (sony_als->managed) /* it restores the power state too */
1965 + sony_nc_als_managed_set(1);
1966 + else if (sony_als->power)
1967 + sony_nc_als_power_set(1);
1970 +static int sony_nc_als_cleanup(struct platform_device *pd)
1975 + for (i = 0; i < sony_als->attrs_num; i++)
1976 + device_remove_file(&pd->dev, &sony_als->attrs[i]);
1978 + /* disable the events notification */
1979 + if (sony_als->managed)
1980 + if (sony_nc_als_managed_set(0))
1981 + pr_info("ALS notifications disable failed\n");
1983 + if (sony_als->power)
1984 + if (sony_nc_als_power_set(0))
1985 + pr_info("ALS power off failed\n");
1987 + if (sony_als->ops->exit)
1988 + if (sony_als->ops->exit())
1989 + pr_info("ALS device cleaning failed\n");
1999 +/* Keyboard backlight feature */
2000 +static struct sony_kbdbl_data {
2001 + unsigned int handle;
2002 + unsigned int base;
2003 + unsigned int mode;
2004 + unsigned int timeout;
2005 + struct device_attribute mode_attr;
2006 + struct device_attribute timeout_attr;
2009 +static int __sony_nc_kbd_backlight_mode_set(u8 value)
2011 + unsigned int result;
2016 + if (sony_call_snc_handle(sony_kbdbl->handle, (value << 0x10) |
2017 + (sony_kbdbl->base), &result))
2020 + sony_kbdbl->mode = value;
2022 + /* Try to turn the light on/off immediately */
2023 + sony_call_snc_handle(sony_kbdbl->handle, (value << 0x10) |
2024 + (sony_kbdbl->base + 0x100), &result);
2029 +static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
2030 + struct device_attribute *attr,
2031 + const char *buffer, size_t count)
2034 + unsigned long value;
2039 + if (strict_strtoul(buffer, 10, &value))
2042 + ret = __sony_nc_kbd_backlight_mode_set(value);
2049 +static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
2050 + struct device_attribute *attr, char *buffer)
2052 + ssize_t count = 0;
2054 + count = snprintf(buffer, PAGE_SIZE, "%d\n", sony_kbdbl->mode);
2059 +static int __sony_nc_kbd_backlight_timeout_set(u8 value)
2061 + unsigned int result;
2066 + if (sony_call_snc_handle(sony_kbdbl->handle, (value << 0x10) |
2067 + (sony_kbdbl->base + 0x200), &result))
2070 + sony_kbdbl->timeout = value;
2075 +static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
2076 + struct device_attribute *attr,
2077 + const char *buffer, size_t count)
2080 + unsigned long value;
2085 + if (strict_strtoul(buffer, 10, &value))
2088 + ret = __sony_nc_kbd_backlight_timeout_set(value);
2095 +static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
2096 + struct device_attribute *attr, char *buffer)
2098 + ssize_t count = 0;
2100 + count = snprintf(buffer, PAGE_SIZE, "%d\n", sony_kbdbl->timeout);
2105 +static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
2106 + unsigned int handle)
2108 + unsigned int result, base_cmd;
2109 + bool found = false;
2111 + /* verify the kbd backlight presence, some models do not have it */
2112 + if (handle == 0x0137) {
2113 + if (sony_call_snc_handle(handle, 0x0B00, &result))
2116 + found = !!(result & 0x02);
2117 + base_cmd = 0x0C00;
2119 + if (sony_call_snc_handle(handle, 0x0100, &result))
2122 + found = result & 0x01;
2123 + base_cmd = 0x4000;
2127 + dprintk("no backlight keyboard found\n");
2131 + sony_kbdbl = kzalloc(sizeof(*sony_kbdbl), GFP_KERNEL);
2135 + sysfs_attr_init(&sony_kbdbl->mode_attr.attr);
2136 + sony_kbdbl->mode_attr.attr.name = "kbd_backlight";
2137 + sony_kbdbl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2138 + sony_kbdbl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
2139 + sony_kbdbl->mode_attr.store = sony_nc_kbd_backlight_mode_store;
2141 + sysfs_attr_init(&sony_kbdbl->timeout_attr.attr);
2142 + sony_kbdbl->timeout_attr.attr.name = "kbd_backlight_timeout";
2143 + sony_kbdbl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
2144 + sony_kbdbl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
2145 + sony_kbdbl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
2147 + if (device_create_file(&pd->dev, &sony_kbdbl->mode_attr))
2150 + if (device_create_file(&pd->dev, &sony_kbdbl->timeout_attr))
2153 + sony_kbdbl->handle = handle;
2154 + sony_kbdbl->base = base_cmd;
2156 + __sony_nc_kbd_backlight_mode_set(kbd_backlight);
2157 + __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
2162 + device_remove_file(&pd->dev, &sony_kbdbl->mode_attr);
2164 + kfree(sony_kbdbl);
2165 + sony_kbdbl = NULL;
2169 +static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
2172 + unsigned int result;
2174 + device_remove_file(&pd->dev, &sony_kbdbl->mode_attr);
2175 + device_remove_file(&pd->dev, &sony_kbdbl->timeout_attr);
2177 + /* restore the default hw behaviour */
2178 + sony_call_snc_handle(sony_kbdbl->handle,
2179 + sony_kbdbl->base | 0x10000, &result);
2180 + sony_call_snc_handle(sony_kbdbl->handle,
2181 + sony_kbdbl->base + 0x200, &result);
2183 + kfree(sony_kbdbl);
2184 + sony_kbdbl = NULL;
2189 +static void sony_nc_kbd_backlight_resume(void)
2191 + unsigned int result;
2196 + if (sony_kbdbl->mode == 0)
2197 + sony_call_snc_handle(sony_kbdbl->handle,
2198 + sony_kbdbl->base, &result);
2200 + if (sony_kbdbl->timeout != 0)
2201 + sony_call_snc_handle(sony_kbdbl->handle,
2202 + (sony_kbdbl->base + 0x200) |
2203 + (sony_kbdbl->timeout << 0x10), &result);
2206 +/* GSensor, HDD Shock Protection */
2208 + X_AXIS = 4, /* frontal */
2209 + Y_AXIS, /* lateral */
2210 + Z_AXIS /* vertical */
2213 +static struct sony_gsensor_device {
2214 + unsigned int handle;
2215 + unsigned int attrs_num;
2216 + struct device_attribute *attrs;
2219 +/* the EC uses pin #11 of the SATA power connector to command the
2220 + immediate idle feature; however some drives do not implement it
2221 + and pin #11 is NC. Let's verify, otherwise no automatic
2222 + protection is possible by the hardware
2224 +static int sony_nc_gsensor_support_get(unsigned int *support)
2226 + unsigned int result;
2228 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2231 + *support = sony_gsensor->handle == 0x0134
2232 + ? !!(result & 0x20)
2233 + : !!(result & 0x01);
2238 +static int sony_nc_gsensor_status_set(int value)
2240 + unsigned int result, capable, reg, arg;
2241 + bool update = false;
2243 + if (sony_nc_gsensor_support_get(&capable))
2247 + pr_warn("hardware protection not available, the HDD"
2248 + " do not support this feature\n");
2250 + /* do not return immediately even though there is no HW
2251 + * capability, userspace can thus receive the shock
2252 + * notifications and call the ATA7 immediate idle command to
2253 + * unload the heads. Just return after enabling notifications
2255 + reg = sony_gsensor->handle == 0x0134 ?
2256 + (!value << 0x08) : (value << 0x10);
2258 + if (sony_call_snc_handle(sony_gsensor->handle, reg, &result))
2264 + /* if the requested protection setting is different
2265 + from the current one
2267 + reg = sony_gsensor->handle == 0x0134 ? 0x0200 : 0x0400;
2268 + if (sony_call_snc_handle(sony_gsensor->handle, reg, &result))
2271 + if (sony_gsensor->handle == 0x0134) {
2272 + if (!!(result & 0x04) != value) {
2273 + arg = (result & 0x1B) | (value << 0x02);
2277 + if ((result & 0x01) != value) {
2283 + if (update && sony_call_snc_handle(sony_gsensor->handle,
2284 + (arg << 0x10) | 0x0300, &result))
2290 +static int sony_nc_gsensor_axis_get(enum axis name)
2292 + unsigned int result;
2294 + if (sony_call_snc_handle(sony_gsensor->handle, name << 0x08, &result))
2300 +/* G sensor sys interface */
2301 +static ssize_t sony_nc_gsensor_type_show(struct device *dev,
2302 + struct device_attribute *attr, char *buffer)
2304 + ssize_t count = 0;
2305 + unsigned int result;
2307 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2310 + count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 0x03) & 0x03);
2315 +static ssize_t sony_nc_gsensor_type_store(struct device *dev,
2316 + struct device_attribute *attr,
2317 + const char *buffer, size_t count)
2320 + * axis out type control file:
2321 + * 0: raw values, 1: acc values 2: threshold values
2323 + unsigned int result;
2324 + unsigned long value;
2326 + /* sanity checks and conversion */
2327 + if (count > 31 || strict_strtoul(buffer, 10, &value) || value > 2)
2332 + /* retrieve the current state / settings */
2333 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2336 + if ((result & 0x18) != value) {
2337 + /* the last 3 bits need to be preserved */
2338 + value |= (result & 0x07);
2340 + if (sony_call_snc_handle(sony_gsensor->handle,
2341 + (value << 0x10) | 0x0300, &result))
2348 +static ssize_t sony_nc_gsensor_axis_show(struct device *dev,
2349 + struct device_attribute *attr, char *buffer)
2351 + ssize_t count = 0;
2352 + unsigned int result;
2355 + /* file being read for axis selection */
2356 + if (!strcmp(attr->attr.name, "gsensor_xval"))
2358 + else if (!strcmp(attr->attr.name, "gsensor_yval"))
2360 + else if (!strcmp(attr->attr.name, "gsensor_zval"))
2365 + result = sony_nc_gsensor_axis_get(arg);
2369 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
2374 +static ssize_t sony_nc_gsensor_status_show(struct device *dev,
2375 + struct device_attribute *attr, char *buffer)
2377 + ssize_t count = 0;
2378 + unsigned int result;
2380 + if (sony_gsensor->handle == 0x0134) {
2381 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200,
2385 + result = !!(result & 0x04);
2387 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0400,
2394 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
2399 +static ssize_t sony_nc_gsensor_status_store(struct device *dev,
2400 + struct device_attribute *attr,
2401 + const char *buffer, size_t count)
2404 + unsigned long value;
2408 + if (strict_strtoul(buffer, 10, &value) || value > 1)
2411 + ret = sony_nc_gsensor_status_set(value);
2418 +static ssize_t sony_nc_gsensor_sensitivity_show(struct device *dev,
2419 + struct device_attribute *attr, char *buffer)
2421 + ssize_t count = 0;
2422 + unsigned int result;
2424 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2427 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x03);
2431 +static ssize_t sony_nc_gsensor_sensitivity_store(struct device *dev,
2432 + struct device_attribute *attr,
2433 + const char *buffer, size_t count)
2435 + unsigned int result;
2436 + unsigned long value;
2440 + if (strict_strtoul(buffer, 10, &value) || value > 2)
2443 + /* retrieve the other parameters to be stored as well */
2444 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2446 + value |= (result & 0x1C); /* preserve only the needed bits */
2448 + if (sony_call_snc_handle(sony_gsensor->handle, (value << 0x10)
2449 + | 0x0300, &result))
2455 +static int sony_nc_gsensor_setup(struct platform_device *pd,
2456 + unsigned int handle)
2458 + int i, enable, support;
2460 + sony_gsensor = kzalloc(sizeof(struct sony_gsensor_device), GFP_KERNEL);
2461 + if (!sony_gsensor)
2464 + sony_gsensor->handle = handle;
2465 + sony_gsensor->attrs_num = handle == 0x0134 ? 6 : 1;
2467 + sony_gsensor->attrs = kzalloc(sizeof(struct device_attribute)
2468 + * sony_gsensor->attrs_num, GFP_KERNEL);
2469 + if (!sony_gsensor->attrs)
2472 + /* check the storing device support */
2473 + if (sony_nc_gsensor_support_get(&support))
2476 + /* enable the HDD protection and notification by default
2477 + when hardware driven protection is possible */
2478 + enable = support ? 1 : force_shock_notifications;
2479 + if (sony_nc_gsensor_status_set(enable))
2481 + pr_warn("failed to enable the HDD shock protection\n");
2483 + /* activation control */
2484 + sysfs_attr_init(&sony_gsensor->attrs[0].attr);
2485 + sony_gsensor->attrs[0].attr.name = "gsensor_protection";
2486 + sony_gsensor->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2487 + sony_gsensor->attrs[0].show = sony_nc_gsensor_status_show;
2488 + sony_gsensor->attrs[0].store = sony_nc_gsensor_status_store;
2490 + if (sony_gsensor->attrs_num > 1) {
2491 + /* sensitivity selection */
2492 + sysfs_attr_init(&sony_gsensor->attrs[1].attr);
2493 + sony_gsensor->attrs[1].attr.name = "gsensor_sensitivity";
2494 + sony_gsensor->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
2495 + sony_gsensor->attrs[1].show = sony_nc_gsensor_sensitivity_show;
2496 + sony_gsensor->attrs[1].store =
2497 + sony_nc_gsensor_sensitivity_store;
2498 + /* x/y/z output selection */
2499 + sysfs_attr_init(&sony_gsensor->attrs[2].attr);
2500 + sony_gsensor->attrs[2].attr.name = "gsensor_val_type";
2501 + sony_gsensor->attrs[2].attr.mode = S_IRUGO | S_IWUSR;
2502 + sony_gsensor->attrs[2].show = sony_nc_gsensor_type_show;
2503 + sony_gsensor->attrs[2].store = sony_nc_gsensor_type_store;
2505 + sysfs_attr_init(&sony_gsensor->attrs[3].attr);
2506 + sony_gsensor->attrs[3].attr.name = "gsensor_xval";
2507 + sony_gsensor->attrs[3].attr.mode = S_IRUGO;
2508 + sony_gsensor->attrs[3].show = sony_nc_gsensor_axis_show;
2510 + sysfs_attr_init(&sony_gsensor->attrs[4].attr);
2511 + sony_gsensor->attrs[4].attr.name = "gsensor_yval";
2512 + sony_gsensor->attrs[4].attr.mode = S_IRUGO;
2513 + sony_gsensor->attrs[4].show = sony_nc_gsensor_axis_show;
2515 + sysfs_attr_init(&sony_gsensor->attrs[5].attr);
2516 + sony_gsensor->attrs[5].attr.name = "gsensor_zval";
2517 + sony_gsensor->attrs[5].attr.mode = S_IRUGO;
2518 + sony_gsensor->attrs[5].show = sony_nc_gsensor_axis_show;
2521 + for (i = 0; i < sony_gsensor->attrs_num; i++) {
2522 + if (device_create_file(&pd->dev, &sony_gsensor->attrs[i]))
2529 + for (; i > 0; i--)
2530 + device_remove_file(&pd->dev, &sony_gsensor->attrs[i]);
2532 + kfree(sony_gsensor->attrs);
2534 + kfree(sony_gsensor);
2535 + sony_gsensor = NULL;
2540 +static int sony_nc_gsensor_cleanup(struct platform_device *pd)
2542 + if (sony_gsensor) {
2543 + unsigned int i, result, reg;
2545 + for (i = 0; i < sony_gsensor->attrs_num; i++)
2546 + device_remove_file(&pd->dev, &sony_gsensor->attrs[i]);
2548 + /* disable the event generation,
2549 + * preserve any other setting
2551 + reg = sony_gsensor->handle == 0x0134 ? 0x0100 : 0x0000;
2553 + sony_call_snc_handle(sony_gsensor->handle, reg, &result);
2555 + kfree(sony_gsensor->attrs);
2556 + kfree(sony_gsensor);
2557 + sony_gsensor = NULL;
2562 +/* end G sensor code */
2564 +static struct sony_battcare_data {
2565 + unsigned int handle;
2566 + struct device_attribute attrs[2];
2569 +static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
2570 + struct device_attribute *attr,
2571 + const char *buffer, size_t count)
2573 + unsigned int result, cmd;
2574 + unsigned long value;
2578 + if (strict_strtoul(buffer, 10, &value))
2581 + /* limit values (2 bits):
2587 + * bit 0: 0 disable BCL, 1 enable BCL
2588 + * bit 1: 1 tell to store the battery limit (see bits 6,7) too
2589 + * bits 2,3: reserved
2590 + * bits 4,5: store the limit into the EC
2591 + * bits 6,7: store the limit into the battery
2595 + * handle 0x0115 should allow storing on battery too;
2596 + * handle 0x0136 same as 0x0115 + health status;
2597 + * handle 0x013f, same as 0x0136 but no storing on the battery
2599 + * Store only inside the EC for now, regardless the handle number
2602 + case 0: /* disable */
2605 + case 1: /* enable, 80% charge limit */
2608 + case 2: /* enable, 50% charge limit */
2615 + if (sony_call_snc_handle(sony_battcare->handle, (cmd << 0x10) | 0x0100,
2622 +static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
2623 + struct device_attribute *attr, char *buffer)
2625 + ssize_t count = 0;
2626 + unsigned int result, status;
2628 + if (sony_call_snc_handle(sony_battcare->handle, 0x0000, &result))
2631 + /* if disabled 0, else take the limit bits */
2632 + status = !(result & 0x01) ? 0 : ((result & 0x30) >> 0x04);
2634 + count = snprintf(buffer, PAGE_SIZE, "%d\n", status);
2638 +static ssize_t sony_nc_battery_care_health_show(struct device *dev,
2639 + struct device_attribute *attr, char *buffer)
2641 + ssize_t count = 0;
2642 + unsigned int health;
2644 + if (sony_call_snc_handle(sony_battcare->handle, 0x0200, &health))
2647 + count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
2652 +static int sony_nc_battery_care_setup(struct platform_device *pd,
2653 + unsigned int handle)
2655 + sony_battcare = kzalloc(sizeof(struct sony_battcare_data), GFP_KERNEL);
2656 + if (!sony_battcare)
2659 + sony_battcare->handle = handle;
2661 + sysfs_attr_init(&sony_battcare->attrs[0].attr);
2662 + sony_battcare->attrs[0].attr.name = "battery_care_limiter";
2663 + sony_battcare->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
2664 + sony_battcare->attrs[0].show = sony_nc_battery_care_limit_show;
2665 + sony_battcare->attrs[0].store = sony_nc_battery_care_limit_store;
2667 + if (device_create_file(&pd->dev, &sony_battcare->attrs[0]))
2670 + if (handle == 0x0115) /* no health indication */
2673 + sysfs_attr_init(&sony_battcare->attrs[1].attr);
2674 + sony_battcare->attrs[1].attr.name = "battery_care_health";
2675 + sony_battcare->attrs[1].attr.mode = S_IRUGO;
2676 + sony_battcare->attrs[1].show = sony_nc_battery_care_health_show;
2678 + if (device_create_file(&pd->dev, &sony_battcare->attrs[1]))
2684 + device_remove_file(&pd->dev, &sony_battcare->attrs[0]);
2686 + kfree(sony_battcare);
2687 + sony_battcare = NULL;
2692 +static int sony_nc_battery_care_cleanup(struct platform_device *pd)
2694 + if (sony_battcare) {
2695 + device_remove_file(&pd->dev, &sony_battcare->attrs[0]);
2696 + if (sony_battcare->handle != 0x0115)
2697 + device_remove_file(&pd->dev, &sony_battcare->attrs[1]);
2699 + kfree(sony_battcare);
2700 + sony_battcare = NULL;
2706 +static struct sony_thermal_data {
2707 + unsigned int mode;
2708 + unsigned int profiles;
2709 + struct device_attribute mode_attr;
2710 + struct device_attribute profiles_attr;
2713 +static int sony_nc_thermal_mode_set(unsigned int profile)
2715 + unsigned int cmd, result;
2717 + /* to avoid the 1 value hole when only 2 profiles are available */
2718 + switch (profile) {
2719 + case 1: /* performance */
2722 + case 2: /* silent */
2725 + default: /* balanced */
2730 + if (sony_call_snc_handle(0x0122, cmd << 0x10 | 0x0200, &result))
2733 + sony_thermal->mode = profile;
2738 +static int sony_nc_thermal_mode_get(unsigned int *profile)
2740 + unsigned int result;
2742 + if (sony_call_snc_handle(0x0122, 0x0100, &result))
2745 + /* to avoid the 1 value hole when only 2 profiles are available */
2746 + switch (result & 0xff) {
2747 + case 2: /* performance */
2750 + case 1: /* silent */
2753 + default: /* balanced */
2761 +static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
2762 + struct device_attribute *attr, char *buffer)
2764 + return snprintf(buffer, PAGE_SIZE, "%u\n", sony_thermal->profiles);
2767 +static ssize_t sony_nc_thermal_mode_store(struct device *dev,
2768 + struct device_attribute *attr,
2769 + const char *buffer, size_t count)
2771 + unsigned long value;
2775 + if (strict_strtoul(buffer, 10, &value) ||
2776 + value > (sony_thermal->profiles - 1))
2779 + if (sony_nc_thermal_mode_set(value))
2785 +static ssize_t sony_nc_thermal_mode_show(struct device *dev,
2786 + struct device_attribute *attr, char *buffer)
2788 + ssize_t count = 0;
2789 + unsigned int profile;
2791 + if (sony_nc_thermal_mode_get(&profile))
2794 + count = snprintf(buffer, PAGE_SIZE, "%d\n", profile);
2799 +static int sony_nc_thermal_setup(struct platform_device *pd)
2801 + sony_thermal = kzalloc(sizeof(struct sony_thermal_data), GFP_KERNEL);
2802 + if (!sony_thermal)
2805 + if (sony_call_snc_handle(0x0122, 0x0000, &sony_thermal->profiles)) {
2806 + pr_warn("unable to retrieve the available profiles\n");
2810 + if (sony_nc_thermal_mode_get(&sony_thermal->mode)) {
2811 + pr_warn("unable to retrieve the current profile");
2815 + sysfs_attr_init(&sony_thermal->profiles_attr.attr);
2816 + sony_thermal->profiles_attr.attr.name = "thermal_profiles";
2817 + sony_thermal->profiles_attr.attr.mode = S_IRUGO;
2818 + sony_thermal->profiles_attr.show = sony_nc_thermal_profiles_show;
2820 + sysfs_attr_init(&sony_thermal->mode_attr.attr);
2821 + sony_thermal->mode_attr.attr.name = "thermal_control";
2822 + sony_thermal->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
2823 + sony_thermal->mode_attr.show = sony_nc_thermal_mode_show;
2824 + sony_thermal->mode_attr.store = sony_nc_thermal_mode_store;
2826 + if (device_create_file(&pd->dev, &sony_thermal->profiles_attr))
2829 + if (device_create_file(&pd->dev, &sony_thermal->mode_attr))
2835 + device_remove_file(&pd->dev, &sony_thermal->profiles_attr);
2837 + kfree(sony_thermal);
2838 + sony_thermal = NULL;
2842 +static int sony_nc_thermal_cleanup(struct platform_device *pd)
2844 + if (sony_thermal) {
2845 + device_remove_file(&pd->dev, &sony_thermal->profiles_attr);
2846 + device_remove_file(&pd->dev, &sony_thermal->mode_attr);
2847 + kfree(sony_thermal);
2848 + sony_thermal = NULL;
2854 +static void sony_nc_thermal_resume(void)
2856 + unsigned int status;
2858 + sony_nc_thermal_mode_get(&status);
2860 + if (status != sony_thermal->mode)
2861 + sony_nc_thermal_mode_set(sony_thermal->mode);
2864 +static struct device_attribute *sony_lid;
2866 +static ssize_t sony_nc_lid_resume_store(struct device *dev,
2867 + struct device_attribute *attr,
2868 + const char *buffer, size_t count)
2870 + unsigned int result;
2871 + unsigned long value;
2875 + if (strict_strtoul(buffer, 10, &value) || value > 3)
2879 + 01 <- resume from S4
2880 + 10 <- resume from S3
2881 + 11 <- resume from S4 and S3
2883 + /* we must set bit 1 and 2 (bit 0 is for S5), so shift one bit more */
2884 + if (sony_call_snc_handle(0x0119, value << 0x11 | 0x0100, &result))
2890 +static ssize_t sony_nc_lid_resume_show(struct device *dev,
2891 + struct device_attribute *attr, char *buffer)
2893 + ssize_t count = 0;
2894 + unsigned int result;
2896 + if (sony_call_snc_handle(0x0119, 0x0000, &result))
2899 + count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 1) & 0x03);
2904 +static int sony_nc_lid_resume_setup(struct platform_device *pd)
2906 + sony_lid = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2910 + sysfs_attr_init(&sony_lid->attr);
2911 + sony_lid->attr.name = "lid_resume_control";
2912 + sony_lid->attr.mode = S_IRUGO | S_IWUSR;
2913 + sony_lid->show = sony_nc_lid_resume_show;
2914 + sony_lid->store = sony_nc_lid_resume_store;
2916 + if (device_create_file(&pd->dev, sony_lid)) {
2925 +static int sony_nc_lid_resume_cleanup(struct platform_device *pd)
2928 + device_remove_file(&pd->dev, sony_lid);
2936 +static struct device_attribute *sony_hsc;
2938 +static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
2939 + struct device_attribute *attr,
2940 + const char *buffer, size_t count)
2942 + unsigned int result;
2943 + unsigned long value;
2947 + if (strict_strtoul(buffer, 10, &value) || value > 1)
2950 + if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2956 +static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
2957 + struct device_attribute *attr, char *buffer)
2959 + ssize_t count = 0;
2960 + unsigned int result;
2962 + if (sony_call_snc_handle(0x0131, 0x0100, &result))
2965 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2970 +static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
2972 + unsigned int result;
2974 + if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
2975 + pr_info("no High Speed Charging capability found\n");
2979 + sony_hsc = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2983 + sysfs_attr_init(&sony_hsc->attr);
2984 + sony_hsc->attr.name = "battery_highspeed_charging";
2985 + sony_hsc->attr.mode = S_IRUGO | S_IWUSR;
2986 + sony_hsc->show = sony_nc_highspeed_charging_show;
2987 + sony_hsc->store = sony_nc_highspeed_charging_store;
2989 + if (device_create_file(&pd->dev, sony_hsc)) {
2998 +static int sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
3001 + device_remove_file(&pd->dev, sony_hsc);
3009 +static struct sony_tpad_device {
3010 + unsigned int handle;
3011 + struct device_attribute attr;
3014 +static ssize_t sony_nc_touchpad_store(struct device *dev,
3015 + struct device_attribute *attr,
3016 + const char *buffer, size_t count)
3018 + unsigned int result;
3019 + unsigned long value;
3023 + if (strict_strtoul(buffer, 10, &value) || value > 1)
3026 + /* sysfs: 0 disabled, 1 enabled; EC: 0 enabled, 1 disabled */
3027 + if (sony_call_snc_handle(sony_tpad->handle,
3028 + (!value << 0x10) | 0x100, &result))
3034 +static ssize_t sony_nc_touchpad_show(struct device *dev,
3035 + struct device_attribute *attr, char *buffer)
3037 + ssize_t count = 0;
3038 + unsigned int result;
3040 + if (sony_call_snc_handle(sony_tpad->handle, 0x000, &result))
3043 + /* 1 tpad off, 0 tpad on */
3044 + count = snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
3048 +static int sony_nc_touchpad_setup(struct platform_device *pd,
3049 + unsigned int handle)
3051 + sony_tpad = kzalloc(sizeof(struct sony_tpad_device), GFP_KERNEL);
3055 + sony_tpad->handle = handle;
3057 + sysfs_attr_init(&sony_tpad->attr.attr);
3058 + sony_tpad->attr.attr.name = "touchpad";
3059 + sony_tpad->attr.attr.mode = S_IRUGO | S_IWUSR;
3060 + sony_tpad->attr.show = sony_nc_touchpad_show;
3061 + sony_tpad->attr.store = sony_nc_touchpad_store;
3063 + if (device_create_file(&pd->dev, &sony_tpad->attr)) {
3072 +static int sony_nc_touchpad_cleanup(struct platform_device *pd)
3075 + device_remove_file(&pd->dev, &sony_tpad->attr);
3083 +#define SONY_FAN_HANDLE 0x0149
3084 +#define FAN_SPEEDS_NUM 4 /* leave some more room */
3085 +#define FAN_ATTRS_NUM 3
3086 +static struct sony_fan_device {
3087 + unsigned int speeds_num;
3088 + unsigned int speeds[4];
3089 + struct device_attribute attrs[3];
3092 +static ssize_t sony_nc_fan_control_store(struct device *dev,
3093 + struct device_attribute *attr,
3094 + const char *buffer, size_t count)
3096 + unsigned int result;
3097 + unsigned long value;
3101 + if (strict_strtoul(buffer, 10, &value)
3102 + || value > sony_fan->speeds_num)
3105 + if (sony_call_snc_handle(SONY_FAN_HANDLE,
3106 + (value << 0x10) | 0x0200, &result))
3112 +static ssize_t sony_nc_fan_control_show(struct device *dev,
3113 + struct device_attribute *attr, char *buffer)
3115 + ssize_t count = 0;
3116 + unsigned int result;
3118 + if (sony_call_snc_handle(SONY_FAN_HANDLE, 0x0100, &result))
3121 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
3125 +static ssize_t sony_nc_fan_profiles_show(struct device *dev,
3126 + struct device_attribute *attr, char *buffer)
3128 + ssize_t count = 0;
3131 + for (i = 0; i < sony_fan->speeds_num; i++)
3132 + count += snprintf(buffer + count, PAGE_SIZE - count,
3133 + "%.4u ", sony_fan->speeds[i] * 100);
3135 + count += snprintf(buffer + count, PAGE_SIZE - count, "\n");
3140 +static ssize_t sony_nc_fan_speed_show(struct device *dev,
3141 + struct device_attribute *attr, char *buffer)
3143 + ssize_t count = 0;
3144 + unsigned int result;
3146 + if (sony_call_snc_handle(SONY_FAN_HANDLE, 0x0300, &result))
3149 + count = snprintf(buffer, PAGE_SIZE, "%d\n",
3150 + (result & 0xff) * 100);
3154 +static int sony_nc_fan_setup(struct platform_device *pd)
3157 + unsigned int i, found;
3158 + u8 list[FAN_SPEEDS_NUM * 2] = { 0 };
3160 + sony_fan = kzalloc(sizeof(struct sony_fan_device), GFP_KERNEL);
3164 + ret = sony_call_snc_handle_buffer(SONY_FAN_HANDLE, 0x0000,
3165 + list, FAN_SPEEDS_NUM * 2);
3167 + pr_info("unable to retrieve fan profiles table\n");
3169 + for (i = 0, found = 0;
3170 + list[i] != 0 && found < FAN_SPEEDS_NUM; i += 2, found++) {
3172 + sony_fan->speeds[found] = list[i+1];
3174 + sony_fan->speeds_num = found;
3176 + sysfs_attr_init(&sony_fan->attrs[0].attr);
3177 + sony_fan->attrs[0].attr.name = "fan_speed";
3178 + sony_fan->attrs[0].attr.mode = S_IRUGO;
3179 + sony_fan->attrs[0].show = sony_nc_fan_speed_show;
3181 + sysfs_attr_init(&sony_fan->attrs[1].attr);
3182 + sony_fan->attrs[1].attr.name = "fan_profiles";
3183 + sony_fan->attrs[1].attr.mode = S_IRUGO;
3184 + sony_fan->attrs[1].show = sony_nc_fan_profiles_show;
3186 + sysfs_attr_init(&sony_fan->attrs[2].attr);
3187 + sony_fan->attrs[2].attr.name = "fan_control";
3188 + sony_fan->attrs[2].attr.mode = S_IRUGO | S_IWUSR;
3189 + sony_fan->attrs[2].show = sony_nc_fan_control_show;
3190 + sony_fan->attrs[2].store = sony_nc_fan_control_store;
3192 + for (i = 0; i < FAN_ATTRS_NUM; i++) {
3193 + if (device_create_file(&pd->dev, &sony_fan->attrs[i]))
3200 + for (; i > 0; i--)
3201 + device_remove_file(&pd->dev, &sony_fan->attrs[i]);
3209 +static int sony_nc_fan_cleanup(struct platform_device *pd)
3214 + for (i = 0; i < FAN_ATTRS_NUM; i++)
3215 + device_remove_file(&pd->dev, &sony_fan->attrs[i]);
3224 +static struct sony_odd_device {
3225 + unsigned int vendor_id;
3226 + unsigned int model_id;
3227 + struct device_attribute status_attr;
3231 +static int sony_nc_odd_remove(void)
3234 + 0 - change the link state first?
3235 + 1 - scsi lookup searching for the optical device (scsi_device *)
3236 + 2 - call int scsi_remove_device(struct scsi_device *sdev)
3239 + struct scsi_device *sdev;
3240 + struct Scsi_Host *shost;
3241 + int error = -ENXIO;
3243 + shost = scsi_host_lookup(host);
3247 + sdev = scsi_device_lookup(shost, channel, id, lun);
3249 + scsi_remove_device(sdev);
3250 + scsi_device_put(sdev);
3254 + scsi_host_put(shost);
3260 +static ssize_t sony_nc_odd_status_store(struct device *dev,
3261 + struct device_attribute *attr,
3262 + const char *buffer, size_t count)
3264 + unsigned int result;
3265 + unsigned long value;
3269 + if (strict_strtoul(buffer, 10, &value) || value > 1)
3274 + sony_nc_odd_remove();
3276 + /* and goes on, otherwise leave */
3279 + /* 0x200 turn on (sysfs: 1), 0x300 turn off (sysfs: 0) */
3280 + value = (!value << 0x08) + 0x200;
3282 + /* the MSB have to be high */
3283 + if (sony_call_snc_handle(0x126, (1 << 0x10) | value, &result))
3288 + /* force a bus scan? */
3294 +static ssize_t sony_nc_odd_status_show(struct device *dev,
3295 + struct device_attribute *attr, char *buffer)
3297 + ssize_t count = 0;
3298 + unsigned int result;
3300 + if (sony_call_snc_handle(0x126, 0x100, &result))
3303 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
3307 +static int sony_nc_odd_setup(struct platform_device *pd)
3309 +#define ODD_TAB_SIZE 32
3310 + u8 list[ODD_TAB_SIZE] = { 0 };
3314 + unsigned int vendor = 0;
3315 + unsigned int model = 0;
3318 + ret = sony_call_snc_handle_buffer(0x126, 0x0000, list, ODD_TAB_SIZE);
3320 + pr_info("unable to retrieve the odd table\n");
3324 + /* parse the table looking for optical devices */
3326 + word = (list[i+1] << 8) | list[i];
3328 + if (word == 1) { /* 1 DWord device data following */
3329 + vendor = (list[i+3] << 8) | list[i+2];
3330 + model = (list[i+5] << 8) | list[i+4];
3336 + } while (word != 0xff00);
3339 + dprintk("one optical device found, connected to: %x:%x\n",
3344 + sony_odd = kzalloc(sizeof(*sony_odd), GFP_KERNEL);
3348 + sony_odd->vendor_id = vendor;
3349 + sony_odd->model_id = model;
3351 + sysfs_attr_init(&sony_odd->status_attr.attr);
3352 + sony_odd->status_attr.attr.name = "odd_power";
3353 + sony_odd->status_attr.attr.mode = S_IRUGO | S_IWUSR;
3354 + sony_odd->status_attr.show = sony_nc_odd_status_show;
3355 + sony_odd->status_attr.store = sony_nc_odd_status_store;
3357 + if (device_create_file(&pd->dev, &sony_odd->status_attr)) {
3366 +static int sony_nc_odd_cleanup(struct platform_device *pd)
3369 + device_remove_file(&pd->dev, &sony_odd->status_attr);
3378 + * Backlight device
3380 +static struct backlight_device *sony_backlight_device;
3382 +static int sony_backlight_update_status(struct backlight_device *bd)
3384 + return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
3385 + bd->props.brightness + 1, NULL);
3388 +static int sony_backlight_get_brightness(struct backlight_device *bd)
3390 + unsigned int value;
3392 + if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
3394 + /* brightness levels are 1-based, while backlight ones are 0-based */
3398 +static const struct backlight_ops sony_backlight_ops = {
3399 + .options = BL_CORE_SUSPENDRESUME,
3400 + .update_status = sony_backlight_update_status,
3401 + .get_brightness = sony_backlight_get_brightness,
3403 +static const struct backlight_ops sony_als_backlight_ops = {
3404 + .options = BL_CORE_SUSPENDRESUME,
3405 + .update_status = sony_nc_als_update_status,
3406 + .get_brightness = sony_nc_als_get_brightness,
3409 +static void sony_nc_backlight_setup(void)
3411 + acpi_handle unused;
3412 + int max_brightness = 0;
3413 + const struct backlight_ops *ops = NULL;
3414 + struct backlight_properties props;
3416 + /* do not use SNC GBRT/SBRT controls along with the ALS */
3418 + /* ALS based backlight device */
3419 + ops = &sony_als_backlight_ops;
3420 + max_brightness = sony_als->levels_num - 1;
3421 + } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
3423 + ops = &sony_backlight_ops;
3424 + max_brightness = SONY_MAX_BRIGHTNESS - 1;
3429 + memset(&props, 0, sizeof(struct backlight_properties));
3430 + props.type = BACKLIGHT_PLATFORM;
3431 + props.max_brightness = max_brightness;
3432 + sony_backlight_device = backlight_device_register("sony", NULL, NULL,
3435 + if (IS_ERR(sony_backlight_device)) {
3436 + pr_warn("unable to register backlight device\n");
3437 + sony_backlight_device = NULL;
3439 + sony_backlight_device->props.brightness =
3440 + ops->get_brightness(sony_backlight_device);
3444 +static void sony_nc_backlight_cleanup(void)
3446 + if (sony_backlight_device)
3447 + backlight_device_unregister(sony_backlight_device);
3450 +static void sony_nc_tests_resume(void)
3455 +/* place here some unknown handles, we might want to see some output */
3456 +static void sony_nc_tests_setup(void)
3459 + unsigned int result;
3462 + ret = sony_call_snc_handle(0x114, 0x000, &result);
3464 + pr_info("handle 0x114 returned: %x\n", result & 0xff);
3467 + ret = sony_call_snc_handle(0x139, 0x0000, &result);
3469 + pr_info("handle 0x139+00 returned: %x\n", result & 0xffff);
3472 + ret = sony_call_snc_handle(0x139, 0x0100, &result);
3474 + pr_info("handle 0x139+01 returned: %x\n", result & 0xffff);
3479 +static void sony_nc_snc_setup_handles(struct platform_device *pd)
3483 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
3485 + int unsigned handle = handles->cap[i];
3490 + dprintk("looking at handle 0x%.4x\n", handle);
3497 + ret = sony_nc_function_setup(handle);
3500 + case 0x0148: /* same as 0x0105 + Fn-F1 combo */
3501 + ret = sony_nc_touchpad_setup(pd, handle);
3506 + ret = sony_nc_battery_care_setup(pd, handle);
3509 + ret = sony_nc_lid_resume_setup(pd);
3512 + ret = sony_nc_thermal_setup(pd);
3515 + ret = sony_nc_odd_setup(pd);
3519 + ret = sony_nc_kbd_backlight_setup(pd, handle);
3520 + case 0x012f: /* no keyboard backlight */
3521 + ret = sony_nc_als_setup(pd, handle);
3524 + ret = sony_nc_highspeed_charging_setup(pd);
3528 + ret = sony_nc_gsensor_setup(pd, handle);
3531 + ret = sony_nc_fan_setup(pd);
3535 + ret = sony_nc_rfkill_setup(sony_nc_acpi_device, handle);
3542 + pr_warn("handle 0x%.4x setup failed (ret: %i)",
3545 + dprintk("handle 0x%.4x setup completed\n", handle);
3550 - kfree(buffer.pointer);
3553 + sony_nc_tests_setup();
3556 -/* Keyboard backlight feature */
3557 -#define KBDBL_HANDLER 0x137
3558 -#define KBDBL_PRESENT 0xB00
3559 -#define SET_MODE 0xC00
3560 -#define SET_STATE 0xD00
3561 -#define SET_TIMEOUT 0xE00
3563 -struct kbd_backlight {
3566 - struct device_attribute mode_attr;
3567 - struct device_attribute timeout_attr;
3570 -static struct kbd_backlight *kbdbl_handle;
3572 -static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
3573 +static void sony_nc_snc_cleanup_handles(struct platform_device *pd)
3580 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
3582 - if (sony_call_snc_handle(KBDBL_HANDLER,
3583 - (value << 0x10) | SET_MODE, &result))
3585 + int unsigned handle = handles->cap[i];
3587 - /* Try to turn the light on/off immediately */
3588 - sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
3593 - kbdbl_handle->mode = value;
3594 + dprintk("looking at handle 0x%.4x\n", handle);
3600 + sony_nc_touchpad_cleanup(pd);
3605 + sony_nc_battery_care_cleanup(pd);
3608 + sony_nc_lid_resume_cleanup(pd);
3611 + sony_nc_thermal_cleanup(pd);
3614 + sony_nc_odd_cleanup(pd);
3618 + sony_nc_kbd_backlight_cleanup(pd);
3620 + sony_nc_als_cleanup(pd);
3623 + sony_nc_highspeed_charging_cleanup(pd);
3627 + sony_nc_gsensor_cleanup(pd);
3630 + sony_nc_fan_cleanup(pd);
3634 + sony_nc_rfkill_cleanup();
3640 + dprintk("handle 0x%.4x deconfigured\n", handle);
3644 -static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
3645 - struct device_attribute *attr,
3646 - const char *buffer, size_t count)
3647 +static int sony_nc_snc_setup(struct platform_device *pd)
3650 - unsigned long value;
3655 - if (strict_strtoul(buffer, 10, &value))
3657 + unsigned int i, string[4], bitmask, result;
3659 - ret = __sony_nc_kbd_backlight_mode_set(value);
3662 + for (i = 0; i < 4; i++) {
3663 + if (acpi_callsetfunc(sony_nc_acpi_handle,
3664 + "SN00", i, &string[i]))
3667 + if (strncmp("SncSupported", (char *) string, 0x10)) {
3668 + pr_info("SNC device present but not supported by hardware");
3674 + if (!acpi_callsetfunc(sony_nc_acpi_handle, "SN00", 0x04, &result)) {
3675 + unsigned int model, i;
3676 + for (model = 0, i = 0; i < 4; i++)
3677 + model |= ((result >> (i * 8)) & 0xff) << ((3 - i) * 8);
3678 + pr_info("found Vaio model ID: %u\n", model);
3681 -static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
3682 - struct device_attribute *attr, char *buffer)
3684 - ssize_t count = 0;
3685 - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
3688 + /* retrieve the implemented offsets mask */
3689 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN00", 0x10, &bitmask))
3692 -static int __sony_nc_kbd_backlight_timeout_set(u8 value)
3695 + /* retrieve the available handles, otherwise return */
3696 + if (sony_nc_handles_setup(pd))
3701 + /* setup found handles here */
3702 + sony_nc_snc_setup_handles(pd);
3704 - if (sony_call_snc_handle(KBDBL_HANDLER,
3705 - (value << 0x10) | SET_TIMEOUT, &result))
3706 + /* Enable all events for the found handles, otherwise return */
3707 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", bitmask, &result))
3710 - kbdbl_handle->timeout = value;
3711 + /* check for SN05 presence? */
3716 -static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
3717 - struct device_attribute *attr,
3718 - const char *buffer, size_t count)
3719 +static int sony_nc_snc_cleanup(struct platform_device *pd)
3722 - unsigned long value;
3723 + unsigned int result, bitmask;
3727 + /* retrieve the event enabled handles */
3728 + acpi_callgetfunc(sony_nc_acpi_handle, "SN01", &bitmask);
3730 - if (strict_strtoul(buffer, 10, &value))
3732 + /* disable the event generation for every handle */
3733 + acpi_callsetfunc(sony_nc_acpi_handle, "SN03", bitmask, &result);
3735 - ret = __sony_nc_kbd_backlight_timeout_set(value);
3738 + /* cleanup handles here */
3739 + sony_nc_snc_cleanup_handles(pd);
3743 + sony_nc_handles_cleanup(pd);
3745 -static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
3746 - struct device_attribute *attr, char *buffer)
3748 - ssize_t count = 0;
3749 - count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
3754 -static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
3755 +static int sony_nc_snc_resume(void)
3758 + unsigned int i, result, bitmask;
3760 - if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
3762 - if (!(result & 0x02))
3764 + /* retrieve the implemented offsets mask */
3765 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN00", 0x10, &bitmask))
3768 - kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
3769 - if (!kbdbl_handle)
3771 + /* Enable all events, otherwise return */
3772 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", bitmask, &result))
3775 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
3776 + int unsigned handle = handles->cap[i];
3778 - sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
3779 - kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
3780 - kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
3781 - kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
3782 - kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
3784 - sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
3785 - kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
3786 - kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
3787 - kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
3788 - kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
3792 - if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
3794 + dprintk("looking at handle 0x%.4x\n", handle);
3796 - if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
3803 + sony_nc_function_setup(handle);
3806 + sony_nc_thermal_resume();
3810 + /* re-read rfkill state */
3811 + sony_nc_rfkill_update();
3813 + case 0x0137: /* kbd + als */
3815 + sony_nc_kbd_backlight_resume();
3816 + case 0x012f: /* als only */
3817 + sony_nc_als_resume();
3823 - __sony_nc_kbd_backlight_mode_set(kbd_backlight);
3824 - __sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
3825 + dprintk("handle 0x%.4x updated\n", handle);
3830 + sony_nc_tests_resume();
3833 - device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
3835 - kfree(kbdbl_handle);
3836 - kbdbl_handle = NULL;
3841 -static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
3845 +static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
3846 + void *context, void **return_value)
3848 - if (kbdbl_handle) {
3851 - device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
3852 - device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
3853 + struct acpi_device_info *info;
3855 - /* restore the default hw behaviour */
3856 - sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
3857 - sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
3858 + if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
3859 + pr_warn("method: name: %4.4s, args %X\n",
3860 + (char *)&info->name, info->param_count);
3862 - kfree(kbdbl_handle);
3870 -static void sony_nc_kbd_backlight_resume(void)
3871 +#define EV_HOTKEYS 1
3872 +#define EV_RFKILL 2
3874 +#define EV_GSENSOR 4
3876 +static void sony_nc_notify(struct acpi_device *device, u32 event)
3881 + char *env[2] = { NULL };
3883 - if (!kbdbl_handle)
3885 + dprintk("sony_nc_notify, event: 0x%.2x\n", event);
3887 - if (kbdbl_handle->mode == 0)
3888 - sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
3889 + /* handles related events */
3890 + if (event >= 0x90) {
3891 + unsigned int result = 0, handle = 0;
3893 + /* the event should corrispond to the offset of the method */
3894 + unsigned int offset = event - 0x90;
3896 + handle = handles->cap[offset];
3898 + /* list of handles known for generating events */
3901 + /* hotkey event, a key has been pressed, retrieve it */
3902 + value = sony_nc_hotkeys_decode(handle);
3903 + if (value > 0) /* known event */
3904 + sony_laptop_report_input_event(value);
3905 + else /* restore the original event */
3908 - if (kbdbl_handle->timeout != 0)
3909 - sony_call_snc_handle(KBDBL_HANDLER,
3910 - (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
3916 -static void sony_nc_backlight_ng_read_limits(int handle,
3917 - struct sony_backlight_props *props)
3920 - acpi_status status;
3922 - u8 min = 0xff, max = 0x00;
3923 - struct acpi_object_list params;
3924 - union acpi_object in_obj;
3925 - union acpi_object *lvl_enum;
3926 - struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
3928 + sony_call_snc_handle(handle, 0x2000, &result);
3929 + /* event reasons are reverted */
3930 + value = (result & 0x03) == 1 ? 2 : 1;
3931 + dprintk("sony_nc_notify, ALS event received (reason:"
3932 + " %s change)\n", value == 1 ? "light" :
3935 - props->handle = handle;
3936 - props->offset = 0;
3937 - props->maxlvl = 0xff;
3938 + env[0] = (value == 1) ? "ALS=1" : "ALS=2";
3939 + kobject_uevent_env(&device->dev.kobj, KOBJ_CHANGE, env);
3941 - offset = sony_find_snc_handle(handle);
3947 - /* try to read the boundaries from ACPI tables, if we fail the above
3948 - * defaults should be reasonable
3951 - params.pointer = &in_obj;
3952 - in_obj.type = ACPI_TYPE_INTEGER;
3953 - in_obj.integer.value = offset;
3954 - status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", ¶ms,
3956 - if (ACPI_FAILURE(status))
3960 + sony_call_snc_handle(handle, 0x0800, &result);
3961 + value = result & 0x03;
3962 + dprintk("sony_nc_notify, ALS event received (reason:"
3963 + " %s change)\n", value == 1 ? "light" :
3965 + if (value == 1) /* lighting change reason */
3966 + sony_nc_als_event_handler();
3968 - lvl_enum = (union acpi_object *) buffer.pointer;
3970 - pr_err("No SN06 return object.");
3973 - if (lvl_enum->type != ACPI_TYPE_BUFFER) {
3974 - pr_err("Invalid SN06 return object 0x%.2x\n",
3978 + env[0] = (value == 1) ? "ALS=1" : "ALS=2";
3979 + kobject_uevent_env(&device->dev.kobj, KOBJ_CHANGE, env);
3981 - /* the buffer lists brightness levels available, brightness levels are
3982 - * from 0 to 8 in the array, other values are used by ALS control.
3984 - for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
3988 - brlvl = *(lvl_enum->buffer.pointer + i);
3989 - dprintk("Brightness level: %d\n", brlvl);
3992 + sony_call_snc_handle(handle, 0x0100, &result);
3994 + dprintk("sony_nc_notify, RFKILL event received "
3995 + "(reason: %s)\n", result == 1 ?
3996 + "switch state changed" : "battery");
3998 + if (result == 1) { /* hw swtich event */
3999 + sony_nc_rfkill_update();
4000 + value = sony_nc_get_rfkill_hwblock();
4001 + } else if (result == 2) { /* battery event */
4002 + /* we might need to change the WWAN rfkill
4003 + state when the battery state changes
4005 + sony_nc_rfkill_update_wwan();
4018 - props->offset = min;
4019 - props->maxlvl = max;
4020 - dprintk("Brightness levels: min=%d max=%d\n", props->offset,
4025 + value = EV_GSENSOR;
4026 + /* hdd protection event, notify userspace */
4029 - kfree(buffer.pointer);
4032 + env[0] = "HDD_SHOCK=1";
4033 + kobject_uevent_env(&device->dev.kobj, KOBJ_CHANGE, env);
4035 -static void sony_nc_backlight_setup(void)
4037 - acpi_handle unused;
4038 - int max_brightness = 0;
4039 - const struct backlight_ops *ops = NULL;
4040 - struct backlight_properties props;
4043 - if (sony_find_snc_handle(0x12f) != -1) {
4044 - ops = &sony_backlight_ng_ops;
4045 - sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
4046 - max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
4048 - } else if (sony_find_snc_handle(0x137) != -1) {
4049 - ops = &sony_backlight_ng_ops;
4050 - sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
4051 - max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
4054 + /* Hybrid GFX switching, 1 */
4055 + sony_call_snc_handle(handle, 0x0000, &result);
4056 + dprintk("sony_nc_notify, Hybrid GFX event received "
4057 + "(reason: %s)\n", (result & 0x01) ?
4058 + "switch position change" : "unknown");
4060 + /* verify the switch state
4061 + (1: discrete GFX, 0: integrated GFX)*/
4063 + sony_call_snc_handle(handle, 0x0100, &result);
4065 - } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
4067 - ops = &sony_backlight_ops;
4068 - max_brightness = SONY_MAX_BRIGHTNESS - 1;
4069 + /* sony_laptop_report_input_event(); */
4074 + value = result & 0xff;
4077 - memset(&props, 0, sizeof(struct backlight_properties));
4078 - props.type = BACKLIGHT_PLATFORM;
4079 - props.max_brightness = max_brightness;
4080 - sony_bl_props.dev = backlight_device_register("sony", NULL,
4085 + dprintk("Unknowk event for handle: 0x%x\n", handle);
4089 - if (IS_ERR(sony_bl_props.dev)) {
4090 - pr_warn("unable to register backlight device\n");
4091 - sony_bl_props.dev = NULL;
4093 - sony_bl_props.dev->props.brightness =
4094 - ops->get_brightness(sony_bl_props.dev);
4096 + /* clear the event (and the event reason when present) */
4097 + acpi_callsetfunc(sony_nc_acpi_handle, "SN05", 1 << offset,
4101 + sony_laptop_report_input_event(event);
4104 -static void sony_nc_backlight_cleanup(void)
4106 - if (sony_bl_props.dev)
4107 - backlight_device_unregister(sony_bl_props.dev);
4108 + acpi_bus_generate_proc_event(device, ev, value);
4109 + acpi_bus_generate_netlink_event(device->pnp.device_class,
4110 + dev_name(&device->dev), ev, value);
4113 static int sony_nc_add(struct acpi_device *device)
4114 @@ -1688,7 +4348,8 @@ static int sony_nc_add(struct acpi_devic
4116 /* read device status */
4117 result = acpi_bus_get_status(device);
4118 - /* bail IFF the above call was successful and the device is not present */
4119 + /* bail IFF the above call was successful
4120 + and the device is not present */
4121 if (!result && !device->status.present) {
4122 dprintk("Device not present\n");
4124 @@ -1719,25 +4380,21 @@ static int sony_nc_add(struct acpi_devic
4125 if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
4127 dprintk("Doing SNC setup\n");
4128 - result = sony_nc_handles_setup(sony_pf_device);
4131 - result = sony_nc_kbd_backlight_setup(sony_pf_device);
4134 + if (sony_nc_snc_setup(sony_pf_device))
4136 - sony_nc_function_setup(device);
4137 - sony_nc_rfkill_setup(device);
4140 /* setup input devices and helper fifo */
4141 result = sony_laptop_setup_input(device);
4143 pr_err("Unable to create input devices\n");
4144 - goto outkbdbacklight;
4148 if (acpi_video_backlight_support()) {
4149 - pr_info("brightness ignored, must be controlled by ACPI video driver\n");
4150 + pr_info("brightness ignored, must be "
4151 + "controlled by ACPI video driver\n");
4153 sony_nc_backlight_setup();
4155 @@ -1783,25 +4440,21 @@ static int sony_nc_add(struct acpi_devic
4160 - for (item = sony_nc_values; item->name; ++item) {
4162 + for (item = sony_nc_values; item->name; ++item)
4163 device_remove_file(&sony_pf_device->dev, &item->devattr);
4166 sony_nc_backlight_cleanup();
4168 sony_laptop_remove_input();
4171 - sony_nc_kbd_backlight_cleanup(sony_pf_device);
4174 - sony_nc_handles_cleanup(sony_pf_device);
4176 + sony_nc_snc_cleanup(sony_pf_device);
4183 - sony_nc_rfkill_cleanup();
4188 @@ -1813,20 +4466,56 @@ static int sony_nc_remove(struct acpi_de
4190 sony_nc_acpi_device = NULL;
4192 - for (item = sony_nc_values; item->name; ++item) {
4193 + for (item = sony_nc_values; item->name; ++item)
4194 device_remove_file(&sony_pf_device->dev, &item->devattr);
4197 - sony_nc_kbd_backlight_cleanup(sony_pf_device);
4198 - sony_nc_handles_cleanup(sony_pf_device);
4199 + sony_nc_snc_cleanup(sony_pf_device);
4201 sony_laptop_remove_input();
4202 - sony_nc_rfkill_cleanup();
4203 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
4208 +static int sony_nc_resume(struct acpi_device *device)
4210 + struct sony_nc_value *item;
4211 + acpi_handle handle;
4213 + for (item = sony_nc_values; item->name; item++) {
4218 + ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
4219 + item->value, NULL);
4221 + pr_err("%s: %d\n", __func__, ret);
4226 + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
4228 + if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
4229 + dprintk("ECON Method failed\n");
4232 + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
4234 + dprintk("Doing SNC setup\n");
4236 + sony_nc_snc_resume();
4239 + /* set the last requested brightness level */
4240 + if (sony_backlight_device &&
4241 + sony_backlight_ops.update_status(sony_backlight_device) < 0)
4242 + pr_warn("unable to restore brightness level\n");
4247 static const struct acpi_device_id sony_device_ids[] = {
4250 @@ -2165,11 +4854,14 @@ static u8 sony_pic_call3(u8 dev, u8 fn,
4254 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
4255 + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
4257 outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
4258 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
4259 + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
4261 outb(fn, spic_dev.cur_ioport->io1.minimum);
4262 - wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
4263 + wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
4265 outb(v, spic_dev.cur_ioport->io1.minimum);
4266 v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
4267 dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
4268 @@ -2283,19 +4975,19 @@ out:
4269 /* the rest don't need a loop until not 0xff */
4270 #define SONYPI_CAMERA_AGC 6
4271 #define SONYPI_CAMERA_AGC_MASK 0x30
4272 -#define SONYPI_CAMERA_SHUTTER_MASK 0x7
4273 +#define SONYPI_CAMERA_SHUTTER_MASK 0x7
4275 #define SONYPI_CAMERA_SHUTDOWN_REQUEST 7
4276 #define SONYPI_CAMERA_CONTROL 0x10
4278 -#define SONYPI_CAMERA_STATUS 7
4279 -#define SONYPI_CAMERA_STATUS_READY 0x2
4280 +#define SONYPI_CAMERA_STATUS 7
4281 +#define SONYPI_CAMERA_STATUS_READY 0x2
4282 #define SONYPI_CAMERA_STATUS_POSITION 0x4
4284 -#define SONYPI_DIRECTION_BACKWARDS 0x4
4285 +#define SONYPI_DIRECTION_BACKWARDS 0x4
4287 -#define SONYPI_CAMERA_REVISION 8
4288 -#define SONYPI_CAMERA_ROMVERSION 9
4289 +#define SONYPI_CAMERA_REVISION 8
4290 +#define SONYPI_CAMERA_ROMVERSION 9
4292 static int __sony_pic_camera_ready(void)
4294 @@ -2379,28 +5071,28 @@ int sony_pic_camera_command(int command,
4295 __sony_pic_camera_off();
4297 case SONY_PIC_COMMAND_SETCAMERABRIGHTNESS:
4298 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS, value),
4299 - ITERATIONS_SHORT);
4300 + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_BRIGHTNESS,
4301 + value), ITERATIONS_SHORT);
4303 case SONY_PIC_COMMAND_SETCAMERACONTRAST:
4304 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST, value),
4305 - ITERATIONS_SHORT);
4306 + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_CONTRAST,
4307 + value), ITERATIONS_SHORT);
4309 case SONY_PIC_COMMAND_SETCAMERAHUE:
4310 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
4313 case SONY_PIC_COMMAND_SETCAMERACOLOR:
4314 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR, value),
4315 - ITERATIONS_SHORT);
4316 + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_COLOR,
4317 + value), ITERATIONS_SHORT);
4319 case SONY_PIC_COMMAND_SETCAMERASHARPNESS:
4320 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS, value),
4321 - ITERATIONS_SHORT);
4322 + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_SHARPNESS,
4323 + value), ITERATIONS_SHORT);
4325 case SONY_PIC_COMMAND_SETCAMERAPICTURE:
4326 - wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE, value),
4327 - ITERATIONS_SHORT);
4328 + wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_PICTURE,
4329 + value), ITERATIONS_SHORT);
4331 case SONY_PIC_COMMAND_SETCAMERAAGC:
4332 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_AGC, value),
4333 @@ -2434,7 +5126,9 @@ static ssize_t sony_pic_wwanpower_store(
4337 - value = simple_strtoul(buffer, NULL, 10);
4338 + if (strict_strtoul(buffer, 10, &value))
4341 mutex_lock(&spic_dev.lock);
4342 __sony_pic_set_wwanpower(value);
4343 mutex_unlock(&spic_dev.lock);
4344 @@ -2471,7 +5165,9 @@ static ssize_t sony_pic_bluetoothpower_s
4348 - value = simple_strtoul(buffer, NULL, 10);
4349 + if (strict_strtoul(buffer, 10, &value))
4352 mutex_lock(&spic_dev.lock);
4353 __sony_pic_set_bluetoothpower(value);
4354 mutex_unlock(&spic_dev.lock);
4355 @@ -2510,7 +5206,9 @@ static ssize_t sony_pic_fanspeed_store(s
4359 - value = simple_strtoul(buffer, NULL, 10);
4360 + if (strict_strtoul(buffer, 10, &value))
4363 if (sony_pic_set_fanspeed(value))
4366 @@ -2659,12 +5357,12 @@ static long sonypi_misc_ioctl(struct fil
4367 void __user *argp = (void __user *)arg;
4371 + unsigned int value;
4373 mutex_lock(&spic_dev.lock);
4375 case SONYPI_IOCGBRT:
4376 - if (sony_bl_props.dev == NULL) {
4377 + if (sony_backlight_device == NULL) {
4381 @@ -2677,7 +5375,7 @@ static long sonypi_misc_ioctl(struct fil
4384 case SONYPI_IOCSBRT:
4385 - if (sony_bl_props.dev == NULL) {
4386 + if (sony_backlight_device == NULL) {
4390 @@ -2691,8 +5389,8 @@ static long sonypi_misc_ioctl(struct fil
4393 /* sync the backlight device status */
4394 - sony_bl_props.dev->props.brightness =
4395 - sony_backlight_get_brightness(sony_bl_props.dev);
4396 + sony_backlight_device->props.brightness =
4397 + sony_backlight_get_brightness(sony_backlight_device);
4399 case SONYPI_IOCGBAT1CAP:
4400 if (ec_read16(SONYPI_BAT1_FULL, &val16)) {
4401 @@ -2861,7 +5559,8 @@ sony_pic_read_possible_resource(struct a
4402 case ACPI_RESOURCE_TYPE_START_DEPENDENT:
4404 /* start IO enumeration */
4405 - struct sony_pic_ioport *ioport = kzalloc(sizeof(*ioport), GFP_KERNEL);
4406 + struct sony_pic_ioport *ioport =
4407 + kzalloc(sizeof(*ioport), GFP_KERNEL);
4411 @@ -2909,7 +5608,8 @@ sony_pic_read_possible_resource(struct a
4413 struct acpi_resource_io *io = &resource->data.io;
4414 struct sony_pic_ioport *ioport =
4415 - list_first_entry(&dev->ioports, struct sony_pic_ioport, list);
4416 + list_first_entry(&dev->ioports,
4417 + struct sony_pic_ioport, list);
4419 dprintk("Blank IO resource\n");
4421 @@ -2917,16 +5617,17 @@ sony_pic_read_possible_resource(struct a
4423 if (!ioport->io1.minimum) {
4424 memcpy(&ioport->io1, io, sizeof(*io));
4425 - dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
4426 + dprintk("IO1 at 0x%.4x (0x%.2x)\n",
4427 + ioport->io1.minimum,
4428 ioport->io1.address_length);
4430 - else if (!ioport->io2.minimum) {
4431 + } else if (!ioport->io2.minimum) {
4432 memcpy(&ioport->io2, io, sizeof(*io));
4433 - dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
4434 + dprintk("IO2 at 0x%.4x (0x%.2x)\n",
4435 + ioport->io2.minimum,
4436 ioport->io2.address_length);
4439 - pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4441 + pr_err("Unknown SPIC Type, "
4442 + "more than 2 IO Ports\n");
4446 @@ -3249,24 +5950,26 @@ static int sony_pic_add(struct acpi_devi
4447 /* Type 1 have 2 ioports */
4448 if (io->io2.minimum) {
4449 if (request_region(io->io2.minimum,
4450 - io->io2.address_length,
4451 - "Sony Programmable I/O Device")) {
4452 - dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
4453 - io->io2.minimum, io->io2.maximum,
4454 + io->io2.address_length,
4455 + "Sony Programmable I/O Device")) {
4456 + dprintk("I/O port2: 0x%.4x (0x%.4x) "
4460 io->io2.address_length);
4461 spic_dev.cur_ioport = io;
4466 dprintk("Unable to get I/O port2: "
4467 - "0x%.4x (0x%.4x) + 0x%.2x\n",
4468 - io->io2.minimum, io->io2.maximum,
4469 + "0x%.4x (0x%.4x) "
4473 io->io2.address_length);
4474 release_region(io->io1.minimum,
4475 io->io1.address_length);
4480 spic_dev.cur_ioport = io;
4483 @@ -3281,7 +5984,7 @@ static int sony_pic_add(struct acpi_devi
4485 list_for_each_entry_reverse(irq, &spic_dev.interrupts, list) {
4486 if (!request_irq(irq->irq.interrupts[0], sony_pic_irq,
4487 - IRQF_DISABLED, "sony-laptop", &spic_dev)) {
4488 + IRQF_DISABLED, "sony-laptop", &spic_dev)) {
4489 dprintk("IRQ: %d - triggering: %d - "
4490 "polarity: %d - shr: %d\n",
4491 irq->irq.interrupts[0],
4492 @@ -3311,7 +6014,8 @@ static int sony_pic_add(struct acpi_devi
4494 goto err_disable_device;
4496 - result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
4497 + result = sysfs_create_group(&sony_pf_device->dev.kobj,
4498 + &spic_attribute_group);