xref: /linux/drivers/iio/light/cm32181.c (revision 68c1b3dd5c48b2323067f8c1f0649ae2f31ab20b)
1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2971672c0SKevin Tsai /*
3971672c0SKevin Tsai  * Copyright (C) 2013 Capella Microsystems Inc.
4971672c0SKevin Tsai  * Author: Kevin Tsai <ktsai@capellamicro.com>
5971672c0SKevin Tsai  */
6971672c0SKevin Tsai 
7d34ca613SHans de Goede #include <linux/acpi.h>
8971672c0SKevin Tsai #include <linux/delay.h>
9971672c0SKevin Tsai #include <linux/err.h>
10971672c0SKevin Tsai #include <linux/i2c.h>
11971672c0SKevin Tsai #include <linux/mutex.h>
12971672c0SKevin Tsai #include <linux/module.h>
139065b780SJonathan Cameron #include <linux/mod_devicetable.h>
14971672c0SKevin Tsai #include <linux/interrupt.h>
15971672c0SKevin Tsai #include <linux/regulator/consumer.h>
16971672c0SKevin Tsai #include <linux/iio/iio.h>
17971672c0SKevin Tsai #include <linux/iio/sysfs.h>
18971672c0SKevin Tsai #include <linux/iio/events.h>
19971672c0SKevin Tsai #include <linux/init.h>
20971672c0SKevin Tsai 
21971672c0SKevin Tsai /* Registers Address */
22971672c0SKevin Tsai #define CM32181_REG_ADDR_CMD		0x00
233bf4a59cSHans de Goede #define CM32181_REG_ADDR_WH		0x01
243bf4a59cSHans de Goede #define CM32181_REG_ADDR_WL		0x02
253bf4a59cSHans de Goede #define CM32181_REG_ADDR_TEST		0x03
26971672c0SKevin Tsai #define CM32181_REG_ADDR_ALS		0x04
27971672c0SKevin Tsai #define CM32181_REG_ADDR_STATUS		0x06
28971672c0SKevin Tsai #define CM32181_REG_ADDR_ID		0x07
29971672c0SKevin Tsai 
30971672c0SKevin Tsai /* Number of Configurable Registers */
317574cb1dSHans de Goede #define CM32181_CONF_REG_NUM		4
32971672c0SKevin Tsai 
33971672c0SKevin Tsai /* CMD register */
343bf4a59cSHans de Goede #define CM32181_CMD_ALS_DISABLE		BIT(0)
353bf4a59cSHans de Goede #define CM32181_CMD_ALS_INT_EN		BIT(1)
363bf4a59cSHans de Goede #define CM32181_CMD_ALS_THRES_WINDOW	BIT(2)
373bf4a59cSHans de Goede 
383bf4a59cSHans de Goede #define CM32181_CMD_ALS_PERS_SHIFT	4
393bf4a59cSHans de Goede #define CM32181_CMD_ALS_PERS_MASK	(0x03 << CM32181_CMD_ALS_PERS_SHIFT)
403bf4a59cSHans de Goede #define CM32181_CMD_ALS_PERS_DEFAULT	(0x01 << CM32181_CMD_ALS_PERS_SHIFT)
41971672c0SKevin Tsai 
42971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_SHIFT	6
43971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_MASK		(0x0F << CM32181_CMD_ALS_IT_SHIFT)
44971672c0SKevin Tsai #define CM32181_CMD_ALS_IT_DEFAULT	(0x00 << CM32181_CMD_ALS_IT_SHIFT)
45971672c0SKevin Tsai 
46971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_SHIFT	11
47971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_MASK		(0x03 << CM32181_CMD_ALS_SM_SHIFT)
48971672c0SKevin Tsai #define CM32181_CMD_ALS_SM_DEFAULT	(0x01 << CM32181_CMD_ALS_SM_SHIFT)
49971672c0SKevin Tsai 
50f50f9831SHans de Goede #define CM32181_LUX_PER_BIT		500	/* ALS_SM=01 IT=800ms */
51f50f9831SHans de Goede #define CM32181_LUX_PER_BIT_RESOLUTION	100000
52f50f9831SHans de Goede #define CM32181_LUX_PER_BIT_BASE_IT	800000	/* Based on IT=800ms */
53f50f9831SHans de Goede #define CM32181_CALIBSCALE_DEFAULT	100000
54f50f9831SHans de Goede #define CM32181_CALIBSCALE_RESOLUTION	100000
55971672c0SKevin Tsai 
56c1e62062SHans de Goede #define SMBUS_ALERT_RESPONSE_ADDRESS	0x0c
57c1e62062SHans de Goede 
58d34ca613SHans de Goede /* CPM0 Index 0: device-id (3218 or 32181), 1: Unknown, 2: init_regs_bitmap */
59d34ca613SHans de Goede #define CPM0_REGS_BITMAP		2
60d34ca613SHans de Goede #define CPM0_HEADER_SIZE		3
61d34ca613SHans de Goede 
62d34ca613SHans de Goede /* CPM1 Index 0: lux_per_bit, 1: calibscale, 2: resolution (100000) */
63d34ca613SHans de Goede #define CPM1_LUX_PER_BIT		0
64d34ca613SHans de Goede #define CPM1_CALIBSCALE			1
65d34ca613SHans de Goede #define CPM1_SIZE			3
66d34ca613SHans de Goede 
6702cdab2aSHans de Goede /* CM3218 Family */
6802cdab2aSHans de Goede static const int cm3218_als_it_bits[] = { 0, 1, 2, 3 };
6902cdab2aSHans de Goede static const int cm3218_als_it_values[] = { 100000, 200000, 400000, 800000 };
7002cdab2aSHans de Goede 
7102cdab2aSHans de Goede /* CM32181 Family */
7202cdab2aSHans de Goede static const int cm32181_als_it_bits[] = { 12, 8, 0, 1, 2, 3 };
7302cdab2aSHans de Goede static const int cm32181_als_it_values[] = {
7402cdab2aSHans de Goede 	25000, 50000, 100000, 200000, 400000, 800000
7502cdab2aSHans de Goede };
76971672c0SKevin Tsai 
77971672c0SKevin Tsai struct cm32181_chip {
78971672c0SKevin Tsai 	struct i2c_client *client;
79d34ca613SHans de Goede 	struct device *dev;
80971672c0SKevin Tsai 	struct mutex lock;
81971672c0SKevin Tsai 	u16 conf_regs[CM32181_CONF_REG_NUM];
827574cb1dSHans de Goede 	unsigned long init_regs_bitmap;
83971672c0SKevin Tsai 	int calibscale;
8463b1be78SHans de Goede 	int lux_per_bit;
8563b1be78SHans de Goede 	int lux_per_bit_base_it;
8602cdab2aSHans de Goede 	int num_als_it;
8702cdab2aSHans de Goede 	const int *als_it_bits;
8802cdab2aSHans de Goede 	const int *als_it_values;
89971672c0SKevin Tsai };
90971672c0SKevin Tsai 
91d34ca613SHans de Goede static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2);
92d34ca613SHans de Goede 
93d34ca613SHans de Goede #ifdef CONFIG_ACPI
94d34ca613SHans de Goede /**
95d34ca613SHans de Goede  * cm32181_acpi_get_cpm() - Get CPM object from ACPI
9661f3e708SLee Jones  * @dev:	pointer of struct device.
9761f3e708SLee Jones  * @obj_name:	pointer of ACPI object name.
9861f3e708SLee Jones  * @values:	pointer of array for return elements.
9961f3e708SLee Jones  * @count:	maximum size of return array.
100d34ca613SHans de Goede  *
101d34ca613SHans de Goede  * Convert ACPI CPM table to array.
102d34ca613SHans de Goede  *
103d34ca613SHans de Goede  * Return: -ENODEV for fail.  Otherwise is number of elements.
104d34ca613SHans de Goede  */
105d34ca613SHans de Goede static int cm32181_acpi_get_cpm(struct device *dev, char *obj_name,
106d34ca613SHans de Goede 				u64 *values, int count)
107d34ca613SHans de Goede {
108d34ca613SHans de Goede 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
109d34ca613SHans de Goede 	union acpi_object *cpm, *elem;
110d34ca613SHans de Goede 	acpi_handle handle;
111d34ca613SHans de Goede 	acpi_status status;
112d34ca613SHans de Goede 	int i;
113d34ca613SHans de Goede 
114d34ca613SHans de Goede 	handle = ACPI_HANDLE(dev);
115d34ca613SHans de Goede 	if (!handle)
116d34ca613SHans de Goede 		return -ENODEV;
117d34ca613SHans de Goede 
118d34ca613SHans de Goede 	status = acpi_evaluate_object(handle, obj_name, NULL, &buffer);
119d34ca613SHans de Goede 	if (ACPI_FAILURE(status)) {
120d34ca613SHans de Goede 		dev_err(dev, "object %s not found\n", obj_name);
121d34ca613SHans de Goede 		return -ENODEV;
122d34ca613SHans de Goede 	}
123d34ca613SHans de Goede 
124d34ca613SHans de Goede 	cpm = buffer.pointer;
125d34ca613SHans de Goede 	if (cpm->package.count > count)
126d34ca613SHans de Goede 		dev_warn(dev, "%s table contains %u values, only using first %d values\n",
127d34ca613SHans de Goede 			 obj_name, cpm->package.count, count);
128d34ca613SHans de Goede 
129d34ca613SHans de Goede 	count = min_t(int, cpm->package.count, count);
130d34ca613SHans de Goede 	for (i = 0; i < count; i++) {
131d34ca613SHans de Goede 		elem = &(cpm->package.elements[i]);
132d34ca613SHans de Goede 		values[i] = elem->integer.value;
133d34ca613SHans de Goede 	}
134d34ca613SHans de Goede 
135d34ca613SHans de Goede 	kfree(buffer.pointer);
136d34ca613SHans de Goede 
137d34ca613SHans de Goede 	return count;
138d34ca613SHans de Goede }
139d34ca613SHans de Goede 
140d34ca613SHans de Goede static void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181)
141d34ca613SHans de Goede {
142d34ca613SHans de Goede 	u64 vals[CPM0_HEADER_SIZE + CM32181_CONF_REG_NUM];
143d34ca613SHans de Goede 	struct device *dev = cm32181->dev;
144d34ca613SHans de Goede 	int i, count;
145d34ca613SHans de Goede 
146d34ca613SHans de Goede 	count = cm32181_acpi_get_cpm(dev, "CPM0", vals, ARRAY_SIZE(vals));
147d34ca613SHans de Goede 	if (count <= CPM0_HEADER_SIZE)
148d34ca613SHans de Goede 		return;
149d34ca613SHans de Goede 
150d34ca613SHans de Goede 	count -= CPM0_HEADER_SIZE;
151d34ca613SHans de Goede 
152d34ca613SHans de Goede 	cm32181->init_regs_bitmap = vals[CPM0_REGS_BITMAP];
153d34ca613SHans de Goede 	cm32181->init_regs_bitmap &= GENMASK(count - 1, 0);
154d34ca613SHans de Goede 	for_each_set_bit(i, &cm32181->init_regs_bitmap, count)
155d34ca613SHans de Goede 		cm32181->conf_regs[i] =	vals[CPM0_HEADER_SIZE + i];
156d34ca613SHans de Goede 
157d34ca613SHans de Goede 	count = cm32181_acpi_get_cpm(dev, "CPM1", vals, ARRAY_SIZE(vals));
158d34ca613SHans de Goede 	if (count != CPM1_SIZE)
159d34ca613SHans de Goede 		return;
160d34ca613SHans de Goede 
161d34ca613SHans de Goede 	cm32181->lux_per_bit = vals[CPM1_LUX_PER_BIT];
162d34ca613SHans de Goede 
163d34ca613SHans de Goede 	/* Check for uncalibrated devices */
164d34ca613SHans de Goede 	if (vals[CPM1_CALIBSCALE] == CM32181_CALIBSCALE_DEFAULT)
165d34ca613SHans de Goede 		return;
166d34ca613SHans de Goede 
167d34ca613SHans de Goede 	cm32181->calibscale = vals[CPM1_CALIBSCALE];
168d34ca613SHans de Goede 	/* CPM1 lux_per_bit is for the current it value */
169d34ca613SHans de Goede 	cm32181_read_als_it(cm32181, &cm32181->lux_per_bit_base_it);
170d34ca613SHans de Goede }
171d34ca613SHans de Goede #else
172d34ca613SHans de Goede static void cm32181_acpi_parse_cpm_tables(struct cm32181_chip *cm32181)
173d34ca613SHans de Goede {
174d34ca613SHans de Goede }
175d34ca613SHans de Goede #endif /* CONFIG_ACPI */
176d34ca613SHans de Goede 
177971672c0SKevin Tsai /**
178971672c0SKevin Tsai  * cm32181_reg_init() - Initialize CM32181 registers
179971672c0SKevin Tsai  * @cm32181:	pointer of struct cm32181.
180971672c0SKevin Tsai  *
181971672c0SKevin Tsai  * Initialize CM32181 ambient light sensor register to default values.
182971672c0SKevin Tsai  *
183971672c0SKevin Tsai  * Return: 0 for success; otherwise for error code.
184971672c0SKevin Tsai  */
185971672c0SKevin Tsai static int cm32181_reg_init(struct cm32181_chip *cm32181)
186971672c0SKevin Tsai {
187971672c0SKevin Tsai 	struct i2c_client *client = cm32181->client;
188971672c0SKevin Tsai 	int i;
189971672c0SKevin Tsai 	s32 ret;
190971672c0SKevin Tsai 
191971672c0SKevin Tsai 	ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID);
192971672c0SKevin Tsai 	if (ret < 0)
193971672c0SKevin Tsai 		return ret;
194971672c0SKevin Tsai 
195971672c0SKevin Tsai 	/* check device ID */
19602cdab2aSHans de Goede 	switch (ret & 0xFF) {
19702cdab2aSHans de Goede 	case 0x18: /* CM3218 */
19802cdab2aSHans de Goede 		cm32181->num_als_it = ARRAY_SIZE(cm3218_als_it_bits);
19902cdab2aSHans de Goede 		cm32181->als_it_bits = cm3218_als_it_bits;
20002cdab2aSHans de Goede 		cm32181->als_it_values = cm3218_als_it_values;
20102cdab2aSHans de Goede 		break;
20202cdab2aSHans de Goede 	case 0x81: /* CM32181 */
20302cdab2aSHans de Goede 	case 0x82: /* CM32182, fully compat. with CM32181 */
20402cdab2aSHans de Goede 		cm32181->num_als_it = ARRAY_SIZE(cm32181_als_it_bits);
20502cdab2aSHans de Goede 		cm32181->als_it_bits = cm32181_als_it_bits;
20602cdab2aSHans de Goede 		cm32181->als_it_values = cm32181_als_it_values;
20702cdab2aSHans de Goede 		break;
20802cdab2aSHans de Goede 	default:
209971672c0SKevin Tsai 		return -ENODEV;
21002cdab2aSHans de Goede 	}
211971672c0SKevin Tsai 
212971672c0SKevin Tsai 	/* Default Values */
2133bf4a59cSHans de Goede 	cm32181->conf_regs[CM32181_REG_ADDR_CMD] =
214971672c0SKevin Tsai 			CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT;
2157574cb1dSHans de Goede 	cm32181->init_regs_bitmap = BIT(CM32181_REG_ADDR_CMD);
216971672c0SKevin Tsai 	cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT;
21763b1be78SHans de Goede 	cm32181->lux_per_bit = CM32181_LUX_PER_BIT;
21863b1be78SHans de Goede 	cm32181->lux_per_bit_base_it = CM32181_LUX_PER_BIT_BASE_IT;
219971672c0SKevin Tsai 
220d34ca613SHans de Goede 	if (ACPI_HANDLE(cm32181->dev))
221d34ca613SHans de Goede 		cm32181_acpi_parse_cpm_tables(cm32181);
222d34ca613SHans de Goede 
223971672c0SKevin Tsai 	/* Initialize registers*/
2247574cb1dSHans de Goede 	for_each_set_bit(i, &cm32181->init_regs_bitmap, CM32181_CONF_REG_NUM) {
2257574cb1dSHans de Goede 		ret = i2c_smbus_write_word_data(client, i,
226971672c0SKevin Tsai 						cm32181->conf_regs[i]);
227971672c0SKevin Tsai 		if (ret < 0)
228971672c0SKevin Tsai 			return ret;
229971672c0SKevin Tsai 	}
230971672c0SKevin Tsai 
231971672c0SKevin Tsai 	return 0;
232971672c0SKevin Tsai }
233971672c0SKevin Tsai 
234971672c0SKevin Tsai /**
235971672c0SKevin Tsai  *  cm32181_read_als_it() - Get sensor integration time (ms)
236971672c0SKevin Tsai  *  @cm32181:	pointer of struct cm32181
2371463a166SBeomho Seo  *  @val2:	pointer of int to load the als_it value.
238971672c0SKevin Tsai  *
239c12d80aeSHans de Goede  *  Report the current integration time in milliseconds.
240971672c0SKevin Tsai  *
2411463a166SBeomho Seo  *  Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
242971672c0SKevin Tsai  */
2431463a166SBeomho Seo static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2)
244971672c0SKevin Tsai {
245971672c0SKevin Tsai 	u16 als_it;
246971672c0SKevin Tsai 	int i;
247971672c0SKevin Tsai 
248971672c0SKevin Tsai 	als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD];
249971672c0SKevin Tsai 	als_it &= CM32181_CMD_ALS_IT_MASK;
250971672c0SKevin Tsai 	als_it >>= CM32181_CMD_ALS_IT_SHIFT;
25102cdab2aSHans de Goede 	for (i = 0; i < cm32181->num_als_it; i++) {
25202cdab2aSHans de Goede 		if (als_it == cm32181->als_it_bits[i]) {
25302cdab2aSHans de Goede 			*val2 = cm32181->als_it_values[i];
2541463a166SBeomho Seo 			return IIO_VAL_INT_PLUS_MICRO;
255971672c0SKevin Tsai 		}
256971672c0SKevin Tsai 	}
257971672c0SKevin Tsai 
258971672c0SKevin Tsai 	return -EINVAL;
259971672c0SKevin Tsai }
260971672c0SKevin Tsai 
261971672c0SKevin Tsai /**
262971672c0SKevin Tsai  * cm32181_write_als_it() - Write sensor integration time
263971672c0SKevin Tsai  * @cm32181:	pointer of struct cm32181.
264971672c0SKevin Tsai  * @val:	integration time by millisecond.
265971672c0SKevin Tsai  *
266971672c0SKevin Tsai  * Convert integration time (ms) to sensor value.
267971672c0SKevin Tsai  *
268971672c0SKevin Tsai  * Return: i2c_smbus_write_word_data command return value.
269971672c0SKevin Tsai  */
270971672c0SKevin Tsai static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
271971672c0SKevin Tsai {
272971672c0SKevin Tsai 	struct i2c_client *client = cm32181->client;
273971672c0SKevin Tsai 	u16 als_it;
274971672c0SKevin Tsai 	int ret, i, n;
275971672c0SKevin Tsai 
27602cdab2aSHans de Goede 	n = cm32181->num_als_it;
277971672c0SKevin Tsai 	for (i = 0; i < n; i++)
27802cdab2aSHans de Goede 		if (val <= cm32181->als_it_values[i])
279971672c0SKevin Tsai 			break;
280971672c0SKevin Tsai 	if (i >= n)
281971672c0SKevin Tsai 		i = n - 1;
282971672c0SKevin Tsai 
28302cdab2aSHans de Goede 	als_it = cm32181->als_it_bits[i];
284971672c0SKevin Tsai 	als_it <<= CM32181_CMD_ALS_IT_SHIFT;
285971672c0SKevin Tsai 
286971672c0SKevin Tsai 	mutex_lock(&cm32181->lock);
287971672c0SKevin Tsai 	cm32181->conf_regs[CM32181_REG_ADDR_CMD] &=
288971672c0SKevin Tsai 		~CM32181_CMD_ALS_IT_MASK;
289971672c0SKevin Tsai 	cm32181->conf_regs[CM32181_REG_ADDR_CMD] |=
290971672c0SKevin Tsai 		als_it;
291971672c0SKevin Tsai 	ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
292971672c0SKevin Tsai 			cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
293971672c0SKevin Tsai 	mutex_unlock(&cm32181->lock);
294971672c0SKevin Tsai 
295971672c0SKevin Tsai 	return ret;
296971672c0SKevin Tsai }
297971672c0SKevin Tsai 
298971672c0SKevin Tsai /**
299971672c0SKevin Tsai  * cm32181_get_lux() - report current lux value
300971672c0SKevin Tsai  * @cm32181:	pointer of struct cm32181.
301971672c0SKevin Tsai  *
302971672c0SKevin Tsai  * Convert sensor raw data to lux.  It depends on integration
303a86ea557SRoberta Dobrescu  * time and calibscale variable.
304971672c0SKevin Tsai  *
305971672c0SKevin Tsai  * Return: Positive value is lux, otherwise is error code.
306971672c0SKevin Tsai  */
307971672c0SKevin Tsai static int cm32181_get_lux(struct cm32181_chip *cm32181)
308971672c0SKevin Tsai {
309971672c0SKevin Tsai 	struct i2c_client *client = cm32181->client;
310971672c0SKevin Tsai 	int ret;
311971672c0SKevin Tsai 	int als_it;
312f50f9831SHans de Goede 	u64 lux;
313971672c0SKevin Tsai 
314971672c0SKevin Tsai 	ret = cm32181_read_als_it(cm32181, &als_it);
315971672c0SKevin Tsai 	if (ret < 0)
316971672c0SKevin Tsai 		return -EINVAL;
317971672c0SKevin Tsai 
31863b1be78SHans de Goede 	lux = cm32181->lux_per_bit;
31963b1be78SHans de Goede 	lux *= cm32181->lux_per_bit_base_it;
320f50f9831SHans de Goede 	lux = div_u64(lux, als_it);
321971672c0SKevin Tsai 
322971672c0SKevin Tsai 	ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS);
323971672c0SKevin Tsai 	if (ret < 0)
324971672c0SKevin Tsai 		return ret;
325971672c0SKevin Tsai 
326971672c0SKevin Tsai 	lux *= ret;
327971672c0SKevin Tsai 	lux *= cm32181->calibscale;
328f50f9831SHans de Goede 	lux = div_u64(lux, CM32181_CALIBSCALE_RESOLUTION);
329f50f9831SHans de Goede 	lux = div_u64(lux, CM32181_LUX_PER_BIT_RESOLUTION);
330971672c0SKevin Tsai 
331971672c0SKevin Tsai 	if (lux > 0xFFFF)
332971672c0SKevin Tsai 		lux = 0xFFFF;
333971672c0SKevin Tsai 
334971672c0SKevin Tsai 	return lux;
335971672c0SKevin Tsai }
336971672c0SKevin Tsai 
337971672c0SKevin Tsai static int cm32181_read_raw(struct iio_dev *indio_dev,
338971672c0SKevin Tsai 			    struct iio_chan_spec const *chan,
339971672c0SKevin Tsai 			    int *val, int *val2, long mask)
340971672c0SKevin Tsai {
341971672c0SKevin Tsai 	struct cm32181_chip *cm32181 = iio_priv(indio_dev);
342971672c0SKevin Tsai 	int ret;
343971672c0SKevin Tsai 
344971672c0SKevin Tsai 	switch (mask) {
345971672c0SKevin Tsai 	case IIO_CHAN_INFO_PROCESSED:
346971672c0SKevin Tsai 		ret = cm32181_get_lux(cm32181);
347971672c0SKevin Tsai 		if (ret < 0)
348971672c0SKevin Tsai 			return ret;
349971672c0SKevin Tsai 		*val = ret;
350971672c0SKevin Tsai 		return IIO_VAL_INT;
351971672c0SKevin Tsai 	case IIO_CHAN_INFO_CALIBSCALE:
352971672c0SKevin Tsai 		*val = cm32181->calibscale;
353971672c0SKevin Tsai 		return IIO_VAL_INT;
354971672c0SKevin Tsai 	case IIO_CHAN_INFO_INT_TIME:
35541c897f8SBeomho Seo 		*val = 0;
3561463a166SBeomho Seo 		ret = cm32181_read_als_it(cm32181, val2);
357971672c0SKevin Tsai 		return ret;
358971672c0SKevin Tsai 	}
359971672c0SKevin Tsai 
360971672c0SKevin Tsai 	return -EINVAL;
361971672c0SKevin Tsai }
362971672c0SKevin Tsai 
363971672c0SKevin Tsai static int cm32181_write_raw(struct iio_dev *indio_dev,
364971672c0SKevin Tsai 			     struct iio_chan_spec const *chan,
365971672c0SKevin Tsai 			     int val, int val2, long mask)
366971672c0SKevin Tsai {
367971672c0SKevin Tsai 	struct cm32181_chip *cm32181 = iio_priv(indio_dev);
368971672c0SKevin Tsai 	int ret;
369971672c0SKevin Tsai 
370971672c0SKevin Tsai 	switch (mask) {
371971672c0SKevin Tsai 	case IIO_CHAN_INFO_CALIBSCALE:
372971672c0SKevin Tsai 		cm32181->calibscale = val;
373971672c0SKevin Tsai 		return val;
374971672c0SKevin Tsai 	case IIO_CHAN_INFO_INT_TIME:
3751463a166SBeomho Seo 		ret = cm32181_write_als_it(cm32181, val2);
376971672c0SKevin Tsai 		return ret;
377971672c0SKevin Tsai 	}
378971672c0SKevin Tsai 
379971672c0SKevin Tsai 	return -EINVAL;
380971672c0SKevin Tsai }
381971672c0SKevin Tsai 
382971672c0SKevin Tsai /**
383971672c0SKevin Tsai  * cm32181_get_it_available() - Get available ALS IT value
384971672c0SKevin Tsai  * @dev:	pointer of struct device.
385971672c0SKevin Tsai  * @attr:	pointer of struct device_attribute.
386971672c0SKevin Tsai  * @buf:	pointer of return string buffer.
387971672c0SKevin Tsai  *
388971672c0SKevin Tsai  * Display the available integration time values by millisecond.
389971672c0SKevin Tsai  *
390971672c0SKevin Tsai  * Return: string length.
391971672c0SKevin Tsai  */
392971672c0SKevin Tsai static ssize_t cm32181_get_it_available(struct device *dev,
393971672c0SKevin Tsai 			struct device_attribute *attr, char *buf)
394971672c0SKevin Tsai {
39502cdab2aSHans de Goede 	struct cm32181_chip *cm32181 = iio_priv(dev_to_iio_dev(dev));
396971672c0SKevin Tsai 	int i, n, len;
397971672c0SKevin Tsai 
39802cdab2aSHans de Goede 	n = cm32181->num_als_it;
399971672c0SKevin Tsai 	for (i = 0, len = 0; i < n; i++)
40002cdab2aSHans de Goede 		len += sprintf(buf + len, "0.%06u ", cm32181->als_it_values[i]);
401971672c0SKevin Tsai 	return len + sprintf(buf + len, "\n");
402971672c0SKevin Tsai }
403971672c0SKevin Tsai 
404971672c0SKevin Tsai static const struct iio_chan_spec cm32181_channels[] = {
405971672c0SKevin Tsai 	{
406971672c0SKevin Tsai 		.type = IIO_LIGHT,
407971672c0SKevin Tsai 		.info_mask_separate =
408971672c0SKevin Tsai 			BIT(IIO_CHAN_INFO_PROCESSED) |
409971672c0SKevin Tsai 			BIT(IIO_CHAN_INFO_CALIBSCALE) |
410971672c0SKevin Tsai 			BIT(IIO_CHAN_INFO_INT_TIME),
411971672c0SKevin Tsai 	}
412971672c0SKevin Tsai };
413971672c0SKevin Tsai 
414971672c0SKevin Tsai static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
415971672c0SKevin Tsai 			S_IRUGO, cm32181_get_it_available, NULL, 0);
416971672c0SKevin Tsai 
417971672c0SKevin Tsai static struct attribute *cm32181_attributes[] = {
418971672c0SKevin Tsai 	&iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
419971672c0SKevin Tsai 	NULL,
420971672c0SKevin Tsai };
421971672c0SKevin Tsai 
422971672c0SKevin Tsai static const struct attribute_group cm32181_attribute_group = {
423971672c0SKevin Tsai 	.attrs = cm32181_attributes
424971672c0SKevin Tsai };
425971672c0SKevin Tsai 
426971672c0SKevin Tsai static const struct iio_info cm32181_info = {
427971672c0SKevin Tsai 	.read_raw		= &cm32181_read_raw,
428971672c0SKevin Tsai 	.write_raw		= &cm32181_write_raw,
429971672c0SKevin Tsai 	.attrs			= &cm32181_attribute_group,
430971672c0SKevin Tsai };
431971672c0SKevin Tsai 
43206770454SHans de Goede static int cm32181_probe(struct i2c_client *client)
433971672c0SKevin Tsai {
434b885d0faSHans de Goede 	struct device *dev = &client->dev;
435971672c0SKevin Tsai 	struct cm32181_chip *cm32181;
436971672c0SKevin Tsai 	struct iio_dev *indio_dev;
437971672c0SKevin Tsai 	int ret;
438971672c0SKevin Tsai 
439b885d0faSHans de Goede 	indio_dev = devm_iio_device_alloc(dev, sizeof(*cm32181));
440b885d0faSHans de Goede 	if (!indio_dev)
441971672c0SKevin Tsai 		return -ENOMEM;
442971672c0SKevin Tsai 
443c1e62062SHans de Goede 	/*
444c1e62062SHans de Goede 	 * Some ACPI systems list 2 I2C resources for the CM3218 sensor, the
445c1e62062SHans de Goede 	 * SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address.
446c1e62062SHans de Goede 	 * Detect this and take the following step to deal with it:
447c1e62062SHans de Goede 	 * 1. When a SMBus Alert capable sensor has an Alert asserted, it will
448c1e62062SHans de Goede 	 *    not respond on its actual I2C address. Read a byte from the ARA
449c1e62062SHans de Goede 	 *    to clear any pending Alerts.
450c1e62062SHans de Goede 	 * 2. Create a "dummy" client for the actual I2C address and
451c1e62062SHans de Goede 	 *    use that client to communicate with the sensor.
452c1e62062SHans de Goede 	 */
453c1e62062SHans de Goede 	if (ACPI_HANDLE(dev) && client->addr == SMBUS_ALERT_RESPONSE_ADDRESS) {
454c1e62062SHans de Goede 		struct i2c_board_info board_info = { .type = "dummy" };
455c1e62062SHans de Goede 
456c1e62062SHans de Goede 		i2c_smbus_read_byte(client);
457c1e62062SHans de Goede 
458c1e62062SHans de Goede 		client = i2c_acpi_new_device(dev, 1, &board_info);
459c1e62062SHans de Goede 		if (IS_ERR(client))
460c1e62062SHans de Goede 			return PTR_ERR(client);
461c1e62062SHans de Goede 	}
462c1e62062SHans de Goede 
463*68c1b3ddSKai-Heng Feng 	i2c_set_clientdata(client, indio_dev);
464*68c1b3ddSKai-Heng Feng 
465971672c0SKevin Tsai 	cm32181 = iio_priv(indio_dev);
466971672c0SKevin Tsai 	cm32181->client = client;
467d34ca613SHans de Goede 	cm32181->dev = dev;
468971672c0SKevin Tsai 
469971672c0SKevin Tsai 	mutex_init(&cm32181->lock);
470971672c0SKevin Tsai 	indio_dev->channels = cm32181_channels;
471971672c0SKevin Tsai 	indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
472971672c0SKevin Tsai 	indio_dev->info = &cm32181_info;
473b885d0faSHans de Goede 	indio_dev->name = dev_name(dev);
474971672c0SKevin Tsai 	indio_dev->modes = INDIO_DIRECT_MODE;
475971672c0SKevin Tsai 
476971672c0SKevin Tsai 	ret = cm32181_reg_init(cm32181);
477971672c0SKevin Tsai 	if (ret) {
478b885d0faSHans de Goede 		dev_err(dev, "%s: register init failed\n", __func__);
479971672c0SKevin Tsai 		return ret;
480971672c0SKevin Tsai 	}
481971672c0SKevin Tsai 
482b885d0faSHans de Goede 	ret = devm_iio_device_register(dev, indio_dev);
483971672c0SKevin Tsai 	if (ret) {
484b885d0faSHans de Goede 		dev_err(dev, "%s: regist device failed\n", __func__);
485971672c0SKevin Tsai 		return ret;
486971672c0SKevin Tsai 	}
487971672c0SKevin Tsai 
488971672c0SKevin Tsai 	return 0;
489971672c0SKevin Tsai }
490971672c0SKevin Tsai 
491*68c1b3ddSKai-Heng Feng static int cm32181_suspend(struct device *dev)
492*68c1b3ddSKai-Heng Feng {
493*68c1b3ddSKai-Heng Feng 	struct i2c_client *client = to_i2c_client(dev);
494*68c1b3ddSKai-Heng Feng 
495*68c1b3ddSKai-Heng Feng 	return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
496*68c1b3ddSKai-Heng Feng 					 CM32181_CMD_ALS_DISABLE);
497*68c1b3ddSKai-Heng Feng }
498*68c1b3ddSKai-Heng Feng 
499*68c1b3ddSKai-Heng Feng static int cm32181_resume(struct device *dev)
500*68c1b3ddSKai-Heng Feng {
501*68c1b3ddSKai-Heng Feng 	struct i2c_client *client = to_i2c_client(dev);
502*68c1b3ddSKai-Heng Feng 	struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev));
503*68c1b3ddSKai-Heng Feng 
504*68c1b3ddSKai-Heng Feng 	return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
505*68c1b3ddSKai-Heng Feng 					 cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
506*68c1b3ddSKai-Heng Feng }
507*68c1b3ddSKai-Heng Feng 
508*68c1b3ddSKai-Heng Feng DEFINE_SIMPLE_DEV_PM_OPS(cm32181_pm_ops, cm32181_suspend, cm32181_resume);
509*68c1b3ddSKai-Heng Feng 
510971672c0SKevin Tsai static const struct of_device_id cm32181_of_match[] = {
51102cdab2aSHans de Goede 	{ .compatible = "capella,cm3218" },
512971672c0SKevin Tsai 	{ .compatible = "capella,cm32181" },
513971672c0SKevin Tsai 	{ }
514971672c0SKevin Tsai };
515119c4fceSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, cm32181_of_match);
516971672c0SKevin Tsai 
51744b9409cSHans de Goede #ifdef CONFIG_ACPI
51844b9409cSHans de Goede static const struct acpi_device_id cm32181_acpi_match[] = {
51944b9409cSHans de Goede 	{ "CPLM3218", 0 },
52044b9409cSHans de Goede 	{ }
52144b9409cSHans de Goede };
52244b9409cSHans de Goede MODULE_DEVICE_TABLE(acpi, cm32181_acpi_match);
52344b9409cSHans de Goede #endif
52444b9409cSHans de Goede 
525971672c0SKevin Tsai static struct i2c_driver cm32181_driver = {
526971672c0SKevin Tsai 	.driver = {
527971672c0SKevin Tsai 		.name	= "cm32181",
52844b9409cSHans de Goede 		.acpi_match_table = ACPI_PTR(cm32181_acpi_match),
5299065b780SJonathan Cameron 		.of_match_table = cm32181_of_match,
530*68c1b3ddSKai-Heng Feng 		.pm = pm_sleep_ptr(&cm32181_pm_ops),
531971672c0SKevin Tsai 	},
53206770454SHans de Goede 	.probe_new	= cm32181_probe,
533971672c0SKevin Tsai };
534971672c0SKevin Tsai 
535971672c0SKevin Tsai module_i2c_driver(cm32181_driver);
536971672c0SKevin Tsai 
537971672c0SKevin Tsai MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
538971672c0SKevin Tsai MODULE_DESCRIPTION("CM32181 ambient light sensor driver");
539971672c0SKevin Tsai MODULE_LICENSE("GPL");
540