x86: Move pci_iommu_init to rootfs_initcall()
[cascardo/linux.git] / drivers / staging / iio / light / tsl2561.c
1 /*
2  *  tsl2561.c - Linux kernel modules for light to digital convertor
3  *
4  *  Copyright (C) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  *  Some portions based upon the tsl2550 driver.
21  *
22  *  This driver could probably be adapted easily to talk to the tsl2560 (smbus)
23  *
24  *  Needs some work to support the events this can generate.
25  *  Todo: Implement interrupt handling.  Currently a hardware bug means
26  *  this isn't available on my test board.
27  */
28
29 #include <linux/module.h>
30 #include <linux/init.h>
31 #include <linux/i2c.h>
32 #include "../iio.h"
33 #include "../sysfs.h"
34 #include "light.h"
35
36 #define TSL2561_CONTROL_REGISTER 0x00
37 #define TSL2561_TIMING_REGISTER 0x01
38 #define TSL2561_THRESHLOW_LOW_REGISTER 0x02
39 #define TSL2561_THRESHLOW_HIGH_REGISTER 0x03
40 #define TSL2561_THRESHHIGH_LOW_REGISTER 0x04
41 #define TSL2561_THRESHHIGH_HIGH_REGISTER 0x05
42 #define TSL2561_INT_CONTROL_REGISTER 0x06
43
44 #define TSL2561_INT_REG_INT_OFF 0x00
45 #define TSL2561_INT_REG_INT_LEVEL 0x08
46 #define TSL2561_INT_REG_INT_SMBUS 0x10
47 #define TSL2561_INT_REG_INT_TEST 0x18
48
49 #define TSL2561_ID_REGISTER 0x0A
50
51 #define TSL2561_DATA_0_LOW 0x0C
52 #define TSL2561_DATA_1_LOW 0x0E
53
54 /* Control Register Values */
55 #define TSL2561_CONT_REG_PWR_ON 0x03
56 #define TSL2561_CONT_REG_PWR_OFF 0x00
57
58 /**
59  * struct tsl2561_state - device specific state
60  * @indio_dev:          the industrialio I/O info structure
61  * @client:             i2c client
62  * @command_buf:        single command buffer used for all operations
63  * @command_buf_lock:   ensure unique access to command_buf
64  */
65 struct tsl2561_state {
66         struct iio_dev          *indio_dev;
67         struct i2c_client       *client;
68         struct tsl2561_command  *command_buf;
69         struct mutex            command_buf_lock;
70 };
71
72 /**
73  * struct tsl2561_command - command byte for smbus
74  * @address:    register address
75  * @block:      is this a block r/w
76  * @word:       is this a word r/w
77  * @clear:      set to 1 to clear pending interrupt
78  * @cmd:        select the command register - always 1.
79  */
80 struct tsl2561_command {
81         unsigned int address:4;
82         unsigned int block:1;
83         unsigned int word:1;
84         unsigned int clear:1;
85         unsigned int cmd:1;
86 };
87
88 static inline void tsl2561_init_command_buf(struct tsl2561_command *buf)
89 {
90         buf->address = 0;
91         buf->block = 0;
92         buf->word = 0;
93         buf->clear = 0;
94         buf->cmd = 1;
95 }
96
97 static ssize_t tsl2561_read_val(struct device *dev,
98                                 struct device_attribute *attr,
99                                 char *buf)
100 {
101         int ret = 0, data;
102         ssize_t len = 0;
103         struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
104         struct iio_dev *indio_dev = dev_get_drvdata(dev);
105         struct tsl2561_state *st = indio_dev->dev_data;
106
107         mutex_lock(&st->command_buf_lock);
108         st->command_buf->cmd = 1;
109         st->command_buf->word = 1;
110         st->command_buf->address = this_attr->address;
111
112         data = i2c_smbus_read_word_data(st->client, *(char *)(st->command_buf));
113         if (data < 0) {
114                 ret = data;
115                 goto error_ret;
116         }
117         len = sprintf(buf, "%u\n", data);
118
119 error_ret:
120         mutex_unlock(&st->command_buf_lock);
121
122         return ret ? ret : len;
123 }
124
125 static IIO_DEV_ATTR_LIGHT_INFRARED(0, tsl2561_read_val, TSL2561_DATA_0_LOW);
126 static IIO_DEV_ATTR_LIGHT_BROAD(0, tsl2561_read_val, TSL2561_DATA_1_LOW);
127
128 static struct attribute *tsl2561_attributes[] = {
129         &iio_dev_attr_light_infrared0.dev_attr.attr,
130         &iio_dev_attr_light_broadspectrum0.dev_attr.attr,
131         NULL,
132 };
133
134 static const struct attribute_group tsl2561_attribute_group = {
135         .attrs = tsl2561_attributes,
136 };
137
138 static int tsl2561_initialize(struct tsl2561_state *st)
139 {
140         int err;
141
142         mutex_lock(&st->command_buf_lock);
143         st->command_buf->word = 0;
144         st->command_buf->block = 0;
145         st->command_buf->address = TSL2561_CONTROL_REGISTER;
146         err = i2c_smbus_write_byte_data(st->client, *(char *)(st->command_buf),
147                                         TSL2561_CONT_REG_PWR_ON);
148         if (err)
149                 goto error_ret;
150
151         st->command_buf->address = TSL2561_INT_CONTROL_REGISTER;
152         err = i2c_smbus_write_byte_data(st->client, *(char *)(st->command_buf),
153                                         TSL2561_INT_REG_INT_TEST);
154
155 error_ret:
156         mutex_unlock(&st->command_buf_lock);
157
158         return err;
159 }
160
161 static int tsl2561_powerdown(struct i2c_client *client)
162 {
163         int err;
164         struct tsl2561_command Command = {
165                 .cmd =  1,
166                 .clear = 0,
167                 .word = 0,
168                 .block = 0,
169                 .address = TSL2561_CONTROL_REGISTER,
170         };
171
172         err = i2c_smbus_write_byte_data(client, *(char *)(&Command),
173                                         TSL2561_CONT_REG_PWR_OFF);
174         return (err < 0) ? err : 0;
175 }
176 static int __devinit tsl2561_probe(struct i2c_client *client,
177                                    const struct i2c_device_id *id)
178 {
179         int ret = 0, regdone = 0;
180         struct tsl2561_state *st = kzalloc(sizeof(*st), GFP_KERNEL);
181
182         if (st == NULL) {
183                 ret = -ENOMEM;
184                 goto error_ret;
185         }
186         i2c_set_clientdata(client, st);
187         st->client = client;
188         mutex_init(&st->command_buf_lock);
189
190         st->command_buf = kmalloc(sizeof(*st->command_buf), GFP_KERNEL);
191         if (st->command_buf == NULL) {
192                 ret = -ENOMEM;
193                 goto error_free_state;
194         }
195         tsl2561_init_command_buf(st->command_buf);
196
197         st->indio_dev = iio_allocate_device();
198         if (st->indio_dev == NULL) {
199                 ret = -ENOMEM;
200                 goto error_free_command_buf;
201         }
202         st->indio_dev->attrs = &tsl2561_attribute_group;
203         st->indio_dev->dev.parent = &client->dev;
204         st->indio_dev->dev_data = (void *)(st);
205         st->indio_dev->driver_module = THIS_MODULE;
206         st->indio_dev->modes = INDIO_DIRECT_MODE;
207         ret = iio_device_register(st->indio_dev);
208         if (ret)
209                 goto error_free_iiodev;
210         regdone = 1;
211         /* Intialize the chip */
212         ret = tsl2561_initialize(st);
213         if (ret)
214                 goto error_unregister_iiodev;
215
216         return 0;
217 error_unregister_iiodev:
218 error_free_iiodev:
219         if (regdone)
220                 iio_device_unregister(st->indio_dev);
221         else
222                 iio_free_device(st->indio_dev);
223 error_free_command_buf:
224         kfree(st->command_buf);
225 error_free_state:
226         kfree(st);
227 error_ret:
228         return ret;
229
230 }
231
232 static int __devexit tsl2561_remove(struct i2c_client *client)
233 {
234         struct tsl2561_state *st =  i2c_get_clientdata(client);
235
236         iio_device_unregister(st->indio_dev);
237         kfree(st);
238
239         return tsl2561_powerdown(client);
240 }
241
242 static unsigned short normal_i2c[] = { 0x29, 0x39, 0x49, I2C_CLIENT_END };
243
244 I2C_CLIENT_INSMOD;
245
246 static const struct i2c_device_id tsl2561_id[] = {
247         { "tsl2561", 0 },
248         { }
249 };
250 MODULE_DEVICE_TABLE(i2c, tsl2561_id);
251
252
253 static struct i2c_driver tsl2561_driver = {
254         .driver = {
255                 .name = "tsl2561",
256         },
257         .probe = tsl2561_probe,
258         .remove = __devexit_p(tsl2561_remove),
259         .id_table  = tsl2561_id,
260 };
261
262 static __init int tsl2561_init(void)
263 {
264         return i2c_add_driver(&tsl2561_driver);
265 }
266 module_init(tsl2561_init);
267
268 static __exit void tsl2561_exit(void)
269 {
270         i2c_del_driver(&tsl2561_driver);
271 }
272 module_exit(tsl2561_exit);
273
274 MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>");
275 MODULE_DESCRIPTION("TSL2561 light sensor driver");
276 MODULE_LICENSE("GPL");