Merge branch 'acpi-cleanup'
[firefly-linux-kernel-4.4.55.git] / drivers / iio / light / adjd_s311.c
1 /*
2  * adjd_s311.c - Support for ADJD-S311-CR999 digital color sensor
3  *
4  * Copyright (C) 2012 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  * driver for ADJD-S311-CR999 digital color sensor (10-bit channels for
11  * red, green, blue, clear); 7-bit I2C slave address 0x74
12  *
13  * limitations: no calibration, no offset mode, no sleep mode
14  */
15
16 #include <linux/module.h>
17 #include <linux/init.h>
18 #include <linux/interrupt.h>
19 #include <linux/i2c.h>
20 #include <linux/slab.h>
21 #include <linux/delay.h>
22 #include <linux/bitmap.h>
23 #include <linux/err.h>
24 #include <linux/irq.h>
25
26 #include <linux/iio/iio.h>
27 #include <linux/iio/sysfs.h>
28 #include <linux/iio/trigger_consumer.h>
29 #include <linux/iio/buffer.h>
30 #include <linux/iio/triggered_buffer.h>
31
32 #define ADJD_S311_DRV_NAME "adjd_s311"
33
34 #define ADJD_S311_CTRL          0x00
35 #define ADJD_S311_CONFIG        0x01
36 #define ADJD_S311_CAP_RED       0x06
37 #define ADJD_S311_CAP_GREEN     0x07
38 #define ADJD_S311_CAP_BLUE      0x08
39 #define ADJD_S311_CAP_CLEAR     0x09
40 #define ADJD_S311_INT_RED_LO    0x0a
41 #define ADJD_S311_INT_RED_HI    0x0b
42 #define ADJD_S311_INT_GREEN_LO  0x0c
43 #define ADJD_S311_INT_GREEN_HI  0x0d
44 #define ADJD_S311_INT_BLUE_LO   0x0e
45 #define ADJD_S311_INT_BLUE_HI   0x0f
46 #define ADJD_S311_INT_CLEAR_LO  0x10
47 #define ADJD_S311_INT_CLEAR_HI  0x11
48 #define ADJD_S311_DATA_RED_LO   0x40
49 #define ADJD_S311_DATA_RED_HI   0x41
50 #define ADJD_S311_DATA_GREEN_LO 0x42
51 #define ADJD_S311_DATA_GREEN_HI 0x43
52 #define ADJD_S311_DATA_BLUE_LO  0x44
53 #define ADJD_S311_DATA_BLUE_HI  0x45
54 #define ADJD_S311_DATA_CLEAR_LO 0x46
55 #define ADJD_S311_DATA_CLEAR_HI 0x47
56 #define ADJD_S311_OFFSET_RED    0x48
57 #define ADJD_S311_OFFSET_GREEN  0x49
58 #define ADJD_S311_OFFSET_BLUE   0x4a
59 #define ADJD_S311_OFFSET_CLEAR  0x4b
60
61 #define ADJD_S311_CTRL_GOFS     0x02
62 #define ADJD_S311_CTRL_GSSR     0x01
63 #define ADJD_S311_CAP_MASK      0x0f
64 #define ADJD_S311_INT_MASK      0x0fff
65 #define ADJD_S311_DATA_MASK     0x03ff
66
67 struct adjd_s311_data {
68         struct i2c_client *client;
69         u16 *buffer;
70 };
71
72 enum adjd_s311_channel_idx {
73         IDX_RED, IDX_GREEN, IDX_BLUE, IDX_CLEAR
74 };
75
76 #define ADJD_S311_DATA_REG(chan) (ADJD_S311_DATA_RED_LO + (chan) * 2)
77 #define ADJD_S311_INT_REG(chan) (ADJD_S311_INT_RED_LO + (chan) * 2)
78 #define ADJD_S311_CAP_REG(chan) (ADJD_S311_CAP_RED + (chan))
79
80 static int adjd_s311_req_data(struct iio_dev *indio_dev)
81 {
82         struct adjd_s311_data *data = iio_priv(indio_dev);
83         int tries = 10;
84
85         int ret = i2c_smbus_write_byte_data(data->client, ADJD_S311_CTRL,
86                 ADJD_S311_CTRL_GSSR);
87         if (ret < 0)
88                 return ret;
89
90         while (tries--) {
91                 ret = i2c_smbus_read_byte_data(data->client, ADJD_S311_CTRL);
92                 if (ret < 0)
93                         return ret;
94                 if (!(ret & ADJD_S311_CTRL_GSSR))
95                         break;
96                 msleep(20);
97         }
98
99         if (tries < 0) {
100                 dev_err(&data->client->dev,
101                         "adjd_s311_req_data() failed, data not ready\n");
102                 return -EIO;
103         }
104
105         return 0;
106 }
107
108 static int adjd_s311_read_data(struct iio_dev *indio_dev, u8 reg, int *val)
109 {
110         struct adjd_s311_data *data = iio_priv(indio_dev);
111
112         int ret = adjd_s311_req_data(indio_dev);
113         if (ret < 0)
114                 return ret;
115
116         ret = i2c_smbus_read_word_data(data->client, reg);
117         if (ret < 0)
118                 return ret;
119
120         *val = ret & ADJD_S311_DATA_MASK;
121
122         return 0;
123 }
124
125 static ssize_t adjd_s311_read_int_time(struct iio_dev *indio_dev,
126         uintptr_t private, const struct iio_chan_spec *chan, char *buf)
127 {
128         struct adjd_s311_data *data = iio_priv(indio_dev);
129         s32 ret;
130
131         ret = i2c_smbus_read_word_data(data->client,
132                 ADJD_S311_INT_REG(chan->address));
133         if (ret < 0)
134                 return ret;
135
136         return sprintf(buf, "%d\n", ret & ADJD_S311_INT_MASK);
137 }
138
139 static ssize_t adjd_s311_write_int_time(struct iio_dev *indio_dev,
140          uintptr_t private, const struct iio_chan_spec *chan, const char *buf,
141          size_t len)
142 {
143         struct adjd_s311_data *data = iio_priv(indio_dev);
144         unsigned long int_time;
145         int ret;
146
147         ret = kstrtoul(buf, 10, &int_time);
148         if (ret)
149                 return ret;
150
151         if (int_time > ADJD_S311_INT_MASK)
152                 return -EINVAL;
153
154         ret = i2c_smbus_write_word_data(data->client,
155                 ADJD_S311_INT_REG(chan->address), int_time);
156         if (ret < 0)
157                 return ret;
158
159         return len;
160 }
161
162 static irqreturn_t adjd_s311_trigger_handler(int irq, void *p)
163 {
164         struct iio_poll_func *pf = p;
165         struct iio_dev *indio_dev = pf->indio_dev;
166         struct adjd_s311_data *data = iio_priv(indio_dev);
167         s64 time_ns = iio_get_time_ns();
168         int len = 0;
169         int i, j = 0;
170
171         int ret = adjd_s311_req_data(indio_dev);
172         if (ret < 0)
173                 goto done;
174
175         for_each_set_bit(i, indio_dev->active_scan_mask,
176                 indio_dev->masklength) {
177                 ret = i2c_smbus_read_word_data(data->client,
178                         ADJD_S311_DATA_REG(i));
179                 if (ret < 0)
180                         goto done;
181
182                 data->buffer[j++] = ret & ADJD_S311_DATA_MASK;
183                 len += 2;
184         }
185
186         if (indio_dev->scan_timestamp)
187                 *(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64)))
188                         = time_ns;
189         iio_push_to_buffers(indio_dev, (u8 *)data->buffer);
190
191 done:
192         iio_trigger_notify_done(indio_dev->trig);
193
194         return IRQ_HANDLED;
195 }
196
197 static const struct iio_chan_spec_ext_info adjd_s311_ext_info[] = {
198         {
199                 .name = "integration_time",
200                 .read = adjd_s311_read_int_time,
201                 .write = adjd_s311_write_int_time,
202         },
203         { }
204 };
205
206 #define ADJD_S311_CHANNEL(_color, _scan_idx) { \
207         .type = IIO_INTENSITY, \
208         .modified = 1, \
209         .address = (IDX_##_color), \
210         .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
211                 BIT(IIO_CHAN_INFO_HARDWAREGAIN), \
212         .channel2 = (IIO_MOD_LIGHT_##_color), \
213         .scan_index = (_scan_idx), \
214         .scan_type = IIO_ST('u', 10, 16, 0), \
215         .ext_info = adjd_s311_ext_info, \
216 }
217
218 static const struct iio_chan_spec adjd_s311_channels[] = {
219         ADJD_S311_CHANNEL(RED, 0),
220         ADJD_S311_CHANNEL(GREEN, 1),
221         ADJD_S311_CHANNEL(BLUE, 2),
222         ADJD_S311_CHANNEL(CLEAR, 3),
223         IIO_CHAN_SOFT_TIMESTAMP(4),
224 };
225
226 static int adjd_s311_read_raw(struct iio_dev *indio_dev,
227                            struct iio_chan_spec const *chan,
228                            int *val, int *val2, long mask)
229 {
230         struct adjd_s311_data *data = iio_priv(indio_dev);
231         int ret;
232
233         switch (mask) {
234         case IIO_CHAN_INFO_RAW:
235                 ret = adjd_s311_read_data(indio_dev,
236                         ADJD_S311_DATA_REG(chan->address), val);
237                 if (ret < 0)
238                         return ret;
239                 return IIO_VAL_INT;
240         case IIO_CHAN_INFO_HARDWAREGAIN:
241                 ret = i2c_smbus_read_byte_data(data->client,
242                         ADJD_S311_CAP_REG(chan->address));
243                 if (ret < 0)
244                         return ret;
245                 *val = ret & ADJD_S311_CAP_MASK;
246                 return IIO_VAL_INT;
247         }
248         return -EINVAL;
249 }
250
251 static int adjd_s311_write_raw(struct iio_dev *indio_dev,
252                                struct iio_chan_spec const *chan,
253                                int val, int val2, long mask)
254 {
255         struct adjd_s311_data *data = iio_priv(indio_dev);
256         int ret;
257
258         switch (mask) {
259         case IIO_CHAN_INFO_HARDWAREGAIN:
260                 if (val < 0 || val > ADJD_S311_CAP_MASK)
261                         return -EINVAL;
262
263                 ret = i2c_smbus_write_byte_data(data->client,
264                         ADJD_S311_CAP_REG(chan->address), val);
265                 return ret;
266         }
267         return -EINVAL;
268 }
269
270 static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
271         const unsigned long *scan_mask)
272 {
273         struct adjd_s311_data *data = iio_priv(indio_dev);
274
275         kfree(data->buffer);
276         data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
277         if (data->buffer == NULL)
278                 return -ENOMEM;
279
280         return 0;
281 }
282
283 static const struct iio_info adjd_s311_info = {
284         .read_raw = adjd_s311_read_raw,
285         .write_raw = adjd_s311_write_raw,
286         .update_scan_mode = adjd_s311_update_scan_mode,
287         .driver_module = THIS_MODULE,
288 };
289
290 static int adjd_s311_probe(struct i2c_client *client,
291                            const struct i2c_device_id *id)
292 {
293         struct adjd_s311_data *data;
294         struct iio_dev *indio_dev;
295         int err;
296
297         indio_dev = iio_device_alloc(sizeof(*data));
298         if (indio_dev == NULL) {
299                 err = -ENOMEM;
300                 goto exit;
301         }
302         data = iio_priv(indio_dev);
303         i2c_set_clientdata(client, indio_dev);
304         data->client = client;
305
306         indio_dev->dev.parent = &client->dev;
307         indio_dev->info = &adjd_s311_info;
308         indio_dev->name = ADJD_S311_DRV_NAME;
309         indio_dev->channels = adjd_s311_channels;
310         indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
311         indio_dev->modes = INDIO_DIRECT_MODE;
312
313         err = iio_triggered_buffer_setup(indio_dev, NULL,
314                 adjd_s311_trigger_handler, NULL);
315         if (err < 0)
316                 goto exit_free_device;
317
318         err = iio_device_register(indio_dev);
319         if (err)
320                 goto exit_unreg_buffer;
321
322         dev_info(&client->dev, "ADJD-S311 color sensor registered\n");
323
324         return 0;
325
326 exit_unreg_buffer:
327         iio_triggered_buffer_cleanup(indio_dev);
328 exit_free_device:
329         iio_device_free(indio_dev);
330 exit:
331         return err;
332 }
333
334 static int adjd_s311_remove(struct i2c_client *client)
335 {
336         struct iio_dev *indio_dev = i2c_get_clientdata(client);
337         struct adjd_s311_data *data = iio_priv(indio_dev);
338
339         iio_device_unregister(indio_dev);
340         iio_triggered_buffer_cleanup(indio_dev);
341         kfree(data->buffer);
342         iio_device_free(indio_dev);
343
344         return 0;
345 }
346
347 static const struct i2c_device_id adjd_s311_id[] = {
348         { "adjd_s311", 0 },
349         { }
350 };
351 MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
352
353 static struct i2c_driver adjd_s311_driver = {
354         .driver = {
355                 .name   = ADJD_S311_DRV_NAME,
356         },
357         .probe          = adjd_s311_probe,
358         .remove         = adjd_s311_remove,
359         .id_table       = adjd_s311_id,
360 };
361 module_i2c_driver(adjd_s311_driver);
362
363 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
364 MODULE_DESCRIPTION("ADJD-S311 color sensor");
365 MODULE_LICENSE("GPL");