blob: aa96bd2d27ead9452d08da3bb62065468f1822f2 [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>
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020027
28#define TSL2550_DRV_NAME "tsl2550"
Jean Delvareac780942009-09-18 22:45:44 +020029#define DRIVER_VERSION "1.2"
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020030
31/*
32 * Defines
33 */
34
35#define TSL2550_POWER_DOWN 0x00
36#define TSL2550_POWER_UP 0x03
37#define TSL2550_STANDARD_RANGE 0x18
38#define TSL2550_EXTENDED_RANGE 0x1d
39#define TSL2550_READ_ADC0 0x43
40#define TSL2550_READ_ADC1 0x83
41
42/*
43 * Structs
44 */
45
46struct tsl2550_data {
47 struct i2c_client *client;
48 struct mutex update_lock;
49
50 unsigned int power_state : 1;
51 unsigned int operating_mode : 1;
52};
53
54/*
55 * Global data
56 */
57
58static const u8 TSL2550_MODE_RANGE[2] = {
59 TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
60};
61
62/*
63 * Management functions
64 */
65
66static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
67{
68 struct tsl2550_data *data = i2c_get_clientdata(client);
69
70 int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
71
72 data->operating_mode = mode;
73
74 return ret;
75}
76
77static int tsl2550_set_power_state(struct i2c_client *client, int state)
78{
79 struct tsl2550_data *data = i2c_get_clientdata(client);
80 int ret;
81
82 if (state == 0)
83 ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
84 else {
85 ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
86
87 /* On power up we should reset operating mode also... */
88 tsl2550_set_operating_mode(client, data->operating_mode);
89 }
90
91 data->power_state = state;
92
93 return ret;
94}
95
96static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
97{
Jean Delvareac780942009-09-18 22:45:44 +020098 int ret;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020099
Jean Delvareac780942009-09-18 22:45:44 +0200100 ret = i2c_smbus_read_byte_data(client, cmd);
101 if (ret < 0)
102 return ret;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200103 if (!(ret & 0x80))
Jean Delvareac780942009-09-18 22:45:44 +0200104 return -EAGAIN;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200105 return ret & 0x7f; /* remove the "valid" bit */
106}
107
108/*
109 * LUX calculation
110 */
111
112#define TSL2550_MAX_LUX 1846
113
114static const u8 ratio_lut[] = {
115 100, 100, 100, 100, 100, 100, 100, 100,
116 100, 100, 100, 100, 100, 100, 99, 99,
117 99, 99, 99, 99, 99, 99, 99, 99,
118 99, 99, 99, 98, 98, 98, 98, 98,
119 98, 98, 97, 97, 97, 97, 97, 96,
120 96, 96, 96, 95, 95, 95, 94, 94,
121 93, 93, 93, 92, 92, 91, 91, 90,
122 89, 89, 88, 87, 87, 86, 85, 84,
123 83, 82, 81, 80, 79, 78, 77, 75,
124 74, 73, 71, 69, 68, 66, 64, 62,
125 60, 58, 56, 54, 52, 49, 47, 44,
126 42, 41, 40, 40, 39, 39, 38, 38,
127 37, 37, 37, 36, 36, 36, 35, 35,
128 35, 35, 34, 34, 34, 34, 33, 33,
129 33, 33, 32, 32, 32, 32, 32, 31,
130 31, 31, 31, 31, 30, 30, 30, 30,
131 30,
132};
133
134static const u16 count_lut[] = {
135 0, 1, 2, 3, 4, 5, 6, 7,
136 8, 9, 10, 11, 12, 13, 14, 15,
137 16, 18, 20, 22, 24, 26, 28, 30,
138 32, 34, 36, 38, 40, 42, 44, 46,
139 49, 53, 57, 61, 65, 69, 73, 77,
140 81, 85, 89, 93, 97, 101, 105, 109,
141 115, 123, 131, 139, 147, 155, 163, 171,
142 179, 187, 195, 203, 211, 219, 227, 235,
143 247, 263, 279, 295, 311, 327, 343, 359,
144 375, 391, 407, 423, 439, 455, 471, 487,
145 511, 543, 575, 607, 639, 671, 703, 735,
146 767, 799, 831, 863, 895, 927, 959, 991,
147 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
148 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
149 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
150 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
151};
152
153/*
154 * This function is described into Taos TSL2550 Designer's Notebook
155 * pages 2, 3.
156 */
157static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
158{
159 unsigned int lux;
160
161 /* Look up count from channel values */
162 u16 c0 = count_lut[ch0];
163 u16 c1 = count_lut[ch1];
164
165 /*
166 * Calculate ratio.
167 * Note: the "128" is a scaling factor
168 */
169 u8 r = 128;
170
171 /* Avoid division by 0 and count 1 cannot be greater than count 0 */
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200172 if (c1 <= c0)
173 if (c0) {
174 r = c1 * 128 / c0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200175
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200176 /* Calculate LUX */
177 lux = ((c0 - c1) * ratio_lut[r]) / 256;
178 } else
179 lux = 0;
180 else
181 return -EAGAIN;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200182
183 /* LUX range check */
184 return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
185}
186
187/*
188 * SysFS support
189 */
190
191static ssize_t tsl2550_show_power_state(struct device *dev,
192 struct device_attribute *attr, char *buf)
193{
194 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
195
196 return sprintf(buf, "%u\n", data->power_state);
197}
198
199static ssize_t tsl2550_store_power_state(struct device *dev,
200 struct device_attribute *attr, const char *buf, size_t count)
201{
202 struct i2c_client *client = to_i2c_client(dev);
203 struct tsl2550_data *data = i2c_get_clientdata(client);
204 unsigned long val = simple_strtoul(buf, NULL, 10);
205 int ret;
206
207 if (val < 0 || val > 1)
208 return -EINVAL;
209
210 mutex_lock(&data->update_lock);
211 ret = tsl2550_set_power_state(client, val);
212 mutex_unlock(&data->update_lock);
213
214 if (ret < 0)
215 return ret;
216
217 return count;
218}
219
220static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
221 tsl2550_show_power_state, tsl2550_store_power_state);
222
223static ssize_t tsl2550_show_operating_mode(struct device *dev,
224 struct device_attribute *attr, char *buf)
225{
226 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
227
228 return sprintf(buf, "%u\n", data->operating_mode);
229}
230
231static ssize_t tsl2550_store_operating_mode(struct device *dev,
232 struct device_attribute *attr, const char *buf, size_t count)
233{
234 struct i2c_client *client = to_i2c_client(dev);
235 struct tsl2550_data *data = i2c_get_clientdata(client);
236 unsigned long val = simple_strtoul(buf, NULL, 10);
237 int ret;
238
239 if (val < 0 || val > 1)
240 return -EINVAL;
241
242 if (data->power_state == 0)
243 return -EBUSY;
244
245 mutex_lock(&data->update_lock);
246 ret = tsl2550_set_operating_mode(client, val);
247 mutex_unlock(&data->update_lock);
248
249 if (ret < 0)
250 return ret;
251
252 return count;
253}
254
255static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
256 tsl2550_show_operating_mode, tsl2550_store_operating_mode);
257
258static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
259{
260 u8 ch0, ch1;
261 int ret;
262
263 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
264 if (ret < 0)
265 return ret;
266 ch0 = ret;
267
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200268 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
269 if (ret < 0)
270 return ret;
271 ch1 = ret;
272
273 /* Do the job */
274 ret = tsl2550_calculate_lux(ch0, ch1);
275 if (ret < 0)
276 return ret;
277
278 return sprintf(buf, "%d\n", ret);
279}
280
281static ssize_t tsl2550_show_lux1_input(struct device *dev,
282 struct device_attribute *attr, char *buf)
283{
284 struct i2c_client *client = to_i2c_client(dev);
285 struct tsl2550_data *data = i2c_get_clientdata(client);
286 int ret;
287
288 /* No LUX data if not operational */
289 if (!data->power_state)
290 return -EBUSY;
291
292 mutex_lock(&data->update_lock);
293 ret = __tsl2550_show_lux(client, buf);
294 mutex_unlock(&data->update_lock);
295
296 return ret;
297}
298
299static DEVICE_ATTR(lux1_input, S_IRUGO,
300 tsl2550_show_lux1_input, NULL);
301
302static struct attribute *tsl2550_attributes[] = {
303 &dev_attr_power_state.attr,
304 &dev_attr_operating_mode.attr,
305 &dev_attr_lux1_input.attr,
306 NULL
307};
308
309static const struct attribute_group tsl2550_attr_group = {
310 .attrs = tsl2550_attributes,
311};
312
313/*
314 * Initialization function
315 */
316
Jean Delvaree296fb72007-07-12 14:12:31 +0200317static int tsl2550_init_client(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200318{
319 struct tsl2550_data *data = i2c_get_clientdata(client);
Jean Delvaree296fb72007-07-12 14:12:31 +0200320 int err;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200321
Jean Delvaree296fb72007-07-12 14:12:31 +0200322 /*
323 * Probe the chip. To do so we try to power up the device and then to
324 * read back the 0x03 code
325 */
Jean Delvareac780942009-09-18 22:45:44 +0200326 err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
Jean Delvaree296fb72007-07-12 14:12:31 +0200327 if (err < 0)
328 return err;
Jean Delvareac780942009-09-18 22:45:44 +0200329 if (err != TSL2550_POWER_UP)
Jean Delvaree296fb72007-07-12 14:12:31 +0200330 return -ENODEV;
331 data->power_state = 1;
332
333 /* Set the default operating mode */
334 err = i2c_smbus_write_byte(client,
335 TSL2550_MODE_RANGE[data->operating_mode]);
336 if (err < 0)
337 return err;
338
339 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200340}
341
342/*
343 * I2C init/probing/exit functions
344 */
345
346static struct i2c_driver tsl2550_driver;
Jean Delvared2653e92008-04-29 23:11:39 +0200347static int __devinit tsl2550_probe(struct i2c_client *client,
348 const struct i2c_device_id *id)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200349{
350 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
351 struct tsl2550_data *data;
352 int *opmode, err = 0;
353
Jean Delvareac780942009-09-18 22:45:44 +0200354 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
355 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200356 err = -EIO;
357 goto exit;
358 }
359
360 data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
361 if (!data) {
362 err = -ENOMEM;
363 goto exit;
364 }
365 data->client = client;
366 i2c_set_clientdata(client, data);
367
368 /* Check platform data */
369 opmode = client->dev.platform_data;
370 if (opmode) {
371 if (*opmode < 0 || *opmode > 1) {
372 dev_err(&client->dev, "invalid operating_mode (%d)\n",
373 *opmode);
374 err = -EINVAL;
375 goto exit_kfree;
376 }
377 data->operating_mode = *opmode;
378 } else
379 data->operating_mode = 0; /* default mode is standard */
380 dev_info(&client->dev, "%s operating mode\n",
381 data->operating_mode ? "extended" : "standard");
382
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200383 mutex_init(&data->update_lock);
384
385 /* Initialize the TSL2550 chip */
Jean Delvaree296fb72007-07-12 14:12:31 +0200386 err = tsl2550_init_client(client);
387 if (err)
388 goto exit_kfree;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200389
390 /* Register sysfs hooks */
391 err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
392 if (err)
393 goto exit_kfree;
394
395 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
396
397 return 0;
398
399exit_kfree:
400 kfree(data);
401exit:
402 return err;
403}
404
405static int __devexit tsl2550_remove(struct i2c_client *client)
406{
407 sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
408
409 /* Power down the device */
410 tsl2550_set_power_state(client, 0);
411
412 kfree(i2c_get_clientdata(client));
413
414 return 0;
415}
416
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100417#ifdef CONFIG_PM
418
419static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
420{
421 return tsl2550_set_power_state(client, 0);
422}
423
424static int tsl2550_resume(struct i2c_client *client)
425{
426 return tsl2550_set_power_state(client, 1);
427}
428
429#else
430
431#define tsl2550_suspend NULL
432#define tsl2550_resume NULL
433
434#endif /* CONFIG_PM */
435
Jean Delvare3760f732008-04-29 23:11:40 +0200436static const struct i2c_device_id tsl2550_id[] = {
437 { "tsl2550", 0 },
438 { }
439};
440MODULE_DEVICE_TABLE(i2c, tsl2550_id);
441
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200442static struct i2c_driver tsl2550_driver = {
443 .driver = {
444 .name = TSL2550_DRV_NAME,
445 .owner = THIS_MODULE,
446 },
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100447 .suspend = tsl2550_suspend,
448 .resume = tsl2550_resume,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200449 .probe = tsl2550_probe,
450 .remove = __devexit_p(tsl2550_remove),
Jean Delvare3760f732008-04-29 23:11:40 +0200451 .id_table = tsl2550_id,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200452};
453
454static int __init tsl2550_init(void)
455{
456 return i2c_add_driver(&tsl2550_driver);
457}
458
459static void __exit tsl2550_exit(void)
460{
461 i2c_del_driver(&tsl2550_driver);
462}
463
464MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
465MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
466MODULE_LICENSE("GPL");
Jean Delvaree296fb72007-07-12 14:12:31 +0200467MODULE_VERSION(DRIVER_VERSION);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200468
469module_init(tsl2550_init);
470module_exit(tsl2550_exit);