[PATCH V4 1/1] iio: Updated Capella cm3232 ambient light sensor driver.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Added ACPI and Power Management support.

Signed-off-by: Kevin Tsai <ktsai@xxxxxxxxxxxxxxxx>
---
v4:
Added ACPI and Power Management support.

Thanks Srinivas Pandruvada's ACPI routines.

v3:
Added hw_id to als_info structure.
Removed unused include files.
Modified cm3232_write_als_it() to handle register update fail.

Thanks comments from Daniel Baluta.

v2:
Removed unused CM3232_CMD_ALS_HS.
Modified cm3232_als_info structure.  Removed id field.
Modified cm3232_chip structure.
Merged CM3232_als_it_bits and CM3232_als_it_values to cm3232_it_scale.
Removed mutex lock.
Renamed als_raw to regs_als.  Moved it to cm3232_chip structure.
Modified cm3232_read_als_it() and cm3232_write_als_it() to support val2.

Thanks comments from Jeremiah Mahler, Peter Meerwald, Daniel Baluta,
and Joe Perches.

v1:
Added cm3232.c to support Capella Microsystems CM3232 Ambient Light
Sensor.

 drivers/iio/light/cm3232.c | 117 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 114 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
index 90e3519..7a8a624 100644
--- a/drivers/iio/light/cm3232.c
+++ b/drivers/iio/light/cm3232.c
@@ -2,7 +2,6 @@
  * CM3232 Ambient Light Sensor
  *
  * Copyright (C) 2014-2015 Capella Microsystems Inc.
- * Author: Kevin Tsai <ktsai@xxxxxxxxxxxxxxxx>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2, as published
@@ -16,6 +15,7 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 #include <linux/init.h>
+#include <linux/acpi.h>
 
 /* Registers Address */
 #define CM3232_REG_ADDR_CMD		0x00
@@ -77,6 +77,50 @@ struct cm3232_chip {
 };
 
 /**
+ *  cm32181_acpi_get_cpm_info() - Get CPM object from ACPI
+ *  @client      pointer of struct i2c_client.
+ *  @obj_name    pointer of ACPI object name.
+ *  @count       maximum size of return array.
+ *  @vals	pointer of array for return elements.
+ *
+ *  Convert ACPI CPM table to array. Special thanks Srinivas Pandruvada's
+ *  help to implement this routine.
+ *
+ *  Return: -ENODEV for fail.  Otherwise is number of elements.
+ */
+static int cm32181_acpi_get_cpm_info(struct i2c_client *client, char *obj_name,
+							int count, u64 *vals)
+{
+	acpi_handle handle;
+	struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+	int i;
+	acpi_status status;
+	union acpi_object *cpm;
+
+	handle = ACPI_HANDLE(&client->dev);
+	if (!handle)
+		return -ENODEV;
+
+	status = acpi_evaluate_object(handle, obj_name, NULL, &buffer);
+	if (ACPI_FAILURE(status)) {
+		dev_err(&client->dev, "object %s not found\n", obj_name);
+		return -ENODEV;
+	}
+
+	cpm = buffer.pointer;
+	for (i = 0; i < cpm->package.count && i < count; ++i) {
+		union acpi_object *elem;
+
+		elem = &(cpm->package.elements[i]);
+		vals[i] = elem->integer.value;
+	}
+
+	kfree(buffer.pointer);
+
+	return cpm->package.count;
+}
+
+/**
  * cm3232_reg_init() - Initialize CM3232
  * @chip:	pointer of struct cm3232_chip.
  *
@@ -88,9 +132,35 @@ static int cm3232_reg_init(struct cm3232_chip *chip)
 {
 	struct i2c_client *client = chip->client;
 	s32 ret;
+	int cpm_elem_count;
+	u64 cpm_elems[20];
 
 	chip->als_info = &cm3232_als_info_default;
 
+	if (ACPI_HANDLE(&client->dev)) {
+		/* Load from ACPI */
+		cpm_elem_count = cm32181_acpi_get_cpm_info(client, "CPM0",
+							ARRAY_SIZE(cpm_elems),
+							cpm_elems);
+		if (cpm_elem_count > 0) {
+			int header_num = 3;
+			int regs_bmp = cpm_elems[2];
+
+			chip->als_info->hw_id = (u8)cpm_elems[0];
+			if (regs_bmp & BIT(0))
+				chip->als_info->regs_cmd_default =
+							 cpm_elems[header_num];
+		}
+
+		cpm_elem_count = cm32181_acpi_get_cpm_info(client, "CPM1",
+							ARRAY_SIZE(cpm_elems),
+							cpm_elems);
+		if (cpm_elem_count > 0) {
+			chip->als_info->mlux_per_bit = (int)cpm_elems[0] / 100;
+			chip->als_info->calibscale = (int)cpm_elems[1];
+		}
+	}
+
 	/* Identify device */
 	ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
 	if (ret < 0) {
@@ -211,6 +281,7 @@ static int cm3232_get_lux(struct cm3232_chip *chip)
 	ret = cm3232_read_als_it(chip, &val, &val2);
 	if (ret < 0)
 		return -EINVAL;
+
 	als_it = val * 1000000 + val2;
 	lux = (__force u64)als_info->mlux_per_bit;
 	lux *= als_info->mlux_per_bit_base_it;
@@ -366,13 +437,41 @@ static int cm3232_remove(struct i2c_client *client)
 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
 	i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
-		CM3232_CMD_ALS_DISABLE);
+				CM3232_CMD_ALS_DISABLE);
 
 	iio_device_unregister(indio_dev);
 
 	return 0;
 }
 
+static int cm3232_suspend(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct cm3232_chip *chip = iio_priv(indio_dev);
+	struct i2c_client *client = chip->client;
+	int ret;
+
+	chip->regs_cmd |= CM3232_CMD_ALS_DISABLE;
+	ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+					chip->regs_cmd);
+
+	return ret;
+}
+
+static int cm3232_resume(struct device *dev)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+	struct cm3232_chip *chip = iio_priv(indio_dev);
+	struct i2c_client *client = chip->client;
+	int ret;
+
+	chip->regs_cmd &= ~CM3232_CMD_ALS_DISABLE;
+	ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+					chip->regs_cmd | CM3232_CMD_ALS_RESET);
+
+	return ret;
+}
+
 static const struct i2c_device_id cm3232_id[] = {
 	{"cm3232", 0},
 	{}
@@ -385,11 +484,23 @@ static const struct of_device_id cm3232_of_match[] = {
 	{}
 };
 
+static const struct acpi_device_id cm3232_acpi_match[] = {
+	{ "CPLM3232", 0},
+	{},
+};
+
+MODULE_DEVICE_TABLE(acpi, cm3232_acpi_match);
+
+static const struct dev_pm_ops cm3232_pm_ops = {
+	SET_SYSTEM_SLEEP_PM_OPS(cm3232_suspend, cm3232_resume)};
+
 static struct i2c_driver cm3232_driver = {
 	.driver = {
 		.name	= "cm3232",
-		.owner	= THIS_MODULE,
+		.acpi_match_table = ACPI_PTR(cm3232_acpi_match),
 		.of_match_table = of_match_ptr(cm3232_of_match),
+		.owner	= THIS_MODULE,
+		.pm	= &cm3232_pm_ops,
 	},
 	.id_table	= cm3232_id,
 	.probe		= cm3232_probe,
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux