Signed-off-by: Kevin Tsai <[email protected]>
---
Renamed company name.
Removed cm32181_reg.
Removed white space.
Removed unused include files.
Updated macro definitions.
Renamed cm32181_chip pointer to chip.
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
Signed-off-by: Kevin Tsai <[email protected]>
---
Added cm32181_als_info structure.
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
Signed-off-by: Kevin Tsai <[email protected]>
---
Added Power Management support.
Added remove routine.
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
Signed-off-by: Kevin Tsai <[email protected]>
---
Replaced als_it_bits and als_it_value by cm32181_als_it_scale.
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
Signed-off-by: Kevin Tsai <[email protected]>
---
Added Device Tree support.
.../devicetree/bindings/iio/light/cm32181.txt | 33 +++++++++++
MAINTAINERS | 13 +++--
drivers/iio/light/cm32181.c | 66 ++++++++++------------
3 files changed, 71 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..3af7eda 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,13 @@ 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
+F: Documentation/devicetree/bindings/iio/light/cm*
+
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
Signed-off-by: Kevin Tsai <[email protected]>
---
Added Interrupt support.
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
On Thu, May 21, 2015 at 05:30:40PM -0700, Kevin Tsai wrote:
> Signed-off-by: Kevin Tsai <[email protected]>
> ---
Your whole changelog ended up in the Subject line :(
On Fri, May 22, 2015 at 4:56 AM, Greg KH <[email protected]> wrote:
> On Thu, May 21, 2015 at 05:30:40PM -0700, Kevin Tsai wrote:
>> Signed-off-by: Kevin Tsai <[email protected]>
>> ---
>
> Your whole changelog ended up in the Subject line :(
Hi Kevin,
Few comments:
1) Please also add a cover letter. Use --cover-letter parameter of git
format-patch.
2) Please create a patch for each logical change. Your current 1/6
patch should be
split in several small patches:
* 1/6 iio: light: cm32181: Update company name
* 2/6 iio: light: cm32181: Remove unused include files
* etc.
3) Please use specific wordings for commit subject. A subject like this:
"Updated Vishay Capella cm32181 ambient light sensor driver" doesn't say much.
thanks,
Daniel.