blob: 5b7afd6190fee6b932d3aaf36449fc76fe4d38e6 [file] [log] [blame]
Thomas Gleixner74ba9202019-05-20 09:19:02 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Rodolfo Giomettia92c3442007-07-12 14:12:30 +02002/*
3 * tsl2550.c - Linux kernel modules for ambient light sensor
4 *
5 * Copyright (C) 2007 Rodolfo Giometti <giometti@linux.it>
6 * Copyright (C) 2007 Eurotech S.p.A. <info@eurotech.it>
Rodolfo Giomettia92c3442007-07-12 14:12:30 +02007 */
8
9#include <linux/module.h>
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020010#include <linux/slab.h>
11#include <linux/i2c.h>
12#include <linux/mutex.h>
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020013
14#define TSL2550_DRV_NAME "tsl2550"
Jean Delvareac780942009-09-18 22:45:44 +020015#define DRIVER_VERSION "1.2"
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020016
17/*
18 * Defines
19 */
20
21#define TSL2550_POWER_DOWN 0x00
22#define TSL2550_POWER_UP 0x03
23#define TSL2550_STANDARD_RANGE 0x18
24#define TSL2550_EXTENDED_RANGE 0x1d
25#define TSL2550_READ_ADC0 0x43
26#define TSL2550_READ_ADC1 0x83
27
28/*
29 * Structs
30 */
31
32struct tsl2550_data {
33 struct i2c_client *client;
34 struct mutex update_lock;
35
Jean Delvare6a9bcce2010-03-13 20:56:54 +010036 unsigned int power_state:1;
37 unsigned int operating_mode:1;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020038};
39
40/*
41 * Global data
42 */
43
44static const u8 TSL2550_MODE_RANGE[2] = {
45 TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
46};
47
48/*
49 * Management functions
50 */
51
52static int tsl2550_set_operating_mode(struct i2c_client *client, int mode)
53{
54 struct tsl2550_data *data = i2c_get_clientdata(client);
55
56 int ret = i2c_smbus_write_byte(client, TSL2550_MODE_RANGE[mode]);
57
58 data->operating_mode = mode;
59
60 return ret;
61}
62
63static int tsl2550_set_power_state(struct i2c_client *client, int state)
64{
65 struct tsl2550_data *data = i2c_get_clientdata(client);
66 int ret;
67
68 if (state == 0)
69 ret = i2c_smbus_write_byte(client, TSL2550_POWER_DOWN);
70 else {
71 ret = i2c_smbus_write_byte(client, TSL2550_POWER_UP);
72
73 /* On power up we should reset operating mode also... */
74 tsl2550_set_operating_mode(client, data->operating_mode);
75 }
76
77 data->power_state = state;
78
79 return ret;
80}
81
82static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
83{
Jean Delvareac780942009-09-18 22:45:44 +020084 int ret;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020085
Jean Delvareac780942009-09-18 22:45:44 +020086 ret = i2c_smbus_read_byte_data(client, cmd);
87 if (ret < 0)
88 return ret;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020089 if (!(ret & 0x80))
Jean Delvareac780942009-09-18 22:45:44 +020090 return -EAGAIN;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +020091 return ret & 0x7f; /* remove the "valid" bit */
92}
93
94/*
95 * LUX calculation
96 */
97
98#define TSL2550_MAX_LUX 1846
99
100static const u8 ratio_lut[] = {
101 100, 100, 100, 100, 100, 100, 100, 100,
102 100, 100, 100, 100, 100, 100, 99, 99,
103 99, 99, 99, 99, 99, 99, 99, 99,
104 99, 99, 99, 98, 98, 98, 98, 98,
105 98, 98, 97, 97, 97, 97, 97, 96,
106 96, 96, 96, 95, 95, 95, 94, 94,
107 93, 93, 93, 92, 92, 91, 91, 90,
108 89, 89, 88, 87, 87, 86, 85, 84,
109 83, 82, 81, 80, 79, 78, 77, 75,
110 74, 73, 71, 69, 68, 66, 64, 62,
111 60, 58, 56, 54, 52, 49, 47, 44,
112 42, 41, 40, 40, 39, 39, 38, 38,
113 37, 37, 37, 36, 36, 36, 35, 35,
114 35, 35, 34, 34, 34, 34, 33, 33,
115 33, 33, 32, 32, 32, 32, 32, 31,
116 31, 31, 31, 31, 30, 30, 30, 30,
117 30,
118};
119
120static const u16 count_lut[] = {
121 0, 1, 2, 3, 4, 5, 6, 7,
122 8, 9, 10, 11, 12, 13, 14, 15,
123 16, 18, 20, 22, 24, 26, 28, 30,
124 32, 34, 36, 38, 40, 42, 44, 46,
125 49, 53, 57, 61, 65, 69, 73, 77,
126 81, 85, 89, 93, 97, 101, 105, 109,
127 115, 123, 131, 139, 147, 155, 163, 171,
128 179, 187, 195, 203, 211, 219, 227, 235,
129 247, 263, 279, 295, 311, 327, 343, 359,
130 375, 391, 407, 423, 439, 455, 471, 487,
131 511, 543, 575, 607, 639, 671, 703, 735,
132 767, 799, 831, 863, 895, 927, 959, 991,
133 1039, 1103, 1167, 1231, 1295, 1359, 1423, 1487,
134 1551, 1615, 1679, 1743, 1807, 1871, 1935, 1999,
135 2095, 2223, 2351, 2479, 2607, 2735, 2863, 2991,
136 3119, 3247, 3375, 3503, 3631, 3759, 3887, 4015,
137};
138
139/*
140 * This function is described into Taos TSL2550 Designer's Notebook
141 * pages 2, 3.
142 */
143static int tsl2550_calculate_lux(u8 ch0, u8 ch1)
144{
145 unsigned int lux;
146
147 /* Look up count from channel values */
148 u16 c0 = count_lut[ch0];
149 u16 c1 = count_lut[ch1];
150
151 /*
152 * Calculate ratio.
153 * Note: the "128" is a scaling factor
154 */
155 u8 r = 128;
156
157 /* Avoid division by 0 and count 1 cannot be greater than count 0 */
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200158 if (c1 <= c0)
159 if (c0) {
160 r = c1 * 128 / c0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200161
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200162 /* Calculate LUX */
163 lux = ((c0 - c1) * ratio_lut[r]) / 256;
164 } else
165 lux = 0;
166 else
Matt Ranostayce054542018-06-08 23:58:15 -0700167 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200168
169 /* LUX range check */
170 return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
171}
172
173/*
174 * SysFS support
175 */
176
177static ssize_t tsl2550_show_power_state(struct device *dev,
178 struct device_attribute *attr, char *buf)
179{
180 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
181
182 return sprintf(buf, "%u\n", data->power_state);
183}
184
185static ssize_t tsl2550_store_power_state(struct device *dev,
186 struct device_attribute *attr, const char *buf, size_t count)
187{
188 struct i2c_client *client = to_i2c_client(dev);
189 struct tsl2550_data *data = i2c_get_clientdata(client);
190 unsigned long val = simple_strtoul(buf, NULL, 10);
191 int ret;
192
Chen Gangae8a35a2013-04-07 11:28:42 +0800193 if (val > 1)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200194 return -EINVAL;
195
196 mutex_lock(&data->update_lock);
197 ret = tsl2550_set_power_state(client, val);
198 mutex_unlock(&data->update_lock);
199
200 if (ret < 0)
201 return ret;
202
203 return count;
204}
205
206static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
207 tsl2550_show_power_state, tsl2550_store_power_state);
208
209static ssize_t tsl2550_show_operating_mode(struct device *dev,
210 struct device_attribute *attr, char *buf)
211{
212 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
213
214 return sprintf(buf, "%u\n", data->operating_mode);
215}
216
217static ssize_t tsl2550_store_operating_mode(struct device *dev,
218 struct device_attribute *attr, const char *buf, size_t count)
219{
220 struct i2c_client *client = to_i2c_client(dev);
221 struct tsl2550_data *data = i2c_get_clientdata(client);
222 unsigned long val = simple_strtoul(buf, NULL, 10);
223 int ret;
224
Chen Gangae8a35a2013-04-07 11:28:42 +0800225 if (val > 1)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200226 return -EINVAL;
227
228 if (data->power_state == 0)
229 return -EBUSY;
230
231 mutex_lock(&data->update_lock);
232 ret = tsl2550_set_operating_mode(client, val);
233 mutex_unlock(&data->update_lock);
234
235 if (ret < 0)
236 return ret;
237
238 return count;
239}
240
241static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
242 tsl2550_show_operating_mode, tsl2550_store_operating_mode);
243
244static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
245{
Michele Jr De Candia5f5bfb02009-11-26 09:22:32 +0100246 struct tsl2550_data *data = i2c_get_clientdata(client);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200247 u8 ch0, ch1;
248 int ret;
249
250 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
251 if (ret < 0)
252 return ret;
253 ch0 = ret;
254
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200255 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
256 if (ret < 0)
257 return ret;
258 ch1 = ret;
259
260 /* Do the job */
261 ret = tsl2550_calculate_lux(ch0, ch1);
262 if (ret < 0)
263 return ret;
Michele Jr De Candia5f5bfb02009-11-26 09:22:32 +0100264 if (data->operating_mode == 1)
265 ret *= 5;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200266
267 return sprintf(buf, "%d\n", ret);
268}
269
270static ssize_t tsl2550_show_lux1_input(struct device *dev,
271 struct device_attribute *attr, char *buf)
272{
273 struct i2c_client *client = to_i2c_client(dev);
274 struct tsl2550_data *data = i2c_get_clientdata(client);
275 int ret;
276
277 /* No LUX data if not operational */
278 if (!data->power_state)
279 return -EBUSY;
280
281 mutex_lock(&data->update_lock);
282 ret = __tsl2550_show_lux(client, buf);
283 mutex_unlock(&data->update_lock);
284
285 return ret;
286}
287
288static DEVICE_ATTR(lux1_input, S_IRUGO,
289 tsl2550_show_lux1_input, NULL);
290
291static struct attribute *tsl2550_attributes[] = {
292 &dev_attr_power_state.attr,
293 &dev_attr_operating_mode.attr,
294 &dev_attr_lux1_input.attr,
295 NULL
296};
297
298static const struct attribute_group tsl2550_attr_group = {
299 .attrs = tsl2550_attributes,
300};
301
302/*
303 * Initialization function
304 */
305
Jean Delvaree296fb72007-07-12 14:12:31 +0200306static int tsl2550_init_client(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200307{
308 struct tsl2550_data *data = i2c_get_clientdata(client);
Jean Delvaree296fb72007-07-12 14:12:31 +0200309 int err;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200310
Jean Delvaree296fb72007-07-12 14:12:31 +0200311 /*
312 * Probe the chip. To do so we try to power up the device and then to
313 * read back the 0x03 code
314 */
Jean Delvareac780942009-09-18 22:45:44 +0200315 err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
Jean Delvaree296fb72007-07-12 14:12:31 +0200316 if (err < 0)
317 return err;
Jean Delvareac780942009-09-18 22:45:44 +0200318 if (err != TSL2550_POWER_UP)
Jean Delvaree296fb72007-07-12 14:12:31 +0200319 return -ENODEV;
320 data->power_state = 1;
321
322 /* Set the default operating mode */
323 err = i2c_smbus_write_byte(client,
324 TSL2550_MODE_RANGE[data->operating_mode]);
325 if (err < 0)
326 return err;
327
328 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200329}
330
331/*
332 * I2C init/probing/exit functions
333 */
334
335static struct i2c_driver tsl2550_driver;
Bill Pemberton80c8ae22012-11-19 13:23:05 -0500336static int tsl2550_probe(struct i2c_client *client,
Jean Delvared2653e92008-04-29 23:11:39 +0200337 const struct i2c_device_id *id)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200338{
339 struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
340 struct tsl2550_data *data;
341 int *opmode, err = 0;
342
Jean Delvareac780942009-09-18 22:45:44 +0200343 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
344 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200345 err = -EIO;
346 goto exit;
347 }
348
349 data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
350 if (!data) {
351 err = -ENOMEM;
352 goto exit;
353 }
354 data->client = client;
355 i2c_set_clientdata(client, data);
356
357 /* Check platform data */
358 opmode = client->dev.platform_data;
359 if (opmode) {
360 if (*opmode < 0 || *opmode > 1) {
361 dev_err(&client->dev, "invalid operating_mode (%d)\n",
362 *opmode);
363 err = -EINVAL;
364 goto exit_kfree;
365 }
366 data->operating_mode = *opmode;
367 } else
368 data->operating_mode = 0; /* default mode is standard */
369 dev_info(&client->dev, "%s operating mode\n",
370 data->operating_mode ? "extended" : "standard");
371
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200372 mutex_init(&data->update_lock);
373
374 /* Initialize the TSL2550 chip */
Jean Delvaree296fb72007-07-12 14:12:31 +0200375 err = tsl2550_init_client(client);
376 if (err)
377 goto exit_kfree;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200378
379 /* Register sysfs hooks */
380 err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
381 if (err)
382 goto exit_kfree;
383
384 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
385
386 return 0;
387
388exit_kfree:
389 kfree(data);
390exit:
391 return err;
392}
393
Bill Pemberton486a5c22012-11-19 13:26:02 -0500394static int tsl2550_remove(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200395{
396 sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
397
398 /* Power down the device */
399 tsl2550_set_power_state(client, 0);
400
401 kfree(i2c_get_clientdata(client));
402
403 return 0;
404}
405
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200406#ifdef CONFIG_PM_SLEEP
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100407
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200408static int tsl2550_suspend(struct device *dev)
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100409{
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200410 return tsl2550_set_power_state(to_i2c_client(dev), 0);
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100411}
412
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200413static int tsl2550_resume(struct device *dev)
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100414{
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200415 return tsl2550_set_power_state(to_i2c_client(dev), 1);
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100416}
417
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200418static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume);
419#define TSL2550_PM_OPS (&tsl2550_pm_ops)
420
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100421#else
422
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200423#define TSL2550_PM_OPS NULL
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100424
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200425#endif /* CONFIG_PM_SLEEP */
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100426
Jean Delvare3760f732008-04-29 23:11:40 +0200427static const struct i2c_device_id tsl2550_id[] = {
428 { "tsl2550", 0 },
429 { }
430};
431MODULE_DEVICE_TABLE(i2c, tsl2550_id);
432
Javier Martinez Canillasd2ce8d6f2017-03-21 10:50:47 -0300433static const struct of_device_id tsl2550_of_match[] = {
434 { .compatible = "taos,tsl2550" },
435 { }
436};
437MODULE_DEVICE_TABLE(of, tsl2550_of_match);
438
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200439static struct i2c_driver tsl2550_driver = {
440 .driver = {
441 .name = TSL2550_DRV_NAME,
Javier Martinez Canillasd2ce8d6f2017-03-21 10:50:47 -0300442 .of_match_table = tsl2550_of_match,
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200443 .pm = TSL2550_PM_OPS,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200444 },
445 .probe = tsl2550_probe,
Bill Pemberton2d6bed92012-11-19 13:21:23 -0500446 .remove = tsl2550_remove,
Jean Delvare3760f732008-04-29 23:11:40 +0200447 .id_table = tsl2550_id,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200448};
449
Axel Lina64fe2e2012-01-22 15:36:45 +0800450module_i2c_driver(tsl2550_driver);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200451
452MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
453MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
454MODULE_LICENSE("GPL");
Jean Delvaree296fb72007-07-12 14:12:31 +0200455MODULE_VERSION(DRIVER_VERSION);