blob: 59c2c662cc45ce2c07a8888d5711034d8cf6f08c [file] [log] [blame]
Rodolfo Giomettia92c3442007-07-12 14:12:30 +02001/*
2 * tsl2550.c - Linux kernel modules for ambient light sensor
3 *
4 * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
5 * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22#include <linux/module.h>
23#include <linux/init.h>
24#include <linux/slab.h>
25#include <linux/i2c.h>
26#include <linux/mutex.h>
27#include <linux/delay.h>
28
29#define TSL2550_DRV_NAME "tsl2550"
Jean Delvaree296fb72007-07-12 14:12:31 +020030#define DRIVER_VERSION "1.1.1"
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020031
32/*
33 * Defines
34 */
35
36#define TSL2550_POWER_DOWN 0x00
37#define TSL2550_POWER_UP 0x03
38#define TSL2550_STANDARD_RANGE 0x18
39#define TSL2550_EXTENDED_RANGE 0x1d
40#define TSL2550_READ_ADC0 0x43
41#define TSL2550_READ_ADC1 0x83
42
43/*
44 * Structs
45 */
46
47struct tsl2550_data {
48 struct i2c_client *client;
49 struct mutex update_lock;
50
51 unsigned int power_state : 1;
52 unsigned int operating_mode : 1;
53};
54
55/*
56 * Global data
57 */
58
59static const u8 TSL2550_MODE_RANGE[2] = {
60 TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
61};
62
63/*
64 * Management functions
65 */
66
67static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
68{
69 struct tsl2550_data *data = i2c_get_clientdata(client);
70
71 int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
72
73 data->operating_mode = mode;
74
75 return ret;
76}
77
78static int tsl2550_set_power_state(struct i2c_client *client, int state)
79{
80 struct tsl2550_data *data = i2c_get_clientdata(client);
81 int ret;
82
83 if (state == 0)
84 ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
85 else {
86 ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
87
88 /* On power up we should reset operating mode also... */
89 tsl2550_set_operating_mode(client, data->operating_mode);
90 }
91
92 data->power_state = state;
93
94 return ret;
95}
96
97static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
98{
99 unsigned long end;
100 int loop = 0, ret = 0;
101
102 /*
103 * Read ADC channel waiting at most 400ms (see data sheet for further
104 * info).
105 * To avoid long busy wait we spin for few milliseconds then
106 * start sleeping.
107 */
108 end = jiffies + msecs_to_jiffies(400);
109 while (time_before(jiffies, end)) {
110 i2c_smbus_write_byte(client, cmd);
111
112 if (loop++ < 5)
113 mdelay(1);
114 else
115 msleep(1);
116
117 ret = i2c_smbus_read_byte(client);
118 if (ret < 0)
119 return ret;
120 else if (ret & 0x0080)
121 break;
122 }
123 if (!(ret & 0x80))
124 return -EIO;
125 return ret & 0x7f; /* remove the "valid" bit */
126}
127
128/*
129 * LUX calculation
130 */
131
132#define TSL2550_MAX_LUX 1846
133
134static const u8 ratio_lut[] = {
135 100, 100, 100, 100, 100, 100, 100, 100,
136 100, 100, 100, 100, 100, 100, 99, 99,
137 99, 99, 99, 99, 99, 99, 99, 99,
138 99, 99, 99, 98, 98, 98, 98, 98,
139 98, 98, 97, 97, 97, 97, 97, 96,
140 96, 96, 96, 95, 95, 95, 94, 94,
141 93, 93, 93, 92, 92, 91, 91, 90,
142 89, 89, 88, 87, 87, 86, 85, 84,
143 83, 82, 81, 80, 79, 78, 77, 75,
144 74, 73, 71, 69, 68, 66, 64, 62,
145 60, 58, 56, 54, 52, 49, 47, 44,
146 42, 41, 40, 40, 39, 39, 38, 38,
147 37, 37, 37, 36, 36, 36, 35, 35,
148 35, 35, 34, 34, 34, 34, 33, 33,
149 33, 33, 32, 32, 32, 32, 32, 31,
150 31, 31, 31, 31, 30, 30, 30, 30,
151 30,
152};
153
154static const u16 count_lut[] = {
155 0, 1, 2, 3, 4, 5, 6, 7,
156 8, 9, 10, 11, 12, 13, 14, 15,
157 16, 18, 20, 22, 24, 26, 28, 30,
158 32, 34, 36, 38, 40, 42, 44, 46,
159 49, 53, 57, 61, 65, 69, 73, 77,
160 81, 85, 89, 93, 97, 101, 105, 109,
161 115, 123, 131, 139, 147, 155, 163, 171,
162 179, 187, 195, 203, 211, 219, 227, 235,
163 247, 263, 279, 295, 311, 327, 343, 359,
164 375, 391, 407, 423, 439, 455, 471, 487,
165 511, 543, 575, 607, 639, 671, 703, 735,
166 767, 799, 831, 863, 895, 927, 959, 991,
167 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
168 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
169 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
170 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
171};
172
173/*
174 * This function is described into Taos TSL2550 Designer's Notebook
175 * pages 2, 3.
176 */
177static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
178{
179 unsigned int lux;
180
181 /* Look up count from channel values */
182 u16 c0 = count_lut[ch0];
183 u16 c1 = count_lut[ch1];
184
185 /*
186 * Calculate ratio.
187 * Note: the "128" is a scaling factor
188 */
189 u8 r = 128;
190
191 /* Avoid division by 0 and count 1 cannot be greater than count 0 */
192 if (c0 && (c1 <= c0))
193 r = c1 * 128 / c0;
194 else
195 return -1;
196
197 /* Calculate LUX */
198 lux = ((c0 - c1) * ratio_lut[r]) / 256;
199
200 /* LUX range check */
201 return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
202}
203
204/*
205 * SysFS support
206 */
207
208static ssize_t tsl2550_show_power_state(struct device *dev,
209 struct device_attribute *attr, char *buf)
210{
211 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
212
213 return sprintf(buf, "%u\n", data->power_state);
214}
215
216static ssize_t tsl2550_store_power_state(struct device *dev,
217 struct device_attribute *attr, const char *buf, size_t count)
218{
219 struct i2c_client *client = to_i2c_client(dev);
220 struct tsl2550_data *data = i2c_get_clientdata(client);
221 unsigned long val = simple_strtoul(buf, NULL, 10);
222 int ret;
223
224 if (val < 0 || val > 1)
225 return -EINVAL;
226
227 mutex_lock(&data->update_lock);
228 ret = tsl2550_set_power_state(client, val);
229 mutex_unlock(&data->update_lock);
230
231 if (ret < 0)
232 return ret;
233
234 return count;
235}
236
237static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
238 tsl2550_show_power_state, tsl2550_store_power_state);
239
240static ssize_t tsl2550_show_operating_mode(struct device *dev,
241 struct device_attribute *attr, char *buf)
242{
243 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
244
245 return sprintf(buf, "%u\n", data->operating_mode);
246}
247
248static ssize_t tsl2550_store_operating_mode(struct device *dev,
249 struct device_attribute *attr, const char *buf, size_t count)
250{
251 struct i2c_client *client = to_i2c_client(dev);
252 struct tsl2550_data *data = i2c_get_clientdata(client);
253 unsigned long val = simple_strtoul(buf, NULL, 10);
254 int ret;
255
256 if (val < 0 || val > 1)
257 return -EINVAL;
258
259 if (data->power_state == 0)
260 return -EBUSY;
261
262 mutex_lock(&data->update_lock);
263 ret = tsl2550_set_operating_mode(client, val);
264 mutex_unlock(&data->update_lock);
265
266 if (ret < 0)
267 return ret;
268
269 return count;
270}
271
272static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
273 tsl2550_show_operating_mode, tsl2550_store_operating_mode);
274
275static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
276{
277 u8 ch0, ch1;
278 int ret;
279
280 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
281 if (ret < 0)
282 return ret;
283 ch0 = ret;
284
285 mdelay(1);
286
287 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
288 if (ret < 0)
289 return ret;
290 ch1 = ret;
291
292 /* Do the job */
293 ret = tsl2550_calculate_lux(ch0, ch1);
294 if (ret < 0)
295 return ret;
296
297 return sprintf(buf, "%d\n", ret);
298}
299
300static ssize_t tsl2550_show_lux1_input(struct device *dev,
301 struct device_attribute *attr, char *buf)
302{
303 struct i2c_client *client = to_i2c_client(dev);
304 struct tsl2550_data *data = i2c_get_clientdata(client);
305 int ret;
306
307 /* No LUX data if not operational */
308 if (!data->power_state)
309 return -EBUSY;
310
311 mutex_lock(&data->update_lock);
312 ret = __tsl2550_show_lux(client, buf);
313 mutex_unlock(&data->update_lock);
314
315 return ret;
316}
317
318static DEVICE_ATTR(lux1_input, S_IRUGO,
319 tsl2550_show_lux1_input, NULL);
320
321static struct attribute *tsl2550_attributes[] = {
322 &dev_attr_power_state.attr,
323 &dev_attr_operating_mode.attr,
324 &dev_attr_lux1_input.attr,
325 NULL
326};
327
328static const struct attribute_group tsl2550_attr_group = {
329 .attrs = tsl2550_attributes,
330};
331
332/*
333 * Initialization function
334 */
335
Jean Delvaree296fb72007-07-12 14:12:31 +0200336static int tsl2550_init_client(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200337{
338 struct tsl2550_data *data = i2c_get_clientdata(client);
Jean Delvaree296fb72007-07-12 14:12:31 +0200339 int err;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200340
Jean Delvaree296fb72007-07-12 14:12:31 +0200341 /*
342 * Probe the chip. To do so we try to power up the device and then to
343 * read back the 0x03 code
344 */
345 err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
346 if (err < 0)
347 return err;
348 mdelay(1);
349 if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
350 return -ENODEV;
351 data->power_state = 1;
352
353 /* Set the default operating mode */
354 err = i2c_smbus_write_byte(client,
355 TSL2550_MODE_RANGE[data->operating_mode]);
356 if (err < 0)
357 return err;
358
359 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200360}
361
362/*
363 * I2C init/probing/exit functions
364 */
365
366static struct i2c_driver tsl2550_driver;
Jean Delvared2653e92008-04-29 23:11:39 +0200367static int __devinit tsl2550_probe(struct i2c_client *client,
368 const struct i2c_device_id *id)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200369{
370 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
371 struct tsl2550_data *data;
372 int *opmode, err = 0;
373
374 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
375 err = -EIO;
376 goto exit;
377 }
378
379 data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
380 if (!data) {
381 err = -ENOMEM;
382 goto exit;
383 }
384 data->client = client;
385 i2c_set_clientdata(client, data);
386
387 /* Check platform data */
388 opmode = client->dev.platform_data;
389 if (opmode) {
390 if (*opmode < 0 || *opmode > 1) {
391 dev_err(&client->dev, "invalid operating_mode (%d)\n",
392 *opmode);
393 err = -EINVAL;
394 goto exit_kfree;
395 }
396 data->operating_mode = *opmode;
397 } else
398 data->operating_mode = 0; /* default mode is standard */
399 dev_info(&client->dev, "%s operating mode\n",
400 data->operating_mode ? "extended" : "standard");
401
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200402 mutex_init(&data->update_lock);
403
404 /* Initialize the TSL2550 chip */
Jean Delvaree296fb72007-07-12 14:12:31 +0200405 err = tsl2550_init_client(client);
406 if (err)
407 goto exit_kfree;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200408
409 /* Register sysfs hooks */
410 err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
411 if (err)
412 goto exit_kfree;
413
414 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
415
416 return 0;
417
418exit_kfree:
419 kfree(data);
420exit:
421 return err;
422}
423
424static int __devexit tsl2550_remove(struct i2c_client *client)
425{
426 sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
427
428 /* Power down the device */
429 tsl2550_set_power_state(client, 0);
430
431 kfree(i2c_get_clientdata(client));
432
433 return 0;
434}
435
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100436#ifdef CONFIG_PM
437
438static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
439{
440 return tsl2550_set_power_state(client, 0);
441}
442
443static int tsl2550_resume(struct i2c_client *client)
444{
445 return tsl2550_set_power_state(client, 1);
446}
447
448#else
449
450#define tsl2550_suspend NULL
451#define tsl2550_resume NULL
452
453#endif /* CONFIG_PM */
454
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200455static struct i2c_driver tsl2550_driver = {
456 .driver = {
457 .name = TSL2550_DRV_NAME,
458 .owner = THIS_MODULE,
459 },
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100460 .suspend = tsl2550_suspend,
461 .resume = tsl2550_resume,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200462 .probe = tsl2550_probe,
463 .remove = __devexit_p(tsl2550_remove),
464};
465
466static int __init tsl2550_init(void)
467{
468 return i2c_add_driver(&tsl2550_driver);
469}
470
471static void __exit tsl2550_exit(void)
472{
473 i2c_del_driver(&tsl2550_driver);
474}
475
476MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
477MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
478MODULE_LICENSE("GPL");
Jean Delvaree296fb72007-07-12 14:12:31 +0200479MODULE_VERSION(DRIVER_VERSION);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200480
481module_init(tsl2550_init);
482module_exit(tsl2550_exit);