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 */
cm32181_acpi_get_cpm(struct device * dev,char * obj_name,u64 * values,int count)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
cm32181_acpi_parse_cpm_tables(struct cm32181_chip * cm32181)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
cm32181_acpi_parse_cpm_tables(struct cm32181_chip * cm32181)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 */
cm32181_reg_init(struct cm32181_chip * cm32181)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 */
cm32181_read_als_it(struct cm32181_chip * cm32181,int * val2)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 */
cm32181_write_als_it(struct cm32181_chip * cm32181,int val)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 */
cm32181_get_lux(struct cm32181_chip * cm32181)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
cm32181_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)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
cm32181_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)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 */
cm32181_get_it_available(struct device * dev,struct device_attribute * attr,char * buf)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
cm32181_unregister_dummy_client(void * data)432099cc90aSKai-Heng Feng static void cm32181_unregister_dummy_client(void *data)
433099cc90aSKai-Heng Feng {
434099cc90aSKai-Heng Feng struct i2c_client *client = data;
435099cc90aSKai-Heng Feng
436099cc90aSKai-Heng Feng /* Unregister the dummy client */
437099cc90aSKai-Heng Feng i2c_unregister_device(client);
438099cc90aSKai-Heng Feng }
439099cc90aSKai-Heng Feng
cm32181_probe(struct i2c_client * client)44006770454SHans de Goede static int cm32181_probe(struct i2c_client *client)
441971672c0SKevin Tsai {
442b885d0faSHans de Goede struct device *dev = &client->dev;
443971672c0SKevin Tsai struct cm32181_chip *cm32181;
444971672c0SKevin Tsai struct iio_dev *indio_dev;
445971672c0SKevin Tsai int ret;
446971672c0SKevin Tsai
447b885d0faSHans de Goede indio_dev = devm_iio_device_alloc(dev, sizeof(*cm32181));
448b885d0faSHans de Goede if (!indio_dev)
449971672c0SKevin Tsai return -ENOMEM;
450971672c0SKevin Tsai
451ee3c5b64SKai-Heng Feng i2c_set_clientdata(client, indio_dev);
452ee3c5b64SKai-Heng Feng
453c1e62062SHans de Goede /*
454c1e62062SHans de Goede * Some ACPI systems list 2 I2C resources for the CM3218 sensor, the
455c1e62062SHans de Goede * SMBus Alert Response Address (ARA, 0x0c) and the actual I2C address.
456c1e62062SHans de Goede * Detect this and take the following step to deal with it:
457c1e62062SHans de Goede * 1. When a SMBus Alert capable sensor has an Alert asserted, it will
458c1e62062SHans de Goede * not respond on its actual I2C address. Read a byte from the ARA
459c1e62062SHans de Goede * to clear any pending Alerts.
460c1e62062SHans de Goede * 2. Create a "dummy" client for the actual I2C address and
461c1e62062SHans de Goede * use that client to communicate with the sensor.
462c1e62062SHans de Goede */
463c1e62062SHans de Goede if (ACPI_HANDLE(dev) && client->addr == SMBUS_ALERT_RESPONSE_ADDRESS) {
464c1e62062SHans de Goede struct i2c_board_info board_info = { .type = "dummy" };
465c1e62062SHans de Goede
466c1e62062SHans de Goede i2c_smbus_read_byte(client);
467c1e62062SHans de Goede
468c1e62062SHans de Goede client = i2c_acpi_new_device(dev, 1, &board_info);
469c1e62062SHans de Goede if (IS_ERR(client))
470c1e62062SHans de Goede return PTR_ERR(client);
471099cc90aSKai-Heng Feng
472099cc90aSKai-Heng Feng ret = devm_add_action_or_reset(dev, cm32181_unregister_dummy_client, client);
473099cc90aSKai-Heng Feng if (ret)
474099cc90aSKai-Heng Feng return ret;
475c1e62062SHans de Goede }
476c1e62062SHans de Goede
477971672c0SKevin Tsai cm32181 = iio_priv(indio_dev);
478971672c0SKevin Tsai cm32181->client = client;
479d34ca613SHans de Goede cm32181->dev = dev;
480971672c0SKevin Tsai
481971672c0SKevin Tsai mutex_init(&cm32181->lock);
482971672c0SKevin Tsai indio_dev->channels = cm32181_channels;
483971672c0SKevin Tsai indio_dev->num_channels = ARRAY_SIZE(cm32181_channels);
484971672c0SKevin Tsai indio_dev->info = &cm32181_info;
485b885d0faSHans de Goede indio_dev->name = dev_name(dev);
486971672c0SKevin Tsai indio_dev->modes = INDIO_DIRECT_MODE;
487971672c0SKevin Tsai
488971672c0SKevin Tsai ret = cm32181_reg_init(cm32181);
489971672c0SKevin Tsai if (ret) {
490b885d0faSHans de Goede dev_err(dev, "%s: register init failed\n", __func__);
491971672c0SKevin Tsai return ret;
492971672c0SKevin Tsai }
493971672c0SKevin Tsai
494b885d0faSHans de Goede ret = devm_iio_device_register(dev, indio_dev);
495971672c0SKevin Tsai if (ret) {
496b885d0faSHans de Goede dev_err(dev, "%s: regist device failed\n", __func__);
497971672c0SKevin Tsai return ret;
498971672c0SKevin Tsai }
499971672c0SKevin Tsai
500971672c0SKevin Tsai return 0;
501971672c0SKevin Tsai }
502971672c0SKevin Tsai
cm32181_suspend(struct device * dev)50368c1b3ddSKai-Heng Feng static int cm32181_suspend(struct device *dev)
50468c1b3ddSKai-Heng Feng {
505ee3c5b64SKai-Heng Feng struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev));
506ee3c5b64SKai-Heng Feng struct i2c_client *client = cm32181->client;
50768c1b3ddSKai-Heng Feng
50868c1b3ddSKai-Heng Feng return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
50968c1b3ddSKai-Heng Feng CM32181_CMD_ALS_DISABLE);
51068c1b3ddSKai-Heng Feng }
51168c1b3ddSKai-Heng Feng
cm32181_resume(struct device * dev)51268c1b3ddSKai-Heng Feng static int cm32181_resume(struct device *dev)
51368c1b3ddSKai-Heng Feng {
51468c1b3ddSKai-Heng Feng struct cm32181_chip *cm32181 = iio_priv(dev_get_drvdata(dev));
515ee3c5b64SKai-Heng Feng struct i2c_client *client = cm32181->client;
51668c1b3ddSKai-Heng Feng
51768c1b3ddSKai-Heng Feng return i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD,
51868c1b3ddSKai-Heng Feng cm32181->conf_regs[CM32181_REG_ADDR_CMD]);
51968c1b3ddSKai-Heng Feng }
52068c1b3ddSKai-Heng Feng
5210096fc87Ssunliming static DEFINE_SIMPLE_DEV_PM_OPS(cm32181_pm_ops, cm32181_suspend, cm32181_resume);
52268c1b3ddSKai-Heng Feng
523971672c0SKevin Tsai static const struct of_device_id cm32181_of_match[] = {
52402cdab2aSHans de Goede { .compatible = "capella,cm3218" },
525971672c0SKevin Tsai { .compatible = "capella,cm32181" },
526971672c0SKevin Tsai { }
527971672c0SKevin Tsai };
528119c4fceSJavier Martinez Canillas MODULE_DEVICE_TABLE(of, cm32181_of_match);
529971672c0SKevin Tsai
53044b9409cSHans de Goede #ifdef CONFIG_ACPI
53144b9409cSHans de Goede static const struct acpi_device_id cm32181_acpi_match[] = {
53244b9409cSHans de Goede { "CPLM3218", 0 },
53344b9409cSHans de Goede { }
53444b9409cSHans de Goede };
53544b9409cSHans de Goede MODULE_DEVICE_TABLE(acpi, cm32181_acpi_match);
53644b9409cSHans de Goede #endif
53744b9409cSHans de Goede
538971672c0SKevin Tsai static struct i2c_driver cm32181_driver = {
539971672c0SKevin Tsai .driver = {
540971672c0SKevin Tsai .name = "cm32181",
54144b9409cSHans de Goede .acpi_match_table = ACPI_PTR(cm32181_acpi_match),
5429065b780SJonathan Cameron .of_match_table = cm32181_of_match,
54368c1b3ddSKai-Heng Feng .pm = pm_sleep_ptr(&cm32181_pm_ops),
544971672c0SKevin Tsai },
545*7cf15f42SUwe Kleine-König .probe = cm32181_probe,
546971672c0SKevin Tsai };
547971672c0SKevin Tsai
548971672c0SKevin Tsai module_i2c_driver(cm32181_driver);
549971672c0SKevin Tsai
550971672c0SKevin Tsai MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
551971672c0SKevin Tsai MODULE_DESCRIPTION("CM32181 ambient light sensor driver");
552971672c0SKevin Tsai MODULE_LICENSE("GPL");
553