Commit | Line | Data |
---|---|---|
ee1f1fa4 AK |
1 | /* |
2 | * drivers/i2c/chips/tsl2563.c | |
3 | * | |
4 | * Copyright (C) 2008 Nokia Corporation | |
5 | * | |
6 | * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com> | |
7 | * Contact: Amit Kucheria <amit.kucheria@verdurent.com> | |
8 | * | |
9 | * Converted to IIO driver | |
10 | * Amit Kucheria <amit.kucheria@verdurent.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU General Public License | |
14 | * version 2 as published by the Free Software Foundation. | |
15 | * | |
16 | * This program is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
22 | * along with this program; if not, write to the Free Software | |
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
24 | * 02110-1301 USA | |
25 | */ | |
26 | ||
27 | #include <linux/module.h> | |
28 | #include <linux/i2c.h> | |
29 | #include <linux/interrupt.h> | |
30 | #include <linux/sched.h> | |
31 | #include <linux/mutex.h> | |
32 | #include <linux/delay.h> | |
33 | #include <linux/platform_device.h> | |
34 | #include <linux/pm.h> | |
35 | #include <linux/hwmon.h> | |
36 | #include <linux/err.h> | |
5a0e3ad6 | 37 | #include <linux/slab.h> |
ee1f1fa4 AK |
38 | |
39 | #include "../iio.h" | |
40 | #include "tsl2563.h" | |
41 | ||
ee1f1fa4 AK |
42 | /* Use this many bits for fraction part. */ |
43 | #define ADC_FRAC_BITS (14) | |
44 | ||
45 | /* Given number of 1/10000's in ADC_FRAC_BITS precision. */ | |
46 | #define FRAC10K(f) (((f) * (1L << (ADC_FRAC_BITS))) / (10000)) | |
47 | ||
48 | /* Bits used for fraction in calibration coefficients.*/ | |
49 | #define CALIB_FRAC_BITS (10) | |
50 | /* 0.5 in CALIB_FRAC_BITS precision */ | |
51 | #define CALIB_FRAC_HALF (1 << (CALIB_FRAC_BITS - 1)) | |
52 | /* Make a fraction from a number n that was multiplied with b. */ | |
53 | #define CALIB_FRAC(n, b) (((n) << CALIB_FRAC_BITS) / (b)) | |
54 | /* Decimal 10^(digits in sysfs presentation) */ | |
55 | #define CALIB_BASE_SYSFS (1000) | |
56 | ||
57 | #define TSL2563_CMD (0x80) | |
58 | #define TSL2563_CLEARINT (0x40) | |
59 | ||
60 | #define TSL2563_REG_CTRL (0x00) | |
61 | #define TSL2563_REG_TIMING (0x01) | |
62 | #define TSL2563_REG_LOWLOW (0x02) /* data0 low threshold, 2 bytes */ | |
63 | #define TSL2563_REG_LOWHIGH (0x03) | |
64 | #define TSL2563_REG_HIGHLOW (0x04) /* data0 high threshold, 2 bytes */ | |
65 | #define TSL2563_REG_HIGHHIGH (0x05) | |
66 | #define TSL2563_REG_INT (0x06) | |
67 | #define TSL2563_REG_ID (0x0a) | |
68 | #define TSL2563_REG_DATA0LOW (0x0c) /* broadband sensor value, 2 bytes */ | |
69 | #define TSL2563_REG_DATA0HIGH (0x0d) | |
70 | #define TSL2563_REG_DATA1LOW (0x0e) /* infrared sensor value, 2 bytes */ | |
71 | #define TSL2563_REG_DATA1HIGH (0x0f) | |
72 | ||
73 | #define TSL2563_CMD_POWER_ON (0x03) | |
74 | #define TSL2563_CMD_POWER_OFF (0x00) | |
75 | #define TSL2563_CTRL_POWER_MASK (0x03) | |
76 | ||
77 | #define TSL2563_TIMING_13MS (0x00) | |
78 | #define TSL2563_TIMING_100MS (0x01) | |
79 | #define TSL2563_TIMING_400MS (0x02) | |
80 | #define TSL2563_TIMING_MASK (0x03) | |
81 | #define TSL2563_TIMING_GAIN16 (0x10) | |
82 | #define TSL2563_TIMING_GAIN1 (0x00) | |
83 | ||
84 | #define TSL2563_INT_DISBLED (0x00) | |
85 | #define TSL2563_INT_LEVEL (0x10) | |
86 | #define TSL2563_INT_PERSIST(n) ((n) & 0x0F) | |
87 | ||
88 | struct tsl2563_gainlevel_coeff { | |
89 | u8 gaintime; | |
90 | u16 min; | |
91 | u16 max; | |
92 | }; | |
93 | ||
94 | static struct tsl2563_gainlevel_coeff tsl2563_gainlevel_table[] = { | |
95 | { | |
96 | .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN16, | |
97 | .min = 0, | |
98 | .max = 65534, | |
99 | }, { | |
100 | .gaintime = TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN1, | |
101 | .min = 2048, | |
102 | .max = 65534, | |
103 | }, { | |
104 | .gaintime = TSL2563_TIMING_100MS | TSL2563_TIMING_GAIN1, | |
105 | .min = 4095, | |
106 | .max = 37177, | |
107 | }, { | |
108 | .gaintime = TSL2563_TIMING_13MS | TSL2563_TIMING_GAIN1, | |
109 | .min = 3000, | |
110 | .max = 65535, | |
111 | }, | |
112 | }; | |
113 | ||
114 | struct tsl2563_chip { | |
115 | struct mutex lock; | |
116 | struct i2c_client *client; | |
117 | struct iio_dev *indio_dev; | |
118 | struct delayed_work poweroff_work; | |
119 | ||
120 | /* Remember state for suspend and resume functions */ | |
121 | pm_message_t state; | |
122 | ||
123 | struct tsl2563_gainlevel_coeff *gainlevel; | |
124 | ||
125 | /* Thresholds are in lux */ | |
126 | u16 low_thres; | |
127 | u16 high_thres; | |
128 | u8 intr; | |
129 | ||
130 | /* Calibration coefficients */ | |
131 | u32 calib0; | |
132 | u32 calib1; | |
133 | int cover_comp_gain; | |
134 | ||
135 | /* Cache current values, to be returned while suspended */ | |
136 | u32 data0; | |
137 | u32 data1; | |
138 | }; | |
139 | ||
140 | static int tsl2563_write(struct i2c_client *client, u8 reg, u8 value) | |
141 | { | |
142 | int ret; | |
143 | u8 buf[2]; | |
144 | ||
145 | buf[0] = TSL2563_CMD | reg; | |
146 | buf[1] = value; | |
147 | ||
148 | ret = i2c_master_send(client, buf, sizeof(buf)); | |
149 | return (ret == sizeof(buf)) ? 0 : ret; | |
150 | } | |
151 | ||
152 | static int tsl2563_read(struct i2c_client *client, u8 reg, void *buf, int len) | |
153 | { | |
154 | int ret; | |
155 | u8 cmd = TSL2563_CMD | reg; | |
156 | ||
157 | ret = i2c_master_send(client, &cmd, sizeof(cmd)); | |
158 | if (ret != sizeof(cmd)) | |
159 | return ret; | |
160 | ||
161 | return i2c_master_recv(client, buf, len); | |
162 | } | |
163 | ||
164 | static int tsl2563_set_power(struct tsl2563_chip *chip, int on) | |
165 | { | |
166 | struct i2c_client *client = chip->client; | |
167 | u8 cmd; | |
168 | ||
169 | cmd = on ? TSL2563_CMD_POWER_ON : TSL2563_CMD_POWER_OFF; | |
170 | return tsl2563_write(client, TSL2563_REG_CTRL, cmd); | |
171 | } | |
172 | ||
173 | /* | |
174 | * Return value is 0 for off, 1 for on, or a negative error | |
175 | * code if reading failed. | |
176 | */ | |
177 | static int tsl2563_get_power(struct tsl2563_chip *chip) | |
178 | { | |
179 | struct i2c_client *client = chip->client; | |
180 | int ret; | |
181 | u8 val; | |
182 | ||
183 | ret = tsl2563_read(client, TSL2563_REG_CTRL, &val, sizeof(val)); | |
184 | if (ret != sizeof(val)) | |
185 | return ret; | |
186 | ||
187 | return (val & TSL2563_CTRL_POWER_MASK) == TSL2563_CMD_POWER_ON; | |
188 | } | |
189 | ||
190 | static int tsl2563_configure(struct tsl2563_chip *chip) | |
191 | { | |
192 | struct i2c_client *client = chip->client; | |
193 | int ret; | |
194 | ||
195 | ret = tsl2563_write(client, TSL2563_REG_TIMING, | |
196 | chip->gainlevel->gaintime); | |
197 | if (ret) | |
198 | goto out; | |
199 | ||
200 | ret = tsl2563_write(client, TSL2563_REG_INT, chip->intr); | |
201 | ||
202 | out: | |
203 | return ret; | |
204 | } | |
205 | ||
206 | static void tsl2563_poweroff_work(struct work_struct *work) | |
207 | { | |
208 | struct tsl2563_chip *chip = | |
209 | container_of(work, struct tsl2563_chip, poweroff_work.work); | |
210 | tsl2563_set_power(chip, 0); | |
211 | } | |
212 | ||
213 | static int tsl2563_detect(struct tsl2563_chip *chip) | |
214 | { | |
215 | int ret; | |
216 | ||
217 | ret = tsl2563_set_power(chip, 1); | |
218 | if (ret) | |
219 | return ret; | |
220 | ||
221 | ret = tsl2563_get_power(chip); | |
222 | if (ret < 0) | |
223 | return ret; | |
224 | ||
225 | return ret ? 0 : -ENODEV; | |
226 | } | |
227 | ||
228 | static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id) | |
229 | { | |
230 | struct i2c_client *client = chip->client; | |
231 | int ret; | |
232 | ||
233 | ret = tsl2563_read(client, TSL2563_REG_ID, id, sizeof(*id)); | |
234 | if (ret != sizeof(*id)) | |
235 | return ret; | |
236 | ||
237 | return 0; | |
238 | } | |
239 | ||
240 | /* | |
241 | * "Normalized" ADC value is one obtained with 400ms of integration time and | |
242 | * 16x gain. This function returns the number of bits of shift needed to | |
243 | * convert between normalized values and HW values obtained using given | |
244 | * timing and gain settings. | |
245 | */ | |
246 | static int adc_shiftbits(u8 timing) | |
247 | { | |
248 | int shift = 0; | |
249 | ||
250 | switch (timing & TSL2563_TIMING_MASK) { | |
251 | case TSL2563_TIMING_13MS: | |
252 | shift += 5; | |
253 | break; | |
254 | case TSL2563_TIMING_100MS: | |
255 | shift += 2; | |
256 | break; | |
257 | case TSL2563_TIMING_400MS: | |
258 | /* no-op */ | |
259 | break; | |
260 | } | |
261 | ||
262 | if (!(timing & TSL2563_TIMING_GAIN16)) | |
263 | shift += 4; | |
264 | ||
265 | return shift; | |
266 | } | |
267 | ||
268 | /* Convert a HW ADC value to normalized scale. */ | |
269 | static u32 normalize_adc(u16 adc, u8 timing) | |
270 | { | |
271 | return adc << adc_shiftbits(timing); | |
272 | } | |
273 | ||
274 | static void tsl2563_wait_adc(struct tsl2563_chip *chip) | |
275 | { | |
276 | unsigned int delay; | |
277 | ||
278 | switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) { | |
279 | case TSL2563_TIMING_13MS: | |
280 | delay = 14; | |
281 | break; | |
282 | case TSL2563_TIMING_100MS: | |
283 | delay = 101; | |
284 | break; | |
285 | default: | |
286 | delay = 402; | |
287 | } | |
288 | /* | |
289 | * TODO: Make sure that we wait at least required delay but why we | |
290 | * have to extend it one tick more? | |
291 | */ | |
292 | schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2); | |
293 | } | |
294 | ||
295 | static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc) | |
296 | { | |
297 | struct i2c_client *client = chip->client; | |
298 | ||
299 | if (adc > chip->gainlevel->max || adc < chip->gainlevel->min) { | |
300 | ||
301 | (adc > chip->gainlevel->max) ? | |
302 | chip->gainlevel++ : chip->gainlevel--; | |
303 | ||
304 | tsl2563_write(client, TSL2563_REG_TIMING, | |
305 | chip->gainlevel->gaintime); | |
306 | ||
307 | tsl2563_wait_adc(chip); | |
308 | tsl2563_wait_adc(chip); | |
309 | ||
310 | return 1; | |
311 | } else | |
312 | return 0; | |
313 | } | |
314 | ||
315 | static int tsl2563_get_adc(struct tsl2563_chip *chip) | |
316 | { | |
317 | struct i2c_client *client = chip->client; | |
318 | u8 buf0[2], buf1[2]; | |
319 | u16 adc0, adc1; | |
320 | int retry = 1; | |
321 | int ret = 0; | |
322 | ||
323 | if (chip->state.event != PM_EVENT_ON) | |
324 | goto out; | |
325 | ||
326 | cancel_delayed_work(&chip->poweroff_work); | |
327 | ||
328 | if (!tsl2563_get_power(chip)) { | |
329 | ret = tsl2563_set_power(chip, 1); | |
330 | if (ret) | |
331 | goto out; | |
332 | ret = tsl2563_configure(chip); | |
333 | if (ret) | |
334 | goto out; | |
335 | tsl2563_wait_adc(chip); | |
336 | } | |
337 | ||
338 | while (retry) { | |
339 | ret = tsl2563_read(client, | |
340 | TSL2563_REG_DATA0LOW | TSL2563_CLEARINT, | |
341 | buf0, sizeof(buf0)); | |
342 | if (ret != sizeof(buf0)) | |
343 | goto out; | |
344 | ||
345 | ret = tsl2563_read(client, TSL2563_REG_DATA1LOW, | |
346 | buf1, sizeof(buf1)); | |
347 | if (ret != sizeof(buf1)) | |
348 | goto out; | |
349 | ||
350 | adc0 = (buf0[1] << 8) + buf0[0]; | |
351 | adc1 = (buf1[1] << 8) + buf1[0]; | |
352 | ||
353 | retry = tsl2563_adjust_gainlevel(chip, adc0); | |
354 | } | |
355 | ||
356 | chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime); | |
357 | chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime); | |
358 | ||
359 | schedule_delayed_work(&chip->poweroff_work, 5 * HZ); | |
360 | ||
361 | ret = 0; | |
362 | out: | |
363 | return ret; | |
364 | } | |
365 | ||
366 | static inline int calib_to_sysfs(u32 calib) | |
367 | { | |
368 | return (int) (((calib * CALIB_BASE_SYSFS) + | |
369 | CALIB_FRAC_HALF) >> CALIB_FRAC_BITS); | |
370 | } | |
371 | ||
372 | static inline u32 calib_from_sysfs(int value) | |
373 | { | |
374 | return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS; | |
375 | } | |
376 | ||
377 | /* | |
378 | * Conversions between lux and ADC values. | |
379 | * | |
380 | * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are | |
381 | * appropriate constants. Different constants are needed for different | |
382 | * kinds of light, determined by the ratio adc1/adc0 (basically the ratio | |
383 | * of the intensities in infrared and visible wavelengths). lux_table below | |
384 | * lists the upper threshold of the adc1/adc0 ratio and the corresponding | |
385 | * constants. | |
386 | */ | |
387 | ||
388 | struct tsl2563_lux_coeff { | |
389 | unsigned long ch_ratio; | |
390 | unsigned long ch0_coeff; | |
391 | unsigned long ch1_coeff; | |
392 | }; | |
393 | ||
394 | static const struct tsl2563_lux_coeff lux_table[] = { | |
395 | { | |
396 | .ch_ratio = FRAC10K(1300), | |
397 | .ch0_coeff = FRAC10K(315), | |
398 | .ch1_coeff = FRAC10K(262), | |
399 | }, { | |
400 | .ch_ratio = FRAC10K(2600), | |
401 | .ch0_coeff = FRAC10K(337), | |
402 | .ch1_coeff = FRAC10K(430), | |
403 | }, { | |
404 | .ch_ratio = FRAC10K(3900), | |
405 | .ch0_coeff = FRAC10K(363), | |
406 | .ch1_coeff = FRAC10K(529), | |
407 | }, { | |
408 | .ch_ratio = FRAC10K(5200), | |
409 | .ch0_coeff = FRAC10K(392), | |
410 | .ch1_coeff = FRAC10K(605), | |
411 | }, { | |
412 | .ch_ratio = FRAC10K(6500), | |
413 | .ch0_coeff = FRAC10K(229), | |
414 | .ch1_coeff = FRAC10K(291), | |
415 | }, { | |
416 | .ch_ratio = FRAC10K(8000), | |
417 | .ch0_coeff = FRAC10K(157), | |
418 | .ch1_coeff = FRAC10K(180), | |
419 | }, { | |
420 | .ch_ratio = FRAC10K(13000), | |
421 | .ch0_coeff = FRAC10K(34), | |
422 | .ch1_coeff = FRAC10K(26), | |
423 | }, { | |
424 | .ch_ratio = ULONG_MAX, | |
425 | .ch0_coeff = 0, | |
426 | .ch1_coeff = 0, | |
427 | }, | |
428 | }; | |
429 | ||
430 | /* | |
431 | * Convert normalized, scaled ADC values to lux. | |
432 | */ | |
433 | static unsigned int adc_to_lux(u32 adc0, u32 adc1) | |
434 | { | |
435 | const struct tsl2563_lux_coeff *lp = lux_table; | |
436 | unsigned long ratio, lux, ch0 = adc0, ch1 = adc1; | |
437 | ||
438 | ratio = ch0 ? ((ch1 << ADC_FRAC_BITS) / ch0) : ULONG_MAX; | |
439 | ||
440 | while (lp->ch_ratio < ratio) | |
441 | lp++; | |
442 | ||
443 | lux = ch0 * lp->ch0_coeff - ch1 * lp->ch1_coeff; | |
444 | ||
445 | return (unsigned int) (lux >> ADC_FRAC_BITS); | |
446 | } | |
447 | ||
448 | /*--------------------------------------------------------------*/ | |
449 | /* Sysfs interface */ | |
450 | /*--------------------------------------------------------------*/ | |
451 | ||
452 | static ssize_t tsl2563_adc0_show(struct device *dev, | |
453 | struct device_attribute *attr, char *buf) | |
454 | { | |
455 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
456 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
457 | int ret; | |
458 | ||
459 | mutex_lock(&chip->lock); | |
460 | ||
461 | ret = tsl2563_get_adc(chip); | |
462 | if (ret) | |
463 | goto out; | |
464 | ||
465 | ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data0); | |
466 | out: | |
467 | mutex_unlock(&chip->lock); | |
468 | return ret; | |
469 | } | |
470 | ||
471 | static ssize_t tsl2563_adc1_show(struct device *dev, | |
472 | struct device_attribute *attr, char *buf) | |
473 | { | |
474 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
475 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
476 | int ret; | |
477 | ||
478 | mutex_lock(&chip->lock); | |
479 | ||
480 | ret = tsl2563_get_adc(chip); | |
481 | if (ret) | |
482 | goto out; | |
483 | ||
484 | ret = snprintf(buf, PAGE_SIZE, "%d\n", chip->data1); | |
485 | out: | |
486 | mutex_unlock(&chip->lock); | |
487 | return ret; | |
488 | } | |
489 | ||
490 | /* Apply calibration coefficient to ADC count. */ | |
491 | static u32 calib_adc(u32 adc, u32 calib) | |
492 | { | |
493 | unsigned long scaled = adc; | |
494 | ||
495 | scaled *= calib; | |
496 | scaled >>= CALIB_FRAC_BITS; | |
497 | ||
498 | return (u32) scaled; | |
499 | } | |
500 | ||
501 | static ssize_t tsl2563_lux_show(struct device *dev, | |
502 | struct device_attribute *attr, char *buf) | |
503 | { | |
504 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
505 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
506 | u32 calib0, calib1; | |
507 | int ret; | |
508 | ||
509 | mutex_lock(&chip->lock); | |
510 | ||
511 | ret = tsl2563_get_adc(chip); | |
512 | if (ret) | |
513 | goto out; | |
514 | ||
515 | calib0 = calib_adc(chip->data0, chip->calib0) * chip->cover_comp_gain; | |
516 | calib1 = calib_adc(chip->data1, chip->calib1) * chip->cover_comp_gain; | |
517 | ||
518 | ret = snprintf(buf, PAGE_SIZE, "%d\n", adc_to_lux(calib0, calib1)); | |
519 | ||
520 | out: | |
521 | mutex_unlock(&chip->lock); | |
522 | return ret; | |
523 | } | |
524 | ||
525 | static ssize_t format_calib(char *buf, int len, u32 calib) | |
526 | { | |
527 | return snprintf(buf, PAGE_SIZE, "%d\n", calib_to_sysfs(calib)); | |
528 | } | |
529 | ||
530 | static ssize_t tsl2563_calib0_show(struct device *dev, | |
531 | struct device_attribute *attr, char *buf) | |
532 | { | |
533 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
534 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
535 | int ret; | |
536 | ||
537 | mutex_lock(&chip->lock); | |
538 | ret = format_calib(buf, PAGE_SIZE, chip->calib0); | |
539 | mutex_unlock(&chip->lock); | |
540 | return ret; | |
541 | } | |
542 | ||
543 | static ssize_t tsl2563_calib1_show(struct device *dev, | |
544 | struct device_attribute *attr, char *buf) | |
545 | { | |
546 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
547 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
548 | int ret; | |
549 | ||
550 | mutex_lock(&chip->lock); | |
551 | ret = format_calib(buf, PAGE_SIZE, chip->calib1); | |
552 | mutex_unlock(&chip->lock); | |
553 | return ret; | |
554 | } | |
555 | ||
556 | static int do_calib_store(struct device *dev, const char *buf, size_t len, | |
557 | int ch) | |
558 | { | |
559 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
560 | struct tsl2563_chip *chip = indio_dev->dev_data; | |
561 | int value; | |
562 | u32 calib; | |
563 | ||
564 | if (1 != sscanf(buf, "%d", &value)) | |
565 | return -EINVAL; | |
566 | ||
567 | calib = calib_from_sysfs(value); | |
568 | ||
569 | if (ch) | |
570 | chip->calib1 = calib; | |
571 | else | |
572 | chip->calib0 = calib; | |
573 | ||
574 | return len; | |
575 | } | |
576 | ||
577 | static ssize_t tsl2563_calib0_store(struct device *dev, | |
578 | struct device_attribute *attr, | |
579 | const char *buf, size_t len) | |
580 | { | |
581 | return do_calib_store(dev, buf, len, 0); | |
582 | } | |
583 | ||
584 | static ssize_t tsl2563_calib1_store(struct device *dev, | |
585 | struct device_attribute *attr, | |
586 | const char *buf, size_t len) | |
587 | { | |
588 | return do_calib_store(dev, buf, len, 1); | |
589 | } | |
590 | ||
591 | /* AmitXXXX: Convert to IIO_DEV_ATTR_LIGHT* as in tsl2561 | |
592 | * once I understand what they mean */ | |
593 | static DEVICE_ATTR(adc0, S_IRUGO, tsl2563_adc0_show, NULL); | |
594 | static DEVICE_ATTR(adc1, S_IRUGO, tsl2563_adc1_show, NULL); | |
595 | static DEVICE_ATTR(lux, S_IRUGO, tsl2563_lux_show, NULL); | |
596 | static DEVICE_ATTR(calib0, S_IRUGO | S_IWUSR, | |
597 | tsl2563_calib0_show, tsl2563_calib0_store); | |
598 | static DEVICE_ATTR(calib1, S_IRUGO | S_IWUSR, | |
599 | tsl2563_calib1_show, tsl2563_calib1_store); | |
600 | ||
601 | static struct attribute *tsl2563_attributes[] = { | |
602 | &dev_attr_adc0.attr, | |
603 | &dev_attr_adc1.attr, | |
604 | &dev_attr_lux.attr, | |
605 | &dev_attr_calib0.attr, | |
606 | &dev_attr_calib1.attr, | |
607 | NULL | |
608 | }; | |
609 | ||
610 | static const struct attribute_group tsl2563_group = { | |
611 | .attrs = tsl2563_attributes, | |
612 | }; | |
613 | ||
614 | /*--------------------------------------------------------------*/ | |
615 | /* Probe, Attach, Remove */ | |
616 | /*--------------------------------------------------------------*/ | |
617 | static struct i2c_driver tsl2563_i2c_driver; | |
618 | ||
619 | static int __devinit tsl2563_probe(struct i2c_client *client, | |
620 | const struct i2c_device_id *device_id) | |
621 | { | |
622 | struct tsl2563_chip *chip; | |
623 | struct tsl2563_platform_data *pdata = client->dev.platform_data; | |
624 | int err = 0; | |
625 | int ret; | |
626 | u8 id; | |
627 | ||
628 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | |
629 | if (!chip) | |
630 | return -ENOMEM; | |
631 | ||
632 | i2c_set_clientdata(client, chip); | |
633 | chip->client = client; | |
634 | ||
635 | err = tsl2563_detect(chip); | |
636 | if (err) { | |
637 | dev_err(&client->dev, "device not found, error %d \n", -err); | |
638 | goto fail1; | |
639 | } | |
640 | ||
641 | err = tsl2563_read_id(chip, &id); | |
642 | if (err) | |
643 | goto fail1; | |
644 | ||
645 | mutex_init(&chip->lock); | |
646 | ||
647 | /* Default values used until userspace says otherwise */ | |
648 | chip->low_thres = 0x0; | |
649 | chip->high_thres = 0xffff; | |
650 | chip->gainlevel = tsl2563_gainlevel_table; | |
651 | chip->intr = TSL2563_INT_PERSIST(4); | |
652 | chip->calib0 = calib_from_sysfs(CALIB_BASE_SYSFS); | |
653 | chip->calib1 = calib_from_sysfs(CALIB_BASE_SYSFS); | |
654 | ||
655 | if (pdata) | |
656 | chip->cover_comp_gain = pdata->cover_comp_gain; | |
657 | else | |
658 | chip->cover_comp_gain = 1; | |
659 | ||
660 | dev_info(&client->dev, "model %d, rev. %d\n", id >> 4, id & 0x0f); | |
661 | ||
662 | chip->indio_dev = iio_allocate_device(); | |
663 | if (!chip->indio_dev) | |
664 | goto fail1; | |
665 | chip->indio_dev->attrs = &tsl2563_group; | |
666 | chip->indio_dev->dev.parent = &client->dev; | |
667 | chip->indio_dev->dev_data = (void *)(chip); | |
668 | chip->indio_dev->driver_module = THIS_MODULE; | |
669 | chip->indio_dev->modes = INDIO_DIRECT_MODE; | |
670 | ret = iio_device_register(chip->indio_dev); | |
671 | if (ret) | |
672 | goto fail1; | |
673 | ||
674 | err = tsl2563_configure(chip); | |
675 | if (err) | |
676 | goto fail2; | |
677 | ||
678 | INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work); | |
679 | schedule_delayed_work(&chip->poweroff_work, 5 * HZ); | |
680 | ||
681 | return 0; | |
682 | fail2: | |
683 | iio_device_unregister(chip->indio_dev); | |
684 | fail1: | |
685 | kfree(chip); | |
686 | return err; | |
687 | } | |
688 | ||
689 | static int tsl2563_remove(struct i2c_client *client) | |
690 | { | |
691 | struct tsl2563_chip *chip = i2c_get_clientdata(client); | |
692 | ||
693 | iio_device_unregister(chip->indio_dev); | |
694 | ||
695 | kfree(chip); | |
696 | return 0; | |
697 | } | |
698 | ||
699 | static int tsl2563_suspend(struct i2c_client *client, pm_message_t state) | |
700 | { | |
701 | struct tsl2563_chip *chip = i2c_get_clientdata(client); | |
702 | int ret; | |
703 | ||
704 | mutex_lock(&chip->lock); | |
705 | ||
706 | ret = tsl2563_set_power(chip, 0); | |
707 | if (ret) | |
708 | goto out; | |
709 | ||
710 | chip->state = state; | |
711 | ||
712 | out: | |
713 | mutex_unlock(&chip->lock); | |
714 | return ret; | |
715 | } | |
716 | ||
717 | static int tsl2563_resume(struct i2c_client *client) | |
718 | { | |
719 | struct tsl2563_chip *chip = i2c_get_clientdata(client); | |
720 | int ret; | |
721 | ||
722 | mutex_lock(&chip->lock); | |
723 | ||
724 | ret = tsl2563_set_power(chip, 1); | |
725 | if (ret) | |
726 | goto out; | |
727 | ||
728 | ret = tsl2563_configure(chip); | |
729 | if (ret) | |
730 | goto out; | |
731 | ||
732 | chip->state.event = PM_EVENT_ON; | |
733 | ||
734 | out: | |
735 | mutex_unlock(&chip->lock); | |
736 | return ret; | |
737 | } | |
738 | ||
739 | static const struct i2c_device_id tsl2563_id[] = { | |
dbd5d239 JC |
740 | { "tsl2560", 0 }, |
741 | { "tsl2561", 1 }, | |
742 | { "tsl2562", 2 }, | |
743 | { "tsl2563", 3 }, | |
744 | {} | |
ee1f1fa4 AK |
745 | }; |
746 | MODULE_DEVICE_TABLE(i2c, tsl2563_id); | |
747 | ||
748 | static struct i2c_driver tsl2563_i2c_driver = { | |
749 | .driver = { | |
dbd5d239 | 750 | .name = "tsl2563", |
ee1f1fa4 AK |
751 | }, |
752 | .suspend = tsl2563_suspend, | |
753 | .resume = tsl2563_resume, | |
754 | .probe = tsl2563_probe, | |
755 | .remove = __devexit_p(tsl2563_remove), | |
756 | .id_table = tsl2563_id, | |
757 | }; | |
758 | ||
759 | static int __init tsl2563_init(void) | |
760 | { | |
761 | return i2c_add_driver(&tsl2563_i2c_driver); | |
762 | } | |
763 | ||
764 | static void __exit tsl2563_exit(void) | |
765 | { | |
766 | i2c_del_driver(&tsl2563_i2c_driver); | |
767 | } | |
768 | ||
769 | MODULE_AUTHOR("Nokia Corporation"); | |
770 | MODULE_DESCRIPTION("tsl2563 light sensor driver"); | |
771 | MODULE_LICENSE("GPL"); | |
772 | ||
773 | module_init(tsl2563_init); | |
774 | module_exit(tsl2563_exit); |