aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/light
diff options
context:
space:
mode:
authorPeter Meerwald <pmeerw@pmeerw.net>2014-05-07 08:38:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-07-07 04:34:36 -0400
commita244e7b57f0fb778bd333b10fffbeb362b94ffc3 (patch)
tree65baf50996e00103b0ce0d87c3293939c46afc0b /drivers/iio/light
parent6c25539cbc460f7f594e30ac6db88d5e61e8baff (diff)
iio: Add driver for AMS/TAOS tcs3414 digital color sensor
16-bit digital color sensor with red, green, blue and clear channel datasheet: http://ams.com/eng/content/download/250258/975997/TCS3414_Datasheet_EN_v1.pdf Signed-off-by: Peter Meerwald <pmeerw@pmeerw.net> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/light')
-rw-r--r--drivers/iio/light/Kconfig12
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/tcs3414.c405
3 files changed, 418 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 7d83dca6d080..bf05ca5b0a57 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -128,6 +128,18 @@ config LTR501
128 This driver can also be built as a module. If so, the module 128 This driver can also be built as a module. If so, the module
129 will be called ltr501. 129 will be called ltr501.
130 130
131config TCS3414
132 tristate "TAOS TCS3414 digital color sensor"
133 depends on I2C
134 select IIO_BUFFER
135 select IIO_TRIGGERED_BUFFER
136 help
137 If you say yes here you get support for the TAOS TCS3414
138 family of digital color sensors.
139
140 This driver can also be built as a module. If so, the module
141 will be called tcs3414.
142
131config TCS3472 143config TCS3472
132 tristate "TAOS TCS3472 color light-to-digital converter" 144 tristate "TAOS TCS3472 color light-to-digital converter"
133 depends on I2C 145 depends on I2C
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index f3d1857b2083..8b8c09f9c1f8 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o
14obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o 14obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
15obj-$(CONFIG_LTR501) += ltr501.o 15obj-$(CONFIG_LTR501) += ltr501.o
16obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o 16obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
17obj-$(CONFIG_TCS3414) += tcs3414.o
17obj-$(CONFIG_TCS3472) += tcs3472.o 18obj-$(CONFIG_TCS3472) += tcs3472.o
18obj-$(CONFIG_TSL4531) += tsl4531.o 19obj-$(CONFIG_TSL4531) += tsl4531.o
19obj-$(CONFIG_VCNL4000) += vcnl4000.o 20obj-$(CONFIG_VCNL4000) += vcnl4000.o
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
new file mode 100644
index 000000000000..a9e449b0be0c
--- /dev/null
+++ b/drivers/iio/light/tcs3414.c
@@ -0,0 +1,405 @@
1/*
2 * tcs3414.c - Support for TAOS TCS3414 digital color sensor
3 *
4 * Copyright (c) 2014 Peter Meerwald <pmeerw@pmeerw.net>
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 * Digital color sensor with 16-bit channels for red, green, blue, clear);
11 * 7-bit I2C slave address 0x39 (TCS3414) or 0x29, 0x49, 0x59 (TCS3413,
12 * TCS3415, TCS3416, resp.)
13 *
14 * TODO: sync, interrupt support, thresholds, prescaler
15 */
16
17#include <linux/module.h>
18#include <linux/i2c.h>
19#include <linux/delay.h>
20#include <linux/pm.h>
21
22#include <linux/iio/iio.h>
23#include <linux/iio/sysfs.h>
24#include <linux/iio/trigger_consumer.h>
25#include <linux/iio/buffer.h>
26#include <linux/iio/triggered_buffer.h>
27
28#define TCS3414_DRV_NAME "tcs3414"
29
30#define TCS3414_COMMAND BIT(7)
31#define TCS3414_COMMAND_WORD (TCS3414_COMMAND | BIT(5))
32
33#define TCS3414_CONTROL (TCS3414_COMMAND | 0x00)
34#define TCS3414_TIMING (TCS3414_COMMAND | 0x01)
35#define TCS3414_ID (TCS3414_COMMAND | 0x04)
36#define TCS3414_GAIN (TCS3414_COMMAND | 0x07)
37#define TCS3414_DATA_GREEN (TCS3414_COMMAND_WORD | 0x10)
38#define TCS3414_DATA_RED (TCS3414_COMMAND_WORD | 0x12)
39#define TCS3414_DATA_BLUE (TCS3414_COMMAND_WORD | 0x14)
40#define TCS3414_DATA_CLEAR (TCS3414_COMMAND_WORD | 0x16)
41
42#define TCS3414_CONTROL_ADC_VALID BIT(4)
43#define TCS3414_CONTROL_ADC_EN BIT(1)
44#define TCS3414_CONTROL_POWER BIT(0)
45
46#define TCS3414_INTEG_MASK GENMASK(1, 0)
47#define TCS3414_INTEG_12MS 0x0
48#define TCS3414_INTEG_100MS 0x1
49#define TCS3414_INTEG_400MS 0x2
50
51#define TCS3414_GAIN_MASK GENMASK(5, 4)
52#define TCS3414_GAIN_SHIFT 4
53
54struct tcs3414_data {
55 struct i2c_client *client;
56 struct mutex lock;
57 u8 control;
58 u8 gain;
59 u8 timing;
60 u16 buffer[8]; /* 4x 16-bit + 8 bytes timestamp */
61};
62
63#define TCS3414_CHANNEL(_color, _si, _addr) { \
64 .type = IIO_INTENSITY, \
65 .modified = 1, \
66 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
67 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
68 BIT(IIO_CHAN_INFO_INT_TIME), \
69 .channel2 = IIO_MOD_LIGHT_##_color, \
70 .address = _addr, \
71 .scan_index = _si, \
72 .scan_type = { \
73 .sign = 'u', \
74 .realbits = 16, \
75 .storagebits = 16, \
76 .endianness = IIO_CPU, \
77 }, \
78}
79
80/* scale factors: 1/gain */
81static const int tcs3414_scales[][2] = {
82 {1, 0}, {0, 250000}, {0, 62500}, {0, 15625}
83};
84
85/* integration time in ms */
86static const int tcs3414_times[] = { 12, 100, 400 };
87
88static const struct iio_chan_spec tcs3414_channels[] = {
89 TCS3414_CHANNEL(GREEN, 0, TCS3414_DATA_GREEN),
90 TCS3414_CHANNEL(RED, 1, TCS3414_DATA_RED),
91 TCS3414_CHANNEL(BLUE, 2, TCS3414_DATA_BLUE),
92 TCS3414_CHANNEL(CLEAR, 3, TCS3414_DATA_CLEAR),
93 IIO_CHAN_SOFT_TIMESTAMP(4),
94};
95
96static int tcs3414_req_data(struct tcs3414_data *data)
97{
98 int tries = 25;
99 int ret;
100
101 ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
102 data->control | TCS3414_CONTROL_ADC_EN);
103 if (ret < 0)
104 return ret;
105
106 while (tries--) {
107 ret = i2c_smbus_read_byte_data(data->client, TCS3414_CONTROL);
108 if (ret < 0)
109 return ret;
110 if (ret & TCS3414_CONTROL_ADC_VALID)
111 break;
112 msleep(20);
113 }
114
115 ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
116 data->control);
117 if (ret < 0)
118 return ret;
119
120 if (tries < 0) {
121 dev_err(&data->client->dev, "data not ready\n");
122 return -EIO;
123 }
124
125 return 0;
126}
127
128static int tcs3414_read_raw(struct iio_dev *indio_dev,
129 struct iio_chan_spec const *chan,
130 int *val, int *val2, long mask)
131{
132 struct tcs3414_data *data = iio_priv(indio_dev);
133 int i, ret;
134
135 switch (mask) {
136 case IIO_CHAN_INFO_RAW:
137 if (iio_buffer_enabled(indio_dev))
138 return -EBUSY;
139 mutex_lock(&data->lock);
140 ret = tcs3414_req_data(data);
141 if (ret < 0) {
142 mutex_unlock(&data->lock);
143 return ret;
144 }
145 ret = i2c_smbus_read_word_data(data->client, chan->address);
146 mutex_unlock(&data->lock);
147 if (ret < 0)
148 return ret;
149 *val = ret;
150 return IIO_VAL_INT;
151 case IIO_CHAN_INFO_SCALE:
152 i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
153 *val = tcs3414_scales[i][0];
154 *val2 = tcs3414_scales[i][1];
155 return IIO_VAL_INT_PLUS_MICRO;
156 case IIO_CHAN_INFO_INT_TIME:
157 *val = 0;
158 *val2 = tcs3414_times[data->timing & TCS3414_INTEG_MASK] * 1000;
159 return IIO_VAL_INT_PLUS_MICRO;
160 }
161 return -EINVAL;
162}
163
164static int tcs3414_write_raw(struct iio_dev *indio_dev,
165 struct iio_chan_spec const *chan,
166 int val, int val2, long mask)
167{
168 struct tcs3414_data *data = iio_priv(indio_dev);
169 int i;
170
171 switch (mask) {
172 case IIO_CHAN_INFO_SCALE:
173 for (i = 0; i < ARRAY_SIZE(tcs3414_scales); i++) {
174 if (val == tcs3414_scales[i][0] &&
175 val2 == tcs3414_scales[i][1]) {
176 data->gain &= ~TCS3414_GAIN_MASK;
177 data->gain |= i << TCS3414_GAIN_SHIFT;
178 return i2c_smbus_write_byte_data(
179 data->client, TCS3414_GAIN,
180 data->gain);
181 }
182 }
183 return -EINVAL;
184 case IIO_CHAN_INFO_INT_TIME:
185 if (val != 0)
186 return -EINVAL;
187 for (i = 0; i < ARRAY_SIZE(tcs3414_times); i++) {
188 if (val == tcs3414_times[i] * 1000) {
189 data->timing &= ~TCS3414_INTEG_MASK;
190 data->timing |= i;
191 return i2c_smbus_write_byte_data(
192 data->client, TCS3414_TIMING,
193 data->timing);
194 }
195 }
196 return -EINVAL;
197 default:
198 return -EINVAL;
199 }
200}
201
202static irqreturn_t tcs3414_trigger_handler(int irq, void *p)
203{
204 struct iio_poll_func *pf = p;
205 struct iio_dev *indio_dev = pf->indio_dev;
206 struct tcs3414_data *data = iio_priv(indio_dev);
207 int i, j = 0;
208
209 for_each_set_bit(i, indio_dev->active_scan_mask,
210 indio_dev->masklength) {
211 int ret = i2c_smbus_read_word_data(data->client,
212 TCS3414_DATA_GREEN + 2*i);
213 if (ret < 0)
214 goto done;
215
216 data->buffer[j++] = ret;
217 }
218
219 iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
220 iio_get_time_ns());
221
222done:
223 iio_trigger_notify_done(indio_dev->trig);
224
225 return IRQ_HANDLED;
226}
227
228static IIO_CONST_ATTR(scale_available, "1 0.25 0.0625 0.015625");
229static IIO_CONST_ATTR_INT_TIME_AVAIL("0.012 0.1 0.4");
230
231static struct attribute *tcs3414_attributes[] = {
232 &iio_const_attr_scale_available.dev_attr.attr,
233 &iio_const_attr_integration_time_available.dev_attr.attr,
234 NULL
235};
236
237static const struct attribute_group tcs3414_attribute_group = {
238 .attrs = tcs3414_attributes,
239};
240
241static const struct iio_info tcs3414_info = {
242 .read_raw = tcs3414_read_raw,
243 .write_raw = tcs3414_write_raw,
244 .attrs = &tcs3414_attribute_group,
245 .driver_module = THIS_MODULE,
246};
247
248static int tcs3414_buffer_preenable(struct iio_dev *indio_dev)
249{
250 struct tcs3414_data *data = iio_priv(indio_dev);
251
252 data->control |= TCS3414_CONTROL_ADC_EN;
253 return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
254 data->control);
255}
256
257static int tcs3414_buffer_predisable(struct iio_dev *indio_dev)
258{
259 struct tcs3414_data *data = iio_priv(indio_dev);
260 int ret;
261
262 ret = iio_triggered_buffer_predisable(indio_dev);
263 if (ret < 0)
264 return ret;
265
266 data->control &= ~TCS3414_CONTROL_ADC_EN;
267 return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
268 data->control);
269}
270
271static const struct iio_buffer_setup_ops tcs3414_buffer_setup_ops = {
272 .preenable = tcs3414_buffer_preenable,
273 .postenable = &iio_triggered_buffer_postenable,
274 .predisable = tcs3414_buffer_predisable,
275};
276
277static int tcs3414_probe(struct i2c_client *client,
278 const struct i2c_device_id *id)
279{
280 struct tcs3414_data *data;
281 struct iio_dev *indio_dev;
282 int ret;
283
284 indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
285 if (indio_dev == NULL)
286 return -ENOMEM;
287
288 data = iio_priv(indio_dev);
289 i2c_set_clientdata(client, indio_dev);
290 data->client = client;
291 mutex_init(&data->lock);
292
293 indio_dev->dev.parent = &client->dev;
294 indio_dev->info = &tcs3414_info;
295 indio_dev->name = TCS3414_DRV_NAME;
296 indio_dev->channels = tcs3414_channels;
297 indio_dev->num_channels = ARRAY_SIZE(tcs3414_channels);
298 indio_dev->modes = INDIO_DIRECT_MODE;
299
300 ret = i2c_smbus_read_byte_data(data->client, TCS3414_ID);
301 if (ret < 0)
302 return ret;
303
304 switch (ret & 0xf0) {
305 case 0x00:
306 dev_info(&client->dev, "TCS3404 found\n");
307 break;
308 case 0x10:
309 dev_info(&client->dev, "TCS3413/14/15/16 found\n");
310 break;
311 default:
312 return -ENODEV;
313 }
314
315 data->control = TCS3414_CONTROL_POWER;
316 ret = i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
317 data->control);
318 if (ret < 0)
319 return ret;
320
321 data->timing = TCS3414_INTEG_12MS; /* free running */
322 ret = i2c_smbus_write_byte_data(data->client, TCS3414_TIMING,
323 data->timing);
324 if (ret < 0)
325 return ret;
326
327 ret = i2c_smbus_read_byte_data(data->client, TCS3414_GAIN);
328 if (ret < 0)
329 return ret;
330 data->gain = ret;
331
332 ret = iio_triggered_buffer_setup(indio_dev, NULL,
333 tcs3414_trigger_handler, &tcs3414_buffer_setup_ops);
334 if (ret < 0)
335 return ret;
336
337 ret = iio_device_register(indio_dev);
338 if (ret < 0)
339 goto buffer_cleanup;
340
341 return 0;
342
343buffer_cleanup:
344 iio_triggered_buffer_cleanup(indio_dev);
345 return ret;
346}
347
348static int tcs3414_powerdown(struct tcs3414_data *data)
349{
350 return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
351 data->control & ~(TCS3414_CONTROL_POWER |
352 TCS3414_CONTROL_ADC_EN));
353}
354
355static int tcs3414_remove(struct i2c_client *client)
356{
357 struct iio_dev *indio_dev = i2c_get_clientdata(client);
358
359 iio_device_unregister(indio_dev);
360 iio_triggered_buffer_cleanup(indio_dev);
361 tcs3414_powerdown(iio_priv(indio_dev));
362
363 return 0;
364}
365
366#ifdef CONFIG_PM_SLEEP
367static int tcs3414_suspend(struct device *dev)
368{
369 struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
370 to_i2c_client(dev)));
371 return tcs3414_powerdown(data);
372}
373
374static int tcs3414_resume(struct device *dev)
375{
376 struct tcs3414_data *data = iio_priv(i2c_get_clientdata(
377 to_i2c_client(dev)));
378 return i2c_smbus_write_byte_data(data->client, TCS3414_CONTROL,
379 data->control);
380}
381#endif
382
383static SIMPLE_DEV_PM_OPS(tcs3414_pm_ops, tcs3414_suspend, tcs3414_resume);
384
385static const struct i2c_device_id tcs3414_id[] = {
386 { "tcs3414", 0 },
387 { }
388};
389MODULE_DEVICE_TABLE(i2c, tcs3414_id);
390
391static struct i2c_driver tcs3414_driver = {
392 .driver = {
393 .name = TCS3414_DRV_NAME,
394 .pm = &tcs3414_pm_ops,
395 .owner = THIS_MODULE,
396 },
397 .probe = tcs3414_probe,
398 .remove = tcs3414_remove,
399 .id_table = tcs3414_id,
400};
401module_i2c_driver(tcs3414_driver);
402
403MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
404MODULE_DESCRIPTION("TCS3414 digital color sensors driver");
405MODULE_LICENSE("GPL");