diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 516dd22bbb26dc2e3c67005646db1b174a0e02f5..326a4600fad19e3cc3d90435e6e7eb8b4634d4d8 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -125,6 +125,19 @@ MODULE_PARM_DESC(minor,
 		 "default is -1 (automatic)");
 #endif
 
+static int kbd_backlight;	/* = 1 */
+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)");
+
 enum sony_nc_rfkill {
 	SONY_WIFI,
 	SONY_BLUETOOTH,
@@ -1309,6 +1322,161 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 	return;
 }
 
+/* Keyboard backlight feature */
+#define KBDBL_HANDLER	0x137
+#define KBDBL_PRESENT	0xB00
+#define	SET_MODE	0xC00
+#define SET_TIMEOUT	0xE00
+
+struct kbd_backlight {
+	int mode;
+	int timeout;
+	struct device_attribute mode_attr;
+	struct device_attribute timeout_attr;
+};
+
+struct kbd_backlight *kbdbl_handle;
+
+static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
+{
+	int result;
+
+	if (value > 1)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(KBDBL_HANDLER,
+				(value << 0x10) | SET_MODE, &result))
+		return -EIO;
+
+	kbdbl_handle->mode = value;
+
+	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 result;
+
+	if (value > 3)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(KBDBL_HANDLER,
+				(value << 0x10) | SET_TIMEOUT, &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)
+{
+	int result;
+
+	if (sony_call_snc_handle(0x137, KBDBL_PRESENT, &result))
+		return 0;
+	if (!(result & 0x02))
+		return 0;
+
+	kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
+
+	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;
+
+	__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) {
+		device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
+		device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
+		kfree(kbdbl_handle);
+	}
+	return 0;
+}
+
 static int sony_nc_add(struct acpi_device *device)
 {
 	acpi_status status;
@@ -1359,6 +1527,8 @@ static int sony_nc_add(struct acpi_device *device)
 		dprintk("Doing SNC setup\n");
 		if (sony_nc_handles_setup(sony_pf_device))
 			goto outpresent;
+		if (sony_nc_kbd_backlight_setup(sony_pf_device))
+			goto outsnc;
 		sony_nc_function_setup(device);
 		sony_nc_rfkill_setup(device);
 	}
@@ -1367,7 +1537,7 @@ static int sony_nc_add(struct acpi_device *device)
 	result = sony_laptop_setup_input(device);
 	if (result) {
 		pr_err(DRV_PFX "Unable to create input devices.\n");
-		goto outsnc;
+		goto outkbdbacklight;
 	}
 
 	if (acpi_video_backlight_support()) {
@@ -1445,6 +1615,9 @@ static int sony_nc_add(struct acpi_device *device)
 
 	sony_laptop_remove_input();
 
+      outkbdbacklight:
+	sony_nc_kbd_backlight_cleanup(sony_pf_device);
+
       outsnc:
 	sony_nc_handles_cleanup(sony_pf_device);
 
@@ -1469,6 +1642,7 @@ static int sony_nc_remove(struct acpi_device *device, int type)
 		device_remove_file(&sony_pf_device->dev, &item->devattr);
 	}
 
+	sony_nc_kbd_backlight_cleanup(sony_pf_device);
 	sony_nc_handles_cleanup(sony_pf_device);
 	sony_pf_remove();
 	sony_laptop_remove_input();