Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/misc/tsl2550.c
15109 views
1
/*
2
* tsl2550.c - Linux kernel modules for ambient light sensor
3
*
4
* Copyright (C) 2007 Rodolfo Giometti <[email protected]>
5
* Copyright (C) 2007 Eurotech S.p.A. <[email protected]>
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
28
#define TSL2550_DRV_NAME "tsl2550"
29
#define DRIVER_VERSION "1.2"
30
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
46
struct 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
58
static const u8 TSL2550_MODE_RANGE[2] = {
59
TSL2550_STANDARD_RANGE, TSL2550_EXTENDED_RANGE,
60
};
61
62
/*
63
* Management functions
64
*/
65
66
static 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
77
static 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
96
static int tsl2550_get_adc_value(struct i2c_client *client, u8 cmd)
97
{
98
int ret;
99
100
ret = i2c_smbus_read_byte_data(client, cmd);
101
if (ret < 0)
102
return ret;
103
if (!(ret & 0x80))
104
return -EAGAIN;
105
return ret & 0x7f; /* remove the "valid" bit */
106
}
107
108
/*
109
* LUX calculation
110
*/
111
112
#define TSL2550_MAX_LUX 1846
113
114
static 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
134
static 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
*/
157
static 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 */
172
if (c1 <= c0)
173
if (c0) {
174
r = c1 * 128 / c0;
175
176
/* Calculate LUX */
177
lux = ((c0 - c1) * ratio_lut[r]) / 256;
178
} else
179
lux = 0;
180
else
181
return -EAGAIN;
182
183
/* LUX range check */
184
return lux > TSL2550_MAX_LUX ? TSL2550_MAX_LUX : lux;
185
}
186
187
/*
188
* SysFS support
189
*/
190
191
static 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
199
static 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
220
static DEVICE_ATTR(power_state, S_IWUSR | S_IRUGO,
221
tsl2550_show_power_state, tsl2550_store_power_state);
222
223
static 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
231
static 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
255
static DEVICE_ATTR(operating_mode, S_IWUSR | S_IRUGO,
256
tsl2550_show_operating_mode, tsl2550_store_operating_mode);
257
258
static ssize_t __tsl2550_show_lux(struct i2c_client *client, char *buf)
259
{
260
struct tsl2550_data *data = i2c_get_clientdata(client);
261
u8 ch0, ch1;
262
int ret;
263
264
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC0);
265
if (ret < 0)
266
return ret;
267
ch0 = ret;
268
269
ret = tsl2550_get_adc_value(client, TSL2550_READ_ADC1);
270
if (ret < 0)
271
return ret;
272
ch1 = ret;
273
274
/* Do the job */
275
ret = tsl2550_calculate_lux(ch0, ch1);
276
if (ret < 0)
277
return ret;
278
if (data->operating_mode == 1)
279
ret *= 5;
280
281
return sprintf(buf, "%d\n", ret);
282
}
283
284
static ssize_t tsl2550_show_lux1_input(struct device *dev,
285
struct device_attribute *attr, char *buf)
286
{
287
struct i2c_client *client = to_i2c_client(dev);
288
struct tsl2550_data *data = i2c_get_clientdata(client);
289
int ret;
290
291
/* No LUX data if not operational */
292
if (!data->power_state)
293
return -EBUSY;
294
295
mutex_lock(&data->update_lock);
296
ret = __tsl2550_show_lux(client, buf);
297
mutex_unlock(&data->update_lock);
298
299
return ret;
300
}
301
302
static DEVICE_ATTR(lux1_input, S_IRUGO,
303
tsl2550_show_lux1_input, NULL);
304
305
static struct attribute *tsl2550_attributes[] = {
306
&dev_attr_power_state.attr,
307
&dev_attr_operating_mode.attr,
308
&dev_attr_lux1_input.attr,
309
NULL
310
};
311
312
static const struct attribute_group tsl2550_attr_group = {
313
.attrs = tsl2550_attributes,
314
};
315
316
/*
317
* Initialization function
318
*/
319
320
static int tsl2550_init_client(struct i2c_client *client)
321
{
322
struct tsl2550_data *data = i2c_get_clientdata(client);
323
int err;
324
325
/*
326
* Probe the chip. To do so we try to power up the device and then to
327
* read back the 0x03 code
328
*/
329
err = i2c_smbus_read_byte_data(client, TSL2550_POWER_UP);
330
if (err < 0)
331
return err;
332
if (err != TSL2550_POWER_UP)
333
return -ENODEV;
334
data->power_state = 1;
335
336
/* Set the default operating mode */
337
err = i2c_smbus_write_byte(client,
338
TSL2550_MODE_RANGE[data->operating_mode]);
339
if (err < 0)
340
return err;
341
342
return 0;
343
}
344
345
/*
346
* I2C init/probing/exit functions
347
*/
348
349
static struct i2c_driver tsl2550_driver;
350
static int __devinit tsl2550_probe(struct i2c_client *client,
351
const struct i2c_device_id *id)
352
{
353
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
354
struct tsl2550_data *data;
355
int *opmode, err = 0;
356
357
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE
358
| I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
359
err = -EIO;
360
goto exit;
361
}
362
363
data = kzalloc(sizeof(struct tsl2550_data), GFP_KERNEL);
364
if (!data) {
365
err = -ENOMEM;
366
goto exit;
367
}
368
data->client = client;
369
i2c_set_clientdata(client, data);
370
371
/* Check platform data */
372
opmode = client->dev.platform_data;
373
if (opmode) {
374
if (*opmode < 0 || *opmode > 1) {
375
dev_err(&client->dev, "invalid operating_mode (%d)\n",
376
*opmode);
377
err = -EINVAL;
378
goto exit_kfree;
379
}
380
data->operating_mode = *opmode;
381
} else
382
data->operating_mode = 0; /* default mode is standard */
383
dev_info(&client->dev, "%s operating mode\n",
384
data->operating_mode ? "extended" : "standard");
385
386
mutex_init(&data->update_lock);
387
388
/* Initialize the TSL2550 chip */
389
err = tsl2550_init_client(client);
390
if (err)
391
goto exit_kfree;
392
393
/* Register sysfs hooks */
394
err = sysfs_create_group(&client->dev.kobj, &tsl2550_attr_group);
395
if (err)
396
goto exit_kfree;
397
398
dev_info(&client->dev, "support ver. %s enabled\n", DRIVER_VERSION);
399
400
return 0;
401
402
exit_kfree:
403
kfree(data);
404
exit:
405
return err;
406
}
407
408
static int __devexit tsl2550_remove(struct i2c_client *client)
409
{
410
sysfs_remove_group(&client->dev.kobj, &tsl2550_attr_group);
411
412
/* Power down the device */
413
tsl2550_set_power_state(client, 0);
414
415
kfree(i2c_get_clientdata(client));
416
417
return 0;
418
}
419
420
#ifdef CONFIG_PM
421
422
static int tsl2550_suspend(struct i2c_client *client, pm_message_t mesg)
423
{
424
return tsl2550_set_power_state(client, 0);
425
}
426
427
static int tsl2550_resume(struct i2c_client *client)
428
{
429
return tsl2550_set_power_state(client, 1);
430
}
431
432
#else
433
434
#define tsl2550_suspend NULL
435
#define tsl2550_resume NULL
436
437
#endif /* CONFIG_PM */
438
439
static const struct i2c_device_id tsl2550_id[] = {
440
{ "tsl2550", 0 },
441
{ }
442
};
443
MODULE_DEVICE_TABLE(i2c, tsl2550_id);
444
445
static struct i2c_driver tsl2550_driver = {
446
.driver = {
447
.name = TSL2550_DRV_NAME,
448
.owner = THIS_MODULE,
449
},
450
.suspend = tsl2550_suspend,
451
.resume = tsl2550_resume,
452
.probe = tsl2550_probe,
453
.remove = __devexit_p(tsl2550_remove),
454
.id_table = tsl2550_id,
455
};
456
457
static int __init tsl2550_init(void)
458
{
459
return i2c_add_driver(&tsl2550_driver);
460
}
461
462
static void __exit tsl2550_exit(void)
463
{
464
i2c_del_driver(&tsl2550_driver);
465
}
466
467
MODULE_AUTHOR("Rodolfo Giometti <[email protected]>");
468
MODULE_DESCRIPTION("TSL2550 ambient light sensor driver");
469
MODULE_LICENSE("GPL");
470
MODULE_VERSION(DRIVER_VERSION);
471
472
module_init(tsl2550_init);
473
module_exit(tsl2550_exit);
474
475