blob: 6d71865c80427ed535690b8fa436ee4afe5c4c00 [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
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200151 /* Avoid division by 0 and count 1 cannot be greater than count 0 */
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200152 if (c1 <= c0)
153 if (c0) {
Colin Ian Kingf896ee52020-01-07 17:52:34 +0000154 /*
155 * Calculate ratio.
156 * Note: the "128" is a scaling factor
157 */
158 u8 r = c1 * 128 / c0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200159
Michele Jr De Candia96f699a2009-07-28 16:33:03 +0200160 /* Calculate LUX */
161 lux = ((c0 - c1) * ratio_lut[r]) / 256;
162 } else
163 lux = 0;
164 else
Matt Ranostayce054542018-06-08 23:58:15 -0700165 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200166
167 /* LUX range check */
168 return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
169}
170
171/*
172 * SysFS support
173 */
174
175static ssize_t tsl2550_show_power_state(struct device *dev,
176 struct device_attribute *attr, char *buf)
177{
178 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
179
180 return sprintf(buf, "%u\n", data->power_state);
181}
182
183static ssize_t tsl2550_store_power_state(struct device *dev,
184 struct device_attribute *attr, const char *buf, size_t count)
185{
186 struct i2c_client *client = to_i2c_client(dev);
187 struct tsl2550_data *data = i2c_get_clientdata(client);
188 unsigned long val = simple_strtoul(buf, NULL, 10);
189 int ret;
190
Chen Gangae8a35a2013-04-07 11:28:42 +0800191 if (val > 1)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200192 return -EINVAL;
193
194 mutex_lock(&data->update_lock);
195 ret = tsl2550_set_power_state(client, val);
196 mutex_unlock(&data->update_lock);
197
198 if (ret < 0)
199 return ret;
200
201 return count;
202}
203
204static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
205 tsl2550_show_power_state, tsl2550_store_power_state);
206
207static ssize_t tsl2550_show_operating_mode(struct device *dev,
208 struct device_attribute *attr, char *buf)
209{
210 struct tsl2550_data *data = i2c_get_clientdata(to_i2c_client(dev));
211
212 return sprintf(buf, "%u\n", data->operating_mode);
213}
214
215static ssize_t tsl2550_store_operating_mode(struct device *dev,
216 struct device_attribute *attr, const char *buf, size_t count)
217{
218 struct i2c_client *client = to_i2c_client(dev);
219 struct tsl2550_data *data = i2c_get_clientdata(client);
220 unsigned long val = simple_strtoul(buf, NULL, 10);
221 int ret;
222
Chen Gangae8a35a2013-04-07 11:28:42 +0800223 if (val > 1)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200224 return -EINVAL;
225
226 if (data->power_state == 0)
227 return -EBUSY;
228
229 mutex_lock(&data->update_lock);
230 ret = tsl2550_set_operating_mode(client, val);
231 mutex_unlock(&data->update_lock);
232
233 if (ret < 0)
234 return ret;
235
236 return count;
237}
238
239static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
240 tsl2550_show_operating_mode, tsl2550_store_operating_mode);
241
242static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
243{
Michele Jr De Candia5f5bfb02009-11-26 09:22:32 +0100244 struct tsl2550_data *data = i2c_get_clientdata(client);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200245 u8 ch0, ch1;
246 int ret;
247
248 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
249 if (ret < 0)
250 return ret;
251 ch0 = ret;
252
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200253 ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
254 if (ret < 0)
255 return ret;
256 ch1 = ret;
257
258 /* Do the job */
259 ret = tsl2550_calculate_lux(ch0, ch1);
260 if (ret < 0)
261 return ret;
Michele Jr De Candia5f5bfb02009-11-26 09:22:32 +0100262 if (data->operating_mode == 1)
263 ret *= 5;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200264
265 return sprintf(buf, "%d\n", ret);
266}
267
268static ssize_t tsl2550_show_lux1_input(struct device *dev,
269 struct device_attribute *attr, char *buf)
270{
271 struct i2c_client *client = to_i2c_client(dev);
272 struct tsl2550_data *data = i2c_get_clientdata(client);
273 int ret;
274
275 /* No LUX data if not operational */
276 if (!data->power_state)
277 return -EBUSY;
278
279 mutex_lock(&data->update_lock);
280 ret = __tsl2550_show_lux(client, buf);
281 mutex_unlock(&data->update_lock);
282
283 return ret;
284}
285
286static DEVICE_ATTR(lux1_input, S_IRUGO,
287 tsl2550_show_lux1_input, NULL);
288
289static struct attribute *tsl2550_attributes[] = {
290 &dev_attr_power_state.attr,
291 &dev_attr_operating_mode.attr,
292 &dev_attr_lux1_input.attr,
293 NULL
294};
295
296static const struct attribute_group tsl2550_attr_group = {
297 .attrs = tsl2550_attributes,
298};
299
300/*
301 * Initialization function
302 */
303
Jean Delvaree296fb72007-07-12 14:12:31 +0200304static int tsl2550_init_client(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200305{
306 struct tsl2550_data *data = i2c_get_clientdata(client);
Jean Delvaree296fb72007-07-12 14:12:31 +0200307 int err;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200308
Jean Delvaree296fb72007-07-12 14:12:31 +0200309 /*
310 * Probe the chip. To do so we try to power up the device and then to
311 * read back the 0x03 code
312 */
Jean Delvareac780942009-09-18 22:45:44 +0200313 err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
Jean Delvaree296fb72007-07-12 14:12:31 +0200314 if (err < 0)
315 return err;
Jean Delvareac780942009-09-18 22:45:44 +0200316 if (err != TSL2550_POWER_UP)
Jean Delvaree296fb72007-07-12 14:12:31 +0200317 return -ENODEV;
318 data->power_state = 1;
319
320 /* Set the default operating mode */
321 err = i2c_smbus_write_byte(client,
322 TSL2550_MODE_RANGE[data->operating_mode]);
323 if (err < 0)
324 return err;
325
326 return 0;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200327}
328
329/*
330 * I2C init/probing/exit functions
331 */
332
333static struct i2c_driver tsl2550_driver;
Bill Pemberton80c8ae22012-11-19 13:23:05 -0500334static int tsl2550_probe(struct i2c_client *client,
Jean Delvared2653e92008-04-29 23:11:39 +0200335 const struct i2c_device_id *id)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200336{
Wolfram Sang3cc2dec2019-06-08 12:55:53 +0200337 struct i2c_adapter *adapter = client->adapter;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200338 struct tsl2550_data *data;
339 int *opmode, err = 0;
340
Jean Delvareac780942009-09-18 22:45:44 +0200341 if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
342 | I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200343 err = -EIO;
344 goto exit;
345 }
346
347 data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
348 if (!data) {
349 err = -ENOMEM;
350 goto exit;
351 }
352 data->client = client;
353 i2c_set_clientdata(client, data);
354
355 /* Check platform data */
356 opmode = client->dev.platform_data;
357 if (opmode) {
358 if (*opmode < 0 || *opmode > 1) {
359 dev_err(&client->dev, "invalid operating_mode (%d)\n",
360 *opmode);
361 err = -EINVAL;
362 goto exit_kfree;
363 }
364 data->operating_mode = *opmode;
365 } else
366 data->operating_mode = 0; /* default mode is standard */
367 dev_info(&client->dev, "%s operating mode\n",
368 data->operating_mode ? "extended" : "standard");
369
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200370 mutex_init(&data->update_lock);
371
372 /* Initialize the TSL2550 chip */
Jean Delvaree296fb72007-07-12 14:12:31 +0200373 err = tsl2550_init_client(client);
374 if (err)
375 goto exit_kfree;
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200376
377 /* Register sysfs hooks */
378 err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
379 if (err)
380 goto exit_kfree;
381
382 dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
383
384 return 0;
385
386exit_kfree:
387 kfree(data);
388exit:
389 return err;
390}
391
Bill Pemberton486a5c22012-11-19 13:26:02 -0500392static int tsl2550_remove(struct i2c_client *client)
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200393{
394 sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
395
396 /* Power down the device */
397 tsl2550_set_power_state(client, 0);
398
399 kfree(i2c_get_clientdata(client));
400
401 return 0;
402}
403
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200404#ifdef CONFIG_PM_SLEEP
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100405
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200406static int tsl2550_suspend(struct device *dev)
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100407{
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200408 return tsl2550_set_power_state(to_i2c_client(dev), 0);
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100409}
410
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200411static int tsl2550_resume(struct device *dev)
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100412{
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200413 return tsl2550_set_power_state(to_i2c_client(dev), 1);
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100414}
415
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200416static SIMPLE_DEV_PM_OPS(tsl2550_pm_ops, tsl2550_suspend, tsl2550_resume);
417#define TSL2550_PM_OPS (&tsl2550_pm_ops)
418
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100419#else
420
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200421#define TSL2550_PM_OPS NULL
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100422
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200423#endif /* CONFIG_PM_SLEEP */
Rodolfo Giometti1b3e5ba2008-01-27 18:14:45 +0100424
Jean Delvare3760f732008-04-29 23:11:40 +0200425static const struct i2c_device_id tsl2550_id[] = {
426 { "tsl2550", 0 },
427 { }
428};
429MODULE_DEVICE_TABLE(i2c, tsl2550_id);
430
Javier Martinez Canillasd2ce8d6f2017-03-21 10:50:47 -0300431static const struct of_device_id tsl2550_of_match[] = {
432 { .compatible = "taos,tsl2550" },
433 { }
434};
435MODULE_DEVICE_TABLE(of, tsl2550_of_match);
436
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200437static struct i2c_driver tsl2550_driver = {
438 .driver = {
439 .name = TSL2550_DRV_NAME,
Javier Martinez Canillasd2ce8d6f2017-03-21 10:50:47 -0300440 .of_match_table = tsl2550_of_match,
Lars-Peter Clausena7761022013-04-11 11:24:42 +0200441 .pm = TSL2550_PM_OPS,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200442 },
443 .probe = tsl2550_probe,
Bill Pemberton2d6bed92012-11-19 13:21:23 -0500444 .remove = tsl2550_remove,
Jean Delvare3760f732008-04-29 23:11:40 +0200445 .id_table = tsl2550_id,
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200446};
447
Axel Lina64fe2e2012-01-22 15:36:45 +0800448module_i2c_driver(tsl2550_driver);
Rodolfo Giomettia92c3442007-07-12 14:12:30 +0200449
450MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
451MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
452MODULE_LICENSE("GPL");
Jean Delvaree296fb72007-07-12 14:12:31 +0200453MODULE_VERSION(DRIVER_VERSION);