2015-05-22 04:27:30

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 1/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Renamed company name.
- Removed cm32181_reg.
- Removed white space.
- Removed unused include files.
- Updated macro definitions.
- Renamed cm32181_chip pointer to chip.

Signed-off-by: Kevin Tsai <[email protected]>
---
drivers/iio/light/Kconfig | 4 +-
drivers/iio/light/cm32181.c | 126 +++++++++++++++++++++++---------------------
2 files changed, 67 insertions(+), 63 deletions(-)

diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index a437bad..583aa6a 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -39,11 +39,11 @@ config APDS9300

config CM32181
depends on I2C
- tristate "CM32181 driver"
+ tristate "Vishay Capella CM32181 driver"
help
Say Y here if you use cm32181.
This option enables ambient light sensor using
- Capella cm32181 device driver.
+ Vishay Capella cm32181 device driver.

To compile this driver as a module, choose M here:
the module will be called cm32181.
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 5d12ae54..0491d73 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -1,19 +1,15 @@
/*
- * Copyright (C) 2013 Capella Microsystems Inc.
- * Author: Kevin Tsai <[email protected]>
+ * Copyright (C) 2013-2015 Vishay Capella
*
* 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
* by the Free Software Foundation.
*/

-#include <linux/delay.h>
-#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/interrupt.h>
-#include <linux/regulator/consumer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/iio/events.h>
@@ -21,36 +17,43 @@

/* Registers Address */
#define CM32181_REG_ADDR_CMD 0x00
+#define CM32181_REG_ADDR_ALS_WH 0x01
+#define CM32181_REG_ADDR_ALS_WL 0x02
#define CM32181_REG_ADDR_ALS 0x04
#define CM32181_REG_ADDR_STATUS 0x06
#define CM32181_REG_ADDR_ID 0x07

/* Number of Configurable Registers */
-#define CM32181_CONF_REG_NUM 0x01
+#define CM32181_CONF_REG_NUM 3

/* CMD register */
-#define CM32181_CMD_ALS_ENABLE 0x00
-#define CM32181_CMD_ALS_DISABLE 0x01
-#define CM32181_CMD_ALS_INT_EN 0x02
+#define CM32181_CMD_ALS_DISABLE BIT(0)
+#define CM32181_CMD_ALS_INT_EN BIT(1)

#define CM32181_CMD_ALS_IT_SHIFT 6
-#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT)
+#define CM32181_CMD_ALS_IT_MASK (BIT(6) | BIT(7) | BIT(8) | BIT(9))
#define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT)

#define CM32181_CMD_ALS_SM_SHIFT 11
-#define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT)
+#define CM32181_CMD_ALS_SM_MASK (BIT(11) | BIT(12))
#define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT)

+#define CM32181_CMD_DEFAULT (CM32181_CMD_ALS_IT_DEFAULT | \
+ CM32181_CMD_ALS_SM_DEFAULT)
+
+/* ALS_WH register */
+#define CM32181_ALS_WH_DEFAULT 0xFFFF
+
+/* ALS_WL register */
+#define CM32181_ALS_WL_DEFAULT 0x0000
+
+/* Software parameters */
#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_DEFAULT 1000
#define CM32181_CALIBSCALE_RESOLUTION 1000
#define MLUX_PER_LUX 1000

-static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
- CM32181_REG_ADDR_CMD,
-};
-
static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
800000};
@@ -64,15 +67,15 @@ struct cm32181_chip {

/**
* cm32181_reg_init() - Initialize CM32181 registers
- * @cm32181: pointer of struct cm32181.
+ * @chip: pointer of struct cm32181_chip
*
* Initialize CM32181 ambient light sensor register to default values.
*
* Return: 0 for success; otherwise for error code.
*/
-static int cm32181_reg_init(struct cm32181_chip *cm32181)
+static int cm32181_reg_init(struct cm32181_chip *chip)
{
- struct i2c_client *client = cm32181->client;
+ struct i2c_client *client = chip->client;
int i;
s32 ret;

@@ -85,14 +88,15 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
return -ENODEV;

/* Default Values */
- cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE |
- CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
- cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
+ chip->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_DEFAULT;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = CM32181_ALS_WH_DEFAULT;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = CM32181_ALS_WL_DEFAULT;
+ chip->calibscale = CM32181_CALIBSCALE_DEFAULT;

/* Initialize registers*/
for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
- ret = i2c_smbus_write_word_data(client, cm32181_reg[i],
- cm32181->conf_regs[i]);
+ ret = i2c_smbus_write_word_data(client, i,
+ chip->conf_regs[i]);
if (ret < 0)
return ret;
}
@@ -101,20 +105,20 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
}

/**
- * cm32181_read_als_it() - Get sensor integration time (ms)
- * @cm32181: pointer of struct cm32181
- * @val2: pointer of int to load the als_it value.
+ * cm32181_read_als_it() - Get sensor integration time (ms)
+ * @chip: pointer of struct cm32181_chip
+ * @val2: pointer of int to load the als_it value.
*
- * Report the current integartion time by millisecond.
+ * Report the current integartion time by millisecond.
*
- * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
+ * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
*/
-static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
+static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
{
u16 als_it;
int i;

- als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
+ als_it = chip->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
@@ -129,16 +133,16 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)

/**
* cm32181_write_als_it() - Write sensor integration time
- * @cm32181: pointer of struct cm32181.
+ * @chip: pointer of struct cm32181_chip.
* @val: integration time by millisecond.
*
* Convert integration time (ms) to sensor value.
*
* Return: i2c_smbus_write_word_data command return value.
*/
-static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
+static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
{
- struct i2c_client *client = cm32181->client;
+ struct i2c_client *client = chip->client;
u16 als_it;
int ret, i, n;

@@ -152,35 +156,35 @@ static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
als_it = als_it_bits[i];
als_it <<= CM32181_CMD_ALS_IT_SHIFT;

- mutex_lock(&cm32181->lock);
- cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
+ mutex_lock(&chip->lock);
+ chip->conf_regs[CM32181_REG_ADDR_CMD] &=
~CM32181_CMD_ALS_IT_MASK;
- cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
+ chip->conf_regs[CM32181_REG_ADDR_CMD] |=
als_it;
ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
- cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
- mutex_unlock(&cm32181->lock);
+ chip->conf_regs[CM32181_REG_ADDR_CMD]);
+ mutex_unlock(&chip->lock);

return ret;
}

/**
* cm32181_get_lux() - report current lux value
- * @cm32181: pointer of struct cm32181.
+ * @chip: pointer of struct cm32181_chip
*
* Convert sensor raw data to lux. It depends on integration
* time and calibscale variable.
*
* Return: Positive value is lux, otherwise is error code.
*/
-static int cm32181_get_lux(struct cm32181_chip *cm32181)
+static int cm32181_get_lux(struct cm32181_chip *chip)
{
- struct i2c_client *client = cm32181->client;
+ struct i2c_client *client = chip->client;
int ret;
int als_it;
unsigned long lux;

- ret = cm32181_read_als_it(cm32181, &als_it);
+ ret = cm32181_read_als_it(chip, &als_it);
if (ret < 0)
return -EINVAL;

@@ -193,7 +197,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
return ret;

lux *= ret;
- lux *= cm32181->calibscale;
+ lux *= chip->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
lux /= MLUX_PER_LUX;

@@ -204,25 +208,25 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
}

static int cm32181_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2, long mask)
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
{
- struct cm32181_chip *cm32181 = iio_priv(indio_dev);
+ struct cm32181_chip *chip = iio_priv(indio_dev);
int ret;

switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
- ret = cm32181_get_lux(cm32181);
+ ret = cm32181_get_lux(chip);
if (ret < 0)
return ret;
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
- *val = cm32181->calibscale;
+ *val = chip->calibscale;
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
- ret = cm32181_read_als_it(cm32181, val2);
+ ret = cm32181_read_als_it(chip, val2);
return ret;
}

@@ -230,18 +234,18 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
}

static int cm32181_write_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int val, int val2, long mask)
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
{
- struct cm32181_chip *cm32181 = iio_priv(indio_dev);
+ struct cm32181_chip *chip = iio_priv(indio_dev);
int ret;

switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
- cm32181->calibscale = val;
+ chip->calibscale = val;
return val;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_write_als_it(cm32181, val2);
+ ret = cm32181_write_als_it(chip, val2);
return ret;
}

@@ -301,21 +305,21 @@ static const struct iio_info cm32181_info = {
static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- struct cm32181_chip *cm32181;
+ struct cm32181_chip *chip;
struct iio_dev *indio_dev;
int ret;

- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
if (!indio_dev) {
dev_err(&client->dev, "devm_iio_device_alloc failed\n");
return -ENOMEM;
}

- cm32181 = iio_priv(indio_dev);
+ chip = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
- cm32181->client = client;
+ chip->client = client;

- mutex_init(&cm32181->lock);
+ mutex_init(&chip->lock);
indio_dev->dev.parent = &client->dev;
indio_dev->channels = cm32181_channels;
indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
@@ -323,7 +327,7 @@ static int cm32181_probe(struct i2c_client *client,
indio_dev->name = id->name;
indio_dev->modes = INDIO_DIRECT_MODE;

- ret = cm32181_reg_init(cm32181);
+ ret = cm32181_reg_init(chip);
if (ret) {
dev_err(&client->dev,
"%s: register init failed\n",
@@ -360,7 +364,7 @@ static struct i2c_driver cm32181_driver = {
.of_match_table = of_match_ptr(cm32181_of_match),
.owner = THIS_MODULE,
},
- .id_table = cm32181_id,
+ .id_table = cm32181_id,
.probe = cm32181_probe,
};

--
1.8.3.1


2015-05-22 04:27:32

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 2/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Added cm32181_als_info structure.

Signed-off-by: Kevin Tsai <[email protected]>
---
drivers/iio/light/cm32181.c | 42 +++++++++++++++++++++++++++++++++---------
1 file changed, 33 insertions(+), 9 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 0491d73..6b11145 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -48,6 +48,7 @@
#define CM32181_ALS_WL_DEFAULT 0x0000

/* Software parameters */
+#define CM32181_HW_ID 0x81
#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_DEFAULT 1000
@@ -58,11 +59,31 @@ static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
800000};

+struct cm32181_als_info {
+ u8 hw_id;
+ u16 reg_cmd;
+ u16 reg_als_wh;
+ u16 reg_als_wl;
+ int calibscale;
+ int mlux_per_bit;
+ int mlux_per_bit_base_it;
+};
+
+static struct cm32181_als_info cm32181_als_info_default = {
+ .hw_id = CM32181_HW_ID,
+ .reg_cmd = CM32181_CMD_DEFAULT,
+ .reg_als_wh = CM32181_ALS_WH_DEFAULT,
+ .reg_als_wl = CM32181_ALS_WL_DEFAULT,
+ .calibscale = CM32181_CALIBSCALE_DEFAULT,
+ .mlux_per_bit = CM32181_MLUX_PER_BIT,
+ .mlux_per_bit_base_it = CM32181_MLUX_PER_BIT_BASE_IT,
+};
+
struct cm32181_chip {
struct i2c_client *client;
struct mutex lock;
+ struct cm32181_als_info *als_info;
u16 conf_regs[CM32181_CONF_REG_NUM];
- int calibscale;
};

/**
@@ -76,22 +97,25 @@ struct cm32181_chip {
static int cm32181_reg_init(struct cm32181_chip *chip)
{
struct i2c_client *client = chip->client;
+ struct cm32181_als_info *als_info;
int i;
s32 ret;

+ chip->als_info = &cm32181_als_info_default;
+ als_info = chip->als_info;
+
ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
if (ret < 0)
return ret;

/* check device ID */
- if ((ret & 0xFF) != 0x81)
+ if ((ret & 0xFF) != als_info->hw_id)
return -ENODEV;

/* Default Values */
- chip->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_DEFAULT;
- chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = CM32181_ALS_WH_DEFAULT;
- chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = CM32181_ALS_WL_DEFAULT;
- chip->calibscale = CM32181_CALIBSCALE_DEFAULT;
+ chip->conf_regs[CM32181_REG_ADDR_CMD] = als_info->reg_cmd;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = als_info->reg_als_wh;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = als_info->reg_als_wl;

/* Initialize registers*/
for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
@@ -197,7 +221,7 @@ static int cm32181_get_lux(struct cm32181_chip *chip)
return ret;

lux *= ret;
- lux *= chip->calibscale;
+ lux *= chip->als_info->calibscale;
lux /= CM32181_CALIBSCALE_RESOLUTION;
lux /= MLUX_PER_LUX;

@@ -222,7 +246,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_CALIBSCALE:
- *val = chip->calibscale;
+ *val = chip->als_info->calibscale;
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
@@ -242,7 +266,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,

switch (mask) {
case IIO_CHAN_INFO_CALIBSCALE:
- chip->calibscale = val;
+ chip->als_info->calibscale = val;
return val;
case IIO_CHAN_INFO_INT_TIME:
ret = cm32181_write_als_it(chip, val2);
--
1.8.3.1

2015-05-22 04:27:40

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 3/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Added Power Management support.
- Added driver remove routine.

Signed-off-by: Kevin Tsai <[email protected]>
---
drivers/iio/light/cm32181.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 6b11145..9bc3e1f 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -370,11 +370,51 @@ static int cm32181_probe(struct i2c_client *client,
return 0;
}

+static int cm32181_remove(struct i2c_client *client)
+{
+ i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
+ CM32181_CMD_ALS_DISABLE);
+
+ return 0;
+}
+
static const struct i2c_device_id cm32181_id[] = {
{ "cm32181", 0 },
{ }
};

+#ifdef CONFIG_PM_SLEEP
+static int cm32181_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct cm32181_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
+ CM32181_CMD_ALS_DISABLE);
+
+ return ret;
+}
+
+static int cm32181_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct cm32181_chip *chip = iio_priv(indio_dev);
+ struct i2c_client *client = chip->client;
+ int ret;
+
+ chip->conf_regs[CM32181_REG_ADDR_CMD] &= ~CM32181_CMD_ALS_DISABLE;
+ ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
+ chip->conf_regs[CM32181_REG_ADDR_CMD]);
+
+ return ret;
+}
+
+static const struct dev_pm_ops cm32181_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cm32181_suspend, cm32181_resume)};
+#endif
+
MODULE_DEVICE_TABLE(i2c, cm32181_id);

static const struct of_device_id cm32181_of_match[] = {
@@ -387,9 +427,13 @@ static struct i2c_driver cm32181_driver = {
.name = "cm32181",
.of_match_table = of_match_ptr(cm32181_of_match),
.owner = THIS_MODULE,
+#ifdef CONFIG_PM_SLEEP
+ .pm = &cm32181_pm_ops,
+#endif
},
.id_table = cm32181_id,
.probe = cm32181_probe,
+ .remove = cm32181_remove,
};

module_i2c_driver(cm32181_driver);
--
1.8.3.1

2015-05-22 04:27:46

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 4/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Replaced als_it_bits and als_it_value by cm32181_als_it_scale.

Signed-off-by: Kevin Tsai <[email protected]>
---
drivers/iio/light/cm32181.c | 95 ++++++++++++++++++++++++++++++++++++---------
1 file changed, 76 insertions(+), 19 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 9bc3e1f..54bf0cb 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -53,12 +53,25 @@
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
#define CM32181_CALIBSCALE_DEFAULT 1000
#define CM32181_CALIBSCALE_RESOLUTION 1000
-#define MLUX_PER_LUX 1000
+#define CM32181_MLUX_PER_LUX 1000

static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
800000};

+static const struct {
+ int val;
+ int val2;
+ u16 it;
+} cm32181_als_it_scales[] = {
+ {0, 25000, 12}, /* 0.025000 */
+ {0, 50000, 8}, /* 0.050000 */
+ {0, 100000, 0}, /* 0.100000 */
+ {0, 200000, 1}, /* 0.200000 */
+ {0, 400000, 2}, /* 0.400000 */
+ {0, 800000, 3}, /* 0.800000 */
+};
+
struct cm32181_als_info {
u8 hw_id;
u16 reg_cmd;
@@ -129,15 +142,16 @@ static int cm32181_reg_init(struct cm32181_chip *chip)
}

/**
- * cm32181_read_als_it() - Get sensor integration time (ms)
+ * cm32181_read_als_it() - Get sensor integration time
* @chip: pointer of struct cm32181_chip
- * @val2: pointer of int to load the als_it value.
+ * @val: pointer of int to load the integration (sec)
+ * @val2: pointer of int to load the integration time (microsecond)
*
* Report the current integartion time by millisecond.
*
* Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
*/
-static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
+static int cm32181_read_als_it(struct cm32181_chip *chip, int *val, int *val2)
{
u16 als_it;
int i;
@@ -145,9 +159,10 @@ static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
als_it = chip->conf_regs[CM32181_REG_ADDR_CMD];
als_it &= CM32181_CMD_ALS_IT_MASK;
als_it >>= CM32181_CMD_ALS_IT_SHIFT;
- for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
- if (als_it == als_it_bits[i]) {
- *val2 = als_it_value[i];
+ for (i = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++) {
+ if (als_it == cm32181_als_it_scales[i].it) {
+ *val = cm32181_als_it_scales[i].val;
+ *val2 = cm32181_als_it_scales[i].val2;
return IIO_VAL_INT_PLUS_MICRO;
}
}
@@ -158,15 +173,44 @@ static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
/**
* cm32181_write_als_it() - Write sensor integration time
* @chip: pointer of struct cm32181_chip.
- * @val: integration time by millisecond.
+ * @val: integration time in second.
+ * @val2: integration time in microsecond.
*
* Convert integration time (ms) to sensor value.
*
* Return: i2c_smbus_write_word_data command return value.
*/
-static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
+static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
{
struct i2c_client *client = chip->client;
+ u16 als_it, cmd;
+ int i;
+ s32 ret;
+
+ for (i = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++) {
+ if (val == cm32181_als_it_scales[i].val &&
+ val2 == cm32181_als_it_scales[i].val2) {
+
+ als_it = cm32181_als_it_scales[i].it;
+ als_it <<= CM32181_CMD_ALS_IT_SHIFT;
+
+ cmd = chip->conf_regs[CM32181_REG_ADDR_CMD];
+ cmd &= ~CM32181_CMD_ALS_IT_MASK;
+ cmd |= als_it;
+ ret = i2c_smbus_write_word_data(client,
+ CM32181_REG_ADDR_CMD,
+ cmd);
+ if (ret < 0)
+ return ret;
+
+ chip->conf_regs[CM32181_REG_ADDR_CMD] = cmd;
+ return 0;
+ }
+ }
+ return -EINVAL;
+
+/*
+ struct i2c_client *client = chip->client;
u16 als_it;
int ret, i, n;

@@ -190,6 +234,7 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
mutex_unlock(&chip->lock);

return ret;
+*/
}

/**
@@ -204,26 +249,29 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
static int cm32181_get_lux(struct cm32181_chip *chip)
{
struct i2c_client *client = chip->client;
+ struct cm32181_als_info *als_info = chip->als_info;
int ret;
+ int val, val2;
int als_it;
- unsigned long lux;
+ u64 lux;

- ret = cm32181_read_als_it(chip, &als_it);
+ ret = cm32181_read_als_it(chip, &val, &val2);
if (ret < 0)
return -EINVAL;
+ als_it = val * 1000000 + val2;

- lux = CM32181_MLUX_PER_BIT;
- lux *= CM32181_MLUX_PER_BIT_BASE_IT;
- lux /= als_it;
+ lux = (__force u64)als_info->mlux_per_bit;
+ lux *= als_info->mlux_per_bit_base_it;
+ lux = div_u64(lux, als_it);

ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
if (ret < 0)
return ret;

lux *= ret;
- lux *= chip->als_info->calibscale;
- lux /= CM32181_CALIBSCALE_RESOLUTION;
- lux /= MLUX_PER_LUX;
+ lux *= als_info->calibscale;
+ lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION);
+ lux = div_u64(lux, CM32181_MLUX_PER_LUX);

if (lux > 0xFFFF)
lux = 0xFFFF;
@@ -250,7 +298,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
return IIO_VAL_INT;
case IIO_CHAN_INFO_INT_TIME:
*val = 0;
- ret = cm32181_read_als_it(chip, val2);
+ ret = cm32181_read_als_it(chip, val, val2);
return ret;
}

@@ -269,7 +317,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
chip->als_info->calibscale = val;
return val;
case IIO_CHAN_INFO_INT_TIME:
- ret = cm32181_write_als_it(chip, val2);
+ ret = cm32181_write_als_it(chip, val, val2);
return ret;
}

@@ -289,12 +337,21 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
static ssize_t cm32181_get_it_available(struct device *dev,
struct device_attribute *attr, char *buf)
{
+ int i, len;
+
+ for (i = 0, len = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
+ cm32181_als_it_scales[i].val,
+ cm32181_als_it_scales[i].val2);
+ return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
+/*
int i, n, len;

n = ARRAY_SIZE(als_it_value);
for (i = 0, len = 0; i < n; i++)
len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
return len + sprintf(buf + len, "\n");
+*/
}

static const struct iio_chan_spec cm32181_channels[] = {
--
1.8.3.1

2015-05-22 04:27:49

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 5/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Added Device Tree support.

Signed-off-by: Kevin Tsai <[email protected]>
---
.../devicetree/bindings/iio/light/cm32181.txt | 33 +++++++++++
MAINTAINERS | 12 ++--
drivers/iio/light/cm32181.c | 66 ++++++++++------------
3 files changed, 70 insertions(+), 41 deletions(-)
create mode 100644 Documentation/devicetree/bindings/iio/light/cm32181.txt

diff --git a/Documentation/devicetree/bindings/iio/light/cm32181.txt b/Documentation/devicetree/bindings/iio/light/cm32181.txt
new file mode 100644
index 0000000..b81a3e3
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/light/cm32181.txt
@@ -0,0 +1,33 @@
+* Vishay Capella CM32181 Ambient Light sensor
+
+Required properties:
+- compatible: must be "capella,cm32181"
+- reg: the I2C address of the device
+
+Optional properties:
+- capella,hw_id: hardware device id.
+- capella,reg_cmd: command register initialization.
+- capella,reg_als_wh: high threshold register initialization.
+- capella,reg_als_wl: low threshold register initialization.
+- capella,calibscale: calibrated factor with 10^-5 notation.
+- capella,hw_id: hardware device id.
+- capella,mlux_per_bit: millilux per bit under the default IT.
+- capella,thd_percent: threshold percentage change to trigger.
+
+Example:
+
+cm32181@10 {
+ compatible = "capella,cm32181";
+ reg = <0x10>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <17 0>;
+
+ capella,hw_id = <0x81>;
+ capella,reg_cmd = <0x04>;
+ capella,reg_als_wh = <0xFFFF>;
+ capella,reg_als_wl = <0x0000>;
+ capella,calibscale = <10000>;
+ capella,mlux_per_bit = <5>;
+ capella,thd_percent = <5>;
+};
+
diff --git a/MAINTAINERS b/MAINTAINERS
index f8e0afb..ee6a8f6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2431,12 +2431,6 @@ F: security/capability.c
F: security/commoncap.c
F: kernel/capability.c

-CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER
-M: Kevin Tsai <[email protected]>
-S: Maintained
-F: drivers/iio/light/cm*
-F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
-
CC2520 IEEE-802.15.4 RADIO DRIVER
M: Varka Bhadram <[email protected]>
L: [email protected]
@@ -10610,6 +10604,12 @@ L: [email protected]
S: Maintained
F: drivers/net/ethernet/via/via-velocity.*

+VISHAY CAPELLA LIGHT SENSOR DRIVER
+M: Kevin Tsai <[email protected]>
+S: Maintained
+F: drivers/iio/light/cm*
+F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
+
VIVID VIRTUAL VIDEO DRIVER
M: Hans Verkuil <[email protected]>
L: [email protected]
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index 54bf0cb..b7abd46 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -51,6 +51,7 @@
#define CM32181_HW_ID 0x81
#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
+#define CM32181_THD_PERCENT 5 /* 0 for polling mode */
#define CM32181_CALIBSCALE_DEFAULT 1000
#define CM32181_CALIBSCALE_RESOLUTION 1000
#define CM32181_MLUX_PER_LUX 1000
@@ -80,6 +81,7 @@ struct cm32181_als_info {
int calibscale;
int mlux_per_bit;
int mlux_per_bit_base_it;
+ int thd_percent;
};

static struct cm32181_als_info cm32181_als_info_default = {
@@ -90,6 +92,7 @@ static struct cm32181_als_info cm32181_als_info_default = {
.calibscale = CM32181_CALIBSCALE_DEFAULT,
.mlux_per_bit = CM32181_MLUX_PER_BIT,
.mlux_per_bit_base_it = CM32181_MLUX_PER_BIT_BASE_IT,
+ .thd_percent = CM32181_THD_PERCENT,
};

struct cm32181_chip {
@@ -99,6 +102,30 @@ struct cm32181_chip {
u16 conf_regs[CM32181_CONF_REG_NUM];
};

+#ifdef CONFIG_OF
+void cm32181_parse_dt(struct cm32181_chip *chip)
+{
+ struct device_node *dn = chip->client->dev.of_node;
+ struct cm32181_als_info *als_info = chip->als_info;
+ u32 temp_val;
+
+ if (!of_property_read_u32(dn, "capella,hw_id", &temp_val))
+ als_info->hw_id = (uint8_t)temp_val;
+ if (!of_property_read_u32(dn, "capella,reg_cmd", &temp_val))
+ als_info->reg_cmd = (uint16_t)temp_val;
+ if (!of_property_read_u32(dn, "capella,reg_als_wh", &temp_val))
+ als_info->reg_als_wh = (uint16_t)temp_val;
+ if (!of_property_read_u32(dn, "capella,reg_als_wl", &temp_val))
+ als_info->reg_als_wl = (uint16_t)temp_val;
+ if (!of_property_read_u32(dn, "capella,calibscale", &temp_val))
+ als_info->calibscale = (int)temp_val;
+ if (!of_property_read_u32(dn, "capella,mlux_per_bit", &temp_val))
+ als_info->mlux_per_bit = (int)temp_val;
+ if (!of_property_read_u32(dn, "capella,thd_percent", &temp_val))
+ als_info->thd_percent = (int)temp_val;
+}
+#endif
+
/**
* cm32181_reg_init() - Initialize CM32181 registers
* @chip: pointer of struct cm32181_chip
@@ -116,6 +143,10 @@ static int cm32181_reg_init(struct cm32181_chip *chip)

chip->als_info = &cm32181_als_info_default;
als_info = chip->als_info;
+#ifdef CONFIG_OF
+ if (client->dev.of_node)
+ cm32181_parse_dt(chip);
+#endif

ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
if (ret < 0)
@@ -208,33 +239,6 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
}
}
return -EINVAL;
-
-/*
- struct i2c_client *client = chip->client;
- u16 als_it;
- int ret, i, n;
-
- n = ARRAY_SIZE(als_it_value);
- for (i = 0; i < n; i++)
- if (val <= als_it_value[i])
- break;
- if (i >= n)
- i = n - 1;
-
- als_it = als_it_bits[i];
- als_it <<= CM32181_CMD_ALS_IT_SHIFT;
-
- mutex_lock(&chip->lock);
- chip->conf_regs[CM32181_REG_ADDR_CMD] &=
- ~CM32181_CMD_ALS_IT_MASK;
- chip->conf_regs[CM32181_REG_ADDR_CMD] |=
- als_it;
- ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
- chip->conf_regs[CM32181_REG_ADDR_CMD]);
- mutex_unlock(&chip->lock);
-
- return ret;
-*/
}

/**
@@ -344,14 +348,6 @@ static ssize_t cm32181_get_it_available(struct device *dev,
cm32181_als_it_scales[i].val,
cm32181_als_it_scales[i].val2);
return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
-/*
- int i, n, len;
-
- n = ARRAY_SIZE(als_it_value);
- for (i = 0, len = 0; i < n; i++)
- len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
- return len + sprintf(buf + len, "\n");
-*/
}

static const struct iio_chan_spec cm32181_channels[] = {
--
1.8.3.1

2015-05-22 04:27:56

by Kevin Tsai

[permalink] [raw]
Subject: [PATCH 6/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

- Added Interrupt support.

Signed-off-by: Kevin Tsai <[email protected]>
---
drivers/iio/light/cm32181.c | 156 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 153 insertions(+), 3 deletions(-)

diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index b7abd46..1ae32a0 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -47,6 +47,10 @@
/* ALS_WL register */
#define CM32181_ALS_WL_DEFAULT 0x0000

+/* STATUS register */
+#define CM32181_STATUS_ALS_IF_L BIT(15)
+#define CM32181_STATUS_ALS_IF_H BIT(14)
+
/* Software parameters */
#define CM32181_HW_ID 0x81
#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
@@ -122,7 +126,8 @@ void cm32181_parse_dt(struct cm32181_chip *chip)
if (!of_property_read_u32(dn, "capella,mlux_per_bit", &temp_val))
als_info->mlux_per_bit = (int)temp_val;
if (!of_property_read_u32(dn, "capella,thd_percent", &temp_val))
- als_info->thd_percent = (int)temp_val;
+ if (((int)temp_val >= 0) && ((int)temp_val < 100))
+ als_info->thd_percent = (int)temp_val;
}
#endif

@@ -173,6 +178,63 @@ static int cm32181_reg_init(struct cm32181_chip *chip)
}

/**
+ * cm32181_interrupt() - enable/disable interrupt
+ * @chip: pointer of struct cm32181_chip
+ * @ int_en: truen for enable; false for disable
+ *
+ * Enable/disable interrupt mode
+ *
+ * Return: 0 for success; otherwise for error code.
+ */
+static int cm32181_interrupt(struct cm32181_chip *cm32181, bool int_en)
+{
+ int ret;
+
+ mutex_lock(&cm32181->lock);
+ if (int_en)
+ cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
+ CM32181_CMD_ALS_INT_EN;
+ else
+ cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
+ ~CM32181_CMD_ALS_INT_EN;
+
+ ret = i2c_smbus_write_word_data(cm32181->client,
+ CM32181_REG_ADDR_CMD,
+ cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
+ mutex_unlock(&cm32181->lock);
+ return ret;
+}
+
+static irqreturn_t cm32181_irq_handler(int irq, void *data)
+{
+ struct iio_dev *indio_dev = data;
+ struct cm32181_chip *cm32181 = iio_priv(indio_dev);
+ struct i2c_client *client = cm32181->client;
+ int ret;
+ u64 ev_code;
+
+ ret = i2c_smbus_read_word_data(cm32181->client,
+ CM32181_REG_ADDR_STATUS);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "%s: Data read failed: %d\n", __func__, ret);
+ return IRQ_NONE;
+ }
+
+ if (!(ret & (CM32181_STATUS_ALS_IF_H | CM32181_STATUS_ALS_IF_L)))
+ return IRQ_NONE;
+
+ ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
+ 0,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_EITHER);
+
+ iio_push_event(indio_dev, ev_code, iio_get_time_ns());
+
+ return IRQ_HANDLED;
+}
+
+/**
* cm32181_read_als_it() - Get sensor integration time
* @chip: pointer of struct cm32181_chip
* @val: pointer of int to load the integration (sec)
@@ -242,6 +304,51 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
}

/**
+ * cm32181_ials_read() - read ALS raw data
+ * @chip: pointer of struct cm32181_chip
+ *
+ * Read the ALS raw data and update the interrupt threshold windows.
+ *
+ * Return: Positive value is ALS raw data, otherwise is error code.
+ */
+static int cm32181_als_read(struct cm32181_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ struct cm32181_als_info *als_info = chip->als_info;
+ u16 als, wh, wl, delta;
+ int ret;
+
+ ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
+ if (ret < 0)
+ return ret;
+
+ als = (u16)ret;
+
+ if (als_info->thd_percent) {
+ delta = als * als_info->thd_percent / 100;
+ if (delta < 3)
+ delta = 3;
+ wh = (als + delta > 0xFFFF) ? 0xFFFF : (als + delta);
+ wl = (als < delta) ? 0 : (als - delta);
+
+ ret = i2c_smbus_write_word_data(client,
+ CM32181_REG_ADDR_ALS_WH, wh);
+ if (ret < 0)
+ return ret;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = wh;
+
+ ret = i2c_smbus_write_word_data(client,
+ CM32181_REG_ADDR_ALS_WL, wl);
+ if (ret < 0)
+ return ret;
+ chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = wl;
+ ret = als;
+ }
+
+ return ret;
+}
+
+/**
* cm32181_get_lux() - report current lux value
* @chip: pointer of struct cm32181_chip
*
@@ -252,7 +359,6 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
*/
static int cm32181_get_lux(struct cm32181_chip *chip)
{
- struct i2c_client *client = chip->client;
struct cm32181_als_info *als_info = chip->als_info;
int ret;
int val, val2;
@@ -268,7 +374,7 @@ static int cm32181_get_lux(struct cm32181_chip *chip)
lux *= als_info->mlux_per_bit_base_it;
lux = div_u64(lux, als_it);

- ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
+ ret = cm32181_als_read(chip);
if (ret < 0)
return ret;

@@ -350,6 +456,15 @@ static ssize_t cm32181_get_it_available(struct device *dev,
return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
}

+static const struct iio_event_spec cm32181_event_spec[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE),
+ }
+};
+
static const struct iio_chan_spec cm32181_channels[] = {
{
.type = IIO_LIGHT,
@@ -357,6 +472,8 @@ static const struct iio_chan_spec cm32181_channels[] = {
BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_CALIBSCALE) |
BIT(IIO_CHAN_INFO_INT_TIME),
+ .event_spec = cm32181_event_spec,
+ .num_event_specs = ARRAY_SIZE(cm32181_event_spec),
}
};

@@ -383,6 +500,7 @@ static int cm32181_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct cm32181_chip *chip;
+ struct cm32181_als_info *als_info;
struct iio_dev *indio_dev;
int ret;

@@ -412,11 +530,35 @@ static int cm32181_probe(struct i2c_client *client,
return ret;
}

+ als_info = chip->als_info;
+ if (als_info->thd_percent && client->irq) {
+ ret = request_threaded_irq(client->irq, NULL,
+ cm32181_irq_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: request irq failed\n",
+ __func__);
+ return ret;
+ }
+
+ ret = cm32181_interrupt(chip, true);
+ if (ret) {
+ als_info->thd_percent = 0;
+ dev_err(&client->dev,
+ "%s: failed to enable interrupt\n", __func__);
+ }
+ } else {
+ als_info->thd_percent = 0; /* Polling Mode */
+ }
+
ret = devm_iio_device_register(&client->dev, indio_dev);
if (ret) {
dev_err(&client->dev,
"%s: regist device failed\n",
__func__);
+ if (als_info->thd_percent)
+ free_irq(client->irq, indio_dev);
return ret;
}

@@ -425,9 +567,17 @@ static int cm32181_probe(struct i2c_client *client,

static int cm32181_remove(struct i2c_client *client)
{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct cm32181_chip *chip = iio_priv(indio_dev);
+ struct cm32181_als_info *als_info = chip->als_info;
+
+ cm32181_interrupt(chip, false);
i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
CM32181_CMD_ALS_DISABLE);

+ if (als_info->thd_percent)
+ free_irq(client->irq, indio_dev);
+
return 0;
}

--
1.8.3.1

2015-05-22 04:37:07

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH 1/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On Thu, 2015-05-21 at 21:19 -0700, Kevin Tsai wrote:
> - Renamed company name.
> - Removed cm32181_reg.
> - Removed white space.
> - Removed unused include files.
> - Updated macro definitions.
> - Renamed cm32181_chip pointer to chip.

Hi Kevin,

Please don't use the same title for multiple patches.

It'd be better if these 6 patches were titled something like

1/6 cm32181: Neatening
2/6 cm32181: Add cm32181_als_info
3/6: cm32181: Add power management support
4/6: cm32181: Add and use cm32181_als_it_scale
5/6: cm32181: Add device tree support
6/6: cm32181: Add interrupt suppor

It's

2015-05-22 04:39:17

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH 1/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

(meh, bad mousing sent the first reply too soon)

It'd also be better if this series had a cover letter
so that could be replied to and added as a merge header
instead of having to ack/nack individual patches.

2015-05-23 10:57:59

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 1/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Renamed company name.
> - Removed cm32181_reg.
> - Removed white space.
> - Removed unused include files.
> - Updated macro definitions.
> - Renamed cm32181_chip pointer to chip.
>
> Signed-off-by: Kevin Tsai <[email protected]>

Obviously this whole series needs better patch titles.

Split this up into little patches doing one thing.

You may end up with a huge series, but every step will be trivial
and obvious which makes for really easy review!

There's a lot of churn in here to do that chip rename that I'm not
sure really matters, but it also doesn't do any harm so if you
really want to do it fair enough... That patch also obscures various
other changes so definitely needs to be done on it's own.

> ---
> drivers/iio/light/Kconfig | 4 +-
> drivers/iio/light/cm32181.c | 126 +++++++++++++++++++++++---------------------
> 2 files changed, 67 insertions(+), 63 deletions(-)
>
> diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
> index a437bad..583aa6a 100644
> --- a/drivers/iio/light/Kconfig
> +++ b/drivers/iio/light/Kconfig
> @@ -39,11 +39,11 @@ config APDS9300
>
> config CM32181
> depends on I2C
> - tristate "CM32181 driver"
> + tristate "Vishay Capella CM32181 driver"
> help
> Say Y here if you use cm32181.
> This option enables ambient light sensor using
> - Capella cm32181 device driver.
> + Vishay Capella cm32181 device driver.
>
> To compile this driver as a module, choose M here:
> the module will be called cm32181.
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index 5d12ae54..0491d73 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -1,19 +1,15 @@
> /*
> - * Copyright (C) 2013 Capella Microsystems Inc.
> - * Author: Kevin Tsai <[email protected]>
> + * Copyright (C) 2013-2015 Vishay Capella
> *
> * 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
> * by the Free Software Foundation.
> */
>
> -#include <linux/delay.h>
> -#include <linux/err.h>
Umm. -ENODEV etc come from here. It might be included via another
header, but that doesn't mean it should not also be explicitly listed
here.

> #include <linux/i2c.h>
> #include <linux/mutex.h>
> #include <linux/module.h>
> #include <linux/interrupt.h>
> -#include <linux/regulator/consumer.h>
> #include <linux/iio/iio.h>
> #include <linux/iio/sysfs.h>
> #include <linux/iio/events.h>
> @@ -21,36 +17,43 @@
>
> /* Registers Address */
> #define CM32181_REG_ADDR_CMD 0x00
> +#define CM32181_REG_ADDR_ALS_WH 0x01
> +#define CM32181_REG_ADDR_ALS_WL 0x02
> #define CM32181_REG_ADDR_ALS 0x04
> #define CM32181_REG_ADDR_STATUS 0x06
> #define CM32181_REG_ADDR_ID 0x07
>
> /* Number of Configurable Registers */
> -#define CM32181_CONF_REG_NUM 0x01
> +#define CM32181_CONF_REG_NUM 3
>
> /* CMD register */
> -#define CM32181_CMD_ALS_ENABLE 0x00
> -#define CM32181_CMD_ALS_DISABLE 0x01
> -#define CM32181_CMD_ALS_INT_EN 0x02
> +#define CM32181_CMD_ALS_DISABLE BIT(0)
> +#define CM32181_CMD_ALS_INT_EN BIT(1)
>
> #define CM32181_CMD_ALS_IT_SHIFT 6
> -#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT)
> +#define CM32181_CMD_ALS_IT_MASK (BIT(6) | BIT(7) | BIT(8) | BIT(9))
Use genmask
> #define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT)
>
> #define CM32181_CMD_ALS_SM_SHIFT 11
> -#define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT)
> +#define CM32181_CMD_ALS_SM_MASK (BIT(11) | BIT(12))
again genmask
> #define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT)
>
> +#define CM32181_CMD_DEFAULT (CM32181_CMD_ALS_IT_DEFAULT | \
> + CM32181_CMD_ALS_SM_DEFAULT)
> +
> +/* ALS_WH register */
> +#define CM32181_ALS_WH_DEFAULT 0xFFFF
> +
> +/* ALS_WL register */
> +#define CM32181_ALS_WL_DEFAULT 0x0000
> +
> +/* Software parameters */
> #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
> #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
> #define CM32181_CALIBSCALE_DEFAULT 1000
> #define CM32181_CALIBSCALE_RESOLUTION 1000
> #define MLUX_PER_LUX 1000
>
> -static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
> - CM32181_REG_ADDR_CMD,
> -};
> -
> static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
> static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
> 800000};
> @@ -64,15 +67,15 @@ struct cm32181_chip {
>
> /**
> * cm32181_reg_init() - Initialize CM32181 registers
> - * @cm32181: pointer of struct cm32181.
> + * @chip: pointer of struct cm32181_chip
> *
> * Initialize CM32181 ambient light sensor register to default values.
> *
> * Return: 0 for success; otherwise for error code.
> */
> -static int cm32181_reg_init(struct cm32181_chip *cm32181)
> +static int cm32181_reg_init(struct cm32181_chip *chip)
> {
> - struct i2c_client *client = cm32181->client;
> + struct i2c_client *client = chip->client;
> int i;
> s32 ret;
>
> @@ -85,14 +88,15 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
> return -ENODEV;
>
> /* Default Values */
> - cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE |
> - CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
> - cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
> + chip->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_DEFAULT;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = CM32181_ALS_WH_DEFAULT;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = CM32181_ALS_WL_DEFAULT;
> + chip->calibscale = CM32181_CALIBSCALE_DEFAULT;
>
> /* Initialize registers*/
> for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
> - ret = i2c_smbus_write_word_data(client, cm32181_reg[i],
> - cm32181->conf_regs[i]);
> + ret = i2c_smbus_write_word_data(client, i,
> + chip->conf_regs[i]);
> if (ret < 0)
> return ret;
> }
> @@ -101,20 +105,20 @@ static int cm32181_reg_init(struct cm32181_chip *cm32181)
> }
>
> /**
> - * cm32181_read_als_it() - Get sensor integration time (ms)
> - * @cm32181: pointer of struct cm32181
> - * @val2: pointer of int to load the als_it value.
> + * cm32181_read_als_it() - Get sensor integration time (ms)
> + * @chip: pointer of struct cm32181_chip
> + * @val2: pointer of int to load the als_it value.
> *
> - * Report the current integartion time by millisecond.
> + * Report the current integartion time by millisecond.
> *
> - * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
> + * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
> */
> -static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
> +static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
> {
> u16 als_it;
> int i;
>
> - als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
> + als_it = chip->conf_regs[CM32181_REG_ADDR_CMD];
> als_it &= CM32181_CMD_ALS_IT_MASK;
> als_it >>= CM32181_CMD_ALS_IT_SHIFT;
> for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
> @@ -129,16 +133,16 @@ static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
>
> /**
> * cm32181_write_als_it() - Write sensor integration time
> - * @cm32181: pointer of struct cm32181.
> + * @chip: pointer of struct cm32181_chip.
> * @val: integration time by millisecond.
> *
> * Convert integration time (ms) to sensor value.
> *
> * Return: i2c_smbus_write_word_data command return value.
> */
> -static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
> +static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
> {
> - struct i2c_client *client = cm32181->client;
> + struct i2c_client *client = chip->client;
> u16 als_it;
> int ret, i, n;
>
> @@ -152,35 +156,35 @@ static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
> als_it = als_it_bits[i];
> als_it <<= CM32181_CMD_ALS_IT_SHIFT;
>
> - mutex_lock(&cm32181->lock);
> - cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
> + mutex_lock(&chip->lock);
> + chip->conf_regs[CM32181_REG_ADDR_CMD] &=
> ~CM32181_CMD_ALS_IT_MASK;
> - cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
> + chip->conf_regs[CM32181_REG_ADDR_CMD] |=
> als_it;
> ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> - cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
> - mutex_unlock(&cm32181->lock);
> + chip->conf_regs[CM32181_REG_ADDR_CMD]);
> + mutex_unlock(&chip->lock);
>
> return ret;
> }
>
> /**
> * cm32181_get_lux() - report current lux value
> - * @cm32181: pointer of struct cm32181.
> + * @chip: pointer of struct cm32181_chip
> *
> * Convert sensor raw data to lux. It depends on integration
> * time and calibscale variable.
> *
> * Return: Positive value is lux, otherwise is error code.
> */
> -static int cm32181_get_lux(struct cm32181_chip *cm32181)
> +static int cm32181_get_lux(struct cm32181_chip *chip)
> {
> - struct i2c_client *client = cm32181->client;
> + struct i2c_client *client = chip->client;
> int ret;
> int als_it;
> unsigned long lux;
>
> - ret = cm32181_read_als_it(cm32181, &als_it);
> + ret = cm32181_read_als_it(chip, &als_it);
> if (ret < 0)
> return -EINVAL;
>
> @@ -193,7 +197,7 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
> return ret;
>
> lux *= ret;
> - lux *= cm32181->calibscale;
> + lux *= chip->calibscale;
> lux /= CM32181_CALIBSCALE_RESOLUTION;
> lux /= MLUX_PER_LUX;
>
> @@ -204,25 +208,25 @@ static int cm32181_get_lux(struct cm32181_chip *cm32181)
> }
>
> static int cm32181_read_raw(struct iio_dev *indio_dev,
> - struct iio_chan_spec const *chan,
> - int *val, int *val2, long mask)
> + struct iio_chan_spec const *chan,
> + int *val, int *val2, long mask)
> {
> - struct cm32181_chip *cm32181 = iio_priv(indio_dev);
> + struct cm32181_chip *chip = iio_priv(indio_dev);
> int ret;
>
> switch (mask) {
> case IIO_CHAN_INFO_PROCESSED:
> - ret = cm32181_get_lux(cm32181);
> + ret = cm32181_get_lux(chip);
> if (ret < 0)
> return ret;
> *val = ret;
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_CALIBSCALE:
> - *val = cm32181->calibscale;
> + *val = chip->calibscale;
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_INT_TIME:
> *val = 0;
> - ret = cm32181_read_als_it(cm32181, val2);
> + ret = cm32181_read_als_it(chip, val2);
> return ret;
> }
>
> @@ -230,18 +234,18 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
> }
>
> static int cm32181_write_raw(struct iio_dev *indio_dev,
> - struct iio_chan_spec const *chan,
> - int val, int val2, long mask)
> + struct iio_chan_spec const *chan,
> + int val, int val2, long mask)
> {
> - struct cm32181_chip *cm32181 = iio_priv(indio_dev);
> + struct cm32181_chip *chip = iio_priv(indio_dev);
> int ret;
>
> switch (mask) {
> case IIO_CHAN_INFO_CALIBSCALE:
> - cm32181->calibscale = val;
> + chip->calibscale = val;
> return val;
> case IIO_CHAN_INFO_INT_TIME:
> - ret = cm32181_write_als_it(cm32181, val2);
> + ret = cm32181_write_als_it(chip, val2);
> return ret;
> }
>
> @@ -301,21 +305,21 @@ static const struct iio_info cm32181_info = {
> static int cm32181_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> {
> - struct cm32181_chip *cm32181;
> + struct cm32181_chip *chip;
> struct iio_dev *indio_dev;
> int ret;
>
> - indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
> + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
> if (!indio_dev) {
> dev_err(&client->dev, "devm_iio_device_alloc failed\n");
> return -ENOMEM;
> }
>
> - cm32181 = iio_priv(indio_dev);
> + chip = iio_priv(indio_dev);
> i2c_set_clientdata(client, indio_dev);
> - cm32181->client = client;
> + chip->client = client;
>
> - mutex_init(&cm32181->lock);
> + mutex_init(&chip->lock);
> indio_dev->dev.parent = &client->dev;
> indio_dev->channels = cm32181_channels;
> indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
> @@ -323,7 +327,7 @@ static int cm32181_probe(struct i2c_client *client,
> indio_dev->name = id->name;
> indio_dev->modes = INDIO_DIRECT_MODE;
>
> - ret = cm32181_reg_init(cm32181);
> + ret = cm32181_reg_init(chip);
> if (ret) {
> dev_err(&client->dev,
> "%s: register init failed\n",
> @@ -360,7 +364,7 @@ static struct i2c_driver cm32181_driver = {
> .of_match_table = of_match_ptr(cm32181_of_match),
> .owner = THIS_MODULE,
> },
> - .id_table = cm32181_id,
> + .id_table = cm32181_id,
> .probe = cm32181_probe,
> };
>
>

2015-05-23 11:03:02

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 2/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Added cm32181_als_info structure.
>
> Signed-off-by: Kevin Tsai <[email protected]>
Comments inline. The big one is that you have broken the abilty
to have more than one sensor supported by this driver on a given
machine. Don't do that!

Jonathan
> ---
> drivers/iio/light/cm32181.c | 42 +++++++++++++++++++++++++++++++++---------
> 1 file changed, 33 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index 0491d73..6b11145 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -48,6 +48,7 @@
> #define CM32181_ALS_WL_DEFAULT 0x0000
>
> /* Software parameters */
> +#define CM32181_HW_ID 0x81
> #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
> #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
> #define CM32181_CALIBSCALE_DEFAULT 1000
> @@ -58,11 +59,31 @@ static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
> static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
> 800000};
>
> +struct cm32181_als_info {
> + u8 hw_id;
> + u16 reg_cmd;
> + u16 reg_als_wh;
> + u16 reg_als_wl;
> + int calibscale;
> + int mlux_per_bit;
> + int mlux_per_bit_base_it;
Introduce element into here, only when they are actually used.
> +};
> +
const -
> +static struct cm32181_als_info cm32181_als_info_default = {
> + .hw_id = CM32181_HW_ID,
Given you elsewhere represent these next 3 as an array, I'd
be consistent and do this here as well. Then you can just use a
loop to assign them when needed.
> + .reg_cmd = CM32181_CMD_DEFAULT,
> + .reg_als_wh = CM32181_ALS_WH_DEFAULT,
> + .reg_als_wl = CM32181_ALS_WL_DEFAULT,
> + .calibscale = CM32181_CALIBSCALE_DEFAULT,
> + .mlux_per_bit = CM32181_MLUX_PER_BIT,
> + .mlux_per_bit_base_it = CM32181_MLUX_PER_BIT_BASE_IT,
> +};
> +
> struct cm32181_chip {
> struct i2c_client *client;
> struct mutex lock;
> + struct cm32181_als_info *als_info;
> u16 conf_regs[CM32181_CONF_REG_NUM];
> - int calibscale;
Leave calibscale here as this is the data that changes, wherease
the als_info stuff is fixed.
> };
>
> /**
> @@ -76,22 +97,25 @@ struct cm32181_chip {
> static int cm32181_reg_init(struct cm32181_chip *chip)
> {
> struct i2c_client *client = chip->client;
> + struct cm32181_als_info *als_info;
> int i;
> s32 ret;
>
> + chip->als_info = &cm32181_als_info_default;
> + als_info = chip->als_info;
Don't do this. Either it's static data or it isn't. You've
just prevented people having two of these sensors on a single machine..
If you want to use this structure, then make a copy of it.

> +
> ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
> if (ret < 0)
> return ret;
>
> /* check device ID */
> - if ((ret & 0xFF) != 0x81)
> + if ((ret & 0xFF) != als_info->hw_id)
> return -ENODEV;
>
> /* Default Values */
> - chip->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_DEFAULT;
> - chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = CM32181_ALS_WH_DEFAULT;
> - chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = CM32181_ALS_WL_DEFAULT;
> - chip->calibscale = CM32181_CALIBSCALE_DEFAULT;
> + chip->conf_regs[CM32181_REG_ADDR_CMD] = als_info->reg_cmd;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = als_info->reg_als_wh;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = als_info->reg_als_wl;
>
> /* Initialize registers*/
> for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
> @@ -197,7 +221,7 @@ static int cm32181_get_lux(struct cm32181_chip *chip)
> return ret;
>
> lux *= ret;
> - lux *= chip->calibscale;
> + lux *= chip->als_info->calibscale;
> lux /= CM32181_CALIBSCALE_RESOLUTION;
> lux /= MLUX_PER_LUX;
>
> @@ -222,7 +246,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
> *val = ret;
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_CALIBSCALE:
> - *val = chip->calibscale;
> + *val = chip->als_info->calibscale;
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_INT_TIME:
> *val = 0;
> @@ -242,7 +266,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
>
> switch (mask) {
> case IIO_CHAN_INFO_CALIBSCALE:
> - chip->calibscale = val;
> + chip->als_info->calibscale = val;

> return val;
> case IIO_CHAN_INFO_INT_TIME:
> ret = cm32181_write_als_it(chip, val2);
>

2015-05-23 11:04:27

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 3/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Added Power Management support.
> - Added driver remove routine.
>
> Signed-off-by: Kevin Tsai <[email protected]>
This one is fine other than the patch title.
You could split it but as the two changes don't interfere and are
kind of related, this one is fine as a single patch.
> ---
> drivers/iio/light/cm32181.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index 6b11145..9bc3e1f 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -370,11 +370,51 @@ static int cm32181_probe(struct i2c_client *client,
> return 0;
> }
>
> +static int cm32181_remove(struct i2c_client *client)
> +{
> + i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> + CM32181_CMD_ALS_DISABLE);
> +
> + return 0;
> +}
> +
> static const struct i2c_device_id cm32181_id[] = {
> { "cm32181", 0 },
> { }
> };
>
> +#ifdef CONFIG_PM_SLEEP
> +static int cm32181_suspend(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> + struct cm32181_chip *chip = iio_priv(indio_dev);
> + struct i2c_client *client = chip->client;
> + int ret;
> +
> + ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> + CM32181_CMD_ALS_DISABLE);
> +
> + return ret;
> +}
> +
> +static int cm32181_resume(struct device *dev)
> +{
> + struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
> + struct cm32181_chip *chip = iio_priv(indio_dev);
> + struct i2c_client *client = chip->client;
> + int ret;
> +
> + chip->conf_regs[CM32181_REG_ADDR_CMD] &= ~CM32181_CMD_ALS_DISABLE;
> + ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> + chip->conf_regs[CM32181_REG_ADDR_CMD]);
> +
> + return ret;
> +}
> +
> +static const struct dev_pm_ops cm32181_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(cm32181_suspend, cm32181_resume)};
> +#endif
> +
> MODULE_DEVICE_TABLE(i2c, cm32181_id);
>
> static const struct of_device_id cm32181_of_match[] = {
> @@ -387,9 +427,13 @@ static struct i2c_driver cm32181_driver = {
> .name = "cm32181",
> .of_match_table = of_match_ptr(cm32181_of_match),
> .owner = THIS_MODULE,
> +#ifdef CONFIG_PM_SLEEP
> + .pm = &cm32181_pm_ops,
> +#endif
> },
> .id_table = cm32181_id,
> .probe = cm32181_probe,
> + .remove = cm32181_remove,
> };
>
> module_i2c_driver(cm32181_driver);
>

2015-05-23 11:10:24

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 4/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Replaced als_it_bits and als_it_value by cm32181_als_it_scale.
>
> Signed-off-by: Kevin Tsai <[email protected]>
> ---
> drivers/iio/light/cm32181.c | 95 ++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 76 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index 9bc3e1f..54bf0cb 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -53,12 +53,25 @@
> #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
> #define CM32181_CALIBSCALE_DEFAULT 1000
> #define CM32181_CALIBSCALE_RESOLUTION 1000
> -#define MLUX_PER_LUX 1000
> +#define CM32181_MLUX_PER_LUX 1000
Hmm. I'd just drop this and put it inline as it's obvious and in capitals
M would be mega ;)
>
> static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
> static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
> 800000};
>
> +static const struct {
> + int val;
> + int val2;
> + u16 it;
> +} cm32181_als_it_scales[] = {
> + {0, 25000, 12}, /* 0.025000 */
> + {0, 50000, 8}, /* 0.050000 */
> + {0, 100000, 0}, /* 0.100000 */
> + {0, 200000, 1}, /* 0.200000 */
> + {0, 400000, 2}, /* 0.400000 */
> + {0, 800000, 3}, /* 0.800000 */
> +};
If all val values are 0, why store them here?
Or is this likely to change shortly?
> +
> struct cm32181_als_info {
> u8 hw_id;
> u16 reg_cmd;
> @@ -129,15 +142,16 @@ static int cm32181_reg_init(struct cm32181_chip *chip)
> }
>
> /**
> - * cm32181_read_als_it() - Get sensor integration time (ms)
> + * cm32181_read_als_it() - Get sensor integration time
> * @chip: pointer of struct cm32181_chip
> - * @val2: pointer of int to load the als_it value.
> + * @val: pointer of int to load the integration (sec)
> + * @val2: pointer of int to load the integration time (microsecond)
> *
> * Report the current integartion time by millisecond.
> *
> * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
> */
> -static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
> +static int cm32181_read_als_it(struct cm32181_chip *chip, int *val, int *val2)
> {
Adding val in here adds a lot of churn and no benefit currently...
> u16 als_it;
> int i;
> @@ -145,9 +159,10 @@ static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
> als_it = chip->conf_regs[CM32181_REG_ADDR_CMD];
> als_it &= CM32181_CMD_ALS_IT_MASK;
> als_it >>= CM32181_CMD_ALS_IT_SHIFT;
> - for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
> - if (als_it == als_it_bits[i]) {
> - *val2 = als_it_value[i];
> + for (i = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++) {
> + if (als_it == cm32181_als_it_scales[i].it) {
> + *val = cm32181_als_it_scales[i].val;
> + *val2 = cm32181_als_it_scales[i].val2;
> return IIO_VAL_INT_PLUS_MICRO;
> }
> }
> @@ -158,15 +173,44 @@ static int cm32181_read_als_it(struct cm32181_chip *chip, int *val2)
> /**
> * cm32181_write_als_it() - Write sensor integration time
> * @chip: pointer of struct cm32181_chip.
> - * @val: integration time by millisecond.
> + * @val: integration time in second.
> + * @val2: integration time in microsecond.
> *
> * Convert integration time (ms) to sensor value.
> *
> * Return: i2c_smbus_write_word_data command return value.
> */
> -static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
> +static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
> {
> struct i2c_client *client = chip->client;
> + u16 als_it, cmd;
> + int i;
> + s32 ret;
> +
> + for (i = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++) {
> + if (val == cm32181_als_it_scales[i].val &&
> + val2 == cm32181_als_it_scales[i].val2) {
> +
> + als_it = cm32181_als_it_scales[i].it;
> + als_it <<= CM32181_CMD_ALS_IT_SHIFT;
> +
> + cmd = chip->conf_regs[CM32181_REG_ADDR_CMD];
> + cmd &= ~CM32181_CMD_ALS_IT_MASK;
> + cmd |= als_it;
> + ret = i2c_smbus_write_word_data(client,
> + CM32181_REG_ADDR_CMD,
> + cmd);
> + if (ret < 0)
> + return ret;
> +
> + chip->conf_regs[CM32181_REG_ADDR_CMD] = cmd;
> + return 0;
> + }
> + }
> + return -EINVAL;
> +
> +/*
Umm. This comments out a load of dead code. Please don't do this in a patch!
(I nearly missed it) Basically this smacks of the fact you didn't clean up
your patches properly before submitting them as this would be really obvious
in the code after applying them!
> + struct i2c_client *client = chip->client;
> u16 als_it;
> int ret, i, n;
>
> @@ -190,6 +234,7 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
> mutex_unlock(&chip->lock);
>
> return ret;
> +*/
> }
>
> /**
> @@ -204,26 +249,29 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val)
> static int cm32181_get_lux(struct cm32181_chip *chip)
> {
> struct i2c_client *client = chip->client;
> + struct cm32181_als_info *als_info = chip->als_info;
> int ret;
> + int val, val2;
> int als_it;
> - unsigned long lux;
> + u64 lux;
>
> - ret = cm32181_read_als_it(chip, &als_it);
> + ret = cm32181_read_als_it(chip, &val, &val2);
> if (ret < 0)
> return -EINVAL;
> + als_it = val * 1000000 + val2;
>
> - lux = CM32181_MLUX_PER_BIT;
> - lux *= CM32181_MLUX_PER_BIT_BASE_IT;
> - lux /= als_it;
> + lux = (__force u64)als_info->mlux_per_bit;
Is the __force necessary? If so then a comment to eplain why!
> + lux *= als_info->mlux_per_bit_base_it;
> + lux = div_u64(lux, als_it);
>
> ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
> if (ret < 0)
> return ret;
>
> lux *= ret;
> - lux *= chip->als_info->calibscale;
> - lux /= CM32181_CALIBSCALE_RESOLUTION;
> - lux /= MLUX_PER_LUX;
> + lux *= als_info->calibscale;
> + lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION);
> + lux = div_u64(lux, CM32181_MLUX_PER_LUX);
>
> if (lux > 0xFFFF)
> lux = 0xFFFF;
> @@ -250,7 +298,7 @@ static int cm32181_read_raw(struct iio_dev *indio_dev,
> return IIO_VAL_INT;
> case IIO_CHAN_INFO_INT_TIME:
> *val = 0;
> - ret = cm32181_read_als_it(chip, val2);
> + ret = cm32181_read_als_it(chip, val, val2);
> return ret;
> }
>
> @@ -269,7 +317,7 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
> chip->als_info->calibscale = val;
> return val;
> case IIO_CHAN_INFO_INT_TIME:
> - ret = cm32181_write_als_it(chip, val2);
> + ret = cm32181_write_als_it(chip, val, val2);
> return ret;
> }
>
> @@ -289,12 +337,21 @@ static int cm32181_write_raw(struct iio_dev *indio_dev,
> static ssize_t cm32181_get_it_available(struct device *dev,
> struct device_attribute *attr, char *buf)
> {
> + int i, len;
> +
> + for (i = 0, len = 0; i < ARRAY_SIZE(cm32181_als_it_scales); i++)
> + len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
> + cm32181_als_it_scales[i].val,
> + cm32181_als_it_scales[i].val2);
> + return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
> +/*
> int i, n, len;
>
> n = ARRAY_SIZE(als_it_value);
> for (i = 0, len = 0; i < n; i++)
> len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
> return len + sprintf(buf + len, "\n");
> +*/
> }
>
> static const struct iio_chan_spec cm32181_channels[] = {
>

2015-05-23 11:15:52

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 5/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Added Device Tree support.
>
> Signed-off-by: Kevin Tsai <[email protected]>
> ---
> .../devicetree/bindings/iio/light/cm32181.txt | 33 +++++++++++
> MAINTAINERS | 12 ++--
> drivers/iio/light/cm32181.c | 66 ++++++++++------------
> 3 files changed, 70 insertions(+), 41 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/iio/light/cm32181.txt
>
> diff --git a/Documentation/devicetree/bindings/iio/light/cm32181.txt b/Documentation/devicetree/bindings/iio/light/cm32181.txt
> new file mode 100644
> index 0000000..b81a3e3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/light/cm32181.txt
> @@ -0,0 +1,33 @@
> +* Vishay Capella CM32181 Ambient Light sensor
> +
> +Required properties:
> +- compatible: must be "capella,cm32181"
> +- reg: the I2C address of the device
> +
> +Optional properties:
> +- capella,hw_id: hardware device id.
Why? Also listing it just the once would be good :)
I'd actively discourage this. If a new part using a different hw_id
turns up then the compatible string should distinguish it and the driver
be ammended to support it.

> +- capella,reg_cmd: command register initialization.
If you want to actually do this then you need to drop the magic numbers
and explicitly support everything these registers support.
> +- capella,reg_als_wh: high threshold register initialization.
> +- capella,reg_als_wl: low threshold register initialization.
> +- capella,calibscale: calibrated factor with 10^-5 notation.
This one is fair enough though impresively random unit.
Documentation here should indicate that this is dependent on device
packaging (and what else?)
> +- capella,hw_id: hardware device id.
> +- capella,mlux_per_bit: millilux per bit under the default IT.
Should be handled by the calibscale value above I think...

> +- capella,thd_percent: threshold percentage change to trigger.
Not a hardware dependent element to my mind. Should not really
be in the device tree...
> +
> +Example:
> +
> +cm32181@10 {
> + compatible = "capella,cm32181";
> + reg = <0x10>;
> + interrupt-parent = <&gpio1>;
> + interrupts = <17 0>;
> +
> + capella,hw_id = <0x81>;
> + capella,reg_cmd = <0x04>;
> + capella,reg_als_wh = <0xFFFF>;
> + capella,reg_als_wl = <0x0000>;
> + capella,calibscale = <10000>;
> + capella,mlux_per_bit = <5>;
> + capella,thd_percent = <5>;
> +};
> +
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f8e0afb..ee6a8f6 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -2431,12 +2431,6 @@ F: security/capability.c
> F: security/commoncap.c
> F: kernel/capability.c
>
> -CAPELLA MICROSYSTEMS LIGHT SENSOR DRIVER
> -M: Kevin Tsai <[email protected]>
> -S: Maintained
> -F: drivers/iio/light/cm*
> -F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
> -
> CC2520 IEEE-802.15.4 RADIO DRIVER
> M: Varka Bhadram <[email protected]>
> L: [email protected]
> @@ -10610,6 +10604,12 @@ L: [email protected]
> S: Maintained
> F: drivers/net/ethernet/via/via-velocity.*
>
> +VISHAY CAPELLA LIGHT SENSOR DRIVER
> +M: Kevin Tsai <[email protected]>
> +S: Maintained
> +F: drivers/iio/light/cm*
> +F: Documentation/devicetree/bindings/i2c/trivial-devices.txt
> +
> VIVID VIRTUAL VIDEO DRIVER
> M: Hans Verkuil <[email protected]>
> L: [email protected]
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index 54bf0cb..b7abd46 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -51,6 +51,7 @@
> #define CM32181_HW_ID 0x81
> #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
> #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
> +#define CM32181_THD_PERCENT 5 /* 0 for polling mode */
> #define CM32181_CALIBSCALE_DEFAULT 1000
> #define CM32181_CALIBSCALE_RESOLUTION 1000
> #define CM32181_MLUX_PER_LUX 1000
> @@ -80,6 +81,7 @@ struct cm32181_als_info {
> int calibscale;
> int mlux_per_bit;
> int mlux_per_bit_base_it;
> + int thd_percent;
> };
>
> static struct cm32181_als_info cm32181_als_info_default = {
> @@ -90,6 +92,7 @@ static struct cm32181_als_info cm32181_als_info_default = {
> .calibscale = CM32181_CALIBSCALE_DEFAULT,
> .mlux_per_bit = CM32181_MLUX_PER_BIT,
> .mlux_per_bit_base_it = CM32181_MLUX_PER_BIT_BASE_IT,
> + .thd_percent = CM32181_THD_PERCENT,
> };
>
> struct cm32181_chip {
> @@ -99,6 +102,30 @@ struct cm32181_chip {
> u16 conf_regs[CM32181_CONF_REG_NUM];
> };
>
> +#ifdef CONFIG_OF
> +void cm32181_parse_dt(struct cm32181_chip *chip)
> +{
> + struct device_node *dn = chip->client->dev.of_node;
> + struct cm32181_als_info *als_info = chip->als_info;
> + u32 temp_val;
> +
> + if (!of_property_read_u32(dn, "capella,hw_id", &temp_val))
> + als_info->hw_id = (uint8_t)temp_val;
> + if (!of_property_read_u32(dn, "capella,reg_cmd", &temp_val))
> + als_info->reg_cmd = (uint16_t)temp_val;
> + if (!of_property_read_u32(dn, "capella,reg_als_wh", &temp_val))
> + als_info->reg_als_wh = (uint16_t)temp_val;
> + if (!of_property_read_u32(dn, "capella,reg_als_wl", &temp_val))
> + als_info->reg_als_wl = (uint16_t)temp_val;
> + if (!of_property_read_u32(dn, "capella,calibscale", &temp_val))
> + als_info->calibscale = (int)temp_val;
> + if (!of_property_read_u32(dn, "capella,mlux_per_bit", &temp_val))
> + als_info->mlux_per_bit = (int)temp_val;
> + if (!of_property_read_u32(dn, "capella,thd_percent", &temp_val))
> + als_info->thd_percent = (int)temp_val;
> +}
> +#endif
> +
> /**
> * cm32181_reg_init() - Initialize CM32181 registers
> * @chip: pointer of struct cm32181_chip
> @@ -116,6 +143,10 @@ static int cm32181_reg_init(struct cm32181_chip *chip)
>
> chip->als_info = &cm32181_als_info_default;
> als_info = chip->als_info;
> +#ifdef CONFIG_OF
> + if (client->dev.of_node)
> + cm32181_parse_dt(chip);
> +#endif
>
> ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
> if (ret < 0)
> @@ -208,33 +239,6 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
> }
> }
> return -EINVAL;
Ah, here's where the dead code from the previous patch gets cleaned up.
Sort this out please.
> -
> -/*
> - struct i2c_client *client = chip->client;
> - u16 als_it;
> - int ret, i, n;
> -
> - n = ARRAY_SIZE(als_it_value);
> - for (i = 0; i < n; i++)
> - if (val <= als_it_value[i])
> - break;
> - if (i >= n)
> - i = n - 1;
> -
> - als_it = als_it_bits[i];
> - als_it <<= CM32181_CMD_ALS_IT_SHIFT;
> -
> - mutex_lock(&chip->lock);
> - chip->conf_regs[CM32181_REG_ADDR_CMD] &=
> - ~CM32181_CMD_ALS_IT_MASK;
> - chip->conf_regs[CM32181_REG_ADDR_CMD] |=
> - als_it;
> - ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> - chip->conf_regs[CM32181_REG_ADDR_CMD]);
> - mutex_unlock(&chip->lock);
> -
> - return ret;
> -*/
> }
>
> /**
> @@ -344,14 +348,6 @@ static ssize_t cm32181_get_it_available(struct device *dev,
> cm32181_als_it_scales[i].val,
> cm32181_als_it_scales[i].val2);
> return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
Hmm. I missed this one. Clean up whereever it came from.
> -/*
> - int i, n, len;
> -
> - n = ARRAY_SIZE(als_it_value);
> - for (i = 0, len = 0; i < n; i++)
> - len += sprintf(buf + len, "0.%06u ", als_it_value[i]);
> - return len + sprintf(buf + len, "\n");
> -*/
> }
>
> static const struct iio_chan_spec cm32181_channels[] = {
>

2015-05-23 11:22:04

by Jonathan Cameron

[permalink] [raw]
Subject: Re: [PATCH 6/6] iio: light: Updated Vishay Capella cm32181 ambient light sensor driver.

On 22/05/15 05:19, Kevin Tsai wrote:
> - Added Interrupt support.
>
> Signed-off-by: Kevin Tsai <[email protected]>
This needs a detailed description. There is interaction in here I think
between auto set thresholds and IIO threshold events. Not entirely
obvious how this intended to work.

Particularly as it seems that any read of the als will result in the thresholds
moving whether or nor a limit has been reached.

Jonathan

> ---
> drivers/iio/light/cm32181.c | 156 +++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 153 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
> index b7abd46..1ae32a0 100644
> --- a/drivers/iio/light/cm32181.c
> +++ b/drivers/iio/light/cm32181.c
> @@ -47,6 +47,10 @@
> /* ALS_WL register */
> #define CM32181_ALS_WL_DEFAULT 0x0000
>
> +/* STATUS register */
> +#define CM32181_STATUS_ALS_IF_L BIT(15)
> +#define CM32181_STATUS_ALS_IF_H BIT(14)
> +
> /* Software parameters */
> #define CM32181_HW_ID 0x81
> #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
> @@ -122,7 +126,8 @@ void cm32181_parse_dt(struct cm32181_chip *chip)
> if (!of_property_read_u32(dn, "capella,mlux_per_bit", &temp_val))
> als_info->mlux_per_bit = (int)temp_val;
> if (!of_property_read_u32(dn, "capella,thd_percent", &temp_val))
> - als_info->thd_percent = (int)temp_val;
> + if (((int)temp_val >= 0) && ((int)temp_val < 100))
> + als_info->thd_percent = (int)temp_val;
> }
> #endif
>
> @@ -173,6 +178,63 @@ static int cm32181_reg_init(struct cm32181_chip *chip)
> }
>
> /**
> + * cm32181_interrupt() - enable/disable interrupt
> + * @chip: pointer of struct cm32181_chip
> + * @ int_en: truen for enable; false for disable
> + *
> + * Enable/disable interrupt mode
> + *
> + * Return: 0 for success; otherwise for error code.
> + */
> +static int cm32181_interrupt(struct cm32181_chip *cm32181, bool int_en)
> +{
> + int ret;
> +
> + mutex_lock(&cm32181->lock);
> + if (int_en)
> + cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
> + CM32181_CMD_ALS_INT_EN;
> + else
> + cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
> + ~CM32181_CMD_ALS_INT_EN;
> +
> + ret = i2c_smbus_write_word_data(cm32181->client,
> + CM32181_REG_ADDR_CMD,
> + cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
> + mutex_unlock(&cm32181->lock);
> + return ret;
> +}
> +
> +static irqreturn_t cm32181_irq_handler(int irq, void *data)
> +{
> + struct iio_dev *indio_dev = data;
> + struct cm32181_chip *cm32181 = iio_priv(indio_dev);
> + struct i2c_client *client = cm32181->client;
> + int ret;
> + u64 ev_code;
> +
> + ret = i2c_smbus_read_word_data(cm32181->client,
> + CM32181_REG_ADDR_STATUS);
> + if (ret < 0) {
> + dev_err(&client->dev,
> + "%s: Data read failed: %d\n", __func__, ret);
> + return IRQ_NONE;
> + }
> +
> + if (!(ret & (CM32181_STATUS_ALS_IF_H | CM32181_STATUS_ALS_IF_L)))
> + return IRQ_NONE;
> +
> + ev_code = IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
> + 0,
> + IIO_EV_TYPE_THRESH,
> + IIO_EV_DIR_EITHER);
> +
> + iio_push_event(indio_dev, ev_code, iio_get_time_ns());
> +
> + return IRQ_HANDLED;
> +}
> +
> +/**
> * cm32181_read_als_it() - Get sensor integration time
> * @chip: pointer of struct cm32181_chip
> * @val: pointer of int to load the integration (sec)
> @@ -242,6 +304,51 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
> }
>
> /**
> + * cm32181_ials_read() - read ALS raw data
typo
> + * @chip: pointer of struct cm32181_chip
> + *
> + * Read the ALS raw data and update the interrupt threshold windows.
> + *
> + * Return: Positive value is ALS raw data, otherwise is error code.
> + */
> +static int cm32181_als_read(struct cm32181_chip *chip)
> +{
> + struct i2c_client *client = chip->client;
> + struct cm32181_als_info *als_info = chip->als_info;
> + u16 als, wh, wl, delta;
> + int ret;
> +
> + ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
> + if (ret < 0)
> + return ret;
> +
> + als = (u16)ret;
> +
> + if (als_info->thd_percent) {
> + delta = als * als_info->thd_percent / 100;
> + if (delta < 3)
> + delta = 3;
> + wh = (als + delta > 0xFFFF) ? 0xFFFF : (als + delta);
> + wl = (als < delta) ? 0 : (als - delta);
> +
> + ret = i2c_smbus_write_word_data(client,
> + CM32181_REG_ADDR_ALS_WH, wh);
> + if (ret < 0)
> + return ret;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WH] = wh;
> +
> + ret = i2c_smbus_write_word_data(client,
> + CM32181_REG_ADDR_ALS_WL, wl);
> + if (ret < 0)
> + return ret;
> + chip->conf_regs[CM32181_REG_ADDR_ALS_WL] = wl;
> + ret = als;
> + }
> +
> + return ret;
> +}
> +
> +/**
> * cm32181_get_lux() - report current lux value
> * @chip: pointer of struct cm32181_chip
> *
> @@ -252,7 +359,6 @@ static int cm32181_write_als_it(struct cm32181_chip *chip, int val, int val2)
> */
> static int cm32181_get_lux(struct cm32181_chip *chip)
> {
> - struct i2c_client *client = chip->client;
> struct cm32181_als_info *als_info = chip->als_info;
> int ret;
> int val, val2;
> @@ -268,7 +374,7 @@ static int cm32181_get_lux(struct cm32181_chip *chip)
> lux *= als_info->mlux_per_bit_base_it;
> lux = div_u64(lux, als_it);
>
> - ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
> + ret = cm32181_als_read(chip);
> if (ret < 0)
> return ret;
>
> @@ -350,6 +456,15 @@ static ssize_t cm32181_get_it_available(struct device *dev,
> return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
> }
>
> +static const struct iio_event_spec cm32181_event_spec[] = {
> + {
> + .type = IIO_EV_TYPE_THRESH,
> + .dir = IIO_EV_DIR_EITHER,
> + .mask_separate = BIT(IIO_EV_INFO_VALUE) |
> + BIT(IIO_EV_INFO_ENABLE),
> + }
> +};
> +
> static const struct iio_chan_spec cm32181_channels[] = {
> {
> .type = IIO_LIGHT,
> @@ -357,6 +472,8 @@ static const struct iio_chan_spec cm32181_channels[] = {
> BIT(IIO_CHAN_INFO_PROCESSED) |
> BIT(IIO_CHAN_INFO_CALIBSCALE) |
> BIT(IIO_CHAN_INFO_INT_TIME),
> + .event_spec = cm32181_event_spec,
> + .num_event_specs = ARRAY_SIZE(cm32181_event_spec),
> }
> };
>
> @@ -383,6 +500,7 @@ static int cm32181_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> {
> struct cm32181_chip *chip;
> + struct cm32181_als_info *als_info;
> struct iio_dev *indio_dev;
> int ret;
>
> @@ -412,11 +530,35 @@ static int cm32181_probe(struct i2c_client *client,
> return ret;
> }
>
> + als_info = chip->als_info;
> + if (als_info->thd_percent && client->irq) {
> + ret = request_threaded_irq(client->irq, NULL,
> + cm32181_irq_handler,
> + IRQF_TRIGGER_LOW | IRQF_ONESHOT,
> + indio_dev->name, indio_dev);
> + if (ret < 0) {
> + dev_err(&client->dev, "%s: request irq failed\n",
> + __func__);
> + return ret;
> + }
> +
> + ret = cm32181_interrupt(chip, true);
> + if (ret) {
> + als_info->thd_percent = 0;
> + dev_err(&client->dev,
> + "%s: failed to enable interrupt\n", __func__);
> + }
> + } else {
> + als_info->thd_percent = 0; /* Polling Mode */
> + }
> +
> ret = devm_iio_device_register(&client->dev, indio_dev);
> if (ret) {
> dev_err(&client->dev,
> "%s: regist device failed\n",
> __func__);
use goto and a combined exit path now we have this to unwind.
> + if (als_info->thd_percent)
> + free_irq(client->irq, indio_dev);
> return ret;
> }
>
> @@ -425,9 +567,17 @@ static int cm32181_probe(struct i2c_client *client,
>
> static int cm32181_remove(struct i2c_client *client)
> {
> + struct iio_dev *indio_dev = i2c_get_clientdata(client);
> + struct cm32181_chip *chip = iio_priv(indio_dev);
> + struct cm32181_als_info *als_info = chip->als_info;
> +
> + cm32181_interrupt(chip, false);
> i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
> CM32181_CMD_ALS_DISABLE);
>
> + if (als_info->thd_percent)
> + free_irq(client->irq, indio_dev);
> +
> return 0;
> }
>
>