xref: /linux/drivers/iio/light/cm36651.c (revision a451521d2229266dae0b876efb5999d82d03850e)
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 */
53e590d451SBeomho Seo #define CM36651_CS_IT1			0x00 /* Integration time 80000 usec */
54e590d451SBeomho Seo #define CM36651_CS_IT2			0x40 /* Integration time 160000 usec */
55e590d451SBeomho Seo #define CM36651_CS_IT3			0x80 /* Integration time 320000 usec */
56e590d451SBeomho Seo #define CM36651_CS_IT4			0xC0 /* Integration time 640000 usec */
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 */
67e590d451SBeomho Seo #define CM36651_PS_IT1			0x00 /* Integration time 320 usec */
68e590d451SBeomho Seo #define CM36651_PS_IT2			0x10 /* Integration time 420 usec */
69e590d451SBeomho Seo #define CM36651_PS_IT3			0x20 /* Integration time 520 usec */
70e590d451SBeomho Seo #define CM36651_PS_IT4			0x30 /* Integration time 640 usec */
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 
96e590d451SBeomho Seo #define CM36651_CS_INT_TIME_AVAIL	"80000 160000 320000 640000"
97e590d451SBeomho Seo #define CM36651_PS_INT_TIME_AVAIL	"320 420 520 640"
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,
359e590d451SBeomho Seo 				struct iio_chan_spec const *chan, int *val)
360e590d451SBeomho Seo {
361e590d451SBeomho Seo 	switch (chan->type) {
362e590d451SBeomho Seo 	case IIO_LIGHT:
363e590d451SBeomho Seo 		if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT1)
364e590d451SBeomho Seo 			*val = 80000;
365e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT2)
366e590d451SBeomho Seo 			*val = 160000;
367e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT3)
368e590d451SBeomho Seo 			*val = 320000;
369e590d451SBeomho Seo 		else if (cm36651->cs_int_time[chan->address] == CM36651_CS_IT4)
370e590d451SBeomho Seo 			*val = 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)
376e590d451SBeomho Seo 			*val = 320;
377e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT2)
378e590d451SBeomho Seo 			*val = 420;
379e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT3)
380e590d451SBeomho Seo 			*val = 520;
381e590d451SBeomho Seo 		else if (cm36651->ps_int_time == CM36651_PS_IT4)
382e590d451SBeomho Seo 			*val = 640;
383e590d451SBeomho Seo 		else
384e590d451SBeomho Seo 			return -EINVAL;
385e590d451SBeomho Seo 		break;
386e590d451SBeomho Seo 	default:
387e590d451SBeomho Seo 		return -EINVAL;
388e590d451SBeomho Seo 	}
389e590d451SBeomho Seo 
390e590d451SBeomho 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:
462e590d451SBeomho Seo 		ret = cm36651_read_int_time(cm36651, chan, val);
463e590d451SBeomho Seo 		break;
464e590d451SBeomho Seo 	default:
465e590d451SBeomho Seo 		ret = -EINVAL;
466e590d451SBeomho Seo 	}
467e590d451SBeomho Seo 
468e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
469e590d451SBeomho Seo 
470e590d451SBeomho Seo 	return ret;
471e590d451SBeomho Seo }
472e590d451SBeomho Seo 
473e590d451SBeomho Seo static int cm36651_write_raw(struct iio_dev *indio_dev,
474e590d451SBeomho Seo 			     struct iio_chan_spec const *chan,
475e590d451SBeomho Seo 			     int val, int val2, long mask)
476e590d451SBeomho Seo {
477e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
478e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
479e590d451SBeomho Seo 	int ret = -EINVAL;
480e590d451SBeomho Seo 
481e590d451SBeomho Seo 	if (mask == IIO_CHAN_INFO_INT_TIME) {
482e590d451SBeomho Seo 		ret = cm36651_write_int_time(cm36651, chan, val);
483e590d451SBeomho Seo 		if (ret < 0)
484e590d451SBeomho Seo 			dev_err(&client->dev, "Integration time write failed\n");
485e590d451SBeomho Seo 	}
486e590d451SBeomho Seo 
487e590d451SBeomho Seo 	return ret;
488e590d451SBeomho Seo }
489e590d451SBeomho Seo 
490e590d451SBeomho Seo static int cm36651_read_prox_thresh(struct iio_dev *indio_dev,
491bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
492bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
493bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
494bb7f9d90SLars-Peter Clausen 					enum iio_event_info info,
495bb7f9d90SLars-Peter Clausen 					int *val, int *val2)
496e590d451SBeomho Seo {
497e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
498e590d451SBeomho Seo 
499e590d451SBeomho Seo 	*val = cm36651->ps_ctrl_regs[CM36651_PS_THD];
500e590d451SBeomho Seo 
501e590d451SBeomho Seo 	return 0;
502e590d451SBeomho Seo }
503e590d451SBeomho Seo 
504e590d451SBeomho Seo static int cm36651_write_prox_thresh(struct iio_dev *indio_dev,
505bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
506bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
507bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
508bb7f9d90SLars-Peter Clausen 					enum iio_event_info info,
509bb7f9d90SLars-Peter Clausen 					int val, int val2)
510e590d451SBeomho Seo {
511e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
512e590d451SBeomho Seo 	struct i2c_client *client = cm36651->client;
513e590d451SBeomho Seo 	int ret;
514e590d451SBeomho Seo 
515e590d451SBeomho Seo 	if (val < 3 || val > 255)
516e590d451SBeomho Seo 		return -EINVAL;
517e590d451SBeomho Seo 
518e590d451SBeomho Seo 	cm36651->ps_ctrl_regs[CM36651_PS_THD] = val;
519e590d451SBeomho Seo 	ret = i2c_smbus_write_byte_data(cm36651->ps_client, CM36651_PS_THD,
520e590d451SBeomho Seo 					cm36651->ps_ctrl_regs[CM36651_PS_THD]);
521e590d451SBeomho Seo 
522e590d451SBeomho Seo 	if (ret < 0) {
523e590d451SBeomho Seo 		dev_err(&client->dev, "PS threshold write failed: %d\n", ret);
524e590d451SBeomho Seo 		return ret;
525e590d451SBeomho Seo 	}
526e590d451SBeomho Seo 
527e590d451SBeomho Seo 	return 0;
528e590d451SBeomho Seo }
529e590d451SBeomho Seo 
530e590d451SBeomho Seo static int cm36651_write_prox_event_config(struct iio_dev *indio_dev,
531bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
532bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
533bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir,
534bb7f9d90SLars-Peter Clausen 					int state)
535e590d451SBeomho Seo {
536e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
537e590d451SBeomho Seo 	int cmd, ret = -EINVAL;
538e590d451SBeomho Seo 
539e590d451SBeomho Seo 	mutex_lock(&cm36651->lock);
540e590d451SBeomho Seo 
541e590d451SBeomho Seo 	cmd = state ? CM36651_CMD_PROX_EV_EN : CM36651_CMD_PROX_EV_DIS;
542e590d451SBeomho Seo 	ret = cm36651_set_operation_mode(cm36651, cmd);
543e590d451SBeomho Seo 
544e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
545e590d451SBeomho Seo 
546e590d451SBeomho Seo 	return ret;
547e590d451SBeomho Seo }
548e590d451SBeomho Seo 
549e590d451SBeomho Seo static int cm36651_read_prox_event_config(struct iio_dev *indio_dev,
550bb7f9d90SLars-Peter Clausen 					const struct iio_chan_spec *chan,
551bb7f9d90SLars-Peter Clausen 					enum iio_event_type type,
552bb7f9d90SLars-Peter Clausen 					enum iio_event_direction dir)
553e590d451SBeomho Seo {
554e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
555e590d451SBeomho Seo 	int event_en;
556e590d451SBeomho Seo 
557e590d451SBeomho Seo 	mutex_lock(&cm36651->lock);
558e590d451SBeomho Seo 
559e590d451SBeomho Seo 	event_en = test_bit(CM36651_PROXIMITY_EV_EN, &cm36651->flags);
560e590d451SBeomho Seo 
561e590d451SBeomho Seo 	mutex_unlock(&cm36651->lock);
562e590d451SBeomho Seo 
563e590d451SBeomho Seo 	return event_en;
564e590d451SBeomho Seo }
565e590d451SBeomho Seo 
566e590d451SBeomho Seo #define CM36651_LIGHT_CHANNEL(_color, _idx) {		\
567e590d451SBeomho Seo 	.type = IIO_LIGHT,				\
568e590d451SBeomho Seo 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |	\
569e590d451SBeomho Seo 			BIT(IIO_CHAN_INFO_INT_TIME),	\
570e590d451SBeomho Seo 	.address = _idx,				\
571e590d451SBeomho Seo 	.modified = 1,					\
572e590d451SBeomho Seo 	.channel2 = IIO_MOD_LIGHT_##_color,		\
573e590d451SBeomho Seo }							\
574e590d451SBeomho Seo 
575bb7f9d90SLars-Peter Clausen static const struct iio_event_spec cm36651_event_spec[] = {
576bb7f9d90SLars-Peter Clausen 	{
577bb7f9d90SLars-Peter Clausen 		.type = IIO_EV_TYPE_THRESH,
578bb7f9d90SLars-Peter Clausen 		.dir = IIO_EV_DIR_EITHER,
579bb7f9d90SLars-Peter Clausen 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
580bb7f9d90SLars-Peter Clausen 				BIT(IIO_EV_INFO_ENABLE),
581bb7f9d90SLars-Peter Clausen 	}
582bb7f9d90SLars-Peter Clausen };
583bb7f9d90SLars-Peter Clausen 
584e590d451SBeomho Seo static const struct iio_chan_spec cm36651_channels[] = {
585e590d451SBeomho Seo 	{
586e590d451SBeomho Seo 		.type = IIO_PROXIMITY,
587e590d451SBeomho Seo 		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
588e590d451SBeomho Seo 				BIT(IIO_CHAN_INFO_INT_TIME),
589bb7f9d90SLars-Peter Clausen 		.event_spec = cm36651_event_spec,
590bb7f9d90SLars-Peter Clausen 		.num_event_specs = ARRAY_SIZE(cm36651_event_spec),
591e590d451SBeomho Seo 	},
592e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(RED, CM36651_LIGHT_CHANNEL_IDX_RED),
593e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(GREEN, CM36651_LIGHT_CHANNEL_IDX_GREEN),
594e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(BLUE, CM36651_LIGHT_CHANNEL_IDX_BLUE),
595e590d451SBeomho Seo 	CM36651_LIGHT_CHANNEL(CLEAR, CM36651_LIGHT_CHANNEL_IDX_CLEAR),
596e590d451SBeomho Seo };
597e590d451SBeomho Seo 
598e590d451SBeomho Seo static IIO_CONST_ATTR(in_illuminance_integration_time_available,
599e590d451SBeomho Seo 					CM36651_CS_INT_TIME_AVAIL);
600e590d451SBeomho Seo static IIO_CONST_ATTR(in_proximity_integration_time_available,
601e590d451SBeomho Seo 					CM36651_PS_INT_TIME_AVAIL);
602e590d451SBeomho Seo 
603e590d451SBeomho Seo static struct attribute *cm36651_attributes[] = {
604e590d451SBeomho Seo 	&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
605e590d451SBeomho Seo 	&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
606e590d451SBeomho Seo 	NULL,
607e590d451SBeomho Seo };
608e590d451SBeomho Seo 
609e590d451SBeomho Seo static const struct attribute_group cm36651_attribute_group = {
610e590d451SBeomho Seo 	.attrs = cm36651_attributes
611e590d451SBeomho Seo };
612e590d451SBeomho Seo 
613e590d451SBeomho Seo static const struct iio_info cm36651_info = {
614e590d451SBeomho Seo 	.driver_module		= THIS_MODULE,
615e590d451SBeomho Seo 	.read_raw		= &cm36651_read_raw,
616e590d451SBeomho Seo 	.write_raw		= &cm36651_write_raw,
617cb955852SLars-Peter Clausen 	.read_event_value	= &cm36651_read_prox_thresh,
618cb955852SLars-Peter Clausen 	.write_event_value	= &cm36651_write_prox_thresh,
619cb955852SLars-Peter Clausen 	.read_event_config	= &cm36651_read_prox_event_config,
620cb955852SLars-Peter Clausen 	.write_event_config	= &cm36651_write_prox_event_config,
621e590d451SBeomho Seo 	.attrs			= &cm36651_attribute_group,
622e590d451SBeomho Seo };
623e590d451SBeomho Seo 
624e590d451SBeomho Seo static int cm36651_probe(struct i2c_client *client,
625e590d451SBeomho Seo 			     const struct i2c_device_id *id)
626e590d451SBeomho Seo {
627e590d451SBeomho Seo 	struct cm36651_data *cm36651;
628e590d451SBeomho Seo 	struct iio_dev *indio_dev;
629e590d451SBeomho Seo 	int ret;
630e590d451SBeomho Seo 
631e590d451SBeomho Seo 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm36651));
632e590d451SBeomho Seo 	if (!indio_dev)
633e590d451SBeomho Seo 		return -ENOMEM;
634e590d451SBeomho Seo 
635e590d451SBeomho Seo 	cm36651 = iio_priv(indio_dev);
636e590d451SBeomho Seo 
637e590d451SBeomho Seo 	cm36651->vled_reg = devm_regulator_get(&client->dev, "vled");
638e590d451SBeomho Seo 	if (IS_ERR(cm36651->vled_reg)) {
639e590d451SBeomho Seo 		dev_err(&client->dev, "get regulator vled failed\n");
640e590d451SBeomho Seo 		return PTR_ERR(cm36651->vled_reg);
641e590d451SBeomho Seo 	}
642e590d451SBeomho Seo 
643e590d451SBeomho Seo 	ret = regulator_enable(cm36651->vled_reg);
644e590d451SBeomho Seo 	if (ret) {
645e590d451SBeomho Seo 		dev_err(&client->dev, "enable regulator vled failed\n");
646e590d451SBeomho Seo 		return ret;
647e590d451SBeomho Seo 	}
648e590d451SBeomho Seo 
649e590d451SBeomho Seo 	i2c_set_clientdata(client, indio_dev);
650e590d451SBeomho Seo 
651e590d451SBeomho Seo 	cm36651->client = client;
652e590d451SBeomho Seo 	cm36651->ps_client = i2c_new_dummy(client->adapter,
653e590d451SBeomho Seo 						     CM36651_I2C_ADDR_PS);
654e590d451SBeomho Seo 	cm36651->ara_client = i2c_new_dummy(client->adapter, CM36651_ARA);
655e590d451SBeomho Seo 	mutex_init(&cm36651->lock);
656e590d451SBeomho Seo 	indio_dev->dev.parent = &client->dev;
657e590d451SBeomho Seo 	indio_dev->channels = cm36651_channels;
658e590d451SBeomho Seo 	indio_dev->num_channels = ARRAY_SIZE(cm36651_channels);
659e590d451SBeomho Seo 	indio_dev->info = &cm36651_info;
660e590d451SBeomho Seo 	indio_dev->name = id->name;
661e590d451SBeomho Seo 	indio_dev->modes = INDIO_DIRECT_MODE;
662e590d451SBeomho Seo 
663e590d451SBeomho Seo 	ret = cm36651_setup_reg(cm36651);
664e590d451SBeomho Seo 	if (ret) {
665e590d451SBeomho Seo 		dev_err(&client->dev, "%s: register setup failed\n", __func__);
666e590d451SBeomho Seo 		goto error_disable_reg;
667e590d451SBeomho Seo 	}
668e590d451SBeomho Seo 
669e590d451SBeomho Seo 	ret = request_threaded_irq(client->irq, NULL, cm36651_irq_handler,
670e590d451SBeomho Seo 					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
671e590d451SBeomho Seo 							"cm36651", indio_dev);
672e590d451SBeomho Seo 	if (ret) {
673e590d451SBeomho Seo 		dev_err(&client->dev, "%s: request irq failed\n", __func__);
674e590d451SBeomho Seo 		goto error_disable_reg;
675e590d451SBeomho Seo 	}
676e590d451SBeomho Seo 
677e590d451SBeomho Seo 	ret = iio_device_register(indio_dev);
678e590d451SBeomho Seo 	if (ret) {
679e590d451SBeomho Seo 		dev_err(&client->dev, "%s: regist device failed\n", __func__);
680e590d451SBeomho Seo 		goto error_free_irq;
681e590d451SBeomho Seo 	}
682e590d451SBeomho Seo 
683e590d451SBeomho Seo 	return 0;
684e590d451SBeomho Seo 
685e590d451SBeomho Seo error_free_irq:
686e590d451SBeomho Seo 	free_irq(client->irq, indio_dev);
687e590d451SBeomho Seo error_disable_reg:
688e590d451SBeomho Seo 	regulator_disable(cm36651->vled_reg);
689e590d451SBeomho Seo 	return ret;
690e590d451SBeomho Seo }
691e590d451SBeomho Seo 
692e590d451SBeomho Seo static int cm36651_remove(struct i2c_client *client)
693e590d451SBeomho Seo {
694e590d451SBeomho Seo 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
695e590d451SBeomho Seo 	struct cm36651_data *cm36651 = iio_priv(indio_dev);
696e590d451SBeomho Seo 
697e590d451SBeomho Seo 	iio_device_unregister(indio_dev);
698e590d451SBeomho Seo 	regulator_disable(cm36651->vled_reg);
699e590d451SBeomho Seo 	free_irq(client->irq, indio_dev);
700e590d451SBeomho Seo 
701e590d451SBeomho Seo 	return 0;
702e590d451SBeomho Seo }
703e590d451SBeomho Seo 
704e590d451SBeomho Seo static const struct i2c_device_id cm36651_id[] = {
705e590d451SBeomho Seo 	{ "cm36651", 0 },
706e590d451SBeomho Seo 	{ }
707e590d451SBeomho Seo };
708e590d451SBeomho Seo 
709e590d451SBeomho Seo MODULE_DEVICE_TABLE(i2c, cm36651_id);
710e590d451SBeomho Seo 
711e590d451SBeomho Seo static const struct of_device_id cm36651_of_match[] = {
712e590d451SBeomho Seo 	{ .compatible = "capella,cm36651" },
713e590d451SBeomho Seo 	{ }
714e590d451SBeomho Seo };
715e590d451SBeomho Seo 
716e590d451SBeomho Seo static struct i2c_driver cm36651_driver = {
717e590d451SBeomho Seo 	.driver = {
718e590d451SBeomho Seo 		.name	= "cm36651",
719*a451521dSSachin Kamat 		.of_match_table = cm36651_of_match,
720e590d451SBeomho Seo 		.owner	= THIS_MODULE,
721e590d451SBeomho Seo 	},
722e590d451SBeomho Seo 	.probe		= cm36651_probe,
723e590d451SBeomho Seo 	.remove		= cm36651_remove,
724e590d451SBeomho Seo 	.id_table	= cm36651_id,
725e590d451SBeomho Seo };
726e590d451SBeomho Seo 
727e590d451SBeomho Seo module_i2c_driver(cm36651_driver);
728e590d451SBeomho Seo 
729e590d451SBeomho Seo MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
730e590d451SBeomho Seo MODULE_DESCRIPTION("CM36651 proximity/ambient light sensor driver");
731e590d451SBeomho Seo MODULE_LICENSE("GPL v2");
732