Blame view

drivers/iio/light/tsl2563.c 21 KB
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
1
  /*
9c2251dd4   Jonathan Cameron   iio:light:tsl2563...
2
   * drivers/iio/light/tsl2563.c
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   *
   * Copyright (C) 2008 Nokia Corporation
   *
   * Written by Timo O. Karjalainen <timo.o.karjalainen@nokia.com>
   * Contact: Amit Kucheria <amit.kucheria@verdurent.com>
   *
   * Converted to IIO driver
   * Amit Kucheria <amit.kucheria@verdurent.com>
   *
   * This program is free software; you can redistribute it and/or
   * modify it under the terms of the GNU General Public License
   * version 2 as published by the Free Software Foundation.
   *
   * This program is distributed in the hope that it will be useful, but
   * WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   * General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   * 02110-1301 USA
   */
  
  #include <linux/module.h>
  #include <linux/i2c.h>
  #include <linux/interrupt.h>
388be4883   Jonathan Cameron   staging:iio: tsl2...
30
  #include <linux/irq.h>
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
31
32
33
  #include <linux/sched.h>
  #include <linux/mutex.h>
  #include <linux/delay.h>
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
34
  #include <linux/pm.h>
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
35
  #include <linux/err.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
36
  #include <linux/slab.h>
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
37

06458e277   Jonathan Cameron   IIO: Move core he...
38
39
40
  #include <linux/iio/iio.h>
  #include <linux/iio/sysfs.h>
  #include <linux/iio/events.h>
9c2251dd4   Jonathan Cameron   iio:light:tsl2563...
41
  #include <linux/platform_data/tsl2563.h>
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
42

ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
43
  /* Use this many bits for fraction part. */
5ade7633a   Jonathan Cameron   staging:iio:light...
44
  #define ADC_FRAC_BITS		14
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
45
46
47
48
49
  
  /* Given number of 1/10000's in ADC_FRAC_BITS precision. */
  #define FRAC10K(f)		(((f) * (1L << (ADC_FRAC_BITS))) / (10000))
  
  /* Bits used for fraction in calibration coefficients.*/
5ade7633a   Jonathan Cameron   staging:iio:light...
50
  #define CALIB_FRAC_BITS		10
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
51
52
53
54
55
  /* 0.5 in CALIB_FRAC_BITS precision */
  #define CALIB_FRAC_HALF		(1 << (CALIB_FRAC_BITS - 1))
  /* Make a fraction from a number n that was multiplied with b. */
  #define CALIB_FRAC(n, b)	(((n) << CALIB_FRAC_BITS) / (b))
  /* Decimal 10^(digits in sysfs presentation) */
5ade7633a   Jonathan Cameron   staging:iio:light...
56
  #define CALIB_BASE_SYSFS	1000
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
57

5ade7633a   Jonathan Cameron   staging:iio:light...
58
59
  #define TSL2563_CMD		0x80
  #define TSL2563_CLEARINT	0x40
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
60

5ade7633a   Jonathan Cameron   staging:iio:light...
61
62
63
64
65
66
67
68
69
70
71
72
  #define TSL2563_REG_CTRL	0x00
  #define TSL2563_REG_TIMING	0x01
  #define TSL2563_REG_LOWLOW	0x02 /* data0 low threshold, 2 bytes */
  #define TSL2563_REG_LOWHIGH	0x03
  #define TSL2563_REG_HIGHLOW	0x04 /* data0 high threshold, 2 bytes */
  #define TSL2563_REG_HIGHHIGH	0x05
  #define TSL2563_REG_INT		0x06
  #define TSL2563_REG_ID		0x0a
  #define TSL2563_REG_DATA0LOW	0x0c /* broadband sensor value, 2 bytes */
  #define TSL2563_REG_DATA0HIGH	0x0d
  #define TSL2563_REG_DATA1LOW	0x0e /* infrared sensor value, 2 bytes */
  #define TSL2563_REG_DATA1HIGH	0x0f
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
73

5ade7633a   Jonathan Cameron   staging:iio:light...
74
75
76
  #define TSL2563_CMD_POWER_ON	0x03
  #define TSL2563_CMD_POWER_OFF	0x00
  #define TSL2563_CTRL_POWER_MASK	0x03
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
77

5ade7633a   Jonathan Cameron   staging:iio:light...
78
79
80
81
82
83
  #define TSL2563_TIMING_13MS	0x00
  #define TSL2563_TIMING_100MS	0x01
  #define TSL2563_TIMING_400MS	0x02
  #define TSL2563_TIMING_MASK	0x03
  #define TSL2563_TIMING_GAIN16	0x10
  #define TSL2563_TIMING_GAIN1	0x00
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
84

5ade7633a   Jonathan Cameron   staging:iio:light...
85
86
  #define TSL2563_INT_DISBLED	0x00
  #define TSL2563_INT_LEVEL	0x10
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
87
88
89
90
91
92
93
  #define TSL2563_INT_PERSIST(n)	((n) & 0x0F)
  
  struct tsl2563_gainlevel_coeff {
  	u8 gaintime;
  	u16 min;
  	u16 max;
  };
1ff7e1d84   Jonathan Cameron   staging:iio:light...
94
  static const struct tsl2563_gainlevel_coeff tsl2563_gainlevel_table[] = {
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  	{
  		.gaintime	= TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN16,
  		.min		= 0,
  		.max		= 65534,
  	}, {
  		.gaintime	= TSL2563_TIMING_400MS | TSL2563_TIMING_GAIN1,
  		.min		= 2048,
  		.max		= 65534,
  	}, {
  		.gaintime	= TSL2563_TIMING_100MS | TSL2563_TIMING_GAIN1,
  		.min		= 4095,
  		.max		= 37177,
  	}, {
  		.gaintime	= TSL2563_TIMING_13MS | TSL2563_TIMING_GAIN1,
  		.min		= 3000,
  		.max		= 65535,
  	},
  };
  
  struct tsl2563_chip {
  	struct mutex		lock;
  	struct i2c_client	*client;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
117
118
119
  	struct delayed_work	poweroff_work;
  
  	/* Remember state for suspend and resume functions */
01788c533   Lars-Peter Clausen   staging:iio: Use ...
120
  	bool suspended;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
121

1ff7e1d84   Jonathan Cameron   staging:iio:light...
122
  	struct tsl2563_gainlevel_coeff const *gainlevel;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
123

ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
124
125
126
  	u16			low_thres;
  	u16			high_thres;
  	u8			intr;
388be4883   Jonathan Cameron   staging:iio: tsl2...
127
  	bool			int_enabled;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
128
129
130
131
132
133
134
135
136
137
  
  	/* Calibration coefficients */
  	u32			calib0;
  	u32			calib1;
  	int			cover_comp_gain;
  
  	/* Cache current values, to be returned while suspended */
  	u32			data0;
  	u32			data1;
  };
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
138
139
140
141
142
143
  static int tsl2563_set_power(struct tsl2563_chip *chip, int on)
  {
  	struct i2c_client *client = chip->client;
  	u8 cmd;
  
  	cmd = on ? TSL2563_CMD_POWER_ON : TSL2563_CMD_POWER_OFF;
d9b42c01a   Bryan Freed   iio: light sensor...
144
145
  	return i2c_smbus_write_byte_data(client,
  					 TSL2563_CMD | TSL2563_REG_CTRL, cmd);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
146
147
148
149
150
151
152
153
154
155
  }
  
  /*
   * Return value is 0 for off, 1 for on, or a negative error
   * code if reading failed.
   */
  static int tsl2563_get_power(struct tsl2563_chip *chip)
  {
  	struct i2c_client *client = chip->client;
  	int ret;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
156

d9b42c01a   Bryan Freed   iio: light sensor...
157
158
  	ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_CTRL);
  	if (ret < 0)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
159
  		return ret;
d9b42c01a   Bryan Freed   iio: light sensor...
160
  	return (ret & TSL2563_CTRL_POWER_MASK) == TSL2563_CMD_POWER_ON;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
161
162
163
164
  }
  
  static int tsl2563_configure(struct tsl2563_chip *chip)
  {
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
165
  	int ret;
d9b42c01a   Bryan Freed   iio: light sensor...
166
167
  	ret = i2c_smbus_write_byte_data(chip->client,
  			TSL2563_CMD | TSL2563_REG_TIMING,
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
168
169
  			chip->gainlevel->gaintime);
  	if (ret)
388be4883   Jonathan Cameron   staging:iio: tsl2...
170
  		goto error_ret;
d9b42c01a   Bryan Freed   iio: light sensor...
171
172
  	ret = i2c_smbus_write_byte_data(chip->client,
  			TSL2563_CMD | TSL2563_REG_HIGHLOW,
388be4883   Jonathan Cameron   staging:iio: tsl2...
173
174
175
  			chip->high_thres & 0xFF);
  	if (ret)
  		goto error_ret;
d9b42c01a   Bryan Freed   iio: light sensor...
176
177
  	ret = i2c_smbus_write_byte_data(chip->client,
  			TSL2563_CMD | TSL2563_REG_HIGHHIGH,
388be4883   Jonathan Cameron   staging:iio: tsl2...
178
179
180
  			(chip->high_thres >> 8) & 0xFF);
  	if (ret)
  		goto error_ret;
d9b42c01a   Bryan Freed   iio: light sensor...
181
182
  	ret = i2c_smbus_write_byte_data(chip->client,
  			TSL2563_CMD | TSL2563_REG_LOWLOW,
388be4883   Jonathan Cameron   staging:iio: tsl2...
183
184
185
  			chip->low_thres & 0xFF);
  	if (ret)
  		goto error_ret;
d9b42c01a   Bryan Freed   iio: light sensor...
186
187
  	ret = i2c_smbus_write_byte_data(chip->client,
  			TSL2563_CMD | TSL2563_REG_LOWHIGH,
388be4883   Jonathan Cameron   staging:iio: tsl2...
188
  			(chip->low_thres >> 8) & 0xFF);
a9e244f65   Jonathan Cameron   staging:iio:light...
189
190
191
192
  /*
   * Interrupt register is automatically written anyway if it is relevant
   * so is not here.
   */
388be4883   Jonathan Cameron   staging:iio: tsl2...
193
  error_ret:
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
  	return ret;
  }
  
  static void tsl2563_poweroff_work(struct work_struct *work)
  {
  	struct tsl2563_chip *chip =
  		container_of(work, struct tsl2563_chip, poweroff_work.work);
  	tsl2563_set_power(chip, 0);
  }
  
  static int tsl2563_detect(struct tsl2563_chip *chip)
  {
  	int ret;
  
  	ret = tsl2563_set_power(chip, 1);
  	if (ret)
  		return ret;
  
  	ret = tsl2563_get_power(chip);
  	if (ret < 0)
  		return ret;
  
  	return ret ? 0 : -ENODEV;
  }
  
  static int tsl2563_read_id(struct tsl2563_chip *chip, u8 *id)
  {
  	struct i2c_client *client = chip->client;
  	int ret;
d9b42c01a   Bryan Freed   iio: light sensor...
223
224
  	ret = i2c_smbus_read_byte_data(client, TSL2563_CMD | TSL2563_REG_ID);
  	if (ret < 0)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
225
  		return ret;
22dc09caf   Maxin B. John   staging:iio:light...
226
  	*id = ret;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
  	return 0;
  }
  
  /*
   * "Normalized" ADC value is one obtained with 400ms of integration time and
   * 16x gain. This function returns the number of bits of shift needed to
   * convert between normalized values and HW values obtained using given
   * timing and gain settings.
   */
  static int adc_shiftbits(u8 timing)
  {
  	int shift = 0;
  
  	switch (timing & TSL2563_TIMING_MASK) {
  	case TSL2563_TIMING_13MS:
  		shift += 5;
  		break;
  	case TSL2563_TIMING_100MS:
  		shift += 2;
  		break;
  	case TSL2563_TIMING_400MS:
  		/* no-op */
  		break;
  	}
  
  	if (!(timing & TSL2563_TIMING_GAIN16))
  		shift += 4;
  
  	return shift;
  }
  
  /* Convert a HW ADC value to normalized scale. */
  static u32 normalize_adc(u16 adc, u8 timing)
  {
  	return adc << adc_shiftbits(timing);
  }
  
  static void tsl2563_wait_adc(struct tsl2563_chip *chip)
  {
  	unsigned int delay;
  
  	switch (chip->gainlevel->gaintime & TSL2563_TIMING_MASK) {
  	case TSL2563_TIMING_13MS:
  		delay = 14;
  		break;
  	case TSL2563_TIMING_100MS:
  		delay = 101;
  		break;
  	default:
  		delay = 402;
  	}
  	/*
  	 * TODO: Make sure that we wait at least required delay but why we
  	 * have to extend it one tick more?
  	 */
  	schedule_timeout_interruptible(msecs_to_jiffies(delay) + 2);
  }
  
  static int tsl2563_adjust_gainlevel(struct tsl2563_chip *chip, u16 adc)
  {
  	struct i2c_client *client = chip->client;
  
  	if (adc > chip->gainlevel->max || adc < chip->gainlevel->min) {
  
  		(adc > chip->gainlevel->max) ?
  			chip->gainlevel++ : chip->gainlevel--;
d9b42c01a   Bryan Freed   iio: light sensor...
293
294
295
  		i2c_smbus_write_byte_data(client,
  					  TSL2563_CMD | TSL2563_REG_TIMING,
  					  chip->gainlevel->gaintime);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
296
297
298
299
300
301
302
303
304
305
306
307
  
  		tsl2563_wait_adc(chip);
  		tsl2563_wait_adc(chip);
  
  		return 1;
  	} else
  		return 0;
  }
  
  static int tsl2563_get_adc(struct tsl2563_chip *chip)
  {
  	struct i2c_client *client = chip->client;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
308
309
310
  	u16 adc0, adc1;
  	int retry = 1;
  	int ret = 0;
01788c533   Lars-Peter Clausen   staging:iio: Use ...
311
  	if (chip->suspended)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
312
  		goto out;
388be4883   Jonathan Cameron   staging:iio: tsl2...
313
314
315
316
317
318
319
320
321
322
323
324
  	if (!chip->int_enabled) {
  		cancel_delayed_work(&chip->poweroff_work);
  
  		if (!tsl2563_get_power(chip)) {
  			ret = tsl2563_set_power(chip, 1);
  			if (ret)
  				goto out;
  			ret = tsl2563_configure(chip);
  			if (ret)
  				goto out;
  			tsl2563_wait_adc(chip);
  		}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
325
326
327
  	}
  
  	while (retry) {
d9b42c01a   Bryan Freed   iio: light sensor...
328
329
330
  		ret = i2c_smbus_read_word_data(client,
  				TSL2563_CMD | TSL2563_REG_DATA0LOW);
  		if (ret < 0)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
331
  			goto out;
d9b42c01a   Bryan Freed   iio: light sensor...
332
  		adc0 = ret;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
333

d9b42c01a   Bryan Freed   iio: light sensor...
334
335
336
  		ret = i2c_smbus_read_word_data(client,
  				TSL2563_CMD | TSL2563_REG_DATA1LOW);
  		if (ret < 0)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
337
  			goto out;
d9b42c01a   Bryan Freed   iio: light sensor...
338
  		adc1 = ret;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
339
340
341
342
343
344
  
  		retry = tsl2563_adjust_gainlevel(chip, adc0);
  	}
  
  	chip->data0 = normalize_adc(adc0, chip->gainlevel->gaintime);
  	chip->data1 = normalize_adc(adc1, chip->gainlevel->gaintime);
388be4883   Jonathan Cameron   staging:iio: tsl2...
345
346
  	if (!chip->int_enabled)
  		schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  
  	ret = 0;
  out:
  	return ret;
  }
  
  static inline int calib_to_sysfs(u32 calib)
  {
  	return (int) (((calib * CALIB_BASE_SYSFS) +
  		       CALIB_FRAC_HALF) >> CALIB_FRAC_BITS);
  }
  
  static inline u32 calib_from_sysfs(int value)
  {
  	return (((u32) value) << CALIB_FRAC_BITS) / CALIB_BASE_SYSFS;
  }
  
  /*
   * Conversions between lux and ADC values.
   *
   * The basic formula is lux = c0 * adc0 - c1 * adc1, where c0 and c1 are
   * appropriate constants. Different constants are needed for different
   * kinds of light, determined by the ratio adc1/adc0 (basically the ratio
   * of the intensities in infrared and visible wavelengths). lux_table below
   * lists the upper threshold of the adc1/adc0 ratio and the corresponding
   * constants.
   */
  
  struct tsl2563_lux_coeff {
  	unsigned long ch_ratio;
  	unsigned long ch0_coeff;
  	unsigned long ch1_coeff;
  };
  
  static const struct tsl2563_lux_coeff lux_table[] = {
  	{
  		.ch_ratio	= FRAC10K(1300),
  		.ch0_coeff	= FRAC10K(315),
  		.ch1_coeff	= FRAC10K(262),
  	}, {
  		.ch_ratio	= FRAC10K(2600),
  		.ch0_coeff	= FRAC10K(337),
  		.ch1_coeff	= FRAC10K(430),
  	}, {
  		.ch_ratio	= FRAC10K(3900),
  		.ch0_coeff	= FRAC10K(363),
  		.ch1_coeff	= FRAC10K(529),
  	}, {
  		.ch_ratio	= FRAC10K(5200),
  		.ch0_coeff	= FRAC10K(392),
  		.ch1_coeff	= FRAC10K(605),
  	}, {
  		.ch_ratio	= FRAC10K(6500),
  		.ch0_coeff	= FRAC10K(229),
  		.ch1_coeff	= FRAC10K(291),
  	}, {
  		.ch_ratio	= FRAC10K(8000),
  		.ch0_coeff	= FRAC10K(157),
  		.ch1_coeff	= FRAC10K(180),
  	}, {
  		.ch_ratio	= FRAC10K(13000),
  		.ch0_coeff	= FRAC10K(34),
  		.ch1_coeff	= FRAC10K(26),
  	}, {
  		.ch_ratio	= ULONG_MAX,
  		.ch0_coeff	= 0,
  		.ch1_coeff	= 0,
  	},
  };
a9e244f65   Jonathan Cameron   staging:iio:light...
416
  /* Convert normalized, scaled ADC values to lux. */
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  static unsigned int adc_to_lux(u32 adc0, u32 adc1)
  {
  	const struct tsl2563_lux_coeff *lp = lux_table;
  	unsigned long ratio, lux, ch0 = adc0, ch1 = adc1;
  
  	ratio = ch0 ? ((ch1 << ADC_FRAC_BITS) / ch0) : ULONG_MAX;
  
  	while (lp->ch_ratio < ratio)
  		lp++;
  
  	lux = ch0 * lp->ch0_coeff - ch1 * lp->ch1_coeff;
  
  	return (unsigned int) (lux >> ADC_FRAC_BITS);
  }
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
431
432
433
434
435
436
437
438
439
440
  /* Apply calibration coefficient to ADC count. */
  static u32 calib_adc(u32 adc, u32 calib)
  {
  	unsigned long scaled = adc;
  
  	scaled *= calib;
  	scaled >>= CALIB_FRAC_BITS;
  
  	return (u32) scaled;
  }
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
441
442
443
444
445
  static int tsl2563_write_raw(struct iio_dev *indio_dev,
  			       struct iio_chan_spec const *chan,
  			       int val,
  			       int val2,
  			       long mask)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
446
  {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
447
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
448

3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
449
450
451
  	if (mask != IIO_CHAN_INFO_CALIBSCALE)
  		return -EINVAL;
  	if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
452
  		chip->calib0 = calib_from_sysfs(val);
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
453
  	else if (chan->channel2 == IIO_MOD_LIGHT_IR)
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
454
  		chip->calib1 = calib_from_sysfs(val);
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
455
456
  	else
  		return -EINVAL;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
457

cbcdf4dd4   Jonathan Cameron   staging:iio:light...
458
  	return 0;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
459
  }
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
460
461
462
463
  static int tsl2563_read_raw(struct iio_dev *indio_dev,
  			    struct iio_chan_spec const *chan,
  			    int *val,
  			    int *val2,
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
464
  			    long mask)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
465
  {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
466
467
468
  	int ret = -EINVAL;
  	u32 calib0, calib1;
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
469
470
  
  	mutex_lock(&chip->lock);
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
471
  	switch (mask) {
90354d003   Jonathan Cameron   staging:iio:light...
472
473
  	case IIO_CHAN_INFO_RAW:
  	case IIO_CHAN_INFO_PROCESSED:
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
  		switch (chan->type) {
  		case IIO_LIGHT:
  			ret = tsl2563_get_adc(chip);
  			if (ret)
  				goto error_ret;
  			calib0 = calib_adc(chip->data0, chip->calib0) *
  				chip->cover_comp_gain;
  			calib1 = calib_adc(chip->data1, chip->calib1) *
  				chip->cover_comp_gain;
  			*val = adc_to_lux(calib0, calib1);
  			ret = IIO_VAL_INT;
  			break;
  		case IIO_INTENSITY:
  			ret = tsl2563_get_adc(chip);
  			if (ret)
  				goto error_ret;
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
490
  			if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
491
492
493
494
495
496
497
498
  				*val = chip->data0;
  			else
  				*val = chip->data1;
  			ret = IIO_VAL_INT;
  			break;
  		default:
  			break;
  		}
388be4883   Jonathan Cameron   staging:iio: tsl2...
499
  		break;
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
500

c8a9f8056   Jonathan Cameron   staging:iio:treew...
501
  	case IIO_CHAN_INFO_CALIBSCALE:
3b5c1635d   Ivaylo Dimitrov   iio: tsl2563: Use...
502
  		if (chan->channel2 == IIO_MOD_LIGHT_BOTH)
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
503
504
505
506
  			*val = calib_to_sysfs(chip->calib0);
  		else
  			*val = calib_to_sysfs(chip->calib1);
  		ret = IIO_VAL_INT;
388be4883   Jonathan Cameron   staging:iio: tsl2...
507
508
  		break;
  	default:
97d35f281   Dan Carpenter   Staging: iio/ligh...
509
510
  		ret = -EINVAL;
  		goto error_ret;
388be4883   Jonathan Cameron   staging:iio: tsl2...
511
  	}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
512

cbcdf4dd4   Jonathan Cameron   staging:iio:light...
513
514
515
  error_ret:
  	mutex_unlock(&chip->lock);
  	return ret;
e9124afad   Jonathan Cameron   staging:iio:tsl25...
516
  }
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
517
518
519
520
521
522
523
524
525
526
527
528
529
  static const struct iio_event_spec tsl2563_events[] = {
  	{
  		.type = IIO_EV_TYPE_THRESH,
  		.dir = IIO_EV_DIR_RISING,
  		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
  				BIT(IIO_EV_INFO_ENABLE),
  	}, {
  		.type = IIO_EV_TYPE_THRESH,
  		.dir = IIO_EV_DIR_FALLING,
  		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
  				BIT(IIO_EV_INFO_ENABLE),
  	},
  };
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
530
  static const struct iio_chan_spec tsl2563_channels[] = {
799390611   Jonathan Cameron   staging:iio:light...
531
532
533
  	{
  		.type = IIO_LIGHT,
  		.indexed = 1,
d292ef8da   Jonathan Cameron   iio:light:tsl2563...
534
  		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
799390611   Jonathan Cameron   staging:iio:light...
535
536
537
538
539
  		.channel = 0,
  	}, {
  		.type = IIO_INTENSITY,
  		.modified = 1,
  		.channel2 = IIO_MOD_LIGHT_BOTH,
d292ef8da   Jonathan Cameron   iio:light:tsl2563...
540
541
  		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  		BIT(IIO_CHAN_INFO_CALIBSCALE),
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
542
543
  		.event_spec = tsl2563_events,
  		.num_event_specs = ARRAY_SIZE(tsl2563_events),
799390611   Jonathan Cameron   staging:iio:light...
544
545
546
  	}, {
  		.type = IIO_INTENSITY,
  		.modified = 1,
a7e3bd669   Jonathan Cameron   staging:iio:light...
547
  		.channel2 = IIO_MOD_LIGHT_IR,
d292ef8da   Jonathan Cameron   iio:light:tsl2563...
548
549
  		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
  		BIT(IIO_CHAN_INFO_CALIBSCALE),
799390611   Jonathan Cameron   staging:iio:light...
550
  	}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
551
  };
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
552
  static int tsl2563_read_thresh(struct iio_dev *indio_dev,
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
553
554
555
  	const struct iio_chan_spec *chan, enum iio_event_type type,
  	enum iio_event_direction dir, enum iio_event_info info, int *val,
  	int *val2)
388be4883   Jonathan Cameron   staging:iio: tsl2...
556
  {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
557
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
558
  	switch (dir) {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
559
560
  	case IIO_EV_DIR_RISING:
  		*val = chip->high_thres;
388be4883   Jonathan Cameron   staging:iio: tsl2...
561
  		break;
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
562
563
  	case IIO_EV_DIR_FALLING:
  		*val = chip->low_thres;
388be4883   Jonathan Cameron   staging:iio: tsl2...
564
  		break;
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
565
566
  	default:
  		return -EINVAL;
388be4883   Jonathan Cameron   staging:iio: tsl2...
567
  	}
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
568

6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
569
  	return IIO_VAL_INT;
388be4883   Jonathan Cameron   staging:iio: tsl2...
570
  }
15fbc198e   Dan Carpenter   Staging: iio/ligh...
571
  static int tsl2563_write_thresh(struct iio_dev *indio_dev,
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
572
573
574
  	const struct iio_chan_spec *chan, enum iio_event_type type,
  	enum iio_event_direction dir, enum iio_event_info info, int val,
  	int val2)
388be4883   Jonathan Cameron   staging:iio: tsl2...
575
  {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
576
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
388be4883   Jonathan Cameron   staging:iio: tsl2...
577
  	int ret;
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
578
  	u8 address;
388be4883   Jonathan Cameron   staging:iio: tsl2...
579

6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
580
  	if (dir == IIO_EV_DIR_RISING)
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
581
582
583
  		address = TSL2563_REG_HIGHLOW;
  	else
  		address = TSL2563_REG_LOWLOW;
388be4883   Jonathan Cameron   staging:iio: tsl2...
584
  	mutex_lock(&chip->lock);
d9b42c01a   Bryan Freed   iio: light sensor...
585
586
  	ret = i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | address,
  					val & 0xFF);
388be4883   Jonathan Cameron   staging:iio: tsl2...
587
588
  	if (ret)
  		goto error_ret;
d9b42c01a   Bryan Freed   iio: light sensor...
589
590
591
  	ret = i2c_smbus_write_byte_data(chip->client,
  					TSL2563_CMD | (address + 1),
  					(val >> 8) & 0xFF);
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
592
  	if (dir == IIO_EV_DIR_RISING)
388be4883   Jonathan Cameron   staging:iio: tsl2...
593
  		chip->high_thres = val;
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
594
  	else
388be4883   Jonathan Cameron   staging:iio: tsl2...
595
  		chip->low_thres = val;
388be4883   Jonathan Cameron   staging:iio: tsl2...
596
597
598
  
  error_ret:
  	mutex_unlock(&chip->lock);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
599
  	return ret;
388be4883   Jonathan Cameron   staging:iio: tsl2...
600
  }
bdab10017   Jonathan Cameron   staging:iio:light...
601
  static irqreturn_t tsl2563_event_handler(int irq, void *private)
388be4883   Jonathan Cameron   staging:iio: tsl2...
602
  {
bdab10017   Jonathan Cameron   staging:iio:light...
603
  	struct iio_dev *dev_info = private;
33789dce5   Jonathan Cameron   staging:iio:tsl25...
604
  	struct tsl2563_chip *chip = iio_priv(dev_info);
388be4883   Jonathan Cameron   staging:iio: tsl2...
605

5aa961889   Jonathan Cameron   staging:iio: remo...
606
  	iio_push_event(dev_info,
c4b14d99b   Jonathan Cameron   staging:iio:event...
607
  		       IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
da1d8b68a   Jonathan Cameron   staging: iio: tsl...
608
609
610
  					    0,
  					    IIO_EV_TYPE_THRESH,
  					    IIO_EV_DIR_EITHER),
bdab10017   Jonathan Cameron   staging:iio:light...
611
  		       iio_get_time_ns());
388be4883   Jonathan Cameron   staging:iio: tsl2...
612

388be4883   Jonathan Cameron   staging:iio: tsl2...
613
  	/* clear the interrupt and push the event */
d9b42c01a   Bryan Freed   iio: light sensor...
614
  	i2c_smbus_write_byte(chip->client, TSL2563_CMD | TSL2563_CLEARINT);
bdab10017   Jonathan Cameron   staging:iio:light...
615
  	return IRQ_HANDLED;
388be4883   Jonathan Cameron   staging:iio: tsl2...
616
  }
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
617
  static int tsl2563_write_interrupt_config(struct iio_dev *indio_dev,
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
618
619
  	const struct iio_chan_spec *chan, enum iio_event_type type,
  	enum iio_event_direction dir, int state)
388be4883   Jonathan Cameron   staging:iio: tsl2...
620
  {
33789dce5   Jonathan Cameron   staging:iio:tsl25...
621
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
622
  	int ret = 0;
388be4883   Jonathan Cameron   staging:iio: tsl2...
623

388be4883   Jonathan Cameron   staging:iio: tsl2...
624
  	mutex_lock(&chip->lock);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
625
  	if (state && !(chip->intr & 0x30)) {
388be4883   Jonathan Cameron   staging:iio: tsl2...
626
627
628
629
630
631
632
633
634
635
636
637
  		chip->intr &= ~0x30;
  		chip->intr |= 0x10;
  		/* ensure the chip is actually on */
  		cancel_delayed_work(&chip->poweroff_work);
  		if (!tsl2563_get_power(chip)) {
  			ret = tsl2563_set_power(chip, 1);
  			if (ret)
  				goto out;
  			ret = tsl2563_configure(chip);
  			if (ret)
  				goto out;
  		}
d9b42c01a   Bryan Freed   iio: light sensor...
638
639
640
  		ret = i2c_smbus_write_byte_data(chip->client,
  						TSL2563_CMD | TSL2563_REG_INT,
  						chip->intr);
388be4883   Jonathan Cameron   staging:iio: tsl2...
641
642
  		chip->int_enabled = true;
  	}
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
643
  	if (!state && (chip->intr & 0x30)) {
95273f895   Derek Basehore   tsl2563: fixed bu...
644
  		chip->intr &= ~0x30;
d9b42c01a   Bryan Freed   iio: light sensor...
645
646
647
  		ret = i2c_smbus_write_byte_data(chip->client,
  						TSL2563_CMD | TSL2563_REG_INT,
  						chip->intr);
388be4883   Jonathan Cameron   staging:iio: tsl2...
648
649
650
651
652
653
  		chip->int_enabled = false;
  		/* now the interrupt is not enabled, we can go to sleep */
  		schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
  	}
  out:
  	mutex_unlock(&chip->lock);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
654
  	return ret;
388be4883   Jonathan Cameron   staging:iio: tsl2...
655
  }
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
656
  static int tsl2563_read_interrupt_config(struct iio_dev *indio_dev,
6d59747eb   Lars-Peter Clausen   iio:tsl2563: Swit...
657
658
  	const struct iio_chan_spec *chan, enum iio_event_type type,
  	enum iio_event_direction dir)
388be4883   Jonathan Cameron   staging:iio: tsl2...
659
  {
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
660
  	struct tsl2563_chip *chip = iio_priv(indio_dev);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
661
  	int ret;
388be4883   Jonathan Cameron   staging:iio: tsl2...
662
663
  
  	mutex_lock(&chip->lock);
d9b42c01a   Bryan Freed   iio: light sensor...
664
665
  	ret = i2c_smbus_read_byte_data(chip->client,
  				       TSL2563_CMD | TSL2563_REG_INT);
388be4883   Jonathan Cameron   staging:iio: tsl2...
666
667
  	mutex_unlock(&chip->lock);
  	if (ret < 0)
a722dcca4   Jonathan Cameron   staging:iio:tsl25...
668
  		return ret;
388be4883   Jonathan Cameron   staging:iio: tsl2...
669

a722dcca4   Jonathan Cameron   staging:iio:tsl25...
670
  	return !!(ret & 0x30);
388be4883   Jonathan Cameron   staging:iio: tsl2...
671
  }
388be4883   Jonathan Cameron   staging:iio: tsl2...
672

6fe8135fc   Jonathan Cameron   staging:iio: impl...
673
674
  static const struct iio_info tsl2563_info_no_irq = {
  	.driver_module = THIS_MODULE,
9e4216fd6   Bryan Freed   iio: light sensor...
675
676
  	.read_raw = &tsl2563_read_raw,
  	.write_raw = &tsl2563_write_raw,
6fe8135fc   Jonathan Cameron   staging:iio: impl...
677
678
679
680
  };
  
  static const struct iio_info tsl2563_info = {
  	.driver_module = THIS_MODULE,
6fe8135fc   Jonathan Cameron   staging:iio: impl...
681
682
  	.read_raw = &tsl2563_read_raw,
  	.write_raw = &tsl2563_write_raw,
cb955852a   Lars-Peter Clausen   iio: Remove suppo...
683
684
685
686
  	.read_event_value = &tsl2563_read_thresh,
  	.write_event_value = &tsl2563_write_thresh,
  	.read_event_config = &tsl2563_read_interrupt_config,
  	.write_event_config = &tsl2563_write_interrupt_config,
6fe8135fc   Jonathan Cameron   staging:iio: impl...
687
  };
4ae1c61ff   Bill Pemberton   staging: iio: rem...
688
  static int tsl2563_probe(struct i2c_client *client,
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
689
690
  				const struct i2c_device_id *device_id)
  {
33789dce5   Jonathan Cameron   staging:iio:tsl25...
691
  	struct iio_dev *indio_dev;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
692
693
  	struct tsl2563_chip *chip;
  	struct tsl2563_platform_data *pdata = client->dev.platform_data;
8175bff5b   Sebastian Reichel   iio:light:tsl2563...
694
  	struct device_node *np = client->dev.of_node;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
695
  	int err = 0;
deda386de   Jonathan Cameron   staging:iio:trivi...
696
  	u8 id = 0;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
697

bace48f44   Sachin Kamat   iio: light: tsl25...
698
  	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
33789dce5   Jonathan Cameron   staging:iio:tsl25...
699
  	if (!indio_dev)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
700
  		return -ENOMEM;
33789dce5   Jonathan Cameron   staging:iio:tsl25...
701
  	chip = iio_priv(indio_dev);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
702
703
704
705
706
  	i2c_set_clientdata(client, chip);
  	chip->client = client;
  
  	err = tsl2563_detect(chip);
  	if (err) {
dbf717fd9   Grant Grundler   staging:iio:tsl25...
707
708
  		dev_err(&client->dev, "detect error %d
  ", -err);
bace48f44   Sachin Kamat   iio: light: tsl25...
709
  		return err;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
710
711
712
  	}
  
  	err = tsl2563_read_id(chip, &id);
dbf717fd9   Grant Grundler   staging:iio:tsl25...
713
714
715
  	if (err) {
  		dev_err(&client->dev, "read id error %d
  ", -err);
bace48f44   Sachin Kamat   iio: light: tsl25...
716
  		return err;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
717
  	}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
718
719
720
721
722
723
724
725
726
727
728
729
730
  
  	mutex_init(&chip->lock);
  
  	/* Default values used until userspace says otherwise */
  	chip->low_thres = 0x0;
  	chip->high_thres = 0xffff;
  	chip->gainlevel = tsl2563_gainlevel_table;
  	chip->intr = TSL2563_INT_PERSIST(4);
  	chip->calib0 = calib_from_sysfs(CALIB_BASE_SYSFS);
  	chip->calib1 = calib_from_sysfs(CALIB_BASE_SYSFS);
  
  	if (pdata)
  		chip->cover_comp_gain = pdata->cover_comp_gain;
8175bff5b   Sebastian Reichel   iio:light:tsl2563...
731
732
733
  	else if (np)
  		of_property_read_u32(np, "amstaos,cover-comp-gain",
  				     &chip->cover_comp_gain);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
734
735
736
737
738
  	else
  		chip->cover_comp_gain = 1;
  
  	dev_info(&client->dev, "model %d, rev. %d
  ", id >> 4, id & 0x0f);
cbcdf4dd4   Jonathan Cameron   staging:iio:light...
739
740
741
  	indio_dev->name = client->name;
  	indio_dev->channels = tsl2563_channels;
  	indio_dev->num_channels = ARRAY_SIZE(tsl2563_channels);
33789dce5   Jonathan Cameron   staging:iio:tsl25...
742
  	indio_dev->dev.parent = &client->dev;
33789dce5   Jonathan Cameron   staging:iio:tsl25...
743
  	indio_dev->modes = INDIO_DIRECT_MODE;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
744

cbcdf4dd4   Jonathan Cameron   staging:iio:light...
745
  	if (client->irq)
6fe8135fc   Jonathan Cameron   staging:iio: impl...
746
747
748
  		indio_dev->info = &tsl2563_info;
  	else
  		indio_dev->info = &tsl2563_info_no_irq;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
749

388be4883   Jonathan Cameron   staging:iio: tsl2...
750
  	if (client->irq) {
bace48f44   Sachin Kamat   iio: light: tsl25...
751
  		err = devm_request_threaded_irq(&client->dev, client->irq,
bdab10017   Jonathan Cameron   staging:iio:light...
752
753
754
755
756
  					   NULL,
  					   &tsl2563_event_handler,
  					   IRQF_TRIGGER_RISING | IRQF_ONESHOT,
  					   "tsl2563_event",
  					   indio_dev);
dbf717fd9   Grant Grundler   staging:iio:tsl25...
757
758
759
  		if (err) {
  			dev_err(&client->dev, "irq request error %d
  ", -err);
bace48f44   Sachin Kamat   iio: light: tsl25...
760
  			return err;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
761
  		}
388be4883   Jonathan Cameron   staging:iio: tsl2...
762
  	}
dbf717fd9   Grant Grundler   staging:iio:tsl25...
763

ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
764
  	err = tsl2563_configure(chip);
dbf717fd9   Grant Grundler   staging:iio:tsl25...
765
766
767
  	if (err) {
  		dev_err(&client->dev, "configure error %d
  ", -err);
bace48f44   Sachin Kamat   iio: light: tsl25...
768
  		return err;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
769
  	}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
770
771
  
  	INIT_DELAYED_WORK(&chip->poweroff_work, tsl2563_poweroff_work);
dbf717fd9   Grant Grundler   staging:iio:tsl25...
772

388be4883   Jonathan Cameron   staging:iio: tsl2...
773
  	/* The interrupt cannot yet be enabled so this is fine without lock */
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
774
  	schedule_delayed_work(&chip->poweroff_work, 5 * HZ);
dbf717fd9   Grant Grundler   staging:iio:tsl25...
775
776
777
778
  	err = iio_device_register(indio_dev);
  	if (err) {
  		dev_err(&client->dev, "iio registration error %d
  ", -err);
bace48f44   Sachin Kamat   iio: light: tsl25...
779
  		goto fail;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
780
  	}
26d25ae3f   Jonathan Cameron   staging:iio: rewo...
781

ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
782
  	return 0;
dbf717fd9   Grant Grundler   staging:iio:tsl25...
783

bace48f44   Sachin Kamat   iio: light: tsl25...
784
  fail:
dbf717fd9   Grant Grundler   staging:iio:tsl25...
785
786
  	cancel_delayed_work(&chip->poweroff_work);
  	flush_scheduled_work();
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
787
788
  	return err;
  }
447d4f29e   Bill Pemberton   staging: iio: rem...
789
  static int tsl2563_remove(struct i2c_client *client)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
790
791
  {
  	struct tsl2563_chip *chip = i2c_get_clientdata(client);
33789dce5   Jonathan Cameron   staging:iio:tsl25...
792
  	struct iio_dev *indio_dev = iio_priv_to_dev(chip);
d2fffd6c2   Jonathan Cameron   staging:iio: fix ...
793
794
  
  	iio_device_unregister(indio_dev);
388be4883   Jonathan Cameron   staging:iio: tsl2...
795
796
797
  	if (!chip->int_enabled)
  		cancel_delayed_work(&chip->poweroff_work);
  	/* Ensure that interrupts are disabled - then flush any bottom halves */
95273f895   Derek Basehore   tsl2563: fixed bu...
798
  	chip->intr &= ~0x30;
d9b42c01a   Bryan Freed   iio: light sensor...
799
800
  	i2c_smbus_write_byte_data(chip->client, TSL2563_CMD | TSL2563_REG_INT,
  				  chip->intr);
388be4883   Jonathan Cameron   staging:iio: tsl2...
801
802
  	flush_scheduled_work();
  	tsl2563_set_power(chip, 0);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
803

ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
804
805
  	return 0;
  }
01788c533   Lars-Peter Clausen   staging:iio: Use ...
806
807
  #ifdef CONFIG_PM_SLEEP
  static int tsl2563_suspend(struct device *dev)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
808
  {
01788c533   Lars-Peter Clausen   staging:iio: Use ...
809
  	struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
810
811
812
813
814
815
816
  	int ret;
  
  	mutex_lock(&chip->lock);
  
  	ret = tsl2563_set_power(chip, 0);
  	if (ret)
  		goto out;
01788c533   Lars-Peter Clausen   staging:iio: Use ...
817
  	chip->suspended = true;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
818
819
820
821
822
  
  out:
  	mutex_unlock(&chip->lock);
  	return ret;
  }
01788c533   Lars-Peter Clausen   staging:iio: Use ...
823
  static int tsl2563_resume(struct device *dev)
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
824
  {
01788c533   Lars-Peter Clausen   staging:iio: Use ...
825
  	struct tsl2563_chip *chip = i2c_get_clientdata(to_i2c_client(dev));
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
826
827
828
829
830
831
832
833
834
835
836
  	int ret;
  
  	mutex_lock(&chip->lock);
  
  	ret = tsl2563_set_power(chip, 1);
  	if (ret)
  		goto out;
  
  	ret = tsl2563_configure(chip);
  	if (ret)
  		goto out;
01788c533   Lars-Peter Clausen   staging:iio: Use ...
837
  	chip->suspended = false;
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
838
839
840
841
842
  
  out:
  	mutex_unlock(&chip->lock);
  	return ret;
  }
01788c533   Lars-Peter Clausen   staging:iio: Use ...
843
844
845
846
847
  static SIMPLE_DEV_PM_OPS(tsl2563_pm_ops, tsl2563_suspend, tsl2563_resume);
  #define TSL2563_PM_OPS (&tsl2563_pm_ops)
  #else
  #define TSL2563_PM_OPS NULL
  #endif
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
848
  static const struct i2c_device_id tsl2563_id[] = {
dbd5d239e   Jonathan Cameron   Staging: IIO: Add...
849
850
851
852
853
  	{ "tsl2560", 0 },
  	{ "tsl2561", 1 },
  	{ "tsl2562", 2 },
  	{ "tsl2563", 3 },
  	{}
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
854
855
856
857
858
  };
  MODULE_DEVICE_TABLE(i2c, tsl2563_id);
  
  static struct i2c_driver tsl2563_i2c_driver = {
  	.driver = {
dbd5d239e   Jonathan Cameron   Staging: IIO: Add...
859
  		.name	 = "tsl2563",
01788c533   Lars-Peter Clausen   staging:iio: Use ...
860
  		.pm	= TSL2563_PM_OPS,
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
861
  	},
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
862
  	.probe		= tsl2563_probe,
e543acf07   Bill Pemberton   staging: iio: rem...
863
  	.remove		= tsl2563_remove,
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
864
865
  	.id_table	= tsl2563_id,
  };
6e5af184f   Lars-Peter Clausen   staging:iio: Use ...
866
  module_i2c_driver(tsl2563_i2c_driver);
ee1f1fa40   Amit Kucheria   Staging: iio: tsl...
867
868
869
870
  
  MODULE_AUTHOR("Nokia Corporation");
  MODULE_DESCRIPTION("tsl2563 light sensor driver");
  MODULE_LICENSE("GPL");