xref: /OK3568_Linux_fs/kernel/drivers/iio/light/vcnl4035.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * VCNL4035 Ambient Light and Proximity Sensor - 7-bit I2C slave address 0x60
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (c) 2018, DENX Software Engineering GmbH
6*4882a593Smuzhiyun  * Author: Parthiban Nallathambi <pn@denx.de>
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  * TODO: Proximity
9*4882a593Smuzhiyun  */
10*4882a593Smuzhiyun #include <linux/bitops.h>
11*4882a593Smuzhiyun #include <linux/i2c.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/pm_runtime.h>
14*4882a593Smuzhiyun #include <linux/regmap.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include <linux/iio/buffer.h>
17*4882a593Smuzhiyun #include <linux/iio/events.h>
18*4882a593Smuzhiyun #include <linux/iio/iio.h>
19*4882a593Smuzhiyun #include <linux/iio/sysfs.h>
20*4882a593Smuzhiyun #include <linux/iio/trigger.h>
21*4882a593Smuzhiyun #include <linux/iio/trigger_consumer.h>
22*4882a593Smuzhiyun #include <linux/iio/triggered_buffer.h>
23*4882a593Smuzhiyun 
24*4882a593Smuzhiyun #define VCNL4035_DRV_NAME	"vcnl4035"
25*4882a593Smuzhiyun #define VCNL4035_IRQ_NAME	"vcnl4035_event"
26*4882a593Smuzhiyun #define VCNL4035_REGMAP_NAME	"vcnl4035_regmap"
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun /* Device registers */
29*4882a593Smuzhiyun #define VCNL4035_ALS_CONF	0x00
30*4882a593Smuzhiyun #define VCNL4035_ALS_THDH	0x01
31*4882a593Smuzhiyun #define VCNL4035_ALS_THDL	0x02
32*4882a593Smuzhiyun #define VCNL4035_ALS_DATA	0x0B
33*4882a593Smuzhiyun #define VCNL4035_WHITE_DATA	0x0C
34*4882a593Smuzhiyun #define VCNL4035_INT_FLAG	0x0D
35*4882a593Smuzhiyun #define VCNL4035_DEV_ID		0x0E
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun /* Register masks */
38*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_MASK		BIT(0)
39*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_WHITE_CHAN	BIT(8)
40*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_INT_MASK	BIT(1)
41*4882a593Smuzhiyun #define VCNL4035_ALS_IT_MASK		GENMASK(7, 5)
42*4882a593Smuzhiyun #define VCNL4035_ALS_PERS_MASK		GENMASK(3, 2)
43*4882a593Smuzhiyun #define VCNL4035_INT_ALS_IF_H_MASK	BIT(12)
44*4882a593Smuzhiyun #define VCNL4035_INT_ALS_IF_L_MASK	BIT(13)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun /* Default values */
47*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_ENABLE	BIT(0)
48*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_DISABLE	0x00
49*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_INT_ENABLE	BIT(1)
50*4882a593Smuzhiyun #define VCNL4035_MODE_ALS_INT_DISABLE	0
51*4882a593Smuzhiyun #define VCNL4035_DEV_ID_VAL		0x80
52*4882a593Smuzhiyun #define VCNL4035_ALS_IT_DEFAULT		0x01
53*4882a593Smuzhiyun #define VCNL4035_ALS_PERS_DEFAULT	0x00
54*4882a593Smuzhiyun #define VCNL4035_ALS_THDH_DEFAULT	5000
55*4882a593Smuzhiyun #define VCNL4035_ALS_THDL_DEFAULT	100
56*4882a593Smuzhiyun #define VCNL4035_SLEEP_DELAY_MS		2000
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun struct vcnl4035_data {
59*4882a593Smuzhiyun 	struct i2c_client *client;
60*4882a593Smuzhiyun 	struct regmap *regmap;
61*4882a593Smuzhiyun 	unsigned int als_it_val;
62*4882a593Smuzhiyun 	unsigned int als_persistence;
63*4882a593Smuzhiyun 	unsigned int als_thresh_low;
64*4882a593Smuzhiyun 	unsigned int als_thresh_high;
65*4882a593Smuzhiyun 	struct iio_trigger *drdy_trigger0;
66*4882a593Smuzhiyun };
67*4882a593Smuzhiyun 
vcnl4035_is_triggered(struct vcnl4035_data * data)68*4882a593Smuzhiyun static inline bool vcnl4035_is_triggered(struct vcnl4035_data *data)
69*4882a593Smuzhiyun {
70*4882a593Smuzhiyun 	int ret;
71*4882a593Smuzhiyun 	int reg;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, VCNL4035_INT_FLAG, &reg);
74*4882a593Smuzhiyun 	if (ret < 0)
75*4882a593Smuzhiyun 		return false;
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	return !!(reg &
78*4882a593Smuzhiyun 		(VCNL4035_INT_ALS_IF_H_MASK | VCNL4035_INT_ALS_IF_L_MASK));
79*4882a593Smuzhiyun }
80*4882a593Smuzhiyun 
vcnl4035_drdy_irq_thread(int irq,void * private)81*4882a593Smuzhiyun static irqreturn_t vcnl4035_drdy_irq_thread(int irq, void *private)
82*4882a593Smuzhiyun {
83*4882a593Smuzhiyun 	struct iio_dev *indio_dev = private;
84*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	if (vcnl4035_is_triggered(data)) {
87*4882a593Smuzhiyun 		iio_push_event(indio_dev, IIO_UNMOD_EVENT_CODE(IIO_LIGHT,
88*4882a593Smuzhiyun 							0,
89*4882a593Smuzhiyun 							IIO_EV_TYPE_THRESH,
90*4882a593Smuzhiyun 							IIO_EV_DIR_EITHER),
91*4882a593Smuzhiyun 				iio_get_time_ns(indio_dev));
92*4882a593Smuzhiyun 		iio_trigger_poll_chained(data->drdy_trigger0);
93*4882a593Smuzhiyun 		return IRQ_HANDLED;
94*4882a593Smuzhiyun 	}
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	return IRQ_NONE;
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
99*4882a593Smuzhiyun /* Triggered buffer */
vcnl4035_trigger_consumer_handler(int irq,void * p)100*4882a593Smuzhiyun static irqreturn_t vcnl4035_trigger_consumer_handler(int irq, void *p)
101*4882a593Smuzhiyun {
102*4882a593Smuzhiyun 	struct iio_poll_func *pf = p;
103*4882a593Smuzhiyun 	struct iio_dev *indio_dev = pf->indio_dev;
104*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
105*4882a593Smuzhiyun 	/* Ensure naturally aligned timestamp */
106*4882a593Smuzhiyun 	u8 buffer[ALIGN(sizeof(u16), sizeof(s64)) + sizeof(s64)]  __aligned(8);
107*4882a593Smuzhiyun 	int ret;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, VCNL4035_ALS_DATA, (int *)buffer);
110*4882a593Smuzhiyun 	if (ret < 0) {
111*4882a593Smuzhiyun 		dev_err(&data->client->dev,
112*4882a593Smuzhiyun 			"Trigger consumer can't read from sensor.\n");
113*4882a593Smuzhiyun 		goto fail_read;
114*4882a593Smuzhiyun 	}
115*4882a593Smuzhiyun 	iio_push_to_buffers_with_timestamp(indio_dev, buffer,
116*4882a593Smuzhiyun 					iio_get_time_ns(indio_dev));
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun fail_read:
119*4882a593Smuzhiyun 	iio_trigger_notify_done(indio_dev->trig);
120*4882a593Smuzhiyun 
121*4882a593Smuzhiyun 	return IRQ_HANDLED;
122*4882a593Smuzhiyun }
123*4882a593Smuzhiyun 
vcnl4035_als_drdy_set_state(struct iio_trigger * trigger,bool enable_drdy)124*4882a593Smuzhiyun static int vcnl4035_als_drdy_set_state(struct iio_trigger *trigger,
125*4882a593Smuzhiyun 					bool enable_drdy)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct iio_dev *indio_dev = iio_trigger_get_drvdata(trigger);
128*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
129*4882a593Smuzhiyun 	int val = enable_drdy ? VCNL4035_MODE_ALS_INT_ENABLE :
130*4882a593Smuzhiyun 					VCNL4035_MODE_ALS_INT_DISABLE;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
133*4882a593Smuzhiyun 				 VCNL4035_MODE_ALS_INT_MASK,
134*4882a593Smuzhiyun 				 val);
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun static const struct iio_trigger_ops vcnl4035_trigger_ops = {
138*4882a593Smuzhiyun 	.validate_device = iio_trigger_validate_own_device,
139*4882a593Smuzhiyun 	.set_trigger_state = vcnl4035_als_drdy_set_state,
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun 
vcnl4035_set_pm_runtime_state(struct vcnl4035_data * data,bool on)142*4882a593Smuzhiyun static int vcnl4035_set_pm_runtime_state(struct vcnl4035_data *data, bool on)
143*4882a593Smuzhiyun {
144*4882a593Smuzhiyun 	int ret;
145*4882a593Smuzhiyun 	struct device *dev = &data->client->dev;
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 	if (on) {
148*4882a593Smuzhiyun 		ret = pm_runtime_get_sync(dev);
149*4882a593Smuzhiyun 		if (ret < 0)
150*4882a593Smuzhiyun 			pm_runtime_put_noidle(dev);
151*4882a593Smuzhiyun 	} else {
152*4882a593Smuzhiyun 		pm_runtime_mark_last_busy(dev);
153*4882a593Smuzhiyun 		ret = pm_runtime_put_autosuspend(dev);
154*4882a593Smuzhiyun 	}
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	return ret;
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun /*
160*4882a593Smuzhiyun  *	Device IT	INT Time (ms)	Scale (lux/step)
161*4882a593Smuzhiyun  *	000		50		0.064
162*4882a593Smuzhiyun  *	001		100		0.032
163*4882a593Smuzhiyun  *	010		200		0.016
164*4882a593Smuzhiyun  *	100		400		0.008
165*4882a593Smuzhiyun  *	101 - 111	800		0.004
166*4882a593Smuzhiyun  * Values are proportional, so ALS INT is selected for input due to
167*4882a593Smuzhiyun  * simplicity reason. Integration time value and scaling is
168*4882a593Smuzhiyun  * calculated based on device INT value
169*4882a593Smuzhiyun  *
170*4882a593Smuzhiyun  * Raw value needs to be scaled using ALS steps
171*4882a593Smuzhiyun  */
vcnl4035_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)172*4882a593Smuzhiyun static int vcnl4035_read_raw(struct iio_dev *indio_dev,
173*4882a593Smuzhiyun 			    struct iio_chan_spec const *chan, int *val,
174*4882a593Smuzhiyun 			    int *val2, long mask)
175*4882a593Smuzhiyun {
176*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
177*4882a593Smuzhiyun 	int ret;
178*4882a593Smuzhiyun 	int raw_data;
179*4882a593Smuzhiyun 	unsigned int reg;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	switch (mask) {
182*4882a593Smuzhiyun 	case IIO_CHAN_INFO_RAW:
183*4882a593Smuzhiyun 		ret = vcnl4035_set_pm_runtime_state(data, true);
184*4882a593Smuzhiyun 		if  (ret < 0)
185*4882a593Smuzhiyun 			return ret;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 		ret = iio_device_claim_direct_mode(indio_dev);
188*4882a593Smuzhiyun 		if (!ret) {
189*4882a593Smuzhiyun 			if (chan->channel)
190*4882a593Smuzhiyun 				reg = VCNL4035_ALS_DATA;
191*4882a593Smuzhiyun 			else
192*4882a593Smuzhiyun 				reg = VCNL4035_WHITE_DATA;
193*4882a593Smuzhiyun 			ret = regmap_read(data->regmap, reg, &raw_data);
194*4882a593Smuzhiyun 			iio_device_release_direct_mode(indio_dev);
195*4882a593Smuzhiyun 			if (!ret) {
196*4882a593Smuzhiyun 				*val = raw_data;
197*4882a593Smuzhiyun 				ret = IIO_VAL_INT;
198*4882a593Smuzhiyun 			}
199*4882a593Smuzhiyun 		}
200*4882a593Smuzhiyun 		vcnl4035_set_pm_runtime_state(data, false);
201*4882a593Smuzhiyun 		return ret;
202*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
203*4882a593Smuzhiyun 		*val = 50;
204*4882a593Smuzhiyun 		if (data->als_it_val)
205*4882a593Smuzhiyun 			*val = data->als_it_val * 100;
206*4882a593Smuzhiyun 		return IIO_VAL_INT;
207*4882a593Smuzhiyun 	case IIO_CHAN_INFO_SCALE:
208*4882a593Smuzhiyun 		*val = 64;
209*4882a593Smuzhiyun 		if (!data->als_it_val)
210*4882a593Smuzhiyun 			*val2 = 1000;
211*4882a593Smuzhiyun 		else
212*4882a593Smuzhiyun 			*val2 = data->als_it_val * 2 * 1000;
213*4882a593Smuzhiyun 		return IIO_VAL_FRACTIONAL;
214*4882a593Smuzhiyun 	default:
215*4882a593Smuzhiyun 		return -EINVAL;
216*4882a593Smuzhiyun 	}
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
vcnl4035_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)219*4882a593Smuzhiyun static int vcnl4035_write_raw(struct iio_dev *indio_dev,
220*4882a593Smuzhiyun 				struct iio_chan_spec const *chan,
221*4882a593Smuzhiyun 				int val, int val2, long mask)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun 	int ret;
224*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	switch (mask) {
227*4882a593Smuzhiyun 	case IIO_CHAN_INFO_INT_TIME:
228*4882a593Smuzhiyun 		if (val <= 0 || val > 800)
229*4882a593Smuzhiyun 			return -EINVAL;
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun 		ret = vcnl4035_set_pm_runtime_state(data, true);
232*4882a593Smuzhiyun 		if  (ret < 0)
233*4882a593Smuzhiyun 			return ret;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
236*4882a593Smuzhiyun 					 VCNL4035_ALS_IT_MASK,
237*4882a593Smuzhiyun 					 val / 100);
238*4882a593Smuzhiyun 		if (!ret)
239*4882a593Smuzhiyun 			data->als_it_val = val / 100;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 		vcnl4035_set_pm_runtime_state(data, false);
242*4882a593Smuzhiyun 		return ret;
243*4882a593Smuzhiyun 	default:
244*4882a593Smuzhiyun 		return -EINVAL;
245*4882a593Smuzhiyun 	}
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun /* No direct ABI for persistence and threshold, so eventing */
vcnl4035_read_thresh(struct iio_dev * indio_dev,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)249*4882a593Smuzhiyun static int vcnl4035_read_thresh(struct iio_dev *indio_dev,
250*4882a593Smuzhiyun 		const struct iio_chan_spec *chan, enum iio_event_type type,
251*4882a593Smuzhiyun 		enum iio_event_direction dir, enum iio_event_info info,
252*4882a593Smuzhiyun 		int *val, int *val2)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	switch (info) {
257*4882a593Smuzhiyun 	case IIO_EV_INFO_VALUE:
258*4882a593Smuzhiyun 		switch (dir) {
259*4882a593Smuzhiyun 		case IIO_EV_DIR_RISING:
260*4882a593Smuzhiyun 			*val = data->als_thresh_high;
261*4882a593Smuzhiyun 			return IIO_VAL_INT;
262*4882a593Smuzhiyun 		case IIO_EV_DIR_FALLING:
263*4882a593Smuzhiyun 			*val = data->als_thresh_low;
264*4882a593Smuzhiyun 			return IIO_VAL_INT;
265*4882a593Smuzhiyun 		default:
266*4882a593Smuzhiyun 			return -EINVAL;
267*4882a593Smuzhiyun 		}
268*4882a593Smuzhiyun 		break;
269*4882a593Smuzhiyun 	case IIO_EV_INFO_PERIOD:
270*4882a593Smuzhiyun 		*val = data->als_persistence;
271*4882a593Smuzhiyun 		return IIO_VAL_INT;
272*4882a593Smuzhiyun 	default:
273*4882a593Smuzhiyun 		return -EINVAL;
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun 
vcnl4035_write_thresh(struct iio_dev * indio_dev,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)278*4882a593Smuzhiyun static int vcnl4035_write_thresh(struct iio_dev *indio_dev,
279*4882a593Smuzhiyun 		const struct iio_chan_spec *chan, enum iio_event_type type,
280*4882a593Smuzhiyun 		enum iio_event_direction dir, enum iio_event_info info, int val,
281*4882a593Smuzhiyun 		int val2)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
284*4882a593Smuzhiyun 	int ret;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	switch (info) {
287*4882a593Smuzhiyun 	case IIO_EV_INFO_VALUE:
288*4882a593Smuzhiyun 		/* 16 bit threshold range 0 - 65535 */
289*4882a593Smuzhiyun 		if (val < 0 || val > 65535)
290*4882a593Smuzhiyun 			return -EINVAL;
291*4882a593Smuzhiyun 		if (dir == IIO_EV_DIR_RISING) {
292*4882a593Smuzhiyun 			if (val < data->als_thresh_low)
293*4882a593Smuzhiyun 				return -EINVAL;
294*4882a593Smuzhiyun 			ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
295*4882a593Smuzhiyun 					   val);
296*4882a593Smuzhiyun 			if (ret)
297*4882a593Smuzhiyun 				return ret;
298*4882a593Smuzhiyun 			data->als_thresh_high = val;
299*4882a593Smuzhiyun 		} else {
300*4882a593Smuzhiyun 			if (val > data->als_thresh_high)
301*4882a593Smuzhiyun 				return -EINVAL;
302*4882a593Smuzhiyun 			ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
303*4882a593Smuzhiyun 					   val);
304*4882a593Smuzhiyun 			if (ret)
305*4882a593Smuzhiyun 				return ret;
306*4882a593Smuzhiyun 			data->als_thresh_low = val;
307*4882a593Smuzhiyun 		}
308*4882a593Smuzhiyun 		return ret;
309*4882a593Smuzhiyun 	case IIO_EV_INFO_PERIOD:
310*4882a593Smuzhiyun 		/* allow only 1 2 4 8 as persistence value */
311*4882a593Smuzhiyun 		if (val < 0 || val > 8 || hweight8(val) != 1)
312*4882a593Smuzhiyun 			return -EINVAL;
313*4882a593Smuzhiyun 		ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
314*4882a593Smuzhiyun 					 VCNL4035_ALS_PERS_MASK, val);
315*4882a593Smuzhiyun 		if (!ret)
316*4882a593Smuzhiyun 			data->als_persistence = val;
317*4882a593Smuzhiyun 		return ret;
318*4882a593Smuzhiyun 	default:
319*4882a593Smuzhiyun 		return -EINVAL;
320*4882a593Smuzhiyun 	}
321*4882a593Smuzhiyun }
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun static IIO_CONST_ATTR_INT_TIME_AVAIL("50 100 200 400 800");
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun static struct attribute *vcnl4035_attributes[] = {
326*4882a593Smuzhiyun 	&iio_const_attr_integration_time_available.dev_attr.attr,
327*4882a593Smuzhiyun 	NULL,
328*4882a593Smuzhiyun };
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun static const struct attribute_group vcnl4035_attribute_group = {
331*4882a593Smuzhiyun 	.attrs = vcnl4035_attributes,
332*4882a593Smuzhiyun };
333*4882a593Smuzhiyun 
334*4882a593Smuzhiyun static const struct iio_info vcnl4035_info = {
335*4882a593Smuzhiyun 	.read_raw		= vcnl4035_read_raw,
336*4882a593Smuzhiyun 	.write_raw		= vcnl4035_write_raw,
337*4882a593Smuzhiyun 	.read_event_value	= vcnl4035_read_thresh,
338*4882a593Smuzhiyun 	.write_event_value	= vcnl4035_write_thresh,
339*4882a593Smuzhiyun 	.attrs			= &vcnl4035_attribute_group,
340*4882a593Smuzhiyun };
341*4882a593Smuzhiyun 
342*4882a593Smuzhiyun static const struct iio_event_spec vcnl4035_event_spec[] = {
343*4882a593Smuzhiyun 	{
344*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_THRESH,
345*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_RISING,
346*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE),
347*4882a593Smuzhiyun 	}, {
348*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_THRESH,
349*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_FALLING,
350*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_VALUE),
351*4882a593Smuzhiyun 	}, {
352*4882a593Smuzhiyun 		.type = IIO_EV_TYPE_THRESH,
353*4882a593Smuzhiyun 		.dir = IIO_EV_DIR_EITHER,
354*4882a593Smuzhiyun 		.mask_separate = BIT(IIO_EV_INFO_PERIOD),
355*4882a593Smuzhiyun 	},
356*4882a593Smuzhiyun };
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun enum vcnl4035_scan_index_order {
359*4882a593Smuzhiyun 	VCNL4035_CHAN_INDEX_LIGHT,
360*4882a593Smuzhiyun 	VCNL4035_CHAN_INDEX_WHITE_LED,
361*4882a593Smuzhiyun };
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
364*4882a593Smuzhiyun 	.validate_scan_mask = &iio_validate_scan_mask_onehot,
365*4882a593Smuzhiyun };
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun static const struct iio_chan_spec vcnl4035_channels[] = {
368*4882a593Smuzhiyun 	{
369*4882a593Smuzhiyun 		.type = IIO_LIGHT,
370*4882a593Smuzhiyun 		.channel = 0,
371*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
372*4882a593Smuzhiyun 				BIT(IIO_CHAN_INFO_INT_TIME) |
373*4882a593Smuzhiyun 				BIT(IIO_CHAN_INFO_SCALE),
374*4882a593Smuzhiyun 		.event_spec = vcnl4035_event_spec,
375*4882a593Smuzhiyun 		.num_event_specs = ARRAY_SIZE(vcnl4035_event_spec),
376*4882a593Smuzhiyun 		.scan_index = VCNL4035_CHAN_INDEX_LIGHT,
377*4882a593Smuzhiyun 		.scan_type = {
378*4882a593Smuzhiyun 			.sign = 'u',
379*4882a593Smuzhiyun 			.realbits = 16,
380*4882a593Smuzhiyun 			.storagebits = 16,
381*4882a593Smuzhiyun 			.endianness = IIO_LE,
382*4882a593Smuzhiyun 		},
383*4882a593Smuzhiyun 	},
384*4882a593Smuzhiyun 	{
385*4882a593Smuzhiyun 		.type = IIO_INTENSITY,
386*4882a593Smuzhiyun 		.channel = 1,
387*4882a593Smuzhiyun 		.modified = 1,
388*4882a593Smuzhiyun 		.channel2 = IIO_MOD_LIGHT_BOTH,
389*4882a593Smuzhiyun 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
390*4882a593Smuzhiyun 		.scan_index = VCNL4035_CHAN_INDEX_WHITE_LED,
391*4882a593Smuzhiyun 		.scan_type = {
392*4882a593Smuzhiyun 			.sign = 'u',
393*4882a593Smuzhiyun 			.realbits = 16,
394*4882a593Smuzhiyun 			.storagebits = 16,
395*4882a593Smuzhiyun 			.endianness = IIO_LE,
396*4882a593Smuzhiyun 		},
397*4882a593Smuzhiyun 	},
398*4882a593Smuzhiyun };
399*4882a593Smuzhiyun 
vcnl4035_set_als_power_state(struct vcnl4035_data * data,u8 status)400*4882a593Smuzhiyun static int vcnl4035_set_als_power_state(struct vcnl4035_data *data, u8 status)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	return regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
403*4882a593Smuzhiyun 					VCNL4035_MODE_ALS_MASK,
404*4882a593Smuzhiyun 					status);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun 
vcnl4035_init(struct vcnl4035_data * data)407*4882a593Smuzhiyun static int vcnl4035_init(struct vcnl4035_data *data)
408*4882a593Smuzhiyun {
409*4882a593Smuzhiyun 	int ret;
410*4882a593Smuzhiyun 	int id;
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	ret = regmap_read(data->regmap, VCNL4035_DEV_ID, &id);
413*4882a593Smuzhiyun 	if (ret < 0) {
414*4882a593Smuzhiyun 		dev_err(&data->client->dev, "Failed to read DEV_ID register\n");
415*4882a593Smuzhiyun 		return ret;
416*4882a593Smuzhiyun 	}
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	if (id != VCNL4035_DEV_ID_VAL) {
419*4882a593Smuzhiyun 		dev_err(&data->client->dev, "Wrong id, got %x, expected %x\n",
420*4882a593Smuzhiyun 			id, VCNL4035_DEV_ID_VAL);
421*4882a593Smuzhiyun 		return -ENODEV;
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
425*4882a593Smuzhiyun 	if (ret < 0)
426*4882a593Smuzhiyun 		return ret;
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun 	/* ALS white channel enable */
429*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
430*4882a593Smuzhiyun 				 VCNL4035_MODE_ALS_WHITE_CHAN,
431*4882a593Smuzhiyun 				 1);
432*4882a593Smuzhiyun 	if (ret) {
433*4882a593Smuzhiyun 		dev_err(&data->client->dev, "set white channel enable %d\n",
434*4882a593Smuzhiyun 			ret);
435*4882a593Smuzhiyun 		return ret;
436*4882a593Smuzhiyun 	}
437*4882a593Smuzhiyun 
438*4882a593Smuzhiyun 	/* set default integration time - 100 ms for ALS */
439*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
440*4882a593Smuzhiyun 				 VCNL4035_ALS_IT_MASK,
441*4882a593Smuzhiyun 				 VCNL4035_ALS_IT_DEFAULT);
442*4882a593Smuzhiyun 	if (ret) {
443*4882a593Smuzhiyun 		dev_err(&data->client->dev, "set default ALS IT returned %d\n",
444*4882a593Smuzhiyun 			ret);
445*4882a593Smuzhiyun 		return ret;
446*4882a593Smuzhiyun 	}
447*4882a593Smuzhiyun 	data->als_it_val = VCNL4035_ALS_IT_DEFAULT;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	/* set default persistence time - 1 for ALS */
450*4882a593Smuzhiyun 	ret = regmap_update_bits(data->regmap, VCNL4035_ALS_CONF,
451*4882a593Smuzhiyun 				 VCNL4035_ALS_PERS_MASK,
452*4882a593Smuzhiyun 				 VCNL4035_ALS_PERS_DEFAULT);
453*4882a593Smuzhiyun 	if (ret) {
454*4882a593Smuzhiyun 		dev_err(&data->client->dev, "set default PERS returned %d\n",
455*4882a593Smuzhiyun 			ret);
456*4882a593Smuzhiyun 		return ret;
457*4882a593Smuzhiyun 	}
458*4882a593Smuzhiyun 	data->als_persistence = VCNL4035_ALS_PERS_DEFAULT;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	/* set default HIGH threshold for ALS */
461*4882a593Smuzhiyun 	ret = regmap_write(data->regmap, VCNL4035_ALS_THDH,
462*4882a593Smuzhiyun 				VCNL4035_ALS_THDH_DEFAULT);
463*4882a593Smuzhiyun 	if (ret) {
464*4882a593Smuzhiyun 		dev_err(&data->client->dev, "set default THDH returned %d\n",
465*4882a593Smuzhiyun 			ret);
466*4882a593Smuzhiyun 		return ret;
467*4882a593Smuzhiyun 	}
468*4882a593Smuzhiyun 	data->als_thresh_high = VCNL4035_ALS_THDH_DEFAULT;
469*4882a593Smuzhiyun 
470*4882a593Smuzhiyun 	/* set default LOW threshold for ALS */
471*4882a593Smuzhiyun 	ret = regmap_write(data->regmap, VCNL4035_ALS_THDL,
472*4882a593Smuzhiyun 				VCNL4035_ALS_THDL_DEFAULT);
473*4882a593Smuzhiyun 	if (ret) {
474*4882a593Smuzhiyun 		dev_err(&data->client->dev, "set default THDL returned %d\n",
475*4882a593Smuzhiyun 			ret);
476*4882a593Smuzhiyun 		return ret;
477*4882a593Smuzhiyun 	}
478*4882a593Smuzhiyun 	data->als_thresh_low = VCNL4035_ALS_THDL_DEFAULT;
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun 	return 0;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun 
vcnl4035_is_volatile_reg(struct device * dev,unsigned int reg)483*4882a593Smuzhiyun static bool vcnl4035_is_volatile_reg(struct device *dev, unsigned int reg)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun 	switch (reg) {
486*4882a593Smuzhiyun 	case VCNL4035_ALS_CONF:
487*4882a593Smuzhiyun 	case VCNL4035_DEV_ID:
488*4882a593Smuzhiyun 		return false;
489*4882a593Smuzhiyun 	default:
490*4882a593Smuzhiyun 		return true;
491*4882a593Smuzhiyun 	}
492*4882a593Smuzhiyun }
493*4882a593Smuzhiyun 
494*4882a593Smuzhiyun static const struct regmap_config vcnl4035_regmap_config = {
495*4882a593Smuzhiyun 	.name		= VCNL4035_REGMAP_NAME,
496*4882a593Smuzhiyun 	.reg_bits	= 8,
497*4882a593Smuzhiyun 	.val_bits	= 16,
498*4882a593Smuzhiyun 	.max_register	= VCNL4035_DEV_ID,
499*4882a593Smuzhiyun 	.cache_type	= REGCACHE_RBTREE,
500*4882a593Smuzhiyun 	.volatile_reg	= vcnl4035_is_volatile_reg,
501*4882a593Smuzhiyun 	.val_format_endian = REGMAP_ENDIAN_LITTLE,
502*4882a593Smuzhiyun };
503*4882a593Smuzhiyun 
vcnl4035_probe_trigger(struct iio_dev * indio_dev)504*4882a593Smuzhiyun static int vcnl4035_probe_trigger(struct iio_dev *indio_dev)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun 	int ret;
507*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
508*4882a593Smuzhiyun 
509*4882a593Smuzhiyun 	data->drdy_trigger0 = devm_iio_trigger_alloc(
510*4882a593Smuzhiyun 			indio_dev->dev.parent,
511*4882a593Smuzhiyun 			"%s-dev%d", indio_dev->name, indio_dev->id);
512*4882a593Smuzhiyun 	if (!data->drdy_trigger0)
513*4882a593Smuzhiyun 		return -ENOMEM;
514*4882a593Smuzhiyun 
515*4882a593Smuzhiyun 	data->drdy_trigger0->dev.parent = indio_dev->dev.parent;
516*4882a593Smuzhiyun 	data->drdy_trigger0->ops = &vcnl4035_trigger_ops;
517*4882a593Smuzhiyun 	iio_trigger_set_drvdata(data->drdy_trigger0, indio_dev);
518*4882a593Smuzhiyun 	ret = devm_iio_trigger_register(indio_dev->dev.parent,
519*4882a593Smuzhiyun 					data->drdy_trigger0);
520*4882a593Smuzhiyun 	if (ret) {
521*4882a593Smuzhiyun 		dev_err(&data->client->dev, "iio trigger register failed\n");
522*4882a593Smuzhiyun 		return ret;
523*4882a593Smuzhiyun 	}
524*4882a593Smuzhiyun 
525*4882a593Smuzhiyun 	/* Trigger setup */
526*4882a593Smuzhiyun 	ret = devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev,
527*4882a593Smuzhiyun 					NULL, vcnl4035_trigger_consumer_handler,
528*4882a593Smuzhiyun 					&iio_triggered_buffer_setup_ops);
529*4882a593Smuzhiyun 	if (ret < 0) {
530*4882a593Smuzhiyun 		dev_err(&data->client->dev, "iio triggered buffer setup failed\n");
531*4882a593Smuzhiyun 		return ret;
532*4882a593Smuzhiyun 	}
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun 	/* IRQ to trigger mapping */
535*4882a593Smuzhiyun 	ret = devm_request_threaded_irq(&data->client->dev, data->client->irq,
536*4882a593Smuzhiyun 			NULL, vcnl4035_drdy_irq_thread,
537*4882a593Smuzhiyun 			IRQF_TRIGGER_LOW | IRQF_ONESHOT,
538*4882a593Smuzhiyun 			VCNL4035_IRQ_NAME, indio_dev);
539*4882a593Smuzhiyun 	if (ret < 0)
540*4882a593Smuzhiyun 		dev_err(&data->client->dev, "request irq %d for trigger0 failed\n",
541*4882a593Smuzhiyun 				data->client->irq);
542*4882a593Smuzhiyun 	return ret;
543*4882a593Smuzhiyun }
544*4882a593Smuzhiyun 
vcnl4035_probe(struct i2c_client * client,const struct i2c_device_id * id)545*4882a593Smuzhiyun static int vcnl4035_probe(struct i2c_client *client,
546*4882a593Smuzhiyun 				const struct i2c_device_id *id)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	struct vcnl4035_data *data;
549*4882a593Smuzhiyun 	struct iio_dev *indio_dev;
550*4882a593Smuzhiyun 	struct regmap *regmap;
551*4882a593Smuzhiyun 	int ret;
552*4882a593Smuzhiyun 
553*4882a593Smuzhiyun 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
554*4882a593Smuzhiyun 	if (!indio_dev)
555*4882a593Smuzhiyun 		return -ENOMEM;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	regmap = devm_regmap_init_i2c(client, &vcnl4035_regmap_config);
558*4882a593Smuzhiyun 	if (IS_ERR(regmap)) {
559*4882a593Smuzhiyun 		dev_err(&client->dev, "regmap_init failed!\n");
560*4882a593Smuzhiyun 		return PTR_ERR(regmap);
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	data = iio_priv(indio_dev);
564*4882a593Smuzhiyun 	i2c_set_clientdata(client, indio_dev);
565*4882a593Smuzhiyun 	data->client = client;
566*4882a593Smuzhiyun 	data->regmap = regmap;
567*4882a593Smuzhiyun 
568*4882a593Smuzhiyun 	indio_dev->info = &vcnl4035_info;
569*4882a593Smuzhiyun 	indio_dev->name = VCNL4035_DRV_NAME;
570*4882a593Smuzhiyun 	indio_dev->channels = vcnl4035_channels;
571*4882a593Smuzhiyun 	indio_dev->num_channels = ARRAY_SIZE(vcnl4035_channels);
572*4882a593Smuzhiyun 	indio_dev->modes = INDIO_DIRECT_MODE;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	ret = vcnl4035_init(data);
575*4882a593Smuzhiyun 	if (ret < 0) {
576*4882a593Smuzhiyun 		dev_err(&client->dev, "vcnl4035 chip init failed\n");
577*4882a593Smuzhiyun 		return ret;
578*4882a593Smuzhiyun 	}
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	if (client->irq > 0) {
581*4882a593Smuzhiyun 		ret = vcnl4035_probe_trigger(indio_dev);
582*4882a593Smuzhiyun 		if (ret < 0) {
583*4882a593Smuzhiyun 			dev_err(&client->dev, "vcnl4035 unable init trigger\n");
584*4882a593Smuzhiyun 			goto fail_poweroff;
585*4882a593Smuzhiyun 		}
586*4882a593Smuzhiyun 	}
587*4882a593Smuzhiyun 
588*4882a593Smuzhiyun 	ret = pm_runtime_set_active(&client->dev);
589*4882a593Smuzhiyun 	if (ret < 0)
590*4882a593Smuzhiyun 		goto fail_poweroff;
591*4882a593Smuzhiyun 
592*4882a593Smuzhiyun 	ret = iio_device_register(indio_dev);
593*4882a593Smuzhiyun 	if (ret < 0)
594*4882a593Smuzhiyun 		goto fail_poweroff;
595*4882a593Smuzhiyun 
596*4882a593Smuzhiyun 	pm_runtime_enable(&client->dev);
597*4882a593Smuzhiyun 	pm_runtime_set_autosuspend_delay(&client->dev, VCNL4035_SLEEP_DELAY_MS);
598*4882a593Smuzhiyun 	pm_runtime_use_autosuspend(&client->dev);
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return 0;
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun fail_poweroff:
603*4882a593Smuzhiyun 	vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
604*4882a593Smuzhiyun 	return ret;
605*4882a593Smuzhiyun }
606*4882a593Smuzhiyun 
vcnl4035_remove(struct i2c_client * client)607*4882a593Smuzhiyun static int vcnl4035_remove(struct i2c_client *client)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun 	pm_runtime_dont_use_autosuspend(&client->dev);
612*4882a593Smuzhiyun 	pm_runtime_disable(&client->dev);
613*4882a593Smuzhiyun 	iio_device_unregister(indio_dev);
614*4882a593Smuzhiyun 	pm_runtime_set_suspended(&client->dev);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	return vcnl4035_set_als_power_state(iio_priv(indio_dev),
617*4882a593Smuzhiyun 					VCNL4035_MODE_ALS_DISABLE);
618*4882a593Smuzhiyun }
619*4882a593Smuzhiyun 
vcnl4035_runtime_suspend(struct device * dev)620*4882a593Smuzhiyun static int __maybe_unused vcnl4035_runtime_suspend(struct device *dev)
621*4882a593Smuzhiyun {
622*4882a593Smuzhiyun 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
623*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
624*4882a593Smuzhiyun 	int ret;
625*4882a593Smuzhiyun 
626*4882a593Smuzhiyun 	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_DISABLE);
627*4882a593Smuzhiyun 	regcache_mark_dirty(data->regmap);
628*4882a593Smuzhiyun 
629*4882a593Smuzhiyun 	return ret;
630*4882a593Smuzhiyun }
631*4882a593Smuzhiyun 
vcnl4035_runtime_resume(struct device * dev)632*4882a593Smuzhiyun static int __maybe_unused vcnl4035_runtime_resume(struct device *dev)
633*4882a593Smuzhiyun {
634*4882a593Smuzhiyun 	struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
635*4882a593Smuzhiyun 	struct vcnl4035_data *data = iio_priv(indio_dev);
636*4882a593Smuzhiyun 	int ret;
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	regcache_sync(data->regmap);
639*4882a593Smuzhiyun 	ret = vcnl4035_set_als_power_state(data, VCNL4035_MODE_ALS_ENABLE);
640*4882a593Smuzhiyun 	if (ret < 0)
641*4882a593Smuzhiyun 		return ret;
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	/* wait for 1 ALS integration cycle */
644*4882a593Smuzhiyun 	msleep(data->als_it_val * 100);
645*4882a593Smuzhiyun 
646*4882a593Smuzhiyun 	return 0;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun 
649*4882a593Smuzhiyun static const struct dev_pm_ops vcnl4035_pm_ops = {
650*4882a593Smuzhiyun 	SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
651*4882a593Smuzhiyun 				pm_runtime_force_resume)
652*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(vcnl4035_runtime_suspend,
653*4882a593Smuzhiyun 			   vcnl4035_runtime_resume, NULL)
654*4882a593Smuzhiyun };
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun static const struct of_device_id vcnl4035_of_match[] = {
657*4882a593Smuzhiyun 	{ .compatible = "vishay,vcnl4035", },
658*4882a593Smuzhiyun 	{ }
659*4882a593Smuzhiyun };
660*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, vcnl4035_of_match);
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun static struct i2c_driver vcnl4035_driver = {
663*4882a593Smuzhiyun 	.driver = {
664*4882a593Smuzhiyun 		.name   = VCNL4035_DRV_NAME,
665*4882a593Smuzhiyun 		.pm	= &vcnl4035_pm_ops,
666*4882a593Smuzhiyun 		.of_match_table = vcnl4035_of_match,
667*4882a593Smuzhiyun 	},
668*4882a593Smuzhiyun 	.probe  = vcnl4035_probe,
669*4882a593Smuzhiyun 	.remove	= vcnl4035_remove,
670*4882a593Smuzhiyun };
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun module_i2c_driver(vcnl4035_driver);
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun MODULE_AUTHOR("Parthiban Nallathambi <pn@denx.de>");
675*4882a593Smuzhiyun MODULE_DESCRIPTION("VCNL4035 Ambient Light Sensor driver");
676*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
677