blob: b96f3025e588245fc498fcaddb78e706bfe03c6e [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"
Michele Jr De Candia96f699a2009-07-28 16:33:03 +020030#define DRIVER_VERSION "1.1.2"
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 */
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200192 if (c1 <= c0)
193 if (c0) {
194 r = c1 * 128 / c0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200195
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200196 /* Calculate LUX */
197 lux = ((c0 - c1) * ratio_lut[r]) / 256;
198 } else
199 lux = 0;
200 else
201 return -EAGAIN;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200202
203 /* LUX range check */
204 return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
205}
206
207/*
208 * SysFS support
209 */
210
211static ssize_t tsl2550_show_power_state(struct device *dev,
212 struct device_attribute *attr, char *buf)
213{
214 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
215
216 return sprintf(buf, "%u\n", data->power_state);
217}
218
219static ssize_t tsl2550_store_power_state(struct device *dev,
220 struct device_attribute *attr, const char *buf, size_t count)
221{
222 struct i2c_client *client = to_i2c_client(dev);
223 struct tsl2550_data *data = i2c_get_clientdata(client);
224 unsigned long val = simple_strtoul(buf, NULL, 10);
225 int ret;
226
227 if (val < 0 || val > 1)
228 return -EINVAL;
229
230 mutex_lock(&data->update_lock);
231 ret = tsl2550_set_power_state(client, val);
232 mutex_unlock(&data->update_lock);
233
234 if (ret < 0)
235 return ret;
236
237 return count;
238}
239
240static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
241 tsl2550_show_power_state, tsl2550_store_power_state);
242
243static ssize_t tsl2550_show_operating_mode(struct device *dev,
244 struct device_attribute *attr, char *buf)
245{
246 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
247
248 return sprintf(buf, "%u\n", data->operating_mode);
249}
250
251static ssize_t tsl2550_store_operating_mode(struct device *dev,
252 struct device_attribute *attr, const char *buf, size_t count)
253{
254 struct i2c_client *client = to_i2c_client(dev);
255 struct tsl2550_data *data = i2c_get_clientdata(client);
256 unsigned long val = simple_strtoul(buf, NULL, 10);
257 int ret;
258
259 if (val < 0 || val > 1)
260 return -EINVAL;
261
262 if (data->power_state == 0)
263 return -EBUSY;
264
265 mutex_lock(&data->update_lock);
266 ret = tsl2550_set_operating_mode(client, val);
267 mutex_unlock(&data->update_lock);
268
269 if (ret < 0)
270 return ret;
271
272 return count;
273}
274
275static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
276 tsl2550_show_operating_mode, tsl2550_store_operating_mode);
277
278static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
279{
280 u8 ch0, ch1;
281 int ret;
282
283 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
284 if (ret < 0)
285 return ret;
286 ch0 = ret;
287
288 mdelay(1);
289
290 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
291 if (ret < 0)
292 return ret;
293 ch1 = ret;
294
295 /* Do the job */
296 ret = tsl2550_calculate_lux(ch0, ch1);
297 if (ret < 0)
298 return ret;
299
300 return sprintf(buf, "%d\n", ret);
301}
302
303static ssize_t tsl2550_show_lux1_input(struct device *dev,
304 struct device_attribute *attr, char *buf)
305{
306 struct i2c_client *client = to_i2c_client(dev);
307 struct tsl2550_data *data = i2c_get_clientdata(client);
308 int ret;
309
310 /* No LUX data if not operational */
311 if (!data->power_state)
312 return -EBUSY;
313
314 mutex_lock(&data->update_lock);
315 ret = __tsl2550_show_lux(client, buf);
316 mutex_unlock(&data->update_lock);
317
318 return ret;
319}
320
321static DEVICE_ATTR(lux1_input, S_IRUGO,
322 tsl2550_show_lux1_input, NULL);
323
324static struct attribute *tsl2550_attributes[] = {
325 &dev_attr_power_state.attr,
326 &dev_attr_operating_mode.attr,
327 &dev_attr_lux1_input.attr,
328 NULL
329};
330
331static const struct attribute_group tsl2550_attr_group = {
332 .attrs = tsl2550_attributes,
333};
334
335/*
336 * Initialization function
337 */
338
Jean Delvaree296fb72007-07-12 14:12:31 +0200339static int tsl2550_init_client(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200340{
341 struct tsl2550_data *data = i2c_get_clientdata(client);
Jean Delvaree296fb72007-07-12 14:12:31 +0200342 int err;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200343
Jean Delvaree296fb72007-07-12 14:12:31 +0200344 /*
345 * Probe the chip. To do so we try to power up the device and then to
346 * read back the 0x03 code
347 */
348 err = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
349 if (err < 0)
350 return err;
351 mdelay(1);
352 if (i2c_smbus_read_byte(client) != TSL2550_POWER_UP)
353 return -ENODEV;
354 data->power_state = 1;
355
356 /* Set the default operating mode */
357 err = i2c_smbus_write_byte(client,
358 TSL2550_MODE_RANGE[data->operating_mode]);
359 if (err < 0)
360 return err;
361
362 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200363}
364
365/*
366 * I2C init/probing/exit functions
367 */
368
369static struct i2c_driver tsl2550_driver;
Jean Delvared2653e92008-04-29 23:11:39 +0200370static int __devinit tsl2550_probe(struct i2c_client *client,
371 const struct i2c_device_id *id)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200372{
373 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
374 struct tsl2550_data *data;
375 int *opmode, err = 0;
376
377 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
378 err = -EIO;
379 goto exit;
380 }
381
382 data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
383 if (!data) {
384 err = -ENOMEM;
385 goto exit;
386 }
387 data->client = client;
388 i2c_set_clientdata(client, data);
389
390 /* Check platform data */
391 opmode = client->dev.platform_data;
392 if (opmode) {
393 if (*opmode < 0 || *opmode > 1) {
394 dev_err(&client->dev, "invalid operating_mode (%d)\n",
395 *opmode);
396 err = -EINVAL;
397 goto exit_kfree;
398 }
399 data->operating_mode = *opmode;
400 } else
401 data->operating_mode = 0; /* default mode is standard */
402 dev_info(&client->dev, "%s operating mode\n",
403 data->operating_mode ? "extended" : "standard");
404
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200405 mutex_init(&data->update_lock);
406
407 /* Initialize the TSL2550 chip */
Jean Delvaree296fb72007-07-12 14:12:31 +0200408 err = tsl2550_init_client(client);
409 if (err)
410 goto exit_kfree;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200411
412 /* Register sysfs hooks */
413 err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
414 if (err)
415 goto exit_kfree;
416
417 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
418
419 return 0;
420
421exit_kfree:
422 kfree(data);
423exit:
424 return err;
425}
426
427static int __devexit tsl2550_remove(struct i2c_client *client)
428{
429 sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
430
431 /* Power down the device */
432 tsl2550_set_power_state(client, 0);
433
434 kfree(i2c_get_clientdata(client));
435
436 return 0;
437}
438
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100439#ifdef CONFIG_PM
440
441static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
442{
443 return tsl2550_set_power_state(client, 0);
444}
445
446static int tsl2550_resume(struct i2c_client *client)
447{
448 return tsl2550_set_power_state(client, 1);
449}
450
451#else
452
453#define tsl2550_suspend NULL
454#define tsl2550_resume NULL
455
456#endif /* CONFIG_PM */
457
Jean Delvare3760f732008-04-29 23:11:40 +0200458static const struct i2c_device_id tsl2550_id[] = {
459 { "tsl2550", 0 },
460 { }
461};
462MODULE_DEVICE_TABLE(i2c, tsl2550_id);
463
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200464static struct i2c_driver tsl2550_driver = {
465 .driver = {
466 .name = TSL2550_DRV_NAME,
467 .owner = THIS_MODULE,
468 },
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100469 .suspend = tsl2550_suspend,
470 .resume = tsl2550_resume,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200471 .probe = tsl2550_probe,
472 .remove = __devexit_p(tsl2550_remove),
Jean Delvare3760f732008-04-29 23:11:40 +0200473 .id_table = tsl2550_id,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200474};
475
476static int __init tsl2550_init(void)
477{
478 return i2c_add_driver(&tsl2550_driver);
479}
480
481static void __exit tsl2550_exit(void)
482{
483 i2c_del_driver(&tsl2550_driver);
484}
485
486MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
487MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
488MODULE_LICENSE("GPL");
Jean Delvaree296fb72007-07-12 14:12:31 +0200489MODULE_VERSION(DRIVER_VERSION);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200490
491module_init(tsl2550_init);
492module_exit(tsl2550_exit);