aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin Tsai <ktsai@capellamicro.com>2013-12-23 20:53:00 -0500
committerJonathan Cameron <jic23@kernel.org>2014-01-01 07:03:32 -0500
commit971672c0b3ccd16ce53299f1ccac0253fc6d7bf6 (patch)
tree7d902d60e69c24ca2b84ce566e7e0b88a7c08c90
parenta6e8e3a470bf96575eebfa9dbfda6e1ec8929fb8 (diff)
iio: add Capella CM32181 ambient light sensor driver.
Add Capella Microsystem CM32181 Ambient Light Sensor IIO driver. This driver will convert raw data to lux value under open-air condition. Change the calibscale based on the cover material. Signed-off-by: Kevin Tsai <ktsai@capellamicro.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt1
-rw-r--r--drivers/iio/light/Kconfig11
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/cm32181.c379
4 files changed, 392 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index b1cb3415e6f1..c65f71cfaa5c 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -16,6 +16,7 @@ adt7461 +/-1C TDM Extended Temp Range I.C
16at,24c08 i2c serial eeprom (24cxx) 16at,24c08 i2c serial eeprom (24cxx)
17atmel,24c02 i2c serial eeprom (24cxx) 17atmel,24c02 i2c serial eeprom (24cxx)
18atmel,at97sc3204t i2c trusted platform module (TPM) 18atmel,at97sc3204t i2c trusted platform module (TPM)
19capella,cm32181 CM32181: Ambient Light Sensor
19catalyst,24c32 i2c serial eeprom 20catalyst,24c32 i2c serial eeprom
20dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock 21dallas,ds1307 64 x 8, Serial, I2C Real-Time Clock
21dallas,ds1338 I2C RTC with 56-Byte NV RAM 22dallas,ds1338 I2C RTC with 56-Byte NV RAM
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index a022f27c6690..d12b2a0dbfbc 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -27,6 +27,17 @@ config APDS9300
27 To compile this driver as a module, choose M here: the 27 To compile this driver as a module, choose M here: the
28 module will be called apds9300. 28 module will be called apds9300.
29 29
30config CM32181
31 depends on I2C
32 tristate "CM32181 driver"
33 help
34 Say Y here if you use cm32181.
35 This option enables ambient light sensor using
36 Capella cm32181 device driver.
37
38 To compile this driver as a module, choose M here:
39 the module will be called cm32181.
40
30config CM36651 41config CM36651
31 depends on I2C 42 depends on I2C
32 tristate "CM36651 driver" 43 tristate "CM36651 driver"
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index daa327f39e04..60e35ac07ff0 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -5,6 +5,7 @@
5# When adding new entries keep the list in alphabetical order 5# When adding new entries keep the list in alphabetical order
6obj-$(CONFIG_ADJD_S311) += adjd_s311.o 6obj-$(CONFIG_ADJD_S311) += adjd_s311.o
7obj-$(CONFIG_APDS9300) += apds9300.o 7obj-$(CONFIG_APDS9300) += apds9300.o
8obj-$(CONFIG_CM32181) += cm32181.o
8obj-$(CONFIG_CM36651) += cm36651.o 9obj-$(CONFIG_CM36651) += cm36651.o
9obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o 10obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
10obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o 11obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
new file mode 100644
index 000000000000..f17b4e6183c6
--- /dev/null
+++ b/drivers/iio/light/cm32181.c
@@ -0,0 +1,379 @@
1/*
2 * Copyright (C) 2013 Capella Microsystems Inc.
3 * Author: Kevin Tsai <ktsai@capellamicro.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2, as published
7 * by the Free Software Foundation.
8 */
9
10#include <linux/delay.h>
11#include <linux/err.h>
12#include <linux/i2c.h>
13#include <linux/mutex.h>
14#include <linux/module.h>
15#include <linux/interrupt.h>
16#include <linux/regulator/consumer.h>
17#include <linux/iio/iio.h>
18#include <linux/iio/sysfs.h>
19#include <linux/iio/events.h>
20#include <linux/init.h>
21
22/* Registers Address */
23#define CM32181_REG_ADDR_CMD 0x00
24#define CM32181_REG_ADDR_ALS 0x04
25#define CM32181_REG_ADDR_STATUS 0x06
26#define CM32181_REG_ADDR_ID 0x07
27
28/* Number of Configurable Registers */
29#define CM32181_CONF_REG_NUM 0x01
30
31/* CMD register */
32#define CM32181_CMD_ALS_ENABLE 0x00
33#define CM32181_CMD_ALS_DISABLE 0x01
34#define CM32181_CMD_ALS_INT_EN 0x02
35
36#define CM32181_CMD_ALS_IT_SHIFT 6
37#define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT)
38#define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT)
39
40#define CM32181_CMD_ALS_SM_SHIFT 11
41#define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT)
42#define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT)
43
44#define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */
45#define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */
46#define CM32181_CALIBSCALE_DEFAULT 1000
47#define CM32181_CALIBSCALE_RESOLUTION 1000
48#define MLUX_PER_LUX 1000
49
50static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = {
51 CM32181_REG_ADDR_CMD,
52};
53
54static const int als_it_bits[] = {12, 8, 0, 1, 2, 3};
55static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000,
56 800000};
57
58struct cm32181_chip {
59 struct i2c_client *client;
60 struct mutex lock;
61 u16 conf_regs[CM32181_CONF_REG_NUM];
62 int calibscale;
63};
64
65/**
66 * cm32181_reg_init() - Initialize CM32181 registers
67 * @cm32181: pointer of struct cm32181.
68 *
69 * Initialize CM32181 ambient light sensor register to default values.
70 *
71 * Return: 0 for success; otherwise for error code.
72 */
73static int cm32181_reg_init(struct cm32181_chip *cm32181)
74{
75 struct i2c_client *client = cm32181->client;
76 int i;
77 s32 ret;
78
79 ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
80 if (ret < 0)
81 return ret;
82
83 /* check device ID */
84 if ((ret & 0xFF) != 0x81)
85 return -ENODEV;
86
87 /* Default Values */
88 cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE |
89 CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
90 cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
91
92 /* Initialize registers*/
93 for (i = 0; i < CM32181_CONF_REG_NUM; i++) {
94 ret = i2c_smbus_write_word_data(client, cm32181_reg[i],
95 cm32181->conf_regs[i]);
96 if (ret < 0)
97 return ret;
98 }
99
100 return 0;
101}
102
103/**
104 * cm32181_read_als_it() - Get sensor integration time (ms)
105 * @cm32181: pointer of struct cm32181
106 * @val: pointer of int to load the als_it value.
107 *
108 * Report the current integartion time by millisecond.
109 *
110 * Return: IIO_VAL_INT for success, otherwise -EINVAL.
111 */
112static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val)
113{
114 u16 als_it;
115 int i;
116
117 als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
118 als_it &= CM32181_CMD_ALS_IT_MASK;
119 als_it >>= CM32181_CMD_ALS_IT_SHIFT;
120 for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) {
121 if (als_it == als_it_bits[i]) {
122 *val = als_it_value[i];
123 return IIO_VAL_INT;
124 }
125 }
126
127 return -EINVAL;
128}
129
130/**
131 * cm32181_write_als_it() - Write sensor integration time
132 * @cm32181: pointer of struct cm32181.
133 * @val: integration time by millisecond.
134 *
135 * Convert integration time (ms) to sensor value.
136 *
137 * Return: i2c_smbus_write_word_data command return value.
138 */
139static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
140{
141 struct i2c_client *client = cm32181->client;
142 u16 als_it;
143 int ret, i, n;
144
145 n = ARRAY_SIZE(als_it_value);
146 for (i = 0; i < n; i++)
147 if (val <= als_it_value[i])
148 break;
149 if (i >= n)
150 i = n - 1;
151
152 als_it = als_it_bits[i];
153 als_it <<= CM32181_CMD_ALS_IT_SHIFT;
154
155 mutex_lock(&cm32181->lock);
156 cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
157 ~CM32181_CMD_ALS_IT_MASK;
158 cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
159 als_it;
160 ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
161 cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
162 mutex_unlock(&cm32181->lock);
163
164 return ret;
165}
166
167/**
168 * cm32181_get_lux() - report current lux value
169 * @cm32181: pointer of struct cm32181.
170 *
171 * Convert sensor raw data to lux. It depends on integration
172 * time and claibscale variable.
173 *
174 * Return: Positive value is lux, otherwise is error code.
175 */
176static int cm32181_get_lux(struct cm32181_chip *cm32181)
177{
178 struct i2c_client *client = cm32181->client;
179 int ret;
180 int als_it;
181 unsigned long lux;
182
183 ret = cm32181_read_als_it(cm32181, &als_it);
184 if (ret < 0)
185 return -EINVAL;
186
187 lux = CM32181_MLUX_PER_BIT;
188 lux *= CM32181_MLUX_PER_BIT_BASE_IT;
189 lux /= als_it;
190
191 ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
192 if (ret < 0)
193 return ret;
194
195 lux *= ret;
196 lux *= cm32181->calibscale;
197 lux /= CM32181_CALIBSCALE_RESOLUTION;
198 lux /= MLUX_PER_LUX;
199
200 if (lux > 0xFFFF)
201 lux = 0xFFFF;
202
203 return lux;
204}
205
206static int cm32181_read_raw(struct iio_dev *indio_dev,
207 struct iio_chan_spec const *chan,
208 int *val, int *val2, long mask)
209{
210 struct cm32181_chip *cm32181 = iio_priv(indio_dev);
211 int ret;
212
213 switch (mask) {
214 case IIO_CHAN_INFO_PROCESSED:
215 ret = cm32181_get_lux(cm32181);
216 if (ret < 0)
217 return ret;
218 *val = ret;
219 return IIO_VAL_INT;
220 case IIO_CHAN_INFO_CALIBSCALE:
221 *val = cm32181->calibscale;
222 return IIO_VAL_INT;
223 case IIO_CHAN_INFO_INT_TIME:
224 ret = cm32181_read_als_it(cm32181, val);
225 return ret;
226 }
227
228 return -EINVAL;
229}
230
231static int cm32181_write_raw(struct iio_dev *indio_dev,
232 struct iio_chan_spec const *chan,
233 int val, int val2, long mask)
234{
235 struct cm32181_chip *cm32181 = iio_priv(indio_dev);
236 int ret;
237
238 switch (mask) {
239 case IIO_CHAN_INFO_CALIBSCALE:
240 cm32181->calibscale = val;
241 return val;
242 case IIO_CHAN_INFO_INT_TIME:
243 ret = cm32181_write_als_it(cm32181, val);
244 return ret;
245 }
246
247 return -EINVAL;
248}
249
250/**
251 * cm32181_get_it_available() - Get available ALS IT value
252 * @dev: pointer of struct device.
253 * @attr: pointer of struct device_attribute.
254 * @buf: pointer of return string buffer.
255 *
256 * Display the available integration time values by millisecond.
257 *
258 * Return: string length.
259 */
260static ssize_t cm32181_get_it_available(struct device *dev,
261 struct device_attribute *attr, char *buf)
262{
263 int i, n, len;
264
265 n = ARRAY_SIZE(als_it_value);
266 for (i = 0, len = 0; i < n; i++)
267 len += sprintf(buf + len, "%d ", als_it_value[i]);
268 return len + sprintf(buf + len, "\n");
269}
270
271static const struct iio_chan_spec cm32181_channels[] = {
272 {
273 .type = IIO_LIGHT,
274 .info_mask_separate =
275 BIT(IIO_CHAN_INFO_PROCESSED) |
276 BIT(IIO_CHAN_INFO_CALIBSCALE) |
277 BIT(IIO_CHAN_INFO_INT_TIME),
278 }
279};
280
281static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
282 S_IRUGO, cm32181_get_it_available, NULL, 0);
283
284static struct attribute *cm32181_attributes[] = {
285 &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
286 NULL,
287};
288
289static const struct attribute_group cm32181_attribute_group = {
290 .attrs = cm32181_attributes
291};
292
293static const struct iio_info cm32181_info = {
294 .driver_module = THIS_MODULE,
295 .read_raw = &cm32181_read_raw,
296 .write_raw = &cm32181_write_raw,
297 .attrs = &cm32181_attribute_group,
298};
299
300static int cm32181_probe(struct i2c_client *client,
301 const struct i2c_device_id *id)
302{
303 struct cm32181_chip *cm32181;
304 struct iio_dev *indio_dev;
305 int ret;
306
307 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181));
308 if (!indio_dev) {
309 dev_err(&client->dev, "devm_iio_device_alloc failed\n");
310 return -ENOMEM;
311 }
312
313 cm32181 = iio_priv(indio_dev);
314 i2c_set_clientdata(client, indio_dev);
315 cm32181->client = client;
316
317 mutex_init(&cm32181->lock);
318 indio_dev->dev.parent = &client->dev;
319 indio_dev->channels = cm32181_channels;
320 indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
321 indio_dev->info = &cm32181_info;
322 indio_dev->name = id->name;
323 indio_dev->modes = INDIO_DIRECT_MODE;
324
325 ret = cm32181_reg_init(cm32181);
326 if (ret) {
327 dev_err(&client->dev,
328 "%s: register init failed\n",
329 __func__);
330 return ret;
331 }
332
333 ret = iio_device_register(indio_dev);
334 if (ret) {
335 dev_err(&client->dev,
336 "%s: regist device failed\n",
337 __func__);
338 return ret;
339 }
340
341 return 0;
342}
343
344static int cm32181_remove(struct i2c_client *client)
345{
346 struct iio_dev *indio_dev = i2c_get_clientdata(client);
347
348 iio_device_unregister(indio_dev);
349 return 0;
350}
351
352static const struct i2c_device_id cm32181_id[] = {
353 { "cm32181", 0 },
354 { }
355};
356
357MODULE_DEVICE_TABLE(i2c, cm32181_id);
358
359static const struct of_device_id cm32181_of_match[] = {
360 { .compatible = "capella,cm32181" },
361 { }
362};
363
364static struct i2c_driver cm32181_driver = {
365 .driver = {
366 .name = "cm32181",
367 .of_match_table = of_match_ptr(cm32181_of_match),
368 .owner = THIS_MODULE,
369 },
370 .id_table = cm32181_id,
371 .probe = cm32181_probe,
372 .remove = cm32181_remove,
373};
374
375module_i2c_driver(cm32181_driver);
376
377MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
378MODULE_DESCRIPTION("CM32181 ambient light sensor driver");
379MODULE_LICENSE("GPL");