Signed-off-by: Marco Chiappero <marco@absence.it>
--- a/include/linux/sonypi.h	2011-04-21 23:34:46.000000000 +0200
+++ b/include/linux/sonypi.h	2011-04-22 17:15:33.832788228 +0200
@@ -40,6 +40,7 @@
 
 /* events the user application reading /dev/sonypi can use */
 
+#define SONYPI_EVENT_IGNORE			 0
 #define SONYPI_EVENT_JOGDIAL_DOWN		 1
 #define SONYPI_EVENT_JOGDIAL_UP			 2
 #define SONYPI_EVENT_JOGDIAL_DOWN_PRESSED	 3
@@ -113,6 +114,7 @@
 #define SONYPI_EVENT_BRIGHTNESS_PRESSED		71
 #define SONYPI_EVENT_MEDIA_PRESSED		72
 #define SONYPI_EVENT_VENDOR_PRESSED		73
+#define SONYPI_EVENT_RFKILL_ALL			74
 
 /* get/set brightness */
 #define SONYPI_IOCGBRT		_IOR('v', 0, __u8)
--- a/drivers/platform/x86/sony-laptop.c	2011-04-21 23:34:46.000000000 +0200
+++ b/drivers/platform/x86/sony-laptop.c	2011-04-26 22:01:44.442776767 +0200
@@ -2,7 +2,8 @@
  * ACPI Sony Notebook Control Driver (SNC and SPIC)
  *
  * Copyright (C) 2004-2005 Stelian Pop <stelian@popies.net>
- * Copyright (C) 2007-2009 Mattia Dongili <malattia@linux.it>
+ * Copyright (C) 2007-2011 Mattia Dongili <malattia@linux.it>
+ * Copyright (C) 2011 Marco Chiappero <marco@absence.it>
  *
  * Parts of this driver inspired from asus_acpi.c and ibm_acpi.c
  * which are copyrighted by their respective authors.
@@ -42,6 +43,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
@@ -61,7 +64,7 @@
 #include <linux/slab.h>
 #include <acpi/acpi_drivers.h>
 #include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <linux/sonypi.h>
 #include <linux/sony-laptop.h>
 #include <linux/rfkill.h>
@@ -71,8 +74,10 @@
 #endif
 
 #define DRV_PFX			"sony-laptop: "
-#define dprintk(msg...)		do {			\
-	if (debug) printk(KERN_WARNING DRV_PFX  msg);	\
+#define dprintk(fmt, ...)			\
+do {						\
+	if (debug)				\
+		pr_warn(fmt, ##__VA_ARGS__);	\
 } while (0)
 
 #define SONY_LAPTOP_DRIVER_VERSION	"0.6"
@@ -124,18 +129,22 @@ MODULE_PARM_DESC(minor,
 		 "default is -1 (automatic)");
 #endif
 
-enum sony_nc_rfkill {
-	SONY_WIFI,
-	SONY_BLUETOOTH,
-	SONY_WWAN,
-	SONY_WIMAX,
-	N_SONY_RFKILL,
-};
+static int kbd_backlight;	/* = 0 */
+module_param(kbd_backlight, int, 0444);
+MODULE_PARM_DESC(kbd_backlight,
+		 "set this to 0 to disable keyboard backlight, "
+		 "1 to enable it (default: 0)");
+
+static int kbd_backlight_timeout;	/* = 0 */
+module_param(kbd_backlight_timeout, int, 0444);
+MODULE_PARM_DESC(kbd_backlight_timeout,
+		 "set this to 0 to set the default 10 seconds timeout, "
+		 "1 for 30 seconds, 2 for 60 seconds and 3 to disable timeout "
+		 "(default: 0)");
 
-static int sony_rfkill_handle;
-static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
-static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
-static void sony_nc_rfkill_update(void);
+
+static int sony_rfkill_handle = -1;
+static int sony_nc_get_rfkill_hwblock(void);
 
 /*********** Input Devices ***********/
 
@@ -236,6 +245,7 @@ static int sony_laptop_input_index[] = {
 	-1,	/* 71 SONYPI_EVENT_BRIGHTNESS_PRESSED */
 	58,	/* 72 SONYPI_EVENT_MEDIA_PRESSED */
 	59,	/* 72 SONYPI_EVENT_VENDOR_PRESSED */
+	-1,	/* 74 SONYPI_EVENT_RFKILL_ALL */
 };
 
 static int sony_laptop_input_keycode_map[] = {
@@ -329,6 +339,7 @@ static void sony_laptop_report_input_eve
 	struct input_dev *jog_dev = sony_laptop_input.jog_dev;
 	struct input_dev *key_dev = sony_laptop_input.key_dev;
 	struct sony_laptop_keypress kp = { NULL };
+	int rfk_switch;
 
 	if (event == SONYPI_EVENT_FNKEY_RELEASED ||
 			event == SONYPI_EVENT_ANYBUTTON_RELEASED) {
@@ -357,9 +368,18 @@ static void sony_laptop_report_input_eve
 		kp.dev = jog_dev;
 		break;
 
+	case SONYPI_EVENT_RFKILL_ALL:
+		rfk_switch = sony_nc_get_rfkill_hwblock();
+		if (!(rfk_switch < 0)) {
+			input_report_switch(key_dev, SW_RFKILL_ALL, rfk_switch);
+			input_sync(key_dev);
+		}
+		return;
+
 	default:
 		if (event >= ARRAY_SIZE(sony_laptop_input_index)) {
-			dprintk("sony_laptop_report_input_event, event not known: %d\n", event);
+			dprintk("sony_laptop_report_input_event, "
+				"event not known: %d\n", event);
 			break;
 		}
 		if (sony_laptop_input_index[event] != -1) {
@@ -402,7 +422,7 @@ static int sony_laptop_setup_input(struc
 	error = kfifo_alloc(&sony_laptop_input.fifo,
 			    SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
 	if (error) {
-		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+		pr_err("kfifo_alloc failed\n");
 		goto err_dec_users;
 	}
 
@@ -432,6 +452,14 @@ static int sony_laptop_setup_input(struc
 		__set_bit(sony_laptop_input_keycode_map[i], key_dev->keybit);
 	__clear_bit(KEY_RESERVED, key_dev->keybit);
 
+	if (sony_rfkill_handle != -1) {
+		int rfk_switch;
+
+		rfk_switch = sony_nc_get_rfkill_hwblock();
+		input_set_capability(key_dev, EV_SW, SW_RFKILL_ALL);
+		input_report_switch(key_dev, SW_RFKILL_ALL, rfk_switch);
+	}
+
 	error = input_register_device(key_dev);
 	if (error)
 		goto err_free_keydev;
@@ -547,12 +575,12 @@ static int sony_pf_add(void)
 
 	return 0;
 
-      out_platform_alloced:
+out_platform_alloced:
 	platform_device_put(sony_pf_device);
 	sony_pf_device = NULL;
-      out_platform_registered:
+out_platform_registered:
 	platform_driver_unregister(&sony_pf_driver);
-      out:
+out:
 	atomic_dec(&sony_pf_users);
 	return ret;
 }
@@ -646,7 +674,8 @@ static struct sony_nc_value sony_nc_valu
 	SNC_HANDLE(brightness_default, snc_brightness_def_get,
 			snc_brightness_def_set, brightness_default_validate, 0),
 	SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0),
-	SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0),
+	SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set,
+			boolean_validate, 0),
 	SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set,
 			boolean_validate, 0),
 	SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set,
@@ -666,12 +695,13 @@ static struct sony_nc_value sony_nc_valu
 };
 
 static acpi_handle sony_nc_acpi_handle;
-static struct acpi_device *sony_nc_acpi_device = NULL;
+static struct acpi_device *sony_nc_acpi_device;
 
 /*
  * acpi_evaluate_object wrappers
  */
-static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
+static int acpi_callgetfunc(acpi_handle handle, char *name,
+				unsigned int *result)
 {
 	struct acpi_buffer output;
 	union acpi_object out_obj;
@@ -686,13 +716,13 @@ static int acpi_callgetfunc(acpi_handle 
 		return 0;
 	}
 
-	printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n");
+	pr_warn("acpi_callreadfunc failed\n");
 
 	return -1;
 }
 
-static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
-			    int *result)
+static int acpi_callsetfunc(acpi_handle handle, char *name, u32 value,
+				unsigned int *result)
 {
 	struct acpi_object_list params;
 	union acpi_object in_obj;
@@ -712,7 +742,7 @@ static int acpi_callsetfunc(acpi_handle 
 	if (status == AE_OK) {
 		if (result != NULL) {
 			if (out_obj.type != ACPI_TYPE_INTEGER) {
-				printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad "
+				pr_warn("acpi_evaluate_object bad "
 				       "return type\n");
 				return -1;
 			}
@@ -721,34 +751,201 @@ static int acpi_callsetfunc(acpi_handle 
 		return 0;
 	}
 
-	printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n");
+	pr_warn("acpi_evaluate_object failed\n");
 
 	return -1;
 }
 
-static int sony_find_snc_handle(int handle)
+static int acpi_callsetfunc_buffer(acpi_handle handle, u64 value,
+					u8 array[], unsigned int size)
+{
+	u8 buffer[sizeof(value)];
+	int length = -1;
+	struct acpi_object_list params;
+	union acpi_object in_obj;
+	union acpi_object *values;
+	struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL};
+	acpi_status status;
+
+	if (!array || !size)
+		return length;
+
+	/* use a buffer type as parameter to overcome any 32 bits ACPI limit */
+	memcpy(buffer, &value, sizeof(buffer));
+
+	params.count = 1;
+	params.pointer = &in_obj;
+	in_obj.type = ACPI_TYPE_BUFFER;
+	in_obj.buffer.length = sizeof(buffer);
+	in_obj.buffer.pointer = buffer;
+
+	/* since SN06 is the only known method returning a buffer we
+	 * can hard code it, it is not necessary to have a parameter
+	 */
+	status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
+			&output);
+	values = (union acpi_object *) output.pointer;
+	if (ACPI_FAILURE(status) || !values) {
+		dprintk("acpi_evaluate_object failed\n");
+		goto error;
+	}
+
+	/* some buggy DSDTs return integer when the output does
+	   not execede the 4 bytes size
+	*/
+	if (values->type == ACPI_TYPE_BUFFER) {
+		if (values->buffer.length <= 0)
+			goto error;
+
+		length = size > values->buffer.length ?
+			values->buffer.length : size;
+
+		memcpy(array, values->buffer.pointer, length);
+	} else if (values->type == ACPI_TYPE_INTEGER) {
+		u32 result = values->integer.value;
+		if (size < 4)
+			goto error;
+
+		length = 0;
+		while (length != 4) {
+			array[length] = result & 0xff;
+			result >>= 8;
+			length++;
+		}
+	} else {
+		pr_err("Invalid return object 0x%.2x\n", values->type);
+		goto error;
+	}
+
+error:
+	kfree(output.pointer);
+	return length;
+}
+
+/*
+ *  SNC handles list
+ */
+struct sony_nc_handles {
+	u16 cap[0x10];
+	struct device_attribute devattr;
+};
+
+static struct sony_nc_handles *handles;
+
+static ssize_t sony_nc_handles_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
 {
+	ssize_t len = 0;
 	int i;
-	int result;
 
-	for (i = 0x20; i < 0x30; i++) {
-		acpi_callsetfunc(sony_nc_acpi_handle, "SN00", i, &result);
-		if (result == handle)
-			return i-0x20;
+	for (i = 0; i < 0x10; i++) {
+		len += snprintf(buffer + len, PAGE_SIZE - len, "0x%.4x ",
+				handles->cap[i]);
+	}
+	len += snprintf(buffer + len, PAGE_SIZE - len, "\n");
+
+	return len;
+}
+
+static int sony_nc_handles_setup(struct platform_device *pd)
+{
+	int i;
+	unsigned int result;
+
+	handles = kzalloc(sizeof(*handles), GFP_KERNEL);
+	if (!handles)
+		return -ENOMEM;
+
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+		if (!acpi_callsetfunc(sony_nc_acpi_handle,
+					"SN00", i + 0x20, &result)) {
+			dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
+					result, i);
+			handles->cap[i] = result;
+		}
+	}
+
+	if (debug) {
+		sysfs_attr_init(&handles->devattr.attr);
+		handles->devattr.attr.name = "handles";
+		handles->devattr.attr.mode = S_IRUGO;
+		handles->devattr.show = sony_nc_handles_show;
+
+		/* allow reading capabilities via sysfs */
+		if (device_create_file(&pd->dev, &handles->devattr)) {
+			kfree(handles);
+			handles = NULL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static int sony_nc_handles_cleanup(struct platform_device *pd)
+{
+	if (handles) {
+		if (debug)
+			device_remove_file(&pd->dev, &handles->devattr);
+		kfree(handles);
+		handles = NULL;
 	}
+	return 0;
+}
+
+static int sony_find_snc_handle(int handle)
+{
+	int i;
+
+	/* not initialized yet, return early */
+	if (!handles)
+		return -1;
 
+	for (i = 0; i < 0x10; i++) {
+		if (handles->cap[i] == handle) {
+			dprintk("found handle 0x%.4x (offset: 0x%.2x)\n",
+					handle, i);
+			return i;
+		}
+	}
+	dprintk("handle 0x%.4x not found\n", handle);
 	return -1;
 }
 
-static int sony_call_snc_handle(int handle, int argument, int *result)
+/* call command method SN07, accepts a 32 bit integer, returns a integer */
+static int sony_call_snc_handle(int handle, unsigned int argument,
+				unsigned int *result)
+{
+	int ret = 0;
+	int offset = sony_find_snc_handle(handle);
+
+	if (offset < 0)
+		return -1;
+
+	/* max 32 bit wide argument, for wider input use SN06 */
+	ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07",
+			offset | argument, result);
+	dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n",
+			offset | argument, *result);
+	return ret;
+}
+
+/* call command method SN06, accepts a wide input buffer, returns a buffer */
+static int sony_call_snc_handle_buffer(int handle, u64 argument, u8 result[],
+					unsigned int size)
 {
+	int ret = 0;
 	int offset = sony_find_snc_handle(handle);
 
 	if (offset < 0)
 		return -1;
 
-	return acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
-				result);
+	ret = acpi_callsetfunc_buffer(sony_nc_acpi_handle,
+			offset | argument, result, size);
+	dprintk("called SN06 with 0x%.4llx (%u bytes read)\n",
+			offset | argument, ret);
+
+	return ret;
 }
 
 /*
@@ -763,11 +960,11 @@ static int sony_call_snc_handle(int hand
 static int brightness_default_validate(const int direction, const int value)
 {
 	switch (direction) {
-		case SNC_VALIDATE_OUT:
-			return value - 1;
-		case SNC_VALIDATE_IN:
-			if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
-				return value + 1;
+	case SNC_VALIDATE_OUT:
+		return value - 1;
+	case SNC_VALIDATE_IN:
+		if (value >= 0 && value < SONY_MAX_BRIGHTNESS)
+			return value + 1;
 	}
 	return -EINVAL;
 }
@@ -789,10 +986,11 @@ static int boolean_validate(const int di
 /*
  * Sysfs show/store common to all sony_nc_values
  */
-static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
-			      char *buffer)
+static ssize_t sony_nc_sysfs_show(struct device *dev,
+					struct device_attribute *attr,
+					char *buffer)
 {
-	int value;
+	unsigned int value;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
 
@@ -812,7 +1010,8 @@ static ssize_t sony_nc_sysfs_store(struc
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
-	int value;
+	int ret;
+	long value;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
 
@@ -822,7 +1021,9 @@ static ssize_t sony_nc_sysfs_store(struc
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	ret = strict_strtoul(buffer, 10, &value);
+	if (ret)
+		return ret;
 
 	if (item->validate)
 		value = item->validate(SNC_VALIDATE_IN, value);
@@ -830,39 +1031,14 @@ static ssize_t sony_nc_sysfs_store(struc
 	if (value < 0)
 		return value;
 
-	if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
+	if (acpi_callsetfunc(sony_nc_acpi_handle,
+				*item->acpiset, value, NULL) < 0)
 		return -EIO;
 	item->value = value;
 	item->valid = 1;
 	return count;
 }
 
-
-/*
- * Backlight device
- */
-static int sony_backlight_update_status(struct backlight_device *bd)
-{
-	return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
-				bd->props.brightness + 1, NULL);
-}
-
-static int sony_backlight_get_brightness(struct backlight_device *bd)
-{
-	int value;
-
-	if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
-		return 0;
-	/* brightness levels are 1-based, while backlight ones are 0-based */
-	return value - 1;
-}
-
-static struct backlight_device *sony_backlight_device;
-static const struct backlight_ops sony_backlight_ops = {
-	.update_status = sony_backlight_update_status,
-	.get_brightness = sony_backlight_get_brightness,
-};
-
 /*
  * New SNC-only Vaios event mapping to driver known keys
  */
@@ -872,10 +1048,6 @@ struct sony_nc_event {
 };
 
 static struct sony_nc_event sony_100_events[] = {
-	{ 0x90, SONYPI_EVENT_PKEY_P1 },
-	{ 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
-	{ 0x91, SONYPI_EVENT_PKEY_P2 },
-	{ 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
 	{ 0x81, SONYPI_EVENT_FNKEY_F1 },
 	{ 0x01, SONYPI_EVENT_FNKEY_RELEASED },
 	{ 0x82, SONYPI_EVENT_FNKEY_F2 },
@@ -890,12 +1062,20 @@ static struct sony_nc_event sony_100_eve
 	{ 0x06, SONYPI_EVENT_FNKEY_RELEASED },
 	{ 0x87, SONYPI_EVENT_FNKEY_F7 },
 	{ 0x07, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x88, SONYPI_EVENT_FNKEY_F8 },
+	{ 0x08, SONYPI_EVENT_FNKEY_RELEASED },
 	{ 0x89, SONYPI_EVENT_FNKEY_F9 },
 	{ 0x09, SONYPI_EVENT_FNKEY_RELEASED },
 	{ 0x8A, SONYPI_EVENT_FNKEY_F10 },
 	{ 0x0A, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x8B, SONYPI_EVENT_FNKEY_F11 },
+	{ 0x0B, SONYPI_EVENT_FNKEY_RELEASED },
 	{ 0x8C, SONYPI_EVENT_FNKEY_F12 },
 	{ 0x0C, SONYPI_EVENT_FNKEY_RELEASED },
+	{ 0x90, SONYPI_EVENT_PKEY_P1 },
+	{ 0x10, SONYPI_EVENT_ANYBUTTON_RELEASED },
+	{ 0x91, SONYPI_EVENT_PKEY_P2 },
+	{ 0x11, SONYPI_EVENT_ANYBUTTON_RELEASED },
 	{ 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
 	{ 0x1d, SONYPI_EVENT_ANYBUTTON_RELEASED },
 	{ 0x9f, SONYPI_EVENT_CD_EJECT_PRESSED },
@@ -932,71 +1112,13 @@ static struct sony_nc_event sony_127_eve
 /*
  * ACPI callbacks
  */
-static void sony_nc_notify(struct acpi_device *device, u32 event)
-{
-	u32 ev = event;
-
-	if (ev >= 0x90) {
-		/* New-style event */
-		int result;
-		int key_handle = 0;
-		ev -= 0x90;
-
-		if (sony_find_snc_handle(0x100) == ev)
-			key_handle = 0x100;
-		if (sony_find_snc_handle(0x127) == ev)
-			key_handle = 0x127;
-
-		if (key_handle) {
-			struct sony_nc_event *key_event;
-
-			if (sony_call_snc_handle(key_handle, 0x200, &result)) {
-				dprintk("sony_nc_notify, unable to decode"
-					" event 0x%.2x 0x%.2x\n", key_handle,
-					ev);
-				/* restore the original event */
-				ev = event;
-			} else {
-				ev = result & 0xFF;
-
-				if (key_handle == 0x100)
-					key_event = sony_100_events;
-				else
-					key_event = sony_127_events;
-
-				for (; key_event->data; key_event++) {
-					if (key_event->data == ev) {
-						ev = key_event->event;
-						break;
-					}
-				}
-
-				if (!key_event->data)
-					printk(KERN_INFO DRV_PFX
-							"Unknown event: 0x%x 0x%x\n",
-							key_handle,
-							ev);
-				else
-					sony_laptop_report_input_event(ev);
-			}
-		} else if (sony_find_snc_handle(sony_rfkill_handle) == ev) {
-			sony_nc_rfkill_update();
-			return;
-		}
-	} else
-		sony_laptop_report_input_event(ev);
-
-	dprintk("sony_nc_notify, event: 0x%.2x\n", ev);
-	acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
-}
-
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
 				      void *context, void **return_value)
 {
 	struct acpi_device_info *info;
 
 	if (ACPI_SUCCESS(acpi_get_object_info(handle, &info))) {
-		printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n",
+		pr_warn("method: name: %4.4s, args %X\n",
 			(char *)&info->name, info->param_count);
 
 		kfree(info);
@@ -1008,241 +1130,2935 @@ static acpi_status sony_walk_callback(ac
 /*
  * ACPI device
  */
-static int sony_nc_function_setup(struct acpi_device *device)
+static int sony_nc_function_setup(unsigned int handle)
 {
-	int result;
+	unsigned int result;
 
-	/* Enable all events */
-	acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result);
+	sony_call_snc_handle(handle, 0, &result);
 
-	/* Setup hotkeys */
-	sony_call_snc_handle(0x0100, 0, &result);
-	sony_call_snc_handle(0x0101, 0, &result);
-	sony_call_snc_handle(0x0102, 0x100, &result);
-	sony_call_snc_handle(0x0127, 0, &result);
+	if (handle == 0x0102)
+		sony_call_snc_handle(0x0102, 0x100, &result);
 
 	return 0;
 }
 
-static int sony_nc_resume(struct acpi_device *device)
+static int sony_nc_hotkeys_decode(unsigned int handle)
 {
-	struct sony_nc_value *item;
-	acpi_handle handle;
+	int ret = 0;
+	unsigned int result = 0;
+	struct sony_nc_event *key_event;
 
-	for (item = sony_nc_values; item->name; item++) {
-		int ret;
+	if (sony_call_snc_handle(handle, 0x200, &result)) {
+		dprintk("sony_nc_hotkeys_decode,"
+				" unable to retrieve the hotkey\n");
+		ret = -1;
+	} else {
+		result &= 0xff;
 
-		if (!item->valid)
-			continue;
-		ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
-				       item->value, NULL);
-		if (ret < 0) {
-			printk("%s: %d\n", __func__, ret);
-			break;
+		if (handle == 0x100)
+			key_event = sony_100_events;
+		else
+			key_event = sony_127_events;
+
+		for (; key_event->data; key_event++) {
+			if (key_event->data == result) {
+				ret = key_event->event;
+				break;
+			}
 		}
+
+		if (!key_event->data)
+			pr_info("Unknown hotkey 0x%.2x (handle 0x%.2x)\n",
+							result, handle);
+		else
+			dprintk("sony_nc_hotkeys_decode, hotkey 0x%.2x decoded "
+					"to event 0x%.2x\n", result, ret);
 	}
 
-	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
-					 &handle))) {
-		if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
-			dprintk("ECON Method failed\n");
+	return ret;
+}
+
+enum sony_nc_rfkill {
+	SONY_WIFI,
+	SONY_BLUETOOTH,
+	SONY_WWAN,
+	SONY_WIMAX,
+	N_SONY_RFKILL,
+};
+static struct rfkill *sony_rfkill_devices[N_SONY_RFKILL];
+static int sony_rfkill_address[N_SONY_RFKILL] = {0x300, 0x500, 0x700, 0x900};
+
+static int sony_nc_rfkill_update_wwan(void)
+{
+	unsigned int result, cmd;
+	bool battery;
+	bool swblock;
+
+	if (sony_call_snc_handle(sony_rfkill_handle, 0x0200, &result))
+		return -EIO;
+	battery = !!(result & 0x2);
+
+	/* retrieve the device block state */
+	if (sony_call_snc_handle(sony_rfkill_handle,
+				sony_rfkill_address[SONY_WWAN], &result))
+		return -EIO;
+	swblock = !(result & 0x02);
+
+	if (battery && !swblock) {
+		/* set the power state according with swblock */
+		cmd = 0xff0000;
+	} else if (!battery && !swblock) {
+		swblock = true;
+		cmd = 0x20000;
+	} else {
+		return 0;
+	}
+
+	cmd |= sony_rfkill_address[SONY_WWAN] + 0x100;
+
+	/* set the power state */
+	sony_call_snc_handle(sony_rfkill_handle, cmd, &result);
+
+	/* update the rfkill sw state */
+	rfkill_set_sw_state(sony_rfkill_devices[SONY_WWAN], swblock);
+
+	return 0;
+}
+
+static int sony_nc_get_rfkill_hwblock(void)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result))
+		return -1;
+
+	return result & 0x1;
+}
+
+static void sony_nc_rfkill_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < N_SONY_RFKILL; i++) {
+		if (sony_rfkill_devices[i]) {
+			rfkill_unregister(sony_rfkill_devices[i]);
+			rfkill_destroy(sony_rfkill_devices[i]);
+		}
+	}
+}
+
+static int sony_nc_rfkill_set(void *data, bool blocked)
+{
+	unsigned int result;
+	int argument = sony_rfkill_address[(long) data];
+
+	/* wwan state change not allowed when the battery is not present */
+	sony_call_snc_handle(sony_rfkill_handle, 0x0200, &result);
+	if (((long) data == SONY_WWAN) && !(result & 0x2)) {
+		if (!blocked) {
+			/* notify user space: the battery must be present */
+			acpi_bus_generate_proc_event(sony_nc_acpi_device,
+				       2, 2);
+			acpi_bus_generate_netlink_event(
+					sony_nc_acpi_device->pnp.device_class,
+					dev_name(&sony_nc_acpi_device->dev),
+					2, 2);
+		}
+
+		return -1;
+	}
+
+	/* do not force an already set state */
+	sony_call_snc_handle(sony_rfkill_handle, argument, &result);
+	if ((result & 0x1) == !blocked)
+		return 0;
+
+	argument += 0x100;
+	if (!blocked)
+		argument |= 0xff0000;
+
+	return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
+}
+
+static const struct rfkill_ops sony_rfkill_ops = {
+	.set_block = sony_nc_rfkill_set,
+};
+
+static int sony_nc_setup_rfkill(struct acpi_device *device,
+				enum sony_nc_rfkill nc_type)
+{
+	int err = 0;
+	struct rfkill *rfk;
+	enum rfkill_type type;
+	const char *name;
+	unsigned int result;
+	bool hwblock, swblock, wwblock;
+
+	switch (nc_type) {
+	case SONY_WIFI:
+		type = RFKILL_TYPE_WLAN;
+		name = "sony-wifi";
+		break;
+	case SONY_BLUETOOTH:
+		type = RFKILL_TYPE_BLUETOOTH;
+		name = "sony-bluetooth";
+		break;
+	case SONY_WWAN:
+		type = RFKILL_TYPE_WWAN;
+		name = "sony-wwan";
+		break;
+	case SONY_WIMAX:
+		type = RFKILL_TYPE_WIMAX;
+		name = "sony-wimax";
+		break;
+	default:
+		return -EINVAL;
 	}
 
-	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
-					 &handle))) {
-		dprintk("Doing SNC setup\n");
-		sony_nc_function_setup(device);
+	rfk = rfkill_alloc(name, &device->dev, type,
+			   &sony_rfkill_ops, (void *)nc_type);
+	if (!rfk)
+		return -ENOMEM;
+
+	sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
+	hwblock = !(result & 0x1);
+	wwblock = !(result & 0x2);
+
+	result = 0;
+	sony_call_snc_handle(sony_rfkill_handle, sony_rfkill_address[nc_type],
+				&result);
+	swblock = !(result & 0x2);
+
+	/* hard block the WWAN module if no battery is present */
+	if ((nc_type == SONY_WWAN) && wwblock)
+		swblock = true;
+
+	rfkill_init_sw_state(rfk, swblock);
+	rfkill_set_hw_state(rfk, hwblock);
+
+	err = rfkill_register(rfk);
+	if (err) {
+		rfkill_destroy(rfk);
+		return err;
+	}
+	sony_rfkill_devices[nc_type] = rfk;
+	return err;
+}
+
+static void sony_nc_rfkill_update(void)
+{
+	enum sony_nc_rfkill i;
+	unsigned int result;
+	bool hwblock, swblock, wwblock;
+
+	sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
+	hwblock = !(result & 0x1);
+	wwblock = !(result & 0x2);
+
+	for (i = 0; i < N_SONY_RFKILL; i++) {
+		int argument = sony_rfkill_address[i];
+
+		if (!sony_rfkill_devices[i])
+			continue;
+
+		sony_call_snc_handle(sony_rfkill_handle, argument, &result);
+		/* block wwan when no battery is present */
+		if ((i == SONY_WWAN) && wwblock)
+			swblock = true;
+		else
+			swblock = !(result & 0x2);
+
+		rfkill_set_states(sony_rfkill_devices[i],
+				  swblock, hwblock);
+	}
+}
+
+static int sony_nc_rfkill_setup(struct acpi_device *device)
+{
+#define	RFKILL_BUFF_SIZE 8
+	u8 dev_code, i, buff[RFKILL_BUFF_SIZE] = { 0 };
+
+	dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
+
+	/* need to read the whole buffer returned by the acpi call to SN06
+	 * here otherwise we may miss some features
+	 */
+	if (sony_call_snc_handle_buffer(sony_rfkill_handle, 0x000,
+					buff, RFKILL_BUFF_SIZE) < 0)
+		return -EIO;
+
+	/*
+	 * the buffer is filled with magic numbers describing the devices
+	 * available, 0xff terminates the enumeration
+	 */
+	for (i = 0; i < RFKILL_BUFF_SIZE; i++) {
+
+		dev_code = buff[i];
+		if (dev_code == 0xff)
+			break;
+
+		/*
+		   known codes:
+
+		   0x00	WLAN
+		   0x10 BLUETOOTH
+		   0x20 WWAN GPRS-EDGE
+		   0x21 WWAN HSDPA
+		   0x22 WWAN EV-DO
+		   0x23 WWAN GPS
+		   0x25	Gobi WWAN no GPS
+		   0x26 Gobi WWAN + GPS
+		   0x28	Gobi WWAN no GPS
+		   0x29 Gobi WWAN + GPS
+		   0x50	Gobi WWAN no GPS
+		   0x51 Gobi WWAN + GPS
+		   0x30	WIMAX
+		   0x70 no SIM card slot
+		   0x71 SIM card slot
+		*/
+		dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
+
+		if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
+			sony_nc_setup_rfkill(device, SONY_WIFI);
+
+		if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
+			sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
+
+		if (((0xf0 & dev_code) == 0x20 || (0xf0 & dev_code) == 0x50) &&
+				!sony_rfkill_devices[SONY_WWAN])
+			sony_nc_setup_rfkill(device, SONY_WWAN);
+
+		if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
+			sony_nc_setup_rfkill(device, SONY_WIMAX);
+	}
+
+	return 0;
+}
+
+/*
+	ALS device part
+*/
+/* generic ALS data and interface */
+#define ALS_ATTRS_NUM	7
+#define ALS_TABLE_SIZE	25
+
+struct als_device_ops {
+	int (*init)(const u8 defaults[]);
+	int (*exit)(void);
+	int (*event_handler)(void);
+	int (*set_power)(unsigned int);
+	int (*get_power)(unsigned int *);
+	int (*get_lux)(unsigned int *, unsigned int *);
+	int (*get_kelvin)(unsigned int *);
+};
+
+struct als_device {
+	unsigned int power;
+	unsigned int managed;
+
+	unsigned int levels_num;
+	u8 *levels;
+	unsigned int defaults_num;
+	u8 *defaults;
+	u8 parameters[ALS_TABLE_SIZE];
+
+	/* common device operations */
+	const struct als_device_ops *ops;
+
+	/* basic ALS sys interface */
+	struct device_attribute attrs[ALS_ATTRS_NUM];
+};
+
+static struct als_device *als_handle;
+static int sony_als_handle = -1;
+
+/*
+	model specific ALS data and controls
+	TAOS TSL256x device data
+*/
+#define LUX_SHIFT_BITS		16	/* for non-floating point math */
+/* scale 100000 multiplied fractional coefficients rounding the values */
+#define SCALE(u)	((((((u64) u) << LUX_SHIFT_BITS) / 10000) + 5) / 10)
+
+#define TSL256X_REG_CTRL	0x00
+#define TSL256X_REG_TIMING	0x01
+#define TSL256X_REG_TLOW	0x02
+#define TSL256X_REG_THIGH	0x04
+#define TSL256X_REG_INT		0x06
+#define TSL256X_REG_ID		0x0a
+#define TSL256X_REG_DATA0	0x0c
+#define TSL256X_REG_DATA1	0x0e
+
+#define TSL256X_POWER_ON	0x03
+#define TSL256X_POWER_OFF	0x00
+
+#define TSL256X_POWER_MASK	0x03
+#define TSL256X_INT_MASK	0x10
+
+#define TSL256X_PERCENTAGE	15
+
+struct tsl256x_coeff {
+	u32 ratio;
+	u32 ch0;
+	u32 ch1;
+	u32 ka;
+	s32 kb;
+};
+
+struct tsl256x_data {
+	unsigned int gaintime;
+	unsigned int periods;
+	struct tsl256x_coeff const *coeff_table;
+};
+static struct tsl256x_data *tsl256x_handle;
+
+static const struct tsl256x_coeff tsl256x_coeff_fn[] = {
+	{
+		.ratio	= SCALE(12500),	/* 0.125 * 2^LUX_SHIFT_BITS  */
+		.ch0	= SCALE(3040),	/* 0.0304 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(2720),	/* 0.0272 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(313550000),
+		.kb	= -10651,
+	}, {
+		.ratio	= SCALE(25000),	/* 0.250 * 2^LUX_SHIFT_BITS  */
+		.ch0	= SCALE(3250),	/* 0.0325 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(4400),	/* 0.0440 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(203390000),
+		.kb	= -2341,
+	}, {
+		.ratio	= SCALE(37500),	/* 0.375 * 2^LUX_SHIFT_BITS  */
+		.ch0	= SCALE(3510),	/* 0.0351 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(5440),	/* 0.0544 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(152180000),
+		.kb	= 157,
+	}, {
+		.ratio	= SCALE(50000),	/* 0.50 * 2^LUX_SHIFT_BITS   */
+		.ch0	= SCALE(3810),	/* 0.0381 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(6240),	/* 0.0624 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(163580000),
+		.kb	= -145,
+	}, {
+		.ratio	= SCALE(61000),	/* 0.61 * 2^LUX_SHIFT_BITS   */
+		.ch0	= SCALE(2240),	/* 0.0224 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(3100),	/* 0.0310 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(180800000),
+		.kb	= -495,
+	}, {
+		.ratio	= SCALE(80000),	/* 0.80 * 2^LUX_SHIFT_BITS   */
+		.ch0	= SCALE(1280),	/* 0.0128 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(1530),	/* 0.0153 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(197340000),
+		.kb	= -765
+	}, {
+		.ratio	= SCALE(130000),/* 1.3 * 2^LUX_SHIFT_BITS     */
+		.ch0	= SCALE(146),	/* 0.00146 * 2^LUX_SHIFT_BITS */
+		.ch1	= SCALE(112),	/* 0.00112 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(182900000),
+		.kb	= -608,
+	}, {
+		.ratio	= UINT_MAX,	/* for higher ratios */
+		.ch0	= 0,
+		.ch1	= 0,
+		.ka	= 0,
+		.kb	= 830,
+	}
+};
+
+static const struct tsl256x_coeff tsl256x_coeff_cs[] = {
+	{
+		.ratio  = SCALE(13000),	/* 0.130 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(3150),	/* 0.0315 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(2620),	/* 0.0262 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(300370000),
+		.kb	= -9587,
+	}, {
+		.ratio  = SCALE(26000),	/* 0.260 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(3370),	/* 0.0337 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(4300),	/* 0.0430 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(194270000),
+		.kb	= -1824,
+	}, {
+		.ratio  = SCALE(39000),	/* 0.390 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(3630),	/* 0.0363 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(5290),	/* 0.0529 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(152520000),
+		.kb	= 145,
+	}, {
+		.ratio  = SCALE(52000),	/* 0.520 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(3920),	/* 0.0392 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(6050),	/* 0.0605 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(165960000),
+		.kb	= -200,
+	}, {
+		.ratio  = SCALE(65000),	/* 0.650 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(2290),	/* 0.0229 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(2910),	/* 0.0291 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(184800000),
+		.kb	= -566,
+	}, {
+		.ratio  = SCALE(80000),	/* 0.800 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(1570),	/* 0.0157 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(1800),	/* 0.0180 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(199220000),
+		.kb	= -791,
+	}, {
+		.ratio  = SCALE(130000),/* 0.130 * 2^LUX_SHIFT_BITS  */
+		.ch0    = SCALE(338),	/* 0.00338 * 2^LUX_SHIFT_BITS */
+		.ch1    = SCALE(260),	/* 0.00260 * 2^LUX_SHIFT_BITS */
+		.ka	= SCALE(182900000),
+		.kb	= -608,
+	}, {
+		.ratio  = UINT_MAX,	/* for higher ratios */
+		.ch0    = 0,
+		.ch1    = 0,
+		.ka	= 0,
+		.kb	= 830,
+	}
+};
+
+/*
+	TAOS helper & control functions
+*/
+static inline int tsl256x_exec_writebyte(unsigned int reg,
+						unsigned int const *value)
+{
+	unsigned int result;
+
+	return (sony_call_snc_handle(sony_als_handle, (*value << 0x18) |
+		(reg << 0x10) | 0x800500, &result) || !(result & 0x01))
+		? -EIO : 0;
+}
+
+static inline int tsl256x_exec_writeword(unsigned int reg,
+						unsigned int const *value)
+{
+	u8 result[1];
+	u64 arg = *value;
+
+	/* using sony_call_snc_handle_buffer due to possible input overflows */
+	return ((sony_call_snc_handle_buffer(sony_als_handle, (arg << 0x18) |
+				(reg << 0x10) | 0xA00700, result, 1) < 0) ||
+				!(result[0] & 0x01)) ? -EIO : 0;
+}
+
+static inline int tsl256x_exec_readbyte(unsigned int reg, unsigned int *result)
+{
+	if (sony_call_snc_handle(sony_als_handle, (reg << 0x10)
+		| 0x800400, result) || !(*result & 0x01))
+		return -EIO;
+	*result = (*result >> 0x08) & 0xFF;
+
+	return 0;
+}
+
+static inline int tsl256x_exec_readword(unsigned int reg, unsigned int *result)
+{
+	if (sony_call_snc_handle(sony_als_handle, (reg << 0x10)
+		| 0xA00600, result) || !(*result & 0x01))
+		return -EIO;
+	*result = (*result >> 0x08) & 0xFFFF;
+
+	return 0;
+}
+
+static int tsl256x_interrupt_ctrls(unsigned int *interrupt,
+					unsigned int *periods)
+{
+	unsigned int value, result;
+
+	/* if no interrupt parameter, retrieve interrupt status */
+	if (!interrupt) {
+		if (tsl256x_exec_readbyte(TSL256X_REG_INT, &result))
+			return -EIO;
+
+		value = (result & TSL256X_INT_MASK);
+	} else {
+		value = *interrupt << 0x04;
+	}
+
+	/* if no periods provided use the last one set */
+	value |= (periods ? *periods : tsl256x_handle->periods);
+
+	if (tsl256x_exec_writebyte(TSL256X_REG_INT, &value))
+		return -EIO;
+
+	if (periods)
+		tsl256x_handle->periods = *periods;
+
+	return 0;
+}
+
+static int tsl256x_setup(void)
+{
+	unsigned int interr = 1, zero = 0;
+
+	/*
+	 *   reset the threshold settings to trigger an event as soon
+	 *   as the events go on, forcing a backlight adaptation to
+	 *   the current lighting conditions
+	 */
+	tsl256x_exec_writeword(TSL256X_REG_TLOW, &zero);
+	tsl256x_exec_writeword(TSL256X_REG_THIGH, &zero);
+
+	/* set gain and time */
+	if (tsl256x_exec_writebyte(TSL256X_REG_TIMING,
+				&tsl256x_handle->gaintime))
+		return -EIO;
+
+	/* restore persistence value and enable the interrupt generation */
+	if (tsl256x_interrupt_ctrls(&interr, &tsl256x_handle->periods))
+		return -EIO;
+
+	return 0;
+}
+
+static int tsl256x_set_power(unsigned int status)
+{
+	int ret;
+
+	if (status) {
+		ret = tsl256x_setup();
+		if (ret)
+			return ret;
+	}
+
+	status = status ? TSL256X_POWER_ON : TSL256X_POWER_OFF;
+	ret = tsl256x_exec_writebyte(TSL256X_REG_CTRL, &status);
+
+	return ret;
+}
+
+static int tsl256x_get_power(unsigned int *status)
+{
+	if (tsl256x_exec_readbyte(TSL256X_REG_CTRL, status))
+		return -EIO;
+
+	*status = ((*status & TSL256X_POWER_MASK) == TSL256X_POWER_ON) ? 1 : 0;
+
+	return 0;
+}
+
+static int tsl256x_get_raw_data(unsigned int *ch0, unsigned int *ch1)
+{
+	if (!ch0)
+		return -1;
+
+	if (tsl256x_exec_readword(TSL256X_REG_DATA0, ch0))
+		return -EIO;
+
+	if (ch1) {
+		if (tsl256x_exec_readword(TSL256X_REG_DATA1, ch1))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int tsl256x_set_thresholds(const unsigned int *ch0)
+{
+	unsigned int tlow, thigh;
+
+	tlow = (*ch0 * (100 - TSL256X_PERCENTAGE)) / 100;
+	thigh = ((*ch0 * (100 + TSL256X_PERCENTAGE)) / 100) + 1;
+
+	if (thigh > 0xffff)
+		thigh = 0xffff;
+
+	if (tsl256x_exec_writeword(TSL256X_REG_TLOW, &tlow) ||
+		tsl256x_exec_writeword(TSL256X_REG_THIGH, &thigh))
+		return -EIO;
+
+	dprintk("tsl256x_set_thresholds: ch0: %d, tlow: %d, thigh: %d\n",
+			*ch0, tlow, thigh);
+
+	return 0;
+}
+
+static void tsl256x_calculate_lux(const u32 ch0, const u32 ch1,
+		unsigned int *integ, unsigned int *fract)
+{
+	/* the raw output from the sensor is just a "count" value, as
+	   it is the result of the integration of the analog sensor
+	   signal, the counts-to-lux curve (and its approximation can
+	   be found on the datasheet.
+	*/
+	const struct tsl256x_coeff *coeff = tsl256x_handle->coeff_table;
+	u32 ratio, temp, integer, fractional;
+
+	/* STEP 1: ratio calculation, for ch0 & ch1 coeff selection */
+
+	/* protect against division by 0 */
+	ratio = ch0 ? ((ch1 << (LUX_SHIFT_BITS + 1)) / ch0) : UINT_MAX;
+	/* round the ratio value */
+	ratio = (ratio + 1) >> 1;
+
+	/* coeff selection rule */
+	while (coeff->ratio < ratio)
+		coeff++;
+
+	/* STEP 2: lux calculation formula using the right coeffcients */
+	temp = (ch0 * coeff->ch0) - (ch1 * coeff->ch1);
+
+	/* STEP 3: separate integer and fractional part */
+
+	/* remove the integer part and multiply for the 10^N, N decimals  */
+	fractional = (temp % (1 << LUX_SHIFT_BITS)) * 100; /* two decimals */
+	/* scale down the value */
+	fractional >>= LUX_SHIFT_BITS;
+
+	/* strip off fractional portion to obtain the integer part */
+	integer = temp >> LUX_SHIFT_BITS;
+
+	*integ = integer;
+	*fract = fractional;
+
+	dprintk("tsl256x_calculate_lux: ratio: %u, temp: %u\n", ratio, temp);
+}
+
+static void tsl256x_calculate_kelvin(const u32 *ch0, const u32 *ch1,
+		unsigned int *temperature)
+{
+	const struct tsl256x_coeff *coeff = tsl256x_handle->coeff_table;
+	u32 ratio;
+
+	/* protect against division by 0 */
+	ratio = *ch0 ? ((*ch1 << (LUX_SHIFT_BITS + 1)) / *ch0) : UINT_MAX;
+	/* round the ratio value */
+	ratio = (ratio + 1) >> 1;
+
+	/* coeff selection rule */
+	while (coeff->ratio < ratio)
+		coeff++;
+
+	*temperature = ratio ? coeff->ka / ratio + coeff->kb : 0;
+}
+
+static int tsl256x_get_lux(unsigned int *integ, unsigned int *fract)
+{
+	int ret = 0;
+	unsigned int ch0, ch1;
+
+	if (!integ || !fract)
+		return -1;
+
+	ret = tsl256x_get_raw_data(&ch0, &ch1);
+	if (!ret)
+		tsl256x_calculate_lux(ch0, ch1, integ, fract);
+
+	return ret;
+}
+
+static int tsl256x_get_kelvin(unsigned int *temperature)
+{
+	int ret = -1;
+	unsigned int ch0, ch1;
+
+	if (!temperature)
+		return ret;
+
+	ret = tsl256x_get_raw_data(&ch0, &ch1);
+	if (!ret)
+		tsl256x_calculate_kelvin(&ch0, &ch1, temperature);
+
+	return ret;
+}
+
+static int tsl256x_get_id(char *model, unsigned int *id, bool *cs)
+{
+	int ret;
+	unsigned int result;
+	char *name = NULL;
+	bool unknown = false;
+	bool type_cs = false;
+
+	ret = tsl256x_exec_readbyte(TSL256X_REG_ID, &result);
+	if (ret)
+		return ret;
+
+	switch ((result >> 0x04) & 0x0F) {
+	case 11:
+		name = "TAOS TSL2569";
+		break;
+	case 5:
+		name = "TAOS TSL2561";
+		break;
+	case 3:
+		name = "TAOS TSL2563";
+		break;
+	case 0:
+		type_cs = true;
+		name = "TAOS TSL2560CS";
+		break;
+	default:
+		unknown = true;
+		break;
+	}
+
+	if (id)
+		*id = result;
+	if (cs)
+		*cs = type_cs;
+	if (model && name)
+		strcpy(model, name);
+
+	return unknown;
+}
+
+static int tsl256x_event_handler(void)
+{
+	unsigned int ch0, interr = 1;
+
+	/* wait for the EC to clear the interrupt */
+/*      schedule_timeout_interruptible(msecs_to_jiffies(100));	*/
+	/* ...or force the interrupt clear immediately */
+	sony_call_snc_handle(sony_als_handle, 0x04C60500, &interr);
+
+	/* read the raw data */
+	tsl256x_get_raw_data(&ch0, NULL);
+
+	/* set the thresholds */
+	tsl256x_set_thresholds(&ch0);
+
+	/* enable interrupt */
+	tsl256x_interrupt_ctrls(&interr, NULL);
+
+	return 0;
+}
+
+static int tsl256x_init(const u8 defaults[])
+{
+	unsigned int id;
+	int ret = 0;
+	bool cs; /* if CS package choose CS coefficients */
+	char model[64];
+
+	/* detect the device */
+	ret = tsl256x_get_id(model, &id, &cs);
+	if (ret < 0)
+		return ret;
+	if (ret) {
+		dprintk("unsupported ALS found (unknown model "
+			"number %u rev. %u\n", id >> 4, id & 0x0F);
+		return ret;
+	} else {
+		dprintk("found ALS model number %u rev. %u (%s)\n",
+				id >> 4, id & 0x0F, model);
+	}
+
+	tsl256x_handle = kzalloc(sizeof(struct tsl256x_data), GFP_KERNEL);
+	if (!tsl256x_handle)
+		return -ENOMEM;
+
+	/* populate the device data */
+	tsl256x_handle->gaintime = 0x12;
+	tsl256x_handle->periods = defaults[9];
+	tsl256x_handle->coeff_table = cs ? tsl256x_coeff_cs : tsl256x_coeff_fn;
+
+	ret = tsl256x_setup();
+
+	return ret;
+}
+
+static int tsl256x_exit(void)
+{
+	int interr = 0, periods = 4;
+
+	/* disable the interrupt generation, restore defaults */
+	tsl256x_interrupt_ctrls(&interr, &periods);
+
+	tsl256x_handle->coeff_table = NULL;
+	kfree(tsl256x_handle);
+
+	return 0;
+}
+
+/* TAOS TSL256x specific ops */
+static const struct als_device_ops tsl256x_ops = {
+	.init = tsl256x_init,
+	.exit = tsl256x_exit,
+	.event_handler = tsl256x_event_handler,
+	.set_power = tsl256x_set_power,
+	.get_power = tsl256x_get_power,
+	.get_lux = tsl256x_get_lux,
+	.get_kelvin = tsl256x_get_kelvin,
+};
+
+/* unknown ALS sensors controlled by the EC present on newer Vaios */
+static inline int ngals_get_raw_data(unsigned int *data)
+{
+	if (sony_call_snc_handle(sony_als_handle, 0x1000, data))
+		return -EIO;
+
+	return 0;
+}
+
+static int ngals_get_power(unsigned int *status)
+{
+	int ret;
+	unsigned int data;
+
+	ret = ngals_get_raw_data(&data);
+	if (ret)
+		return ret;
+
+	*status = (data >> 0x10) & 0xff;
+
+	return 0;
+}
+
+static int ngals_get_lux(unsigned int *integ, unsigned int *fract)
+{
+	int ret;
+	unsigned int data;
+
+	ret = ngals_get_raw_data(&data);
+	if (ret)
+		return ret;
+
+	*integ = 0xff & data;
+	*fract = 0;
+
+	return 0;
+}
+
+static const struct als_device_ops ngals_ops = {
+	.init = NULL,
+	.exit = NULL,
+	.event_handler = NULL,
+	.set_power = NULL,
+	.get_power = ngals_get_power,
+	.get_lux = ngals_get_lux,
+	.get_kelvin = NULL,
+};
+
+/*
+	ALS common data and functions
+*/
+static int sony_nc_als_event_handler(void)
+{
+	/* call the device handler */
+	if (als_handle->ops->event_handler)
+		als_handle->ops->event_handler();
+
+	return 0;
+}
+
+static int sony_nc_als_power_set(unsigned int status)
+{
+	if (!als_handle->ops->set_power)
+		return -EPERM;
+
+	if (als_handle->ops->set_power(status))
+		return -EIO;
+
+	als_handle->power = status;
+
+	return 0;
+}
+
+static int sony_nc_als_managed_set(unsigned int status)
+{
+	int ret = 0;
+	unsigned int result, cmd;
+	static bool was_on;
+
+	/*  turn on/off the event notification
+	 *  (and enable als_backlight writes)
+	 */
+	cmd = sony_als_handle == 0x0143 ? 0x2200 : 0x0900;
+	if (sony_call_snc_handle(sony_als_handle,
+		(status << 0x10) | cmd, &result))
+		return -EIO;
+
+	als_handle->managed = status;
+
+	/* turn on the ALS; this will also enable the interrupt generation */
+	if (status) /* store the power state else check the previous state */
+		was_on = als_handle->power;
+	else if (was_on)
+		return 0;
+
+	ret = sony_nc_als_power_set(status);
+	if (ret == -EPERM) /* new models do not allow power control */
+		ret = 0;
+
+	return ret;
+}
+
+static unsigned int level;
+static int sony_nc_als_get_brightness(struct backlight_device *bd)
+{
+	if (bd->props.brightness != level)
+		dprintk("bd->props.brightness != level\n");
+
+	return level;
+}
+
+static int sony_nc_als_update_status(struct backlight_device *bd)
+{
+	unsigned int value, result;
+
+	if (als_handle->managed) {
+		if (bd->props.brightness != level) {
+			dprintk("generating ALS event 3 (reason: 2)\n");
+			acpi_bus_generate_proc_event(sony_nc_acpi_device,
+					3, 2);
+			acpi_bus_generate_netlink_event(
+					sony_nc_acpi_device->pnp.device_class,
+					dev_name(&sony_nc_acpi_device->dev),
+					3, 2);
+		}
+	} else {
+		unsigned int cmd;
+
+		value = als_handle->levels[bd->props.brightness];
+		cmd = sony_als_handle == 0x0143 ? 0x3000 : 0x0100;
+		if (sony_call_snc_handle(sony_als_handle,
+					(value << 0x10) | cmd, &result))
+			return -EIO;
+	}
+
+	level = bd->props.brightness;
+
+	return level;
+}
+
+/*
+	ALS sys interface
+*/
+static ssize_t sony_nc_als_power_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	int status;
+
+	if (!als_handle->ops->get_power)
+		return -EPERM;
+
+	if (als_handle->ops->get_power(&status))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", status);
+
+	return count;
+}
+
+static ssize_t sony_nc_als_power_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	int ret;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	/* no action if already set */
+	if (value == als_handle->power)
+		return count;
+
+	ret = sony_nc_als_power_set(value);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sony_nc_als_managed_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int status, cmd;
+
+	cmd = sony_als_handle == 0x0143 ? 0x2100 : 0x0A00;
+	if (sony_call_snc_handle(sony_als_handle, cmd, &status))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", status & 0x01);
+
+	return count;
+}
+
+static ssize_t sony_nc_als_managed_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	if (als_handle->managed != value) {
+		int ret = sony_nc_als_managed_set(value);
+		if (ret)
+			return ret;
+	}
+
+	return count;
+}
+
+static ssize_t sony_nc_als_lux_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int integ = 0, fract = 0;
+
+	if (als_handle->power)
+		/* als_handle->ops->get_lux is mandatory, no check */
+		als_handle->ops->get_lux(&integ, &fract);
+
+	count = snprintf(buffer, PAGE_SIZE, "%d.%.2d\n", integ, fract);
+
+	return count;
+}
+
+static ssize_t sony_nc_als_parameters_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int i, num;
+	u8 *list;
+
+	if (!strcmp(attr->attr.name, "als_defaults")) {
+		list = als_handle->defaults;
+		num = als_handle->defaults_num;
+	} else { /* als_backlight_levels */
+		list = als_handle->levels;
+		num = als_handle->levels_num;
+	}
+
+	for (i = 0; i < num; i++)
+		count += snprintf(buffer + count, PAGE_SIZE - count,
+				"0x%.2x ", list[i]);
+
+	count += snprintf(buffer + count, PAGE_SIZE - count, "\n");
+
+	return count;
+}
+
+static ssize_t sony_nc_als_backlight_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result, cmd;
+
+	cmd = sony_als_handle == 0x0143 ? 0x3100 : 0x0200;
+	if (sony_call_snc_handle(sony_als_handle, cmd, &result))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0xff);
+
+	return count;
+}
+
+static ssize_t sony_nc_als_backlight_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+	unsigned int result, cmd, max = als_handle->levels_num - 1;
+
+	if (count > 31)
+		return -EINVAL;
+
+	if (strict_strtoul(buffer, 10, &value))
+		return -EINVAL;
+
+	if (!als_handle->managed)
+		return -EPERM;
+
+	/* verify that the provided value falls inside the model
+	   specific backlight range */
+	if ((value < als_handle->levels[0])
+			|| (value > als_handle->levels[max]))
+		return -EINVAL;
+
+	cmd = sony_als_handle == 0x0143 ? 0x3000 : 0x0100;
+	if (sony_call_snc_handle(sony_als_handle, (value << 0x10) | cmd,
+				&result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_als_kelvin_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int kelvin = 0;
+
+	if (als_handle->ops->get_kelvin && als_handle->power)
+		als_handle->ops->get_kelvin(&kelvin);
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", kelvin);
+
+	return count;
+}
+
+
+/*
+	ALS attach/detach functions
+*/
+static int sony_nc_als_setup(struct platform_device *pd)
+{
+	int i = 0;
+
+	/* check the device presence */
+	if (sony_als_handle == 0x0137) {
+		unsigned int result;
+
+		if (sony_call_snc_handle(sony_als_handle, 0xB00, &result))
+			return -EIO;
+
+		if (!(result & 0x01)) {
+			pr_info("no ALS present\n");
+			return 0;
+		}
+	}
+
+	als_handle = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als_handle)
+		return -ENOMEM;
+
+	/* set model specific data */
+	/* if handle 0x012f or 0x0137 use tsl256x_ops, else new als controls */
+	if (sony_als_handle == 0x0143) {
+		als_handle->ops = &ngals_ops;
+		als_handle->levels_num = 16;
+		als_handle->defaults_num = 9;
+	} else {
+		als_handle->ops = &tsl256x_ops;
+		als_handle->levels_num = 9;
+		als_handle->defaults_num = 13;
+	}
+	/* backlight levels are the first levels_num values, the remaining
+	   defaults_num values are default settings for als regulation
+	*/
+	als_handle->levels = als_handle->parameters;
+	als_handle->defaults = als_handle->parameters + als_handle->levels_num;
+
+	/* get power state */
+	if (als_handle->ops->get_power) {
+		if (als_handle->ops->get_power(&als_handle->power))
+			pr_warn("unable to retrieve the power status\n");
+	}
+
+	/* set managed to 0, userspace daemon should enable it */
+	sony_nc_als_managed_set(0);
+
+	/* get ALS parameters */
+	if (sony_call_snc_handle_buffer(sony_als_handle, 0x0000,
+		als_handle->parameters, ALS_TABLE_SIZE) < 0)
+		goto nosensor;
+
+	/* initial device configuration */
+	if (als_handle->ops->init)
+		if (als_handle->ops->init(als_handle->defaults)) {
+			pr_warn("ALS setup failed\n");
+			goto nosensor;
+		}
+
+	/* set up the sys interface */
+
+	/* als power control */
+	sysfs_attr_init(&als_handle->attrs[0].attr);
+	als_handle->attrs[0].attr.name = "als_power";
+	als_handle->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	als_handle->attrs[0].show = sony_nc_als_power_show;
+	als_handle->attrs[0].store = sony_nc_als_power_store;
+	/* notifications and backlight enable control file */
+	sysfs_attr_init(&als_handle->attrs[1].attr);
+	als_handle->attrs[1].attr.name = "als_managed";
+	als_handle->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
+	als_handle->attrs[1].show = sony_nc_als_managed_show;
+	als_handle->attrs[1].store = sony_nc_als_managed_store;
+	/* lux equivalent value */
+	sysfs_attr_init(&als_handle->attrs[2].attr);
+	als_handle->attrs[2].attr.name = "als_lux";
+	als_handle->attrs[2].attr.mode = S_IRUGO;
+	als_handle->attrs[2].show = sony_nc_als_lux_show;
+	/* ALS default parameters */
+	sysfs_attr_init(&als_handle->attrs[3].attr);
+	als_handle->attrs[3].attr.name = "als_defaults";
+	als_handle->attrs[3].attr.mode = S_IRUGO;
+	als_handle->attrs[3].show = sony_nc_als_parameters_show;
+	/* ALS default backlight levels */
+	sysfs_attr_init(&als_handle->attrs[4].attr);
+	als_handle->attrs[4].attr.name = "als_backlight_levels";
+	als_handle->attrs[4].attr.mode = S_IRUGO;
+	als_handle->attrs[4].show = sony_nc_als_parameters_show;
+	/* als backlight control */
+	sysfs_attr_init(&als_handle->attrs[5].attr);
+	als_handle->attrs[5].attr.name = "als_backlight";
+	als_handle->attrs[5].attr.mode = S_IRUGO | S_IWUSR;
+	als_handle->attrs[5].show = sony_nc_als_backlight_show;
+	als_handle->attrs[5].store = sony_nc_als_backlight_store;
+
+/*	if (als_handle->ops->get_kelvin) {	*/
+	/* light temperature */
+	sysfs_attr_init(&als_handle->attrs[6].attr);
+	als_handle->attrs[6].attr.name = "als_kelvin";
+	als_handle->attrs[6].attr.mode = S_IRUGO;
+	als_handle->attrs[6].show = sony_nc_als_kelvin_show;
+
+	/* everything or nothing, otherwise unable to control the ALS */
+	for (; i < ALS_ATTRS_NUM; i++) {
+		if (device_create_file(&pd->dev, &als_handle->attrs[i]))
+			goto attrserror;
+	}
+
+	return 0;
+
+attrserror:
+	for (; i > 0; i--)
+		device_remove_file(&pd->dev, &als_handle->attrs[i]);
+nosensor:
+	kfree(als_handle);
+	als_handle = NULL;
+
+	return -1;
+}
+
+static void sony_nc_als_resume(void)
+{
+	if (als_handle->managed) /* it restores the power state too */
+		sony_nc_als_managed_set(1);
+	else if (als_handle->power)
+		sony_nc_als_power_set(1);
+}
+
+static int sony_nc_als_cleanup(struct platform_device *pd)
+{
+	if (als_handle) {
+		int i;
+
+		for (i = 0; i < ALS_ATTRS_NUM; i++)
+			device_remove_file(&pd->dev, &als_handle->attrs[i]);
+
+		/* disable the events notification */
+		if (als_handle->managed)
+			if (sony_nc_als_managed_set(0))
+				pr_info("ALS notifications disable failed\n");
+
+		if (als_handle->power)
+			if (sony_nc_als_power_set(0))
+				pr_info("ALS power off failed\n");
+
+		if (als_handle->ops->exit)
+			if (als_handle->ops->exit())
+				pr_info("ALS device cleaning failed\n");
+
+		kfree(als_handle);
+		als_handle = NULL;
+	}
+
+	return 0;
+}
+/*	end ALS code	*/
+
+/*
+	HDD Shock Protection
+*/
+enum axis {
+	X_AXIS = 4,	/* frontal  */
+	Y_AXIS,		/* lateral  */
+	Z_AXIS		/* vertical */
+};
+
+#define FFS_ATTRS_NUM 6
+struct device_attribute *gsensor_attrs;
+static int sony_gs_handle = -1;
+
+static int sony_nc_gsensor_status_set(int value)
+{
+	unsigned int result, tmp;
+	bool capable;
+
+	/* retrieve the current state/settings */
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EIO;
+
+	/* the EC uses pin #11 of the SATA power connector to command the
+	   immediate idle feature; however some drives do not implement it
+	   and pin #11 is NC. Let's verify, otherwise no automatic
+	   protection is possible by the hardware
+	*/
+	capable = result & 0x20;
+	if (!capable)
+		pr_warn("hardware protection not available, the HDD"
+			       " do not support this feature\n");
+
+	/* do not return even though there is no HW capability,
+	   userspace can thus receive the shock notifications and
+	   call the ATA7 immediate idle command to unload the heads
+	*/
+
+	/* if the requested notification setting is different
+	   from the current one
+	*/
+	if (!!(result & 0x80) != value) {
+		int arg = !value & 0x01;
+
+		if (sony_call_snc_handle(sony_gs_handle,
+			arg << 0x08, &tmp))
+			return -EIO;
+	}
+
+	/* if the requested protection setting is different
+	   from the current one
+	*/
+	if (capable && (!!(result & 0x04) != value)) {
+		int arg = (result & 0x1B) | (value << 0x02);
+
+		if (sony_call_snc_handle(sony_gs_handle,
+			(arg << 0x10) | 0x0300, &tmp))
+			return -EIO;
+	}
+
+	return 0;
+}
+
+static int sony_nc_gsensor_axis_get(enum axis name)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_gs_handle, name << 0x08, &result))
+		return -EIO;
+
+	return result;
+}
+
+/*			G sensor sys interface			*/
+static ssize_t sony_nc_gsensor_type_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 0x03) & 0x03);
+
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_type_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	/*
+	 *  axis out type control file:
+	 *  0: raw values, 1: acc values 2: threshold values
+	 */
+	unsigned int result;
+	unsigned long value;
+
+	/* sanity checks and conversion */
+	if (count > 31 || strict_strtoul(buffer, 10, &value) || value > 2)
+		return -EINVAL;
+
+	value <<= 0x03;
+
+	/* retrieve the current state / settings */
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EIO;
+
+	if ((result & 0x18) != value) {
+		/* the last 3 bits need to be preserved */
+		value |= (result & 0x07);
+
+		if (sony_call_snc_handle(sony_gs_handle,
+				(value << 0x10) | 0x0300, &result))
+				return -EIO;
+	}
+
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_axis_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+	enum axis arg;
+
+	/* file being read for axis selection */
+	if (!strcmp(attr->attr.name, "gsensor_xval"))
+		arg = X_AXIS;
+	else if (!strcmp(attr->attr.name, "gsensor_yval"))
+		arg = Y_AXIS;
+	else if (!strcmp(attr->attr.name, "gsensor_zval"))
+		arg = Z_AXIS;
+	else
+		return count;
+
+	result = sony_nc_gsensor_axis_get(arg);
+	if (result < 0)
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
+
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_status_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", !!(result & 0x04));
+
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_status_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	int ret;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	ret = sony_nc_gsensor_status_set(value);
+	if (ret)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_sensitivity_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EINVAL;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x03);
+	return count;
+}
+
+static ssize_t sony_nc_gsensor_sensitivity_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 2)
+		return -EINVAL;
+
+	/* retrieve the other parameters to be stored as well */
+	if (sony_call_snc_handle(sony_gs_handle, 0x0200, &result))
+		return -EIO;
+	value |= (result & 0x1C); /* preserve only the needed bits */
+
+	if (sony_call_snc_handle(sony_gs_handle, (value << 0x10)
+		| 0x0300, &result))
+		return -EIO;
+
+	return count;
+}
+
+static int sony_nc_gsensor_setup(struct platform_device *pd)
+{
+	int i;
+
+	gsensor_attrs = kzalloc(sizeof(struct device_attribute) * FFS_ATTRS_NUM,
+			GFP_KERNEL);
+	if (!gsensor_attrs)
+		return -ENOMEM;
+
+	/* enable the HDD protection and notification by default */
+	if (sony_nc_gsensor_status_set(1))
+		pr_warn("failed to enable the HDD shock protection\n");
+
+	/* activation control	*/
+	sysfs_attr_init(&gsensor_attrs[0].attr);
+	gsensor_attrs[0].attr.name = "gsensor_protection";
+	gsensor_attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	gsensor_attrs[0].show = sony_nc_gsensor_status_show;
+	gsensor_attrs[0].store = sony_nc_gsensor_status_store;
+	/* sensitivity selection */
+	sysfs_attr_init(&gsensor_attrs[1].attr);
+	gsensor_attrs[1].attr.name = "gsensor_sensitivity";
+	gsensor_attrs[1].attr.mode = S_IRUGO | S_IWUSR;
+	gsensor_attrs[1].show = sony_nc_gsensor_sensitivity_show;
+	gsensor_attrs[1].store = sony_nc_gsensor_sensitivity_store;
+	/* x/y/z output selection */
+	sysfs_attr_init(&gsensor_attrs[2].attr);
+	gsensor_attrs[2].attr.name = "gsensor_val_type";
+	gsensor_attrs[2].attr.mode = S_IRUGO | S_IWUSR;
+	gsensor_attrs[2].show = sony_nc_gsensor_type_show;
+	gsensor_attrs[2].store = sony_nc_gsensor_type_store;
+
+	sysfs_attr_init(&gsensor_attrs[3].attr);
+	gsensor_attrs[3].attr.name = "gsensor_xval";
+	gsensor_attrs[3].attr.mode = S_IRUGO;
+	gsensor_attrs[3].show = sony_nc_gsensor_axis_show;
+
+	sysfs_attr_init(&gsensor_attrs[4].attr);
+	gsensor_attrs[4].attr.name = "gsensor_yval";
+	gsensor_attrs[4].attr.mode = S_IRUGO;
+	gsensor_attrs[4].show = sony_nc_gsensor_axis_show;
+
+	sysfs_attr_init(&gsensor_attrs[5].attr);
+	gsensor_attrs[5].attr.name = "gsensor_zval";
+	gsensor_attrs[5].attr.mode = S_IRUGO;
+	gsensor_attrs[5].show = sony_nc_gsensor_axis_show;
+
+	for (i = 0; i < FFS_ATTRS_NUM; i++) {
+		if (device_create_file(&pd->dev, &gsensor_attrs[i]))
+			goto attrserror;
+	}
+
+	return 0;
+
+attrserror:
+	for (; i > 0; i--)
+		device_remove_file(&pd->dev, &gsensor_attrs[i]);
+
+	kfree(gsensor_attrs);
+	gsensor_attrs = NULL;
+
+	return -1;
+}
+
+static int sony_nc_gsensor_cleanup(struct platform_device *pd)
+{
+	if (sony_gs_handle != -1) {
+		unsigned int i, result;
+
+		for (i = 0; i < FFS_ATTRS_NUM; i++)
+			device_remove_file(&pd->dev, &gsensor_attrs[i]);
+
+		/* disable the event generation, preserve any other setting */
+		sony_call_snc_handle(sony_gs_handle, 0x0100, &result);
+
+		kfree(gsensor_attrs);
+		gsensor_attrs = NULL;
+	}
+
+	return 0;
+}
+/*			end G sensor code			*/
+
+struct thermal_ctrl {
+	unsigned int mode;
+	unsigned int profiles;
+	struct device_attribute mode_attr;
+	struct device_attribute profiles_attr;
+};
+static struct thermal_ctrl *th_handle;
+
+static int sony_nc_thermal_mode_set(unsigned int profile)
+{
+	unsigned int cmd, result;
+
+	/* to avoid the 1 value hole when only 2 profiles are available */
+	switch (profile) {
+	case 1: /* performance */
+		cmd = 2;
+		break;
+	case 2: /* silent */
+		cmd = 1;
+		break;
+	default: /* balanced */
+		cmd = 0;
+		break;
+	}
+
+	if (sony_call_snc_handle(0x0122, cmd << 0x10 | 0x0200, &result))
+		return -EIO;
+
+	th_handle->mode = profile;
+
+	return 0;
+}
+
+static int sony_nc_thermal_mode_get(unsigned int *profile)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0122, 0x0100, &result))
+		return -EIO;
+
+	/* to avoid the 1 value hole when only 2 profiles are available */
+	switch (result & 0xff) {
+	case 2: /* performance */
+		*profile = 1;
+		break;
+	case 1: /* silent */
+		*profile = 2;
+		break;
+	default: /* balanced */
+		*profile = 0;
+		break;
+	}
+
+	return 0;
+}
+
+static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	return snprintf(buffer, PAGE_SIZE, "%u\n", th_handle->profiles);
+}
+
+static ssize_t sony_nc_thermal_mode_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) ||
+		value > (th_handle->profiles - 1))
+		return -EINVAL;
+
+	if (sony_nc_thermal_mode_set(value))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_thermal_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int profile;
+
+	if (sony_nc_thermal_mode_get(&profile))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", profile);
+
+	return count;
+}
+
+static int sony_nc_thermal_setup(struct platform_device *pd)
+{
+	th_handle = kzalloc(sizeof(struct thermal_ctrl), GFP_KERNEL);
+	if (!th_handle)
+		return -ENOMEM;
+
+	if (sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles)) {
+		pr_warn("unable to retrieve the available profiles\n");
+		goto outkzalloc;
+	}
+
+	if (sony_nc_thermal_mode_get(&th_handle->mode)) {
+		pr_warn("unable to retrieve the current profile");
+		goto outkzalloc;
+	}
+
+	sysfs_attr_init(&th_handle->profiles_attr.attr);
+	th_handle->profiles_attr.attr.name = "thermal_profiles";
+	th_handle->profiles_attr.attr.mode = S_IRUGO;
+	th_handle->profiles_attr.show = sony_nc_thermal_profiles_show;
+
+	sysfs_attr_init(&th_handle->mode_attr.attr);
+	th_handle->mode_attr.attr.name = "thermal_control";
+	th_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
+	th_handle->mode_attr.show = sony_nc_thermal_mode_show;
+	th_handle->mode_attr.store = sony_nc_thermal_mode_store;
+
+	if (device_create_file(&pd->dev, &th_handle->profiles_attr))
+		goto outkzalloc;
+
+	if (device_create_file(&pd->dev, &th_handle->mode_attr))
+		goto outprofiles;
+
+	return 0;
+
+outprofiles:
+	device_remove_file(&pd->dev, &th_handle->profiles_attr);
+outkzalloc:
+	kfree(th_handle);
+	th_handle = NULL;
+	return -1;
+}
+
+static int sony_nc_thermal_cleanup(struct platform_device *pd)
+{
+	if (th_handle) {
+		device_remove_file(&pd->dev, &th_handle->profiles_attr);
+		device_remove_file(&pd->dev, &th_handle->mode_attr);
+		kfree(th_handle);
+		th_handle = NULL;
+	}
+
+	return 0;
+}
+
+static void sony_nc_thermal_resume(void)
+{
+	unsigned int status;
+
+	sony_nc_thermal_mode_get(&status);
+
+	if (status != th_handle->mode)
+		sony_nc_thermal_mode_set(th_handle->mode);
+}
+
+static struct device_attribute *tpad_handle;
+static int sony_tpad_handle = -1;
+
+static ssize_t sony_nc_touchpad_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	/* sysfs: 0 disabled, 1 enabled; EC: 0 enabled, 1 disabled */
+	if (sony_call_snc_handle(sony_tpad_handle,
+				(!value << 0x10) | 0x100, &result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_touchpad_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(sony_tpad_handle, 0x000, &result))
+		return -EINVAL;
+
+	/* 1 tpad off, 0 tpad on */
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
+	return count;
+}
+
+static int sony_nc_touchpad_setup(struct platform_device *pd)
+{
+	tpad_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
+	if (!tpad_handle)
+		return -ENOMEM;
+
+	sysfs_attr_init(&tpad_handle->attr);
+	tpad_handle->attr.name = "touchpad";
+	tpad_handle->attr.mode = S_IRUGO | S_IWUSR;
+	tpad_handle->show = sony_nc_touchpad_show;
+	tpad_handle->store = sony_nc_touchpad_store;
+
+	if (device_create_file(&pd->dev, tpad_handle)) {
+		kfree(tpad_handle);
+		tpad_handle = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sony_nc_touchpad_cleanup(struct platform_device *pd)
+{
+	if (tpad_handle) {
+		device_remove_file(&pd->dev, tpad_handle);
+		kfree(tpad_handle);
+		tpad_handle = NULL;
+	}
+
+	return 0;
+}
+
+static struct device_attribute *hsc_handle;
+
+static ssize_t sony_nc_highspeed_charging_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(0x0131, value << 0x10 | 0x0200, &result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_highspeed_charging_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0131, 0x0100, &result))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
+
+	return count;
+}
+
+static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
+		pr_info("no High Speed Charging capability found\n");
+		return 0;
+	}
+
+	hsc_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
+	if (!hsc_handle)
+		return -ENOMEM;
+
+	sysfs_attr_init(&hsc_handle->attr);
+	hsc_handle->attr.name = "battery_highspeed_charging";
+	hsc_handle->attr.mode = S_IRUGO | S_IWUSR;
+	hsc_handle->show = sony_nc_highspeed_charging_show;
+	hsc_handle->store = sony_nc_highspeed_charging_store;
+
+	if (device_create_file(&pd->dev, hsc_handle)) {
+		kfree(hsc_handle);
+		hsc_handle = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
+{
+	if (hsc_handle) {
+		device_remove_file(&pd->dev, hsc_handle);
+		kfree(hsc_handle);
+		hsc_handle = NULL;
+	}
+
+	return 0;
+}
+
+static struct device_attribute *lid_handle;
+
+static ssize_t sony_nc_lid_resume_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 3)
+		return -EINVAL;
+
+	/* 00 <- disabled
+	   01 <- resume from S4
+	   10 <- resume from S3
+	   11 <- resume from S4 and S3
+	*/
+	/* we must set bit 1 and 2 (bit 0 is for S5), so shift one bit more */
+	if (sony_call_snc_handle(0x0119, value << 0x11 | 0x0100, &result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_lid_resume_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0119, 0x0000, &result))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", (result >> 1) & 0x03);
+
+	return count;
+}
+
+static int sony_nc_lid_resume_setup(struct platform_device *pd)
+{
+	lid_handle = kzalloc(sizeof(struct device_attribute), GFP_KERNEL);
+	if (!lid_handle)
+		return -ENOMEM;
+
+	sysfs_attr_init(&lid_handle->attr);
+	lid_handle->attr.name = "lid_resume_control";
+	lid_handle->attr.mode = S_IRUGO | S_IWUSR;
+	lid_handle->show = sony_nc_lid_resume_show;
+	lid_handle->store = sony_nc_lid_resume_store;
+
+	if (device_create_file(&pd->dev, lid_handle)) {
+		kfree(lid_handle);
+		lid_handle = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sony_nc_lid_resume_cleanup(struct platform_device *pd)
+{
+	if (lid_handle) {
+		device_remove_file(&pd->dev, lid_handle);
+		kfree(lid_handle);
+		lid_handle = NULL;
+	}
+
+	return 0;
+}
+
+
+static struct device_attribute *bcare_attrs;
+static int sony_bc_handle = -1;
+
+static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result, cmd;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value))
+		return -EINVAL;
+
+	/*  limit values (2 bits):
+	 *  00 - none
+	 *  01 - 80%
+	 *  10 - 50%
+	 *  11 - 100%
+	 *
+	 *  bit 0: 0 disable BCL, 1 enable BCL
+	 *  bit 1: 1 tell to store the battery limit (see bits 6,7) too
+	 *  bits 2,3: reserved
+	 *  bits 4,5: store the limit into the EC
+	 *  bits 6,7: store the limit into the battery
+	 */
+
+	/*
+	 * handle 0x0115 should allow storing on battery too;
+	 * handle 0x0136 same as 0x0115 + health status;
+	 * handle 0x013f, same as 0x0136 but no storing on the battery
+	 *
+	 * Store only inside the EC for now, regardless the handle number
+	 */
+	switch (value) {
+	case 0:	/* disable */
+		cmd = 0x00;
+		break;
+	case 1: /* enable, 80% charge limit */
+		cmd = 0x11;
+		break;
+	case 2: /* enable, 50% charge limit */
+		cmd = 0x21;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (sony_call_snc_handle(sony_bc_handle, (cmd << 0x10) | 0x0100,
+				&result))
+		return -EIO;
+
+	return count;
+}
+
+static ssize_t sony_nc_battery_care_limit_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result, status;
+
+	if (sony_call_snc_handle(sony_bc_handle, 0x0000, &result))
+		return -EIO;
+
+	/* if disabled 0, else take the limit bits */
+	status = !(result & 0x01) ? 0 : ((result & 0x30) >> 0x04);
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", status);
+	return count;
+}
+
+static ssize_t sony_nc_battery_care_health_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int health;
+
+	if (sony_call_snc_handle(sony_bc_handle, 0x0200, &health))
+		return -EIO;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", health & 0xff);
+
+	return count;
+}
+
+static int sony_nc_battery_care_setup(struct platform_device *pd)
+{
+	bcare_attrs = kzalloc(sizeof(struct device_attribute) * 2, GFP_KERNEL);
+	if (!bcare_attrs)
+		return -ENOMEM;
+
+	sysfs_attr_init(&bcare_attrs[0].attr);
+	bcare_attrs[0].attr.name = "battery_care_limiter";
+	bcare_attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	bcare_attrs[0].show = sony_nc_battery_care_limit_show;
+	bcare_attrs[0].store = sony_nc_battery_care_limit_store;
+
+	if (device_create_file(&pd->dev, &bcare_attrs[0]))
+		goto outkzalloc;
+
+	if (sony_bc_handle == 0x0115) /* no health indication */
+		return 0;
+
+	sysfs_attr_init(&bcare_attrs[1].attr);
+	bcare_attrs[1].attr.name = "battery_care_health";
+	bcare_attrs[1].attr.mode = S_IRUGO;
+	bcare_attrs[1].show = sony_nc_battery_care_health_show;
+
+	if (device_create_file(&pd->dev, &bcare_attrs[1]))
+		goto outlimiter;
+
+	return 0;
+
+outlimiter:
+	device_remove_file(&pd->dev, &bcare_attrs[0]);
+outkzalloc:
+	kfree(bcare_attrs);
+	bcare_attrs = NULL;
+
+	return -1;
+}
+
+static int sony_nc_battery_care_cleanup(struct platform_device *pd)
+{
+	if (sony_bc_handle != -1) {
+		device_remove_file(&pd->dev, &bcare_attrs[0]);
+		if (sony_bc_handle != 0x0115)
+			device_remove_file(&pd->dev, &bcare_attrs[1]);
+
+		kfree(bcare_attrs);
+		bcare_attrs = NULL;
+	}
+
+	return 0;
+}
+
+/*	Optical device driver part	*/
+struct odd {
+	unsigned int vendor_id;
+	unsigned int model_id;
+	struct device_attribute status_attr;
+};
+static struct odd *odd_handle;
+
+#if 0
+static int sony_nc_odd_remove(void)
+{
+	/*
+	   0 - change the link state first?
+	   1 - scsi lookup searching for the optical device (scsi_device *)
+	   2 - call int scsi_remove_device(struct scsi_device *sdev)
+	*/
+
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost;
+	int error = -ENXIO;
+
+	shost = scsi_host_lookup(host);
+	if (!shost)
+		return error;
+
+	sdev = scsi_device_lookup(shost, channel, id, lun);
+	if (sdev) {
+		scsi_remove_device(sdev);
+		scsi_device_put(sdev);
+		error = 0;
+	}
+
+	scsi_host_put(shost);
+
+	return 0;
+}
+#endif
+
+static ssize_t sony_nc_odd_status_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+#if 0
+	if (off)
+		sony_nc_odd_remove();
+
+		/* and goes on, otherwise leave */
+#endif
+
+	/* 0x200 turn on (sysfs: 1), 0x300 turn off (sysfs: 0) */
+	value = (!value << 0x08) + 0x200;
+
+	/* the MSB have to be high */
+	if (sony_call_snc_handle(0x126, (1 << 0x10) | value, &result))
+		return -EIO;
+
+#if 0
+	if (on)
+		/* force a bus scan? */
+#endif
+
+	return count;
+}
+
+static ssize_t sony_nc_odd_status_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x126, 0x100, &result))
+		return -EINVAL;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
+	return count;
+}
+
+static int sony_nc_odd_setup(struct platform_device *pd)
+{
+#define ODD_TAB_SIZE 32
+	u8 list[ODD_TAB_SIZE] = { 0 };
+	int ret = 0;
+	int found = 0;
+	int i = 0;
+	unsigned int vendor = 0;
+	unsigned int model = 0;
+	u16 word = 0;
+
+	ret = sony_call_snc_handle_buffer(0x126, 0x0000, list, ODD_TAB_SIZE);
+	if (ret < 0) {
+		pr_info("unable to retrieve the odd table\n");
+		return -EIO;
+	}
+
+	/* parse the table looking for optical devices */
+	do {
+		word = (list[i+1] << 8) | list[i];
+
+		if (word == 1) { /* 1 DWord device data following */
+			vendor = (list[i+3] << 8) | list[i+2];
+			model = (list[i+5] << 8) | list[i+4];
+			found++;
+			i += 6;
+		} else {
+			i += 2;
+		}
+	} while (word != 0xff00);
+
+	if (found)
+		dprintk("one optical device found, connected to: %x:%x\n",
+				vendor, model);
+	else
+		return 0;
+
+	odd_handle = kzalloc(sizeof(*odd_handle), GFP_KERNEL);
+	if (!odd_handle)
+		return -ENOMEM;
+
+	odd_handle->vendor_id = vendor;
+	odd_handle->model_id = model;
+
+	sysfs_attr_init(&odd_handle->status_attr.attr);
+	odd_handle->status_attr.attr.name = "odd_power";
+	odd_handle->status_attr.attr.mode = S_IRUGO | S_IWUSR;
+	odd_handle->status_attr.show = sony_nc_odd_status_show;
+	odd_handle->status_attr.store = sony_nc_odd_status_store;
+
+	if (device_create_file(&pd->dev, &odd_handle->status_attr)) {
+		kfree(odd_handle);
+		odd_handle = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+static int sony_nc_odd_cleanup(struct platform_device *pd)
+{
+	if (odd_handle) {
+		device_remove_file(&pd->dev, &odd_handle->status_attr);
+		kfree(odd_handle);
+		odd_handle = NULL;
+	}
+
+	return 0;
+}
+
+struct kbd_backlight {
+	unsigned int base;
+	unsigned int mode;
+	unsigned int timeout;
+	struct device_attribute mode_attr;
+	struct device_attribute timeout_attr;
+};
+static struct kbd_backlight *kbdbl_handle;
+
+static int __sony_nc_kbd_backlight_mode_set(u8 value)
+{
+	unsigned int result;
+
+	if (value > 1)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(sony_als_handle, (value << 0x10) |
+				(kbdbl_handle->base), &result))
+		return -EIO;
+
+	kbdbl_handle->mode = value;
+
+	/* Turn the light on/off immediately */
+	if (sony_call_snc_handle(sony_als_handle, (value << 0x10) |
+				(kbdbl_handle->base + 0x100), &result))
+		return -EIO;
+
+	return 0;
+}
+
+static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	int ret = 0;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value))
+		return -EINVAL;
+
+	ret = __sony_nc_kbd_backlight_mode_set(value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sony_nc_kbd_backlight_mode_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->mode);
+
+	return count;
+}
+
+static int __sony_nc_kbd_backlight_timeout_set(u8 value)
+{
+	int unsigned result;
+
+	if (value > 3)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(sony_als_handle, (value << 0x10) |
+				(kbdbl_handle->base + 0x200), &result))
+		return -EIO;
+
+	kbdbl_handle->timeout = value;
+
+	return 0;
+}
+
+static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	int ret = 0;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+	if (strict_strtoul(buffer, 10, &value))
+		return -EINVAL;
+
+	ret = __sony_nc_kbd_backlight_timeout_set(value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	ssize_t count = 0;
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_handle->timeout);
+
+	return count;
+}
+
+static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
+{
+	unsigned int result, base_cmd;
+	bool found = false;
+
+	/* verify the kbd backlight presence */
+	if (sony_als_handle == 0x0137) {
+		if (sony_call_snc_handle(sony_als_handle, 0x0B00, &result))
+			return -EIO;
+
+		found = !!(result & 0x02);
+		base_cmd = 0x0C00;
+	} else {
+		if (sony_call_snc_handle(sony_als_handle, 0x0100, &result))
+			return -EIO;
+
+		found = result & 0x01;
+		base_cmd = 0x4000;
+	}
+
+	if (!found) {
+		dprintk("no backlight keyboard found\n");
+		return 0;
+	}
+
+	kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
+	if (!kbdbl_handle)
+		return -ENOMEM;
+
+	sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
+	kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
+	kbdbl_handle->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
+	kbdbl_handle->mode_attr.show = sony_nc_kbd_backlight_mode_show;
+	kbdbl_handle->mode_attr.store = sony_nc_kbd_backlight_mode_store;
+
+	sysfs_attr_init(&kbdbl_handle->timeout_attr.attr);
+	kbdbl_handle->timeout_attr.attr.name = "kbd_backlight_timeout";
+	kbdbl_handle->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
+	kbdbl_handle->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
+	kbdbl_handle->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
+
+	if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
+		goto outkzalloc;
+
+	if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
+		goto outmode;
+
+	kbdbl_handle->base = base_cmd;
+
+	__sony_nc_kbd_backlight_mode_set(kbd_backlight);
+	__sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
+
+	return 0;
+
+outmode:
+	device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
+outkzalloc:
+	kfree(kbdbl_handle);
+	kbdbl_handle = NULL;
+	return -1;
+}
+
+static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
+{
+	if (kbdbl_handle) {
+		unsigned int result;
+
+		device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
+		device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
+
+		/* restore the default hw behaviour */
+		sony_call_snc_handle(sony_als_handle,
+				kbdbl_handle->base | 0x10000, &result);
+		sony_call_snc_handle(sony_als_handle,
+				kbdbl_handle->base + 0x200, &result);
+
+		kfree(kbdbl_handle);
+		kbdbl_handle = NULL;
+	}
+
+	return 0;
+}
+
+static void sony_nc_kbd_backlight_resume(void)
+{
+	unsigned int result;
+
+	if (!kbdbl_handle)
+		return;
+
+	if (kbdbl_handle->mode == 0)
+		sony_call_snc_handle(sony_als_handle,
+				kbdbl_handle->base, &result);
+
+	if (kbdbl_handle->timeout != 0)
+		sony_call_snc_handle(sony_als_handle,
+				(kbdbl_handle->base + 0x200) |
+				(kbdbl_handle->timeout << 0x10), &result);
+}
+
+/*
+ * Backlight device
+ */
+static int sony_backlight_update_status(struct backlight_device *bd)
+{
+	return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
+				bd->props.brightness + 1, NULL);
+}
+
+static int sony_backlight_get_brightness(struct backlight_device *bd)
+{
+	unsigned int value;
+
+	if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
+		return 0;
+	/* brightness levels are 1-based, while backlight ones are 0-based */
+	return value - 1;
+}
+
+static const struct backlight_ops sony_backlight_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = sony_backlight_update_status,
+	.get_brightness = sony_backlight_get_brightness,
+};
+
+static const struct backlight_ops sony_als_backlight_ops = {
+	.options = BL_CORE_SUSPENDRESUME,
+	.update_status = sony_nc_als_update_status,
+	.get_brightness = sony_nc_als_get_brightness,
+};
+
+static struct backlight_device *sony_backlight_device;
+static const struct backlight_ops sony_backlight_ops;
+
+static void sony_nc_backlight_setup(void)
+{
+	acpi_handle unused;
+	int max_brightness = 0;
+	const struct backlight_ops *ops = NULL;
+	struct backlight_properties props;
+
+	/* do not use SNC GBRT/SBRT controls along with the ALS */
+	if (sony_als_handle != -1) { /* ALS based backlight device */
+		ops = &sony_als_backlight_ops;
+		max_brightness = als_handle->levels_num - 1;
+	} else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
+						&unused))) {
+		ops = &sony_backlight_ops;
+		max_brightness = SONY_MAX_BRIGHTNESS - 1;
+	} else {
+		return;
 	}
 
-	/* set the last requested brightness level */
-	if (sony_backlight_device &&
-			sony_backlight_update_status(sony_backlight_device) < 0)
-		printk(KERN_WARNING DRV_PFX "unable to restore brightness level\n");
+	memset(&props, 0, sizeof(struct backlight_properties));
+	props.max_brightness = max_brightness;
+	sony_backlight_device = backlight_device_register("sony", NULL,
+							&sony_als_handle,
+							ops, &props);
+
+	if (IS_ERR(sony_backlight_device)) {
+		pr_warning(DRV_PFX "unable to register backlight device\n");
+		sony_backlight_device = NULL;
+	} else {
+		sony_backlight_device->props.brightness =
+		    sony_backlight_ops.get_brightness(sony_backlight_device);
+	}
+}
 
-	/* re-read rfkill state */
-	sony_nc_rfkill_update();
+static void sony_nc_backlight_cleanup(void)
+{
+	if (sony_backlight_device)
+		backlight_device_unregister(sony_backlight_device);
+}
 
-	return 0;
+static void sony_nc_tests_resume(void)
+{
+	return;
 }
 
-static void sony_nc_rfkill_cleanup(void)
+/* place here some unknown handles, we might want to see some output */
+static void sony_nc_tests_setup(void)
 {
-	int i;
+	int ret;
+	unsigned int result;
+	u8 buffer[6];
+
+	result = 0;
+	ret = sony_call_snc_handle(0x114, 0x000, &result);
+	if (!ret)
+		pr_info("handle 0x114 returned: %x\n", result & 0xff);
+
+	result = 0;
+	ret = sony_call_snc_handle(0x13A, 0x000, &result);
+	if (!ret)
+		pr_info("handle 0x13A returned: %x\n", result & 0xff);
+
+	result = 0;
+	ret = sony_call_snc_handle(0x139, 0x0000, &result);
+	if (!ret)
+		pr_info("handle 0x139+00 returned: %x\n", result & 0xffff);
+
+	result = 0;
+	ret = sony_call_snc_handle(0x139, 0x0100, &result);
+	if (!ret)
+		pr_info("handle 0x139+01 returned: %x\n", result & 0xffff);
+
+	ret = sony_call_snc_handle_buffer(0x140, 0x0000, buffer, 6);
+	if (ret >= 0)
+		for (ret = 0; ret < 6; ret++)
+			dprintk("buffer[%d]: %u\n", ret, buffer[ret]);
+
+	ret = sony_call_snc_handle(0x147, 0x0100, &result);
+	if (!ret)
+		pr_info("handle 0x147+01 returned: %x\n", result & 0x01);
+
+	ret = sony_call_snc_handle(0x147, 0x0200, &result);
+	if (!ret)
+		pr_info("handle 0x147+02 returned: %x\n", result & 0x0f);
+
+	ret = sony_call_snc_handle(0x147, 0x0400, &result);
+	if (!ret)
+		pr_info("handle 0x147+04 returned: %x\n", result & 0x01);
+
+	ret = sony_call_snc_handle(0x147, 0x0400, &result);
+	if (!ret)
+		pr_info("handle 0x147+06 returned: %x\n", result & 0x01);
+
+	ret = sony_call_snc_handle(0x149, 0x0000, &result);
+	if (!ret)
+		pr_info("handle 0x149+00 returned: %x\n", result & 0xff);
+
+	ret = sony_call_snc_handle(0x149, 0x0100, &result);
+	if (!ret)
+		pr_info("handle 0x149+01 returned: %x\n", result & 0x01);
+
+	ret = sony_call_snc_handle(0x149, 0x0300, &result);
+	if (!ret)
+		pr_info("handle 0x149+03 returned: %x\n", result & 0xffff);
 
-	for (i = 0; i < N_SONY_RFKILL; i++) {
-		if (sony_rfkill_devices[i]) {
-			rfkill_unregister(sony_rfkill_devices[i]);
-			rfkill_destroy(sony_rfkill_devices[i]);
-		}
-	}
+	return;
 }
 
-static int sony_nc_rfkill_set(void *data, bool blocked)
+static int sony_nc_snc_setup(struct platform_device *pd)
 {
-	int result;
-	int argument = sony_rfkill_address[(long) data] + 0x100;
+	unsigned int result, i;
 
-	if (!blocked)
-		argument |= 0xff0000;
+	/* Enable all events, otherwise return */
+	if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result))
+		return -1;
 
-	return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
-}
+	/* retrieve the available handles, otherwise return */
+	if (sony_nc_handles_setup(pd))
+		return -2;
+
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+		int ret = 0;
+		int unsigned handle = handles->cap[i];
 
-static const struct rfkill_ops sony_rfkill_ops = {
-	.set_block = sony_nc_rfkill_set,
-};
+		if (!handle)
+			continue;
 
-static int sony_nc_setup_rfkill(struct acpi_device *device,
-				enum sony_nc_rfkill nc_type)
-{
-	int err = 0;
-	struct rfkill *rfk;
-	enum rfkill_type type;
-	const char *name;
-	int result;
-	bool hwblock;
+		dprintk("looking at handle 0x%.4x\n", handle);
 
-	switch (nc_type) {
-	case SONY_WIFI:
-		type = RFKILL_TYPE_WLAN;
-		name = "sony-wifi";
-		break;
-	case SONY_BLUETOOTH:
-		type = RFKILL_TYPE_BLUETOOTH;
-		name = "sony-bluetooth";
-		break;
-	case SONY_WWAN:
-		type = RFKILL_TYPE_WWAN;
-		name = "sony-wwan";
-		break;
-	case SONY_WIMAX:
-		type = RFKILL_TYPE_WIMAX;
-		name = "sony-wimax";
-		break;
-	default:
-		return -EINVAL;
+		switch (handle) {
+		case 0x0100:
+		case 0x0127:
+		case 0x0101:
+		case 0x0102:
+			ret = sony_nc_function_setup(handle);
+			break;
+		case 0x0137:
+		case 0x0143:
+			sony_als_handle = handle;
+			ret = sony_nc_kbd_backlight_setup(pd);
+		case 0x012f: /* no keyboard backlight */
+			sony_als_handle = handle;
+			ret = sony_nc_als_setup(pd);
+			break;
+		case 0x0119:
+			ret = sony_nc_lid_resume_setup(pd);
+			break;
+		case 0x0105:
+		case 0x0148: /* same as 0x0105 + Fn-F1 combo */
+			sony_tpad_handle = handle;
+			ret = sony_nc_touchpad_setup(pd);
+			break;
+		case 0x0126:
+			ret = sony_nc_odd_setup(pd);
+			break;
+		case 0x0115:
+		case 0x0136:
+		case 0x013f:
+			sony_bc_handle = handle;
+			ret = sony_nc_battery_care_setup(pd);
+			break;
+		case 0x0134:
+			sony_gs_handle = handle;
+			ret = sony_nc_gsensor_setup(pd);
+			break;
+		case 0x0122:
+			ret = sony_nc_thermal_setup(pd);
+			break;
+		case 0x0124:
+		case 0x0135:
+			sony_rfkill_handle = handle;
+			ret = sony_nc_rfkill_setup(sony_nc_acpi_device);
+			break;
+		case 0x0131:
+			ret = sony_nc_highspeed_charging_setup(pd);
+		default:
+			continue;
+		}
+
+		if (ret < 0) {
+			pr_warn("handle 0x%.4x setup failed (ret: %i)",
+								handle, ret);
+		} else {
+			dprintk("handle 0x%.4x setup completed\n", handle);
+		}
 	}
 
-	rfk = rfkill_alloc(name, &device->dev, type,
-			   &sony_rfkill_ops, (void *)nc_type);
-	if (!rfk)
-		return -ENOMEM;
+	if (debug)
+		sony_nc_tests_setup();
 
-	sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
-	hwblock = !(result & 0x1);
-	rfkill_set_hw_state(rfk, hwblock);
+	return 0;
+}
 
-	err = rfkill_register(rfk);
-	if (err) {
-		rfkill_destroy(rfk);
-		return err;
-	}
-	sony_rfkill_devices[nc_type] = rfk;
-	return err;
+static void sony_nc_snc_cleanup(struct platform_device *pd)
+{
+	unsigned int result;
+
+	/* disable the event generation	for every handles */
+	acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0xffff, &result);
+
+	/* we can safely call them all */
+	sony_nc_kbd_backlight_cleanup(pd);
+	sony_nc_als_cleanup(pd);
+	sony_nc_touchpad_cleanup(pd);
+	sony_nc_battery_care_cleanup(pd);
+	sony_nc_odd_cleanup(pd);
+	sony_nc_gsensor_cleanup(pd);
+	sony_nc_lid_resume_cleanup(pd);
+	sony_nc_thermal_cleanup(pd);
+	sony_nc_handles_cleanup(pd);
+	sony_nc_highspeed_charging_cleanup(pd);
+	sony_nc_rfkill_cleanup();
+
+	return;
 }
 
-static void sony_nc_rfkill_update(void)
+static void sony_nc_snc_resume(void)
 {
-	enum sony_nc_rfkill i;
-	int result;
-	bool hwblock;
+	unsigned int i, result;
 
-	sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
-	hwblock = !(result & 0x1);
+	/* Enable all events, otherwise return */
+	if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result))
+		return;
 
-	for (i = 0; i < N_SONY_RFKILL; i++) {
-		int argument = sony_rfkill_address[i];
+	/*  Call the necessary update or resume functions looking
+	 *  at the available HW capabilities.
+	 */
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+		int unsigned handle = handles->cap[i];
 
-		if (!sony_rfkill_devices[i])
+		if (!handle)
 			continue;
 
-		if (hwblock) {
-			if (rfkill_set_hw_state(sony_rfkill_devices[i], true)) {
-				/* we already know we're blocked */
-			}
+		dprintk("looking at handle 0x%.4x\n", handle);
+
+		switch (handle) {
+		case 0x0100:
+		case 0x0127:
+		case 0x0101:
+		case 0x0102:
+			sony_nc_function_setup(handle);
+			break;
+		case 0x0124:
+		case 0x0135:
+			/* re-read rfkill state */
+			sony_nc_rfkill_update();
+			break;
+		case 0x0137: /* kbd + als */
+		case 0x0143:
+			sony_nc_kbd_backlight_resume();
+		case 0x012f: /* als only */
+			sony_nc_als_resume();
+			break;
+		case 0x0122:
+			sony_nc_thermal_resume();
+			break;
+		default:
 			continue;
 		}
 
-		sony_call_snc_handle(sony_rfkill_handle, argument, &result);
-		rfkill_set_states(sony_rfkill_devices[i],
-				  !(result & 0xf), false);
+		dprintk("handle 0x%.4x updated\n", handle);
 	}
+
+	if (debug)
+		sony_nc_tests_resume();
+
+	return;
 }
 
-static void sony_nc_rfkill_setup(struct acpi_device *device)
+static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
-	int offset;
-	u8 dev_code, i;
-	acpi_status status;
-	struct acpi_object_list params;
-	union acpi_object in_obj;
-	union acpi_object *device_enum;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	u8 ev = 0;
+	int value = 0;
 
-	offset = sony_find_snc_handle(0x124);
-	if (offset == -1) {
-		offset = sony_find_snc_handle(0x135);
-		if (offset == -1)
-			return;
-		else
-			sony_rfkill_handle = 0x135;
-	} else
-		sony_rfkill_handle = 0x124;
-	dprintk("Found rkfill handle: 0x%.4x\n", sony_rfkill_handle);
+	dprintk("sony_nc_notify, event: 0x%.2x\n", event);
 
-	/* need to read the whole buffer returned by the acpi call to SN06
-	 * here otherwise we may miss some features
+	/* events codes list
+	 * 1    Hotkeys
+	 * 2    RFKILL
+	 * 3    ALS
+	 * 4    HDD protection
+	 * 5	Hybrid GFX
 	 */
-	params.count = 1;
-	params.pointer = &in_obj;
-	in_obj.type = ACPI_TYPE_INTEGER;
-	in_obj.integer.value = offset;
-	status = acpi_evaluate_object(sony_nc_acpi_handle, "SN06", &params,
-			&buffer);
-	if (ACPI_FAILURE(status)) {
-		dprintk("Radio device enumeration failed\n");
-		return;
-	}
 
-	device_enum = (union acpi_object *) buffer.pointer;
-	if (!device_enum) {
-		pr_err("Invalid SN06 return object\n");
-		goto out_no_enum;
-	}
-	if (device_enum->type != ACPI_TYPE_BUFFER) {
-		pr_err("Invalid SN06 return object type 0x%.2x\n",
-		       device_enum->type);
-		goto out_no_enum;
-	}
+	/* handles related events */
+	if (event >= 0x90) {
+		unsigned int result = 0, handle = 0;
+
+		/* the event should corrispond to the offset of the method */
+		unsigned int offset = event - 0x90;
+
+		handle = handles->cap[offset];
+		switch (handle) {
+		/* list of handles known for generating events */
+		case 0x0100:
+		case 0x0127:
+			/* hotkey event, a key has been pressed, retrieve it */
+			value = sony_nc_hotkeys_decode(handle);
+			if (value > 0) /* known event */
+				sony_laptop_report_input_event(value);
+			/* else unknown event or failure, do nothing */
+			ev = 1;
+			break;
 
-	/* the buffer is filled with magic numbers describing the devices
-	 * available, 0xff terminates the enumeration
-	 */
-	for (i = 0; i < device_enum->buffer.length; i++) {
+		case 0x0143:
+			sony_call_snc_handle(sony_als_handle, 0x2000, &result);
+			/* event reasons are reverted */
+			value = (result & 0x03) == 1 ? 2 : 1;
+			dprintk("sony_nc_notify, ALS event received (reason:"
+				       " %s change)\n", value == 1 ? "light" :
+				       "backlight");
+			/* no further actions needed */
 
-		dev_code = *(device_enum->buffer.pointer + i);
-		if (dev_code == 0xff)
+			ev = 3;
 			break;
 
-		dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
+		case 0x012f:
+		case 0x0137:
+			sony_call_snc_handle(sony_als_handle, 0x0800, &result);
+			value = result & 0x03;
+			dprintk("sony_nc_notify, ALS event received (reason:"
+					" %s change)\n", value == 1 ? "light" :
+					"backlight");
+			if (value == 1) /* lighting change reason */
+				sony_nc_als_event_handler();
 
-		if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
-			sony_nc_setup_rfkill(device, SONY_WIFI);
+			ev = 3;
+			break;
 
-		if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
-			sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
+		case 0x0124:
+		case 0x0135:
+			sony_call_snc_handle(sony_rfkill_handle, 0x0100,
+						&result);
+			result &= 0x03;
+			dprintk("sony_nc_notify, RFKILL event received "
+					"(reason: %s)\n", result == 1 ?
+					"switch state changed" : "battery");
+
+			if (result == 1) { /* hw swtich event */
+				sony_nc_rfkill_update();
+				sony_laptop_report_input_event(
+						SONYPI_EVENT_RFKILL_ALL);
+				value = sony_nc_get_rfkill_hwblock();
+			} else if (result == 2) { /* battery event */
+				/*  we might need to change the WWAN rfkill
+				    state when the battery state changes
+				 */
+				sony_nc_rfkill_update_wwan();
+				return;
+			}
 
-		if ((0xf0 & dev_code) == 0x20 &&
-				!sony_rfkill_devices[SONY_WWAN])
-			sony_nc_setup_rfkill(device, SONY_WWAN);
+			ev = 2;
+			break;
 
-		if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
-			sony_nc_setup_rfkill(device, SONY_WIMAX);
+		case 0x0134:
+		case 0x0147:
+			ev = 4;
+			value = 1;
+			/* hdd protection event, notify userspace */
+			break;
+		case 0x0128:
+		case 0x0146:
+			/* Hybrid GFX switching */
+			sony_call_snc_handle(handle, 0x0000, &result);
+			dprintk("sony_nc_notify, Hybrid GFX event received "
+					"(reason: %s)\n", (result & 0x01) ?
+					"switch position change" : "unknown");
+
+			/* verify the switch state */
+			result = 0;
+			sony_call_snc_handle(handle, 0x0100, &result);
+
+			ev = 5;
+			value = result & 0xff;
+			break;
+
+		default:
+			value = event;
+			dprintk(DRV_PFX "Unknowk event for handle: 0x%x\n",
+					handle);
+			break;
+		}
+
+		/* clear the event (and the event reason when present) */
+		acpi_callsetfunc(sony_nc_acpi_handle, "SN05", 1 << offset,
+				&result);
+	} else {
+		ev = 1;
+		sony_laptop_report_input_event(event);
 	}
 
-out_no_enum:
-	kfree(buffer.pointer);
-	return;
+	acpi_bus_generate_proc_event(device, ev, value);
+	acpi_bus_generate_netlink_event(device->pnp.device_class,
+					dev_name(&device->dev), ev, value);
 }
 
 static int sony_nc_add(struct acpi_device *device)
@@ -1252,8 +4068,7 @@ static int sony_nc_add(struct acpi_devic
 	acpi_handle handle;
 	struct sony_nc_value *item;
 
-	printk(KERN_INFO DRV_PFX "%s v%s.\n",
-		SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+	pr_info("%s v%s.\n", SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
 	sony_nc_acpi_device = device;
 	strcpy(acpi_device_class(device), "sony/hotkey");
@@ -1262,20 +4077,26 @@ static int sony_nc_add(struct acpi_devic
 
 	/* read device status */
 	result = acpi_bus_get_status(device);
-	/* bail IFF the above call was successful and the device is not present */
+	/* bail IFF the above call was successful
+	   and the device is not present */
 	if (!result && !device->status.present) {
 		dprintk("Device not present\n");
 		result = -ENODEV;
 		goto outwalk;
 	}
 
+	result = sony_pf_add();
+	if (result)
+		goto outpresent;
+
 	if (debug) {
-		status = acpi_walk_namespace(ACPI_TYPE_METHOD, sony_nc_acpi_handle,
-					     1, sony_walk_callback, NULL, NULL, NULL);
+		status = acpi_walk_namespace(ACPI_TYPE_METHOD,
+				sony_nc_acpi_handle, 1, sony_walk_callback,
+				NULL, NULL, NULL);
 		if (ACPI_FAILURE(status)) {
-			printk(KERN_WARNING DRV_PFX "unable to walk acpi resources\n");
+			pr_warn("unable to walk acpi resources\n");
 			result = -ENODEV;
-			goto outwalk;
+			goto outpresent;
 		}
 	}
 
@@ -1287,47 +4108,28 @@ static int sony_nc_add(struct acpi_devic
 
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
 					 &handle))) {
+
 		dprintk("Doing SNC setup\n");
-		sony_nc_function_setup(device);
-		sony_nc_rfkill_setup(device);
+
+		/* setup the available hw capabilities if necessary */
+		if (sony_nc_snc_setup(sony_pf_device))
+			goto outpresent;
 	}
 
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input(device);
 	if (result) {
-		printk(KERN_ERR DRV_PFX
-				"Unable to create input devices.\n");
-		goto outwalk;
+		pr_err("Unable to create input devices.\n");
+		goto outsnc;
 	}
 
 	if (acpi_video_backlight_support()) {
-		printk(KERN_INFO DRV_PFX "brightness ignored, must be "
+		pr_info("brightness ignored, must be "
 		       "controlled by ACPI video driver\n");
-	} else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
-						&handle))) {
-							struct backlight_properties props;
-		memset(&props, 0, sizeof(struct backlight_properties));
-		props.max_brightness = SONY_MAX_BRIGHTNESS - 1;
-		sony_backlight_device = backlight_device_register("sony", NULL,
-								  NULL,
-								  &sony_backlight_ops,
-								  &props);
-
-		if (IS_ERR(sony_backlight_device)) {
-			printk(KERN_WARNING DRV_PFX "unable to register backlight device\n");
-			sony_backlight_device = NULL;
-		} else {
-			sony_backlight_device->props.brightness =
-			    sony_backlight_get_brightness
-			    (sony_backlight_device);
-		}
-
+	} else {
+		sony_nc_backlight_setup();
 	}
 
-	result = sony_pf_add();
-	if (result)
-		goto outbacklight;
-
 	/* create sony_pf sysfs attributes related to the SNC device */
 	for (item = sony_nc_values; item->name; ++item) {
 
@@ -1369,20 +4171,22 @@ static int sony_nc_add(struct acpi_devic
 
 	return 0;
 
-      out_sysfs:
-	for (item = sony_nc_values; item->name; ++item) {
+out_sysfs:
+	for (item = sony_nc_values; item->name; ++item)
 		device_remove_file(&sony_pf_device->dev, &item->devattr);
-	}
-	sony_pf_remove();
 
-      outbacklight:
-	if (sony_backlight_device)
-		backlight_device_unregister(sony_backlight_device);
+	sony_nc_backlight_cleanup();
 
 	sony_laptop_remove_input();
 
-      outwalk:
-	sony_nc_rfkill_cleanup();
+
+outsnc:
+	sony_nc_snc_cleanup(sony_pf_device);
+
+outpresent:
+	sony_pf_remove();
+
+outwalk:
 	return result;
 }
 
@@ -1390,23 +4194,60 @@ static int sony_nc_remove(struct acpi_de
 {
 	struct sony_nc_value *item;
 
-	if (sony_backlight_device)
-		backlight_device_unregister(sony_backlight_device);
+	sony_nc_backlight_cleanup();
 
 	sony_nc_acpi_device = NULL;
 
-	for (item = sony_nc_values; item->name; ++item) {
+	for (item = sony_nc_values; item->name; ++item)
 		device_remove_file(&sony_pf_device->dev, &item->devattr);
-	}
 
+	sony_nc_snc_cleanup(sony_pf_device);
 	sony_pf_remove();
 	sony_laptop_remove_input();
-	sony_nc_rfkill_cleanup();
 	dprintk(SONY_NC_DRIVER_NAME " removed.\n");
 
 	return 0;
 }
 
+static int sony_nc_resume(struct acpi_device *device)
+{
+	struct sony_nc_value *item;
+	acpi_handle handle;
+
+	for (item = sony_nc_values; item->name; item++) {
+		int ret;
+
+		if (!item->valid)
+			continue;
+		ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
+				       item->value, NULL);
+		if (ret < 0) {
+			pr_err("%s: %d\n", __func__, ret);
+			break;
+		}
+	}
+
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
+					 &handle))) {
+		if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
+			dprintk("ECON Method failed\n");
+	}
+
+	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
+					 &handle))) {
+		dprintk("Doing SNC setup\n");
+
+		sony_nc_snc_resume();
+	}
+
+	/* set the last requested brightness level */
+	if (sony_backlight_device &&
+		sony_backlight_ops.update_status(sony_backlight_device) < 0)
+		pr_warn("unable to restore brightness level\n");
+
+	return 0;
+}
+
 static const struct acpi_device_id sony_device_ids[] = {
 	{SONY_NC_HID, 0},
 	{SONY_PIC_HID, 0},
@@ -1437,7 +4278,6 @@ static struct acpi_driver sony_nc_driver
 #define SONYPI_DEVICE_TYPE1	0x00000001
 #define SONYPI_DEVICE_TYPE2	0x00000002
 #define SONYPI_DEVICE_TYPE3	0x00000004
-#define SONYPI_DEVICE_TYPE4	0x00000008
 
 #define SONYPI_TYPE1_OFFSET	0x04
 #define SONYPI_TYPE2_OFFSET	0x12
@@ -1583,8 +4423,8 @@ static struct sonypi_event sonypi_blueev
 
 /* The set of possible wireless events */
 static struct sonypi_event sonypi_wlessev[] = {
-	{ 0x59, SONYPI_EVENT_WIRELESS_ON },
-	{ 0x5a, SONYPI_EVENT_WIRELESS_OFF },
+	{ 0x59, SONYPI_EVENT_IGNORE },
+	{ 0x5a, SONYPI_EVENT_IGNORE },
 	{ 0, 0 }
 };
 
@@ -1746,11 +4586,14 @@ static u8 sony_pic_call3(u8 dev, u8 fn, 
 {
 	u8 v1;
 
-	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
+			ITERATIONS_LONG);
 	outb(dev, spic_dev.cur_ioport->io1.minimum + 4);
-	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
+			ITERATIONS_LONG);
 	outb(fn, spic_dev.cur_ioport->io1.minimum);
-	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2, ITERATIONS_LONG);
+	wait_on_command(inb_p(spic_dev.cur_ioport->io1.minimum + 4) & 2,
+			ITERATIONS_LONG);
 	outb(v, spic_dev.cur_ioport->io1.minimum);
 	v1 = inb_p(spic_dev.cur_ioport->io1.minimum);
 	dprintk("sony_pic_call3(0x%.2x - 0x%.2x - 0x%.2x): 0x%.4x\n",
@@ -1841,7 +4684,7 @@ out:
 	if (pcidev)
 		pci_dev_put(pcidev);
 
-	printk(KERN_INFO DRV_PFX "detected Type%d model\n",
+	pr_info("detected Type%d model\n",
 			dev->model == SONYPI_DEVICE_TYPE1 ? 1 :
 			dev->model == SONYPI_DEVICE_TYPE2 ? 2 : 3);
 }
@@ -1864,19 +4707,19 @@ out:
 /* the rest don't need a loop until not 0xff */
 #define SONYPI_CAMERA_AGC			6
 #define SONYPI_CAMERA_AGC_MASK			0x30
-#define SONYPI_CAMERA_SHUTTER_MASK 		0x7
+#define SONYPI_CAMERA_SHUTTER_MASK		0x7
 
 #define SONYPI_CAMERA_SHUTDOWN_REQUEST		7
 #define SONYPI_CAMERA_CONTROL			0x10
 
-#define SONYPI_CAMERA_STATUS 			7
-#define SONYPI_CAMERA_STATUS_READY 		0x2
+#define SONYPI_CAMERA_STATUS			7
+#define SONYPI_CAMERA_STATUS_READY		0x2
 #define SONYPI_CAMERA_STATUS_POSITION		0x4
 
-#define SONYPI_DIRECTION_BACKWARDS 		0x4
+#define SONYPI_DIRECTION_BACKWARDS		0x4
 
-#define SONYPI_CAMERA_REVISION 			8
-#define SONYPI_CAMERA_ROMVERSION 		9
+#define SONYPI_CAMERA_REVISION			8
+#define SONYPI_CAMERA_ROMVERSION		9
 
 static int __sony_pic_camera_ready(void)
 {
@@ -1889,7 +4732,7 @@ static int __sony_pic_camera_ready(void)
 static int __sony_pic_camera_off(void)
 {
 	if (!camera) {
-		printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+		pr_warn("camera control not enabled\n");
 		return -ENODEV;
 	}
 
@@ -1909,7 +4752,7 @@ static int __sony_pic_camera_on(void)
 	int i, j, x;
 
 	if (!camera) {
-		printk(KERN_WARNING DRV_PFX "camera control not enabled\n");
+		pr_warn("camera control not enabled\n");
 		return -ENODEV;
 	}
 
@@ -1932,7 +4775,7 @@ static int __sony_pic_camera_on(void)
 	}
 
 	if (j == 0) {
-		printk(KERN_WARNING DRV_PFX "failed to power on camera\n");
+		pr_warn("failed to power on camera\n");
 		return -ENODEV;
 	}
 
@@ -1988,7 +4831,7 @@ int sony_pic_camera_command(int command,
 				ITERATIONS_SHORT);
 		break;
 	default:
-		printk(KERN_ERR DRV_PFX "sony_pic_camera_command invalid: %d\n",
+		pr_err("sony_pic_camera_command invalid: %d\n",
 		       command);
 		break;
 	}
@@ -2012,11 +4855,15 @@ static ssize_t sony_pic_wwanpower_store(
 		struct device_attribute *attr,
 		const char *buffer, size_t count)
 {
+	int ret;
 	unsigned long value;
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	ret = strict_strtoul(buffer, 10, &value);
+	if (ret)
+		return ret;
+
 	mutex_lock(&spic_dev.lock);
 	__sony_pic_set_wwanpower(value);
 	mutex_unlock(&spic_dev.lock);
@@ -2049,11 +4896,15 @@ static ssize_t sony_pic_bluetoothpower_s
 		struct device_attribute *attr,
 		const char *buffer, size_t count)
 {
+	int ret;
 	unsigned long value;
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	ret = strict_strtoul(buffer, 10, &value);
+	if (ret)
+		return ret;
+
 	mutex_lock(&spic_dev.lock);
 	__sony_pic_set_bluetoothpower(value);
 	mutex_unlock(&spic_dev.lock);
@@ -2088,11 +4939,15 @@ static ssize_t sony_pic_fanspeed_store(s
 		struct device_attribute *attr,
 		const char *buffer, size_t count)
 {
+	int ret;
 	unsigned long value;
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	ret = strict_strtoul(buffer, 10, &value);
+	if (ret)
+		return ret;
+
 	if (sony_pic_set_fanspeed(value))
 		return -EIO;
 
@@ -2241,7 +5096,7 @@ static long sonypi_misc_ioctl(struct fil
 	void __user *argp = (void __user *)arg;
 	u8 val8;
 	u16 val16;
-	int value;
+	unsigned int value;
 
 	mutex_lock(&spic_dev.lock);
 	switch (cmd) {
@@ -2395,7 +5250,7 @@ static int sonypi_compat_init(void)
 	error =
 	 kfifo_alloc(&sonypi_compat.fifo, SONY_LAPTOP_BUF_SIZE, GFP_KERNEL);
 	if (error) {
-		printk(KERN_ERR DRV_PFX "kfifo_alloc failed\n");
+		pr_err("kfifo_alloc failed\n");
 		return error;
 	}
 
@@ -2405,11 +5260,11 @@ static int sonypi_compat_init(void)
 		sonypi_misc_device.minor = minor;
 	error = misc_register(&sonypi_misc_device);
 	if (error) {
-		printk(KERN_ERR DRV_PFX "misc_register failed\n");
+		pr_err("misc_register failed\n");
 		goto err_free_kfifo;
 	}
 	if (minor == -1)
-		printk(KERN_INFO DRV_PFX "device allocated minor is %d\n",
+		pr_info("device allocated minor is %d\n",
 		       sonypi_misc_device.minor);
 
 	return 0;
@@ -2469,8 +5324,7 @@ sony_pic_read_possible_resource(struct a
 			}
 			for (i = 0; i < p->interrupt_count; i++) {
 				if (!p->interrupts[i]) {
-					printk(KERN_WARNING DRV_PFX
-							"Invalid IRQ %d\n",
+					pr_warn("Invalid IRQ %d\n",
 							p->interrupts[i]);
 					continue;
 				}
@@ -2502,14 +5356,12 @@ sony_pic_read_possible_resource(struct a
 				memcpy(&ioport->io1, io, sizeof(*io));
 				dprintk("IO1 at 0x%.4x (0x%.2x)\n", ioport->io1.minimum,
 						ioport->io1.address_length);
-			}
-			else if (!ioport->io2.minimum) {
+			} else if (!ioport->io2.minimum) {
 				memcpy(&ioport->io2, io, sizeof(*io));
 				dprintk("IO2 at 0x%.4x (0x%.2x)\n", ioport->io2.minimum,
 						ioport->io2.address_length);
-			}
-			else {
-				printk(KERN_ERR DRV_PFX "Unknown SPIC Type, more than 2 IO Ports\n");
+			} else {
+				pr_err("Unknown SPIC Type, more than 2 IO Ports\n");
 				return AE_ERROR;
 			}
 			return AE_OK;
@@ -2537,7 +5389,7 @@ static int sony_pic_possible_resources(s
 	dprintk("Evaluating _STA\n");
 	result = acpi_bus_get_status(device);
 	if (result) {
-		printk(KERN_WARNING DRV_PFX "Unable to read status\n");
+		pr_warn("Unable to read status\n");
 		goto end;
 	}
 
@@ -2553,8 +5405,7 @@ static int sony_pic_possible_resources(s
 	status = acpi_walk_resources(device->handle, METHOD_NAME__PRS,
 			sony_pic_read_possible_resource, &spic_dev);
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_WARNING DRV_PFX
-				"Failure evaluating %s\n",
+		pr_warn("Failure evaluating %s\n",
 				METHOD_NAME__PRS);
 		result = -ENODEV;
 	}
@@ -2668,7 +5519,7 @@ static int sony_pic_enable(struct acpi_d
 
 	/* check for total failure */
 	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR DRV_PFX "Error evaluating _SRS\n");
+		pr_err("Error evaluating _SRS\n");
 		result = -ENODEV;
 		goto end;
 	}
@@ -2724,6 +5575,9 @@ static irqreturn_t sony_pic_irq(int irq,
 			if (ev == dev->event_types[i].events[j].data) {
 				device_event =
 					dev->event_types[i].events[j].event;
+				/* some events may require ignoring */
+				if (!device_event)
+					return IRQ_HANDLED;
 				goto found;
 			}
 		}
@@ -2743,7 +5597,6 @@ found:
 	sony_laptop_report_input_event(device_event);
 	acpi_bus_generate_proc_event(dev->acpi_dev, 1, device_event);
 	sonypi_compat_report_event(device_event);
-
 	return IRQ_HANDLED;
 }
 
@@ -2758,7 +5611,7 @@ static int sony_pic_remove(struct acpi_d
 	struct sony_pic_irq *irq, *tmp_irq;
 
 	if (sony_pic_disable(device)) {
-		printk(KERN_ERR DRV_PFX "Couldn't disable device.\n");
+		pr_err("Couldn't disable device.\n");
 		return -ENXIO;
 	}
 
@@ -2798,8 +5651,7 @@ static int sony_pic_add(struct acpi_devi
 	struct sony_pic_ioport *io, *tmp_io;
 	struct sony_pic_irq *irq, *tmp_irq;
 
-	printk(KERN_INFO DRV_PFX "%s v%s.\n",
-		SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
+	pr_info("%s v%s.\n", SONY_PIC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
 
 	spic_dev.acpi_dev = device;
 	strcpy(acpi_device_class(device), "sony/hotkey");
@@ -2809,16 +5661,14 @@ static int sony_pic_add(struct acpi_devi
 	/* read _PRS resources */
 	result = sony_pic_possible_resources(device);
 	if (result) {
-		printk(KERN_ERR DRV_PFX
-				"Unable to read possible resources.\n");
+		pr_err("Unable to read possible resources.\n");
 		goto err_free_resources;
 	}
 
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input(device);
 	if (result) {
-		printk(KERN_ERR DRV_PFX
-				"Unable to create input devices.\n");
+		pr_err("Unable to create input devices.\n");
 		goto err_free_resources;
 	}
 
@@ -2828,7 +5678,7 @@ static int sony_pic_add(struct acpi_devi
 	/* request io port */
 	list_for_each_entry_reverse(io, &spic_dev.ioports, list) {
 		if (request_region(io->io1.minimum, io->io1.address_length,
-					"Sony Programable I/O Device")) {
+				"Sony Programable I/O Device")) {
 			dprintk("I/O port1: 0x%.4x (0x%.4x) + 0x%.2x\n",
 					io->io1.minimum, io->io1.maximum,
 					io->io1.address_length);
@@ -2836,14 +5686,13 @@ static int sony_pic_add(struct acpi_devi
 			if (io->io2.minimum) {
 				if (request_region(io->io2.minimum,
 						io->io2.address_length,
-						"Sony Programable I/O Device")) {
+					"Sony Programable I/O Device")) {
 					dprintk("I/O port2: 0x%.4x (0x%.4x) + 0x%.2x\n",
 							io->io2.minimum, io->io2.maximum,
 							io->io2.address_length);
 					spic_dev.cur_ioport = io;
 					break;
-				}
-				else {
+				} else {
 					dprintk("Unable to get I/O port2: "
 							"0x%.4x (0x%.4x) + 0x%.2x\n",
 							io->io2.minimum, io->io2.maximum,
@@ -2851,15 +5700,14 @@ static int sony_pic_add(struct acpi_devi
 					release_region(io->io1.minimum,
 							io->io1.address_length);
 				}
-			}
-			else {
+			} else {
 				spic_dev.cur_ioport = io;
 				break;
 			}
 		}
 	}
 	if (!spic_dev.cur_ioport) {
-		printk(KERN_ERR DRV_PFX "Failed to request_region.\n");
+		pr_err("Failed to request_region.\n");
 		result = -ENODEV;
 		goto err_remove_compat;
 	}
@@ -2879,7 +5727,7 @@ static int sony_pic_add(struct acpi_devi
 		}
 	}
 	if (!spic_dev.cur_irq) {
-		printk(KERN_ERR DRV_PFX "Failed to request_irq.\n");
+		pr_err("Failed to request_irq.\n");
 		result = -ENODEV;
 		goto err_release_region;
 	}
@@ -2887,7 +5735,7 @@ static int sony_pic_add(struct acpi_devi
 	/* set resource status _SRS */
 	result = sony_pic_enable(device, spic_dev.cur_ioport, spic_dev.cur_irq);
 	if (result) {
-		printk(KERN_ERR DRV_PFX "Couldn't enable device.\n");
+		pr_err("Couldn't enable device.\n");
 		goto err_free_irq;
 	}
 
@@ -2897,7 +5745,8 @@ static int sony_pic_add(struct acpi_devi
 	if (result)
 		goto err_disable_device;
 
-	result = sysfs_create_group(&sony_pf_device->dev.kobj, &spic_attribute_group);
+	result = sysfs_create_group(&sony_pf_device->dev.kobj,
+			&spic_attribute_group);
 	if (result)
 		goto err_remove_pf;
 
@@ -2996,8 +5845,7 @@ static int __init sony_laptop_init(void)
 	if (!no_spic && dmi_check_system(sonypi_dmi_table)) {
 		result = acpi_bus_register_driver(&sony_pic_driver);
 		if (result) {
-			printk(KERN_ERR DRV_PFX
-					"Unable to register SPIC driver.");
+			pr_err("Unable to register SPIC driver.");
 			goto out;
 		}
 		spic_drv_registered = 1;
@@ -3005,7 +5853,7 @@ static int __init sony_laptop_init(void)
 
 	result = acpi_bus_register_driver(&sony_nc_driver);
 	if (result) {
-		printk(KERN_ERR DRV_PFX "Unable to register SNC driver.");
+		pr_err("Unable to register SNC driver.");
 		goto out_unregister_pic;
 	}
 
