updated on Sun Jan 15 08:01:04 UTC 2012
[aur-mirror.git] / linux-sony / vaio-full-3.0.4.patch
blob5dac175a04e000141fff371b291682624e5f9b14
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[] = {
10 + {
11 + .ident = "Sony Vaio S1",
12 + .matches = {
13 + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
14 + DMI_MATCH(DMI_PRODUCT_NAME, "VPCS1"),
15 + },
16 + },
17 + {
18 + .ident = "Sony Vaio TT",
19 + .matches = {
20 + DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"),
21 + DMI_MATCH(DMI_PRODUCT_NAME, "VGN-TT"),
22 + },
23 + },
24 + { }
25 +};
27 static acpi_status
28 acpi_backlight_cap_match(acpi_handle handle, u32 level, void *context,
29 void **retyurn_value)
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;
37 } else {
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
43 @@ -3,6 +3,8 @@
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.
52 @@ -63,7 +65,7 @@
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)");
63 #endif
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 "
72 "(default: 0)");
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 {
83 - SONY_WIFI,
84 - SONY_BLUETOOTH,
85 - SONY_WWAN,
86 - SONY_WIMAX,
87 - N_SONY_RFKILL,
88 -};
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
108 default:
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);
113 break;
115 if (sony_laptop_input_index[event] != -1) {
116 @@ -565,12 +561,12 @@ static int sony_pf_add(void)
118 return 0;
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);
127 - out:
128 +out:
129 atomic_dec(&sony_pf_users);
130 return ret;
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
159 return -1;
162 -static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
163 - int *result)
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 "
175 + "return type\n");
176 return -1;
178 *result = out_obj.integer.value;
179 @@ -743,6 +742,72 @@ static int acpi_callsetfunc(acpi_handle
180 return -1;
183 +static int acpi_callsetfunc_buffer(acpi_handle handle, u64 value,
184 + u8 array[], unsigned int size)
186 + u8 buffer[sizeof(value)];
187 + int length = -1;
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)
195 + return length;
197 + /* use a buffer type as parameter to overcome any 32 bits ACPI limit */
198 + memcpy(buffer, &value, sizeof(buffer));
200 + params.count = 1;
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
208 + */
209 + status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
210 + &output);
211 + values = (union acpi_object *) output.pointer;
212 + if (ACPI_FAILURE(status) || !values) {
213 + dprintk("acpi_evaluate_object failed\n");
214 + goto error;
217 + /* some buggy DSDTs return integer when the output does
218 + not execede the 4 bytes size
219 + */
220 + if (values->type == ACPI_TYPE_BUFFER) {
221 + if (values->buffer.length <= 0)
222 + goto error;
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;
230 + if (size < 4)
231 + goto error;
233 + length = 0;
234 + while (length != 4) {
235 + array[length] = result & 0xff;
236 + result >>= 8;
237 + length++;
239 + } else {
240 + pr_err("Invalid return object 0x%.2x\n", values->type);
241 + goto error;
244 +error:
245 + kfree(output.pointer);
246 + return length;
249 struct sony_nc_handles {
250 u16 cap[0x10];
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)
256 - int i;
257 - int result;
258 + unsigned int i, result;
260 handles = kzalloc(sizeof(*handles), GFP_KERNEL);
261 if (!handles)
262 @@ -811,12 +875,12 @@ static int sony_nc_handles_cleanup(struc
263 return 0;
266 -static int sony_find_snc_handle(int handle)
267 +static int sony_find_snc_handle(unsigned int handle)
269 int i;
271 - /* not initialized yet, return early */
272 - if (!handles)
273 + /* not initialized yet or invalid handle, return early */
274 + if (!handles || !handle)
275 return -1;
277 for (i = 0; i < 0x10; i++) {
278 @@ -830,7 +894,9 @@ static int sony_find_snc_handle(int hand
279 return -1;
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)
287 int ret = 0;
288 int offset = sony_find_snc_handle(handle);
289 @@ -838,6 +904,7 @@ static int sony_call_snc_handle(int hand
290 if (offset < 0)
291 return -1;
293 + /* max 32 bit wide argument, for wider input use SN06 */
294 ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
295 result);
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
298 return ret;
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)
305 + int ret = 0;
306 + int offset = sony_find_snc_handle(handle);
308 + if (offset < 0)
309 + return -1;
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);
316 + return 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)
325 switch (direction) {
326 - case SNC_VALIDATE_OUT:
327 - return value - 1;
328 - case SNC_VALIDATE_IN:
329 - if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
330 - return value + 1;
331 + case SNC_VALIDATE_OUT:
332 + return value - 1;
333 + case SNC_VALIDATE_IN:
334 + if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
335 + return value + 1;
337 return -EINVAL;
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,
344 - char *buffer)
345 +static ssize_t sony_nc_sysfs_show(struct device *dev,
346 + struct device_attribute *attr,
347 + char *buffer)
349 - int value;
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)
358 - int value;
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
364 if (count > 31)
365 return -EINVAL;
367 - value = simple_strtoul(buffer, NULL, 10);
368 + if (strict_strtoul(buffer, 10, &value))
369 + return -EINVAL;
371 if (item->validate)
372 value = item->validate(SNC_VALIDATE_IN, value);
373 @@ -924,76 +1011,14 @@ static ssize_t sony_nc_sysfs_store(struc
374 if (value < 0)
375 return value;
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)
380 return -EIO;
381 item->value = value;
382 item->valid = 1;
383 return count;
388 - * Backlight device
389 - */
390 -struct sony_backlight_props {
391 - struct backlight_device *dev;
392 - int handle;
393 - u8 offset;
394 - u8 maxlvl;
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)
406 - int value;
408 - if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
409 - return 0;
410 - /* brightness levels are 1-based, while backlight ones are 0-based */
411 - return value - 1;
414 -static int sony_nc_get_brightness_ng(struct backlight_device *bd)
416 - int result;
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)
427 - int value, result;
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))
433 - return -EIO;
435 - return value;
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
488 - * ACPI callbacks
489 + * ACPI device
491 -static void sony_nc_notify(struct acpi_device *device, u32 event)
492 +static int sony_nc_function_setup(unsigned int handle)
494 - u32 ev = event;
496 - if (ev >= 0x90) {
497 - /* New-style event */
498 - int result;
499 - int key_handle = 0;
500 - ev -= 0x90;
502 - if (sony_find_snc_handle(0x100) == ev)
503 - key_handle = 0x100;
504 - if (sony_find_snc_handle(0x127) == ev)
505 - key_handle = 0x127;
507 - if (key_handle) {
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,
513 - ev);
514 - /* restore the original event */
515 - ev = event;
516 - } else {
517 - ev = result & 0xFF;
518 + unsigned int result;
520 - if (key_handle == 0x100)
521 - key_event = sony_100_events;
522 - else
523 - key_event = sony_127_events;
525 - for (; key_event->data; key_event++) {
526 - if (key_event->data == ev) {
527 - ev = key_event->event;
528 - break;
532 - if (!key_event->data)
533 - pr_info("Unknown event: 0x%x 0x%x\n",
534 - key_handle, ev);
535 - else
536 - sony_laptop_report_input_event(ev);
538 - } else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
539 - sony_nc_rfkill_update();
540 - return;
542 - } else
543 - sony_laptop_report_input_event(ev);
544 + if (handle == 0x0102)
545 + sony_call_snc_handle(0x0102, 0x100, &result);
546 + else
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);
551 + return 0;
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;
559 + int ret = -EINVAL;
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");
566 + } else {
567 + result &= 0xff;
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;
574 + else
575 + key_event = sony_127_events;
577 - kfree(info);
578 + for (; key_event->data; key_event++) {
579 + if (key_event->data == result) {
580 + ret = key_event->event;
581 + break;
585 + if (!key_event->data)
586 + pr_info("Unknown hotkey 0x%.2x (handle 0x%.2x)\n",
587 + result, handle);
588 + else
589 + dprintk("sony_nc_hotkeys_decode, hotkey 0x%.2x decoded "
590 + "to event 0x%.2x\n", result, ret);
593 - return AE_OK;
594 + return ret;
598 - * ACPI device
599 - */
600 -static int sony_nc_function_setup(struct acpi_device *device)
602 - int result;
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);
613 - return 0;
615 +enum sony_nc_rfkill {
616 + SONY_WIFI,
617 + SONY_BLUETOOTH,
618 + SONY_WWAN,
619 + SONY_WIMAX,
620 + N_SONY_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;
636 + bool battery;
637 + bool swblock;
639 - for (item = sony_nc_values; item->name; item++) {
640 - int ret;
641 + if (sony_call_snc_handle(sony_rfkill.handle, 0x0200, &result))
642 + return -EIO;
643 + battery = !!(result & 0x2);
645 - if (!item->valid)
646 - continue;
647 - ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
648 - item->value, NULL);
649 - if (ret < 0) {
650 - pr_err("%s: %d\n", __func__, ret);
651 - break;
654 + /* retrieve the device block state */
655 + if (sony_call_snc_handle(sony_rfkill.handle,
656 + sony_rfkill.address[SONY_WWAN], &result))
657 + return -EIO;
658 + swblock = !(result & 0x02);
660 - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
661 - &handle))) {
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 */
666 + cmd = 0xff0000;
667 + } else if (!battery && !swblock) {
668 + swblock = true;
669 + cmd = 0x20000;
670 + } else {
671 + return 0;
674 - if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
675 - &handle))) {
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);
691 return 0;
694 +static int sony_nc_get_rfkill_hwblock(void)
696 + unsigned int result;
698 + if (sony_call_snc_handle(sony_rfkill.handle, 0x200, &result))
699 + return -1;
701 + return result & 0x1;
704 static void sony_nc_rfkill_cleanup(void)
706 int i;
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)
721 - int result;
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)) {
728 + if (!blocked) {
729 + /* notify user space: the battery must be present */
730 + acpi_bus_generate_proc_event(sony_nc_acpi_device,
731 + 2, 2);
732 + acpi_bus_generate_netlink_event(
733 + sony_nc_acpi_device->pnp.device_class,
734 + dev_name(&sony_nc_acpi_device->dev),
735 + 2, 2);
738 + return -1;
741 + /* do not force an already set state */
742 + sony_call_snc_handle(sony_rfkill.handle, argument, &result);
743 + if ((result & 0x1) == !blocked)
744 + return 0;
746 + argument += 0x100;
747 if (!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
756 struct rfkill *rfk;
757 enum rfkill_type type;
758 const char *name;
759 - int result;
760 - bool hwblock;
761 + unsigned int result;
762 + bool hwblock, swblock, wwblock;
764 switch (nc_type) {
765 case SONY_WIFI:
766 @@ -1255,8 +1285,20 @@ static int sony_nc_setup_rfkill(struct a
767 if (!rfk)
768 return -ENOMEM;
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);
775 + result = 0;
776 + sony_call_snc_handle(sony_rfkill.handle, sony_rfkill.address[nc_type],
777 + &result);
778 + swblock = !(result & 0x2);
780 + /* hard block the WWAN module if no battery is present */
781 + if ((nc_type == SONY_WWAN) && wwblock)
782 + swblock = true;
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
789 rfkill_destroy(rfk);
790 return err;
792 - sony_rfkill_devices[nc_type] = rfk;
793 + sony_rfkill.devices[nc_type] = rfk;
794 return err;
797 static void sony_nc_rfkill_update(void)
799 enum sony_nc_rfkill i;
800 - int result;
801 - bool hwblock;
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])
816 continue;
818 - if (hwblock) {
819 - if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
820 - /* we already know we're blocked */
822 - continue;
824 + sony_call_snc_handle(sony_rfkill.handle, argument, &result);
825 + /* block wwan when no battery is present */
826 + if ((i == SONY_WWAN) && wwblock)
827 + swblock = true;
828 + else
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],
835 + swblock, hwblock);
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)
842 - int offset;
843 - u8 dev_code, i;
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);
855 - if (offset == -1)
856 - return;
857 - else
858 - sony_rfkill_handle = 0x135;
859 - } else
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
867 - params.count = 1;
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", &params,
872 - &buffer);
873 - if (ACPI_FAILURE(status)) {
874 - dprintk("Radio device enumeration failed\n");
875 - return;
878 - device_enum = (union acpi_object *) buffer.pointer;
879 - if (!device_enum) {
880 - pr_err("No SN06 return object\n");
881 - goto out_no_enum;
883 - if (device_enum->type != ACPI_TYPE_BUFFER) {
884 - pr_err("Invalid SN06 return object 0x%.2x\n",
885 - device_enum->type);
886 - goto out_no_enum;
888 + if (sony_call_snc_handle_buffer(sony_rfkill.handle, 0x000,
889 + buff, RFKILL_BUFF_SIZE) < 0)
890 + return -EIO;
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)
901 break;
903 + /*
904 + known codes:
906 + 0x00 WLAN
907 + 0x10 BLUETOOTH
908 + 0x20 WWAN GPRS-EDGE
909 + 0x21 WWAN HSDPA
910 + 0x22 WWAN EV-DO
911 + 0x23 WWAN GPS
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
918 + 0x30 WIMAX
919 + 0x70 no SIM card slot
920 + 0x71 SIM card slot
921 + */
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);
944 + return 0;
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[]);
953 + int (*exit)(void);
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;
968 + u8 *levels;
969 + unsigned int defaults_num;
970 + u8 *defaults;
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];
979 +} *sony_als;
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 {
1005 + u32 ratio;
1006 + u32 ch0;
1007 + u32 ch1;
1008 + u32 ka;
1009 + s32 kb;
1012 +struct tsl256x_data {
1013 + unsigned int gaintime;
1014 + unsigned int periods;
1015 + u8 *defaults;
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),
1026 + .kb = -10651,
1027 + }, {
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),
1032 + .kb = -2341,
1033 + }, {
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),
1038 + .kb = 157,
1039 + }, {
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),
1044 + .kb = -145,
1045 + }, {
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),
1050 + .kb = -495,
1051 + }, {
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),
1056 + .kb = -765
1057 + }, {
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),
1062 + .kb = -608,
1063 + }, {
1064 + .ratio = UINT_MAX, /* for higher ratios */
1065 + .ch0 = 0,
1066 + .ch1 = 0,
1067 + .ka = 0,
1068 + .kb = 830,
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),
1078 + .kb = -9587,
1079 + }, {
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),
1084 + .kb = -1824,
1085 + }, {
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),
1090 + .kb = 145,
1091 + }, {
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),
1096 + .kb = -200,
1097 + }, {
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),
1102 + .kb = -566,
1103 + }, {
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),
1108 + .kb = -791,
1109 + }, {
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),
1114 + .kb = -608,
1115 + }, {
1116 + .ratio = UINT_MAX, /* for higher ratios */
1117 + .ch0 = 0,
1118 + .ch1 = 0,
1119 + .ka = 0,
1120 + .kb = 830,
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))
1132 + ? -EIO : 0;
1135 +static inline int tsl256x_exec_writeword(unsigned int reg,
1136 + unsigned int const *value)
1138 + u8 result[1];
1139 + u64 arg = *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))
1151 + return -EIO;
1152 + *result = (*result >> 0x08) & 0xFF;
1154 + return 0;
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))
1161 + return -EIO;
1162 + *result = (*result >> 0x08) & 0xFFFF;
1164 + return 0;
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 */
1173 + if (!interrupt) {
1174 + if (tsl256x_exec_readbyte(TSL256X_REG_INT, &result))
1175 + return -EIO;
1177 + value = (result & TSL256X_INT_MASK);
1178 + } else {
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))
1186 + return -EIO;
1188 + if (periods)
1189 + tsl256x_handle->periods = *periods;
1191 + return 0;
1194 +static int tsl256x_setup(void)
1196 + unsigned int interr = 1, zero = 0;
1198 + /*
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
1202 + */
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))
1209 + return -EIO;
1211 + /* restore persistence value and enable the interrupt generation */
1212 + if (tsl256x_interrupt_ctrls(&interr, &tsl256x_handle->periods))
1213 + return -EIO;
1215 + return 0;
1218 +static int tsl256x_set_power(unsigned int status)
1220 + int ret;
1222 + if (status) {
1223 + ret = tsl256x_setup();
1224 + if (ret)
1225 + return ret;
1228 + status = status ? TSL256X_POWER_ON : TSL256X_POWER_OFF;
1229 + ret = tsl256x_exec_writebyte(TSL256X_REG_CTRL, &status);
1231 + return ret;
1234 +static int tsl256x_get_power(unsigned int *status)
1236 + if (tsl256x_exec_readbyte(TSL256X_REG_CTRL, status))
1237 + return -EIO;
1239 + *status = ((*status & TSL256X_POWER_MASK) == TSL256X_POWER_ON) ? 1 : 0;
1241 + return 0;
1244 +static int tsl256x_get_raw_data(unsigned int *ch0, unsigned int *ch1)
1246 + if (!ch0)
1247 + return -1;
1249 + if (tsl256x_exec_readword(TSL256X_REG_DATA0, ch0))
1250 + return -EIO;
1252 + if (ch1) {
1253 + if (tsl256x_exec_readword(TSL256X_REG_DATA1, ch1))
1254 + return -EIO;
1257 + return 0;
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)
1268 + thigh = 0xffff;
1270 + if (tsl256x_exec_writeword(TSL256X_REG_TLOW, &tlow) ||
1271 + tsl256x_exec_writeword(TSL256X_REG_THIGH, &thigh))
1272 + return -EIO;
1274 + return 0;
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.
1285 + */
1286 + const struct tsl256x_coeff *coeff = tsl256x_handle->coeff_table;
1287 + u32 ratio, temp, integer, fractional;
1289 + if (ch0 >= 65535 || ch1 >= 65535)
1290 + goto saturation;
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)
1301 + coeff++;
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.
1309 + */
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)
1322 + goto saturation;
1324 + *integ = integer;
1325 + *fract = fractional;
1327 + return;
1329 +saturation:
1330 + *integ = MAX_LUX;
1331 + *fract = 0;
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;
1338 + u32 ratio;
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)
1347 + coeff++;
1349 + *temperature = ratio ? coeff->ka / ratio + coeff->kb : 0;
1352 +static int tsl256x_get_lux(unsigned int *integ, unsigned int *fract)
1354 + int ret = 0;
1355 + unsigned int ch0, ch1;
1357 + if (!integ || !fract)
1358 + return -1;
1360 + ret = tsl256x_get_raw_data(&ch0, &ch1);
1361 + if (!ret)
1362 + tsl256x_calculate_lux(ch0, ch1, integ, fract);
1364 + return ret;
1367 +static int tsl256x_get_kelvin(unsigned int *temperature)
1369 + int ret = -1;
1370 + unsigned int ch0, ch1;
1372 + if (!temperature)
1373 + return ret;
1375 + ret = tsl256x_get_raw_data(&ch0, &ch1);
1376 + if (!ret)
1377 + tsl256x_calculate_kelvin(&ch0, &ch1, temperature);
1379 + return ret;
1382 +static int tsl256x_get_id(char *model, unsigned int *id, bool *cs)
1384 + int ret;
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);
1391 + if (ret)
1392 + return ret;
1394 + switch ((result >> 0x04) & 0x0F) {
1395 + case 5:
1396 + name = "TAOS TSL2561";
1397 + break;
1398 + case 4:
1399 + name = "TAOS TSL2560";
1400 + break;
1401 + case 3:
1402 + name = "TAOS TSL2563";
1403 + break;
1404 + case 2:
1405 + name = "TAOS TSL2562";
1406 + break;
1407 + case 1:
1408 + type_cs = true;
1409 + name = "TAOS TSL2561CS";
1410 + break;
1411 + case 0:
1412 + type_cs = true;
1413 + name = "TAOS TSL2560CS";
1414 + break;
1415 + default:
1416 + unknown = true;
1417 + break;
1420 + if (id)
1421 + *id = result;
1422 + if (cs)
1423 + *cs = type_cs;
1424 + if (model && name)
1425 + strcpy(model, name);
1427 + return unknown;
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);
1448 + return 0;
1451 +static int tsl256x_init(const u8 defaults[])
1453 + unsigned int id;
1454 + int ret = 0;
1455 + bool cs; /* if CS package choose CS coefficients */
1456 + char model[64];
1458 + /* detect the device */
1459 + ret = tsl256x_get_id(model, &id, &cs);
1460 + if (ret < 0)
1461 + return ret;
1462 + if (ret) {
1463 + dprintk("unsupported ALS found (unknown model "
1464 + "number %u rev. %u\n", id >> 4, id & 0x0F);
1465 + return ret;
1466 + } else {
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)
1473 + return -ENOMEM;
1475 + tsl256x_handle->defaults = kzalloc(sizeof(u8) * 4, GFP_KERNEL);
1476 + if (!tsl256x_handle->defaults) {
1477 + kfree(tsl256x_handle);
1478 + return -ENOMEM;
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();
1492 + return ret;
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);
1507 + return 0;
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))
1525 + return -EIO;
1527 + return 0;
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))
1535 + return -EIO;
1537 + /* if we have a valid lux data */
1538 + if (!!(data & 0xff0000) == 0x01) {
1539 + *integ = 0xffff & data;
1540 + *fract = 0;
1541 + } else {
1542 + return -1;
1545 + return 0;
1548 +static const struct als_device_ops ngals_ops = {
1549 + .init = NULL,
1550 + .exit = NULL,
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();
1565 + return 0;
1568 +static int sony_nc_als_power_set(unsigned int status)
1570 + if (!sony_als->ops->set_power)
1571 + return -EPERM;
1573 + if (sony_als->ops->set_power(status))
1574 + return -EIO;
1576 + sony_als->power = status;
1578 + return 0;
1581 +static int sony_nc_als_managed_set(unsigned int status)
1583 + int ret = 0;
1584 + unsigned int result, cmd;
1585 + static bool was_on;
1587 + /* turn on/off the event notification
1588 + * (and enable als_backlight writes)
1589 + */
1590 + cmd = sony_als->handle == 0x0143 ? 0x2200 : 0x0900;
1591 + if (sony_call_snc_handle(sony_als->handle,
1592 + (status << 0x10) | cmd, &result))
1593 + return -EIO;
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;
1600 + else if (was_on)
1601 + return 0;
1603 + ret = sony_nc_als_power_set(status);
1604 + if (ret == -EPERM) /* new models do not allow power control */
1605 + ret = 0;
1607 + return ret;
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");
1616 + return level;
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,
1631 + 3, 2);
1632 + acpi_bus_generate_netlink_event(
1633 + sony_nc_acpi_device->pnp.device_class,
1634 + dev_name(&sony_nc_acpi_device->dev),
1635 + 3, 2);
1637 + } else {
1638 + unsigned int cmd;
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))
1644 + return -EIO;
1647 + level = bd->props.brightness;
1649 + return level;
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;
1657 + int status;
1659 + if (!sony_als->ops->get_power)
1660 + return -EPERM;
1662 + if (sony_als->ops->get_power(&status))
1663 + return -EIO;
1665 + count = snprintf(buffer, PAGE_SIZE, "%d\n", status);
1667 + return count;
1670 +static ssize_t sony_nc_als_power_store(struct device *dev,
1671 + struct device_attribute *attr,
1672 + const char *buffer, size_t count)
1674 + int ret;
1675 + unsigned long value;
1677 + if (count > 31)
1678 + return -EINVAL;
1680 + if (strict_strtoul(buffer, 10, &value) || value > 1)
1681 + return -EINVAL;
1683 + /* no action if already set */
1684 + if (value == sony_als->power)
1685 + return count;
1687 + ret = sony_nc_als_power_set(value);
1688 + if (ret)
1689 + return ret;
1691 + return count;
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))
1702 + return -EIO;
1704 + count = snprintf(buffer, PAGE_SIZE, "%d\n", status & 0x01);
1706 + return count;
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;
1715 + if (count > 31)
1716 + return -EINVAL;
1718 + if (strict_strtoul(buffer, 10, &value) || value > 1)
1719 + return -EINVAL;
1721 + if (sony_als->managed != value) {
1722 + int ret = sony_nc_als_managed_set(value);
1723 + if (ret)
1724 + return ret;
1727 + return count;
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);
1742 + return count;
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;
1750 + u8 *list;
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");
1766 + return count;
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))
1777 + return -EIO;
1779 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
1781 + return count;
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;
1791 + if (count > 31)
1792 + return -EINVAL;
1794 + if (strict_strtoul(buffer, 10, &value))
1795 + return -EINVAL;
1797 + if (!sony_als->managed)
1798 + return -EPERM;
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]))
1804 + return -EINVAL;
1806 + cmd = sony_als->handle == 0x0143 ? 0x3000 : 0x0100;
1807 + if (sony_call_snc_handle(sony_als->handle, (value << 0x10) | cmd,
1808 + &result))
1809 + return -EIO;
1811 + return count;
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);
1825 + return count;
1828 +/* ALS attach/detach functions */
1829 +static int sony_nc_als_setup(struct platform_device *pd, unsigned int handle)
1831 + int i = 0;
1833 + /* check the device presence */
1834 + if (handle == 0x0137) {
1835 + unsigned int result;
1837 + if (sony_call_snc_handle(handle, 0xB00, &result))
1838 + return -EIO;
1840 + if (!(result & 0x01)) {
1841 + pr_info("no ALS present\n");
1842 + return 0;
1846 + sony_als = kzalloc(sizeof(struct sony_als_device), GFP_KERNEL);
1847 + if (!sony_als)
1848 + return -ENOMEM;
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;
1856 + } else {
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
1863 + */
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)
1881 + goto nosensor;
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");
1887 + goto nosensor;
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]))
1947 + goto attrserror;
1950 + return 0;
1952 +attrserror:
1953 + for (; i > 0; i--)
1954 + device_remove_file(&pd->dev, &sony_als->attrs[i]);
1955 +nosensor:
1956 + kfree(sony_als);
1957 + sony_als = NULL;
1959 + return -1;
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)
1972 + if (sony_als) {
1973 + int i;
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");
1991 + kfree(sony_als);
1992 + sony_als = NULL;
1995 + return 0;
1997 +/* end ALS code */
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;
2007 +} *sony_kbdbl;
2009 +static int __sony_nc_kbd_backlight_mode_set(u8 value)
2011 + unsigned int result;
2013 + if (value > 1)
2014 + return -EINVAL;
2016 + if (sony_call_snc_handle(sony_kbdbl->handle, (value << 0x10) |
2017 + (sony_kbdbl->base), &result))
2018 + return -EIO;
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);
2026 + return 0;
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)
2033 + int ret = 0;
2034 + unsigned long value;
2036 + if (count > 31)
2037 + return -EINVAL;
2039 + if (strict_strtoul(buffer, 10, &value))
2040 + return -EINVAL;
2042 + ret = __sony_nc_kbd_backlight_mode_set(value);
2043 + if (ret < 0)
2044 + return ret;
2046 + return count;
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);
2056 + return count;
2059 +static int __sony_nc_kbd_backlight_timeout_set(u8 value)
2061 + unsigned int result;
2063 + if (value > 3)
2064 + return -EINVAL;
2066 + if (sony_call_snc_handle(sony_kbdbl->handle, (value << 0x10) |
2067 + (sony_kbdbl->base + 0x200), &result))
2068 + return -EIO;
2070 + sony_kbdbl->timeout = value;
2072 + return 0;
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)
2079 + int ret = 0;
2080 + unsigned long value;
2082 + if (count > 31)
2083 + return -EINVAL;
2085 + if (strict_strtoul(buffer, 10, &value))
2086 + return -EINVAL;
2088 + ret = __sony_nc_kbd_backlight_timeout_set(value);
2089 + if (ret < 0)
2090 + return ret;
2092 + return count;
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);
2102 + return count;
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))
2114 + return -EIO;
2116 + found = !!(result & 0x02);
2117 + base_cmd = 0x0C00;
2118 + } else {
2119 + if (sony_call_snc_handle(handle, 0x0100, &result))
2120 + return -EIO;
2122 + found = result & 0x01;
2123 + base_cmd = 0x4000;
2126 + if (!found) {
2127 + dprintk("no backlight keyboard found\n");
2128 + return 0;
2131 + sony_kbdbl = kzalloc(sizeof(*sony_kbdbl), GFP_KERNEL);
2132 + if (!sony_kbdbl)
2133 + return -ENOMEM;
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))
2148 + goto outkzalloc;
2150 + if (device_create_file(&pd->dev, &sony_kbdbl->timeout_attr))
2151 + goto outmode;
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);
2159 + return 0;
2161 +outmode:
2162 + device_remove_file(&pd->dev, &sony_kbdbl->mode_attr);
2163 +outkzalloc:
2164 + kfree(sony_kbdbl);
2165 + sony_kbdbl = NULL;
2166 + return -1;
2169 +static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
2171 + if (sony_kbdbl) {
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;
2186 + return 0;
2189 +static void sony_nc_kbd_backlight_resume(void)
2191 + unsigned int result;
2193 + if (!sony_kbdbl)
2194 + return;
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 */
2207 +enum axis {
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;
2217 +} *sony_gsensor;
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))
2229 + return -EIO;
2231 + *support = sony_gsensor->handle == 0x0134
2232 + ? !!(result & 0x20)
2233 + : !!(result & 0x01);
2235 + return 0;
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))
2244 + return -EIO;
2246 + if (!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
2254 + */
2255 + reg = sony_gsensor->handle == 0x0134 ?
2256 + (!value << 0x08) : (value << 0x10);
2258 + if (sony_call_snc_handle(sony_gsensor->handle, reg, &result))
2259 + return -EIO;
2261 + if (!capable)
2262 + return 0;
2264 + /* if the requested protection setting is different
2265 + from the current one
2266 + */
2267 + reg = sony_gsensor->handle == 0x0134 ? 0x0200 : 0x0400;
2268 + if (sony_call_snc_handle(sony_gsensor->handle, reg, &result))
2269 + return -EIO;
2271 + if (sony_gsensor->handle == 0x0134) {
2272 + if (!!(result & 0x04) != value) {
2273 + arg = (result & 0x1B) | (value << 0x02);
2274 + update = true;
2276 + } else {
2277 + if ((result & 0x01) != value) {
2278 + arg = value;
2279 + update = true;
2283 + if (update && sony_call_snc_handle(sony_gsensor->handle,
2284 + (arg << 0x10) | 0x0300, &result))
2285 + return -EIO;
2287 + return 0;
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))
2295 + return -EIO;
2297 + return 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))
2308 + return -EIO;
2310 + count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 0x03) & 0x03);
2312 + return count;
2315 +static ssize_t sony_nc_gsensor_type_store(struct device *dev,
2316 + struct device_attribute *attr,
2317 + const char *buffer, size_t count)
2319 + /*
2320 + * axis out type control file:
2321 + * 0: raw values, 1: acc values 2: threshold values
2322 + */
2323 + unsigned int result;
2324 + unsigned long value;
2326 + /* sanity checks and conversion */
2327 + if (count > 31 || strict_strtoul(buffer, 10, &value) || value > 2)
2328 + return -EINVAL;
2330 + value <<= 0x03;
2332 + /* retrieve the current state / settings */
2333 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2334 + return -EIO;
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))
2342 + return -EIO;
2345 + return count;
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;
2353 + enum axis arg;
2355 + /* file being read for axis selection */
2356 + if (!strcmp(attr->attr.name, "gsensor_xval"))
2357 + arg = X_AXIS;
2358 + else if (!strcmp(attr->attr.name, "gsensor_yval"))
2359 + arg = Y_AXIS;
2360 + else if (!strcmp(attr->attr.name, "gsensor_zval"))
2361 + arg = Z_AXIS;
2362 + else
2363 + return count;
2365 + result = sony_nc_gsensor_axis_get(arg);
2366 + if (result < 0)
2367 + return -EIO;
2369 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
2371 + return count;
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,
2382 + &result))
2383 + return -EIO;
2385 + result = !!(result & 0x04);
2386 + } else {
2387 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0400,
2388 + &result))
2389 + return -EIO;
2391 + result &= 0x01;
2394 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
2396 + return count;
2399 +static ssize_t sony_nc_gsensor_status_store(struct device *dev,
2400 + struct device_attribute *attr,
2401 + const char *buffer, size_t count)
2403 + int ret;
2404 + unsigned long value;
2406 + if (count > 31)
2407 + return -EINVAL;
2408 + if (strict_strtoul(buffer, 10, &value) || value > 1)
2409 + return -EINVAL;
2411 + ret = sony_nc_gsensor_status_set(value);
2412 + if (ret)
2413 + return ret;
2415 + return count;
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))
2425 + return -EINVAL;
2427 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x03);
2428 + return count;
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;
2438 + if (count > 31)
2439 + return -EINVAL;
2440 + if (strict_strtoul(buffer, 10, &value) || value > 2)
2441 + return -EINVAL;
2443 + /* retrieve the other parameters to be stored as well */
2444 + if (sony_call_snc_handle(sony_gsensor->handle, 0x0200, &result))
2445 + return -EIO;
2446 + value |= (result & 0x1C); /* preserve only the needed bits */
2448 + if (sony_call_snc_handle(sony_gsensor->handle, (value << 0x10)
2449 + | 0x0300, &result))
2450 + return -EIO;
2452 + return count;
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)
2462 + return -ENOMEM;
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)
2470 + goto memerror;
2472 + /* check the storing device support */
2473 + if (sony_nc_gsensor_support_get(&support))
2474 + return -EIO;
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))
2480 + if (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]))
2523 + goto attrserror;
2526 + return 0;
2528 +attrserror:
2529 + for (; i > 0; i--)
2530 + device_remove_file(&pd->dev, &sony_gsensor->attrs[i]);
2532 + kfree(sony_gsensor->attrs);
2533 +memerror:
2534 + kfree(sony_gsensor);
2535 + sony_gsensor = NULL;
2537 + return -1;
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
2550 + */
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;
2560 + return 0;
2562 +/* end G sensor code */
2564 +static struct sony_battcare_data {
2565 + unsigned int handle;
2566 + struct device_attribute attrs[2];
2567 +} *sony_battcare;
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;
2576 + if (count > 31)
2577 + return -EINVAL;
2578 + if (strict_strtoul(buffer, 10, &value))
2579 + return -EINVAL;
2581 + /* limit values (2 bits):
2582 + * 00 - none
2583 + * 01 - 80%
2584 + * 10 - 50%
2585 + * 11 - 100%
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
2592 + */
2594 + /*
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
2600 + */
2601 + switch (value) {
2602 + case 0: /* disable */
2603 + cmd = 0x00;
2604 + break;
2605 + case 1: /* enable, 80% charge limit */
2606 + cmd = 0x11;
2607 + break;
2608 + case 2: /* enable, 50% charge limit */
2609 + cmd = 0x21;
2610 + break;
2611 + default:
2612 + return -EINVAL;
2615 + if (sony_call_snc_handle(sony_battcare->handle, (cmd << 0x10) | 0x0100,
2616 + &result))
2617 + return -EIO;
2619 + return count;
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))
2629 + return -EIO;
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);
2635 + return count;
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))
2645 + return -EIO;
2647 + count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
2649 + return count;
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)
2657 + return -ENOMEM;
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]))
2668 + goto outkzalloc;
2670 + if (handle == 0x0115) /* no health indication */
2671 + return 0;
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]))
2679 + goto outlimiter;
2681 + return 0;
2683 +outlimiter:
2684 + device_remove_file(&pd->dev, &sony_battcare->attrs[0]);
2685 +outkzalloc:
2686 + kfree(sony_battcare);
2687 + sony_battcare = NULL;
2689 + return -1;
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;
2703 + return 0;
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;
2711 +} *sony_thermal;
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 */
2720 + cmd = 2;
2721 + break;
2722 + case 2: /* silent */
2723 + cmd = 1;
2724 + break;
2725 + default: /* balanced */
2726 + cmd = 0;
2727 + break;
2730 + if (sony_call_snc_handle(0x0122, cmd << 0x10 | 0x0200, &result))
2731 + return -EIO;
2733 + sony_thermal->mode = profile;
2735 + return 0;
2738 +static int sony_nc_thermal_mode_get(unsigned int *profile)
2740 + unsigned int result;
2742 + if (sony_call_snc_handle(0x0122, 0x0100, &result))
2743 + return -EIO;
2745 + /* to avoid the 1 value hole when only 2 profiles are available */
2746 + switch (result & 0xff) {
2747 + case 2: /* performance */
2748 + *profile = 1;
2749 + break;
2750 + case 1: /* silent */
2751 + *profile = 2;
2752 + break;
2753 + default: /* balanced */
2754 + *profile = 0;
2755 + break;
2758 + return 0;
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;
2773 + if (count > 31)
2774 + return -EINVAL;
2775 + if (strict_strtoul(buffer, 10, &value) ||
2776 + value > (sony_thermal->profiles - 1))
2777 + return -EINVAL;
2779 + if (sony_nc_thermal_mode_set(value))
2780 + return -EIO;
2782 + return count;
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))
2792 + return -EIO;
2794 + count = snprintf(buffer, PAGE_SIZE, "%d\n", profile);
2796 + return count;
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)
2803 + return -ENOMEM;
2805 + if (sony_call_snc_handle(0x0122, 0x0000, &sony_thermal->profiles)) {
2806 + pr_warn("unable to retrieve the available profiles\n");
2807 + goto outkzalloc;
2810 + if (sony_nc_thermal_mode_get(&sony_thermal->mode)) {
2811 + pr_warn("unable to retrieve the current profile");
2812 + goto outkzalloc;
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))
2827 + goto outkzalloc;
2829 + if (device_create_file(&pd->dev, &sony_thermal->mode_attr))
2830 + goto outprofiles;
2832 + return 0;
2834 +outprofiles:
2835 + device_remove_file(&pd->dev, &sony_thermal->profiles_attr);
2836 +outkzalloc:
2837 + kfree(sony_thermal);
2838 + sony_thermal = NULL;
2839 + return -1;
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;
2851 + return 0;
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;
2873 + if (count > 31)
2874 + return -EINVAL;
2875 + if (strict_strtoul(buffer, 10, &value) || value > 3)
2876 + return -EINVAL;
2878 + /* 00 <- disabled
2879 + 01 <- resume from S4
2880 + 10 <- resume from S3
2881 + 11 <- resume from S4 and S3
2882 + */
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))
2885 + return -EIO;
2887 + return count;
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))
2897 + return -EIO;
2899 + count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 1) & 0x03);
2901 + return count;
2904 +static int sony_nc_lid_resume_setup(struct platform_device *pd)
2906 + sony_lid = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2907 + if (!sony_lid)
2908 + return -ENOMEM;
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)) {
2917 + kfree(sony_lid);
2918 + sony_lid = NULL;
2919 + return -1;
2922 + return 0;
2925 +static int sony_nc_lid_resume_cleanup(struct platform_device *pd)
2927 + if (sony_lid) {
2928 + device_remove_file(&pd->dev, sony_lid);
2929 + kfree(sony_lid);
2930 + sony_lid = NULL;
2933 + return 0;
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;
2945 + if (count > 31)
2946 + return -EINVAL;
2947 + if (strict_strtoul(buffer, 10, &value) || value > 1)
2948 + return -EINVAL;
2950 + if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
2951 + return -EIO;
2953 + return count;
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))
2963 + return -EIO;
2965 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
2967 + return count;
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");
2976 + return 0;
2979 + sony_hsc = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
2980 + if (!sony_hsc)
2981 + return -ENOMEM;
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)) {
2990 + kfree(sony_hsc);
2991 + sony_hsc = NULL;
2992 + return -1;
2995 + return 0;
2998 +static int sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
3000 + if (sony_hsc) {
3001 + device_remove_file(&pd->dev, sony_hsc);
3002 + kfree(sony_hsc);
3003 + sony_hsc = NULL;
3006 + return 0;
3009 +static struct sony_tpad_device {
3010 + unsigned int handle;
3011 + struct device_attribute attr;
3012 +} *sony_tpad;
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;
3021 + if (count > 31)
3022 + return -EINVAL;
3023 + if (strict_strtoul(buffer, 10, &value) || value > 1)
3024 + return -EINVAL;
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))
3029 + return -EIO;
3031 + return count;
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))
3041 + return -EINVAL;
3043 + /* 1 tpad off, 0 tpad on */
3044 + count = snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
3045 + return count;
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);
3052 + if (!sony_tpad)
3053 + return -ENOMEM;
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)) {
3064 + kfree(sony_tpad);
3065 + sony_tpad = NULL;
3066 + return -1;
3069 + return 0;
3072 +static int sony_nc_touchpad_cleanup(struct platform_device *pd)
3074 + if (sony_tpad) {
3075 + device_remove_file(&pd->dev, &sony_tpad->attr);
3076 + kfree(sony_tpad);
3077 + sony_tpad = NULL;
3080 + return 0;
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];
3090 +} *sony_fan;
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;
3099 + if (count > 31)
3100 + return -EINVAL;
3101 + if (strict_strtoul(buffer, 10, &value)
3102 + || value > sony_fan->speeds_num)
3103 + return -EINVAL;
3105 + if (sony_call_snc_handle(SONY_FAN_HANDLE,
3106 + (value << 0x10) | 0x0200, &result))
3107 + return -EIO;
3109 + return count;
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))
3119 + return -EINVAL;
3121 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
3122 + return count;
3125 +static ssize_t sony_nc_fan_profiles_show(struct device *dev,
3126 + struct device_attribute *attr, char *buffer)
3128 + ssize_t count = 0;
3129 + unsigned int i;
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");
3137 + return count;
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))
3147 + return -EINVAL;
3149 + count = snprintf(buffer, PAGE_SIZE, "%d\n",
3150 + (result & 0xff) * 100);
3151 + return count;
3154 +static int sony_nc_fan_setup(struct platform_device *pd)
3156 + int ret;
3157 + unsigned int i, found;
3158 + u8 list[FAN_SPEEDS_NUM * 2] = { 0 };
3160 + sony_fan = kzalloc(sizeof(struct sony_fan_device), GFP_KERNEL);
3161 + if (!sony_fan)
3162 + return -ENOMEM;
3164 + ret = sony_call_snc_handle_buffer(SONY_FAN_HANDLE, 0x0000,
3165 + list, FAN_SPEEDS_NUM * 2);
3166 + if (ret < 0)
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]))
3194 + goto attrserror;
3197 + return 0;
3199 +attrserror:
3200 + for (; i > 0; i--)
3201 + device_remove_file(&pd->dev, &sony_fan->attrs[i]);
3203 + kfree(sony_fan);
3204 + sony_fan = NULL;
3206 + return -1;
3209 +static int sony_nc_fan_cleanup(struct platform_device *pd)
3211 + if (sony_fan) {
3212 + int i;
3214 + for (i = 0; i < FAN_ATTRS_NUM; i++)
3215 + device_remove_file(&pd->dev, &sony_fan->attrs[i]);
3217 + kfree(sony_fan);
3218 + sony_fan = NULL;
3221 + return 0;
3224 +static struct sony_odd_device {
3225 + unsigned int vendor_id;
3226 + unsigned int model_id;
3227 + struct device_attribute status_attr;
3228 +} *sony_odd;
3230 +#if 0
3231 +static int sony_nc_odd_remove(void)
3233 + /*
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)
3237 + */
3239 + struct scsi_device *sdev;
3240 + struct Scsi_Host *shost;
3241 + int error = -ENXIO;
3243 + shost = scsi_host_lookup(host);
3244 + if (!shost)
3245 + return error;
3247 + sdev = scsi_device_lookup(shost, channel, id, lun);
3248 + if (sdev) {
3249 + scsi_remove_device(sdev);
3250 + scsi_device_put(sdev);
3251 + error = 0;
3254 + scsi_host_put(shost);
3256 + return 0;
3258 +#endif
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;
3267 + if (count > 31)
3268 + return -EINVAL;
3269 + if (strict_strtoul(buffer, 10, &value) || value > 1)
3270 + return -EINVAL;
3272 +#if 0
3273 + if (off)
3274 + sony_nc_odd_remove();
3276 + /* and goes on, otherwise leave */
3277 +#endif
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))
3284 + return -EIO;
3286 +#if 0
3287 + if (on)
3288 + /* force a bus scan? */
3289 +#endif
3291 + return count;
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))
3301 + return -EINVAL;
3303 + count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
3304 + return count;
3307 +static int sony_nc_odd_setup(struct platform_device *pd)
3309 +#define ODD_TAB_SIZE 32
3310 + u8 list[ODD_TAB_SIZE] = { 0 };
3311 + int ret = 0;
3312 + int found = 0;
3313 + int i = 0;
3314 + unsigned int vendor = 0;
3315 + unsigned int model = 0;
3316 + u16 word = 0;
3318 + ret = sony_call_snc_handle_buffer(0x126, 0x0000, list, ODD_TAB_SIZE);
3319 + if (ret < 0) {
3320 + pr_info("unable to retrieve the odd table\n");
3321 + return -EIO;
3324 + /* parse the table looking for optical devices */
3325 + do {
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];
3331 + found++;
3332 + i += 6;
3333 + } else {
3334 + i += 2;
3336 + } while (word != 0xff00);
3338 + if (found)
3339 + dprintk("one optical device found, connected to: %x:%x\n",
3340 + vendor, model);
3341 + else
3342 + return 0;
3344 + sony_odd = kzalloc(sizeof(*sony_odd), GFP_KERNEL);
3345 + if (!sony_odd)
3346 + return -ENOMEM;
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)) {
3358 + kfree(sony_odd);
3359 + sony_odd = NULL;
3360 + return -1;
3363 + return 0;
3366 +static int sony_nc_odd_cleanup(struct platform_device *pd)
3368 + if (sony_odd) {
3369 + device_remove_file(&pd->dev, &sony_odd->status_attr);
3370 + kfree(sony_odd);
3371 + sony_odd = NULL;
3374 + return 0;
3378 + * Backlight device
3379 + */
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))
3393 + return 0;
3394 + /* brightness levels are 1-based, while backlight ones are 0-based */
3395 + return value - 1;
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 */
3417 + if (sony_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",
3422 + &unused))) {
3423 + ops = &sony_backlight_ops;
3424 + max_brightness = SONY_MAX_BRIGHTNESS - 1;
3425 + } else {
3426 + return;
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,
3433 + ops, &props);
3435 + if (IS_ERR(sony_backlight_device)) {
3436 + pr_warn("unable to register backlight device\n");
3437 + sony_backlight_device = NULL;
3438 + } else {
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)
3452 + return;
3455 +/* place here some unknown handles, we might want to see some output */
3456 +static void sony_nc_tests_setup(void)
3458 + int ret;
3459 + unsigned int result;
3461 + result = 0;
3462 + ret = sony_call_snc_handle(0x114, 0x000, &result);
3463 + if (!ret)
3464 + pr_info("handle 0x114 returned: %x\n", result & 0xff);
3466 + result = 0;
3467 + ret = sony_call_snc_handle(0x139, 0x0000, &result);
3468 + if (!ret)
3469 + pr_info("handle 0x139+00 returned: %x\n", result & 0xffff);
3471 + result = 0;
3472 + ret = sony_call_snc_handle(0x139, 0x0100, &result);
3473 + if (!ret)
3474 + pr_info("handle 0x139+01 returned: %x\n", result & 0xffff);
3476 + return;
3479 +static void sony_nc_snc_setup_handles(struct platform_device *pd)
3481 + unsigned int i;
3483 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
3484 + int ret = 0;
3485 + int unsigned handle = handles->cap[i];
3487 + if (!handle)
3488 + continue;
3490 + dprintk("looking at handle 0x%.4x\n", handle);
3492 + switch (handle) {
3493 + case 0x0100:
3494 + case 0x0127:
3495 + case 0x0101:
3496 + case 0x0102:
3497 + ret = sony_nc_function_setup(handle);
3498 + break;
3499 + case 0x0105:
3500 + case 0x0148: /* same as 0x0105 + Fn-F1 combo */
3501 + ret = sony_nc_touchpad_setup(pd, handle);
3502 + break;
3503 + case 0x0115:
3504 + case 0x0136:
3505 + case 0x013f:
3506 + ret = sony_nc_battery_care_setup(pd, handle);
3507 + break;
3508 + case 0x0119:
3509 + ret = sony_nc_lid_resume_setup(pd);
3510 + break;
3511 + case 0x0122:
3512 + ret = sony_nc_thermal_setup(pd);
3513 + break;
3514 + case 0x0126:
3515 + ret = sony_nc_odd_setup(pd);
3516 + break;
3517 + case 0x0137:
3518 + case 0x0143:
3519 + ret = sony_nc_kbd_backlight_setup(pd, handle);
3520 + case 0x012f: /* no keyboard backlight */
3521 + ret = sony_nc_als_setup(pd, handle);
3522 + break;
3523 + case 0x0131:
3524 + ret = sony_nc_highspeed_charging_setup(pd);
3525 + break;
3526 + case 0x0134:
3527 + case 0x0147:
3528 + ret = sony_nc_gsensor_setup(pd, handle);
3529 + break;
3530 + case 0x0149:
3531 + ret = sony_nc_fan_setup(pd);
3532 + break;
3533 + case 0x0124:
3534 + case 0x0135:
3535 + ret = sony_nc_rfkill_setup(sony_nc_acpi_device, handle);
3536 + break;
3537 + default:
3538 + continue;
3541 + if (ret < 0) {
3542 + pr_warn("handle 0x%.4x setup failed (ret: %i)",
3543 + handle, ret);
3544 + } else {
3545 + dprintk("handle 0x%.4x setup completed\n", handle);
3549 -out_no_enum:
3550 - kfree(buffer.pointer);
3551 - return;
3552 + if (debug)
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 {
3564 - int mode;
3565 - int timeout;
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)
3575 - int result;
3576 + unsigned int i;
3578 - if (value > 1)
3579 - return -EINVAL;
3580 + for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
3582 - if (sony_call_snc_handle(KBDBL_HANDLER,
3583 - (value << 0x10) | SET_MODE, &result))
3584 - return -EIO;
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,
3589 - &result);
3590 + if (!handle)
3591 + continue;
3593 - kbdbl_handle->mode = value;
3594 + dprintk("looking at handle 0x%.4x\n", handle);
3596 - return 0;
3597 + switch (handle) {
3598 + case 0x0105:
3599 + case 0x0148:
3600 + sony_nc_touchpad_cleanup(pd);
3601 + break;
3602 + case 0x0115:
3603 + case 0x0136:
3604 + case 0x013f:
3605 + sony_nc_battery_care_cleanup(pd);
3606 + break;
3607 + case 0x0119:
3608 + sony_nc_lid_resume_cleanup(pd);
3609 + break;
3610 + case 0x0122:
3611 + sony_nc_thermal_cleanup(pd);
3612 + break;
3613 + case 0x0126:
3614 + sony_nc_odd_cleanup(pd);
3615 + break;
3616 + case 0x0137:
3617 + case 0x0143:
3618 + sony_nc_kbd_backlight_cleanup(pd);
3619 + case 0x012f:
3620 + sony_nc_als_cleanup(pd);
3621 + break;
3622 + case 0x0131:
3623 + sony_nc_highspeed_charging_cleanup(pd);
3624 + break;
3625 + case 0x0134:
3626 + case 0x0147:
3627 + sony_nc_gsensor_cleanup(pd);
3628 + break;
3629 + case 0x0149:
3630 + sony_nc_fan_cleanup(pd);
3631 + break;
3632 + case 0x0124:
3633 + case 0x0135:
3634 + sony_nc_rfkill_cleanup();
3635 + break;
3636 + default:
3637 + continue;
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)
3649 - int ret = 0;
3650 - unsigned long value;
3652 - if (count > 31)
3653 - return -EINVAL;
3655 - if (strict_strtoul(buffer, 10, &value))
3656 - return -EINVAL;
3657 + unsigned int i, string[4], bitmask, result;
3659 - ret = __sony_nc_kbd_backlight_mode_set(value);
3660 - if (ret < 0)
3661 - return ret;
3662 + for (i = 0; i < 4; i++) {
3663 + if (acpi_callsetfunc(sony_nc_acpi_handle,
3664 + "SN00", i, &string[i]))
3665 + return -EIO;
3667 + if (strncmp("SncSupported", (char *) string, 0x10)) {
3668 + pr_info("SNC device present but not supported by hardware");
3669 + return -1;
3672 - return count;
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);
3686 - return count;
3688 + /* retrieve the implemented offsets mask */
3689 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN00", 0x10, &bitmask))
3690 + return -EIO;
3692 -static int __sony_nc_kbd_backlight_timeout_set(u8 value)
3694 - int result;
3695 + /* retrieve the available handles, otherwise return */
3696 + if (sony_nc_handles_setup(pd))
3697 + return -2;
3699 - if (value > 3)
3700 - return -EINVAL;
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))
3708 return -EIO;
3710 - kbdbl_handle->timeout = value;
3711 + /* check for SN05 presence? */
3713 return 0;
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)
3721 - int ret = 0;
3722 - unsigned long value;
3723 + unsigned int result, bitmask;
3725 - if (count > 31)
3726 - return -EINVAL;
3727 + /* retrieve the event enabled handles */
3728 + acpi_callgetfunc(sony_nc_acpi_handle, "SN01", &bitmask);
3730 - if (strict_strtoul(buffer, 10, &value))
3731 - return -EINVAL;
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);
3736 - if (ret < 0)
3737 - return ret;
3738 + /* cleanup handles here */
3739 + sony_nc_snc_cleanup_handles(pd);
3741 - return count;
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);
3750 - return count;
3751 + return 0;
3754 -static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
3755 +static int sony_nc_snc_resume(void)
3757 - int result;
3758 + unsigned int i, result, bitmask;
3760 - if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
3761 - return 0;
3762 - if (!(result & 0x02))
3763 - return 0;
3764 + /* retrieve the implemented offsets mask */
3765 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN00", 0x10, &bitmask))
3766 + return -EIO;
3768 - kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
3769 - if (!kbdbl_handle)
3770 - return -ENOMEM;
3771 + /* Enable all events, otherwise return */
3772 + if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", bitmask, &result))
3773 + return -EIO;
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;
3789 + if (!handle)
3790 + continue;
3792 - if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
3793 - goto outkzalloc;
3794 + dprintk("looking at handle 0x%.4x\n", handle);
3796 - if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
3797 - goto outmode;
3798 + switch (handle) {
3799 + case 0x0100:
3800 + case 0x0127:
3801 + case 0x0101:
3802 + case 0x0102:
3803 + sony_nc_function_setup(handle);
3804 + break;
3805 + case 0x0122:
3806 + sony_nc_thermal_resume();
3807 + break;
3808 + case 0x0124:
3809 + case 0x0135:
3810 + /* re-read rfkill state */
3811 + sony_nc_rfkill_update();
3812 + break;
3813 + case 0x0137: /* kbd + als */
3814 + case 0x0143:
3815 + sony_nc_kbd_backlight_resume();
3816 + case 0x012f: /* als only */
3817 + sony_nc_als_resume();
3818 + break;
3819 + default:
3820 + continue;
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);
3828 - return 0;
3829 + if (debug)
3830 + sony_nc_tests_resume();
3832 -outmode:
3833 - device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
3834 -outkzalloc:
3835 - kfree(kbdbl_handle);
3836 - kbdbl_handle = NULL;
3837 - return -1;
3838 + return 0;
3841 -static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
3843 + * ACPI callbacks
3844 + */
3845 +static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
3846 + void *context, void **return_value)
3848 - if (kbdbl_handle) {
3849 - int result;
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);
3863 + kfree(info);
3865 - return 0;
3867 + return AE_OK;
3870 -static void sony_nc_kbd_backlight_resume(void)
3871 +#define EV_HOTKEYS 1
3872 +#define EV_RFKILL 2
3873 +#define EV_ALS 3
3874 +#define EV_GSENSOR 4
3875 +#define EV_HGFX 5
3876 +static void sony_nc_notify(struct acpi_device *device, u32 event)
3878 - int ignore = 0;
3879 + u8 ev = 0;
3880 + int value = 0;
3881 + char *env[2] = { NULL };
3883 - if (!kbdbl_handle)
3884 - return;
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];
3897 + switch (handle) {
3898 + /* list of handles known for generating events */
3899 + case 0x0100:
3900 + case 0x0127:
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 */
3906 + value = event;
3908 - if (kbdbl_handle->timeout != 0)
3909 - sony_call_snc_handle(KBDBL_HANDLER,
3910 - (kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
3911 - &ignore);
3913 + ev = EV_HOTKEYS;
3914 + break;
3916 -static void sony_nc_backlight_ng_read_limits(int handle,
3917 - struct sony_backlight_props *props)
3919 - int offset;
3920 - acpi_status status;
3921 - u8 brlvl, i;
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 };
3927 + case 0x0143:
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" :
3933 + "backlight");
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);
3942 - if (offset < 0)
3943 - return;
3944 + ev = EV_ALS;
3945 + break;
3947 - /* try to read the boundaries from ACPI tables, if we fail the above
3948 - * defaults should be reasonable
3949 - */
3950 - params.count = 1;
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", &params,
3955 - &buffer);
3956 - if (ACPI_FAILURE(status))
3957 - return;
3958 + case 0x012f:
3959 + case 0x0137:
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" :
3964 + "backlight");
3965 + if (value == 1) /* lighting change reason */
3966 + sony_nc_als_event_handler();
3968 - lvl_enum = (union acpi_object *) buffer.pointer;
3969 - if (!lvl_enum) {
3970 - pr_err("No SN06 return object.");
3971 - return;
3973 - if (lvl_enum->type != ACPI_TYPE_BUFFER) {
3974 - pr_err("Invalid SN06 return object 0x%.2x\n",
3975 - lvl_enum->type);
3976 - goto out_invalid;
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.
3983 - */
3984 - for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
3985 + ev = EV_ALS;
3986 + break;
3988 - brlvl = *(lvl_enum->buffer.pointer + i);
3989 - dprintk("Brightness level: %d\n", brlvl);
3990 + case 0x0124:
3991 + case 0x0135:
3992 + sony_call_snc_handle(handle, 0x0100, &result);
3993 + result &= 0x03;
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
4004 + */
4005 + sony_nc_rfkill_update_wwan();
4006 + return;
4009 - if (!brlvl)
4010 + ev = EV_RFKILL;
4011 break;
4013 - if (brlvl > max)
4014 - max = brlvl;
4015 - if (brlvl < min)
4016 - min = brlvl;
4018 - props->offset = min;
4019 - props->maxlvl = max;
4020 - dprintk("Brightness levels: min=%d max=%d\n", props->offset,
4021 - props->maxlvl);
4022 + case 0x0134:
4023 + case 0x0147:
4024 + ev = 4;
4025 + value = EV_GSENSOR;
4026 + /* hdd protection event, notify userspace */
4028 -out_invalid:
4029 - kfree(buffer.pointer);
4030 - return;
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;
4041 + break;
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;
4052 + case 0x0128:
4053 + case 0x0146:
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)*/
4062 + result = 0;
4063 + sony_call_snc_handle(handle, 0x0100, &result);
4065 - } else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
4066 - &unused))) {
4067 - ops = &sony_backlight_ops;
4068 - max_brightness = SONY_MAX_BRIGHTNESS - 1;
4069 + /* sony_laptop_report_input_event(); */
4071 - } else
4072 - return;
4073 + ev = EV_HGFX;
4074 + value = result & 0xff;
4075 + break;
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,
4081 - &sony_bl_props,
4082 - ops, &props);
4083 + default:
4084 + value = event;
4085 + dprintk("Unknowk event for handle: 0x%x\n", handle);
4086 + break;
4089 - if (IS_ERR(sony_bl_props.dev)) {
4090 - pr_warn("unable to register backlight device\n");
4091 - sony_bl_props.dev = NULL;
4092 - } else
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,
4098 + &result);
4099 + } else {
4100 + ev = 1;
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");
4123 result = -ENODEV;
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",
4126 &handle))) {
4127 dprintk("Doing SNC setup\n");
4128 - result = sony_nc_handles_setup(sony_pf_device);
4129 - if (result)
4130 - goto outpresent;
4131 - result = sony_nc_kbd_backlight_setup(sony_pf_device);
4132 - if (result)
4134 + if (sony_nc_snc_setup(sony_pf_device))
4135 goto outsnc;
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);
4142 if (result) {
4143 pr_err("Unable to create input devices\n");
4144 - goto outkbdbacklight;
4145 + goto outsnc;
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");
4152 } else {
4153 sony_nc_backlight_setup();
4155 @@ -1783,25 +4440,21 @@ static int sony_nc_add(struct acpi_devic
4157 return 0;
4159 - out_sysfs:
4160 - for (item = sony_nc_values; item->name; ++item) {
4161 +out_sysfs:
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();
4170 - outkbdbacklight:
4171 - sony_nc_kbd_backlight_cleanup(sony_pf_device);
4173 - outsnc:
4174 - sony_nc_handles_cleanup(sony_pf_device);
4175 +outsnc:
4176 + sony_nc_snc_cleanup(sony_pf_device);
4178 - outpresent:
4179 +outpresent:
4180 sony_pf_remove();
4182 - outwalk:
4183 - sony_nc_rfkill_cleanup();
4184 +outwalk:
4185 return result;
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);
4200 sony_pf_remove();
4201 sony_laptop_remove_input();
4202 - sony_nc_rfkill_cleanup();
4203 dprintk(SONY_NC_DRIVER_NAME " removed.\n");
4205 return 0;
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++) {
4214 + int ret;
4216 + if (!item->valid)
4217 + continue;
4218 + ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
4219 + item->value, NULL);
4220 + if (ret < 0) {
4221 + pr_err("%s: %d\n", __func__, ret);
4222 + break;
4226 + if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
4227 + &handle))) {
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",
4233 + &handle))) {
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");
4244 + return 0;
4247 static const struct acpi_device_id sony_device_ids[] = {
4248 {SONY_NC_HID, 0},
4249 {SONY_PIC_HID, 0},
4250 @@ -2165,11 +4854,14 @@ static u8 sony_pic_call3(u8 dev, u8 fn,
4252 u8 v1;
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,
4256 + ITERATIONS_LONG);
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,
4260 + ITERATIONS_LONG);
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,
4264 + ITERATIONS_LONG);
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();
4296 break;
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);
4302 break;
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);
4308 break;
4309 case SONY_PIC_COMMAND_SETCAMERAHUE:
4310 wait_on_command(sony_pic_call3(0x90, SONYPI_CAMERA_HUE, value),
4311 ITERATIONS_SHORT);
4312 break;
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);
4318 break;
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);
4324 break;
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);
4330 break;
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(
4334 if (count > 31)
4335 return -EINVAL;
4337 - value = simple_strtoul(buffer, NULL, 10);
4338 + if (strict_strtoul(buffer, 10, &value))
4339 + return -EINVAL;
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
4345 if (count > 31)
4346 return -EINVAL;
4348 - value = simple_strtoul(buffer, NULL, 10);
4349 + if (strict_strtoul(buffer, 10, &value))
4350 + return -EINVAL;
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
4356 if (count > 31)
4357 return -EINVAL;
4359 - value = simple_strtoul(buffer, NULL, 10);
4360 + if (strict_strtoul(buffer, 10, &value))
4361 + return -EINVAL;
4363 if (sony_pic_set_fanspeed(value))
4364 return -EIO;
4366 @@ -2659,12 +5357,12 @@ static long sonypi_misc_ioctl(struct fil
4367 void __user *argp = (void __user *)arg;
4368 u8 val8;
4369 u16 val16;
4370 - int value;
4371 + unsigned int value;
4373 mutex_lock(&spic_dev.lock);
4374 switch (cmd) {
4375 case SONYPI_IOCGBRT:
4376 - if (sony_bl_props.dev == NULL) {
4377 + if (sony_backlight_device == NULL) {
4378 ret = -EIO;
4379 break;
4381 @@ -2677,7 +5375,7 @@ static long sonypi_misc_ioctl(struct fil
4382 ret = -EFAULT;
4383 break;
4384 case SONYPI_IOCSBRT:
4385 - if (sony_bl_props.dev == NULL) {
4386 + if (sony_backlight_device == NULL) {
4387 ret = -EIO;
4388 break;
4390 @@ -2691,8 +5389,8 @@ static long sonypi_misc_ioctl(struct fil
4391 break;
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);
4398 break;
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);
4408 if (!ioport)
4409 return AE_ERROR;
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);
4418 if (!io) {
4419 dprintk("Blank IO resource\n");
4420 return AE_OK;
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);
4438 - else {
4439 - pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
4440 + } else {
4441 + pr_err("Unknown SPIC Type, "
4442 + "more than 2 IO Ports\n");
4443 return AE_ERROR;
4445 return AE_OK;
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) "
4457 + "+ 0x%.2x\n",
4458 + io->io2.minimum,
4459 + io->io2.maximum,
4460 io->io2.address_length);
4461 spic_dev.cur_ioport = io;
4462 break;
4464 - else {
4465 + } else {
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) "
4470 + "+ 0x%.2x\n",
4471 + io->io2.minimum,
4472 + io->io2.maximum,
4473 io->io2.address_length);
4474 release_region(io->io1.minimum,
4475 io->io1.address_length);
4478 - else {
4479 + } else {
4480 spic_dev.cur_ioport = io;
4481 break;
4483 @@ -3281,7 +5984,7 @@ static int sony_pic_add(struct acpi_devi
4484 /* request IRQ */
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
4493 if (result)
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);
4499 if (result)
4500 goto err_remove_pf;