All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/19] sony-laptop: support for new functions
@ 2012-05-19 13:35 Mattia Dongili
  2012-05-19 13:35 ` [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw Mattia Dongili
                   ` (18 more replies)
  0 siblings, 19 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86

Hi Matthew,

here's the old series from Marco Chiappero adjusted for inclusion. Most of the
patches are more or less the same as he sent with the notable exception of the
ALS code for the "managed" backlight regulation (the original code was creating
a backlight interface within the platform sysfs tree to provide a different way
of setting lid brightness).

I tried to note the changes that I did to the original code in the commit
messages but left the author as it was. Hopefully that is fine.

Javier Achirica (1):
      sony-laptop: add the ALS interface via SNC

Marco Chiappero (12):
      sony-laptop: use soft rfkill status stored in hw
      sony-laptop: improve SNC initialization and acpi notify callback code
      sony-laptop: support battery care functions
      sony-laptop: add thermal profiles support
      sony-laptop: g-shock HD protection function
      sony-laptop: support automatic resume on lid open
      sony-laptop: add high speed battery charging function
      sony-laptop: new keyboard backlight handle
      sony-laptop: add support for more WWAN modems
      sony-laptop: add missing Fn key combos for 0x100 handlers
      sony-laptop: add touchpad enable/disable function
      sony-laptop: notify userspace of GFX switch position changes

Mattia Dongili (6):
      sony-laptop: fix return path when no ACPI buffer is allocated
      sony-laptop: generalise ACPI calls into SNC functions
      sony-laptop: use kstrtoul to parse sysfs values
      sony-laptop: additional debug statements
      sony-laptop: adjust error handling in finding SNC handles
      sony-laptop: use an enum for SNC event types

 drivers/platform/x86/sony-laptop.c | 2901 +++++++++++++++++++++++++++++++-----
 1 file changed, 2552 insertions(+), 349 deletions(-)

-- 
mattia
:wq

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-31 18:39   ` Matthew Garrett
  2012-05-19 13:35 ` [PATCH 02/19] sony-laptop: fix return path when no ACPI buffer is allocated Mattia Dongili
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

The SNC device on recent Vaio laptops also stores the soft status and
leaves it available after reboot. Use it and always set the last soft
and hard status on module load.

[malattia@linux.it: patch taken from a largely modified sony-laptop.c,
smaller modifications to the original code to simplify it]

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 8a51795..c6dc3f7 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1213,7 +1213,7 @@ static int sony_nc_rfkill_set(void *data, bool blocked)
 	int argument = sony_rfkill_address[(long) data] + 0x100;
 
 	if (!blocked)
-		argument |= 0xff0000;
+		argument |= 0x030000;
 
 	return sony_call_snc_handle(sony_rfkill_handle, argument, &result);
 }
@@ -1230,7 +1230,7 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
 	enum rfkill_type type;
 	const char *name;
 	int result;
-	bool hwblock;
+	bool hwblock, swblock;
 
 	switch (nc_type) {
 	case SONY_WIFI:
@@ -1258,8 +1258,21 @@ static int sony_nc_setup_rfkill(struct acpi_device *device,
 	if (!rfk)
 		return -ENOMEM;
 
-	sony_call_snc_handle(sony_rfkill_handle, 0x200, &result);
+	if (sony_call_snc_handle(sony_rfkill_handle, 0x200, &result) < 0) {
+		rfkill_destroy(rfk);
+		return -1;
+	}
 	hwblock = !(result & 0x1);
+
+	if (sony_call_snc_handle(sony_rfkill_handle,
+				sony_rfkill_address[nc_type],
+				&result) < 0) {
+		rfkill_destroy(rfk);
+		return -1;
+	}
+	swblock = !(result & 0x2);
+
+	rfkill_init_sw_state(rfk, swblock);
 	rfkill_set_hw_state(rfk, hwblock);
 
 	err = rfkill_register(rfk);
@@ -1295,7 +1308,7 @@ static void sony_nc_rfkill_update(void)
 
 		sony_call_snc_handle(sony_rfkill_handle, argument, &result);
 		rfkill_set_states(sony_rfkill_devices[i],
-				  !(result & 0xf), false);
+				  !(result & 0x2), false);
 	}
 }
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 02/19] sony-laptop: fix return path when no ACPI buffer is allocated
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
  2012-05-19 13:35 ` [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 03/19] sony-laptop: generalise ACPI calls into SNC functions Mattia Dongili
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

The goto target location would still try to free a buffer that was
never allocated.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index c6dc3f7..455beeb 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1349,8 +1349,8 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 
 	device_enum = (union acpi_object *) buffer.pointer;
 	if (!device_enum) {
-		pr_err("No SN06 return object\n");
-		goto out_no_enum;
+		pr_err("No SN06 return object.");
+		return;
 	}
 	if (device_enum->type != ACPI_TYPE_BUFFER) {
 		pr_err("Invalid SN06 return object 0x%.2x\n",
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 03/19] sony-laptop: generalise ACPI calls into SNC functions
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
  2012-05-19 13:35 ` [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw Mattia Dongili
  2012-05-19 13:35 ` [PATCH 02/19] sony-laptop: fix return path when no ACPI buffer is allocated Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 04/19] sony-laptop: use kstrtoul to parse sysfs values Mattia Dongili
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

All calls into the SNC device methods have zero or one arguments and
return an integer or a buffer (some functions go as far as returning an
integer _or_ a buffer depending on the input parameter...).
This allows simplifying a couple of code paths and prepares the field
for other users of functions returning buffers.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  275 +++++++++++++++++-------------------
 1 file changed, 133 insertions(+), 142 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 455beeb..6aefd35 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -691,59 +691,92 @@ static struct acpi_device *sony_nc_acpi_device = NULL;
 
 /*
  * acpi_evaluate_object wrappers
+ * all useful calls into SNC methods take one or zero parameters and return
+ * integers or arrays.
  */
-static int acpi_callgetfunc(acpi_handle handle, char *name, int *result)
+static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
+		u64 *value)
 {
-	struct acpi_buffer output;
-	union acpi_object out_obj;
+	union acpi_object *result = NULL;
+	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
 	acpi_status status;
 
-	output.length = sizeof(out_obj);
-	output.pointer = &out_obj;
+	if (value) {
+		struct acpi_object_list params;
+		union acpi_object in;
+		in.type = ACPI_TYPE_INTEGER;
+		in.integer.value = *value;
+		params.count = 1;
+		params.pointer = &in;
+		status = acpi_evaluate_object(handle, method, &params, &output);
+	} else
+		status = acpi_evaluate_object(handle, method, NULL, &output);
 
-	status = acpi_evaluate_object(handle, name, NULL, &output);
-	if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) {
-		*result = out_obj.integer.value;
-		return 0;
+	if (ACPI_FAILURE(status)) {
+		pr_err("Failed to evaluate [%s]\n", method);
+		return NULL;
 	}
 
-	pr_warn("acpi_callreadfunc failed\n");
+	result = (union acpi_object *) output.pointer;
+	if (!result)
+		dprintk("No return object [%s]\n", method);
 
-	return -1;
+	return result;
 }
 
-static int acpi_callsetfunc(acpi_handle handle, char *name, int value,
-			    int *result)
+static int sony_nc_int_call(acpi_handle handle, char *name, int *value,
+		int *result)
 {
-	struct acpi_object_list params;
-	union acpi_object in_obj;
-	struct acpi_buffer output;
-	union acpi_object out_obj;
-	acpi_status status;
-
-	params.count = 1;
-	params.pointer = &in_obj;
-	in_obj.type = ACPI_TYPE_INTEGER;
-	in_obj.integer.value = value;
+	union acpi_object *object = NULL;
+	if (value) {
+		u64 v = *value;
+		object = __call_snc_method(handle, name, &v);
+	} else
+		object = __call_snc_method(handle, name, NULL);
 
-	output.length = sizeof(out_obj);
-	output.pointer = &out_obj;
+	if (!object)
+		return -EINVAL;
 
-	status = acpi_evaluate_object(handle, name, &params, &output);
-	if (status == AE_OK) {
-		if (result != NULL) {
-			if (out_obj.type != ACPI_TYPE_INTEGER) {
-				pr_warn("acpi_evaluate_object bad return type\n");
-				return -1;
-			}
-			*result = out_obj.integer.value;
-		}
-		return 0;
+	if (object->type != ACPI_TYPE_INTEGER) {
+		pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
+				ACPI_TYPE_INTEGER, object->type);
+		kfree(object);
+		return -EINVAL;
 	}
 
-	pr_warn("acpi_evaluate_object failed\n");
+	if (result)
+		*result = object->integer.value;
 
-	return -1;
+	kfree(object);
+	return 0;
+}
+
+#define MIN(a, b)	(a > b ? b : a)
+static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
+		void *buffer, size_t buflen)
+{
+	size_t len = len;
+	union acpi_object *object = __call_snc_method(handle, name, value);
+
+	if (!object)
+		return -EINVAL;
+
+	if (object->type == ACPI_TYPE_BUFFER)
+		len = MIN(buflen, object->buffer.length);
+
+	else if (object->type == ACPI_TYPE_INTEGER)
+		len = MIN(buflen, sizeof(object->integer.value));
+
+	else {
+		pr_warn("Invalid acpi_object: expected 0x%x got 0x%x\n",
+				ACPI_TYPE_BUFFER, object->type);
+		kfree(object);
+		return -EINVAL;
+	}
+
+	memcpy(buffer, object->buffer.pointer, len);
+	kfree(object);
+	return 0;
 }
 
 struct sony_nc_handles {
@@ -770,16 +803,17 @@ static ssize_t sony_nc_handles_show(struct device *dev,
 
 static int sony_nc_handles_setup(struct platform_device *pd)
 {
-	int i;
-	int result;
+	int i, r, result, arg;
 
 	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)) {
+		arg = i + 0x20;
+		r = sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg,
+					&result);
+		if (!r) {
 			dprintk("caching handle 0x%.4x (offset: 0x%.2x)\n",
 					result, i);
 			handles->cap[i] = result;
@@ -835,16 +869,15 @@ static int sony_find_snc_handle(int handle)
 
 static int sony_call_snc_handle(int handle, int argument, int *result)
 {
-	int ret = 0;
+	int arg, ret = 0;
 	int offset = sony_find_snc_handle(handle);
 
 	if (offset < 0)
 		return -1;
 
-	ret = acpi_callsetfunc(sony_nc_acpi_handle, "SN07", offset | argument,
-			result);
-	dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", offset | argument,
-			*result);
+	arg = offset | argument;
+	ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
+	dprintk("called SN07 with 0x%.4x (result: 0x%.4x)\n", arg, *result);
 	return ret;
 }
 
@@ -889,14 +922,16 @@ static int boolean_validate(const int direction, const int value)
 static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr,
 			      char *buffer)
 {
-	int value;
+	int value, ret = 0;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
 
 	if (!*item->acpiget)
 		return -EIO;
 
-	if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0)
+	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiget, NULL,
+				&value);
+	if (ret < 0)
 		return -EIO;
 
 	if (item->validate)
@@ -909,7 +944,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
-	int value;
+	int value, ret = 0;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
 
@@ -927,8 +962,11 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 	if (value < 0)
 		return value;
 
-	if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0)
+	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, &value,
+			NULL);
+	if (ret < 0)
 		return -EIO;
+
 	item->value = value;
 	item->valid = 1;
 	return count;
@@ -948,15 +986,15 @@ struct sony_backlight_props sony_bl_props;
 
 static int sony_backlight_update_status(struct backlight_device *bd)
 {
-	return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
-				bd->props.brightness + 1, NULL);
+	int arg = bd->props.brightness + 1;
+	return sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &arg, NULL);
 }
 
 static int sony_backlight_get_brightness(struct backlight_device *bd)
 {
 	int value;
 
-	if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value))
+	if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL, &value))
 		return 0;
 	/* brightness levels are 1-based, while backlight ones are 0-based */
 	return value - 1;
@@ -1142,10 +1180,11 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
  */
 static int sony_nc_function_setup(struct acpi_device *device)
 {
-	int result;
+	int result, arg;
 
 	/* Enable all events */
-	acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0xffff, &result);
+	arg = 0xffff;
+	sony_nc_int_call(sony_nc_acpi_handle, "SN02", &arg, &result);
 
 	/* Setup hotkeys */
 	sony_call_snc_handle(0x0100, 0, &result);
@@ -1166,8 +1205,8 @@ static int sony_nc_resume(struct acpi_device *device)
 
 		if (!item->valid)
 			continue;
-		ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset,
-				       item->value, NULL);
+		ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
+				       &item->value, NULL);
 		if (ret < 0) {
 			pr_err("%s: %d\n", __func__, ret);
 			break;
@@ -1176,7 +1215,8 @@ static int sony_nc_resume(struct acpi_device *device)
 
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
 					 &handle))) {
-		if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
+		int arg = 1;
+		if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
 			dprintk("ECON Method failed\n");
 	}
 
@@ -1314,13 +1354,9 @@ static void sony_nc_rfkill_update(void)
 
 static void sony_nc_rfkill_setup(struct acpi_device *device)
 {
-	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 };
+	u64 offset;
+	int i;
+	unsigned char buffer[32] = { 0 };
 
 	offset = sony_find_snc_handle(0x124);
 	if (offset == -1) {
@@ -1333,59 +1369,34 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 		sony_rfkill_handle = 0x124;
 	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
-	 */
-	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");
+	i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
+			32);
+	if (i < 0)
 		return;
-	}
-
-	device_enum = (union acpi_object *) buffer.pointer;
-	if (!device_enum) {
-		pr_err("No SN06 return object.");
-		return;
-	}
-	if (device_enum->type != ACPI_TYPE_BUFFER) {
-		pr_err("Invalid SN06 return object 0x%.2x\n",
-		       device_enum->type);
-		goto out_no_enum;
-	}
 
 	/* the buffer is filled with magic numbers describing the devices
 	 * available, 0xff terminates the enumeration
 	 */
-	for (i = 0; i < device_enum->buffer.length; i++) {
+	for (i = 0; i < ARRAY_SIZE(buffer); i++) {
 
-		dev_code = *(device_enum->buffer.pointer + i);
-		if (dev_code == 0xff)
+		if (buffer[i] == 0xff)
 			break;
 
-		dprintk("Radio devices, looking at 0x%.2x\n", dev_code);
+		dprintk("Radio devices, looking at 0x%.2x\n", buffer[i]);
 
-		if (dev_code == 0 && !sony_rfkill_devices[SONY_WIFI])
+		if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
 			sony_nc_setup_rfkill(device, SONY_WIFI);
 
-		if (dev_code == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
+		if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
 			sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
 
-		if ((0xf0 & dev_code) == 0x20 &&
+		if ((0xf0 & buffer[i]) == 0x20 &&
 				!sony_rfkill_devices[SONY_WWAN])
 			sony_nc_setup_rfkill(device, SONY_WWAN);
 
-		if (dev_code == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
+		if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
 			sony_nc_setup_rfkill(device, SONY_WIMAX);
 	}
-
-out_no_enum:
-	kfree(buffer.pointer);
-	return;
 }
 
 /* Keyboard backlight feature */
@@ -1576,14 +1587,10 @@ static void sony_nc_kbd_backlight_resume(void)
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-	int offset;
-	acpi_status status;
-	u8 brlvl, i;
+	u64 offset;
+	int i;
 	u8 min = 0xff, max = 0x00;
-	struct acpi_object_list params;
-	union acpi_object in_obj;
-	union acpi_object *lvl_enum;
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	unsigned char buffer[32] = { 0 };
 
 	props->handle = handle;
 	props->offset = 0;
@@ -1596,50 +1603,31 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 	/* try to read the boundaries from ACPI tables, if we fail the above
 	 * defaults should be reasonable
 	 */
-	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))
-		return;
-
-	lvl_enum = (union acpi_object *) buffer.pointer;
-	if (!lvl_enum) {
-		pr_err("No SN06 return object.");
+	i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
+			32);
+	if (i < 0)
 		return;
-	}
-	if (lvl_enum->type != ACPI_TYPE_BUFFER) {
-		pr_err("Invalid SN06 return object 0x%.2x\n",
-		       lvl_enum->type);
-		goto out_invalid;
-	}
 
 	/* the buffer lists brightness levels available, brightness levels are
-	 * from 0 to 8 in the array, other values are used by ALS control.
+	 * from position 0 to 8 in the array, other values are used by ALS
+	 * control.
 	 */
-	for (i = 0; i < 9 && i < lvl_enum->buffer.length; i++) {
+	for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
 
-		brlvl = *(lvl_enum->buffer.pointer + i);
-		dprintk("Brightness level: %d\n", brlvl);
+		dprintk("Brightness level: %d\n", buffer[i]);
 
-		if (!brlvl)
+		if (!buffer[i])
 			break;
 
-		if (brlvl > max)
-			max = brlvl;
-		if (brlvl < min)
-			min = brlvl;
+		if (buffer[i] > max)
+			max = buffer[i];
+		if (buffer[i] < min)
+			min = buffer[i];
 	}
 	props->offset = min;
 	props->maxlvl = max;
 	dprintk("Brightness levels: min=%d max=%d\n", props->offset,
 			props->maxlvl);
-
-out_invalid:
-	kfree(buffer.pointer);
-	return;
 }
 
 static void sony_nc_backlight_setup(void)
@@ -1728,7 +1716,8 @@ static int sony_nc_add(struct acpi_device *device)
 
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
 					 &handle))) {
-		if (acpi_callsetfunc(sony_nc_acpi_handle, "ECON", 1, NULL))
+		int arg = 1;
+		if (sony_nc_int_call(sony_nc_acpi_handle, "ECON", &arg, NULL))
 			dprintk("ECON Method failed\n");
 	}
 
@@ -2684,7 +2673,8 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
 			ret = -EIO;
 			break;
 		}
-		if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) {
+		if (sony_nc_int_call(sony_nc_acpi_handle, "GBRT", NULL,
+					&value)) {
 			ret = -EIO;
 			break;
 		}
@@ -2701,8 +2691,9 @@ static long sonypi_misc_ioctl(struct file *fp, unsigned int cmd,
 			ret = -EFAULT;
 			break;
 		}
-		if (acpi_callsetfunc(sony_nc_acpi_handle, "SBRT",
-				(val8 >> 5) + 1, NULL)) {
+		value = (val8 >> 5) + 1;
+		if (sony_nc_int_call(sony_nc_acpi_handle, "SBRT", &value,
+					NULL)) {
 			ret = -EIO;
 			break;
 		}
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 04/19] sony-laptop: use kstrtoul to parse sysfs values
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (2 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 03/19] sony-laptop: generalise ACPI calls into SNC functions Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 05/19] sony-laptop: improve SNC initialization and acpi notify callback code Mattia Dongili
                   ` (14 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

This avoids surprises like echoing "enable" into a sysfs file and
finding that the feature was actually disabled.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   26 +++++++++++++++++---------
 1 file changed, 17 insertions(+), 9 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 6aefd35..d6c53c6 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -944,7 +944,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
-	int value, ret = 0;
+	unsigned long value = 0;
+	int ret = 0;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
 
@@ -954,7 +955,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	if (kstrtoul(buffer, 10, &value))
+		return -EINVAL;
 
 	if (item->validate)
 		value = item->validate(SNC_VALIDATE_IN, value);
@@ -962,8 +964,8 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 	if (value < 0)
 		return value;
 
-	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset, &value,
-			NULL);
+	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
+			(int *)&value, NULL);
 	if (ret < 0)
 		return -EIO;
 
@@ -1445,7 +1447,7 @@ static ssize_t sony_nc_kbd_backlight_mode_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	if (strict_strtoul(buffer, 10, &value))
+	if (kstrtoul(buffer, 10, &value))
 		return -EINVAL;
 
 	ret = __sony_nc_kbd_backlight_mode_set(value);
@@ -1489,7 +1491,7 @@ static ssize_t sony_nc_kbd_backlight_timeout_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	if (strict_strtoul(buffer, 10, &value))
+	if (kstrtoul(buffer, 10, &value))
 		return -EINVAL;
 
 	ret = __sony_nc_kbd_backlight_timeout_set(value);
@@ -2439,7 +2441,9 @@ static ssize_t sony_pic_wwanpower_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	if (kstrtoul(buffer, 10, &value))
+		return -EINVAL;
+
 	mutex_lock(&spic_dev.lock);
 	__sony_pic_set_wwanpower(value);
 	mutex_unlock(&spic_dev.lock);
@@ -2476,7 +2480,9 @@ static ssize_t sony_pic_bluetoothpower_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	if (kstrtoul(buffer, 10, &value))
+		return -EINVAL;
+
 	mutex_lock(&spic_dev.lock);
 	__sony_pic_set_bluetoothpower(value);
 	mutex_unlock(&spic_dev.lock);
@@ -2515,7 +2521,9 @@ static ssize_t sony_pic_fanspeed_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	value = simple_strtoul(buffer, NULL, 10);
+	if (kstrtoul(buffer, 10, &value))
+		return -EINVAL;
+
 	if (sony_pic_set_fanspeed(value))
 		return -EIO;
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 05/19] sony-laptop: improve SNC initialization and acpi notify callback code
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (3 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 04/19] sony-laptop: use kstrtoul to parse sysfs values Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 06/19] sony-laptop: additional debug statements Mattia Dongili
                   ` (13 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Loop through the list of SNC handles and run the proper initialization
function for each of the known handles. Also return void in function
where we are not checking the return value anyway.
For notifications we also know which handle is linked to the event and
the code becomes simpler to read with a switch rather than using
convoluted ifs.

[malattia@linux.it: Code reworked to merge the initialization code
improvements and the notify callback changes. Modified the code paths to
allow easier error exit paths.  Also fixed some missing break statements
and spelling mistakes.]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  319 ++++++++++++++++++++++++++----------
 1 file changed, 233 insertions(+), 86 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index d6c53c6..4420353 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -141,6 +141,8 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
 		 "(default: 0)");
 
 static void sony_nc_kbd_backlight_resume(void);
+static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
+static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
 
 enum sony_nc_rfkill {
 	SONY_WIFI,
@@ -153,6 +155,8 @@ enum sony_nc_rfkill {
 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_setup(struct acpi_device *device);
+static void sony_nc_rfkill_cleanup(void);
 static void sony_nc_rfkill_update(void);
 
 /*********** Input Devices ***********/
@@ -1103,63 +1107,116 @@ static struct sony_nc_event sony_127_events[] = {
 	{ 0, 0 },
 };
 
+static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
+{
+	int ret = -EINVAL;
+	unsigned int result = 0;
+	struct sony_nc_event *key_event;
+
+	if (sony_call_snc_handle(handle, 0x200, &result)) {
+		dprintk("Unable to decode event 0x%.2x 0x%.2x\n", handle,
+				event);
+		return -EINVAL;
+	}
+
+	result &= 0xFF;
+
+	if (handle == 0x0100)
+		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/0x%.2x (handle 0x%.2x)\n",
+				event, result, handle);
+
+	return ret;
+}
+
 /*
  * ACPI callbacks
  */
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
-	u32 ev = event;
+	u32 real_ev = event;
+	u8 ev_type = 0;
+	dprintk("sony_nc_notify, event: 0x%.2x\n", 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 (event >= 0x90) {
+		unsigned int result = 0;
+		unsigned int arg = 0;
+		unsigned int handle = 0;
+		unsigned int offset = event - 0x90;
 
-				if (!key_event->data)
-					pr_info("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();
+		if (offset >= ARRAY_SIZE(handles->cap)) {
+			pr_err("Event 0x%x outside of capabilities list\n",
+					event);
 			return;
 		}
-	} else
-		sony_laptop_report_input_event(ev);
+		handle = handles->cap[offset];
+
+		/* list of handles known for generating events */
+		switch (handle) {
+		/* hotkey event */
+		case 0x0100:
+		case 0x0127:
+			ev_type = 1;
+			real_ev = sony_nc_hotkeys_decode(event, handle);
+
+			if (real_ev > 0)
+				sony_laptop_report_input_event(real_ev);
+			else
+				/* restore the original event for reporting */
+				real_ev = event;
+
+			break;
+
+		/* wlan switch */
+		case 0x0124:
+		case 0x0135:
+			/* events on this handle are reported when the
+			 * switch changes position or for battery
+			 * events. We'll notify both of them but only
+			 * update the rfkill device status when the
+			 * switch is moved.
+			 */
+			ev_type = 2;
+			sony_call_snc_handle(handle, 0x0100, &result);
+			real_ev = result & 0x03;
+
+			/* hw switch event */
+			if (real_ev == 1)
+				sony_nc_rfkill_update();
+
+			break;
+
+		default:
+			dprintk("Unknown event 0x%x for handle 0x%x\n",
+					event, handle);
+			break;
+		}
 
-	dprintk("sony_nc_notify, event: 0x%.2x\n", ev);
-	acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);
+		/* clear the event (and the event reason when present) */
+		arg = 1 << offset;
+		sony_nc_int_call(sony_nc_acpi_handle, "SN05", &arg, &result);
+
+	} else {
+		/* old style event */
+		ev_type = 1;
+		sony_laptop_report_input_event(real_ev);
+	}
+
+	acpi_bus_generate_proc_event(sony_nc_acpi_device, ev_type, real_ev);
+
+	acpi_bus_generate_netlink_event(sony_nc_acpi_device->pnp.device_class,
+			dev_name(&sony_nc_acpi_device->dev), ev_type, real_ev);
 }
 
 static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
@@ -1180,21 +1237,126 @@ static acpi_status sony_walk_callback(acpi_handle handle, u32 level,
 /*
  * ACPI device
  */
-static int sony_nc_function_setup(struct acpi_device *device)
+static void sony_nc_function_setup(struct acpi_device *device,
+		struct platform_device *pf_device)
 {
-	int result, arg;
+	unsigned int i, result, bitmask, arg;
+
+	if (!handles)
+		return;
+
+	/* setup found handles here */
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+		unsigned int handle = handles->cap[i];
+
+		if (!handle)
+			continue;
+
+		dprintk("setting up handle 0x%.4x\n", handle);
+
+		switch (handle) {
+		case 0x0100:
+		case 0x0101:
+		case 0x0127:
+			/* setup hotkeys */
+			sony_call_snc_handle(handle, 0, &result);
+			break;
+		case 0x0102:
+			/* setup hotkeys */
+			sony_call_snc_handle(handle, 0x100, &result);
+			break;
+		case 0x0124:
+		case 0x0135:
+			sony_nc_rfkill_setup(device);
+			break;
+		case 0x0137:
+			sony_nc_kbd_backlight_setup(pf_device);
+			break;
+		default:
+			continue;
+		}
+	}
 
 	/* Enable all events */
-	arg = 0xffff;
-	sony_nc_int_call(sony_nc_acpi_handle, "SN02", &arg, &result);
+	arg = 0x10;
+	if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
+		sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
+				&result);
+}
+
+static void sony_nc_function_cleanup(struct platform_device *pd)
+{
+	unsigned int i, result, bitmask, handle;
 
-	/* 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);
+	/* get enabled events and disable them */
+	sony_nc_int_call(sony_nc_acpi_handle, "SN01", NULL, &bitmask);
+	sony_nc_int_call(sony_nc_acpi_handle, "SN03", &bitmask, &result);
 
-	return 0;
+	/* cleanup handles here */
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+
+		handle = handles->cap[i];
+
+		if (!handle)
+			continue;
+
+		switch (handle) {
+		case 0x0124:
+		case 0x0135:
+			sony_nc_rfkill_cleanup();
+			break;
+		case 0x0137:
+			sony_nc_kbd_backlight_cleanup(pd);
+			break;
+		default:
+			continue;
+		}
+	}
+
+	/* finally cleanup the handles list */
+	sony_nc_handles_cleanup(pd);
+}
+
+static void sony_nc_function_resume(void)
+{
+	unsigned int i, result, bitmask, arg;
+
+	dprintk("Resuming SNC device\n");
+
+	for (i = 0; i < ARRAY_SIZE(handles->cap); i++) {
+		unsigned int handle = handles->cap[i];
+
+		if (!handle)
+			continue;
+
+		switch (handle) {
+		case 0x0100:
+		case 0x0101:
+		case 0x0127:
+			/* re-enable hotkeys */
+			sony_call_snc_handle(handle, 0, &result);
+			break;
+		case 0x0102:
+			/* re-enable hotkeys */
+			sony_call_snc_handle(handle, 0x100, &result);
+			break;
+		case 0x0124:
+		case 0x0135:
+			sony_nc_rfkill_update();
+			break;
+		case 0x0137:
+			sony_nc_kbd_backlight_resume();
+			break;
+		default:
+			continue;
+		}
+	}
+
+	/* Enable all events */
+	arg = 0x10;
+	if (!sony_nc_int_call(sony_nc_acpi_handle, "SN00", &arg, &bitmask))
+		sony_nc_int_call(sony_nc_acpi_handle, "SN02", &bitmask,
+				&result);
 }
 
 static int sony_nc_resume(struct acpi_device *device)
@@ -1223,16 +1385,8 @@ static int sony_nc_resume(struct acpi_device *device)
 	}
 
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
-					 &handle))) {
-		dprintk("Doing SNC setup\n");
-		sony_nc_function_setup(device);
-	}
-
-	/* re-read rfkill state */
-	sony_nc_rfkill_update();
-
-	/* restore kbd backlight states */
-	sony_nc_kbd_backlight_resume();
+					 &handle)))
+		sony_nc_function_resume();
 
 	return 0;
 }
@@ -1509,18 +1663,18 @@ static ssize_t sony_nc_kbd_backlight_timeout_show(struct device *dev,
 	return count;
 }
 
-static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
+static void sony_nc_kbd_backlight_setup(struct platform_device *pd)
 {
 	int result;
 
 	if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
-		return 0;
+		return;
 	if (!(result & 0x02))
-		return 0;
+		return;
 
 	kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
 	if (!kbdbl_handle)
-		return -ENOMEM;
+		return;
 
 	sysfs_attr_init(&kbdbl_handle->mode_attr.attr);
 	kbdbl_handle->mode_attr.attr.name = "kbd_backlight";
@@ -1543,14 +1697,14 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd)
 	__sony_nc_kbd_backlight_mode_set(kbd_backlight);
 	__sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
 
-	return 0;
+	return;
 
 outmode:
 	device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
 outkzalloc:
 	kfree(kbdbl_handle);
 	kbdbl_handle = NULL;
-	return -1;
+	return;
 }
 
 static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
@@ -1726,21 +1880,17 @@ static int sony_nc_add(struct acpi_device *device)
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "SN00",
 					 &handle))) {
 		dprintk("Doing SNC setup\n");
+		/* retrieve the available handles */
 		result = sony_nc_handles_setup(sony_pf_device);
-		if (result)
-			goto outpresent;
-		result = sony_nc_kbd_backlight_setup(sony_pf_device);
-		if (result)
-			goto outsnc;
-		sony_nc_function_setup(device);
-		sony_nc_rfkill_setup(device);
+		if (!result)
+			sony_nc_function_setup(device, sony_pf_device);
 	}
 
 	/* setup input devices and helper fifo */
 	result = sony_laptop_setup_input(device);
 	if (result) {
 		pr_err("Unable to create input devices\n");
-		goto outkbdbacklight;
+		goto outsnc;
 	}
 
 	if (acpi_video_backlight_support()) {
@@ -1798,10 +1948,8 @@ 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_function_cleanup(sony_pf_device);
 	sony_nc_handles_cleanup(sony_pf_device);
 
       outpresent:
@@ -1824,11 +1972,10 @@ 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_function_cleanup(sony_pf_device);
 	sony_nc_handles_cleanup(sony_pf_device);
 	sony_pf_remove();
 	sony_laptop_remove_input();
-	sony_nc_rfkill_cleanup();
 	dprintk(SONY_NC_DRIVER_NAME " removed.\n");
 
 	return 0;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 06/19] sony-laptop: additional debug statements
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (4 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 05/19] sony-laptop: improve SNC initialization and acpi notify callback code Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 07/19] sony-laptop: support battery care functions Mattia Dongili
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 4420353..89e5cf9 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -713,8 +713,13 @@ static union acpi_object *__call_snc_method(acpi_handle handle, char *method,
 		params.count = 1;
 		params.pointer = &in;
 		status = acpi_evaluate_object(handle, method, &params, &output);
-	} else
+		dprintk("__call_snc_method: [%s:0x%.8x%.8x]\n", method,
+				(unsigned int)(*value >> 32),
+				(unsigned int)*value & 0xffffffff);
+	} else {
 		status = acpi_evaluate_object(handle, method, NULL, &output);
+		dprintk("__call_snc_method: [%s]\n", method);
+	}
 
 	if (ACPI_FAILURE(status)) {
 		pr_err("Failed to evaluate [%s]\n", method);
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 07/19] sony-laptop: support battery care functions
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (5 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 06/19] sony-laptop: additional debug statements Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-31 18:20   ` Matthew Garrett
  2012-05-19 13:35 ` [PATCH 08/19] sony-laptop: add thermal profiles support Mattia Dongili
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Allows limiting the maximum battery charge level to a selectable value
(100%, 80% and 50%).

[malattia@linux.it: group function specific variables in a struct, use
kstrtoul. Allow 0 to 100 values into sysfs files rounding to the actual
limit.]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  178 ++++++++++++++++++++++++++++++++++++
 1 file changed, 178 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 89e5cf9..0ac186e9 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -144,6 +144,10 @@ static void sony_nc_kbd_backlight_resume(void);
 static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
 static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
 
+static int sony_nc_battery_care_setup(struct platform_device *pd,
+		unsigned int handle);
+static void sony_nc_battery_care_cleanup(struct platform_device *pd);
+
 enum sony_nc_rfkill {
 	SONY_WIFI,
 	SONY_BLUETOOTH,
@@ -1270,6 +1274,14 @@ static void sony_nc_function_setup(struct acpi_device *device,
 			/* setup hotkeys */
 			sony_call_snc_handle(handle, 0x100, &result);
 			break;
+		case 0x0115:
+		case 0x0136:
+		case 0x013f:
+			result = sony_nc_battery_care_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up battery care function (%d)\n",
+						result);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_setup(device);
@@ -1306,6 +1318,11 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 			continue;
 
 		switch (handle) {
+		case 0x0115:
+		case 0x0136:
+		case 0x013f:
+			sony_nc_battery_care_cleanup(pd);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_cleanup();
@@ -1745,6 +1762,167 @@ static void sony_nc_kbd_backlight_resume(void)
 				&ignore);
 }
 
+struct battery_care_control {
+	struct device_attribute attrs[2];
+	unsigned int handle;
+};
+static struct battery_care_control *bcare_ctl;
+
+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 (kstrtoul(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
+	 */
+	if (value == 0)
+		/* disable limits */
+		cmd = 0x0;
+
+	else if (value <= 50)
+		cmd = 0x21;
+
+	else if (value <= 80)
+		cmd = 0x11;
+
+	else if (value <= 100)
+		cmd = 0x31;
+
+	else
+		return -EINVAL;
+
+	if (sony_call_snc_handle(bcare_ctl->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)
+{
+	unsigned int result, status;
+
+	if (sony_call_snc_handle(bcare_ctl->handle, 0x0000, &result))
+		return -EIO;
+
+	status = (result & 0x01) ? ((result & 0x30) >> 0x04) : 0;
+	switch (status) {
+	case 1:
+		status = 80;
+		break;
+	case 2:
+		status = 50;
+		break;
+	case 3:
+		status = 100;
+		break;
+	default:
+		status = 0;
+		break;
+	}
+
+	return snprintf(buffer, PAGE_SIZE, "%d\n", status);
+}
+
+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(bcare_ctl->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,
+		unsigned int handle)
+{
+	int ret = 0;
+
+	bcare_ctl = kzalloc(sizeof(struct battery_care_control), GFP_KERNEL);
+	if (!bcare_ctl)
+		return -ENOMEM;
+
+	bcare_ctl->handle = handle;
+
+	sysfs_attr_init(&bcare_ctl->attrs[0].attr);
+	bcare_ctl->attrs[0].attr.name = "battery_care_limiter";
+	bcare_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	bcare_ctl->attrs[0].show = sony_nc_battery_care_limit_show;
+	bcare_ctl->attrs[0].store = sony_nc_battery_care_limit_store;
+
+	ret = device_create_file(&pd->dev, &bcare_ctl->attrs[0]);
+	if (ret)
+		goto outkzalloc;
+
+	/* 0x0115 is for models with no health reporting capability */
+	if (handle == 0x0115)
+		return 0;
+
+	sysfs_attr_init(&bcare_ctl->attrs[1].attr);
+	bcare_ctl->attrs[1].attr.name = "battery_care_health";
+	bcare_ctl->attrs[1].attr.mode = S_IRUGO;
+	bcare_ctl->attrs[1].show = sony_nc_battery_care_health_show;
+
+	ret = device_create_file(&pd->dev, &bcare_ctl->attrs[1]);
+	if (ret)
+		goto outlimiter;
+
+	return 0;
+
+outlimiter:
+	device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
+
+outkzalloc:
+	kfree(bcare_ctl);
+	bcare_ctl = NULL;
+
+	return ret;
+}
+
+static void sony_nc_battery_care_cleanup(struct platform_device *pd)
+{
+	if (bcare_ctl) {
+		device_remove_file(&pd->dev, &bcare_ctl->attrs[0]);
+		if (bcare_ctl->handle != 0x0115)
+			device_remove_file(&pd->dev, &bcare_ctl->attrs[1]);
+
+		kfree(bcare_ctl);
+		bcare_ctl = NULL;
+	}
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 08/19] sony-laptop: add thermal profiles support
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (6 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 07/19] sony-laptop: support battery care functions Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 09/19] sony-laptop: adjust error handling in finding SNC handles Mattia Dongili
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

[malattia@linux.it: support string based profiles names]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  183 ++++++++++++++++++++++++++++++++++++
 1 file changed, 183 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 0ac186e9..c3f54ad 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -148,6 +148,10 @@ static int sony_nc_battery_care_setup(struct platform_device *pd,
 		unsigned int handle);
 static void sony_nc_battery_care_cleanup(struct platform_device *pd);
 
+static int sony_nc_thermal_setup(struct platform_device *pd);
+static void sony_nc_thermal_cleanup(struct platform_device *pd);
+static void sony_nc_thermal_resume(void);
+
 enum sony_nc_rfkill {
 	SONY_WIFI,
 	SONY_BLUETOOTH,
@@ -1282,6 +1286,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
 				pr_err("couldn't set up battery care function (%d)\n",
 						result);
 			break;
+		case 0x0122:
+			result = sony_nc_thermal_setup(pf_device);
+			if (result)
+				pr_err("couldn't set up thermal profile function (%d)\n",
+						result);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_setup(device);
@@ -1323,6 +1333,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x013f:
 			sony_nc_battery_care_cleanup(pd);
 			break;
+		case 0x0122:
+			sony_nc_thermal_cleanup(pd);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_cleanup();
@@ -1362,6 +1375,9 @@ static void sony_nc_function_resume(void)
 			/* re-enable hotkeys */
 			sony_call_snc_handle(handle, 0x100, &result);
 			break;
+		case 0x0122:
+			sony_nc_thermal_resume();
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_update();
@@ -1923,6 +1939,173 @@ static void sony_nc_battery_care_cleanup(struct platform_device *pd)
 	}
 }
 
+struct snc_thermal_ctrl {
+	unsigned int mode;
+	unsigned int profiles;
+	struct device_attribute mode_attr;
+	struct device_attribute profiles_attr;
+};
+static struct snc_thermal_ctrl *th_handle;
+
+#define THM_PROFILE_MAX 3
+static const char * const snc_thermal_profiles[] = {
+	"balanced",
+	"silent",
+	"performance"
+};
+
+static int sony_nc_thermal_mode_set(unsigned short mode)
+{
+	unsigned int result;
+
+	/* the thermal profile seems to be a two bit bitmask:
+	 * lsb -> silent
+	 * msb -> performance
+	 * no bit set is the normal operation and is always valid
+	 * Some vaio models only have "balanced" and "performance"
+	 */
+	if ((mode && !(th_handle->profiles & mode)) || mode >= THM_PROFILE_MAX)
+		return -EINVAL;
+
+	if (sony_call_snc_handle(0x0122, mode << 0x10 | 0x0200, &result))
+		return -EIO;
+
+	th_handle->mode = mode;
+
+	return 0;
+}
+
+static int sony_nc_thermal_mode_get(void)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0122, 0x0100, &result))
+		return -EIO;
+
+	return result & 0xff;
+}
+
+static ssize_t sony_nc_thermal_profiles_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	short cnt;
+	size_t idx = 0;
+
+	for (cnt = 0; cnt < THM_PROFILE_MAX; cnt++) {
+		if (!cnt || (th_handle->profiles & cnt))
+			idx += snprintf(buffer + idx, PAGE_SIZE - idx, "%s ",
+					snc_thermal_profiles[cnt]);
+	}
+	idx += snprintf(buffer + idx, PAGE_SIZE - idx, "\n");
+
+	return idx;
+}
+
+static ssize_t sony_nc_thermal_mode_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned short cmd;
+	size_t len = count;
+
+	if (count == 0)
+		return -EINVAL;
+
+	/* skip the newline if present */
+	if (buffer[len - 1] == '\n')
+		len--;
+
+	for (cmd = 0; cmd < THM_PROFILE_MAX; cmd++)
+		if (strncmp(buffer, snc_thermal_profiles[cmd], len) == 0)
+			break;
+
+	if (sony_nc_thermal_mode_set(cmd))
+		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 mode = sony_nc_thermal_mode_get();
+
+	if (mode < 0)
+		return mode;
+
+	count = snprintf(buffer, PAGE_SIZE, "%s\n", snc_thermal_profiles[mode]);
+
+	return count;
+}
+
+static int sony_nc_thermal_setup(struct platform_device *pd)
+{
+	int ret = 0;
+	th_handle = kzalloc(sizeof(struct snc_thermal_ctrl), GFP_KERNEL);
+	if (!th_handle)
+		return -ENOMEM;
+
+	ret = sony_call_snc_handle(0x0122, 0x0000, &th_handle->profiles);
+	if (ret) {
+		pr_warn("couldn't to read the thermal profiles\n");
+		goto outkzalloc;
+	}
+
+	ret = sony_nc_thermal_mode_get();
+	if (ret < 0) {
+		pr_warn("couldn't to read the current thermal profile");
+		goto outkzalloc;
+	}
+	th_handle->mode = ret;
+
+	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;
+
+	ret = device_create_file(&pd->dev, &th_handle->profiles_attr);
+	if (ret)
+		goto outkzalloc;
+
+	ret = device_create_file(&pd->dev, &th_handle->mode_attr);
+	if (ret)
+		goto outprofiles;
+
+	return 0;
+
+outprofiles:
+	device_remove_file(&pd->dev, &th_handle->profiles_attr);
+outkzalloc:
+	kfree(th_handle);
+	th_handle = NULL;
+	return ret;
+}
+
+static void 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;
+	}
+}
+
+static void sony_nc_thermal_resume(void)
+{
+	unsigned int status = sony_nc_thermal_mode_get();
+
+	if (status != th_handle->mode)
+		sony_nc_thermal_mode_set(th_handle->mode);
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 09/19] sony-laptop: adjust error handling in finding SNC handles
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (7 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 08/19] sony-laptop: add thermal profiles support Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 10/19] sony-laptop: g-shock HD protection function Mattia Dongili
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

All handles must be greater than 0, also return more meaningful error
codes on invalid conditions.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index c3f54ad..2b72e47 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -870,8 +870,8 @@ static int sony_find_snc_handle(int handle)
 	int i;
 
 	/* not initialized yet, return early */
-	if (!handles)
-		return -1;
+	if (!handles || !handle)
+		return -EINVAL;
 
 	for (i = 0; i < 0x10; i++) {
 		if (handles->cap[i] == handle) {
@@ -881,7 +881,7 @@ static int sony_find_snc_handle(int handle)
 		}
 	}
 	dprintk("handle 0x%.4x not found\n", handle);
-	return -1;
+	return -EINVAL;
 }
 
 static int sony_call_snc_handle(int handle, int argument, int *result)
@@ -890,7 +890,7 @@ static int sony_call_snc_handle(int handle, int argument, int *result)
 	int offset = sony_find_snc_handle(handle);
 
 	if (offset < 0)
-		return -1;
+		return offset;
 
 	arg = offset | argument;
 	ret = sony_nc_int_call(sony_nc_acpi_handle, "SN07", &arg, result);
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 10/19] sony-laptop: g-shock HD protection function
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (8 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 09/19] sony-laptop: adjust error handling in finding SNC handles Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 11/19] sony-laptop: support automatic resume on lid open Mattia Dongili
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Vaio S models can unload the HDD heads by means of the SATA power
connector and an accelerometer, using the Embedded Controller.
Some models only provide notifications, others also allow reading of
component vectors of the applied force.

[malattia@linux.it: simplify error handling, set proper return error
codes and fit the general coding style of the sony-laptop driver. Also
make the sysfs interface accept descriptive strings rather than numbers
to signify the value type to be output as the vector components and
added a sysfs file to enumerate the acceptable values. Unloading the
driver also disables the function completely rather than just disabling
notifications.]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  376 ++++++++++++++++++++++++++++++++++++
 1 file changed, 376 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2b72e47..99ce7b6 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -152,6 +152,17 @@ static int sony_nc_thermal_setup(struct platform_device *pd);
 static void sony_nc_thermal_cleanup(struct platform_device *pd);
 static void sony_nc_thermal_resume(void);
 
+struct gsensor_control {
+	int handle;
+	unsigned int attrs_num;
+	bool supports_unloading;
+	struct device_attribute *attrs;
+};
+static struct gsensor_control *gs_ctl;
+static int sony_nc_gsensor_setup(struct platform_device *pd,
+		unsigned int handle);
+static void sony_nc_gsensor_cleanup(struct platform_device *pd);
+
 enum sony_nc_rfkill {
 	SONY_WIFI,
 	SONY_BLUETOOTH,
@@ -1210,6 +1221,12 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 			break;
 
+		/* hdd protection event */
+		case 0x0134:
+		case 0x0147:
+			ev_type = 3;
+			break;
+
 		default:
 			dprintk("Unknown event 0x%x for handle 0x%x\n",
 					event, handle);
@@ -1292,6 +1309,13 @@ static void sony_nc_function_setup(struct acpi_device *device,
 				pr_err("couldn't set up thermal profile function (%d)\n",
 						result);
 			break;
+		case 0x0134:
+		case 0x0147:
+			result = sony_nc_gsensor_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up g-shock protection function (%d)\n",
+						result);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_setup(device);
@@ -1336,6 +1360,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x0122:
 			sony_nc_thermal_cleanup(pd);
 			break;
+		case 0x0134:
+		case 0x0147:
+			sony_nc_gsensor_cleanup(pd);
+			break;
 		case 0x0124:
 		case 0x0135:
 			sony_nc_rfkill_cleanup();
@@ -2106,6 +2134,354 @@ static void sony_nc_thermal_resume(void)
 		sony_nc_thermal_mode_set(th_handle->mode);
 }
 
+/* GSensor, HDD Shock Protection */
+static int __sony_nc_gsensor_status_set(int enable)
+{
+	unsigned int result, reg, arg;
+
+	/* enable or disable shock notifications */
+	reg = gs_ctl->handle == 0x0134 ? (!enable << 0x08) : (enable << 0x10);
+	if (sony_call_snc_handle(gs_ctl->handle, reg, &result))
+		return -EIO;
+
+	if (!gs_ctl->supports_unloading) {
+		dprintk("g-shock automatic protection not available\n");
+		return 0;
+	}
+
+	/* enable or disable shock protection */
+	reg = gs_ctl->handle == 0x0134 ? 0x0200 : 0x0400;
+	if (sony_call_snc_handle(gs_ctl->handle, reg, &result))
+		return -EIO;
+
+	if (gs_ctl->handle == 0x0134) {
+		/* already set to what we want */
+		if (!!(result & 0x04) == enable)
+			return 0;
+		arg = (result & 0x1B) | (enable << 0x02);
+	} else {
+		/* already set to what we want */
+		if ((result & 0x01) == enable)
+			return 0;
+		arg = enable;
+	}
+
+	if (sony_call_snc_handle(gs_ctl->handle,
+			(arg << 0x10) | 0x0300, &result))
+		return -EIO;
+
+	return 0;
+}
+
+/*
+ * G sensor sys interface
+ */
+static ssize_t sony_nc_gsensor_types_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	return snprintf(buffer, PAGE_SIZE, "raw accel threshold");
+}
+
+static ssize_t sony_nc_gsensor_type_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(gs_ctl->handle, 0x0200, &result))
+		return -EIO;
+	switch (result & 0x18) {
+	case 0x00:
+		return snprintf(buffer, PAGE_SIZE, "raw\n");
+	case 0x08:
+		return snprintf(buffer, PAGE_SIZE, "accel\n");
+	case 0x10:
+		return snprintf(buffer, PAGE_SIZE, "threshold\n");
+	}
+	return -EINVAL;
+}
+
+static ssize_t sony_nc_gsensor_type_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	/* Value types:
+	 * 0x00: raw values
+	 * 0x08: accel values
+	 * 0x10: threshold values
+	 */
+	unsigned int result;
+	unsigned long value;
+	size_t len = count;
+
+	/* skip the newline if present */
+	if (buffer[len - 1] == '\n')
+		len--;
+
+	if (strncmp(buffer, "raw", len) == 0)
+		value = 0x00;
+	else if (strncmp(buffer, "accel", len) == 0)
+		value = 0x08;
+	else if (strncmp(buffer, "threshold", len) == 0)
+		value = 0x10;
+	else
+		return -EINVAL;
+
+	/* retrieve the current state / settings */
+	if (sony_call_snc_handle(gs_ctl->handle, 0x0200, &result))
+		return -EIO;
+
+	/* do nothing if already set to the requested value */
+	if ((result & 0x18) != value)
+		return count;
+
+	/* the last 3 bits need to be preserved */
+	value |= (result & 0x07);
+
+	if (sony_call_snc_handle(gs_ctl->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 axis, result;
+
+	/* file being read for axis selection */
+	if (strcmp(attr->attr.name, "gsensor_x_axis") == 0)
+		/* X frontal */
+		axis = 0x400;
+	else if (strcmp(attr->attr.name, "gsensor_y_axis") == 0)
+		/* Y lateral */
+		axis = 0x500;
+	else if (strcmp(attr->attr.name, "gsensor_z_axis") == 0)
+		/* Z vertical */
+		axis = 0x600;
+	else
+		return -EINVAL;
+
+	if (sony_call_snc_handle(gs_ctl->handle, axis, &result))
+		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 (gs_ctl->handle == 0x0134) {
+		if (sony_call_snc_handle(gs_ctl->handle, 0x0200,
+					&result))
+			return -EIO;
+
+		result = !!(result & 0x04);
+	} else {
+		if (sony_call_snc_handle(gs_ctl->handle, 0x0400,
+					&result))
+			return -EIO;
+
+		result &= 0x01;
+	}
+
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", result);
+
+	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 (kstrtoul(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(gs_ctl->handle, 0x0200, &result))
+		return -EIO;
+
+	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 (kstrtoul(buffer, 10, &value) || value > 2)
+		return -EINVAL;
+
+	/* retrieve the other parameters to be stored as well */
+	if (sony_call_snc_handle(gs_ctl->handle, 0x0200, &result))
+		return -EIO;
+
+	/* preserve only the needed bits */
+	value |= (result & 0x1C);
+
+	if (sony_call_snc_handle(gs_ctl->handle, (value << 0x10) | 0x0300,
+				&result))
+		return -EIO;
+
+	return count;
+}
+
+static int sony_nc_gsensor_setup(struct platform_device *pd,
+		unsigned int handle)
+{
+	int i, result;
+
+	gs_ctl = kzalloc(sizeof(struct gsensor_control), GFP_KERNEL);
+	if (!gs_ctl)
+		return -ENOMEM;
+
+	gs_ctl->handle = handle;
+
+	/* Check support for unloading heads.
+	 * 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 and in this case no automatic protection is
+	 * available.
+	 */
+	if (sony_call_snc_handle(handle, 0x0200, &result))
+		return -EIO;
+
+	if (handle == 0x0134)
+		gs_ctl->supports_unloading = !!(result & 0x20);
+	else
+		gs_ctl->supports_unloading = !!(result & 0x01);
+
+	/* handle 0x0134 has support for tuning sensitivity and reading force
+	 * vector components: we need more sysfs attributes for that one.
+	 */
+	gs_ctl->attrs_num = handle == 0x0134 ? 7 : 1;
+	gs_ctl->attrs = kzalloc(sizeof(struct device_attribute)
+				* gs_ctl->attrs_num, GFP_KERNEL);
+	if (!gs_ctl->attrs) {
+		result = -ENOMEM;
+		goto outnomem;
+	}
+
+	/* enable the HDD protection and notification by default */
+	result = __sony_nc_gsensor_status_set(1);
+	if (result) {
+		pr_warn("failed to enable the HDD shock protection\n");
+		goto outenable;
+	}
+
+	/* activation control	*/
+	sysfs_attr_init(&gs_ctl->attrs[0].attr);
+	gs_ctl->attrs[0].attr.name = "gsensor_protection";
+	gs_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	gs_ctl->attrs[0].show = sony_nc_gsensor_status_show;
+	gs_ctl->attrs[0].store = sony_nc_gsensor_status_store;
+
+	if (gs_ctl->attrs_num > 1) {
+		/* sensitivity selection */
+		sysfs_attr_init(&gs_ctl->attrs[1].attr);
+		gs_ctl->attrs[1].attr.name = "gsensor_sensitivity";
+		gs_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
+		gs_ctl->attrs[1].show = sony_nc_gsensor_sensitivity_show;
+		gs_ctl->attrs[1].store = sony_nc_gsensor_sensitivity_store;
+		/* x/y/z output selection */
+		sysfs_attr_init(&gs_ctl->attrs[2].attr);
+		gs_ctl->attrs[2].attr.name = "gsensor_value_types";
+		gs_ctl->attrs[2].attr.mode = S_IRUGO;
+		gs_ctl->attrs[2].show = sony_nc_gsensor_types_show;
+
+		/* x/y/z output selection */
+		sysfs_attr_init(&gs_ctl->attrs[3].attr);
+		gs_ctl->attrs[3].attr.name = "gsensor_value_type";
+		gs_ctl->attrs[3].attr.mode = S_IRUGO | S_IWUSR;
+		gs_ctl->attrs[3].show = sony_nc_gsensor_type_show;
+		gs_ctl->attrs[3].store = sony_nc_gsensor_type_store;
+
+		sysfs_attr_init(&gs_ctl->attrs[3].attr);
+		gs_ctl->attrs[4].attr.name = "gsensor_x_axis";
+		gs_ctl->attrs[4].attr.mode = S_IRUGO;
+		gs_ctl->attrs[4].show = sony_nc_gsensor_axis_show;
+
+		sysfs_attr_init(&gs_ctl->attrs[4].attr);
+		gs_ctl->attrs[5].attr.name = "gsensor_y_axis";
+		gs_ctl->attrs[5].attr.mode = S_IRUGO;
+		gs_ctl->attrs[5].show = sony_nc_gsensor_axis_show;
+
+		sysfs_attr_init(&gs_ctl->attrs[5].attr);
+		gs_ctl->attrs[6].attr.name = "gsensor_z_axis";
+		gs_ctl->attrs[6].attr.mode = S_IRUGO;
+		gs_ctl->attrs[6].show = sony_nc_gsensor_axis_show;
+	}
+
+	for (i = 0; i < gs_ctl->attrs_num; i++) {
+		result = device_create_file(&pd->dev, &gs_ctl->attrs[i]);
+		if (result)
+			goto attrserror;
+	}
+
+	return 0;
+
+attrserror:
+	/* disable g-shock on the error path out */
+	__sony_nc_gsensor_status_set(0);
+
+	for (; i > 0; i--)
+		device_remove_file(&pd->dev, &gs_ctl->attrs[i]);
+
+outenable:
+	kfree(gs_ctl->attrs);
+
+outnomem:
+	kfree(gs_ctl);
+	gs_ctl = NULL;
+
+	return result;
+}
+
+static void sony_nc_gsensor_cleanup(struct platform_device *pd)
+{
+	if (gs_ctl) {
+		unsigned int i;
+
+		for (i = 0; i < gs_ctl->attrs_num; i++)
+			device_remove_file(&pd->dev, &gs_ctl->attrs[i]);
+
+		__sony_nc_gsensor_status_set(0);
+
+		kfree(gs_ctl->attrs);
+		kfree(gs_ctl);
+		gs_ctl = NULL;
+	}
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 11/19] sony-laptop: support automatic resume on lid open
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (9 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 10/19] sony-laptop: g-shock HD protection function Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 12/19] sony-laptop: add high speed battery charging function Mattia Dongili
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

A few models offer the chance to set whether to resume from S3 and/or S4
when opening the lid.

[malattia@linux.it: create three sysfs files for S3/4/5 rather than
using a single one accepting a bitmask. Support S5 since the DSDT
exports it. Use a struct to hold all the related values, caching of the
current status value rather than re-reading all the time in the sysfs
show function.]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  141 ++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 99ce7b6..4a4ecfa 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -152,6 +152,9 @@ static int sony_nc_thermal_setup(struct platform_device *pd);
 static void sony_nc_thermal_cleanup(struct platform_device *pd);
 static void sony_nc_thermal_resume(void);
 
+static int sony_nc_lid_resume_setup(struct platform_device *pd);
+static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
+
 struct gsensor_control {
 	int handle;
 	unsigned int attrs_num;
@@ -1303,6 +1306,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
 				pr_err("couldn't set up battery care function (%d)\n",
 						result);
 			break;
+		case 0x0119:
+			result = sony_nc_lid_resume_setup(pf_device);
+			if (result)
+				pr_err("couldn't set up lid resume function (%d)\n",
+						result);
+			break;
 		case 0x0122:
 			result = sony_nc_thermal_setup(pf_device);
 			if (result)
@@ -1357,6 +1366,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x013f:
 			sony_nc_battery_care_cleanup(pd);
 			break;
+		case 0x0119:
+			sony_nc_lid_resume_cleanup(pd);
+			break;
 		case 0x0122:
 			sony_nc_thermal_cleanup(pd);
 			break;
@@ -2482,6 +2494,135 @@ static void sony_nc_gsensor_cleanup(struct platform_device *pd)
 	}
 }
 
+/* resume on LID open */
+struct snc_lid_resume_control {
+	struct device_attribute attrs[3];
+	unsigned int status;
+};
+static struct snc_lid_resume_control *lid_ctl;
+
+static ssize_t sony_nc_lid_resume_store(struct device *dev,
+		struct device_attribute *attr,
+		const char *buffer, size_t count)
+{
+	unsigned int result, pos;
+	unsigned long value;
+
+	if (count > 31)
+		return -EINVAL;
+
+	if (kstrtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	/* the value we have to write to SNC is a bitmask:
+	 * +--------------+
+	 * | S3 | S4 | S5 |
+	 * +--------------+
+	 *   2    1    0
+	 */
+	if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
+		pos = 2;
+	else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
+		pos = 1;
+	else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
+		pos = 0;
+	else
+		return -EINVAL;
+
+	if (value)
+		value = lid_ctl->status | (1 << pos);
+	else
+		value = lid_ctl->status & ~(1 << pos);
+
+	if (sony_call_snc_handle(0x0119, value << 0x10 | 0x0100, &result))
+		return -EIO;
+
+	lid_ctl->status = value;
+
+	return count;
+}
+
+static ssize_t sony_nc_lid_resume_show(struct device *dev,
+		struct device_attribute *attr, char *buffer)
+{
+	unsigned int pos;
+
+	if (strcmp(attr->attr.name, "lid_resume_S3") == 0)
+		pos = 2;
+	else if (strcmp(attr->attr.name, "lid_resume_S4") == 0)
+		pos = 1;
+	else if (strcmp(attr->attr.name, "lid_resume_S5") == 0)
+		pos = 0;
+	else
+		return -EINVAL;
+
+	return snprintf(buffer, PAGE_SIZE, "%d\n",
+			(lid_ctl->status >> pos) & 0x01);
+}
+
+static int sony_nc_lid_resume_setup(struct platform_device *pd)
+{
+	unsigned int result;
+	int i;
+
+	if (sony_call_snc_handle(0x0119, 0x0000, &result))
+		return -EIO;
+
+	lid_ctl = kzalloc(sizeof(struct snc_lid_resume_control), GFP_KERNEL);
+	if (!lid_ctl)
+		return -ENOMEM;
+
+	lid_ctl->status = result & 0x7;
+
+	sysfs_attr_init(&lid_ctl->attrs[0].attr);
+	lid_ctl->attrs[0].attr.name = "lid_resume_S3";
+	lid_ctl->attrs[0].attr.mode = S_IRUGO | S_IWUSR;
+	lid_ctl->attrs[0].show = sony_nc_lid_resume_show;
+	lid_ctl->attrs[0].store = sony_nc_lid_resume_store;
+
+	sysfs_attr_init(&lid_ctl->attrs[1].attr);
+	lid_ctl->attrs[1].attr.name = "lid_resume_S4";
+	lid_ctl->attrs[1].attr.mode = S_IRUGO | S_IWUSR;
+	lid_ctl->attrs[1].show = sony_nc_lid_resume_show;
+	lid_ctl->attrs[1].store = sony_nc_lid_resume_store;
+
+	sysfs_attr_init(&lid_ctl->attrs[2].attr);
+	lid_ctl->attrs[2].attr.name = "lid_resume_S5";
+	lid_ctl->attrs[2].attr.mode = S_IRUGO | S_IWUSR;
+	lid_ctl->attrs[2].show = sony_nc_lid_resume_show;
+	lid_ctl->attrs[2].store = sony_nc_lid_resume_store;
+
+	for (i = 0; i < 3; i++) {
+		result = device_create_file(&pd->dev, &lid_ctl->attrs[i]);
+		if (result)
+			goto liderror;
+	}
+
+	return 0;
+
+liderror:
+	for (; i > 0; i--)
+		device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
+
+	kfree(lid_ctl);
+	lid_ctl = NULL;
+
+	return result;
+}
+
+static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
+{
+	int i;
+
+	if (lid_ctl) {
+		for (i = 0; i < 3; i++)
+			device_remove_file(&pd->dev, &lid_ctl->attrs[i]);
+
+		kfree(lid_ctl);
+		lid_ctl = NULL;
+	}
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 12/19] sony-laptop: add high speed battery charging function
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (10 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 11/19] sony-laptop: support automatic resume on lid open Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 13/19] sony-laptop: new keyboard backlight handle Mattia Dongili
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   86 ++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 4a4ecfa..f4dfdb0 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -155,6 +155,9 @@ static void sony_nc_thermal_resume(void);
 static int sony_nc_lid_resume_setup(struct platform_device *pd);
 static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
 
+static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
+static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
+
 struct gsensor_control {
 	int handle;
 	unsigned int attrs_num;
@@ -1318,6 +1321,12 @@ static void sony_nc_function_setup(struct acpi_device *device,
 				pr_err("couldn't set up thermal profile function (%d)\n",
 						result);
 			break;
+		case 0x0131:
+			result = sony_nc_highspeed_charging_setup(pf_device);
+			if (result)
+				pr_err("couldn't set up high speed charging function (%d)\n",
+						result);
+			break;
 		case 0x0134:
 		case 0x0147:
 			result = sony_nc_gsensor_setup(pf_device, handle);
@@ -1372,6 +1381,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x0122:
 			sony_nc_thermal_cleanup(pd);
 			break;
+		case 0x0131:
+			sony_nc_highspeed_charging_cleanup(pd);
+			break;
 		case 0x0134:
 		case 0x0147:
 			sony_nc_gsensor_cleanup(pd);
@@ -2623,6 +2635,80 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd)
 	}
 }
 
+/* High speed charging function */
+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 (kstrtoul(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)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0131, 0x0100, &result))
+		return -EIO;
+
+	return snprintf(buffer, PAGE_SIZE, "%d\n", result & 0x01);
+}
+
+static int sony_nc_highspeed_charging_setup(struct platform_device *pd)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(0x0131, 0x0000, &result) || !(result & 0x01)) {
+		/* some models advertise the handle but have no implementation
+		 * for it
+		 */
+		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;
+
+	result = device_create_file(&pd->dev, hsc_handle);
+	if (result) {
+		kfree(hsc_handle);
+		hsc_handle = NULL;
+		return result;
+	}
+
+	return 0;
+}
+
+static void 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;
+	}
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 13/19] sony-laptop: new keyboard backlight handle
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (11 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 12/19] sony-laptop: add high speed battery charging function Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 14/19] sony-laptop: add support for more WWAN modems Mattia Dongili
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Add support for handle 0x0143 (Vaio SA/SB/SC, CA/CB) and rework the code
to be hable to support different handles for the keyboard backlight
function.

[malattia@linux.it: group function specific variables in a struct]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  149 +++++++++++++++++++++---------------
 1 file changed, 87 insertions(+), 62 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f4dfdb0..f2d296a 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -141,8 +141,9 @@ MODULE_PARM_DESC(kbd_backlight_timeout,
 		 "(default: 0)");
 
 static void sony_nc_kbd_backlight_resume(void);
-static void sony_nc_kbd_backlight_setup(struct platform_device *pd);
-static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
+static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
+		unsigned int handle);
+static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd);
 
 static int sony_nc_battery_care_setup(struct platform_device *pd,
 		unsigned int handle);
@@ -1339,7 +1340,11 @@ static void sony_nc_function_setup(struct acpi_device *device,
 			sony_nc_rfkill_setup(device);
 			break;
 		case 0x0137:
-			sony_nc_kbd_backlight_setup(pf_device);
+		case 0x0143:
+			result = sony_nc_kbd_backlight_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up keyboard backlight function (%d)\n",
+						result);
 			break;
 		default:
 			continue;
@@ -1393,6 +1398,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 			sony_nc_rfkill_cleanup();
 			break;
 		case 0x0137:
+		case 0x0143:
 			sony_nc_kbd_backlight_cleanup(pd);
 			break;
 		default:
@@ -1435,6 +1441,7 @@ static void sony_nc_function_resume(void)
 			sony_nc_rfkill_update();
 			break;
 		case 0x0137:
+		case 0x0143:
 			sony_nc_kbd_backlight_resume();
 			break;
 		default:
@@ -1646,20 +1653,16 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 }
 
 /* Keyboard backlight feature */
-#define KBDBL_HANDLER	0x137
-#define KBDBL_PRESENT	0xB00
-#define	SET_MODE	0xC00
-#define SET_STATE	0xD00
-#define SET_TIMEOUT	0xE00
-
 struct kbd_backlight {
-	int mode;
-	int timeout;
+	unsigned int handle;
+	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 struct kbd_backlight *kbdbl_ctl;
 
 static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
 {
@@ -1668,15 +1671,15 @@ static ssize_t __sony_nc_kbd_backlight_mode_set(u8 value)
 	if (value > 1)
 		return -EINVAL;
 
-	if (sony_call_snc_handle(KBDBL_HANDLER,
-				(value << 0x10) | SET_MODE, &result))
+	if (sony_call_snc_handle(kbdbl_ctl->handle,
+				(value << 0x10) | (kbdbl_ctl->base), &result))
 		return -EIO;
 
 	/* Try to turn the light on/off immediately */
-	sony_call_snc_handle(KBDBL_HANDLER, (value << 0x10) | SET_STATE,
-			&result);
+	sony_call_snc_handle(kbdbl_ctl->handle,
+			(value << 0x10) | (kbdbl_ctl->base + 0x100), &result);
 
-	kbdbl_handle->mode = value;
+	kbdbl_ctl->mode = value;
 
 	return 0;
 }
@@ -1705,7 +1708,7 @@ 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);
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->mode);
 	return count;
 }
 
@@ -1716,11 +1719,11 @@ static int __sony_nc_kbd_backlight_timeout_set(u8 value)
 	if (value > 3)
 		return -EINVAL;
 
-	if (sony_call_snc_handle(KBDBL_HANDLER,
-				(value << 0x10) | SET_TIMEOUT, &result))
+	if (sony_call_snc_handle(kbdbl_ctl->handle, (value << 0x10) |
+				(kbdbl_ctl->base + 0x200), &result))
 		return -EIO;
 
-	kbdbl_handle->timeout = value;
+	kbdbl_ctl->timeout = value;
 
 	return 0;
 }
@@ -1749,85 +1752,107 @@ 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);
+	count = snprintf(buffer, PAGE_SIZE, "%d\n", kbdbl_ctl->timeout);
 	return count;
 }
 
-static void sony_nc_kbd_backlight_setup(struct platform_device *pd)
+static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
+		unsigned int handle)
 {
 	int result;
+	int ret = 0;
 
-	if (sony_call_snc_handle(KBDBL_HANDLER, KBDBL_PRESENT, &result))
-		return;
-	if (!(result & 0x02))
-		return;
+	/* verify the kbd backlight presence, these handles are not used for
+	 * keyboard backlight only
+	 */
+	ret = sony_call_snc_handle(handle, handle == 0x0137 ? 0x0B00 : 0x0100,
+			&result);
+	if (ret)
+		return ret;
 
-	kbdbl_handle = kzalloc(sizeof(*kbdbl_handle), GFP_KERNEL);
-	if (!kbdbl_handle)
-		return;
+	if ((handle == 0x0137 && !(result & 0x02)) ||
+			!(result & 0x01)) {
+		dprintk("no backlight keyboard found\n");
+		return 0;
+	}
+
+	kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
+	if (!kbdbl_ctl)
+		return -ENOMEM;
+
+	kbdbl_ctl->handle = handle;
+	if (handle == 0x0137)
+		kbdbl_ctl->base = 0x0C00;
+	else
+		kbdbl_ctl->base = 0x4000;
 
-	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_ctl->mode_attr.attr);
+	kbdbl_ctl->mode_attr.attr.name = "kbd_backlight";
+	kbdbl_ctl->mode_attr.attr.mode = S_IRUGO | S_IWUSR;
+	kbdbl_ctl->mode_attr.show = sony_nc_kbd_backlight_mode_show;
+	kbdbl_ctl->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;
+	sysfs_attr_init(&kbdbl_ctl->timeout_attr.attr);
+	kbdbl_ctl->timeout_attr.attr.name = "kbd_backlight_timeout";
+	kbdbl_ctl->timeout_attr.attr.mode = S_IRUGO | S_IWUSR;
+	kbdbl_ctl->timeout_attr.show = sony_nc_kbd_backlight_timeout_show;
+	kbdbl_ctl->timeout_attr.store = sony_nc_kbd_backlight_timeout_store;
 
-	if (device_create_file(&pd->dev, &kbdbl_handle->mode_attr))
+	ret = device_create_file(&pd->dev, &kbdbl_ctl->mode_attr);
+	if (ret)
 		goto outkzalloc;
 
-	if (device_create_file(&pd->dev, &kbdbl_handle->timeout_attr))
+	ret = device_create_file(&pd->dev, &kbdbl_ctl->timeout_attr);
+	if (ret)
 		goto outmode;
 
 	__sony_nc_kbd_backlight_mode_set(kbd_backlight);
 	__sony_nc_kbd_backlight_timeout_set(kbd_backlight_timeout);
 
-	return;
+	return 0;
 
 outmode:
-	device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
+	device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
 outkzalloc:
-	kfree(kbdbl_handle);
-	kbdbl_handle = NULL;
-	return;
+	kfree(kbdbl_ctl);
+	kbdbl_ctl = NULL;
+	return ret;
 }
 
-static int sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
+static void sony_nc_kbd_backlight_cleanup(struct platform_device *pd)
 {
-	if (kbdbl_handle) {
+	if (kbdbl_ctl) {
 		int result;
 
-		device_remove_file(&pd->dev, &kbdbl_handle->mode_attr);
-		device_remove_file(&pd->dev, &kbdbl_handle->timeout_attr);
+		device_remove_file(&pd->dev, &kbdbl_ctl->mode_attr);
+		device_remove_file(&pd->dev, &kbdbl_ctl->timeout_attr);
 
 		/* restore the default hw behaviour */
-		sony_call_snc_handle(KBDBL_HANDLER, 0x1000 | SET_MODE, &result);
-		sony_call_snc_handle(KBDBL_HANDLER, SET_TIMEOUT, &result);
+		sony_call_snc_handle(kbdbl_ctl->handle,
+				kbdbl_ctl->base | 0x10000, &result);
+		sony_call_snc_handle(kbdbl_ctl->handle,
+				kbdbl_ctl->base + 0x200, &result);
 
-		kfree(kbdbl_handle);
+		kfree(kbdbl_ctl);
+		kbdbl_ctl = NULL;
 	}
-	return 0;
 }
 
 static void sony_nc_kbd_backlight_resume(void)
 {
 	int ignore = 0;
 
-	if (!kbdbl_handle)
+	if (!kbdbl_ctl)
 		return;
 
-	if (kbdbl_handle->mode == 0)
-		sony_call_snc_handle(KBDBL_HANDLER, SET_MODE, &ignore);
-
-	if (kbdbl_handle->timeout != 0)
-		sony_call_snc_handle(KBDBL_HANDLER,
-				(kbdbl_handle->timeout << 0x10) | SET_TIMEOUT,
+	if (kbdbl_ctl->mode == 0)
+		sony_call_snc_handle(kbdbl_ctl->handle, kbdbl_ctl->base,
 				&ignore);
+
+	if (kbdbl_ctl->timeout != 0)
+		sony_call_snc_handle(kbdbl_ctl->handle,
+				(kbdbl_ctl->base + 0x200) |
+				(kbdbl_ctl->timeout << 0x10), &ignore);
 }
 
 struct battery_care_control {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 14/19] sony-laptop: add support for more WWAN modems
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (12 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 13/19] sony-laptop: new keyboard backlight handle Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 15/19] sony-laptop: add the ALS interface via SNC Mattia Dongili
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Also make the initialization function return a value for consistency
with all the other setup functions.

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   53 +++++++++++++++++++++++-------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index f2d296a..7f8de3f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -181,7 +181,8 @@ enum sony_nc_rfkill {
 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_setup(struct acpi_device *device);
+static int sony_nc_rfkill_setup(struct acpi_device *device,
+		unsigned int handle);
 static void sony_nc_rfkill_cleanup(void);
 static void sony_nc_rfkill_update(void);
 
@@ -1337,7 +1338,10 @@ static void sony_nc_function_setup(struct acpi_device *device,
 			break;
 		case 0x0124:
 		case 0x0135:
-			sony_nc_rfkill_setup(device);
+			result = sony_nc_rfkill_setup(device, handle);
+			if (result)
+				pr_err("couldn't set up rfkill support (%d)\n",
+						result);
 			break;
 		case 0x0137:
 		case 0x0143:
@@ -1605,37 +1609,46 @@ static void sony_nc_rfkill_update(void)
 	}
 }
 
-static void sony_nc_rfkill_setup(struct acpi_device *device)
+static int sony_nc_rfkill_setup(struct acpi_device *device,
+		unsigned int handle)
 {
 	u64 offset;
 	int i;
 	unsigned char buffer[32] = { 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);
+	offset = sony_find_snc_handle(handle);
+	sony_rfkill_handle = handle;
 
 	i = sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &offset, buffer,
 			32);
 	if (i < 0)
-		return;
-
-	/* the buffer is filled with magic numbers describing the devices
-	 * available, 0xff terminates the enumeration
+		return i;
+
+	/* The buffer is filled with magic numbers describing the devices
+	 * available, 0xff terminates the enumeration.
+	 * 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
+	 *	0x30 WIMAX
+	 *	0x50 Gobi WWAN no GPS
+	 *	0x51 Gobi WWAN + GPS
+	 *	0x70 no SIM card slot
+	 *	0x71 SIM card slot
 	 */
 	for (i = 0; i < ARRAY_SIZE(buffer); i++) {
 
 		if (buffer[i] == 0xff)
 			break;
 
-		dprintk("Radio devices, looking at 0x%.2x\n", buffer[i]);
+		dprintk("Radio devices, found 0x%.2x\n", buffer[i]);
 
 		if (buffer[i] == 0 && !sony_rfkill_devices[SONY_WIFI])
 			sony_nc_setup_rfkill(device, SONY_WIFI);
@@ -1643,13 +1656,15 @@ static void sony_nc_rfkill_setup(struct acpi_device *device)
 		if (buffer[i] == 0x10 && !sony_rfkill_devices[SONY_BLUETOOTH])
 			sony_nc_setup_rfkill(device, SONY_BLUETOOTH);
 
-		if ((0xf0 & buffer[i]) == 0x20 &&
+		if (((0xf0 & buffer[i]) == 0x20 ||
+					(0xf0 & buffer[i]) == 0x50) &&
 				!sony_rfkill_devices[SONY_WWAN])
 			sony_nc_setup_rfkill(device, SONY_WWAN);
 
 		if (buffer[i] == 0x30 && !sony_rfkill_devices[SONY_WIMAX])
 			sony_nc_setup_rfkill(device, SONY_WIMAX);
 	}
+	return 0;
 }
 
 /* Keyboard backlight feature */
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 15/19] sony-laptop: add the ALS interface via SNC
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (13 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 14/19] sony-laptop: add support for more WWAN modems Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:35 ` [PATCH 16/19] sony-laptop: add missing Fn key combos for 0x100 handlers Mattia Dongili
                   ` (3 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Javier Achirica

From: Javier Achirica <jachirica@gmail.com>

SNC provides an interface to the ALS chip present on a number of recent
Vaio models.

[marco@absence.it: extend support to recent models, sysfs interface]

Signed-off-by: Javier Achirica <achirica@gmail.com>
Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |  922 ++++++++++++++++++++++++++++++++++++
 1 file changed, 922 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 7f8de3f..4ffcc1f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -186,6 +186,42 @@ static int sony_nc_rfkill_setup(struct acpi_device *device,
 static void sony_nc_rfkill_cleanup(void);
 static void sony_nc_rfkill_update(void);
 
+#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 {
+	int handle;
+	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 */
+	unsigned int attrs_num;
+	struct device_attribute attrs[7];
+};
+static struct als_device *als_handle;
+
+static int sony_nc_als_setup(struct platform_device *pd, unsigned int handle);
+static void sony_nc_als_cleanup(struct platform_device *pd);
+static void sony_nc_als_resume(void);
+
 /*********** Input Devices ***********/
 
 #define SONY_LAPTOP_BUF_SIZE	128
@@ -1235,6 +1271,31 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 			ev_type = 3;
 			break;
 
+		case 0x0143:
+			sony_call_snc_handle(handle, 0x2000, &result);
+			/* event reasons are inverted ? */
+			real_ev = (result & 0x03) == 1 ? 2 : 1;
+			dprintk("ALS event received (%s change)\n",
+					real_ev == 1 ?
+					"light" : "backlight");
+
+			ev_type = 4;
+			break;
+
+		case 0x012f:
+		case 0x0137:
+			sony_call_snc_handle(handle, 0x0800, &result);
+			real_ev = result & 0x03;
+			dprintk("ALS event received (%s change)\n",
+					real_ev == 1 ?
+					"light" : "backlight");
+			if (real_ev == 1 &&
+					als_handle->ops->event_handler)
+				als_handle->ops->event_handler();
+
+			ev_type = 4;
+			break;
+
 		default:
 			dprintk("Unknown event 0x%x for handle 0x%x\n",
 					event, handle);
@@ -1323,6 +1384,11 @@ static void sony_nc_function_setup(struct acpi_device *device,
 				pr_err("couldn't set up thermal profile function (%d)\n",
 						result);
 			break;
+		case 0x012f:
+			result = sony_nc_als_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up ALS (%d)\n", result);
+			break;
 		case 0x0131:
 			result = sony_nc_highspeed_charging_setup(pf_device);
 			if (result)
@@ -1349,6 +1415,9 @@ static void sony_nc_function_setup(struct acpi_device *device,
 			if (result)
 				pr_err("couldn't set up keyboard backlight function (%d)\n",
 						result);
+			result = sony_nc_als_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up ALS (%d)\n", result);
 			break;
 		default:
 			continue;
@@ -1390,6 +1459,9 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x0122:
 			sony_nc_thermal_cleanup(pd);
 			break;
+		case 0x012f:
+			sony_nc_als_cleanup(pd);
+			break;
 		case 0x0131:
 			sony_nc_highspeed_charging_cleanup(pd);
 			break;
@@ -1404,6 +1476,7 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 		case 0x0137:
 		case 0x0143:
 			sony_nc_kbd_backlight_cleanup(pd);
+			sony_nc_als_cleanup(pd);
 			break;
 		default:
 			continue;
@@ -1444,9 +1517,13 @@ static void sony_nc_function_resume(void)
 		case 0x0135:
 			sony_nc_rfkill_update();
 			break;
+		case 0x012f:
+			sony_nc_als_resume();
+			break;
 		case 0x0137:
 		case 0x0143:
 			sony_nc_kbd_backlight_resume();
+			sony_nc_als_resume();
 			break;
 		default:
 			continue;
@@ -1667,6 +1744,851 @@ static int sony_nc_rfkill_setup(struct acpi_device *device,
 	return 0;
 }
 
+/* ALS */
+
+/* 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
+
+struct tsl256x_coeff {
+	u32 ratio;
+	u32 ch0;
+	u32 ch1;
+	u32 ka;
+	s32 kb;
+};
+
+struct tsl256x_data {
+	unsigned int gaintime;
+	unsigned int periods;
+	u8 *defaults;
+	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(als_handle->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];
+	int offset = sony_find_snc_handle(als_handle->handle);
+	u64 arg = (*value << 0x18) | (reg << 0x10) | 0xA00700 | offset;
+
+	/* using sony_call_snc_handle_buffer due to possible input overflows */
+	if (sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &arg,
+				result, 1) < 0)
+		return -EIO;
+
+	return result[0] & 0x01;
+}
+
+static inline int tsl256x_exec_readbyte(unsigned int reg, unsigned int *result)
+{
+	int arg = (reg << 0x10) | 0x800400;
+
+	if (sony_call_snc_handle(als_handle->handle, arg, result) < 0)
+		return -EIO;
+
+	if (!(*result & 0x01))
+		return -EINVAL;
+
+	*result = (*result >> 0x08) & 0xFF;
+
+	return 0;
+}
+
+static inline int tsl256x_exec_readword(unsigned int reg, unsigned int *result)
+{
+	int arg = (reg << 0x10) | 0xA00600;
+
+	if (sony_call_snc_handle(als_handle->handle, arg, result) < 0)
+		return -EIO;
+
+	if (!(*result & 0x01))
+		return -EINVAL;
+
+	*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 event goes 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 * tsl256x_handle->defaults[0]) / 100;
+	thigh = ((*ch0 * tsl256x_handle->defaults[1]) / 100) + 1;
+
+	if (thigh > 0xffff)
+		thigh = 0xffff;
+
+	if (tsl256x_exec_writeword(TSL256X_REG_TLOW, &tlow) ||
+		tsl256x_exec_writeword(TSL256X_REG_THIGH, &thigh))
+		return -EIO;
+
+	return 0;
+}
+
+#define MAX_LUX 1500
+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;
+
+	if (ch0 >= 65535 || ch1 >= 65535)
+		goto saturation;
+
+	/* 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);
+	/* the sensor is placed under a plastic or glass cover which filters
+	   a certain ammount of light (depending on that particular material).
+	   To have an accurate reading, we need to compensate for this loss,
+	   multiplying for compensation parameter, taken from the DSDT.
+	*/
+	temp *= tsl256x_handle->defaults[3] / 10;
+
+	/* 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;
+
+	if (integer > MAX_LUX)
+		goto saturation;
+
+	*integ = integer;
+	*fract = fractional;
+
+	return;
+
+saturation:
+	*integ = MAX_LUX;
+	*fract = 0;
+}
+
+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;
+
+	/* clear the notification */
+	sony_call_snc_handle(als_handle->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 = 0;
+	int ret = 0;
+	bool cs = false; /* 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 model %u rev%u\n", id >> 4, id & 0x0F);
+		return ret;
+	} else {
+		dprintk("ALS model %u rev%u (%s)\n", id >> 4, id & 0x0F, model);
+	}
+
+	tsl256x_handle = kzalloc(sizeof(struct tsl256x_data), GFP_KERNEL);
+	if (!tsl256x_handle)
+		return -ENOMEM;
+
+	tsl256x_handle->defaults = kzalloc(sizeof(u8) * 4, GFP_KERNEL);
+	if (!tsl256x_handle->defaults) {
+		kfree(tsl256x_handle);
+		return -ENOMEM;
+	}
+
+	/* populate the device data */
+	tsl256x_handle->defaults[0] = defaults[3];  /* low threshold % */
+	tsl256x_handle->defaults[1] = defaults[4];  /* high threshold % */
+	tsl256x_handle->defaults[2] = defaults[9];  /* sensor interrupt rate */
+	tsl256x_handle->defaults[3] = defaults[10]; /* light compensat. rate */
+	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)
+{
+	unsigned int interr = 0, periods = tsl256x_handle->defaults[2];
+
+	/* disable the interrupt generation, restore defaults */
+	tsl256x_interrupt_ctrls(&interr, &periods);
+
+	tsl256x_handle->coeff_table = NULL;
+	kfree(tsl256x_handle->defaults);
+	tsl256x_handle->defaults = 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(als_handle->handle, 0x1000, data))
+		return -EIO;
+
+	return 0;
+}
+
+static int ngals_get_lux(unsigned int *integ, unsigned int *fract)
+{
+	unsigned int data;
+
+	if (sony_call_snc_handle(als_handle->handle, 0x1000, &data))
+		return -EIO;
+
+	/* if we have a valid lux data */
+	if (!!(data & 0xff0000) == 0x01) {
+		*integ = 0xffff & data;
+		*fract = 0;
+	} else {
+		return -1;
+	}
+
+	return 0;
+}
+
+static const struct als_device_ops ngals_ops = {
+	.init = NULL,
+	.exit = NULL,
+	.event_handler = NULL,
+	.set_power = NULL,
+	.get_power = NULL,
+	.get_lux = ngals_get_lux,
+	.get_kelvin = NULL,
+};
+
+static int __sony_nc_als_power_set(unsigned int status)
+{
+	unsigned int cmd, result;
+
+	if (als_handle->ops->set_power) {
+		if (als_handle->ops->set_power(status))
+			return -EIO;
+		else
+			als_handle->power = status;
+	}
+
+
+	/*  turn on/off the event notification */
+	cmd = als_handle->handle == 0x0143 ? 0x2200 : 0x0900;
+	if (sony_call_snc_handle(als_handle->handle,
+				(status << 0x10) | cmd, &result))
+		return -EIO;
+
+	return 0;
+}
+
+/* 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)
+		status = 1;
+	/* TODO: can't use the cached value instead? */
+	else 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 (kstrtoul(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_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, "%u.%.2u\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_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, unsigned int handle)
+{
+	unsigned int result;
+	int i = 0;
+	u64 arg;
+
+	/* check the device presence */
+	if (handle == 0x0137) {
+		if (sony_call_snc_handle(als_handle->handle, 0xB00, &result))
+			return -EIO;
+
+		if (!(result & 0x01))
+			/* no ALS controls */
+			return 0;
+	}
+
+	als_handle = kzalloc(sizeof(struct als_device), GFP_KERNEL);
+	if (!als_handle)
+		return -ENOMEM;
+
+	als_handle->handle = handle;
+
+	/* set model specific data
+	 * if handle 0x012f or 0x0137 use tsl256x_ops, else new als controls
+	 */
+	if (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");
+	}
+
+	/* get ALS parameters */
+	arg = sony_find_snc_handle(handle);
+	if (sony_nc_buffer_call(sony_nc_acpi_handle, "SN06", &arg,
+		als_handle->parameters, ALS_TABLE_SIZE) < 0)
+		goto nosensor;
+
+	/* initial device configuration */
+	if (als_handle->ops->init) {
+		result = als_handle->ops->init(als_handle->defaults);
+		if (result)
+			goto nosensor;
+	}
+
+	/* set up the sys interface */
+
+	/* lux equivalent value */
+	sysfs_attr_init(&als_handle->attrs[0].attr);
+	als_handle->attrs[0].attr.name = "als_lux";
+	als_handle->attrs[0].attr.mode = S_IRUGO;
+	als_handle->attrs[0].show = sony_nc_als_lux_show;
+	als_handle->attrs_num++;
+
+	/* ALS default parameters */
+	sysfs_attr_init(&als_handle->attrs[1].attr);
+	als_handle->attrs[1].attr.name = "als_defaults";
+	als_handle->attrs[1].attr.mode = S_IRUGO;
+	als_handle->attrs[1].show = sony_nc_als_parameters_show;
+	als_handle->attrs_num++;
+
+	if (als_handle->ops->get_power || als_handle->ops->set_power) {
+		/* als power control */
+		sysfs_attr_init(&als_handle->attrs[als_handle->attrs_num].attr);
+		als_handle->attrs[als_handle->attrs_num].attr.name =
+			"als_power";
+		als_handle->attrs[als_handle->attrs_num].attr.mode =
+			S_IRUGO | S_IWUSR;
+		als_handle->attrs[als_handle->attrs_num].show =
+			sony_nc_als_power_show;
+		als_handle->attrs[als_handle->attrs_num].store =
+			sony_nc_als_power_store;
+		als_handle->attrs_num++;
+	}
+
+	if (als_handle->ops->get_kelvin) {
+		/* light temperature */
+		sysfs_attr_init(&als_handle->attrs[als_handle->attrs_num].attr);
+		als_handle->attrs[als_handle->attrs_num].attr.name =
+			"als_kelvin";
+		als_handle->attrs[als_handle->attrs_num].attr.mode = S_IRUGO;
+		als_handle->attrs[als_handle->attrs_num].show =
+			sony_nc_als_kelvin_show;
+		als_handle->attrs_num++;
+	}
+
+	for (; i < als_handle->attrs_num; i++) {
+		result = device_create_file(&pd->dev, &als_handle->attrs[i]);
+		if (result)
+			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 result;
+}
+
+static void sony_nc_als_resume(void)
+{
+	if (als_handle->power)
+		__sony_nc_als_power_set(1);
+}
+
+static void sony_nc_als_cleanup(struct platform_device *pd)
+{
+	if (als_handle) {
+		int i;
+
+		for (i = 0; i < als_handle->attrs_num; i++)
+			device_remove_file(&pd->dev, &als_handle->attrs[i]);
+
+		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 clean-up failed\n");
+
+		kfree(als_handle);
+		als_handle = NULL;
+	}
+}
+/* end ALS code */
+
 /* Keyboard backlight feature */
 struct kbd_backlight {
 	unsigned int handle;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 16/19] sony-laptop: add missing Fn key combos for 0x100 handlers
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (14 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 15/19] sony-laptop: add the ALS interface via SNC Mattia Dongili
@ 2012-05-19 13:35 ` Mattia Dongili
  2012-05-19 13:36 ` [PATCH 17/19] sony-laptop: add touchpad enable/disable function Mattia Dongili
                   ` (2 subsequent siblings)
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:35 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 4ffcc1f..2614262 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1136,10 +1136,14 @@ static struct sony_nc_event sony_100_events[] = {
 	{ 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 },
 	{ 0x9d, SONYPI_EVENT_ZOOM_PRESSED },
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 17/19] sony-laptop: add touchpad enable/disable function
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (15 preceding siblings ...)
  2012-05-19 13:35 ` [PATCH 16/19] sony-laptop: add missing Fn key combos for 0x100 handlers Mattia Dongili
@ 2012-05-19 13:36 ` Mattia Dongili
  2012-05-19 13:36 ` [PATCH 18/19] sony-laptop: use an enum for SNC event types Mattia Dongili
  2012-05-19 13:36 ` [PATCH 19/19] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

This setting is stored in the EC and available across reboots.

[malattia@linux.it: group function specific variables in a struct, use
kstrtoul]

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   91 ++++++++++++++++++++++++++++++++++++
 1 file changed, 91 insertions(+)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 2614262..3a95855 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -159,6 +159,10 @@ static void sony_nc_lid_resume_cleanup(struct platform_device *pd);
 static int sony_nc_highspeed_charging_setup(struct platform_device *pd);
 static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd);
 
+static int sony_nc_touchpad_setup(struct platform_device *pd,
+		unsigned int handle);
+static void sony_nc_touchpad_cleanup(struct platform_device *pd);
+
 struct gsensor_control {
 	int handle;
 	unsigned int attrs_num;
@@ -1368,6 +1372,14 @@ static void sony_nc_function_setup(struct acpi_device *device,
 			/* setup hotkeys */
 			sony_call_snc_handle(handle, 0x100, &result);
 			break;
+		case 0x0105:
+		case 0x0148:
+			/* touchpad enable/disable */
+			result = sony_nc_touchpad_setup(pf_device, handle);
+			if (result)
+				pr_err("couldn't set up touchpad control function (%d)\n",
+						result);
+			break;
 		case 0x0115:
 		case 0x0136:
 		case 0x013f:
@@ -1452,6 +1464,10 @@ static void sony_nc_function_cleanup(struct platform_device *pd)
 			continue;
 
 		switch (handle) {
+		case 0x0105:
+		case 0x0148:
+			sony_nc_touchpad_cleanup(pd);
+			break;
 		case 0x0115:
 		case 0x0136:
 		case 0x013f:
@@ -3675,6 +3691,81 @@ static void sony_nc_highspeed_charging_cleanup(struct platform_device *pd)
 	}
 }
 
+/* Touchpad enable/disable */
+struct touchpad_control {
+	struct device_attribute attr;
+	int handle;
+};
+static struct touchpad_control *tp_ctl;
+
+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 (kstrtoul(buffer, 10, &value) || value > 1)
+		return -EINVAL;
+
+	/* sysfs: 0 disabled, 1 enabled
+	 * EC: 0 enabled, 1 disabled
+	 */
+	if (sony_call_snc_handle(tp_ctl->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)
+{
+	unsigned int result;
+
+	if (sony_call_snc_handle(tp_ctl->handle, 0x000, &result))
+		return -EINVAL;
+
+	return snprintf(buffer, PAGE_SIZE, "%d\n", !(result & 0x01));
+}
+
+static int sony_nc_touchpad_setup(struct platform_device *pd,
+		unsigned int handle)
+{
+	int ret = 0;
+
+	tp_ctl = kzalloc(sizeof(struct touchpad_control), GFP_KERNEL);
+	if (!tp_ctl)
+		return -ENOMEM;
+
+	tp_ctl->handle = handle;
+
+	sysfs_attr_init(&tp_ctl->attr.attr);
+	tp_ctl->attr.attr.name = "touchpad";
+	tp_ctl->attr.attr.mode = S_IRUGO | S_IWUSR;
+	tp_ctl->attr.show = sony_nc_touchpad_show;
+	tp_ctl->attr.store = sony_nc_touchpad_store;
+
+	ret = device_create_file(&pd->dev, &tp_ctl->attr);
+	if (ret) {
+		kfree(tp_ctl);
+		tp_ctl = NULL;
+	}
+
+	return ret;
+}
+
+static void sony_nc_touchpad_cleanup(struct platform_device *pd)
+{
+	if (tp_ctl) {
+		device_remove_file(&pd->dev, &tp_ctl->attr);
+		kfree(tp_ctl);
+		tp_ctl = NULL;
+	}
+}
+
 static void sony_nc_backlight_ng_read_limits(int handle,
 		struct sony_backlight_props *props)
 {
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 18/19] sony-laptop: use an enum for SNC event types
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (16 preceding siblings ...)
  2012-05-19 13:36 ` [PATCH 17/19] sony-laptop: add touchpad enable/disable function Mattia Dongili
@ 2012-05-19 13:36 ` Mattia Dongili
  2012-05-19 13:36 ` [PATCH 19/19] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 3a95855..7f56f8d 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1219,6 +1219,12 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
 /*
  * ACPI callbacks
  */
+enum event_types {
+	HOTKEY = 1,
+	KILLSWITCH,
+	HDDSHOCK,
+	ALS
+};
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
 	u32 real_ev = event;
@@ -1243,7 +1249,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 		/* hotkey event */
 		case 0x0100:
 		case 0x0127:
-			ev_type = 1;
+			ev_type = HOTKEY;
 			real_ev = sony_nc_hotkeys_decode(event, handle);
 
 			if (real_ev > 0)
@@ -1263,7 +1269,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 			 * update the rfkill device status when the
 			 * switch is moved.
 			 */
-			ev_type = 2;
+			ev_type = KILLSWITCH;
 			sony_call_snc_handle(handle, 0x0100, &result);
 			real_ev = result & 0x03;
 
@@ -1276,7 +1282,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 		/* hdd protection event */
 		case 0x0134:
 		case 0x0147:
-			ev_type = 3;
+			ev_type = HDDSHOCK;
 			break;
 
 		case 0x0143:
@@ -1287,7 +1293,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 					real_ev == 1 ?
 					"light" : "backlight");
 
-			ev_type = 4;
+			ev_type = ALS;
 			break;
 
 		case 0x012f:
@@ -1301,7 +1307,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 					als_handle->ops->event_handler)
 				als_handle->ops->event_handler();
 
-			ev_type = 4;
+			ev_type = ALS;
 			break;
 
 		default:
@@ -1316,7 +1322,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 	} else {
 		/* old style event */
-		ev_type = 1;
+		ev_type = HOTKEY;
 		sony_laptop_report_input_event(real_ev);
 	}
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 19/19] sony-laptop: notify userspace of GFX switch position changes
  2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
                   ` (17 preceding siblings ...)
  2012-05-19 13:36 ` [PATCH 18/19] sony-laptop: use an enum for SNC event types Mattia Dongili
@ 2012-05-19 13:36 ` Mattia Dongili
  18 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-05-19 13:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Some Vaios come with both integrated and discrete graphics, plus a
switch for choosing one of the two. When the switch position is changed,
a notification is generated.

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 7f56f8d..48a1ca6 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1223,7 +1223,8 @@ enum event_types {
 	HOTKEY = 1,
 	KILLSWITCH,
 	HDDSHOCK,
-	ALS
+	ALS,
+	GFX_SWITCH
 };
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
@@ -1310,6 +1311,24 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 			ev_type = ALS;
 			break;
 
+		case 0x0128:
+		case 0x0146:
+			/* Hybrid GFX switching */
+			sony_call_snc_handle(handle, 0x0000, &result);
+			dprintk("GFX switch event received (reason: %s)\n",
+					(result & 0x01) ?
+					"switch change" : "unknown");
+
+			/* verify the switch state
+			 * 1: discrete GFX
+			 * 0: integrated GFX
+			 */
+			sony_call_snc_handle(handle, 0x0100, &result);
+
+			ev_type = GFX_SWITCH;
+			real_ev = result & 0xff;
+			break;
+
 		default:
 			dprintk("Unknown event 0x%x for handle 0x%x\n",
 					event, handle);
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 07/19] sony-laptop: support battery care functions
  2012-05-19 13:35 ` [PATCH 07/19] sony-laptop: support battery care functions Mattia Dongili
@ 2012-05-31 18:20   ` Matthew Garrett
  0 siblings, 0 replies; 36+ messages in thread
From: Matthew Garrett @ 2012-05-31 18:20 UTC (permalink / raw)
  To: Mattia Dongili; +Cc: platform-driver-x86, Marco Chiappero

It'd be nice if this kind of functionality could be added to the power 
supply class, but I'm happy to take this for now.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw
  2012-05-19 13:35 ` [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw Mattia Dongili
@ 2012-05-31 18:39   ` Matthew Garrett
  2012-05-31 22:02     ` Mattia Dongili
  0 siblings, 1 reply; 36+ messages in thread
From: Matthew Garrett @ 2012-05-31 18:39 UTC (permalink / raw)
  To: Mattia Dongili; +Cc: platform-driver-x86, Marco Chiappero

I've applied the set other than the HDD shock and ALS code. I just want 
to do some more checking of the current state of interfaces there to see 
if there's more commonality - the generic ACPI ALS driver looks like it 
may finally go somewhere, and I want to ensure compatibility.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw
  2012-05-31 18:39   ` Matthew Garrett
@ 2012-05-31 22:02     ` Mattia Dongili
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
  0 siblings, 1 reply; 36+ messages in thread
From: Mattia Dongili @ 2012-05-31 22:02 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Javier Achirica

On Thu, May 31, 2012 at 07:39:52PM +0100, Matthew Garrett wrote:
> I've applied the set other than the HDD shock and ALS code. I just want 
> to do some more checking of the current state of interfaces there to see 
> if there's more commonality - the generic ACPI ALS driver looks like it 
> may finally go somewhere, and I want to ensure compatibility.

Thanks, makes sense.
How about including them as experimental features (CONFIG_EXPERIMENTAL)?

Also, I have a handful of fixes that I was planning to fold into this
series and resend as v2 this weekend. I'll send incremental patches
instead.

-- 
mattia
:wq!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 0/7] sony-laptop fixes on 3.5-rc1
  2012-05-31 22:02     ` Mattia Dongili
@ 2012-06-09  4:18       ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 1/7] sony-laptop: use an enum for SNC event types Mattia Dongili
                           ` (9 more replies)
  0 siblings, 10 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86

Hi Matthew,

here's a few fixes on top of the patches you took for 3.5.
I may have more coming but I'm a bit short of time these days so I'm sending
these first.

--- 
Dan Carpenter (2):
      sony-laptop: fix sony_nc_sysfs_store()
      sony-laptop: fix a couple signedness bugs

Marco Chiappero (1):
      sony-laptop: notify userspace of GFX switch position changes

Mattia Dongili (4):
      sony-laptop: use an enum for SNC event types
      sony-laptop: store battery care limits on batteries
      sony-laptop: add lid backlight support for handle 0x143
      sony-laptop: input initialization should be done before SNC
--- 
 drivers/platform/x86/sony-laptop.c |  132 ++++++++++++++++++++++++------------
 1 file changed, 87 insertions(+), 45 deletions(-)
-- 
Mattia

^ permalink raw reply	[flat|nested] 36+ messages in thread

* [PATCH 1/7] sony-laptop: use an enum for SNC event types
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 2/7] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili
                           ` (8 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 210d4ae..615ab06 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1172,6 +1172,10 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
 /*
  * ACPI callbacks
  */
+enum event_types {
+	HOTKEY = 1,
+	KILLSWITCH
+};
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
 	u32 real_ev = event;
@@ -1196,7 +1200,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 		/* hotkey event */
 		case 0x0100:
 		case 0x0127:
-			ev_type = 1;
+			ev_type = HOTKEY;
 			real_ev = sony_nc_hotkeys_decode(event, handle);
 
 			if (real_ev > 0)
@@ -1216,7 +1220,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 			 * update the rfkill device status when the
 			 * switch is moved.
 			 */
-			ev_type = 2;
+			ev_type = KILLSWITCH;
 			sony_call_snc_handle(handle, 0x0100, &result);
 			real_ev = result & 0x03;
 
@@ -1238,7 +1242,7 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 	} else {
 		/* old style event */
-		ev_type = 1;
+		ev_type = HOTKEY;
 		sony_laptop_report_input_event(real_ev);
 	}
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 2/7] sony-laptop: notify userspace of GFX switch position changes
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
  2012-06-09  4:18         ` [PATCH 1/7] sony-laptop: use an enum for SNC event types Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 3/7] sony-laptop: store battery care limits on batteries Mattia Dongili
                           ` (7 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Marco Chiappero, Mattia Dongili

From: Marco Chiappero <marco@absence.it>

Some Vaios come with both integrated and discrete graphics, plus a
switch for choosing one of the two. When the switch position is changed,
a notification is generated.

Signed-off-by: Marco Chiappero <marco@absence.it>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   21 ++++++++++++++++++++-
 1 file changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 615ab06..4f42e56 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1174,7 +1174,8 @@ static int sony_nc_hotkeys_decode(u32 event, unsigned int handle)
  */
 enum event_types {
 	HOTKEY = 1,
-	KILLSWITCH
+	KILLSWITCH,
+	GFX_SWITCH
 };
 static void sony_nc_notify(struct acpi_device *device, u32 event)
 {
@@ -1230,6 +1231,24 @@ static void sony_nc_notify(struct acpi_device *device, u32 event)
 
 			break;
 
+		case 0x0128:
+		case 0x0146:
+			/* Hybrid GFX switching */
+			sony_call_snc_handle(handle, 0x0000, &result);
+			dprintk("GFX switch event received (reason: %s)\n",
+					(result & 0x01) ?
+					"switch change" : "unknown");
+
+			/* verify the switch state
+			 * 1: discrete GFX
+			 * 0: integrated GFX
+			 */
+			sony_call_snc_handle(handle, 0x0100, &result);
+
+			ev_type = GFX_SWITCH;
+			real_ev = result & 0xff;
+			break;
+
 		default:
 			dprintk("Unknown event 0x%x for handle 0x%x\n",
 					event, handle);
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 3/7] sony-laptop: store battery care limits on batteries
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
  2012-06-09  4:18         ` [PATCH 1/7] sony-laptop: use an enum for SNC event types Mattia Dongili
  2012-06-09  4:18         ` [PATCH 2/7] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-10 22:18           ` [PATCH 3/7 v2] " Mattia Dongili
  2012-06-09  4:18         ` [PATCH 4/7] sony-laptop: add lid backlight support for handle 0x143 Mattia Dongili
                           ` (6 subsequent siblings)
  9 siblings, 1 reply; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Some models offer the option to store the limits on the battery
(firmware?).

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   41 ++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 4f42e56..5d8f3fa 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1916,32 +1916,33 @@ static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
 	 *  bits 4,5: store the limit into the EC
 	 *  bits 6,7: store the limit into the battery
 	 */
+	cmd = 0;
 
-	/*
-	 * 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
-	 */
-	if (value == 0)
-		/* disable limits */
-		cmd = 0x0;
+	if (value > 0) {
+		if (value <= 50)
+			cmd = 0x20;
 
-	else if (value <= 50)
-		cmd = 0x21;
+		else if (value <= 80)
+			cmd = 0x10;
 
-	else if (value <= 80)
-		cmd = 0x11;
+		else if (value <= 100)
+			cmd = 0x30;
+
+		else
+			return -EINVAL;
 
-	else if (value <= 100)
-		cmd = 0x31;
+		/*
+		 * 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
+		 */
+		if (bcare_ctl->handle != 0x013f)
+			cmd = cmd | (cmd << 2);
 
-	else
-		return -EINVAL;
+		cmd = (cmd << 0x10) | 1;
+	}
 
-	if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
-				&result))
+	if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
 		return -EIO;
 
 	return count;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 4/7] sony-laptop: add lid backlight support for handle 0x143
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (2 preceding siblings ...)
  2012-06-09  4:18         ` [PATCH 3/7] sony-laptop: store battery care limits on batteries Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 5/7] sony-laptop: input initialization should be done before SNC Mattia Dongili
                           ` (5 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 5d8f3fa..ec7f4e0 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1010,6 +1010,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 struct sony_backlight_props {
 	struct backlight_device *dev;
 	int			handle;
+	int			cmd_base;
 	u8			offset;
 	u8			maxlvl;
 };
@@ -1037,7 +1038,7 @@ static int sony_nc_get_brightness_ng(struct backlight_device *bd)
 	struct sony_backlight_props *sdev =
 		(struct sony_backlight_props *)bl_get_data(bd);
 
-	sony_call_snc_handle(sdev->handle, 0x0200, &result);
+	sony_call_snc_handle(sdev->handle, sdev->cmd_base + 0x100, &result);
 
 	return (result & 0xff) - sdev->offset;
 }
@@ -1049,7 +1050,8 @@ static int sony_nc_update_status_ng(struct backlight_device *bd)
 		(struct sony_backlight_props *)bl_get_data(bd);
 
 	value = bd->props.brightness + sdev->offset;
-	if (sony_call_snc_handle(sdev->handle, 0x0100 | (value << 16), &result))
+	if (sony_call_snc_handle(sdev->handle, sdev->cmd_base | (value << 0x10),
+				&result))
 		return -EIO;
 
 	return value;
@@ -2496,6 +2498,7 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 {
 	u64 offset;
 	int i;
+	int lvl_table_len = 0;
 	u8 min = 0xff, max = 0x00;
 	unsigned char buffer[32] = { 0 };
 
@@ -2515,11 +2518,21 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 	if (i < 0)
 		return;
 
+	switch (handle) {
+	case 0x012f:
+	case 0x0137:
+		lvl_table_len = 9;
+		break;
+	case 0x143:
+		lvl_table_len = 16;
+		break;
+	}
+
 	/* the buffer lists brightness levels available, brightness levels are
 	 * from position 0 to 8 in the array, other values are used by ALS
 	 * control.
 	 */
-	for (i = 0; i < 9 && i < ARRAY_SIZE(buffer); i++) {
+	for (i = 0; i < lvl_table_len && i < ARRAY_SIZE(buffer); i++) {
 
 		dprintk("Brightness level: %d\n", buffer[i]);
 
@@ -2546,14 +2559,22 @@ static void sony_nc_backlight_setup(void)
 
 	if (sony_find_snc_handle(0x12f) != -1) {
 		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
 	} else if (sony_find_snc_handle(0x137) != -1) {
 		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
+	} else if (sony_find_snc_handle(0x143) != -1) {
+		ops = &sony_backlight_ng_ops;
+		sony_bl_props.cmd_base = 0x3000;
+		sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
+		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
+
 	} else if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "GBRT",
 						&unused))) {
 		ops = &sony_backlight_ops;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 5/7] sony-laptop: input initialization should be done before SNC
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (3 preceding siblings ...)
  2012-06-09  4:18         ` [PATCH 4/7] sony-laptop: add lid backlight support for handle 0x143 Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 6/7] sony-laptop: fix sony_nc_sysfs_store() Mattia Dongili
                           ` (4 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

SNC needs input devices so better have those ready before starting
handle events.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |   25 ++++++++++++-------------
 1 file changed, 12 insertions(+), 13 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index ec7f4e0..534c295 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2642,6 +2642,12 @@ static int sony_nc_add(struct acpi_device *device)
 		}
 	}
 
+	result = sony_laptop_setup_input(device);
+	if (result) {
+		pr_err("Unable to create input devices\n");
+		goto outplatform;
+	}
+
 	if (ACPI_SUCCESS(acpi_get_handle(sony_nc_acpi_handle, "ECON",
 					 &handle))) {
 		int arg = 1;
@@ -2659,12 +2665,6 @@ static int sony_nc_add(struct acpi_device *device)
 	}
 
 	/* setup input devices and helper fifo */
-	result = sony_laptop_setup_input(device);
-	if (result) {
-		pr_err("Unable to create input devices\n");
-		goto outsnc;
-	}
-
 	if (acpi_video_backlight_support()) {
 		pr_info("brightness ignored, must be controlled by ACPI video driver\n");
 	} else {
@@ -2712,22 +2712,21 @@ static int sony_nc_add(struct acpi_device *device)
 
 	return 0;
 
-      out_sysfs:
+out_sysfs:
 	for (item = sony_nc_values; item->name; ++item) {
 		device_remove_file(&sony_pf_device->dev, &item->devattr);
 	}
 	sony_nc_backlight_cleanup();
-
-	sony_laptop_remove_input();
-
-      outsnc:
 	sony_nc_function_cleanup(sony_pf_device);
 	sony_nc_handles_cleanup(sony_pf_device);
 
-      outpresent:
+outplatform:
+	sony_laptop_remove_input();
+
+outpresent:
 	sony_pf_remove();
 
-      outwalk:
+outwalk:
 	sony_nc_rfkill_cleanup();
 	return result;
 }
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 6/7] sony-laptop: fix sony_nc_sysfs_store()
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (4 preceding siblings ...)
  2012-06-09  4:18         ` [PATCH 5/7] sony-laptop: input initialization should be done before SNC Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-09  4:18         ` [PATCH 7/7] sony-laptop: fix a couple signedness bugs Mattia Dongili
                           ` (3 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Dan Carpenter, Mattia Dongili

From: Dan Carpenter <dan.carpenter@oracle.com>

We made this an unsigned long and it causes a bug on 64 bit big endian
systems when we try to pass the value to sony_nc_int_call().

Also value has to be signed because validate() returns negative error
codes.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 534c295..6123987 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -973,7 +973,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 			       struct device_attribute *attr,
 			       const char *buffer, size_t count)
 {
-	unsigned long value = 0;
+	int value;
 	int ret = 0;
 	struct sony_nc_value *item =
 	    container_of(attr, struct sony_nc_value, devattr);
@@ -984,7 +984,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 	if (count > 31)
 		return -EINVAL;
 
-	if (kstrtoul(buffer, 10, &value))
+	if (kstrtoint(buffer, 10, &value))
 		return -EINVAL;
 
 	if (item->validate)
@@ -994,7 +994,7 @@ static ssize_t sony_nc_sysfs_store(struct device *dev,
 		return value;
 
 	ret = sony_nc_int_call(sony_nc_acpi_handle, *item->acpiset,
-			(int *)&value, NULL);
+			       &value, NULL);
 	if (ret < 0)
 		return -EIO;
 
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 7/7] sony-laptop: fix a couple signedness bugs
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (5 preceding siblings ...)
  2012-06-09  4:18         ` [PATCH 6/7] sony-laptop: fix sony_nc_sysfs_store() Mattia Dongili
@ 2012-06-09  4:18         ` Mattia Dongili
  2012-06-13 21:36         ` [PATCH] sony-laptop: correct find_snc_handle failure checks Mattia Dongili
                           ` (2 subsequent siblings)
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-09  4:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Dan Carpenter, Mattia Dongili

From: Dan Carpenter <dan.carpenter@oracle.com>

This needs to be signed to handle negative error codes.
Remove a redundant check, read_limits is always called with a valid
handle.

Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
Signed-off-by: Mattia Dongili <malattia@linux.it>
---
 drivers/platform/x86/sony-laptop.c |    4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 6123987..3fc92fa 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2139,7 +2139,7 @@ static ssize_t sony_nc_thermal_mode_show(struct device *dev,
 		struct device_attribute *attr, char *buffer)
 {
 	ssize_t count = 0;
-	unsigned int mode = sony_nc_thermal_mode_get();
+	int mode = sony_nc_thermal_mode_get();
 
 	if (mode < 0)
 		return mode;
@@ -2507,8 +2507,6 @@ static void sony_nc_backlight_ng_read_limits(int handle,
 	props->maxlvl = 0xff;
 
 	offset = sony_find_snc_handle(handle);
-	if (offset < 0)
-		return;
 
 	/* try to read the boundaries from ACPI tables, if we fail the above
 	 * defaults should be reasonable
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH 3/7 v2] sony-laptop: store battery care limits on batteries
  2012-06-09  4:18         ` [PATCH 3/7] sony-laptop: store battery care limits on batteries Mattia Dongili
@ 2012-06-10 22:18           ` Mattia Dongili
  0 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-10 22:18 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Some models offer the option to store the limits on the battery
(firmware?).

Signed-off-by: Mattia Dongili <malattia@linux.it>
---

Hi Matthew,
please ignore the previous one as it had a bug, this one is good.
Thanks!

---
 drivers/platform/x86/sony-laptop.c |   41 ++++++++++++++++++------------------
 1 file changed, 21 insertions(+), 20 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 4f42e56..f045e3e 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1916,32 +1916,33 @@ static ssize_t sony_nc_battery_care_limit_store(struct device *dev,
 	 *  bits 4,5: store the limit into the EC
 	 *  bits 6,7: store the limit into the battery
 	 */
+	cmd = 0;
 
-	/*
-	 * 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
-	 */
-	if (value == 0)
-		/* disable limits */
-		cmd = 0x0;
+	if (value > 0) {
+		if (value <= 50)
+			cmd = 0x20;
 
-	else if (value <= 50)
-		cmd = 0x21;
+		else if (value <= 80)
+			cmd = 0x10;
 
-	else if (value <= 80)
-		cmd = 0x11;
+		else if (value <= 100)
+			cmd = 0x30;
+
+		else
+			return -EINVAL;
 
-	else if (value <= 100)
-		cmd = 0x31;
+		/*
+		 * 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
+		 */
+		if (bcare_ctl->handle != 0x013f)
+			cmd = cmd | (cmd << 2);
 
-	else
-		return -EINVAL;
+		cmd = (cmd | 0x1) << 0x10;
+	}
 
-	if (sony_call_snc_handle(bcare_ctl->handle, (cmd << 0x10) | 0x0100,
-				&result))
+	if (sony_call_snc_handle(bcare_ctl->handle, cmd | 0x0100, &result))
 		return -EIO;
 
 	return count;
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* [PATCH] sony-laptop: correct find_snc_handle failure checks
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (6 preceding siblings ...)
  2012-06-09  4:18         ` [PATCH 7/7] sony-laptop: fix a couple signedness bugs Mattia Dongili
@ 2012-06-13 21:36         ` Mattia Dongili
  2012-06-25 21:36         ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
  2012-06-26 18:37         ` Matthew Garrett
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-13 21:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86, Mattia Dongili

Since bab7084c745bf4d75b760728387f375fd34dc683, find_snc_handle
returns -EINVAL, not -1.

Signed-off-by: Mattia Dongili <malattia@linux.it>
---

Hi Matthew,
this bug is a bug present in current 3.5-rc could you please pick this patch
up?
The patch will apply fine on top of the other series I sent, let me know if I
should rebase it on something else.

Thanks

 drivers/platform/x86/sony-laptop.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 3617858..f4fc73f 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -2555,19 +2555,19 @@ static void sony_nc_backlight_setup(void)
 	const struct backlight_ops *ops = NULL;
 	struct backlight_properties props;
 
-	if (sony_find_snc_handle(0x12f) != -1) {
+	if (sony_find_snc_handle(0x12f) >= 0) {
 		ops = &sony_backlight_ng_ops;
 		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x12f, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
-	} else if (sony_find_snc_handle(0x137) != -1) {
+	} else if (sony_find_snc_handle(0x137) >= 0) {
 		ops = &sony_backlight_ng_ops;
 		sony_bl_props.cmd_base = 0x0100;
 		sony_nc_backlight_ng_read_limits(0x137, &sony_bl_props);
 		max_brightness = sony_bl_props.maxlvl - sony_bl_props.offset;
 
-	} else if (sony_find_snc_handle(0x143) != -1) {
+	} else if (sony_find_snc_handle(0x143) >= 0) {
 		ops = &sony_backlight_ng_ops;
 		sony_bl_props.cmd_base = 0x3000;
 		sony_nc_backlight_ng_read_limits(0x143, &sony_bl_props);
-- 
1.7.10

^ permalink raw reply related	[flat|nested] 36+ messages in thread

* Re: [PATCH 0/7] sony-laptop fixes on 3.5-rc1
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (7 preceding siblings ...)
  2012-06-13 21:36         ` [PATCH] sony-laptop: correct find_snc_handle failure checks Mattia Dongili
@ 2012-06-25 21:36         ` Mattia Dongili
  2012-06-26 18:37         ` Matthew Garrett
  9 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-06-25 21:36 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86

On Sat, Jun 09, 2012 at 01:18:07PM +0900, Mattia Dongili wrote:
> Hi Matthew,
> 
> here's a few fixes on top of the patches you took for 3.5.
> I may have more coming but I'm a bit short of time these days so I'm sending
> these first.

Hi Matthew,

have you got any time to look at these patches and the additional fix I
sent later[1]?
If you need a shorter list for 3.5 I can also prepare a different set of
must-be-in-3.5.

> --- 
> Dan Carpenter (2):
>       sony-laptop: fix sony_nc_sysfs_store()
>       sony-laptop: fix a couple signedness bugs
> 
> Marco Chiappero (1):
>       sony-laptop: notify userspace of GFX switch position changes
> 
> Mattia Dongili (4):
>       sony-laptop: use an enum for SNC event types
>       sony-laptop: store battery care limits on batteries
>       sony-laptop: add lid backlight support for handle 0x143
>       sony-laptop: input initialization should be done before SNC

[1]: sony-laptop: correct find_snc_handle failure checks

Thanks
-- 
mattia
:wq!

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 0/7] sony-laptop fixes on 3.5-rc1
  2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
                           ` (8 preceding siblings ...)
  2012-06-25 21:36         ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
@ 2012-06-26 18:37         ` Matthew Garrett
  2012-07-16  8:03           ` Mattia Dongili
  9 siblings, 1 reply; 36+ messages in thread
From: Matthew Garrett @ 2012-06-26 18:37 UTC (permalink / raw)
  To: Mattia Dongili; +Cc: platform-driver-x86

Applied these, thanks.

-- 
Matthew Garrett | mjg59@srcf.ucam.org

^ permalink raw reply	[flat|nested] 36+ messages in thread

* Re: [PATCH 0/7] sony-laptop fixes on 3.5-rc1
  2012-06-26 18:37         ` Matthew Garrett
@ 2012-07-16  8:03           ` Mattia Dongili
  0 siblings, 0 replies; 36+ messages in thread
From: Mattia Dongili @ 2012-07-16  8:03 UTC (permalink / raw)
  To: Matthew Garrett; +Cc: platform-driver-x86

On Tue, Jun 26, 2012 at 07:37:33PM +0100, Matthew Garrett wrote:
> Applied these, thanks.

Hi Matthew,

what's the status of these patches?

At least the following 3 commits would be good to have in 3.5.
The last one expecially fixes a bug that will break backlight control
detection on a relatively large number of vaios.

c7a2918373983b32db3ca35823d930641747e26f
56f4a9f76d8ce7c7cef92905c909aad0c7e5c9db
a1071a5abf1f4d4a7f8324e21b8b32b1342013c7

Thanks!
-- 
mattia
:wq!

^ permalink raw reply	[flat|nested] 36+ messages in thread

end of thread, other threads:[~2012-07-16  8:03 UTC | newest]

Thread overview: 36+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-05-19 13:35 [PATCH 00/19] sony-laptop: support for new functions Mattia Dongili
2012-05-19 13:35 ` [PATCH 01/19] sony-laptop: use soft rfkill status stored in hw Mattia Dongili
2012-05-31 18:39   ` Matthew Garrett
2012-05-31 22:02     ` Mattia Dongili
2012-06-09  4:18       ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
2012-06-09  4:18         ` [PATCH 1/7] sony-laptop: use an enum for SNC event types Mattia Dongili
2012-06-09  4:18         ` [PATCH 2/7] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili
2012-06-09  4:18         ` [PATCH 3/7] sony-laptop: store battery care limits on batteries Mattia Dongili
2012-06-10 22:18           ` [PATCH 3/7 v2] " Mattia Dongili
2012-06-09  4:18         ` [PATCH 4/7] sony-laptop: add lid backlight support for handle 0x143 Mattia Dongili
2012-06-09  4:18         ` [PATCH 5/7] sony-laptop: input initialization should be done before SNC Mattia Dongili
2012-06-09  4:18         ` [PATCH 6/7] sony-laptop: fix sony_nc_sysfs_store() Mattia Dongili
2012-06-09  4:18         ` [PATCH 7/7] sony-laptop: fix a couple signedness bugs Mattia Dongili
2012-06-13 21:36         ` [PATCH] sony-laptop: correct find_snc_handle failure checks Mattia Dongili
2012-06-25 21:36         ` [PATCH 0/7] sony-laptop fixes on 3.5-rc1 Mattia Dongili
2012-06-26 18:37         ` Matthew Garrett
2012-07-16  8:03           ` Mattia Dongili
2012-05-19 13:35 ` [PATCH 02/19] sony-laptop: fix return path when no ACPI buffer is allocated Mattia Dongili
2012-05-19 13:35 ` [PATCH 03/19] sony-laptop: generalise ACPI calls into SNC functions Mattia Dongili
2012-05-19 13:35 ` [PATCH 04/19] sony-laptop: use kstrtoul to parse sysfs values Mattia Dongili
2012-05-19 13:35 ` [PATCH 05/19] sony-laptop: improve SNC initialization and acpi notify callback code Mattia Dongili
2012-05-19 13:35 ` [PATCH 06/19] sony-laptop: additional debug statements Mattia Dongili
2012-05-19 13:35 ` [PATCH 07/19] sony-laptop: support battery care functions Mattia Dongili
2012-05-31 18:20   ` Matthew Garrett
2012-05-19 13:35 ` [PATCH 08/19] sony-laptop: add thermal profiles support Mattia Dongili
2012-05-19 13:35 ` [PATCH 09/19] sony-laptop: adjust error handling in finding SNC handles Mattia Dongili
2012-05-19 13:35 ` [PATCH 10/19] sony-laptop: g-shock HD protection function Mattia Dongili
2012-05-19 13:35 ` [PATCH 11/19] sony-laptop: support automatic resume on lid open Mattia Dongili
2012-05-19 13:35 ` [PATCH 12/19] sony-laptop: add high speed battery charging function Mattia Dongili
2012-05-19 13:35 ` [PATCH 13/19] sony-laptop: new keyboard backlight handle Mattia Dongili
2012-05-19 13:35 ` [PATCH 14/19] sony-laptop: add support for more WWAN modems Mattia Dongili
2012-05-19 13:35 ` [PATCH 15/19] sony-laptop: add the ALS interface via SNC Mattia Dongili
2012-05-19 13:35 ` [PATCH 16/19] sony-laptop: add missing Fn key combos for 0x100 handlers Mattia Dongili
2012-05-19 13:36 ` [PATCH 17/19] sony-laptop: add touchpad enable/disable function Mattia Dongili
2012-05-19 13:36 ` [PATCH 18/19] sony-laptop: use an enum for SNC event types Mattia Dongili
2012-05-19 13:36 ` [PATCH 19/19] sony-laptop: notify userspace of GFX switch position changes Mattia Dongili

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.