Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * apds9300.c - IIO driver for Avago APDS9300 ambient light sensor
  4 *
  5 * Copyright 2013 Oleksandr Kravchenko <o.v.kravchenko@globallogic.com>
  6 */
  7
  8#include <linux/module.h>
  9#include <linux/slab.h>
 10#include <linux/pm.h>
 11#include <linux/i2c.h>
 12#include <linux/err.h>
 13#include <linux/mutex.h>
 14#include <linux/interrupt.h>
 15#include <linux/iio/iio.h>
 16#include <linux/iio/sysfs.h>
 17#include <linux/iio/events.h>
 18
 19#define APDS9300_DRV_NAME "apds9300"
 20#define APDS9300_IRQ_NAME "apds9300_event"
 21
 22/* Command register bits */
 23#define APDS9300_CMD	BIT(7) /* Select command register. Must write as 1 */
 24#define APDS9300_WORD	BIT(5) /* I2C write/read: if 1 word, if 0 byte */
 25#define APDS9300_CLEAR	BIT(6) /* Interrupt clear. Clears pending interrupt */
 26
 27/* Register set */
 28#define APDS9300_CONTROL	0x00 /* Control of basic functions */
 29#define APDS9300_THRESHLOWLOW	0x02 /* Low byte of low interrupt threshold */
 30#define APDS9300_THRESHHIGHLOW	0x04 /* Low byte of high interrupt threshold */
 31#define APDS9300_INTERRUPT	0x06 /* Interrupt control */
 32#define APDS9300_DATA0LOW	0x0c /* Low byte of ADC channel 0 */
 33#define APDS9300_DATA1LOW	0x0e /* Low byte of ADC channel 1 */
 34
 35/* Power on/off value for APDS9300_CONTROL register */
 36#define APDS9300_POWER_ON	0x03
 37#define APDS9300_POWER_OFF	0x00
 38
 39/* Interrupts */
 40#define APDS9300_INTR_ENABLE	0x10
 41/* Interrupt Persist Function: Any value outside of threshold range */
 42#define APDS9300_THRESH_INTR	0x01
 43
 44#define APDS9300_THRESH_MAX	0xffff /* Max threshold value */
 45
 46struct apds9300_data {
 47	struct i2c_client *client;
 48	struct mutex mutex;
 49	int power_state;
 50	int thresh_low;
 51	int thresh_hi;
 52	int intr_en;
 53};
 54
 55/* Lux calculation */
 56
 57/* Calculated values 1000 * (CH1/CH0)^1.4 for CH1/CH0 from 0 to 0.52 */
 58static const u16 apds9300_lux_ratio[] = {
 59	0, 2, 4, 7, 11, 15, 19, 24, 29, 34, 40, 45, 51, 57, 64, 70, 77, 84, 91,
 60	98, 105, 112, 120, 128, 136, 144, 152, 160, 168, 177, 185, 194, 203,
 61	212, 221, 230, 239, 249, 258, 268, 277, 287, 297, 307, 317, 327, 337,
 62	347, 358, 368, 379, 390, 400,
 63};
 64
 65static unsigned long apds9300_calculate_lux(u16 ch0, u16 ch1)
 66{
 67	unsigned long lux, tmp;
 68
 69	/* avoid division by zero */
 70	if (ch0 == 0)
 71		return 0;
 72
 73	tmp = DIV_ROUND_UP(ch1 * 100, ch0);
 74	if (tmp <= 52) {
 75		lux = 3150 * ch0 - (unsigned long)DIV_ROUND_UP_ULL(ch0
 76				* apds9300_lux_ratio[tmp] * 5930ull, 1000);
 77	} else if (tmp <= 65) {
 78		lux = 2290 * ch0 - 2910 * ch1;
 79	} else if (tmp <= 80) {
 80		lux = 1570 * ch0 - 1800 * ch1;
 81	} else if (tmp <= 130) {
 82		lux = 338 * ch0 - 260 * ch1;
 83	} else {
 84		lux = 0;
 85	}
 86
 87	return lux / 100000;
 88}
 89
 90static int apds9300_get_adc_val(struct apds9300_data *data, int adc_number)
 91{
 92	int ret;
 93	u8 flags = APDS9300_CMD | APDS9300_WORD;
 94
 95	if (!data->power_state)
 96		return -EBUSY;
 97
 98	/* Select ADC0 or ADC1 data register */
 99	flags |= adc_number ? APDS9300_DATA1LOW : APDS9300_DATA0LOW;
100
101	ret = i2c_smbus_read_word_data(data->client, flags);
102	if (ret < 0)
103		dev_err(&data->client->dev,
104			"failed to read ADC%d value\n", adc_number);
105
106	return ret;
107}
108
109static int apds9300_set_thresh_low(struct apds9300_data *data, int value)
110{
111	int ret;
112
113	if (!data->power_state)
114		return -EBUSY;
115
116	if (value > APDS9300_THRESH_MAX)
117		return -EINVAL;
118
119	ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHLOWLOW
120			| APDS9300_CMD | APDS9300_WORD, value);
121	if (ret) {
122		dev_err(&data->client->dev, "failed to set thresh_low\n");
123		return ret;
124	}
125	data->thresh_low = value;
126
127	return 0;
128}
129
130static int apds9300_set_thresh_hi(struct apds9300_data *data, int value)
131{
132	int ret;
133
134	if (!data->power_state)
135		return -EBUSY;
136
137	if (value > APDS9300_THRESH_MAX)
138		return -EINVAL;
139
140	ret = i2c_smbus_write_word_data(data->client, APDS9300_THRESHHIGHLOW
141			| APDS9300_CMD | APDS9300_WORD, value);
142	if (ret) {
143		dev_err(&data->client->dev, "failed to set thresh_hi\n");
144		return ret;
145	}
146	data->thresh_hi = value;
147
148	return 0;
149}
150
151static int apds9300_set_intr_state(struct apds9300_data *data, int state)
152{
153	int ret;
154	u8 cmd;
155
156	if (!data->power_state)
157		return -EBUSY;
158
159	cmd = state ? APDS9300_INTR_ENABLE | APDS9300_THRESH_INTR : 0x00;
160	ret = i2c_smbus_write_byte_data(data->client,
161			APDS9300_INTERRUPT | APDS9300_CMD, cmd);
162	if (ret) {
163		dev_err(&data->client->dev,
164			"failed to set interrupt state %d\n", state);
165		return ret;
166	}
167	data->intr_en = state;
168
169	return 0;
170}
171
172static int apds9300_set_power_state(struct apds9300_data *data, int state)
173{
174	int ret;
175	u8 cmd;
176
177	cmd = state ? APDS9300_POWER_ON : APDS9300_POWER_OFF;
178	ret = i2c_smbus_write_byte_data(data->client,
179			APDS9300_CONTROL | APDS9300_CMD, cmd);
180	if (ret) {
181		dev_err(&data->client->dev,
182			"failed to set power state %d\n", state);
183		return ret;
184	}
185	data->power_state = state;
186
187	return 0;
188}
189
190static void apds9300_clear_intr(struct apds9300_data *data)
191{
192	int ret;
193
194	ret = i2c_smbus_write_byte(data->client, APDS9300_CLEAR | APDS9300_CMD);
195	if (ret < 0)
196		dev_err(&data->client->dev, "failed to clear interrupt\n");
197}
198
199static int apds9300_chip_init(struct apds9300_data *data)
200{
201	int ret;
202
203	/* Need to set power off to ensure that the chip is off */
204	ret = apds9300_set_power_state(data, 0);
205	if (ret < 0)
206		goto err;
207	/*
208	 * Probe the chip. To do so we try to power up the device and then to
209	 * read back the 0x03 code
210	 */
211	ret = apds9300_set_power_state(data, 1);
212	if (ret < 0)
213		goto err;
214	ret = i2c_smbus_read_byte_data(data->client,
215			APDS9300_CONTROL | APDS9300_CMD);
216	if (ret != APDS9300_POWER_ON) {
217		ret = -ENODEV;
218		goto err;
219	}
220	/*
221	 * Disable interrupt to ensure thai it is doesn't enable
222	 * i.e. after device soft reset
223	 */
224	ret = apds9300_set_intr_state(data, 0);
225	if (ret < 0)
226		goto err;
227
228	return 0;
229
230err:
231	dev_err(&data->client->dev, "failed to init the chip\n");
232	return ret;
233}
234
235static int apds9300_read_raw(struct iio_dev *indio_dev,
236		struct iio_chan_spec const *chan, int *val, int *val2,
237		long mask)
238{
239	int ch0, ch1, ret = -EINVAL;
240	struct apds9300_data *data = iio_priv(indio_dev);
241
242	mutex_lock(&data->mutex);
243	switch (chan->type) {
244	case IIO_LIGHT:
245		ch0 = apds9300_get_adc_val(data, 0);
246		if (ch0 < 0) {
247			ret = ch0;
248			break;
249		}
250		ch1 = apds9300_get_adc_val(data, 1);
251		if (ch1 < 0) {
252			ret = ch1;
253			break;
254		}
255		*val = apds9300_calculate_lux(ch0, ch1);
256		ret = IIO_VAL_INT;
257		break;
258	case IIO_INTENSITY:
259		ret = apds9300_get_adc_val(data, chan->channel);
260		if (ret < 0)
261			break;
262		*val = ret;
263		ret = IIO_VAL_INT;
264		break;
265	default:
266		break;
267	}
268	mutex_unlock(&data->mutex);
269
270	return ret;
271}
272
273static int apds9300_read_thresh(struct iio_dev *indio_dev,
274		const struct iio_chan_spec *chan, enum iio_event_type type,
275		enum iio_event_direction dir, enum iio_event_info info,
276		int *val, int *val2)
277{
278	struct apds9300_data *data = iio_priv(indio_dev);
279
280	switch (dir) {
281	case IIO_EV_DIR_RISING:
282		*val = data->thresh_hi;
283		break;
284	case IIO_EV_DIR_FALLING:
285		*val = data->thresh_low;
286		break;
287	default:
288		return -EINVAL;
289	}
290
291	return IIO_VAL_INT;
292}
293
294static int apds9300_write_thresh(struct iio_dev *indio_dev,
295		const struct iio_chan_spec *chan, enum iio_event_type type,
296		enum iio_event_direction dir, enum iio_event_info info, int val,
297		int val2)
298{
299	struct apds9300_data *data = iio_priv(indio_dev);
300	int ret;
301
302	mutex_lock(&data->mutex);
303	if (dir == IIO_EV_DIR_RISING)
304		ret = apds9300_set_thresh_hi(data, val);
305	else
306		ret = apds9300_set_thresh_low(data, val);
307	mutex_unlock(&data->mutex);
308
309	return ret;
310}
311
312static int apds9300_read_interrupt_config(struct iio_dev *indio_dev,
313		const struct iio_chan_spec *chan,
314		enum iio_event_type type,
315		enum iio_event_direction dir)
316{
317	struct apds9300_data *data = iio_priv(indio_dev);
318
319	return data->intr_en;
320}
321
322static int apds9300_write_interrupt_config(struct iio_dev *indio_dev,
323		const struct iio_chan_spec *chan, enum iio_event_type type,
324		enum iio_event_direction dir, int state)
325{
326	struct apds9300_data *data = iio_priv(indio_dev);
327	int ret;
328
329	mutex_lock(&data->mutex);
330	ret = apds9300_set_intr_state(data, state);
331	mutex_unlock(&data->mutex);
332
333	return ret;
334}
335
336static const struct iio_info apds9300_info_no_irq = {
337	.read_raw	= apds9300_read_raw,
338};
339
340static const struct iio_info apds9300_info = {
341	.read_raw		= apds9300_read_raw,
342	.read_event_value	= apds9300_read_thresh,
343	.write_event_value	= apds9300_write_thresh,
344	.read_event_config	= apds9300_read_interrupt_config,
345	.write_event_config	= apds9300_write_interrupt_config,
346};
347
348static const struct iio_event_spec apds9300_event_spec[] = {
349	{
350		.type = IIO_EV_TYPE_THRESH,
351		.dir = IIO_EV_DIR_RISING,
352		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
353			BIT(IIO_EV_INFO_ENABLE),
354	}, {
355		.type = IIO_EV_TYPE_THRESH,
356		.dir = IIO_EV_DIR_FALLING,
357		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
358			BIT(IIO_EV_INFO_ENABLE),
359	},
360};
361
362static const struct iio_chan_spec apds9300_channels[] = {
363	{
364		.type = IIO_LIGHT,
365		.channel = 0,
366		.indexed = true,
367		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
368	}, {
369		.type = IIO_INTENSITY,
370		.channel = 0,
371		.channel2 = IIO_MOD_LIGHT_BOTH,
372		.indexed = true,
373		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
374		.event_spec = apds9300_event_spec,
375		.num_event_specs = ARRAY_SIZE(apds9300_event_spec),
376	}, {
377		.type = IIO_INTENSITY,
378		.channel = 1,
379		.channel2 = IIO_MOD_LIGHT_IR,
380		.indexed = true,
381		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
382	},
383};
384
385static irqreturn_t apds9300_interrupt_handler(int irq, void *private)
386{
387	struct iio_dev *dev_info = private;
388	struct apds9300_data *data = iio_priv(dev_info);
389
390	iio_push_event(dev_info,
391		       IIO_UNMOD_EVENT_CODE(IIO_INTENSITY, 0,
392					    IIO_EV_TYPE_THRESH,
393					    IIO_EV_DIR_EITHER),
394		       iio_get_time_ns(dev_info));
395
396	apds9300_clear_intr(data);
397
398	return IRQ_HANDLED;
399}
400
401static int apds9300_probe(struct i2c_client *client,
402		const struct i2c_device_id *id)
403{
404	struct apds9300_data *data;
405	struct iio_dev *indio_dev;
406	int ret;
407
408	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
409	if (!indio_dev)
410		return -ENOMEM;
411
412	data = iio_priv(indio_dev);
413	i2c_set_clientdata(client, indio_dev);
414	data->client = client;
415
416	ret = apds9300_chip_init(data);
417	if (ret < 0)
418		goto err;
419
420	mutex_init(&data->mutex);
421
422	indio_dev->channels = apds9300_channels;
423	indio_dev->num_channels = ARRAY_SIZE(apds9300_channels);
424	indio_dev->name = APDS9300_DRV_NAME;
425	indio_dev->modes = INDIO_DIRECT_MODE;
426
427	if (client->irq)
428		indio_dev->info = &apds9300_info;
429	else
430		indio_dev->info = &apds9300_info_no_irq;
431
432	if (client->irq) {
433		ret = devm_request_threaded_irq(&client->dev, client->irq,
434				NULL, apds9300_interrupt_handler,
435				IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
436				APDS9300_IRQ_NAME, indio_dev);
437		if (ret) {
438			dev_err(&client->dev, "irq request error %d\n", -ret);
439			goto err;
440		}
441	}
442
443	ret = iio_device_register(indio_dev);
444	if (ret < 0)
445		goto err;
446
447	return 0;
448
449err:
450	/* Ensure that power off in case of error */
451	apds9300_set_power_state(data, 0);
452	return ret;
453}
454
455static int apds9300_remove(struct i2c_client *client)
456{
457	struct iio_dev *indio_dev = i2c_get_clientdata(client);
458	struct apds9300_data *data = iio_priv(indio_dev);
459
460	iio_device_unregister(indio_dev);
461
462	/* Ensure that power off and interrupts are disabled */
463	apds9300_set_intr_state(data, 0);
464	apds9300_set_power_state(data, 0);
465
466	return 0;
467}
468
469#ifdef CONFIG_PM_SLEEP
470static int apds9300_suspend(struct device *dev)
471{
472	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
473	struct apds9300_data *data = iio_priv(indio_dev);
474	int ret;
475
476	mutex_lock(&data->mutex);
477	ret = apds9300_set_power_state(data, 0);
478	mutex_unlock(&data->mutex);
479
480	return ret;
481}
482
483static int apds9300_resume(struct device *dev)
484{
485	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
486	struct apds9300_data *data = iio_priv(indio_dev);
487	int ret;
488
489	mutex_lock(&data->mutex);
490	ret = apds9300_set_power_state(data, 1);
491	mutex_unlock(&data->mutex);
492
493	return ret;
494}
495
496static SIMPLE_DEV_PM_OPS(apds9300_pm_ops, apds9300_suspend, apds9300_resume);
497#define APDS9300_PM_OPS (&apds9300_pm_ops)
498#else
499#define APDS9300_PM_OPS NULL
500#endif
501
502static const struct i2c_device_id apds9300_id[] = {
503	{ APDS9300_DRV_NAME, 0 },
504	{ }
505};
506
507MODULE_DEVICE_TABLE(i2c, apds9300_id);
508
509static struct i2c_driver apds9300_driver = {
510	.driver = {
511		.name	= APDS9300_DRV_NAME,
512		.pm	= APDS9300_PM_OPS,
513	},
514	.probe		= apds9300_probe,
515	.remove		= apds9300_remove,
516	.id_table	= apds9300_id,
517};
518
519module_i2c_driver(apds9300_driver);
520
521MODULE_AUTHOR("Kravchenko Oleksandr <o.v.kravchenko@globallogic.com>");
522MODULE_AUTHOR("GlobalLogic inc.");
523MODULE_DESCRIPTION("APDS9300 ambient light photo sensor driver");
524MODULE_LICENSE("GPL");