aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baluta <daniel.baluta@intel.com>2015-03-14 15:11:41 -0400
committerJonathan Cameron <jic23@kernel.org>2015-03-15 07:43:02 -0400
commit8b0544263761adbc7308f6910cdcc0d601782cb1 (patch)
treedde3cd9caffcf8b2671c356ddfda172ecde9c9da
parent40dbbfb5e49c9317a24111bb71151090e8ea95e8 (diff)
iio: light: Add support for Capella CM3323 color sensor
Minimal implementation providing raw light intensity and integration time attribute. Userspace applications can use GREEN channel for raw illuminance readings following this table: Integration Time | G Sensitivity ================================ 40 ms | 0.18 80 ms | 0.09 160 ms | 0.045 320 ms | 0.0225 640 ms | 0.01125 1280 ms | 0.005625 Signed-off-by: Daniel Baluta <daniel.baluta@intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r--drivers/iio/light/Kconfig10
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/cm3323.c286
3 files changed, 297 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index ae68c64bdad3..cd937d9293ff 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -59,6 +59,16 @@ config CM3232
59 To compile this driver as a module, choose M here: 59 To compile this driver as a module, choose M here:
60 the module will be called cm3232. 60 the module will be called cm3232.
61 61
62config CM3323
63 depends on I2C
64 tristate "Capella CM3323 color light sensor"
65 help
66 Say Y here if you want to build a driver for Capela CM3323
67 color sensor.
68
69 To compile this driver as a module, choose M here: the module will
70 be called cm3323.
71
62config CM36651 72config CM36651
63 depends on I2C 73 depends on I2C
64 tristate "CM36651 driver" 74 tristate "CM36651 driver"
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index b12a5160d9e0..ad7c30fe443b 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_AL3320A) += al3320a.o
8obj-$(CONFIG_APDS9300) += apds9300.o 8obj-$(CONFIG_APDS9300) += apds9300.o
9obj-$(CONFIG_CM32181) += cm32181.o 9obj-$(CONFIG_CM32181) += cm32181.o
10obj-$(CONFIG_CM3232) += cm3232.o 10obj-$(CONFIG_CM3232) += cm3232.o
11obj-$(CONFIG_CM3323) += cm3323.o
11obj-$(CONFIG_CM36651) += cm36651.o 12obj-$(CONFIG_CM36651) += cm36651.o
12obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o 13obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
13obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o 14obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
diff --git a/drivers/iio/light/cm3323.c b/drivers/iio/light/cm3323.c
new file mode 100644
index 000000000000..869033e48a1f
--- /dev/null
+++ b/drivers/iio/light/cm3323.c
@@ -0,0 +1,286 @@
1/*
2 * CM3323 - Capella Color Light Sensor
3 *
4 * Copyright (c) 2015, Intel Corporation.
5 *
6 * This file is subject to the terms and conditions of version 2 of
7 * the GNU General Public License. See the file COPYING in the main
8 * directory of this archive for more details.
9 *
10 * IIO driver for CM3323 (7-bit I2C slave address 0x10)
11 *
12 * TODO: calibscale to correct the lens factor
13 */
14#include <linux/module.h>
15#include <linux/init.h>
16#include <linux/i2c.h>
17#include <linux/mutex.h>
18
19#include <linux/iio/iio.h>
20#include <linux/iio/sysfs.h>
21
22#define CM3323_DRV_NAME "cm3323"
23
24#define CM3323_CMD_CONF 0x00
25#define CM3323_CMD_RED_DATA 0x08
26#define CM3323_CMD_GREEN_DATA 0x09
27#define CM3323_CMD_BLUE_DATA 0x0A
28#define CM3323_CMD_CLEAR_DATA 0x0B
29
30#define CM3323_CONF_SD_BIT BIT(0) /* sensor disable */
31#define CM3323_CONF_AF_BIT BIT(1) /* auto/manual force mode */
32#define CM3323_CONF_IT_MASK (BIT(4) | BIT(5) | BIT(6))
33#define CM3323_CONF_IT_SHIFT 4
34
35#define CM3323_INT_TIME_AVAILABLE "0.04 0.08 0.16 0.32 0.64 1.28"
36
37static const struct {
38 int val;
39 int val2;
40} cm3323_int_time[] = {
41 {0, 40000}, /* 40 ms */
42 {0, 80000}, /* 80 ms */
43 {0, 160000}, /* 160 ms */
44 {0, 320000}, /* 320 ms */
45 {0, 640000}, /* 640 ms */
46 {1, 280000}, /* 1280 ms */
47};
48
49struct cm3323_data {
50 struct i2c_client *client;
51 u16 reg_conf;
52 struct mutex mutex;
53};
54
55#define CM3323_COLOR_CHANNEL(_color, _addr) { \
56 .type = IIO_INTENSITY, \
57 .modified = 1, \
58 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
59 .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_INT_TIME), \
60 .channel2 = IIO_MOD_LIGHT_##_color, \
61 .address = _addr, \
62}
63
64static const struct iio_chan_spec cm3323_channels[] = {
65 CM3323_COLOR_CHANNEL(RED, CM3323_CMD_RED_DATA),
66 CM3323_COLOR_CHANNEL(GREEN, CM3323_CMD_GREEN_DATA),
67 CM3323_COLOR_CHANNEL(BLUE, CM3323_CMD_BLUE_DATA),
68 CM3323_COLOR_CHANNEL(CLEAR, CM3323_CMD_CLEAR_DATA),
69};
70
71static IIO_CONST_ATTR_INT_TIME_AVAIL(CM3323_INT_TIME_AVAILABLE);
72
73static struct attribute *cm3323_attributes[] = {
74 &iio_const_attr_integration_time_available.dev_attr.attr,
75 NULL
76};
77
78static const struct attribute_group cm3323_attribute_group = {
79 .attrs = cm3323_attributes,
80};
81
82static int cm3323_init(struct iio_dev *indio_dev)
83{
84 int ret;
85 struct cm3323_data *data = iio_priv(indio_dev);
86
87 ret = i2c_smbus_read_word_data(data->client, CM3323_CMD_CONF);
88 if (ret < 0) {
89 dev_err(&data->client->dev, "Error reading reg_conf\n");
90 return ret;
91 }
92
93 /* enable sensor and set auto force mode */
94 ret &= ~(CM3323_CONF_SD_BIT | CM3323_CONF_AF_BIT);
95
96 ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF, ret);
97 if (ret < 0) {
98 dev_err(&data->client->dev, "Error writing reg_conf\n");
99 return ret;
100 }
101
102 data->reg_conf = ret;
103
104 return 0;
105}
106
107static void cm3323_disable(struct iio_dev *indio_dev)
108{
109 int ret;
110 struct cm3323_data *data = iio_priv(indio_dev);
111
112 ret = i2c_smbus_write_word_data(data->client, CM3323_CMD_CONF,
113 CM3323_CONF_SD_BIT);
114 if (ret < 0)
115 dev_err(&data->client->dev, "Error writing reg_conf\n");
116}
117
118static int cm3323_set_it_bits(struct cm3323_data *data, int val, int val2)
119{
120 int i, ret;
121 u16 reg_conf;
122
123 for (i = 0; i < ARRAY_SIZE(cm3323_int_time); i++) {
124 if (val == cm3323_int_time[i].val &&
125 val2 == cm3323_int_time[i].val2) {
126 reg_conf = data->reg_conf;
127 reg_conf |= i << CM3323_CONF_IT_SHIFT;
128
129 ret = i2c_smbus_write_word_data(data->client,
130 CM3323_CMD_CONF,
131 reg_conf);
132 if (ret < 0)
133 return ret;
134
135 data->reg_conf = reg_conf;
136 return 0;
137 }
138 }
139 return -EINVAL;
140}
141
142static int cm3323_get_it_bits(struct cm3323_data *data)
143{
144 int bits;
145
146 bits = (data->reg_conf & CM3323_CONF_IT_MASK) >>
147 CM3323_CONF_IT_SHIFT;
148
149 if (bits >= ARRAY_SIZE(cm3323_int_time))
150 return -EINVAL;
151 return bits;
152}
153
154static int cm3323_read_raw(struct iio_dev *indio_dev,
155 struct iio_chan_spec const *chan, int *val,
156 int *val2, long mask)
157{
158 int i, ret;
159 struct cm3323_data *data = iio_priv(indio_dev);
160
161 switch (mask) {
162 case IIO_CHAN_INFO_RAW:
163 mutex_lock(&data->mutex);
164 ret = i2c_smbus_read_word_data(data->client, chan->address);
165 if (ret < 0) {
166 mutex_unlock(&data->mutex);
167 return ret;
168 }
169 *val = ret;
170 mutex_unlock(&data->mutex);
171
172 return IIO_VAL_INT;
173 case IIO_CHAN_INFO_INT_TIME:
174 mutex_lock(&data->mutex);
175 i = cm3323_get_it_bits(data);
176 if (i < 0) {
177 mutex_unlock(&data->mutex);
178 return -EINVAL;
179 }
180
181 *val = cm3323_int_time[i].val;
182 *val2 = cm3323_int_time[i].val2;
183 mutex_unlock(&data->mutex);
184
185 return IIO_VAL_INT_PLUS_MICRO;
186 default:
187 return -EINVAL;
188 }
189}
190
191static int cm3323_write_raw(struct iio_dev *indio_dev,
192 struct iio_chan_spec const *chan, int val,
193 int val2, long mask)
194{
195 struct cm3323_data *data = iio_priv(indio_dev);
196 int ret;
197
198 switch (mask) {
199 case IIO_CHAN_INFO_INT_TIME:
200 mutex_lock(&data->mutex);
201 ret = cm3323_set_it_bits(data, val, val2);
202 mutex_unlock(&data->mutex);
203
204 return ret;
205 default:
206 return -EINVAL;
207 }
208}
209
210static const struct iio_info cm3323_info = {
211 .driver_module = THIS_MODULE,
212 .read_raw = cm3323_read_raw,
213 .write_raw = cm3323_write_raw,
214 .attrs = &cm3323_attribute_group,
215};
216
217static int cm3323_probe(struct i2c_client *client,
218 const struct i2c_device_id *id)
219{
220 struct cm3323_data *data;
221 struct iio_dev *indio_dev;
222 int ret;
223
224 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
225 if (!indio_dev)
226 return -ENOMEM;
227
228 data = iio_priv(indio_dev);
229 i2c_set_clientdata(client, indio_dev);
230 data->client = client;
231
232 mutex_init(&data->mutex);
233
234 indio_dev->dev.parent = &client->dev;
235 indio_dev->info = &cm3323_info;
236 indio_dev->name = CM3323_DRV_NAME;
237 indio_dev->channels = cm3323_channels;
238 indio_dev->num_channels = ARRAY_SIZE(cm3323_channels);
239 indio_dev->modes = INDIO_DIRECT_MODE;
240
241 ret = cm3323_init(indio_dev);
242 if (ret < 0) {
243 dev_err(&client->dev, "cm3323 chip init failed\n");
244 return ret;
245 }
246 ret = iio_device_register(indio_dev);
247 if (ret < 0) {
248 dev_err(&client->dev, "failed to register iio dev\n");
249 goto err_init;
250 }
251 return 0;
252err_init:
253 cm3323_disable(indio_dev);
254 return ret;
255}
256
257static int cm3323_remove(struct i2c_client *client)
258{
259 struct iio_dev *indio_dev = i2c_get_clientdata(client);
260
261 iio_device_unregister(indio_dev);
262 cm3323_disable(indio_dev);
263
264 return 0;
265}
266
267static const struct i2c_device_id cm3323_id[] = {
268 {"cm3323", 0},
269 {}
270};
271MODULE_DEVICE_TABLE(i2c, cm3323_id);
272
273static struct i2c_driver cm3323_driver = {
274 .driver = {
275 .name = CM3323_DRV_NAME,
276 },
277 .probe = cm3323_probe,
278 .remove = cm3323_remove,
279 .id_table = cm3323_id,
280};
281
282module_i2c_driver(cm3323_driver);
283
284MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
285MODULE_DESCRIPTION("Capella CM3323 Color Light Sensor driver");
286MODULE_LICENSE("GPL v2");