xref: /linux/drivers/iio/light/cm36651.c (revision d0a588a57c2b0748df8307a0865a1bbbf1624c53)
1e590d451SBeomho Seo /*
2e590d451SBeomho Seo  * Copyright (C) 2013 Samsung Electronics Co., Ltd.
3e590d451SBeomho Seo  * Author: Beomho Seo <beomho.seo@samsung.com>
4e590d451SBeomho Seo  *
5e590d451SBeomho Seo  * This program is free software; you can redistribute  it and/or modify it
6e590d451SBeomho Seo  * under  the terms of  the GNU General Public License version 2, as published
7e590d451SBeomho Seo  * by the Free Software Foundation.
8e590d451SBeomho Seo  */
9e590d451SBeomho Seo 
10e590d451SBeomho Seo #include <linux/delay.h>
11e590d451SBeomho Seo #include <linux/err.h>
12e590d451SBeomho Seo #include <linux/i2c.h>
13e590d451SBeomho Seo #include <linux/mutex.h>
14e590d451SBeomho Seo #include <linux/module.h>
15e590d451SBeomho Seo #include <linux/interrupt.h>
16e590d451SBeomho Seo #include <linux/regulator/consumer.h>
17e590d451SBeomho Seo #include <linux/iio/iio.h>
18e590d451SBeomho Seo #include <linux/iio/sysfs.h>
19e590d451SBeomho Seo #include <linux/iio/events.h>
20e590d451SBeomho Seo 
21e590d451SBeomho Seo /* Slave address 0x19 for PS of 7 bit addressing protocol for I2C */
22e590d451SBeomho Seo #define CM36651_I2C_ADDR_PS		0x19
23e590d451SBeomho Seo /* Alert Response Address */
24e590d451SBeomho Seo #define CM36651_ARA			0x0C
25e590d451SBeomho Seo 
26e590d451SBeomho Seo /* Ambient light sensor */
27e590d451SBeomho Seo #define CM36651_CS_CONF1		0x00
28e590d451SBeomho Seo #define CM36651_CS_CONF2		0x01
29e590d451SBeomho Seo #define CM36651_ALS_WH_M		0x02
30e590d451SBeomho Seo #define CM36651_ALS_WH_L		0x03
31e590d451SBeomho Seo #define CM36651_ALS_WL_M		0x04
32e590d451SBeomho Seo #define CM36651_ALS_WL_L		0x05
33e590d451SBeomho Seo #define CM36651_CS_CONF3		0x06
34e590d451SBeomho Seo #define CM36651_CS_CONF_REG_NUM		0x02
35e590d451SBeomho Seo 
36e590d451SBeomho Seo /* Proximity sensor */
37e590d451SBeomho Seo #define CM36651_PS_CONF1		0x00
38e590d451SBeomho Seo #define CM36651_PS_THD			0x01
39e590d451SBeomho Seo #define CM36651_PS_CANC			0x02
40e590d451SBeomho Seo #define CM36651_PS_CONF2		0x03
41e590d451SBeomho Seo #define CM36651_PS_REG_NUM		0x04
42e590d451SBeomho Seo 
43e590d451SBeomho Seo /* CS_CONF1 command code */
44e590d451SBeomho Seo #define CM36651_ALS_ENABLE		0x00
45e590d451SBeomho Seo #define CM36651_ALS_DISABLE		0x01
46e590d451SBeomho Seo #define CM36651_ALS_INT_EN		0x02
47e590d451SBeomho Seo #define CM36651_ALS_THRES		0x04
48e590d451SBeomho Seo 
49e590d451SBeomho Seo /* CS_CONF2 command code */
50e590d451SBeomho Seo #define CM36651_CS_CONF2_DEFAULT_BIT	0x08
51e590d451SBeomho Seo 
52e590d451SBeomho Seo /* CS_CONF3 channel integration time */
5326c17a1cSBeomho Seo #define CM36651_CS_IT1			0x00 /* Integration time 80 msec */
5426c17a1cSBeomho Seo #define CM36651_CS_IT2			0x40 /* Integration time 160 msec */
5526c17a1cSBeomho Seo #define CM36651_CS_IT3			0x80 /* Integration time 320 msec */
5626c17a1cSBeomho Seo #define CM36651_CS_IT4			0xC0 /* Integration time 640 msec */
57e590d451SBeomho Seo 
58e590d451SBeomho Seo /* PS_CONF1 command code */
59e590d451SBeomho Seo #define CM36651_PS_ENABLE		0x00
60e590d451SBeomho Seo #define CM36651_PS_DISABLE		0x01
61e590d451SBeomho Seo #define CM36651_PS_INT_EN		0x02
62e590d451SBeomho Seo #define CM36651_PS_PERS2		0x04
63e590d451SBeomho Seo #define CM36651_PS_PERS3		0x08
64e590d451SBeomho Seo #define CM36651_PS_PERS4		0x0C
65e590d451SBeomho Seo 
66e590d451SBeomho Seo /* PS_CONF1 command code: integration time */
6726c17a1cSBeomho Seo #define CM36651_PS_IT1			0x00 /* Integration time 0.32 msec */
6826c17a1cSBeomho Seo #define CM36651_PS_IT2			0x10 /* Integration time 0.42 msec */
6926c17a1cSBeomho Seo #define CM36651_PS_IT3			0x20 /* Integration time 0.52 msec */
7026c17a1cSBeomho Seo #define CM36651_PS_IT4			0x30 /* Integration time 0.64 msec */
71e590d451SBeomho Seo 
72e590d451SBeomho Seo /* PS_CONF1 command code: duty ratio */
73e590d451SBeomho Seo #define CM36651_PS_DR1			0x00 /* Duty ratio 1/80 */
74e590d451SBeomho Seo #define CM36651_PS_DR2			0x40 /* Duty ratio 1/160 */
75e590d451SBeomho Seo #define CM36651_PS_DR3			0x80 /* Duty ratio 1/320 */
76e590d451SBeomho Seo #define CM36651_PS_DR4			0xC0 /* Duty ratio 1/640 */
77e590d451SBeomho Seo 
78e590d451SBeomho Seo /* PS_THD command code */
79e590d451SBeomho Seo #define CM36651_PS_INITIAL_THD		0x05
80e590d451SBeomho Seo 
81e590d451SBeomho Seo /* PS_CANC command code */
82e590d451SBeomho Seo #define CM36651_PS_CANC_DEFAULT		0x00
83e590d451SBeomho Seo 
84e590d451SBeomho Seo /* PS_CONF2 command code */
85e590d451SBeomho Seo #define CM36651_PS_HYS1			0x00
86e590d451SBeomho Seo #define CM36651_PS_HYS2			0x01
87e590d451SBeomho Seo #define CM36651_PS_SMART_PERS_EN	0x02
88e590d451SBeomho Seo #define CM36651_PS_DIR_INT		0x04
89e590d451SBeomho Seo #define CM36651_PS_MS			0x10
90e590d451SBeomho Seo 
91e590d451SBeomho Seo #define CM36651_CS_COLOR_NUM		4
92e590d451SBeomho Seo 
93e590d451SBeomho Seo #define CM36651_CLOSE_PROXIMITY		0x32
94e590d451SBeomho Seo #define CM36651_FAR_PROXIMITY			0x33
95e590d451SBeomho Seo 
9626c17a1cSBeomho Seo #define CM36651_CS_INT_TIME_AVAIL	"0.08 0.16 0.32 0.64"
9726c17a1cSBeomho Seo #define CM36651_PS_INT_TIME_AVAIL	"0.000320 0.000420 0.000520 0.000640"
98e590d451SBeomho Seo 
99e590d451SBeomho Seo enum cm36651_operation_mode {
100e590d451SBeomho Seo 	CM36651_LIGHT_EN,
101e590d451SBeomho Seo 	CM36651_PROXIMITY_EN,
102e590d451SBeomho Seo 	CM36651_PROXIMITY_EV_EN,
103e590d451SBeomho Seo };
104e590d451SBeomho Seo 
105e590d451SBeomho Seo enum cm36651_light_channel_idx {
106e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL_IDX_RED,
107e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL_IDX_GREEN,
108e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL_IDX_BLUE,
109e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL_IDX_CLEAR,
110e590d451SBeomho Seo };
111e590d451SBeomho Seo 
112e590d451SBeomho Seo enum cm36651_command {
113e590d451SBeomho Seo 	CM36651_CMD_READ_RAW_LIGHT,
114e590d451SBeomho Seo 	CM36651_CMD_READ_RAW_PROXIMITY,
115e590d451SBeomho Seo 	CM36651_CMD_PROX_EV_EN,
116e590d451SBeomho Seo 	CM36651_CMD_PROX_EV_DIS,
117e590d451SBeomho Seo };
118e590d451SBeomho Seo 
119e590d451SBeomho Seo static const u8 cm36651_cs_reg[CM36651_CS_CONF_REG_NUM] = {
120e590d451SBeomho Seo 	CM36651_CS_CONF1,
121e590d451SBeomho Seo 	CM36651_CS_CONF2,
122e590d451SBeomho Seo };
123e590d451SBeomho Seo 
124e590d451SBeomho Seo static const u8 cm36651_ps_reg[CM36651_PS_REG_NUM] = {
125e590d451SBeomho Seo 	CM36651_PS_CONF1,
126e590d451SBeomho Seo 	CM36651_PS_THD,
127e590d451SBeomho Seo 	CM36651_PS_CANC,
128e590d451SBeomho Seo 	CM36651_PS_CONF2,
129e590d451SBeomho Seo };
130e590d451SBeomho Seo 
131e590d451SBeomho Seo struct cm36651_data {
132e590d451SBeomho Seo 	const struct cm36651_platform_data *pdata;
133e590d451SBeomho Seo 	struct i2c_client *client;
134e590d451SBeomho Seo 	struct i2c_client *ps_client;
135e590d451SBeomho Seo 	struct i2c_client *ara_client;
136e590d451SBeomho Seo 	struct mutex lock;
137e590d451SBeomho Seo 	struct regulator *vled_reg;
138e590d451SBeomho Seo 	unsigned long flags;
139e590d451SBeomho Seo 	int cs_int_time[CM36651_CS_COLOR_NUM];
140e590d451SBeomho Seo 	int ps_int_time;
141e590d451SBeomho Seo 	u8 cs_ctrl_regs[CM36651_CS_CONF_REG_NUM];
142e590d451SBeomho Seo 	u8 ps_ctrl_regs[CM36651_PS_REG_NUM];
143e590d451SBeomho Seo 	u16 color[CM36651_CS_COLOR_NUM];
144e590d451SBeomho Seo };
145e590d451SBeomho Seo 
146e590d451SBeomho Seo static int cm36651_setup_reg(struct cm36651_data *cm36651)
147e590d451SBeomho Seo {
148e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
149e590d451SBeomho Seo 	struct i2c_client *ps_client = cm36651->ps_client;
150e590d451SBeomho Seo 	int i, ret;
151e590d451SBeomho Seo 
152e590d451SBeomho Seo 	/* CS initialization */
153e590d451SBeomho Seo 	cm36651->cs_ctrl_regs[CM36651_CS_CONF1] = CM36651_ALS_ENABLE |
154e590d451SBeomho Seo 							     CM36651_ALS_THRES;
155e590d451SBeomho Seo 	cm36651->cs_ctrl_regs[CM36651_CS_CONF2] = CM36651_CS_CONF2_DEFAULT_BIT;
156e590d451SBeomho Seo 
157e590d451SBeomho Seo 	for (i = 0; i < CM36651_CS_CONF_REG_NUM; i++) {
158e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(client, cm36651_cs_reg[i],
159e590d451SBeomho Seo 						     cm36651->cs_ctrl_regs[i]);
160e590d451SBeomho Seo 		if (ret < 0)
161e590d451SBeomho Seo 			return ret;
162e590d451SBeomho Seo 	}
163e590d451SBeomho Seo 
164e590d451SBeomho Seo 	/* PS initialization */
165e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_CONF1] = CM36651_PS_ENABLE |
166e590d451SBeomho Seo 								CM36651_PS_IT2;
167e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_THD] = CM36651_PS_INITIAL_THD;
168e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_CANC] = CM36651_PS_CANC_DEFAULT;
169e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_CONF2] = CM36651_PS_HYS2 |
170e590d451SBeomho Seo 				CM36651_PS_DIR_INT | CM36651_PS_SMART_PERS_EN;
171e590d451SBeomho Seo 
172e590d451SBeomho Seo 	for (i = 0; i < CM36651_PS_REG_NUM; i++) {
173e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(ps_client, cm36651_ps_reg[i],
174e590d451SBeomho Seo 						     cm36651->ps_ctrl_regs[i]);
175e590d451SBeomho Seo 		if (ret < 0)
176e590d451SBeomho Seo 			return ret;
177e590d451SBeomho Seo 	}
178e590d451SBeomho Seo 
179e590d451SBeomho Seo 	/* Set shutdown mode */
180e590d451SBeomho Seo 	ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
181e590d451SBeomho Seo 							  CM36651_ALS_DISABLE);
182e590d451SBeomho Seo 	if (ret < 0)
183e590d451SBeomho Seo 		return ret;
184e590d451SBeomho Seo 
185e590d451SBeomho Seo 	ret = i2c_smbus_write_byte_data(cm36651->ps_client,
186e590d451SBeomho Seo 					 CM36651_PS_CONF1, CM36651_PS_DISABLE);
187e590d451SBeomho Seo 	if (ret < 0)
188e590d451SBeomho Seo 		return ret;
189e590d451SBeomho Seo 
190e590d451SBeomho Seo 	return 0;
191e590d451SBeomho Seo }
192e590d451SBeomho Seo 
193e590d451SBeomho Seo static int cm36651_read_output(struct cm36651_data *cm36651,
194e590d451SBeomho Seo 				struct iio_chan_spec const *chan, int *val)
195e590d451SBeomho Seo {
196e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
197e590d451SBeomho Seo 	int ret = -EINVAL;
198e590d451SBeomho Seo 
199e590d451SBeomho Seo 	switch (chan->type) {
200e590d451SBeomho Seo 	case IIO_LIGHT:
201e590d451SBeomho Seo 		*val = i2c_smbus_read_word_data(client, chan->address);
202e590d451SBeomho Seo 		if (*val < 0)
203e590d451SBeomho Seo 			return ret;
204e590d451SBeomho Seo 
205e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
206e590d451SBeomho Seo 							CM36651_ALS_DISABLE);
207e590d451SBeomho Seo 		if (ret < 0)
208e590d451SBeomho Seo 			return ret;
209e590d451SBeomho Seo 
210e590d451SBeomho Seo 		ret = IIO_VAL_INT;
211e590d451SBeomho Seo 		break;
212e590d451SBeomho Seo 	case IIO_PROXIMITY:
213e590d451SBeomho Seo 		*val = i2c_smbus_read_byte(cm36651->ps_client);
214e590d451SBeomho Seo 		if (*val < 0)
215e590d451SBeomho Seo 			return ret;
216e590d451SBeomho Seo 
217e590d451SBeomho Seo 		if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
218e590d451SBeomho Seo 			ret = i2c_smbus_write_byte_data(cm36651->ps_client,
219e590d451SBeomho Seo 					CM36651_PS_CONF1, CM36651_PS_DISABLE);
220e590d451SBeomho Seo 			if (ret < 0)
221e590d451SBeomho Seo 				return ret;
222e590d451SBeomho Seo 		}
223e590d451SBeomho Seo 
224e590d451SBeomho Seo 		ret = IIO_VAL_INT;
225e590d451SBeomho Seo 		break;
226e590d451SBeomho Seo 	default:
227e590d451SBeomho Seo 		break;
228e590d451SBeomho Seo 	}
229e590d451SBeomho Seo 
230e590d451SBeomho Seo 	return ret;
231e590d451SBeomho Seo }
232e590d451SBeomho Seo 
233e590d451SBeomho Seo static irqreturn_t cm36651_irq_handler(int irq, void *data)
234e590d451SBeomho Seo {
235e590d451SBeomho Seo 	struct iio_dev *indio_dev = data;
236e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
237e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
238e590d451SBeomho Seo 	int ev_dir, ret;
239e590d451SBeomho Seo 	u64 ev_code;
240e590d451SBeomho Seo 
241e590d451SBeomho Seo 	/*
242e590d451SBeomho Seo 	 * The PS INT pin is an active low signal that PS INT move logic low
243e590d451SBeomho Seo 	 * when the object is detect. Once the MCU host received the PS INT
244e590d451SBeomho Seo 	 * "LOW" signal, the Host needs to read the data at Alert Response
245e590d451SBeomho Seo 	 * Address(ARA) to clear the PS INT signal. After clearing the PS
246e590d451SBeomho Seo 	 * INT pin, the PS INT signal toggles from low to high.
247e590d451SBeomho Seo 	 */
248e590d451SBeomho Seo 	ret = i2c_smbus_read_byte(cm36651->ara_client);
249e590d451SBeomho Seo 	if (ret < 0) {
250e590d451SBeomho Seo 		dev_err(&client->dev,
251e590d451SBeomho Seo 				"%s: Data read failed: %d\n", __func__, ret);
252e590d451SBeomho Seo 		return IRQ_HANDLED;
253e590d451SBeomho Seo 	}
254e590d451SBeomho Seo 	switch (ret) {
255e590d451SBeomho Seo 	case CM36651_CLOSE_PROXIMITY:
256e590d451SBeomho Seo 		ev_dir = IIO_EV_DIR_RISING;
257e590d451SBeomho Seo 		break;
258e590d451SBeomho Seo 	case CM36651_FAR_PROXIMITY:
259e590d451SBeomho Seo 		ev_dir = IIO_EV_DIR_FALLING;
260e590d451SBeomho Seo 		break;
261e590d451SBeomho Seo 	default:
262e590d451SBeomho Seo 		dev_err(&client->dev,
263e590d451SBeomho Seo 			"%s: Data read wrong: %d\n", __func__, ret);
264e590d451SBeomho Seo 		return IRQ_HANDLED;
265e590d451SBeomho Seo 	}
266e590d451SBeomho Seo 
267e590d451SBeomho Seo 	ev_code = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
268e590d451SBeomho Seo 				CM36651_CMD_READ_RAW_PROXIMITY,
269e590d451SBeomho Seo 				IIO_EV_TYPE_THRESH, ev_dir);
270e590d451SBeomho Seo 
271e590d451SBeomho Seo 	iio_push_event(indio_dev, ev_code, iio_get_time_ns());
272e590d451SBeomho Seo 
273e590d451SBeomho Seo 	return IRQ_HANDLED;
274e590d451SBeomho Seo }
275e590d451SBeomho Seo 
276e590d451SBeomho Seo static int cm36651_set_operation_mode(struct cm36651_data *cm36651, int cmd)
277e590d451SBeomho Seo {
278e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
279e590d451SBeomho Seo 	struct i2c_client *ps_client = cm36651->ps_client;
280e590d451SBeomho Seo 	int ret = -EINVAL;
281e590d451SBeomho Seo 
282e590d451SBeomho Seo 	switch (cmd) {
283e590d451SBeomho Seo 	case CM36651_CMD_READ_RAW_LIGHT:
284e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF1,
285e590d451SBeomho Seo 				cm36651->cs_ctrl_regs[CM36651_CS_CONF1]);
286e590d451SBeomho Seo 		break;
287e590d451SBeomho Seo 	case CM36651_CMD_READ_RAW_PROXIMITY:
288e590d451SBeomho Seo 		if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags))
289e590d451SBeomho Seo 			return CM36651_PROXIMITY_EV_EN;
290e590d451SBeomho Seo 
291e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(ps_client, CM36651_PS_CONF1,
292e590d451SBeomho Seo 				cm36651->ps_ctrl_regs[CM36651_PS_CONF1]);
293e590d451SBeomho Seo 		break;
294e590d451SBeomho Seo 	case CM36651_CMD_PROX_EV_EN:
295e590d451SBeomho Seo 		if (test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
296e590d451SBeomho Seo 			dev_err(&client->dev,
297e590d451SBeomho Seo 				"Already proximity event enable state\n");
298e590d451SBeomho Seo 			return ret;
299e590d451SBeomho Seo 		}
300e590d451SBeomho Seo 		set_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
301e590d451SBeomho Seo 
302e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(ps_client,
303e590d451SBeomho Seo 			cm36651_ps_reg[CM36651_PS_CONF1],
304e590d451SBeomho Seo 			CM36651_PS_INT_EN | CM36651_PS_PERS2 | CM36651_PS_IT2);
305e590d451SBeomho Seo 
306e590d451SBeomho Seo 		if (ret < 0) {
307e590d451SBeomho Seo 			dev_err(&client->dev, "Proximity enable event failed\n");
308e590d451SBeomho Seo 			return ret;
309e590d451SBeomho Seo 		}
310e590d451SBeomho Seo 		break;
311e590d451SBeomho Seo 	case CM36651_CMD_PROX_EV_DIS:
312e590d451SBeomho Seo 		if (!test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags)) {
313e590d451SBeomho Seo 			dev_err(&client->dev,
314e590d451SBeomho Seo 				"Already proximity event disable state\n");
315e590d451SBeomho Seo 			return ret;
316e590d451SBeomho Seo 		}
317e590d451SBeomho Seo 		clear_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
318e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(ps_client,
319e590d451SBeomho Seo 					CM36651_PS_CONF1, CM36651_PS_DISABLE);
320e590d451SBeomho Seo 		break;
321e590d451SBeomho Seo 	}
322e590d451SBeomho Seo 
323e590d451SBeomho Seo 	if (ret < 0)
324e590d451SBeomho Seo 		dev_err(&client->dev, "Write register failed\n");
325e590d451SBeomho Seo 
326e590d451SBeomho Seo 	return ret;
327e590d451SBeomho Seo }
328e590d451SBeomho Seo 
329e590d451SBeomho Seo static int cm36651_read_channel(struct cm36651_data *cm36651,
330e590d451SBeomho Seo 				struct iio_chan_spec const *chan, int *val)
331e590d451SBeomho Seo {
332e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
333e590d451SBeomho Seo 	int cmd, ret;
334e590d451SBeomho Seo 
335e590d451SBeomho Seo 	if (chan->type == IIO_LIGHT)
336e590d451SBeomho Seo 		cmd = CM36651_CMD_READ_RAW_LIGHT;
337e590d451SBeomho Seo 	else if (chan->type == IIO_PROXIMITY)
338e590d451SBeomho Seo 		cmd = CM36651_CMD_READ_RAW_PROXIMITY;
339e590d451SBeomho Seo 	else
340e590d451SBeomho Seo 		return -EINVAL;
341e590d451SBeomho Seo 
342e590d451SBeomho Seo 	ret = cm36651_set_operation_mode(cm36651, cmd);
343e590d451SBeomho Seo 	if (ret < 0) {
344e590d451SBeomho Seo 		dev_err(&client->dev, "CM36651 set operation mode failed\n");
345e590d451SBeomho Seo 		return ret;
346e590d451SBeomho Seo 	}
347e590d451SBeomho Seo 	/* Delay for work after enable operation */
348e590d451SBeomho Seo 	msleep(50);
349e590d451SBeomho Seo 	ret = cm36651_read_output(cm36651, chan, val);
350e590d451SBeomho Seo 	if (ret < 0) {
351e590d451SBeomho Seo 		dev_err(&client->dev, "CM36651 read output failed\n");
352e590d451SBeomho Seo 		return ret;
353e590d451SBeomho Seo 	}
354e590d451SBeomho Seo 
355e590d451SBeomho Seo 	return ret;
356e590d451SBeomho Seo }
357e590d451SBeomho Seo 
358e590d451SBeomho Seo static int cm36651_read_int_time(struct cm36651_data *cm36651,
35926c17a1cSBeomho Seo 				struct iio_chan_spec const *chan, int *val2)
360e590d451SBeomho Seo {
361e590d451SBeomho Seo 	switch (chan->type) {
362e590d451SBeomho Seo 	case IIO_LIGHT:
363e590d451SBeomho Seo 		if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
36426c17a1cSBeomho Seo 			*val2 = 80000;
365e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
36626c17a1cSBeomho Seo 			*val2 = 160000;
367e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
36826c17a1cSBeomho Seo 			*val2 = 320000;
369e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
37026c17a1cSBeomho Seo 			*val2 = 640000;
371e590d451SBeomho Seo 		else
372e590d451SBeomho Seo 			return -EINVAL;
373e590d451SBeomho Seo 		break;
374e590d451SBeomho Seo 	case IIO_PROXIMITY:
375e590d451SBeomho Seo 		if (cm36651->ps_int_time == CM36651_PS_IT1)
37626c17a1cSBeomho Seo 			*val2 = 320;
377e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT2)
37826c17a1cSBeomho Seo 			*val2 = 420;
379e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT3)
38026c17a1cSBeomho Seo 			*val2 = 520;
381e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT4)
38226c17a1cSBeomho Seo 			*val2 = 640;
383e590d451SBeomho Seo 		else
384e590d451SBeomho Seo 			return -EINVAL;
385e590d451SBeomho Seo 		break;
386e590d451SBeomho Seo 	default:
387e590d451SBeomho Seo 		return -EINVAL;
388e590d451SBeomho Seo 	}
389e590d451SBeomho Seo 
39026c17a1cSBeomho Seo 	return IIO_VAL_INT_PLUS_MICRO;
391e590d451SBeomho Seo }
392e590d451SBeomho Seo 
393e590d451SBeomho Seo static int cm36651_write_int_time(struct cm36651_data *cm36651,
394e590d451SBeomho Seo 				struct iio_chan_spec const *chan, int val)
395e590d451SBeomho Seo {
396e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
397e590d451SBeomho Seo 	struct i2c_client *ps_client = cm36651->ps_client;
398e590d451SBeomho Seo 	int int_time, ret;
399e590d451SBeomho Seo 
400e590d451SBeomho Seo 	switch (chan->type) {
401e590d451SBeomho Seo 	case IIO_LIGHT:
402e590d451SBeomho Seo 		if (val == 80000)
403e590d451SBeomho Seo 			int_time = CM36651_CS_IT1;
404e590d451SBeomho Seo 		else if (val == 160000)
405e590d451SBeomho Seo 			int_time = CM36651_CS_IT2;
406e590d451SBeomho Seo 		else if (val == 320000)
407e590d451SBeomho Seo 			int_time = CM36651_CS_IT3;
408e590d451SBeomho Seo 		else if (val == 640000)
409e590d451SBeomho Seo 			int_time = CM36651_CS_IT4;
410e590d451SBeomho Seo 		else
411e590d451SBeomho Seo 			return -EINVAL;
412e590d451SBeomho Seo 
413e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(client, CM36651_CS_CONF3,
414e590d451SBeomho Seo 					   int_time >> 2 * (chan->address));
415e590d451SBeomho Seo 		if (ret < 0) {
416e590d451SBeomho Seo 			dev_err(&client->dev, "CS integration time write failed\n");
417e590d451SBeomho Seo 			return ret;
418e590d451SBeomho Seo 		}
419e590d451SBeomho Seo 		cm36651->cs_int_time[chan->address] = int_time;
420e590d451SBeomho Seo 		break;
421e590d451SBeomho Seo 	case IIO_PROXIMITY:
422e590d451SBeomho Seo 		if (val == 320)
423e590d451SBeomho Seo 			int_time = CM36651_PS_IT1;
424e590d451SBeomho Seo 		else if (val == 420)
425e590d451SBeomho Seo 			int_time = CM36651_PS_IT2;
426e590d451SBeomho Seo 		else if (val == 520)
427e590d451SBeomho Seo 			int_time = CM36651_PS_IT3;
428e590d451SBeomho Seo 		else if (val == 640)
429e590d451SBeomho Seo 			int_time = CM36651_PS_IT4;
430e590d451SBeomho Seo 		else
431e590d451SBeomho Seo 			return -EINVAL;
432e590d451SBeomho Seo 
433e590d451SBeomho Seo 		ret = i2c_smbus_write_byte_data(ps_client,
434e590d451SBeomho Seo 						CM36651_PS_CONF1, int_time);
435e590d451SBeomho Seo 		if (ret < 0) {
436e590d451SBeomho Seo 			dev_err(&client->dev, "PS integration time write failed\n");
437e590d451SBeomho Seo 			return ret;
438e590d451SBeomho Seo 		}
439e590d451SBeomho Seo 		cm36651->ps_int_time = int_time;
440e590d451SBeomho Seo 		break;
441e590d451SBeomho Seo 	default:
442e590d451SBeomho Seo 		return -EINVAL;
443e590d451SBeomho Seo 	}
444e590d451SBeomho Seo 
445e590d451SBeomho Seo 	return ret;
446e590d451SBeomho Seo }
447e590d451SBeomho Seo 
448e590d451SBeomho Seo static int cm36651_read_raw(struct iio_dev *indio_dev,
449e590d451SBeomho Seo 			    struct iio_chan_spec const *chan,
450e590d451SBeomho Seo 			    int *val, int *val2, long mask)
451e590d451SBeomho Seo {
452e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
453e590d451SBeomho Seo 	int ret;
454e590d451SBeomho Seo 
455e590d451SBeomho Seo 	mutex_lock(&cm36651->lock);
456e590d451SBeomho Seo 
457e590d451SBeomho Seo 	switch (mask) {
458e590d451SBeomho Seo 	case IIO_CHAN_INFO_RAW:
459e590d451SBeomho Seo 		ret = cm36651_read_channel(cm36651, chan, val);
460e590d451SBeomho Seo 		break;
461e590d451SBeomho Seo 	case IIO_CHAN_INFO_INT_TIME:
46226c17a1cSBeomho Seo 		*val = 0;
46326c17a1cSBeomho Seo 		ret = cm36651_read_int_time(cm36651, chan, val2);
464e590d451SBeomho Seo 		break;
465e590d451SBeomho Seo 	default:
466e590d451SBeomho Seo 		ret = -EINVAL;
467e590d451SBeomho Seo 	}
468e590d451SBeomho Seo 
469e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
470e590d451SBeomho Seo 
471e590d451SBeomho Seo 	return ret;
472e590d451SBeomho Seo }
473e590d451SBeomho Seo 
474e590d451SBeomho Seo static int cm36651_write_raw(struct iio_dev *indio_dev,
475e590d451SBeomho Seo 			     struct iio_chan_spec const *chan,
476e590d451SBeomho Seo 			     int val, int val2, long mask)
477e590d451SBeomho Seo {
478e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
479e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
480e590d451SBeomho Seo 	int ret = -EINVAL;
481e590d451SBeomho Seo 
482e590d451SBeomho Seo 	if (mask == IIO_CHAN_INFO_INT_TIME) {
48326c17a1cSBeomho Seo 		ret = cm36651_write_int_time(cm36651, chan, val2);
484e590d451SBeomho Seo 		if (ret < 0)
485e590d451SBeomho Seo 			dev_err(&client->dev, "Integration time write failed\n");
486e590d451SBeomho Seo 	}
487e590d451SBeomho Seo 
488e590d451SBeomho Seo 	return ret;
489e590d451SBeomho Seo }
490e590d451SBeomho Seo 
491e590d451SBeomho Seo static int cm36651_read_prox_thresh(struct iio_dev *indio_dev,
492bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
493bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
494bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
495bb7f9d90SLars-Peter Clausen 					enum iio_event_info info,
496bb7f9d90SLars-Peter Clausen 					int *val, int *val2)
497e590d451SBeomho Seo {
498e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
499e590d451SBeomho Seo 
500e590d451SBeomho Seo 	*val = cm36651->ps_ctrl_regs[CM36651_PS_THD];
501e590d451SBeomho Seo 
502e590d451SBeomho Seo 	return 0;
503e590d451SBeomho Seo }
504e590d451SBeomho Seo 
505e590d451SBeomho Seo static int cm36651_write_prox_thresh(struct iio_dev *indio_dev,
506bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
507bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
508bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
509bb7f9d90SLars-Peter Clausen 					enum iio_event_info info,
510bb7f9d90SLars-Peter Clausen 					int val, int val2)
511e590d451SBeomho Seo {
512e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
513e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
514e590d451SBeomho Seo 	int ret;
515e590d451SBeomho Seo 
516e590d451SBeomho Seo 	if (val < 3 || val > 255)
517e590d451SBeomho Seo 		return -EINVAL;
518e590d451SBeomho Seo 
519e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_THD] = val;
520e590d451SBeomho Seo 	ret = i2c_smbus_write_byte_data(cm36651->ps_client, CM36651_PS_THD,
521e590d451SBeomho Seo 					cm36651->ps_ctrl_regs[CM36651_PS_THD]);
522e590d451SBeomho Seo 
523e590d451SBeomho Seo 	if (ret < 0) {
524e590d451SBeomho Seo 		dev_err(&client->dev, "PS threshold write failed: %d\n", ret);
525e590d451SBeomho Seo 		return ret;
526e590d451SBeomho Seo 	}
527e590d451SBeomho Seo 
528e590d451SBeomho Seo 	return 0;
529e590d451SBeomho Seo }
530e590d451SBeomho Seo 
531e590d451SBeomho Seo static int cm36651_write_prox_event_config(struct iio_dev *indio_dev,
532bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
533bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
534bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
535bb7f9d90SLars-Peter Clausen 					int state)
536e590d451SBeomho Seo {
537e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
538e590d451SBeomho Seo 	int cmd, ret = -EINVAL;
539e590d451SBeomho Seo 
540e590d451SBeomho Seo 	mutex_lock(&cm36651->lock);
541e590d451SBeomho Seo 
542e590d451SBeomho Seo 	cmd = state ? CM36651_CMD_PROX_EV_EN : CM36651_CMD_PROX_EV_DIS;
543e590d451SBeomho Seo 	ret = cm36651_set_operation_mode(cm36651, cmd);
544e590d451SBeomho Seo 
545e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
546e590d451SBeomho Seo 
547e590d451SBeomho Seo 	return ret;
548e590d451SBeomho Seo }
549e590d451SBeomho Seo 
550e590d451SBeomho Seo static int cm36651_read_prox_event_config(struct iio_dev *indio_dev,
551bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
552bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
553bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir)
554e590d451SBeomho Seo {
555e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
556e590d451SBeomho Seo 	int event_en;
557e590d451SBeomho Seo 
558e590d451SBeomho Seo 	mutex_lock(&cm36651->lock);
559e590d451SBeomho Seo 
560e590d451SBeomho Seo 	event_en = test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
561e590d451SBeomho Seo 
562e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
563e590d451SBeomho Seo 
564e590d451SBeomho Seo 	return event_en;
565e590d451SBeomho Seo }
566e590d451SBeomho Seo 
567e590d451SBeomho Seo #define CM36651_LIGHT_CHANNEL(_color, _idx) {		\
568e590d451SBeomho Seo 	.type = IIO_LIGHT,				\
569e590d451SBeomho Seo 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
570e590d451SBeomho Seo 			BIT(IIO_CHAN_INFO_INT_TIME),	\
571e590d451SBeomho Seo 	.address = _idx,				\
572e590d451SBeomho Seo 	.modified = 1,					\
573e590d451SBeomho Seo 	.channel2 = IIO_MOD_LIGHT_##_color,		\
574e590d451SBeomho Seo }							\
575e590d451SBeomho Seo 
576bb7f9d90SLars-Peter Clausen static const struct iio_event_spec cm36651_event_spec[] = {
577bb7f9d90SLars-Peter Clausen 	{
578bb7f9d90SLars-Peter Clausen 		.type = IIO_EV_TYPE_THRESH,
579bb7f9d90SLars-Peter Clausen 		.dir = IIO_EV_DIR_EITHER,
580bb7f9d90SLars-Peter Clausen 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
581bb7f9d90SLars-Peter Clausen 				BIT(IIO_EV_INFO_ENABLE),
582bb7f9d90SLars-Peter Clausen 	}
583bb7f9d90SLars-Peter Clausen };
584bb7f9d90SLars-Peter Clausen 
585e590d451SBeomho Seo static const struct iio_chan_spec cm36651_channels[] = {
586e590d451SBeomho Seo 	{
587e590d451SBeomho Seo 		.type = IIO_PROXIMITY,
588e590d451SBeomho Seo 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
589e590d451SBeomho Seo 				BIT(IIO_CHAN_INFO_INT_TIME),
590bb7f9d90SLars-Peter Clausen 		.event_spec = cm36651_event_spec,
591bb7f9d90SLars-Peter Clausen 		.num_event_specs = ARRAY_SIZE(cm36651_event_spec),
592e590d451SBeomho Seo 	},
593e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(RED, CM36651_LIGHT_CHANNEL_IDX_RED),
594e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(GREEN, CM36651_LIGHT_CHANNEL_IDX_GREEN),
595e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(BLUE, CM36651_LIGHT_CHANNEL_IDX_BLUE),
596e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(CLEAR, CM36651_LIGHT_CHANNEL_IDX_CLEAR),
597e590d451SBeomho Seo };
598e590d451SBeomho Seo 
599e590d451SBeomho Seo static IIO_CONST_ATTR(in_illuminance_integration_time_available,
600e590d451SBeomho Seo 					CM36651_CS_INT_TIME_AVAIL);
601e590d451SBeomho Seo static IIO_CONST_ATTR(in_proximity_integration_time_available,
602e590d451SBeomho Seo 					CM36651_PS_INT_TIME_AVAIL);
603e590d451SBeomho Seo 
604e590d451SBeomho Seo static struct attribute *cm36651_attributes[] = {
605e590d451SBeomho Seo 	&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
606e590d451SBeomho Seo 	&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
607e590d451SBeomho Seo 	NULL,
608e590d451SBeomho Seo };
609e590d451SBeomho Seo 
610e590d451SBeomho Seo static const struct attribute_group cm36651_attribute_group = {
611e590d451SBeomho Seo 	.attrs = cm36651_attributes
612e590d451SBeomho Seo };
613e590d451SBeomho Seo 
614e590d451SBeomho Seo static const struct iio_info cm36651_info = {
615e590d451SBeomho Seo 	.driver_module		= THIS_MODULE,
616e590d451SBeomho Seo 	.read_raw		= &cm36651_read_raw,
617e590d451SBeomho Seo 	.write_raw		= &cm36651_write_raw,
618e590d451SBeomho Seo 	.read_event_value	= &cm36651_read_prox_thresh,
619e590d451SBeomho Seo 	.write_event_value	= &cm36651_write_prox_thresh,
620e590d451SBeomho Seo 	.read_event_config	= &cm36651_read_prox_event_config,
621e590d451SBeomho Seo 	.write_event_config	= &cm36651_write_prox_event_config,
622e590d451SBeomho Seo 	.attrs			= &cm36651_attribute_group,
623e590d451SBeomho Seo };
624e590d451SBeomho Seo 
625e590d451SBeomho Seo static int cm36651_probe(struct i2c_client *client,
626e590d451SBeomho Seo 			     const struct i2c_device_id *id)
627e590d451SBeomho Seo {
628e590d451SBeomho Seo 	struct cm36651_data *cm36651;
629e590d451SBeomho Seo 	struct iio_dev *indio_dev;
630e590d451SBeomho Seo 	int ret;
631e590d451SBeomho Seo 
632e590d451SBeomho Seo 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm36651));
633e590d451SBeomho Seo 	if (!indio_dev)
634e590d451SBeomho Seo 		return -ENOMEM;
635e590d451SBeomho Seo 
636e590d451SBeomho Seo 	cm36651 = iio_priv(indio_dev);
637e590d451SBeomho Seo 
638e590d451SBeomho Seo 	cm36651->vled_reg = devm_regulator_get(&client->dev, "vled");
639e590d451SBeomho Seo 	if (IS_ERR(cm36651->vled_reg)) {
640e590d451SBeomho Seo 		dev_err(&client->dev, "get regulator vled failed\n");
641e590d451SBeomho Seo 		return PTR_ERR(cm36651->vled_reg);
642e590d451SBeomho Seo 	}
643e590d451SBeomho Seo 
644e590d451SBeomho Seo 	ret = regulator_enable(cm36651->vled_reg);
645e590d451SBeomho Seo 	if (ret) {
646e590d451SBeomho Seo 		dev_err(&client->dev, "enable regulator vled failed\n");
647e590d451SBeomho Seo 		return ret;
648e590d451SBeomho Seo 	}
649e590d451SBeomho Seo 
650e590d451SBeomho Seo 	i2c_set_clientdata(client, indio_dev);
651e590d451SBeomho Seo 
652e590d451SBeomho Seo 	cm36651->client = client;
653e590d451SBeomho Seo 	cm36651->ps_client = i2c_new_dummy(client->adapter,
654e590d451SBeomho Seo 						     CM36651_I2C_ADDR_PS);
655*d0a588a5SKrzysztof Kozlowski 	if (!cm36651->ps_client) {
656*d0a588a5SKrzysztof Kozlowski 		dev_err(&client->dev, "%s: new i2c device failed\n", __func__);
657*d0a588a5SKrzysztof Kozlowski 		ret = -ENODEV;
658*d0a588a5SKrzysztof Kozlowski 		goto error_disable_reg;
659*d0a588a5SKrzysztof Kozlowski 	}
660*d0a588a5SKrzysztof Kozlowski 
661e590d451SBeomho Seo 	cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA);
662*d0a588a5SKrzysztof Kozlowski 	if (!cm36651->ara_client) {
663*d0a588a5SKrzysztof Kozlowski 		dev_err(&client->dev, "%s: new i2c device failed\n", __func__);
664*d0a588a5SKrzysztof Kozlowski 		ret = -ENODEV;
665*d0a588a5SKrzysztof Kozlowski 		goto error_i2c_unregister_ps;
666*d0a588a5SKrzysztof Kozlowski 	}
667*d0a588a5SKrzysztof Kozlowski 
668e590d451SBeomho Seo 	mutex_init(&cm36651->lock);
669e590d451SBeomho Seo 	indio_dev->dev.parent = &client->dev;
670e590d451SBeomho Seo 	indio_dev->channels = cm36651_channels;
671e590d451SBeomho Seo 	indio_dev->num_channels = ARRAY_SIZE(cm36651_channels);
672e590d451SBeomho Seo 	indio_dev->info = &cm36651_info;
673e590d451SBeomho Seo 	indio_dev->name = id->name;
674e590d451SBeomho Seo 	indio_dev->modes = INDIO_DIRECT_MODE;
675e590d451SBeomho Seo 
676e590d451SBeomho Seo 	ret = cm36651_setup_reg(cm36651);
677e590d451SBeomho Seo 	if (ret) {
678e590d451SBeomho Seo 		dev_err(&client->dev, "%s: register setup failed\n", __func__);
679*d0a588a5SKrzysztof Kozlowski 		goto error_i2c_unregister_ara;
680e590d451SBeomho Seo 	}
681e590d451SBeomho Seo 
682e590d451SBeomho Seo 	ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler,
683e590d451SBeomho Seo 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
684e590d451SBeomho Seo 							"cm36651", indio_dev);
685e590d451SBeomho Seo 	if (ret) {
686e590d451SBeomho Seo 		dev_err(&client->dev, "%s: request irq failed\n", __func__);
687*d0a588a5SKrzysztof Kozlowski 		goto error_i2c_unregister_ara;
688e590d451SBeomho Seo 	}
689e590d451SBeomho Seo 
690e590d451SBeomho Seo 	ret = iio_device_register(indio_dev);
691e590d451SBeomho Seo 	if (ret) {
692e590d451SBeomho Seo 		dev_err(&client->dev, "%s: regist device failed\n", __func__);
693e590d451SBeomho Seo 		goto error_free_irq;
694e590d451SBeomho Seo 	}
695e590d451SBeomho Seo 
696e590d451SBeomho Seo 	return 0;
697e590d451SBeomho Seo 
698e590d451SBeomho Seo error_free_irq:
699e590d451SBeomho Seo 	free_irq(client->irq, indio_dev);
700*d0a588a5SKrzysztof Kozlowski error_i2c_unregister_ara:
701*d0a588a5SKrzysztof Kozlowski 	i2c_unregister_device(cm36651->ara_client);
702*d0a588a5SKrzysztof Kozlowski error_i2c_unregister_ps:
703*d0a588a5SKrzysztof Kozlowski 	i2c_unregister_device(cm36651->ps_client);
704e590d451SBeomho Seo error_disable_reg:
705e590d451SBeomho Seo 	regulator_disable(cm36651->vled_reg);
706e590d451SBeomho Seo 	return ret;
707e590d451SBeomho Seo }
708e590d451SBeomho Seo 
709e590d451SBeomho Seo static int cm36651_remove(struct i2c_client *client)
710e590d451SBeomho Seo {
711e590d451SBeomho Seo 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
712e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
713e590d451SBeomho Seo 
714e590d451SBeomho Seo 	iio_device_unregister(indio_dev);
715e590d451SBeomho Seo 	regulator_disable(cm36651->vled_reg);
716e590d451SBeomho Seo 	free_irq(client->irq, indio_dev);
717*d0a588a5SKrzysztof Kozlowski 	i2c_unregister_device(cm36651->ps_client);
718*d0a588a5SKrzysztof Kozlowski 	i2c_unregister_device(cm36651->ara_client);
719e590d451SBeomho Seo 
720e590d451SBeomho Seo 	return 0;
721e590d451SBeomho Seo }
722e590d451SBeomho Seo 
723e590d451SBeomho Seo static const struct i2c_device_id cm36651_id[] = {
724e590d451SBeomho Seo 	{ "cm36651", 0 },
725e590d451SBeomho Seo 	{ }
726e590d451SBeomho Seo };
727e590d451SBeomho Seo 
728e590d451SBeomho Seo MODULE_DEVICE_TABLE(i2c, cm36651_id);
729e590d451SBeomho Seo 
730e590d451SBeomho Seo static const struct of_device_id cm36651_of_match[] = {
731e590d451SBeomho Seo 	{ .compatible = "capella,cm36651" },
732e590d451SBeomho Seo 	{ }
733e590d451SBeomho Seo };
734e590d451SBeomho Seo 
735e590d451SBeomho Seo static struct i2c_driver cm36651_driver = {
736e590d451SBeomho Seo 	.driver = {
737e590d451SBeomho Seo 		.name	= "cm36651",
738a451521dSSachin Kamat 		.of_match_table = cm36651_of_match,
739e590d451SBeomho Seo 		.owner	= THIS_MODULE,
740e590d451SBeomho Seo 	},
741e590d451SBeomho Seo 	.probe		= cm36651_probe,
742e590d451SBeomho Seo 	.remove		= cm36651_remove,
743e590d451SBeomho Seo 	.id_table	= cm36651_id,
744e590d451SBeomho Seo };
745e590d451SBeomho Seo 
746e590d451SBeomho Seo module_i2c_driver(cm36651_driver);
747e590d451SBeomho Seo 
748e590d451SBeomho Seo MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
749e590d451SBeomho Seo MODULE_DESCRIPTION("CM36651 proximity/ambient light sensor driver");
750e590d451SBeomho Seo MODULE_LICENSE("GPL v2");
751