~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/iio/light/tsl2583.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Device driver for monitoring ambient light intensity (lux)
 
3
 * within the TAOS tsl258x family of devices (tsl2580, tsl2581).
 
4
 *
 
5
 * Copyright (c) 2011, TAOS Corporation.
 
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, but WITHOUT
 
13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
14
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 
15
 * more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License along
 
18
 * with this program; if not, write to the Free Software Foundation, Inc.,
 
19
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 
20
 */
 
21
 
 
22
#include <linux/kernel.h>
 
23
#include <linux/i2c.h>
 
24
#include <linux/errno.h>
 
25
#include <linux/delay.h>
 
26
#include <linux/string.h>
 
27
#include <linux/mutex.h>
 
28
#include <linux/unistd.h>
 
29
#include <linux/slab.h>
 
30
#include <linux/module.h>
 
31
#include "../iio.h"
 
32
 
 
33
#define TSL258X_MAX_DEVICE_REGS         32
 
34
 
 
35
/* Triton register offsets */
 
36
#define TSL258X_REG_MAX         8
 
37
 
 
38
/* Device Registers and Masks */
 
39
#define TSL258X_CNTRL                   0x00
 
40
#define TSL258X_ALS_TIME                0X01
 
41
#define TSL258X_INTERRUPT               0x02
 
42
#define TSL258X_GAIN                    0x07
 
43
#define TSL258X_REVID                   0x11
 
44
#define TSL258X_CHIPID                  0x12
 
45
#define TSL258X_ALS_CHAN0LO             0x14
 
46
#define TSL258X_ALS_CHAN0HI             0x15
 
47
#define TSL258X_ALS_CHAN1LO             0x16
 
48
#define TSL258X_ALS_CHAN1HI             0x17
 
49
#define TSL258X_TMR_LO                  0x18
 
50
#define TSL258X_TMR_HI                  0x19
 
51
 
 
52
/* tsl2583 cmd reg masks */
 
53
#define TSL258X_CMD_REG                 0x80
 
54
#define TSL258X_CMD_SPL_FN              0x60
 
55
#define TSL258X_CMD_ALS_INT_CLR 0X01
 
56
 
 
57
/* tsl2583 cntrl reg masks */
 
58
#define TSL258X_CNTL_ADC_ENBL   0x02
 
59
#define TSL258X_CNTL_PWR_ON             0x01
 
60
 
 
61
/* tsl2583 status reg masks */
 
62
#define TSL258X_STA_ADC_VALID   0x01
 
63
#define TSL258X_STA_ADC_INTR    0x10
 
64
 
 
65
/* Lux calculation constants */
 
66
#define TSL258X_LUX_CALC_OVER_FLOW              65535
 
67
 
 
68
enum {
 
69
        TSL258X_CHIP_UNKNOWN = 0,
 
70
        TSL258X_CHIP_WORKING = 1,
 
71
        TSL258X_CHIP_SUSPENDED = 2
 
72
};
 
73
 
 
74
/* Per-device data */
 
75
struct taos_als_info {
 
76
        u16 als_ch0;
 
77
        u16 als_ch1;
 
78
        u16 lux;
 
79
};
 
80
 
 
81
struct taos_settings {
 
82
        int als_time;
 
83
        int als_gain;
 
84
        int als_gain_trim;
 
85
        int als_cal_target;
 
86
};
 
87
 
 
88
struct tsl2583_chip {
 
89
        struct mutex als_mutex;
 
90
        struct i2c_client *client;
 
91
        struct taos_als_info als_cur_info;
 
92
        struct taos_settings taos_settings;
 
93
        int als_time_scale;
 
94
        int als_saturation;
 
95
        int taos_chip_status;
 
96
        u8 taos_config[8];
 
97
};
 
98
 
 
99
/*
 
100
 * Initial values for device - this values can/will be changed by driver.
 
101
 * and applications as needed.
 
102
 * These values are dynamic.
 
103
 */
 
104
static const u8 taos_config[8] = {
 
105
                0x00, 0xee, 0x00, 0x03, 0x00, 0xFF, 0xFF, 0x00
 
106
}; /*   cntrl atime intC  Athl0 Athl1 Athh0 Athh1 gain */
 
107
 
 
108
struct taos_lux {
 
109
        unsigned int ratio;
 
110
        unsigned int ch0;
 
111
        unsigned int ch1;
 
112
};
 
113
 
 
114
/* This structure is intentionally large to accommodate updates via sysfs. */
 
115
/* Sized to 11 = max 10 segments + 1 termination segment */
 
116
/* Assumption is is one and only one type of glass used  */
 
117
static struct taos_lux taos_device_lux[11] = {
 
118
        {  9830,  8520, 15729 },
 
119
        { 12452, 10807, 23344 },
 
120
        { 14746,  6383, 11705 },
 
121
        { 17695,  4063,  6554 },
 
122
};
 
123
 
 
124
struct gainadj {
 
125
        s16 ch0;
 
126
        s16 ch1;
 
127
};
 
128
 
 
129
/* Index = (0 - 3) Used to validate the gain selection index */
 
130
static const struct gainadj gainadj[] = {
 
131
        { 1, 1 },
 
132
        { 8, 8 },
 
133
        { 16, 16 },
 
134
        { 107, 115 }
 
135
};
 
136
 
 
137
/*
 
138
 * Provides initial operational parameter defaults.
 
139
 * These defaults may be changed through the device's sysfs files.
 
140
 */
 
141
static void taos_defaults(struct tsl2583_chip *chip)
 
142
{
 
143
        /* Operational parameters */
 
144
        chip->taos_settings.als_time = 100;
 
145
        /* must be a multiple of 50mS */
 
146
        chip->taos_settings.als_gain = 0;
 
147
        /* this is actually an index into the gain table */
 
148
        /* assume clear glass as default */
 
149
        chip->taos_settings.als_gain_trim = 1000;
 
150
        /* default gain trim to account for aperture effects */
 
151
        chip->taos_settings.als_cal_target = 130;
 
152
        /* Known external ALS reading used for calibration */
 
153
}
 
154
 
 
155
/*
 
156
 * Read a number of bytes starting at register (reg) location.
 
157
 * Return 0, or i2c_smbus_write_byte ERROR code.
 
158
 */
 
159
static int
 
160
taos_i2c_read(struct i2c_client *client, u8 reg, u8 *val, unsigned int len)
 
161
{
 
162
        int i, ret;
 
163
 
 
164
        for (i = 0; i < len; i++) {
 
165
                /* select register to write */
 
166
                ret = i2c_smbus_write_byte(client, (TSL258X_CMD_REG | reg));
 
167
                if (ret < 0) {
 
168
                        dev_err(&client->dev, "taos_i2c_read failed to write"
 
169
                                " register %x\n", reg);
 
170
                        return ret;
 
171
                }
 
172
                /* read the data */
 
173
                *val = i2c_smbus_read_byte(client);
 
174
                val++;
 
175
                reg++;
 
176
        }
 
177
        return 0;
 
178
}
 
179
 
 
180
/*
 
181
 * Reads and calculates current lux value.
 
182
 * The raw ch0 and ch1 values of the ambient light sensed in the last
 
183
 * integration cycle are read from the device.
 
184
 * Time scale factor array values are adjusted based on the integration time.
 
185
 * The raw values are multiplied by a scale factor, and device gain is obtained
 
186
 * using gain index. Limit checks are done next, then the ratio of a multiple
 
187
 * of ch1 value, to the ch0 value, is calculated. The array taos_device_lux[]
 
188
 * declared above is then scanned to find the first ratio value that is just
 
189
 * above the ratio we just calculated. The ch0 and ch1 multiplier constants in
 
190
 * the array are then used along with the time scale factor array values, to
 
191
 * calculate the lux.
 
192
 */
 
193
static int taos_get_lux(struct iio_dev *indio_dev)
 
194
{
 
195
        u16 ch0, ch1; /* separated ch0/ch1 data from device */
 
196
        u32 lux; /* raw lux calculated from device data */
 
197
        u32 ratio;
 
198
        u8 buf[5];
 
199
        struct taos_lux *p;
 
200
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
201
        int i, ret;
 
202
        u32 ch0lux = 0;
 
203
        u32 ch1lux = 0;
 
204
 
 
205
        if (mutex_trylock(&chip->als_mutex) == 0) {
 
206
                dev_info(&chip->client->dev, "taos_get_lux device is busy\n");
 
207
                return chip->als_cur_info.lux; /* busy, so return LAST VALUE */
 
208
        }
 
209
 
 
210
        if (chip->taos_chip_status != TSL258X_CHIP_WORKING) {
 
211
                /* device is not enabled */
 
212
                dev_err(&chip->client->dev, "taos_get_lux device is not enabled\n");
 
213
                ret = -EBUSY ;
 
214
                goto out_unlock;
 
215
        }
 
216
 
 
217
        ret = taos_i2c_read(chip->client, (TSL258X_CMD_REG), &buf[0], 1);
 
218
        if (ret < 0) {
 
219
                dev_err(&chip->client->dev, "taos_get_lux failed to read CMD_REG\n");
 
220
                goto out_unlock;
 
221
        }
 
222
        /* is data new & valid */
 
223
        if (!(buf[0] & TSL258X_STA_ADC_INTR)) {
 
224
                dev_err(&chip->client->dev, "taos_get_lux data not valid\n");
 
225
                ret = chip->als_cur_info.lux; /* return LAST VALUE */
 
226
                goto out_unlock;
 
227
        }
 
228
 
 
229
        for (i = 0; i < 4; i++) {
 
230
                int reg = TSL258X_CMD_REG | (TSL258X_ALS_CHAN0LO + i);
 
231
                ret = taos_i2c_read(chip->client, reg, &buf[i], 1);
 
232
                if (ret < 0) {
 
233
                        dev_err(&chip->client->dev, "taos_get_lux failed to read"
 
234
                                " register %x\n", reg);
 
235
                        goto out_unlock;
 
236
                }
 
237
        }
 
238
 
 
239
        /* clear status, really interrupt status (interrupts are off), but
 
240
         * we use the bit anyway - don't forget 0x80 - this is a command*/
 
241
        ret = i2c_smbus_write_byte(chip->client,
 
242
                                   (TSL258X_CMD_REG | TSL258X_CMD_SPL_FN |
 
243
                                    TSL258X_CMD_ALS_INT_CLR));
 
244
 
 
245
        if (ret < 0) {
 
246
                dev_err(&chip->client->dev,
 
247
                        "taos_i2c_write_command failed in taos_get_lux, err = %d\n",
 
248
                        ret);
 
249
                goto out_unlock; /* have no data, so return failure */
 
250
        }
 
251
 
 
252
        /* extract ALS/lux data */
 
253
        ch0 = le16_to_cpup((const __le16 *)&buf[0]);
 
254
        ch1 = le16_to_cpup((const __le16 *)&buf[2]);
 
255
 
 
256
        chip->als_cur_info.als_ch0 = ch0;
 
257
        chip->als_cur_info.als_ch1 = ch1;
 
258
 
 
259
        if ((ch0 >= chip->als_saturation) || (ch1 >= chip->als_saturation))
 
260
                goto return_max;
 
261
 
 
262
        if (ch0 == 0) {
 
263
                /* have no data, so return LAST VALUE */
 
264
                ret = chip->als_cur_info.lux = 0;
 
265
                goto out_unlock;
 
266
        }
 
267
        /* calculate ratio */
 
268
        ratio = (ch1 << 15) / ch0;
 
269
        /* convert to unscaled lux using the pointer to the table */
 
270
        for (p = (struct taos_lux *) taos_device_lux;
 
271
             p->ratio != 0 && p->ratio < ratio; p++)
 
272
                ;
 
273
 
 
274
        if (p->ratio == 0) {
 
275
                lux = 0;
 
276
        } else {
 
277
                ch0lux = ((ch0 * p->ch0) +
 
278
                          (gainadj[chip->taos_settings.als_gain].ch0 >> 1))
 
279
                         / gainadj[chip->taos_settings.als_gain].ch0;
 
280
                ch1lux = ((ch1 * p->ch1) +
 
281
                          (gainadj[chip->taos_settings.als_gain].ch1 >> 1))
 
282
                         / gainadj[chip->taos_settings.als_gain].ch1;
 
283
                lux = ch0lux - ch1lux;
 
284
        }
 
285
 
 
286
        /* note: lux is 31 bit max at this point */
 
287
        if (ch1lux > ch0lux) {
 
288
                dev_dbg(&chip->client->dev, "No Data - Return last value\n");
 
289
                ret = chip->als_cur_info.lux = 0;
 
290
                goto out_unlock;
 
291
        }
 
292
 
 
293
        /* adjust for active time scale */
 
294
        if (chip->als_time_scale == 0)
 
295
                lux = 0;
 
296
        else
 
297
                lux = (lux + (chip->als_time_scale >> 1)) /
 
298
                        chip->als_time_scale;
 
299
 
 
300
        /* adjust for active gain scale */
 
301
        lux >>= 13; /* tables have factor of 8192 builtin for accuracy */
 
302
        lux = (lux * chip->taos_settings.als_gain_trim + 500) / 1000;
 
303
        if (lux > TSL258X_LUX_CALC_OVER_FLOW) { /* check for overflow */
 
304
return_max:
 
305
                lux = TSL258X_LUX_CALC_OVER_FLOW;
 
306
        }
 
307
 
 
308
        /* Update the structure with the latest VALID lux. */
 
309
        chip->als_cur_info.lux = lux;
 
310
        ret = lux;
 
311
 
 
312
out_unlock:
 
313
        mutex_unlock(&chip->als_mutex);
 
314
        return ret;
 
315
}
 
316
 
 
317
/*
 
318
 * Obtain single reading and calculate the als_gain_trim (later used
 
319
 * to derive actual lux).
 
320
 * Return updated gain_trim value.
 
321
 */
 
322
static int taos_als_calibrate(struct iio_dev *indio_dev)
 
323
{
 
324
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
325
        u8 reg_val;
 
326
        unsigned int gain_trim_val;
 
327
        int ret;
 
328
        int lux_val;
 
329
 
 
330
        ret = i2c_smbus_write_byte(chip->client,
 
331
                                   (TSL258X_CMD_REG | TSL258X_CNTRL));
 
332
        if (ret < 0) {
 
333
                dev_err(&chip->client->dev,
 
334
                        "taos_als_calibrate failed to reach the CNTRL register, ret=%d\n",
 
335
                        ret);
 
336
                return ret;
 
337
        }
 
338
 
 
339
        reg_val = i2c_smbus_read_byte(chip->client);
 
340
        if ((reg_val & (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON))
 
341
                        != (TSL258X_CNTL_ADC_ENBL | TSL258X_CNTL_PWR_ON)) {
 
342
                dev_err(&chip->client->dev,
 
343
                        "taos_als_calibrate failed: device not powered on with ADC enabled\n");
 
344
                return -1;
 
345
        }
 
346
 
 
347
        ret = i2c_smbus_write_byte(chip->client,
 
348
                                   (TSL258X_CMD_REG | TSL258X_CNTRL));
 
349
        if (ret < 0) {
 
350
                dev_err(&chip->client->dev,
 
351
                        "taos_als_calibrate failed to reach the STATUS register, ret=%d\n",
 
352
                        ret);
 
353
                return ret;
 
354
        }
 
355
        reg_val = i2c_smbus_read_byte(chip->client);
 
356
 
 
357
        if ((reg_val & TSL258X_STA_ADC_VALID) != TSL258X_STA_ADC_VALID) {
 
358
                dev_err(&chip->client->dev,
 
359
                        "taos_als_calibrate failed: STATUS - ADC not valid.\n");
 
360
                return -ENODATA;
 
361
        }
 
362
        lux_val = taos_get_lux(indio_dev);
 
363
        if (lux_val < 0) {
 
364
                dev_err(&chip->client->dev, "taos_als_calibrate failed to get lux\n");
 
365
                return lux_val;
 
366
        }
 
367
        gain_trim_val = (unsigned int) (((chip->taos_settings.als_cal_target)
 
368
                        * chip->taos_settings.als_gain_trim) / lux_val);
 
369
 
 
370
        if ((gain_trim_val < 250) || (gain_trim_val > 4000)) {
 
371
                dev_err(&chip->client->dev,
 
372
                        "taos_als_calibrate failed: trim_val of %d is out of range\n",
 
373
                        gain_trim_val);
 
374
                return -ENODATA;
 
375
        }
 
376
        chip->taos_settings.als_gain_trim = (int) gain_trim_val;
 
377
 
 
378
        return (int) gain_trim_val;
 
379
}
 
380
 
 
381
/*
 
382
 * Turn the device on.
 
383
 * Configuration must be set before calling this function.
 
384
 */
 
385
static int taos_chip_on(struct iio_dev *indio_dev)
 
386
{
 
387
        int i;
 
388
        int ret;
 
389
        u8 *uP;
 
390
        u8 utmp;
 
391
        int als_count;
 
392
        int als_time;
 
393
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
394
 
 
395
        /* and make sure we're not already on */
 
396
        if (chip->taos_chip_status == TSL258X_CHIP_WORKING) {
 
397
                /* if forcing a register update - turn off, then on */
 
398
                dev_info(&chip->client->dev, "device is already enabled\n");
 
399
                return -EINVAL;
 
400
        }
 
401
 
 
402
        /* determine als integration regster */
 
403
        als_count = (chip->taos_settings.als_time * 100 + 135) / 270;
 
404
        if (als_count == 0)
 
405
                als_count = 1; /* ensure at least one cycle */
 
406
 
 
407
        /* convert back to time (encompasses overrides) */
 
408
        als_time = (als_count * 27 + 5) / 10;
 
409
        chip->taos_config[TSL258X_ALS_TIME] = 256 - als_count;
 
410
 
 
411
        /* Set the gain based on taos_settings struct */
 
412
        chip->taos_config[TSL258X_GAIN] = chip->taos_settings.als_gain;
 
413
 
 
414
        /* set chip struct re scaling and saturation */
 
415
        chip->als_saturation = als_count * 922; /* 90% of full scale */
 
416
        chip->als_time_scale = (als_time + 25) / 50;
 
417
 
 
418
        /* TSL258x Specific power-on / adc enable sequence
 
419
         * Power on the device 1st. */
 
420
        utmp = TSL258X_CNTL_PWR_ON;
 
421
        ret = i2c_smbus_write_byte_data(chip->client,
 
422
                                        TSL258X_CMD_REG | TSL258X_CNTRL, utmp);
 
423
        if (ret < 0) {
 
424
                dev_err(&chip->client->dev, "taos_chip_on failed on CNTRL reg.\n");
 
425
                return -1;
 
426
        }
 
427
 
 
428
        /* Use the following shadow copy for our delay before enabling ADC.
 
429
         * Write all the registers. */
 
430
        for (i = 0, uP = chip->taos_config; i < TSL258X_REG_MAX; i++) {
 
431
                ret = i2c_smbus_write_byte_data(chip->client,
 
432
                                                TSL258X_CMD_REG + i,
 
433
                                                *uP++);
 
434
                if (ret < 0) {
 
435
                        dev_err(&chip->client->dev,
 
436
                                "taos_chip_on failed on reg %d.\n", i);
 
437
                        return -1;
 
438
                }
 
439
        }
 
440
 
 
441
        msleep(3);
 
442
        /* NOW enable the ADC
 
443
         * initialize the desired mode of operation */
 
444
        utmp = TSL258X_CNTL_PWR_ON | TSL258X_CNTL_ADC_ENBL;
 
445
        ret = i2c_smbus_write_byte_data(chip->client,
 
446
                                        TSL258X_CMD_REG | TSL258X_CNTRL,
 
447
                                        utmp);
 
448
        if (ret < 0) {
 
449
                dev_err(&chip->client->dev, "taos_chip_on failed on 2nd CTRL reg.\n");
 
450
                return -1;
 
451
        }
 
452
        chip->taos_chip_status = TSL258X_CHIP_WORKING;
 
453
 
 
454
        return ret;
 
455
}
 
456
 
 
457
static int taos_chip_off(struct iio_dev *indio_dev)
 
458
{
 
459
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
460
        int ret;
 
461
 
 
462
        /* turn device off */
 
463
        chip->taos_chip_status = TSL258X_CHIP_SUSPENDED;
 
464
        ret = i2c_smbus_write_byte_data(chip->client,
 
465
                                        TSL258X_CMD_REG | TSL258X_CNTRL,
 
466
                                        0x00);
 
467
        return ret;
 
468
}
 
469
 
 
470
/* Sysfs Interface Functions */
 
471
 
 
472
static ssize_t taos_power_state_show(struct device *dev,
 
473
        struct device_attribute *attr, char *buf)
 
474
{
 
475
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
476
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
477
 
 
478
        return sprintf(buf, "%d\n", chip->taos_chip_status);
 
479
}
 
480
 
 
481
static ssize_t taos_power_state_store(struct device *dev,
 
482
        struct device_attribute *attr, const char *buf, size_t len)
 
483
{
 
484
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
485
        unsigned long value;
 
486
 
 
487
        if (strict_strtoul(buf, 0, &value))
 
488
                return -EINVAL;
 
489
 
 
490
        if (value == 0)
 
491
                taos_chip_off(indio_dev);
 
492
        else
 
493
                taos_chip_on(indio_dev);
 
494
 
 
495
        return len;
 
496
}
 
497
 
 
498
static ssize_t taos_gain_show(struct device *dev,
 
499
        struct device_attribute *attr, char *buf)
 
500
{
 
501
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
502
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
503
        char gain[4] = {0};
 
504
 
 
505
        switch (chip->taos_settings.als_gain) {
 
506
        case 0:
 
507
                strcpy(gain, "001");
 
508
                break;
 
509
        case 1:
 
510
                strcpy(gain, "008");
 
511
                break;
 
512
        case 2:
 
513
                strcpy(gain, "016");
 
514
                break;
 
515
        case 3:
 
516
                strcpy(gain, "111");
 
517
                break;
 
518
        }
 
519
 
 
520
        return sprintf(buf, "%s\n", gain);
 
521
}
 
522
 
 
523
static ssize_t taos_gain_store(struct device *dev,
 
524
        struct device_attribute *attr, const char *buf, size_t len)
 
525
{
 
526
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
527
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
528
        unsigned long value;
 
529
 
 
530
        if (strict_strtoul(buf, 0, &value))
 
531
                return -EINVAL;
 
532
 
 
533
        switch (value) {
 
534
        case 1:
 
535
                chip->taos_settings.als_gain = 0;
 
536
                break;
 
537
        case 8:
 
538
                chip->taos_settings.als_gain = 1;
 
539
                break;
 
540
        case 16:
 
541
                chip->taos_settings.als_gain = 2;
 
542
                break;
 
543
        case 111:
 
544
                chip->taos_settings.als_gain = 3;
 
545
                break;
 
546
        default:
 
547
                dev_err(dev, "Invalid Gain Index (must be 1,8,16,111)\n");
 
548
                return -1;
 
549
        }
 
550
 
 
551
        return len;
 
552
}
 
553
 
 
554
static ssize_t taos_gain_available_show(struct device *dev,
 
555
        struct device_attribute *attr, char *buf)
 
556
{
 
557
        return sprintf(buf, "%s\n", "1 8 16 111");
 
558
}
 
559
 
 
560
static ssize_t taos_als_time_show(struct device *dev,
 
561
        struct device_attribute *attr, char *buf)
 
562
{
 
563
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
564
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
565
 
 
566
        return sprintf(buf, "%d\n", chip->taos_settings.als_time);
 
567
}
 
568
 
 
569
static ssize_t taos_als_time_store(struct device *dev,
 
570
        struct device_attribute *attr, const char *buf, size_t len)
 
571
{
 
572
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
573
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
574
        unsigned long value;
 
575
 
 
576
        if (strict_strtoul(buf, 0, &value))
 
577
                return -EINVAL;
 
578
 
 
579
        if ((value < 50) || (value > 650))
 
580
                return -EINVAL;
 
581
 
 
582
        if (value % 50)
 
583
                return -EINVAL;
 
584
 
 
585
        chip->taos_settings.als_time = value;
 
586
 
 
587
        return len;
 
588
}
 
589
 
 
590
static ssize_t taos_als_time_available_show(struct device *dev,
 
591
        struct device_attribute *attr, char *buf)
 
592
{
 
593
        return sprintf(buf, "%s\n",
 
594
                "50 100 150 200 250 300 350 400 450 500 550 600 650");
 
595
}
 
596
 
 
597
static ssize_t taos_als_trim_show(struct device *dev,
 
598
        struct device_attribute *attr, char *buf)
 
599
{
 
600
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
601
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
602
 
 
603
        return sprintf(buf, "%d\n", chip->taos_settings.als_gain_trim);
 
604
}
 
605
 
 
606
static ssize_t taos_als_trim_store(struct device *dev,
 
607
        struct device_attribute *attr, const char *buf, size_t len)
 
608
{
 
609
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
610
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
611
        unsigned long value;
 
612
 
 
613
        if (strict_strtoul(buf, 0, &value))
 
614
                return -EINVAL;
 
615
 
 
616
        if (value)
 
617
                chip->taos_settings.als_gain_trim = value;
 
618
 
 
619
        return len;
 
620
}
 
621
 
 
622
static ssize_t taos_als_cal_target_show(struct device *dev,
 
623
        struct device_attribute *attr, char *buf)
 
624
{
 
625
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
626
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
627
 
 
628
        return sprintf(buf, "%d\n", chip->taos_settings.als_cal_target);
 
629
}
 
630
 
 
631
static ssize_t taos_als_cal_target_store(struct device *dev,
 
632
        struct device_attribute *attr, const char *buf, size_t len)
 
633
{
 
634
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
635
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
636
        unsigned long value;
 
637
 
 
638
        if (strict_strtoul(buf, 0, &value))
 
639
                return -EINVAL;
 
640
 
 
641
        if (value)
 
642
                chip->taos_settings.als_cal_target = value;
 
643
 
 
644
        return len;
 
645
}
 
646
 
 
647
static ssize_t taos_lux_show(struct device *dev, struct device_attribute *attr,
 
648
        char *buf)
 
649
{
 
650
        int ret;
 
651
 
 
652
        ret = taos_get_lux(dev_get_drvdata(dev));
 
653
        if (ret < 0)
 
654
                return ret;
 
655
 
 
656
        return sprintf(buf, "%d\n", ret);
 
657
}
 
658
 
 
659
static ssize_t taos_do_calibrate(struct device *dev,
 
660
        struct device_attribute *attr, const char *buf, size_t len)
 
661
{
 
662
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
663
        unsigned long value;
 
664
 
 
665
        if (strict_strtoul(buf, 0, &value))
 
666
                return -EINVAL;
 
667
 
 
668
        if (value == 1)
 
669
                taos_als_calibrate(indio_dev);
 
670
 
 
671
        return len;
 
672
}
 
673
 
 
674
static ssize_t taos_luxtable_show(struct device *dev,
 
675
        struct device_attribute *attr, char *buf)
 
676
{
 
677
        int i;
 
678
        int offset = 0;
 
679
 
 
680
        for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) {
 
681
                offset += sprintf(buf + offset, "%d,%d,%d,",
 
682
                                  taos_device_lux[i].ratio,
 
683
                                  taos_device_lux[i].ch0,
 
684
                                  taos_device_lux[i].ch1);
 
685
                if (taos_device_lux[i].ratio == 0) {
 
686
                        /* We just printed the first "0" entry.
 
687
                         * Now get rid of the extra "," and break. */
 
688
                        offset--;
 
689
                        break;
 
690
                }
 
691
        }
 
692
 
 
693
        offset += sprintf(buf + offset, "\n");
 
694
        return offset;
 
695
}
 
696
 
 
697
static ssize_t taos_luxtable_store(struct device *dev,
 
698
        struct device_attribute *attr, const char *buf, size_t len)
 
699
{
 
700
        struct iio_dev *indio_dev = dev_get_drvdata(dev);
 
701
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
702
        int value[ARRAY_SIZE(taos_device_lux)*3 + 1];
 
703
        int n;
 
704
 
 
705
        get_options(buf, ARRAY_SIZE(value), value);
 
706
 
 
707
        /* We now have an array of ints starting at value[1], and
 
708
         * enumerated by value[0].
 
709
         * We expect each group of three ints is one table entry,
 
710
         * and the last table entry is all 0.
 
711
         */
 
712
        n = value[0];
 
713
        if ((n % 3) || n < 6 || n > ((ARRAY_SIZE(taos_device_lux) - 1) * 3)) {
 
714
                dev_info(dev, "LUX TABLE INPUT ERROR 1 Value[0]=%d\n", n);
 
715
                return -EINVAL;
 
716
        }
 
717
        if ((value[(n - 2)] | value[(n - 1)] | value[n]) != 0) {
 
718
                dev_info(dev, "LUX TABLE INPUT ERROR 2 Value[0]=%d\n", n);
 
719
                return -EINVAL;
 
720
        }
 
721
 
 
722
        if (chip->taos_chip_status == TSL258X_CHIP_WORKING)
 
723
                taos_chip_off(indio_dev);
 
724
 
 
725
        /* Zero out the table */
 
726
        memset(taos_device_lux, 0, sizeof(taos_device_lux));
 
727
        memcpy(taos_device_lux, &value[1], (value[0] * 4));
 
728
 
 
729
        taos_chip_on(indio_dev);
 
730
 
 
731
        return len;
 
732
}
 
733
 
 
734
static DEVICE_ATTR(power_state, S_IRUGO | S_IWUSR,
 
735
                taos_power_state_show, taos_power_state_store);
 
736
 
 
737
static DEVICE_ATTR(illuminance0_calibscale, S_IRUGO | S_IWUSR,
 
738
                taos_gain_show, taos_gain_store);
 
739
static DEVICE_ATTR(illuminance0_calibscale_available, S_IRUGO,
 
740
                taos_gain_available_show, NULL);
 
741
 
 
742
static DEVICE_ATTR(illuminance0_integration_time, S_IRUGO | S_IWUSR,
 
743
                taos_als_time_show, taos_als_time_store);
 
744
static DEVICE_ATTR(illuminance0_integration_time_available, S_IRUGO,
 
745
                taos_als_time_available_show, NULL);
 
746
 
 
747
static DEVICE_ATTR(illuminance0_calibbias, S_IRUGO | S_IWUSR,
 
748
                taos_als_trim_show, taos_als_trim_store);
 
749
 
 
750
static DEVICE_ATTR(illuminance0_input_target, S_IRUGO | S_IWUSR,
 
751
                taos_als_cal_target_show, taos_als_cal_target_store);
 
752
 
 
753
static DEVICE_ATTR(illuminance0_input, S_IRUGO, taos_lux_show, NULL);
 
754
static DEVICE_ATTR(illuminance0_calibrate, S_IWUSR, NULL, taos_do_calibrate);
 
755
static DEVICE_ATTR(illuminance0_lux_table, S_IRUGO | S_IWUSR,
 
756
                taos_luxtable_show, taos_luxtable_store);
 
757
 
 
758
static struct attribute *sysfs_attrs_ctrl[] = {
 
759
        &dev_attr_power_state.attr,
 
760
        &dev_attr_illuminance0_calibscale.attr,                 /* Gain  */
 
761
        &dev_attr_illuminance0_calibscale_available.attr,
 
762
        &dev_attr_illuminance0_integration_time.attr,   /* I time*/
 
763
        &dev_attr_illuminance0_integration_time_available.attr,
 
764
        &dev_attr_illuminance0_calibbias.attr,                  /* trim  */
 
765
        &dev_attr_illuminance0_input_target.attr,
 
766
        &dev_attr_illuminance0_input.attr,
 
767
        &dev_attr_illuminance0_calibrate.attr,
 
768
        &dev_attr_illuminance0_lux_table.attr,
 
769
        NULL
 
770
};
 
771
 
 
772
static struct attribute_group tsl2583_attribute_group = {
 
773
        .attrs = sysfs_attrs_ctrl,
 
774
};
 
775
 
 
776
/* Use the default register values to identify the Taos device */
 
777
static int taos_tsl258x_device(unsigned char *bufp)
 
778
{
 
779
        return ((bufp[TSL258X_CHIPID] & 0xf0) == 0x90);
 
780
}
 
781
 
 
782
static const struct iio_info tsl2583_info = {
 
783
        .attrs = &tsl2583_attribute_group,
 
784
        .driver_module = THIS_MODULE,
 
785
};
 
786
 
 
787
/*
 
788
 * Client probe function - When a valid device is found, the driver's device
 
789
 * data structure is updated, and initialization completes successfully.
 
790
 */
 
791
static int __devinit taos_probe(struct i2c_client *clientp,
 
792
                      const struct i2c_device_id *idp)
 
793
{
 
794
        int i, ret;
 
795
        unsigned char buf[TSL258X_MAX_DEVICE_REGS];
 
796
        struct tsl2583_chip *chip;
 
797
        struct iio_dev *indio_dev;
 
798
 
 
799
        if (!i2c_check_functionality(clientp->adapter,
 
800
                I2C_FUNC_SMBUS_BYTE_DATA)) {
 
801
                dev_err(&clientp->dev,
 
802
                        "taos_probe() - i2c smbus byte data "
 
803
                        "functions unsupported\n");
 
804
                return -EOPNOTSUPP;
 
805
        }
 
806
 
 
807
        indio_dev = iio_allocate_device(sizeof(*chip));
 
808
        if (indio_dev == NULL) {
 
809
                ret = -ENOMEM;
 
810
                dev_err(&clientp->dev, "iio allocation failed\n");
 
811
                goto fail1;
 
812
        }
 
813
        chip = iio_priv(indio_dev);
 
814
        chip->client = clientp;
 
815
        i2c_set_clientdata(clientp, indio_dev);
 
816
 
 
817
        mutex_init(&chip->als_mutex);
 
818
        chip->taos_chip_status = TSL258X_CHIP_UNKNOWN;
 
819
        memcpy(chip->taos_config, taos_config, sizeof(chip->taos_config));
 
820
 
 
821
        for (i = 0; i < TSL258X_MAX_DEVICE_REGS; i++) {
 
822
                ret = i2c_smbus_write_byte(clientp,
 
823
                                (TSL258X_CMD_REG | (TSL258X_CNTRL + i)));
 
824
                if (ret < 0) {
 
825
                        dev_err(&clientp->dev, "i2c_smbus_write_bytes() to cmd "
 
826
                                "reg failed in taos_probe(), err = %d\n", ret);
 
827
                        goto fail2;
 
828
                }
 
829
                ret = i2c_smbus_read_byte(clientp);
 
830
                if (ret < 0) {
 
831
                        dev_err(&clientp->dev, "i2c_smbus_read_byte from "
 
832
                                "reg failed in taos_probe(), err = %d\n", ret);
 
833
 
 
834
                        goto fail2;
 
835
                }
 
836
                buf[i] = ret;
 
837
        }
 
838
 
 
839
        if (!taos_tsl258x_device(buf)) {
 
840
                dev_info(&clientp->dev, "i2c device found but does not match "
 
841
                        "expected id in taos_probe()\n");
 
842
                goto fail2;
 
843
        }
 
844
 
 
845
        ret = i2c_smbus_write_byte(clientp, (TSL258X_CMD_REG | TSL258X_CNTRL));
 
846
        if (ret < 0) {
 
847
                dev_err(&clientp->dev, "i2c_smbus_write_byte() to cmd reg "
 
848
                        "failed in taos_probe(), err = %d\n", ret);
 
849
                goto fail2;
 
850
        }
 
851
 
 
852
        indio_dev->info = &tsl2583_info;
 
853
        indio_dev->dev.parent = &clientp->dev;
 
854
        indio_dev->modes = INDIO_DIRECT_MODE;
 
855
        indio_dev->name = chip->client->name;
 
856
        ret = iio_device_register(indio_dev);
 
857
        if (ret) {
 
858
                dev_err(&clientp->dev, "iio registration failed\n");
 
859
                goto fail2;
 
860
        }
 
861
 
 
862
        /* Load up the V2 defaults (these are hard coded defaults for now) */
 
863
        taos_defaults(chip);
 
864
 
 
865
        /* Make sure the chip is on */
 
866
        taos_chip_on(indio_dev);
 
867
 
 
868
        dev_info(&clientp->dev, "Light sensor found.\n");
 
869
        return 0;
 
870
fail1:
 
871
        iio_free_device(indio_dev);
 
872
fail2:
 
873
        return ret;
 
874
}
 
875
 
 
876
static int taos_suspend(struct i2c_client *client, pm_message_t state)
 
877
{
 
878
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
879
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
880
        int ret = 0;
 
881
 
 
882
        mutex_lock(&chip->als_mutex);
 
883
 
 
884
        if (chip->taos_chip_status == TSL258X_CHIP_WORKING) {
 
885
                ret = taos_chip_off(indio_dev);
 
886
                chip->taos_chip_status = TSL258X_CHIP_SUSPENDED;
 
887
        }
 
888
 
 
889
        mutex_unlock(&chip->als_mutex);
 
890
        return ret;
 
891
}
 
892
 
 
893
static int taos_resume(struct i2c_client *client)
 
894
{
 
895
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
896
        struct tsl2583_chip *chip = iio_priv(indio_dev);
 
897
        int ret = 0;
 
898
 
 
899
        mutex_lock(&chip->als_mutex);
 
900
 
 
901
        if (chip->taos_chip_status == TSL258X_CHIP_SUSPENDED)
 
902
                ret = taos_chip_on(indio_dev);
 
903
 
 
904
        mutex_unlock(&chip->als_mutex);
 
905
        return ret;
 
906
}
 
907
 
 
908
 
 
909
static int __devexit taos_remove(struct i2c_client *client)
 
910
{
 
911
        iio_device_unregister(i2c_get_clientdata(client));
 
912
        iio_free_device(i2c_get_clientdata(client));
 
913
 
 
914
        return 0;
 
915
}
 
916
 
 
917
static struct i2c_device_id taos_idtable[] = {
 
918
        { "tsl2580", 0 },
 
919
        { "tsl2581", 1 },
 
920
        { "tsl2583", 2 },
 
921
        {}
 
922
};
 
923
MODULE_DEVICE_TABLE(i2c, taos_idtable);
 
924
 
 
925
/* Driver definition */
 
926
static struct i2c_driver taos_driver = {
 
927
        .driver = {
 
928
                .name = "tsl2583",
 
929
        },
 
930
        .id_table = taos_idtable,
 
931
        .suspend        = taos_suspend,
 
932
        .resume         = taos_resume,
 
933
        .probe = taos_probe,
 
934
        .remove = __devexit_p(taos_remove),
 
935
};
 
936
 
 
937
static int __init taos_init(void)
 
938
{
 
939
        return i2c_add_driver(&taos_driver);
 
940
}
 
941
 
 
942
static void __exit taos_exit(void)
 
943
{
 
944
        i2c_del_driver(&taos_driver);
 
945
}
 
946
 
 
947
module_init(taos_init);
 
948
module_exit(taos_exit);
 
949
 
 
950
MODULE_AUTHOR("J. August Brenner<jbrenner@taosinc.com>");
 
951
MODULE_DESCRIPTION("TAOS tsl2583 ambient light sensor driver");
 
952
MODULE_LICENSE("GPL");