xref: /openbmc/linux/drivers/iio/light/gp2ap002.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
197d642e2SLinus Walleij // SPDX-License-Identifier: GPL-2.0-only
297d642e2SLinus Walleij /*
397d642e2SLinus Walleij  * These are the two Sharp GP2AP002 variants supported by this driver:
497d642e2SLinus Walleij  * GP2AP002A00F Ambient Light and Proximity Sensor
597d642e2SLinus Walleij  * GP2AP002S00F Proximity Sensor
697d642e2SLinus Walleij  *
797d642e2SLinus Walleij  * Copyright (C) 2020 Linaro Ltd.
897d642e2SLinus Walleij  * Author: Linus Walleij <linus.walleij@linaro.org>
997d642e2SLinus Walleij  *
1097d642e2SLinus Walleij  * Based partly on the code in Sony Ericssons GP2AP00200F driver by
1197d642e2SLinus Walleij  * Courtney Cavin and Oskar Andero in drivers/input/misc/gp2ap002a00f.c
1297d642e2SLinus Walleij  * Based partly on a Samsung misc driver submitted by
1397d642e2SLinus Walleij  * Donggeun Kim & Minkyu Kang in 2011:
1497d642e2SLinus Walleij  * https://lore.kernel.org/lkml/1315556546-7445-1-git-send-email-dg77.kim@samsung.com/
1597d642e2SLinus Walleij  * Based partly on a submission by
1697d642e2SLinus Walleij  * Jonathan Bakker and Paweł Chmiel in january 2019:
1797d642e2SLinus Walleij  * https://lore.kernel.org/linux-input/20190125175045.22576-1-pawel.mikolaj.chmiel@gmail.com/
1897d642e2SLinus Walleij  * Based partly on code from the Samsung GT-S7710 by <mjchen@sta.samsung.com>
1997d642e2SLinus Walleij  * Based partly on the code in LG Electronics GP2AP00200F driver by
2097d642e2SLinus Walleij  * Kenobi Lee <sungyoung.lee@lge.com> and EunYoung Cho <ey.cho@lge.com>
2197d642e2SLinus Walleij  */
2297d642e2SLinus Walleij #include <linux/module.h>
2397d642e2SLinus Walleij #include <linux/i2c.h>
2497d642e2SLinus Walleij #include <linux/regmap.h>
2597d642e2SLinus Walleij #include <linux/iio/iio.h>
2697d642e2SLinus Walleij #include <linux/iio/sysfs.h>
2797d642e2SLinus Walleij #include <linux/iio/events.h>
2897d642e2SLinus Walleij #include <linux/iio/consumer.h> /* To get our ADC channel */
2997d642e2SLinus Walleij #include <linux/iio/types.h> /* To deal with our ADC channel */
3097d642e2SLinus Walleij #include <linux/init.h>
3197d642e2SLinus Walleij #include <linux/delay.h>
3297d642e2SLinus Walleij #include <linux/regulator/consumer.h>
3397d642e2SLinus Walleij #include <linux/pm_runtime.h>
3497d642e2SLinus Walleij #include <linux/interrupt.h>
3597d642e2SLinus Walleij #include <linux/bits.h>
3697d642e2SLinus Walleij #include <linux/math64.h>
3797d642e2SLinus Walleij #include <linux/pm.h>
3897d642e2SLinus Walleij 
3997d642e2SLinus Walleij #define GP2AP002_PROX_CHANNEL 0
4097d642e2SLinus Walleij #define GP2AP002_ALS_CHANNEL 1
4197d642e2SLinus Walleij 
4297d642e2SLinus Walleij /* ------------------------------------------------------------------------ */
4397d642e2SLinus Walleij /* ADDRESS SYMBOL             DATA                                 Init R/W */
4497d642e2SLinus Walleij /*                   D7    D6    D5    D4    D3    D2    D1    D0           */
4597d642e2SLinus Walleij /* ------------------------------------------------------------------------ */
4697d642e2SLinus Walleij /*    0      PROX     X     X     X     X     X     X     X    VO  H'00   R */
4797d642e2SLinus Walleij /*    1      GAIN     X     X     X     X  LED0     X     X     X  H'00   W */
4897d642e2SLinus Walleij /*    2       HYS  HYSD HYSC1 HYSC0     X HYSF3 HYSF2 HYSF1 HYSF0  H'00   W */
4997d642e2SLinus Walleij /*    3     CYCLE     X     X CYCL2 CYCL1 CYCL0  OSC2     X     X  H'00   W */
5097d642e2SLinus Walleij /*    4     OPMOD     X     X     X   ASD     X     X  VCON   SSD  H'00   W */
5197d642e2SLinus Walleij /*    6       CON     X     X     X OCON1 OCON0     X     X     X  H'00   W */
5297d642e2SLinus Walleij /* ------------------------------------------------------------------------ */
5397d642e2SLinus Walleij /* VO   :Proximity sensing result(0: no detection, 1: detection)            */
5497d642e2SLinus Walleij /* LED0 :Select switch for LED driver's On-registence(0:2x higher, 1:normal)*/
5597d642e2SLinus Walleij /* HYSD/HYSF :Adjusts the receiver sensitivity                              */
5697d642e2SLinus Walleij /* OSC  :Select switch internal clocl frequency hoppling(0:effective)       */
5797d642e2SLinus Walleij /* CYCL :Determine the detection cycle(typically 8ms, up to 128x)           */
5897d642e2SLinus Walleij /* SSD  :Software Shutdown function(0:shutdown, 1:operating)                */
5997d642e2SLinus Walleij /* VCON :VOUT output method control(0:normal, 1:interrupt)                  */
6097d642e2SLinus Walleij /* ASD  :Select switch for analog sleep function(0:ineffective, 1:effective)*/
6197d642e2SLinus Walleij /* OCON :Select switch for enabling/disabling VOUT (00:enable, 11:disable)  */
6297d642e2SLinus Walleij 
6397d642e2SLinus Walleij #define GP2AP002_PROX				0x00
6497d642e2SLinus Walleij #define GP2AP002_GAIN				0x01
6597d642e2SLinus Walleij #define GP2AP002_HYS				0x02
6697d642e2SLinus Walleij #define GP2AP002_CYCLE				0x03
6797d642e2SLinus Walleij #define GP2AP002_OPMOD				0x04
6897d642e2SLinus Walleij #define GP2AP002_CON				0x06
6997d642e2SLinus Walleij 
7097d642e2SLinus Walleij #define GP2AP002_PROX_VO_DETECT			BIT(0)
7197d642e2SLinus Walleij 
7297d642e2SLinus Walleij /* Setting this bit to 0 means 2x higher LED resistance */
7397d642e2SLinus Walleij #define GP2AP002_GAIN_LED_NORMAL		BIT(3)
7497d642e2SLinus Walleij 
7597d642e2SLinus Walleij /*
7697d642e2SLinus Walleij  * These bits adjusts the proximity sensitivity, determining characteristics
7797d642e2SLinus Walleij  * of the detection distance and its hysteresis.
7897d642e2SLinus Walleij  */
7997d642e2SLinus Walleij #define GP2AP002_HYS_HYSD_SHIFT		7
8097d642e2SLinus Walleij #define GP2AP002_HYS_HYSD_MASK		BIT(7)
8197d642e2SLinus Walleij #define GP2AP002_HYS_HYSC_SHIFT		5
8297d642e2SLinus Walleij #define GP2AP002_HYS_HYSC_MASK		GENMASK(6, 5)
8397d642e2SLinus Walleij #define GP2AP002_HYS_HYSF_SHIFT		0
8497d642e2SLinus Walleij #define GP2AP002_HYS_HYSF_MASK		GENMASK(3, 0)
8597d642e2SLinus Walleij #define GP2AP002_HYS_MASK		(GP2AP002_HYS_HYSD_MASK | \
8697d642e2SLinus Walleij 					 GP2AP002_HYS_HYSC_MASK | \
8797d642e2SLinus Walleij 					 GP2AP002_HYS_HYSF_MASK)
8897d642e2SLinus Walleij 
8997d642e2SLinus Walleij /*
9097d642e2SLinus Walleij  * These values determine the detection cycle response time
9197d642e2SLinus Walleij  * 0: 8ms, 1: 16ms, 2: 32ms, 3: 64ms, 4: 128ms,
9297d642e2SLinus Walleij  * 5: 256ms, 6: 512ms, 7: 1024ms
9397d642e2SLinus Walleij  */
9497d642e2SLinus Walleij #define GP2AP002_CYCLE_CYCL_SHIFT	3
9597d642e2SLinus Walleij #define GP2AP002_CYCLE_CYCL_MASK	GENMASK(5, 3)
9697d642e2SLinus Walleij 
9797d642e2SLinus Walleij /*
9897d642e2SLinus Walleij  * Select switch for internal clock frequency hopping
9997d642e2SLinus Walleij  *	0: effective,
10097d642e2SLinus Walleij  *	1: ineffective
10197d642e2SLinus Walleij  */
10297d642e2SLinus Walleij #define GP2AP002_CYCLE_OSC_EFFECTIVE	0
10397d642e2SLinus Walleij #define GP2AP002_CYCLE_OSC_INEFFECTIVE	BIT(2)
10497d642e2SLinus Walleij #define GP2AP002_CYCLE_OSC_MASK		BIT(2)
10597d642e2SLinus Walleij 
10697d642e2SLinus Walleij /* Analog sleep effective */
10797d642e2SLinus Walleij #define GP2AP002_OPMOD_ASD		BIT(4)
10897d642e2SLinus Walleij /* Enable chip */
10997d642e2SLinus Walleij #define GP2AP002_OPMOD_SSD_OPERATING	BIT(0)
11097d642e2SLinus Walleij /* IRQ mode */
11197d642e2SLinus Walleij #define GP2AP002_OPMOD_VCON_IRQ		BIT(1)
11297d642e2SLinus Walleij #define GP2AP002_OPMOD_MASK		(BIT(0) | BIT(1) | BIT(4))
11397d642e2SLinus Walleij 
11497d642e2SLinus Walleij /*
11597d642e2SLinus Walleij  * Select switch for enabling/disabling Vout pin
11697d642e2SLinus Walleij  * 0: enable
11797d642e2SLinus Walleij  * 2: force to go Low
11897d642e2SLinus Walleij  * 3: force to go High
11997d642e2SLinus Walleij  */
12097d642e2SLinus Walleij #define GP2AP002_CON_OCON_SHIFT		3
12197d642e2SLinus Walleij #define GP2AP002_CON_OCON_ENABLE	(0x0 << GP2AP002_CON_OCON_SHIFT)
12297d642e2SLinus Walleij #define GP2AP002_CON_OCON_LOW		(0x2 << GP2AP002_CON_OCON_SHIFT)
12397d642e2SLinus Walleij #define GP2AP002_CON_OCON_HIGH		(0x3 << GP2AP002_CON_OCON_SHIFT)
12497d642e2SLinus Walleij #define GP2AP002_CON_OCON_MASK		(0x3 << GP2AP002_CON_OCON_SHIFT)
12597d642e2SLinus Walleij 
12697d642e2SLinus Walleij /**
12797d642e2SLinus Walleij  * struct gp2ap002 - GP2AP002 state
12897d642e2SLinus Walleij  * @map: regmap pointer for the i2c regmap
12997d642e2SLinus Walleij  * @dev: pointer to parent device
13097d642e2SLinus Walleij  * @vdd: regulator controlling VDD
13197d642e2SLinus Walleij  * @vio: regulator controlling VIO
13297d642e2SLinus Walleij  * @alsout: IIO ADC channel to convert the ALSOUT signal
13397d642e2SLinus Walleij  * @hys_far: hysteresis control from device tree
13497d642e2SLinus Walleij  * @hys_close: hysteresis control from device tree
13597d642e2SLinus Walleij  * @is_gp2ap002s00f: this is the GP2AP002F variant of the chip
13697d642e2SLinus Walleij  * @irq: the IRQ line used by this device
13797d642e2SLinus Walleij  * @enabled: we cannot read the status of the hardware so we need to
13897d642e2SLinus Walleij  * keep track of whether the event is enabled using this state variable
13997d642e2SLinus Walleij  */
14097d642e2SLinus Walleij struct gp2ap002 {
14197d642e2SLinus Walleij 	struct regmap *map;
14297d642e2SLinus Walleij 	struct device *dev;
14397d642e2SLinus Walleij 	struct regulator *vdd;
14497d642e2SLinus Walleij 	struct regulator *vio;
14597d642e2SLinus Walleij 	struct iio_channel *alsout;
14697d642e2SLinus Walleij 	u8 hys_far;
14797d642e2SLinus Walleij 	u8 hys_close;
14897d642e2SLinus Walleij 	bool is_gp2ap002s00f;
14997d642e2SLinus Walleij 	int irq;
15097d642e2SLinus Walleij 	bool enabled;
15197d642e2SLinus Walleij };
15297d642e2SLinus Walleij 
gp2ap002_prox_irq(int irq,void * d)15397d642e2SLinus Walleij static irqreturn_t gp2ap002_prox_irq(int irq, void *d)
15497d642e2SLinus Walleij {
15597d642e2SLinus Walleij 	struct iio_dev *indio_dev = d;
15697d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
15797d642e2SLinus Walleij 	u64 ev;
15897d642e2SLinus Walleij 	int val;
15997d642e2SLinus Walleij 	int ret;
16097d642e2SLinus Walleij 
161f6dbf83cSJonathan Bakker 	if (!gp2ap002->enabled)
162f6dbf83cSJonathan Bakker 		goto err_retrig;
163f6dbf83cSJonathan Bakker 
16497d642e2SLinus Walleij 	ret = regmap_read(gp2ap002->map, GP2AP002_PROX, &val);
16597d642e2SLinus Walleij 	if (ret) {
16697d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error reading proximity\n");
16797d642e2SLinus Walleij 		goto err_retrig;
16897d642e2SLinus Walleij 	}
16997d642e2SLinus Walleij 
17097d642e2SLinus Walleij 	if (val & GP2AP002_PROX_VO_DETECT) {
17197d642e2SLinus Walleij 		/* Close */
17297d642e2SLinus Walleij 		dev_dbg(gp2ap002->dev, "close\n");
17397d642e2SLinus Walleij 		ret = regmap_write(gp2ap002->map, GP2AP002_HYS,
17497d642e2SLinus Walleij 				   gp2ap002->hys_far);
17597d642e2SLinus Walleij 		if (ret)
17697d642e2SLinus Walleij 			dev_err(gp2ap002->dev,
17797d642e2SLinus Walleij 				"error setting up proximity hysteresis\n");
17897d642e2SLinus Walleij 		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, GP2AP002_PROX_CHANNEL,
17997d642e2SLinus Walleij 					IIO_EV_TYPE_THRESH, IIO_EV_DIR_RISING);
18097d642e2SLinus Walleij 	} else {
18197d642e2SLinus Walleij 		/* Far */
18297d642e2SLinus Walleij 		dev_dbg(gp2ap002->dev, "far\n");
18397d642e2SLinus Walleij 		ret = regmap_write(gp2ap002->map, GP2AP002_HYS,
18497d642e2SLinus Walleij 				   gp2ap002->hys_close);
18597d642e2SLinus Walleij 		if (ret)
18697d642e2SLinus Walleij 			dev_err(gp2ap002->dev,
18797d642e2SLinus Walleij 				"error setting up proximity hysteresis\n");
18897d642e2SLinus Walleij 		ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, GP2AP002_PROX_CHANNEL,
18997d642e2SLinus Walleij 					IIO_EV_TYPE_THRESH, IIO_EV_DIR_FALLING);
19097d642e2SLinus Walleij 	}
19197d642e2SLinus Walleij 	iio_push_event(indio_dev, ev, iio_get_time_ns(indio_dev));
19297d642e2SLinus Walleij 
19397d642e2SLinus Walleij 	/*
19497d642e2SLinus Walleij 	 * After changing hysteresis, we need to wait for one detection
19597d642e2SLinus Walleij 	 * cycle to see if anything changed, or we will just trigger the
19697d642e2SLinus Walleij 	 * previous interrupt again. A detection cycle depends on the CYCLE
19797d642e2SLinus Walleij 	 * register, we are hard-coding ~8 ms in probe() so wait some more
19897d642e2SLinus Walleij 	 * than this, 20-30 ms.
19997d642e2SLinus Walleij 	 */
20097d642e2SLinus Walleij 	usleep_range(20000, 30000);
20197d642e2SLinus Walleij 
20297d642e2SLinus Walleij err_retrig:
20397d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_CON,
20497d642e2SLinus Walleij 			   GP2AP002_CON_OCON_ENABLE);
20597d642e2SLinus Walleij 	if (ret)
20697d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error setting up VOUT control\n");
20797d642e2SLinus Walleij 
20897d642e2SLinus Walleij 	return IRQ_HANDLED;
20997d642e2SLinus Walleij }
21097d642e2SLinus Walleij 
21197d642e2SLinus Walleij /*
21297d642e2SLinus Walleij  * This array maps current and lux.
21397d642e2SLinus Walleij  *
21497d642e2SLinus Walleij  * Ambient light sensing range is 3 to 55000 lux.
21597d642e2SLinus Walleij  *
21697d642e2SLinus Walleij  * This mapping is based on the following formula.
217070bd30aSGregor Riepl  * illuminance = 10 ^ (current[mA] / 10)
218070bd30aSGregor Riepl  *
219070bd30aSGregor Riepl  * When the ADC measures 0, return 0 lux.
22097d642e2SLinus Walleij  */
221070bd30aSGregor Riepl static const u16 gp2ap002_illuminance_table[] = {
222070bd30aSGregor Riepl 	0, 1, 1, 2, 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 25, 32, 40, 50, 63, 79,
223070bd30aSGregor Riepl 	100, 126, 158, 200, 251, 316, 398, 501, 631, 794, 1000, 1259, 1585,
224070bd30aSGregor Riepl 	1995, 2512, 3162, 3981, 5012, 6310, 7943, 10000, 12589, 15849, 19953,
225070bd30aSGregor Riepl 	25119, 31623, 39811, 50119,
22697d642e2SLinus Walleij };
22797d642e2SLinus Walleij 
gp2ap002_get_lux(struct gp2ap002 * gp2ap002)22897d642e2SLinus Walleij static int gp2ap002_get_lux(struct gp2ap002 *gp2ap002)
22997d642e2SLinus Walleij {
23097d642e2SLinus Walleij 	int ret, res;
231070bd30aSGregor Riepl 	u16 lux;
23297d642e2SLinus Walleij 
23397d642e2SLinus Walleij 	ret = iio_read_channel_processed(gp2ap002->alsout, &res);
23497d642e2SLinus Walleij 	if (ret < 0)
23597d642e2SLinus Walleij 		return ret;
23697d642e2SLinus Walleij 
23797d642e2SLinus Walleij 	dev_dbg(gp2ap002->dev, "read %d mA from ADC\n", res);
23897d642e2SLinus Walleij 
239070bd30aSGregor Riepl 	/* ensure we don't under/overflow */
240070bd30aSGregor Riepl 	res = clamp(res, 0, (int)ARRAY_SIZE(gp2ap002_illuminance_table) - 1);
241070bd30aSGregor Riepl 	lux = gp2ap002_illuminance_table[res];
24297d642e2SLinus Walleij 
243070bd30aSGregor Riepl 	return (int)lux;
24497d642e2SLinus Walleij }
24597d642e2SLinus Walleij 
gp2ap002_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)24697d642e2SLinus Walleij static int gp2ap002_read_raw(struct iio_dev *indio_dev,
24797d642e2SLinus Walleij 			   struct iio_chan_spec const *chan,
24897d642e2SLinus Walleij 			   int *val, int *val2, long mask)
24997d642e2SLinus Walleij {
25097d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
25197d642e2SLinus Walleij 	int ret;
25297d642e2SLinus Walleij 
253f6dbf83cSJonathan Bakker 	pm_runtime_get_sync(gp2ap002->dev);
254f6dbf83cSJonathan Bakker 
25597d642e2SLinus Walleij 	switch (mask) {
25697d642e2SLinus Walleij 	case IIO_CHAN_INFO_RAW:
25797d642e2SLinus Walleij 		switch (chan->type) {
25897d642e2SLinus Walleij 		case IIO_LIGHT:
25997d642e2SLinus Walleij 			ret = gp2ap002_get_lux(gp2ap002);
26097d642e2SLinus Walleij 			if (ret < 0)
26197d642e2SLinus Walleij 				return ret;
26297d642e2SLinus Walleij 			*val = ret;
263f6dbf83cSJonathan Bakker 			ret = IIO_VAL_INT;
264f6dbf83cSJonathan Bakker 			goto out;
26597d642e2SLinus Walleij 		default:
266f6dbf83cSJonathan Bakker 			ret = -EINVAL;
267f6dbf83cSJonathan Bakker 			goto out;
26897d642e2SLinus Walleij 		}
26997d642e2SLinus Walleij 	default:
270f6dbf83cSJonathan Bakker 		ret = -EINVAL;
27197d642e2SLinus Walleij 	}
272f6dbf83cSJonathan Bakker 
273f6dbf83cSJonathan Bakker out:
274f6dbf83cSJonathan Bakker 	pm_runtime_mark_last_busy(gp2ap002->dev);
275f6dbf83cSJonathan Bakker 	pm_runtime_put_autosuspend(gp2ap002->dev);
276f6dbf83cSJonathan Bakker 
277f6dbf83cSJonathan Bakker 	return ret;
27897d642e2SLinus Walleij }
27997d642e2SLinus Walleij 
gp2ap002_init(struct gp2ap002 * gp2ap002)28097d642e2SLinus Walleij static int gp2ap002_init(struct gp2ap002 *gp2ap002)
28197d642e2SLinus Walleij {
28297d642e2SLinus Walleij 	int ret;
28397d642e2SLinus Walleij 
28497d642e2SLinus Walleij 	/* Set up the IR LED resistance */
28597d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_GAIN,
28697d642e2SLinus Walleij 			   GP2AP002_GAIN_LED_NORMAL);
28797d642e2SLinus Walleij 	if (ret) {
28897d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error setting up LED gain\n");
28997d642e2SLinus Walleij 		return ret;
29097d642e2SLinus Walleij 	}
29197d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_HYS, gp2ap002->hys_far);
29297d642e2SLinus Walleij 	if (ret) {
29397d642e2SLinus Walleij 		dev_err(gp2ap002->dev,
29497d642e2SLinus Walleij 			"error setting up proximity hysteresis\n");
29597d642e2SLinus Walleij 		return ret;
29697d642e2SLinus Walleij 	}
29797d642e2SLinus Walleij 
29897d642e2SLinus Walleij 	/* Disable internal frequency hopping */
29997d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_CYCLE,
30097d642e2SLinus Walleij 			   GP2AP002_CYCLE_OSC_INEFFECTIVE);
30197d642e2SLinus Walleij 	if (ret) {
30297d642e2SLinus Walleij 		dev_err(gp2ap002->dev,
30397d642e2SLinus Walleij 			"error setting up internal frequency hopping\n");
30497d642e2SLinus Walleij 		return ret;
30597d642e2SLinus Walleij 	}
30697d642e2SLinus Walleij 
30797d642e2SLinus Walleij 	/* Enable chip and IRQ, disable analog sleep */
30897d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD,
30997d642e2SLinus Walleij 			   GP2AP002_OPMOD_SSD_OPERATING |
31097d642e2SLinus Walleij 			   GP2AP002_OPMOD_VCON_IRQ);
31197d642e2SLinus Walleij 	if (ret) {
31297d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error setting up operation mode\n");
31397d642e2SLinus Walleij 		return ret;
31497d642e2SLinus Walleij 	}
31597d642e2SLinus Walleij 
31697d642e2SLinus Walleij 	/* Interrupt on VOUT enabled */
31797d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_CON,
31897d642e2SLinus Walleij 			   GP2AP002_CON_OCON_ENABLE);
31997d642e2SLinus Walleij 	if (ret)
32097d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error setting up VOUT control\n");
32197d642e2SLinus Walleij 
32297d642e2SLinus Walleij 	return ret;
32397d642e2SLinus Walleij }
32497d642e2SLinus Walleij 
gp2ap002_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)32597d642e2SLinus Walleij static int gp2ap002_read_event_config(struct iio_dev *indio_dev,
32697d642e2SLinus Walleij 				      const struct iio_chan_spec *chan,
32797d642e2SLinus Walleij 				      enum iio_event_type type,
32897d642e2SLinus Walleij 				      enum iio_event_direction dir)
32997d642e2SLinus Walleij {
33097d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
33197d642e2SLinus Walleij 
33297d642e2SLinus Walleij 	/*
33397d642e2SLinus Walleij 	 * We just keep track of this internally, as it is not possible to
33497d642e2SLinus Walleij 	 * query the hardware.
33597d642e2SLinus Walleij 	 */
33697d642e2SLinus Walleij 	return gp2ap002->enabled;
33797d642e2SLinus Walleij }
33897d642e2SLinus Walleij 
gp2ap002_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,int state)33997d642e2SLinus Walleij static int gp2ap002_write_event_config(struct iio_dev *indio_dev,
34097d642e2SLinus Walleij 				       const struct iio_chan_spec *chan,
34197d642e2SLinus Walleij 				       enum iio_event_type type,
34297d642e2SLinus Walleij 				       enum iio_event_direction dir,
34397d642e2SLinus Walleij 				       int state)
34497d642e2SLinus Walleij {
34597d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
34697d642e2SLinus Walleij 
34797d642e2SLinus Walleij 	if (state) {
34897d642e2SLinus Walleij 		/*
34997d642e2SLinus Walleij 		 * This will bring the regulators up (unless they are on
35097d642e2SLinus Walleij 		 * already) and reintialize the sensor by using runtime_pm
35197d642e2SLinus Walleij 		 * callbacks.
35297d642e2SLinus Walleij 		 */
35397d642e2SLinus Walleij 		pm_runtime_get_sync(gp2ap002->dev);
35497d642e2SLinus Walleij 		gp2ap002->enabled = true;
35597d642e2SLinus Walleij 	} else {
35697d642e2SLinus Walleij 		pm_runtime_mark_last_busy(gp2ap002->dev);
35797d642e2SLinus Walleij 		pm_runtime_put_autosuspend(gp2ap002->dev);
35897d642e2SLinus Walleij 		gp2ap002->enabled = false;
35997d642e2SLinus Walleij 	}
36097d642e2SLinus Walleij 
36197d642e2SLinus Walleij 	return 0;
36297d642e2SLinus Walleij }
36397d642e2SLinus Walleij 
36497d642e2SLinus Walleij static const struct iio_info gp2ap002_info = {
36597d642e2SLinus Walleij 	.read_raw = gp2ap002_read_raw,
36697d642e2SLinus Walleij 	.read_event_config = gp2ap002_read_event_config,
36797d642e2SLinus Walleij 	.write_event_config = gp2ap002_write_event_config,
36897d642e2SLinus Walleij };
36997d642e2SLinus Walleij 
37097d642e2SLinus Walleij static const struct iio_event_spec gp2ap002_events[] = {
37197d642e2SLinus Walleij 	{
37297d642e2SLinus Walleij 		.type = IIO_EV_TYPE_THRESH,
37397d642e2SLinus Walleij 		.dir = IIO_EV_DIR_EITHER,
37497d642e2SLinus Walleij 		.mask_separate = BIT(IIO_EV_INFO_ENABLE),
37597d642e2SLinus Walleij 	},
37697d642e2SLinus Walleij };
37797d642e2SLinus Walleij 
37897d642e2SLinus Walleij static const struct iio_chan_spec gp2ap002_channels[] = {
37997d642e2SLinus Walleij 	{
38097d642e2SLinus Walleij 		.type = IIO_PROXIMITY,
38197d642e2SLinus Walleij 		.event_spec = gp2ap002_events,
38297d642e2SLinus Walleij 		.num_event_specs = ARRAY_SIZE(gp2ap002_events),
38397d642e2SLinus Walleij 	},
38497d642e2SLinus Walleij 	{
38597d642e2SLinus Walleij 		.type = IIO_LIGHT,
38697d642e2SLinus Walleij 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
38797d642e2SLinus Walleij 		.channel = GP2AP002_ALS_CHANNEL,
38897d642e2SLinus Walleij 	},
38997d642e2SLinus Walleij };
39097d642e2SLinus Walleij 
39197d642e2SLinus Walleij /*
39297d642e2SLinus Walleij  * We need a special regmap because this hardware expects to
39397d642e2SLinus Walleij  * write single bytes to registers but read a 16bit word on some
39497d642e2SLinus Walleij  * variants and discard the lower 8 bits so combine
39597d642e2SLinus Walleij  * i2c_smbus_read_word_data() with i2c_smbus_write_byte_data()
39697d642e2SLinus Walleij  * selectively like this.
39797d642e2SLinus Walleij  */
gp2ap002_regmap_i2c_read(void * context,unsigned int reg,unsigned int * val)39897d642e2SLinus Walleij static int gp2ap002_regmap_i2c_read(void *context, unsigned int reg,
39997d642e2SLinus Walleij 				    unsigned int *val)
40097d642e2SLinus Walleij {
40197d642e2SLinus Walleij 	struct device *dev = context;
40297d642e2SLinus Walleij 	struct i2c_client *i2c = to_i2c_client(dev);
40397d642e2SLinus Walleij 	int ret;
40497d642e2SLinus Walleij 
40597d642e2SLinus Walleij 	ret = i2c_smbus_read_word_data(i2c, reg);
40697d642e2SLinus Walleij 	if (ret < 0)
40797d642e2SLinus Walleij 		return ret;
40897d642e2SLinus Walleij 
40997d642e2SLinus Walleij 	*val = (ret >> 8) & 0xFF;
41097d642e2SLinus Walleij 
41197d642e2SLinus Walleij 	return 0;
41297d642e2SLinus Walleij }
41397d642e2SLinus Walleij 
gp2ap002_regmap_i2c_write(void * context,unsigned int reg,unsigned int val)41497d642e2SLinus Walleij static int gp2ap002_regmap_i2c_write(void *context, unsigned int reg,
41597d642e2SLinus Walleij 				     unsigned int val)
41697d642e2SLinus Walleij {
41797d642e2SLinus Walleij 	struct device *dev = context;
41897d642e2SLinus Walleij 	struct i2c_client *i2c = to_i2c_client(dev);
41997d642e2SLinus Walleij 
42097d642e2SLinus Walleij 	return i2c_smbus_write_byte_data(i2c, reg, val);
42197d642e2SLinus Walleij }
42297d642e2SLinus Walleij 
42397d642e2SLinus Walleij static struct regmap_bus gp2ap002_regmap_bus = {
42497d642e2SLinus Walleij 	.reg_read = gp2ap002_regmap_i2c_read,
42597d642e2SLinus Walleij 	.reg_write = gp2ap002_regmap_i2c_write,
42697d642e2SLinus Walleij };
42797d642e2SLinus Walleij 
gp2ap002_probe(struct i2c_client * client)428b3f8e22eSUwe Kleine-König static int gp2ap002_probe(struct i2c_client *client)
42997d642e2SLinus Walleij {
43097d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002;
43197d642e2SLinus Walleij 	struct iio_dev *indio_dev;
43297d642e2SLinus Walleij 	struct device *dev = &client->dev;
43397d642e2SLinus Walleij 	enum iio_chan_type ch_type;
43497d642e2SLinus Walleij 	static const struct regmap_config config = {
43597d642e2SLinus Walleij 		.reg_bits = 8,
43697d642e2SLinus Walleij 		.val_bits = 8,
43797d642e2SLinus Walleij 		.max_register = GP2AP002_CON,
43897d642e2SLinus Walleij 	};
43997d642e2SLinus Walleij 	struct regmap *regmap;
44097d642e2SLinus Walleij 	int num_chan;
44197d642e2SLinus Walleij 	const char *compat;
44297d642e2SLinus Walleij 	u8 val;
44397d642e2SLinus Walleij 	int ret;
44497d642e2SLinus Walleij 
44597d642e2SLinus Walleij 	indio_dev = devm_iio_device_alloc(dev, sizeof(*gp2ap002));
44697d642e2SLinus Walleij 	if (!indio_dev)
44797d642e2SLinus Walleij 		return -ENOMEM;
44897d642e2SLinus Walleij 	i2c_set_clientdata(client, indio_dev);
44997d642e2SLinus Walleij 
45097d642e2SLinus Walleij 	gp2ap002 = iio_priv(indio_dev);
45197d642e2SLinus Walleij 	gp2ap002->dev = dev;
45297d642e2SLinus Walleij 
45397d642e2SLinus Walleij 	/*
45497d642e2SLinus Walleij 	 * Check the device compatible like this makes it possible to use
45597d642e2SLinus Walleij 	 * ACPI PRP0001 for registering the sensor using device tree
45697d642e2SLinus Walleij 	 * properties.
45797d642e2SLinus Walleij 	 */
45897d642e2SLinus Walleij 	ret = device_property_read_string(dev, "compatible", &compat);
45997d642e2SLinus Walleij 	if (ret) {
46097d642e2SLinus Walleij 		dev_err(dev, "cannot check compatible\n");
46197d642e2SLinus Walleij 		return ret;
46297d642e2SLinus Walleij 	}
46397d642e2SLinus Walleij 	gp2ap002->is_gp2ap002s00f = !strcmp(compat, "sharp,gp2ap002s00f");
46497d642e2SLinus Walleij 
46597d642e2SLinus Walleij 	regmap = devm_regmap_init(dev, &gp2ap002_regmap_bus, dev, &config);
46697d642e2SLinus Walleij 	if (IS_ERR(regmap)) {
467941f6676SAndy Shevchenko 		dev_err(dev, "Failed to register i2c regmap %ld\n", PTR_ERR(regmap));
46897d642e2SLinus Walleij 		return PTR_ERR(regmap);
46997d642e2SLinus Walleij 	}
47097d642e2SLinus Walleij 	gp2ap002->map = regmap;
47197d642e2SLinus Walleij 
47297d642e2SLinus Walleij 	/*
47397d642e2SLinus Walleij 	 * The hysteresis settings are coded into the device tree as values
47497d642e2SLinus Walleij 	 * to be written into the hysteresis register. The datasheet defines
47597d642e2SLinus Walleij 	 * modes "A", "B1" and "B2" with fixed values to be use but vendor
47697d642e2SLinus Walleij 	 * code trees for actual devices are tweaking these values and refer to
47797d642e2SLinus Walleij 	 * modes named things like "B1.5". To be able to support any devices,
47897d642e2SLinus Walleij 	 * we allow passing an arbitrary hysteresis setting for "near" and
47997d642e2SLinus Walleij 	 * "far".
48097d642e2SLinus Walleij 	 */
48197d642e2SLinus Walleij 
48297d642e2SLinus Walleij 	/* Check the device tree for the IR LED hysteresis */
48397d642e2SLinus Walleij 	ret = device_property_read_u8(dev, "sharp,proximity-far-hysteresis",
48497d642e2SLinus Walleij 				      &val);
48597d642e2SLinus Walleij 	if (ret) {
48697d642e2SLinus Walleij 		dev_err(dev, "failed to obtain proximity far setting\n");
48797d642e2SLinus Walleij 		return ret;
48897d642e2SLinus Walleij 	}
48997d642e2SLinus Walleij 	dev_dbg(dev, "proximity far setting %02x\n", val);
49097d642e2SLinus Walleij 	gp2ap002->hys_far = val;
49197d642e2SLinus Walleij 
49297d642e2SLinus Walleij 	ret = device_property_read_u8(dev, "sharp,proximity-close-hysteresis",
49397d642e2SLinus Walleij 				      &val);
49497d642e2SLinus Walleij 	if (ret) {
49597d642e2SLinus Walleij 		dev_err(dev, "failed to obtain proximity close setting\n");
49697d642e2SLinus Walleij 		return ret;
49797d642e2SLinus Walleij 	}
49897d642e2SLinus Walleij 	dev_dbg(dev, "proximity close setting %02x\n", val);
49997d642e2SLinus Walleij 	gp2ap002->hys_close = val;
50097d642e2SLinus Walleij 
50197d642e2SLinus Walleij 	/* The GP2AP002A00F has a light sensor too */
50297d642e2SLinus Walleij 	if (!gp2ap002->is_gp2ap002s00f) {
50397d642e2SLinus Walleij 		gp2ap002->alsout = devm_iio_channel_get(dev, "alsout");
50497d642e2SLinus Walleij 		if (IS_ERR(gp2ap002->alsout)) {
50577b91b1cSCai Huoqing 			ret = PTR_ERR(gp2ap002->alsout);
50677b91b1cSCai Huoqing 			ret = (ret == -ENODEV) ? -EPROBE_DEFER : ret;
50777b91b1cSCai Huoqing 			return dev_err_probe(dev, ret, "failed to get ALSOUT ADC channel\n");
50897d642e2SLinus Walleij 		}
50997d642e2SLinus Walleij 		ret = iio_get_channel_type(gp2ap002->alsout, &ch_type);
51097d642e2SLinus Walleij 		if (ret < 0)
51197d642e2SLinus Walleij 			return ret;
51297d642e2SLinus Walleij 		if (ch_type != IIO_CURRENT) {
51397d642e2SLinus Walleij 			dev_err(dev,
51497d642e2SLinus Walleij 				"wrong type of IIO channel specified for ALSOUT\n");
51597d642e2SLinus Walleij 			return -EINVAL;
51697d642e2SLinus Walleij 		}
51797d642e2SLinus Walleij 	}
51897d642e2SLinus Walleij 
51997d642e2SLinus Walleij 	gp2ap002->vdd = devm_regulator_get(dev, "vdd");
52077b91b1cSCai Huoqing 	if (IS_ERR(gp2ap002->vdd))
52177b91b1cSCai Huoqing 		return dev_err_probe(dev, PTR_ERR(gp2ap002->vdd),
52277b91b1cSCai Huoqing 				     "failed to get VDD regulator\n");
52377b91b1cSCai Huoqing 
52497d642e2SLinus Walleij 	gp2ap002->vio = devm_regulator_get(dev, "vio");
52577b91b1cSCai Huoqing 	if (IS_ERR(gp2ap002->vio))
52677b91b1cSCai Huoqing 		return dev_err_probe(dev, PTR_ERR(gp2ap002->vio),
52777b91b1cSCai Huoqing 				     "failed to get VIO regulator\n");
52897d642e2SLinus Walleij 
52997d642e2SLinus Walleij 	/* Operating voltage 2.4V .. 3.6V according to datasheet */
53097d642e2SLinus Walleij 	ret = regulator_set_voltage(gp2ap002->vdd, 2400000, 3600000);
53197d642e2SLinus Walleij 	if (ret) {
53297d642e2SLinus Walleij 		dev_err(dev, "failed to sett VDD voltage\n");
53397d642e2SLinus Walleij 		return ret;
53497d642e2SLinus Walleij 	}
53597d642e2SLinus Walleij 
53697d642e2SLinus Walleij 	/* VIO should be between 1.65V and VDD */
53797d642e2SLinus Walleij 	ret = regulator_get_voltage(gp2ap002->vdd);
53897d642e2SLinus Walleij 	if (ret < 0) {
53997d642e2SLinus Walleij 		dev_err(dev, "failed to get VDD voltage\n");
54097d642e2SLinus Walleij 		return ret;
54197d642e2SLinus Walleij 	}
54297d642e2SLinus Walleij 	ret = regulator_set_voltage(gp2ap002->vio, 1650000, ret);
54397d642e2SLinus Walleij 	if (ret) {
54497d642e2SLinus Walleij 		dev_err(dev, "failed to set VIO voltage\n");
54597d642e2SLinus Walleij 		return ret;
54697d642e2SLinus Walleij 	}
54797d642e2SLinus Walleij 
54897d642e2SLinus Walleij 	ret = regulator_enable(gp2ap002->vdd);
54997d642e2SLinus Walleij 	if (ret) {
55097d642e2SLinus Walleij 		dev_err(dev, "failed to enable VDD regulator\n");
55197d642e2SLinus Walleij 		return ret;
55297d642e2SLinus Walleij 	}
55397d642e2SLinus Walleij 	ret = regulator_enable(gp2ap002->vio);
55497d642e2SLinus Walleij 	if (ret) {
55597d642e2SLinus Walleij 		dev_err(dev, "failed to enable VIO regulator\n");
55697d642e2SLinus Walleij 		goto out_disable_vdd;
55797d642e2SLinus Walleij 	}
55897d642e2SLinus Walleij 
55997d642e2SLinus Walleij 	msleep(20);
56097d642e2SLinus Walleij 
56197d642e2SLinus Walleij 	/*
56297d642e2SLinus Walleij 	 * Initialize the device and signal to runtime PM that now we are
5631f026587SWang Qing 	 * definitely up and using power.
56497d642e2SLinus Walleij 	 */
56597d642e2SLinus Walleij 	ret = gp2ap002_init(gp2ap002);
56697d642e2SLinus Walleij 	if (ret) {
56797d642e2SLinus Walleij 		dev_err(dev, "initialization failed\n");
56897d642e2SLinus Walleij 		goto out_disable_vio;
56997d642e2SLinus Walleij 	}
57097d642e2SLinus Walleij 	pm_runtime_get_noresume(dev);
57197d642e2SLinus Walleij 	pm_runtime_set_active(dev);
57297d642e2SLinus Walleij 	pm_runtime_enable(dev);
57397d642e2SLinus Walleij 	gp2ap002->enabled = false;
57497d642e2SLinus Walleij 
57597d642e2SLinus Walleij 	ret = devm_request_threaded_irq(dev, client->irq, NULL,
57697d642e2SLinus Walleij 					gp2ap002_prox_irq, IRQF_ONESHOT,
57797d642e2SLinus Walleij 					"gp2ap002", indio_dev);
57897d642e2SLinus Walleij 	if (ret) {
57997d642e2SLinus Walleij 		dev_err(dev, "unable to request IRQ\n");
5808edb79afSDinghao Liu 		goto out_put_pm;
58197d642e2SLinus Walleij 	}
58297d642e2SLinus Walleij 	gp2ap002->irq = client->irq;
58397d642e2SLinus Walleij 
58497d642e2SLinus Walleij 	/*
58597d642e2SLinus Walleij 	 * As the device takes 20 ms + regulator delay to come up with a fresh
58697d642e2SLinus Walleij 	 * measurement after power-on, do not shut it down unnecessarily.
58797d642e2SLinus Walleij 	 * Set autosuspend to a one second.
58897d642e2SLinus Walleij 	 */
58997d642e2SLinus Walleij 	pm_runtime_set_autosuspend_delay(dev, 1000);
59097d642e2SLinus Walleij 	pm_runtime_use_autosuspend(dev);
59197d642e2SLinus Walleij 	pm_runtime_put(dev);
59297d642e2SLinus Walleij 
59397d642e2SLinus Walleij 	indio_dev->info = &gp2ap002_info;
59497d642e2SLinus Walleij 	indio_dev->name = "gp2ap002";
59597d642e2SLinus Walleij 	indio_dev->channels = gp2ap002_channels;
59697d642e2SLinus Walleij 	/* Skip light channel for the proximity-only sensor */
59797d642e2SLinus Walleij 	num_chan = ARRAY_SIZE(gp2ap002_channels);
59897d642e2SLinus Walleij 	if (gp2ap002->is_gp2ap002s00f)
59997d642e2SLinus Walleij 		num_chan--;
60097d642e2SLinus Walleij 	indio_dev->num_channels = num_chan;
60197d642e2SLinus Walleij 	indio_dev->modes = INDIO_DIRECT_MODE;
60297d642e2SLinus Walleij 
60397d642e2SLinus Walleij 	ret = iio_device_register(indio_dev);
60497d642e2SLinus Walleij 	if (ret)
60597d642e2SLinus Walleij 		goto out_disable_pm;
60697d642e2SLinus Walleij 	dev_dbg(dev, "Sharp GP2AP002 probed successfully\n");
60797d642e2SLinus Walleij 
60897d642e2SLinus Walleij 	return 0;
60997d642e2SLinus Walleij 
6108edb79afSDinghao Liu out_put_pm:
61197d642e2SLinus Walleij 	pm_runtime_put_noidle(dev);
6128edb79afSDinghao Liu out_disable_pm:
61397d642e2SLinus Walleij 	pm_runtime_disable(dev);
61497d642e2SLinus Walleij out_disable_vio:
61597d642e2SLinus Walleij 	regulator_disable(gp2ap002->vio);
61697d642e2SLinus Walleij out_disable_vdd:
61797d642e2SLinus Walleij 	regulator_disable(gp2ap002->vdd);
61897d642e2SLinus Walleij 	return ret;
61997d642e2SLinus Walleij }
62097d642e2SLinus Walleij 
gp2ap002_remove(struct i2c_client * client)621ed5c2f5fSUwe Kleine-König static void gp2ap002_remove(struct i2c_client *client)
62297d642e2SLinus Walleij {
62397d642e2SLinus Walleij 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
62497d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
62597d642e2SLinus Walleij 	struct device *dev = &client->dev;
62697d642e2SLinus Walleij 
62797d642e2SLinus Walleij 	pm_runtime_get_sync(dev);
62897d642e2SLinus Walleij 	pm_runtime_put_noidle(dev);
62997d642e2SLinus Walleij 	pm_runtime_disable(dev);
63097d642e2SLinus Walleij 	iio_device_unregister(indio_dev);
63197d642e2SLinus Walleij 	regulator_disable(gp2ap002->vio);
63297d642e2SLinus Walleij 	regulator_disable(gp2ap002->vdd);
63397d642e2SLinus Walleij }
63497d642e2SLinus Walleij 
gp2ap002_runtime_suspend(struct device * dev)6357b79cda9SJonathan Cameron static int gp2ap002_runtime_suspend(struct device *dev)
63697d642e2SLinus Walleij {
63797d642e2SLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
63897d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
63997d642e2SLinus Walleij 	int ret;
64097d642e2SLinus Walleij 
64197d642e2SLinus Walleij 	/* Deactivate the IRQ */
64297d642e2SLinus Walleij 	disable_irq(gp2ap002->irq);
64397d642e2SLinus Walleij 
64497d642e2SLinus Walleij 	/* Disable chip and IRQ, everything off */
64597d642e2SLinus Walleij 	ret = regmap_write(gp2ap002->map, GP2AP002_OPMOD, 0x00);
64697d642e2SLinus Walleij 	if (ret) {
64797d642e2SLinus Walleij 		dev_err(gp2ap002->dev, "error setting up operation mode\n");
64897d642e2SLinus Walleij 		return ret;
64997d642e2SLinus Walleij 	}
65097d642e2SLinus Walleij 	/*
65197d642e2SLinus Walleij 	 * As these regulators may be shared, at least we are now in
65297d642e2SLinus Walleij 	 * sleep even if the regulators aren't really turned off.
65397d642e2SLinus Walleij 	 */
65497d642e2SLinus Walleij 	regulator_disable(gp2ap002->vio);
65597d642e2SLinus Walleij 	regulator_disable(gp2ap002->vdd);
65697d642e2SLinus Walleij 
65797d642e2SLinus Walleij 	return 0;
65897d642e2SLinus Walleij }
65997d642e2SLinus Walleij 
gp2ap002_runtime_resume(struct device * dev)6607b79cda9SJonathan Cameron static int gp2ap002_runtime_resume(struct device *dev)
66197d642e2SLinus Walleij {
66297d642e2SLinus Walleij 	struct iio_dev *indio_dev = dev_get_drvdata(dev);
66397d642e2SLinus Walleij 	struct gp2ap002 *gp2ap002 = iio_priv(indio_dev);
66497d642e2SLinus Walleij 	int ret;
66597d642e2SLinus Walleij 
66697d642e2SLinus Walleij 	ret = regulator_enable(gp2ap002->vdd);
66797d642e2SLinus Walleij 	if (ret) {
66897d642e2SLinus Walleij 		dev_err(dev, "failed to enable VDD regulator in resume path\n");
66997d642e2SLinus Walleij 		return ret;
67097d642e2SLinus Walleij 	}
67197d642e2SLinus Walleij 	ret = regulator_enable(gp2ap002->vio);
67297d642e2SLinus Walleij 	if (ret) {
67397d642e2SLinus Walleij 		dev_err(dev, "failed to enable VIO regulator in resume path\n");
67497d642e2SLinus Walleij 		return ret;
67597d642e2SLinus Walleij 	}
67697d642e2SLinus Walleij 
67797d642e2SLinus Walleij 	msleep(20);
67897d642e2SLinus Walleij 
67997d642e2SLinus Walleij 	ret = gp2ap002_init(gp2ap002);
68097d642e2SLinus Walleij 	if (ret) {
68197d642e2SLinus Walleij 		dev_err(dev, "re-initialization failed\n");
68297d642e2SLinus Walleij 		return ret;
68397d642e2SLinus Walleij 	}
68497d642e2SLinus Walleij 
68597d642e2SLinus Walleij 	/* Re-activate the IRQ */
68697d642e2SLinus Walleij 	enable_irq(gp2ap002->irq);
68797d642e2SLinus Walleij 
68897d642e2SLinus Walleij 	return 0;
68997d642e2SLinus Walleij }
69097d642e2SLinus Walleij 
6917b79cda9SJonathan Cameron static DEFINE_RUNTIME_DEV_PM_OPS(gp2ap002_dev_pm_ops, gp2ap002_runtime_suspend,
6927b79cda9SJonathan Cameron 				 gp2ap002_runtime_resume, NULL);
69397d642e2SLinus Walleij 
69497d642e2SLinus Walleij static const struct i2c_device_id gp2ap002_id_table[] = {
69597d642e2SLinus Walleij 	{ "gp2ap002", 0 },
69697d642e2SLinus Walleij 	{ },
69797d642e2SLinus Walleij };
69897d642e2SLinus Walleij MODULE_DEVICE_TABLE(i2c, gp2ap002_id_table);
69997d642e2SLinus Walleij 
70097d642e2SLinus Walleij static const struct of_device_id gp2ap002_of_match[] = {
70197d642e2SLinus Walleij 	{ .compatible = "sharp,gp2ap002a00f" },
70297d642e2SLinus Walleij 	{ .compatible = "sharp,gp2ap002s00f" },
70397d642e2SLinus Walleij 	{ },
70497d642e2SLinus Walleij };
70597d642e2SLinus Walleij MODULE_DEVICE_TABLE(of, gp2ap002_of_match);
70697d642e2SLinus Walleij 
70797d642e2SLinus Walleij static struct i2c_driver gp2ap002_driver = {
70897d642e2SLinus Walleij 	.driver = {
70997d642e2SLinus Walleij 		.name = "gp2ap002",
71097d642e2SLinus Walleij 		.of_match_table = gp2ap002_of_match,
7117b79cda9SJonathan Cameron 		.pm = pm_ptr(&gp2ap002_dev_pm_ops),
71297d642e2SLinus Walleij 	},
713*7cf15f42SUwe Kleine-König 	.probe = gp2ap002_probe,
71497d642e2SLinus Walleij 	.remove = gp2ap002_remove,
71597d642e2SLinus Walleij 	.id_table = gp2ap002_id_table,
71697d642e2SLinus Walleij };
71797d642e2SLinus Walleij module_i2c_driver(gp2ap002_driver);
71897d642e2SLinus Walleij 
71997d642e2SLinus Walleij MODULE_AUTHOR("Linus Walleij <linus.walleij@linaro.org>");
72097d642e2SLinus Walleij MODULE_DESCRIPTION("GP2AP002 ambient light and proximity sensor driver");
72197d642e2SLinus Walleij MODULE_LICENSE("GPL v2");
722