Drivers: iio: remove __dev* attributes.
[pandora-kernel.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 = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \
211                 IIO_CHAN_INFO_HARDWAREGAIN_SEPARATE_BIT, \
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, chan->address, val);
236                 if (ret < 0)
237                         return ret;
238                 return IIO_VAL_INT;
239         case IIO_CHAN_INFO_HARDWAREGAIN:
240                 ret = i2c_smbus_read_byte_data(data->client,
241                         ADJD_S311_CAP_REG(chan->address));
242                 if (ret < 0)
243                         return ret;
244                 *val = ret & ADJD_S311_CAP_MASK;
245                 return IIO_VAL_INT;
246         }
247         return -EINVAL;
248 }
249
250 static int adjd_s311_write_raw(struct iio_dev *indio_dev,
251                                struct iio_chan_spec const *chan,
252                                int val, int val2, long mask)
253 {
254         struct adjd_s311_data *data = iio_priv(indio_dev);
255         int ret;
256
257         switch (mask) {
258         case IIO_CHAN_INFO_HARDWAREGAIN:
259                 if (val < 0 || val > ADJD_S311_CAP_MASK)
260                         return -EINVAL;
261
262                 ret = i2c_smbus_write_byte_data(data->client,
263                         ADJD_S311_CAP_REG(chan->address), val);
264                 return ret;
265         }
266         return -EINVAL;
267 }
268
269 static int adjd_s311_update_scan_mode(struct iio_dev *indio_dev,
270         const unsigned long *scan_mask)
271 {
272         struct adjd_s311_data *data = iio_priv(indio_dev);
273
274         kfree(data->buffer);
275         data->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
276         if (data->buffer == NULL)
277                 return -ENOMEM;
278
279         return 0;
280 }
281
282 static const struct iio_info adjd_s311_info = {
283         .read_raw = adjd_s311_read_raw,
284         .write_raw = adjd_s311_write_raw,
285         .update_scan_mode = adjd_s311_update_scan_mode,
286         .driver_module = THIS_MODULE,
287 };
288
289 static int adjd_s311_probe(struct i2c_client *client,
290                            const struct i2c_device_id *id)
291 {
292         struct adjd_s311_data *data;
293         struct iio_dev *indio_dev;
294         int err;
295
296         indio_dev = iio_device_alloc(sizeof(*data));
297         if (indio_dev == NULL) {
298                 err = -ENOMEM;
299                 goto exit;
300         }
301         data = iio_priv(indio_dev);
302         i2c_set_clientdata(client, indio_dev);
303         data->client = client;
304
305         indio_dev->dev.parent = &client->dev;
306         indio_dev->info = &adjd_s311_info;
307         indio_dev->name = ADJD_S311_DRV_NAME;
308         indio_dev->channels = adjd_s311_channels;
309         indio_dev->num_channels = ARRAY_SIZE(adjd_s311_channels);
310         indio_dev->modes = INDIO_DIRECT_MODE;
311
312         err = iio_triggered_buffer_setup(indio_dev, NULL,
313                 adjd_s311_trigger_handler, NULL);
314         if (err < 0)
315                 goto exit_free_device;
316
317         err = iio_device_register(indio_dev);
318         if (err)
319                 goto exit_unreg_buffer;
320
321         dev_info(&client->dev, "ADJD-S311 color sensor registered\n");
322
323         return 0;
324
325 exit_unreg_buffer:
326         iio_triggered_buffer_cleanup(indio_dev);
327 exit_free_device:
328         iio_device_free(indio_dev);
329 exit:
330         return err;
331 }
332
333 static int adjd_s311_remove(struct i2c_client *client)
334 {
335         struct iio_dev *indio_dev = i2c_get_clientdata(client);
336         struct adjd_s311_data *data = iio_priv(indio_dev);
337
338         iio_device_unregister(indio_dev);
339         iio_triggered_buffer_cleanup(indio_dev);
340         kfree(data->buffer);
341         iio_device_free(indio_dev);
342
343         return 0;
344 }
345
346 static const struct i2c_device_id adjd_s311_id[] = {
347         { "adjd_s311", 0 },
348         { }
349 };
350 MODULE_DEVICE_TABLE(i2c, adjd_s311_id);
351
352 static struct i2c_driver adjd_s311_driver = {
353         .driver = {
354                 .name   = ADJD_S311_DRV_NAME,
355         },
356         .probe          = adjd_s311_probe,
357         .remove         = adjd_s311_remove,
358         .id_table       = adjd_s311_id,
359 };
360 module_i2c_driver(adjd_s311_driver);
361
362 MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>");
363 MODULE_DESCRIPTION("ADJD-S311 color sensor");
364 MODULE_LICENSE("GPL");