xref: /openbmc/linux/drivers/iio/light/stk3310.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
136edc939SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b9d453a5SGwendal Grignou /*
3be9e6229STiberiu Breana  * Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor
4be9e6229STiberiu Breana  *
5be9e6229STiberiu Breana  * Copyright (c) 2015, Intel Corporation.
6be9e6229STiberiu Breana  *
7be9e6229STiberiu Breana  * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48.
8be9e6229STiberiu Breana  */
9be9e6229STiberiu Breana 
10be9e6229STiberiu Breana #include <linux/acpi.h>
11be9e6229STiberiu Breana #include <linux/i2c.h>
123dd477acSTiberiu Breana #include <linux/interrupt.h>
13be9e6229STiberiu Breana #include <linux/kernel.h>
14be9e6229STiberiu Breana #include <linux/module.h>
15be9e6229STiberiu Breana #include <linux/regmap.h>
163dd477acSTiberiu Breana #include <linux/iio/events.h>
17be9e6229STiberiu Breana #include <linux/iio/iio.h>
18be9e6229STiberiu Breana #include <linux/iio/sysfs.h>
19be9e6229STiberiu Breana 
20be9e6229STiberiu Breana #define STK3310_REG_STATE			0x00
21be9e6229STiberiu Breana #define STK3310_REG_PSCTRL			0x01
22be9e6229STiberiu Breana #define STK3310_REG_ALSCTRL			0x02
233dd477acSTiberiu Breana #define STK3310_REG_INT				0x04
243dd477acSTiberiu Breana #define STK3310_REG_THDH_PS			0x06
253dd477acSTiberiu Breana #define STK3310_REG_THDL_PS			0x08
263dd477acSTiberiu Breana #define STK3310_REG_FLAG			0x10
27be9e6229STiberiu Breana #define STK3310_REG_PS_DATA_MSB			0x11
28be9e6229STiberiu Breana #define STK3310_REG_PS_DATA_LSB			0x12
29be9e6229STiberiu Breana #define STK3310_REG_ALS_DATA_MSB		0x13
30be9e6229STiberiu Breana #define STK3310_REG_ALS_DATA_LSB		0x14
31be9e6229STiberiu Breana #define STK3310_REG_ID				0x3E
32be9e6229STiberiu Breana #define STK3310_MAX_REG				0x80
33be9e6229STiberiu Breana 
34952c3aa3SHartmut Knaack #define STK3310_STATE_EN_PS			BIT(0)
35952c3aa3SHartmut Knaack #define STK3310_STATE_EN_ALS			BIT(1)
36be9e6229STiberiu Breana #define STK3310_STATE_STANDBY			0x00
37be9e6229STiberiu Breana 
38be9e6229STiberiu Breana #define STK3310_CHIP_ID_VAL			0x13
39be9e6229STiberiu Breana #define STK3311_CHIP_ID_VAL			0x1D
405ef8f84aSIcenowy Zheng #define STK3311X_CHIP_ID_VAL			0x12
41677f1681SMartijn Braam #define STK3335_CHIP_ID_VAL			0x51
423dd477acSTiberiu Breana #define STK3310_PSINT_EN			0x01
43be9e6229STiberiu Breana #define STK3310_PS_MAX_VAL			0xFFFF
44be9e6229STiberiu Breana 
45be9e6229STiberiu Breana #define STK3310_DRIVER_NAME			"stk3310"
46be9e6229STiberiu Breana #define STK3310_REGMAP_NAME			"stk3310_regmap"
473dd477acSTiberiu Breana #define STK3310_EVENT				"stk3310_event"
48be9e6229STiberiu Breana 
49be9e6229STiberiu Breana #define STK3310_SCALE_AVAILABLE			"6.4 1.6 0.4 0.1"
50be9e6229STiberiu Breana 
51be9e6229STiberiu Breana #define STK3310_IT_AVAILABLE \
52be9e6229STiberiu Breana 	"0.000185 0.000370 0.000741 0.001480 0.002960 0.005920 0.011840 " \
53be9e6229STiberiu Breana 	"0.023680 0.047360 0.094720 0.189440 0.378880 0.757760 1.515520 " \
54be9e6229STiberiu Breana 	"3.031040 6.062080"
55be9e6229STiberiu Breana 
56be9e6229STiberiu Breana #define STK3310_REGFIELD(name)						    \
57be9e6229STiberiu Breana 	do {								    \
58be9e6229STiberiu Breana 		data->reg_##name =					    \
59be9e6229STiberiu Breana 			devm_regmap_field_alloc(&client->dev, regmap,	    \
60be9e6229STiberiu Breana 				stk3310_reg_field_##name);		    \
61be9e6229STiberiu Breana 		if (IS_ERR(data->reg_##name)) {				    \
62be9e6229STiberiu Breana 			dev_err(&client->dev, "reg field alloc failed.\n"); \
63be9e6229STiberiu Breana 			return PTR_ERR(data->reg_##name);		    \
64be9e6229STiberiu Breana 		}							    \
65be9e6229STiberiu Breana 	} while (0)
66be9e6229STiberiu Breana 
67be9e6229STiberiu Breana static const struct reg_field stk3310_reg_field_state =
68be9e6229STiberiu Breana 				REG_FIELD(STK3310_REG_STATE, 0, 2);
69be9e6229STiberiu Breana static const struct reg_field stk3310_reg_field_als_gain =
70be9e6229STiberiu Breana 				REG_FIELD(STK3310_REG_ALSCTRL, 4, 5);
71be9e6229STiberiu Breana static const struct reg_field stk3310_reg_field_ps_gain =
72be9e6229STiberiu Breana 				REG_FIELD(STK3310_REG_PSCTRL, 4, 5);
73be9e6229STiberiu Breana static const struct reg_field stk3310_reg_field_als_it =
74be9e6229STiberiu Breana 				REG_FIELD(STK3310_REG_ALSCTRL, 0, 3);
75be9e6229STiberiu Breana static const struct reg_field stk3310_reg_field_ps_it =
76be9e6229STiberiu Breana 				REG_FIELD(STK3310_REG_PSCTRL, 0, 3);
773dd477acSTiberiu Breana static const struct reg_field stk3310_reg_field_int_ps =
783dd477acSTiberiu Breana 				REG_FIELD(STK3310_REG_INT, 0, 2);
793dd477acSTiberiu Breana static const struct reg_field stk3310_reg_field_flag_psint =
803dd477acSTiberiu Breana 				REG_FIELD(STK3310_REG_FLAG, 4, 4);
813dd477acSTiberiu Breana static const struct reg_field stk3310_reg_field_flag_nf =
823dd477acSTiberiu Breana 				REG_FIELD(STK3310_REG_FLAG, 0, 0);
830f16fc8bSTiberiu Breana 
840f16fc8bSTiberiu Breana /* Estimate maximum proximity values with regard to measurement scale. */
85be9e6229STiberiu Breana static const int stk3310_ps_max[4] = {
860f16fc8bSTiberiu Breana 	STK3310_PS_MAX_VAL / 640,
870f16fc8bSTiberiu Breana 	STK3310_PS_MAX_VAL / 160,
880f16fc8bSTiberiu Breana 	STK3310_PS_MAX_VAL /  40,
890f16fc8bSTiberiu Breana 	STK3310_PS_MAX_VAL /  10
90be9e6229STiberiu Breana };
91be9e6229STiberiu Breana 
92be9e6229STiberiu Breana static const int stk3310_scale_table[][2] = {
93be9e6229STiberiu Breana 	{6, 400000}, {1, 600000}, {0, 400000}, {0, 100000}
94be9e6229STiberiu Breana };
95be9e6229STiberiu Breana 
96be9e6229STiberiu Breana /* Integration time in seconds, microseconds */
97be9e6229STiberiu Breana static const int stk3310_it_table[][2] = {
98be9e6229STiberiu Breana 	{0, 185},	{0, 370},	{0, 741},	{0, 1480},
99be9e6229STiberiu Breana 	{0, 2960},	{0, 5920},	{0, 11840},	{0, 23680},
100be9e6229STiberiu Breana 	{0, 47360},	{0, 94720},	{0, 189440},	{0, 378880},
101be9e6229STiberiu Breana 	{0, 757760},	{1, 515520},	{3, 31040},	{6, 62080},
102be9e6229STiberiu Breana };
103be9e6229STiberiu Breana 
104be9e6229STiberiu Breana struct stk3310_data {
105be9e6229STiberiu Breana 	struct i2c_client *client;
106be9e6229STiberiu Breana 	struct mutex lock;
107be9e6229STiberiu Breana 	bool als_enabled;
108be9e6229STiberiu Breana 	bool ps_enabled;
109d6ecb015SArnaud Ferraris 	uint32_t ps_near_level;
1103dd477acSTiberiu Breana 	u64 timestamp;
111be9e6229STiberiu Breana 	struct regmap *regmap;
112be9e6229STiberiu Breana 	struct regmap_field *reg_state;
113be9e6229STiberiu Breana 	struct regmap_field *reg_als_gain;
114be9e6229STiberiu Breana 	struct regmap_field *reg_ps_gain;
115be9e6229STiberiu Breana 	struct regmap_field *reg_als_it;
116be9e6229STiberiu Breana 	struct regmap_field *reg_ps_it;
1173dd477acSTiberiu Breana 	struct regmap_field *reg_int_ps;
1183dd477acSTiberiu Breana 	struct regmap_field *reg_flag_psint;
1193dd477acSTiberiu Breana 	struct regmap_field *reg_flag_nf;
1203dd477acSTiberiu Breana };
1213dd477acSTiberiu Breana 
1223dd477acSTiberiu Breana static const struct iio_event_spec stk3310_events[] = {
1233dd477acSTiberiu Breana 	/* Proximity event */
1243dd477acSTiberiu Breana 	{
1253dd477acSTiberiu Breana 		.type = IIO_EV_TYPE_THRESH,
1260f16fc8bSTiberiu Breana 		.dir = IIO_EV_DIR_RISING,
1273dd477acSTiberiu Breana 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1283dd477acSTiberiu Breana 				 BIT(IIO_EV_INFO_ENABLE),
1293dd477acSTiberiu Breana 	},
1303dd477acSTiberiu Breana 	/* Out-of-proximity event */
1313dd477acSTiberiu Breana 	{
1323dd477acSTiberiu Breana 		.type = IIO_EV_TYPE_THRESH,
1330f16fc8bSTiberiu Breana 		.dir = IIO_EV_DIR_FALLING,
1343dd477acSTiberiu Breana 		.mask_separate = BIT(IIO_EV_INFO_VALUE) |
1353dd477acSTiberiu Breana 				 BIT(IIO_EV_INFO_ENABLE),
1363dd477acSTiberiu Breana 	},
137be9e6229STiberiu Breana };
138be9e6229STiberiu Breana 
stk3310_read_near_level(struct iio_dev * indio_dev,uintptr_t priv,const struct iio_chan_spec * chan,char * buf)139d6ecb015SArnaud Ferraris static ssize_t stk3310_read_near_level(struct iio_dev *indio_dev,
140d6ecb015SArnaud Ferraris 				       uintptr_t priv,
141d6ecb015SArnaud Ferraris 				       const struct iio_chan_spec *chan,
142d6ecb015SArnaud Ferraris 				       char *buf)
143d6ecb015SArnaud Ferraris {
144d6ecb015SArnaud Ferraris 	struct stk3310_data *data = iio_priv(indio_dev);
145d6ecb015SArnaud Ferraris 
146d6ecb015SArnaud Ferraris 	return sprintf(buf, "%u\n", data->ps_near_level);
147d6ecb015SArnaud Ferraris }
148d6ecb015SArnaud Ferraris 
149d6ecb015SArnaud Ferraris static const struct iio_chan_spec_ext_info stk3310_ext_info[] = {
150d6ecb015SArnaud Ferraris 	{
151d6ecb015SArnaud Ferraris 		.name = "nearlevel",
152d6ecb015SArnaud Ferraris 		.shared = IIO_SEPARATE,
153d6ecb015SArnaud Ferraris 		.read = stk3310_read_near_level,
154d6ecb015SArnaud Ferraris 	},
155d6ecb015SArnaud Ferraris 	{ /* sentinel */ }
156d6ecb015SArnaud Ferraris };
157d6ecb015SArnaud Ferraris 
158be9e6229STiberiu Breana static const struct iio_chan_spec stk3310_channels[] = {
159be9e6229STiberiu Breana 	{
160be9e6229STiberiu Breana 		.type = IIO_LIGHT,
161be9e6229STiberiu Breana 		.info_mask_separate =
162be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_RAW) |
163be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_SCALE) |
164be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_INT_TIME),
165be9e6229STiberiu Breana 	},
166be9e6229STiberiu Breana 	{
167be9e6229STiberiu Breana 		.type = IIO_PROXIMITY,
168be9e6229STiberiu Breana 		.info_mask_separate =
169be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_RAW) |
170be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_SCALE) |
171be9e6229STiberiu Breana 			BIT(IIO_CHAN_INFO_INT_TIME),
1723dd477acSTiberiu Breana 		.event_spec = stk3310_events,
1733dd477acSTiberiu Breana 		.num_event_specs = ARRAY_SIZE(stk3310_events),
174d6ecb015SArnaud Ferraris 		.ext_info = stk3310_ext_info,
175be9e6229STiberiu Breana 	}
176be9e6229STiberiu Breana };
177be9e6229STiberiu Breana 
178be9e6229STiberiu Breana static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE);
179be9e6229STiberiu Breana 
180be9e6229STiberiu Breana static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE);
181be9e6229STiberiu Breana 
182be9e6229STiberiu Breana static IIO_CONST_ATTR(in_illuminance_integration_time_available,
183be9e6229STiberiu Breana 		      STK3310_IT_AVAILABLE);
184be9e6229STiberiu Breana 
185be9e6229STiberiu Breana static IIO_CONST_ATTR(in_proximity_integration_time_available,
186be9e6229STiberiu Breana 		      STK3310_IT_AVAILABLE);
187be9e6229STiberiu Breana 
188be9e6229STiberiu Breana static struct attribute *stk3310_attributes[] = {
189be9e6229STiberiu Breana 	&iio_const_attr_in_illuminance_scale_available.dev_attr.attr,
190be9e6229STiberiu Breana 	&iio_const_attr_in_proximity_scale_available.dev_attr.attr,
191be9e6229STiberiu Breana 	&iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr,
192be9e6229STiberiu Breana 	&iio_const_attr_in_proximity_integration_time_available.dev_attr.attr,
193be9e6229STiberiu Breana 	NULL,
194be9e6229STiberiu Breana };
195be9e6229STiberiu Breana 
196be9e6229STiberiu Breana static const struct attribute_group stk3310_attribute_group = {
197be9e6229STiberiu Breana 	.attrs = stk3310_attributes
198be9e6229STiberiu Breana };
199be9e6229STiberiu Breana 
stk3310_get_index(const int table[][2],int table_size,int val,int val2)200be9e6229STiberiu Breana static int stk3310_get_index(const int table[][2], int table_size,
201be9e6229STiberiu Breana 			     int val, int val2)
202be9e6229STiberiu Breana {
203be9e6229STiberiu Breana 	int i;
204be9e6229STiberiu Breana 
205be9e6229STiberiu Breana 	for (i = 0; i < table_size; i++) {
206be9e6229STiberiu Breana 		if (val == table[i][0] && val2 == table[i][1])
207be9e6229STiberiu Breana 			return i;
208be9e6229STiberiu Breana 	}
209be9e6229STiberiu Breana 
210be9e6229STiberiu Breana 	return -EINVAL;
211be9e6229STiberiu Breana }
212be9e6229STiberiu Breana 
stk3310_read_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int * val,int * val2)2133dd477acSTiberiu Breana static int stk3310_read_event(struct iio_dev *indio_dev,
2143dd477acSTiberiu Breana 			      const struct iio_chan_spec *chan,
2153dd477acSTiberiu Breana 			      enum iio_event_type type,
2163dd477acSTiberiu Breana 			      enum iio_event_direction dir,
2173dd477acSTiberiu Breana 			      enum iio_event_info info,
2183dd477acSTiberiu Breana 			      int *val, int *val2)
2193dd477acSTiberiu Breana {
2203dd477acSTiberiu Breana 	u8 reg;
221423ad0c4SHartmut Knaack 	__be16 buf;
2223dd477acSTiberiu Breana 	int ret;
2233dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
2243dd477acSTiberiu Breana 
2253dd477acSTiberiu Breana 	if (info != IIO_EV_INFO_VALUE)
2263dd477acSTiberiu Breana 		return -EINVAL;
2273dd477acSTiberiu Breana 
2280f16fc8bSTiberiu Breana 	/* Only proximity interrupts are implemented at the moment. */
2293dd477acSTiberiu Breana 	if (dir == IIO_EV_DIR_RISING)
2303dd477acSTiberiu Breana 		reg = STK3310_REG_THDH_PS;
2310f16fc8bSTiberiu Breana 	else if (dir == IIO_EV_DIR_FALLING)
2320f16fc8bSTiberiu Breana 		reg = STK3310_REG_THDL_PS;
2333dd477acSTiberiu Breana 	else
2343dd477acSTiberiu Breana 		return -EINVAL;
2353dd477acSTiberiu Breana 
2363dd477acSTiberiu Breana 	mutex_lock(&data->lock);
2373dd477acSTiberiu Breana 	ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
2383dd477acSTiberiu Breana 	mutex_unlock(&data->lock);
2393dd477acSTiberiu Breana 	if (ret < 0) {
2403dd477acSTiberiu Breana 		dev_err(&data->client->dev, "register read failed\n");
2413dd477acSTiberiu Breana 		return ret;
2423dd477acSTiberiu Breana 	}
243423ad0c4SHartmut Knaack 	*val = be16_to_cpu(buf);
2443dd477acSTiberiu Breana 
2453dd477acSTiberiu Breana 	return IIO_VAL_INT;
2463dd477acSTiberiu Breana }
2473dd477acSTiberiu Breana 
stk3310_write_event(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,enum iio_event_info info,int val,int val2)2483dd477acSTiberiu Breana static int stk3310_write_event(struct iio_dev *indio_dev,
2493dd477acSTiberiu Breana 			       const struct iio_chan_spec *chan,
2503dd477acSTiberiu Breana 			       enum iio_event_type type,
2513dd477acSTiberiu Breana 			       enum iio_event_direction dir,
2523dd477acSTiberiu Breana 			       enum iio_event_info info,
2533dd477acSTiberiu Breana 			       int val, int val2)
2543dd477acSTiberiu Breana {
2553dd477acSTiberiu Breana 	u8 reg;
256423ad0c4SHartmut Knaack 	__be16 buf;
2573dd477acSTiberiu Breana 	int ret;
2583dd477acSTiberiu Breana 	unsigned int index;
2593dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
2603dd477acSTiberiu Breana 	struct i2c_client *client = data->client;
2613dd477acSTiberiu Breana 
2627c7a9eeaSHartmut Knaack 	ret = regmap_field_read(data->reg_ps_gain, &index);
2637c7a9eeaSHartmut Knaack 	if (ret < 0)
2647c7a9eeaSHartmut Knaack 		return ret;
2657c7a9eeaSHartmut Knaack 
2667c7a9eeaSHartmut Knaack 	if (val < 0 || val > stk3310_ps_max[index])
2673dd477acSTiberiu Breana 		return -EINVAL;
2683dd477acSTiberiu Breana 
2693dd477acSTiberiu Breana 	if (dir == IIO_EV_DIR_RISING)
2703dd477acSTiberiu Breana 		reg = STK3310_REG_THDH_PS;
2710f16fc8bSTiberiu Breana 	else if (dir == IIO_EV_DIR_FALLING)
2720f16fc8bSTiberiu Breana 		reg = STK3310_REG_THDL_PS;
2733dd477acSTiberiu Breana 	else
2743dd477acSTiberiu Breana 		return -EINVAL;
2753dd477acSTiberiu Breana 
276423ad0c4SHartmut Knaack 	buf = cpu_to_be16(val);
2773dd477acSTiberiu Breana 	ret = regmap_bulk_write(data->regmap, reg, &buf, 2);
2783dd477acSTiberiu Breana 	if (ret < 0)
2793dd477acSTiberiu Breana 		dev_err(&client->dev, "failed to set PS threshold!\n");
2803dd477acSTiberiu Breana 
2813dd477acSTiberiu Breana 	return ret;
2823dd477acSTiberiu Breana }
2833dd477acSTiberiu Breana 
stk3310_read_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir)2843dd477acSTiberiu Breana static int stk3310_read_event_config(struct iio_dev *indio_dev,
2853dd477acSTiberiu Breana 				     const struct iio_chan_spec *chan,
2863dd477acSTiberiu Breana 				     enum iio_event_type type,
2873dd477acSTiberiu Breana 				     enum iio_event_direction dir)
2883dd477acSTiberiu Breana {
2893dd477acSTiberiu Breana 	unsigned int event_val;
2907c7a9eeaSHartmut Knaack 	int ret;
2913dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
2923dd477acSTiberiu Breana 
2937c7a9eeaSHartmut Knaack 	ret = regmap_field_read(data->reg_int_ps, &event_val);
2947c7a9eeaSHartmut Knaack 	if (ret < 0)
2957c7a9eeaSHartmut Knaack 		return ret;
2963dd477acSTiberiu Breana 
2973dd477acSTiberiu Breana 	return event_val;
2983dd477acSTiberiu Breana }
2993dd477acSTiberiu Breana 
stk3310_write_event_config(struct iio_dev * indio_dev,const struct iio_chan_spec * chan,enum iio_event_type type,enum iio_event_direction dir,int state)3003dd477acSTiberiu Breana static int stk3310_write_event_config(struct iio_dev *indio_dev,
3013dd477acSTiberiu Breana 				      const struct iio_chan_spec *chan,
3023dd477acSTiberiu Breana 				      enum iio_event_type type,
3033dd477acSTiberiu Breana 				      enum iio_event_direction dir,
3043dd477acSTiberiu Breana 				      int state)
3053dd477acSTiberiu Breana {
3063dd477acSTiberiu Breana 	int ret;
3073dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
3083dd477acSTiberiu Breana 	struct i2c_client *client = data->client;
3093dd477acSTiberiu Breana 
3103dd477acSTiberiu Breana 	if (state < 0 || state > 7)
3113dd477acSTiberiu Breana 		return -EINVAL;
3123dd477acSTiberiu Breana 
3133dd477acSTiberiu Breana 	/* Set INT_PS value */
3143dd477acSTiberiu Breana 	mutex_lock(&data->lock);
3153dd477acSTiberiu Breana 	ret = regmap_field_write(data->reg_int_ps, state);
3163dd477acSTiberiu Breana 	if (ret < 0)
3173dd477acSTiberiu Breana 		dev_err(&client->dev, "failed to set interrupt mode\n");
3183dd477acSTiberiu Breana 	mutex_unlock(&data->lock);
3193dd477acSTiberiu Breana 
3203dd477acSTiberiu Breana 	return ret;
3213dd477acSTiberiu Breana }
3223dd477acSTiberiu Breana 
stk3310_read_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int * val,int * val2,long mask)323be9e6229STiberiu Breana static int stk3310_read_raw(struct iio_dev *indio_dev,
324be9e6229STiberiu Breana 			    struct iio_chan_spec const *chan,
325be9e6229STiberiu Breana 			    int *val, int *val2, long mask)
326be9e6229STiberiu Breana {
327be9e6229STiberiu Breana 	u8 reg;
328423ad0c4SHartmut Knaack 	__be16 buf;
329be9e6229STiberiu Breana 	int ret;
330be9e6229STiberiu Breana 	unsigned int index;
331be9e6229STiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
332be9e6229STiberiu Breana 	struct i2c_client *client = data->client;
333be9e6229STiberiu Breana 
3347c7a9eeaSHartmut Knaack 	if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
3357c7a9eeaSHartmut Knaack 		return -EINVAL;
3367c7a9eeaSHartmut Knaack 
337be9e6229STiberiu Breana 	switch (mask) {
338be9e6229STiberiu Breana 	case IIO_CHAN_INFO_RAW:
339be9e6229STiberiu Breana 		if (chan->type == IIO_LIGHT)
340be9e6229STiberiu Breana 			reg = STK3310_REG_ALS_DATA_MSB;
341be9e6229STiberiu Breana 		else
3427c7a9eeaSHartmut Knaack 			reg = STK3310_REG_PS_DATA_MSB;
3437c7a9eeaSHartmut Knaack 
344be9e6229STiberiu Breana 		mutex_lock(&data->lock);
345be9e6229STiberiu Breana 		ret = regmap_bulk_read(data->regmap, reg, &buf, 2);
346be9e6229STiberiu Breana 		if (ret < 0) {
347be9e6229STiberiu Breana 			dev_err(&client->dev, "register read failed\n");
348be9e6229STiberiu Breana 			mutex_unlock(&data->lock);
349be9e6229STiberiu Breana 			return ret;
350be9e6229STiberiu Breana 		}
351423ad0c4SHartmut Knaack 		*val = be16_to_cpu(buf);
352be9e6229STiberiu Breana 		mutex_unlock(&data->lock);
353be9e6229STiberiu Breana 		return IIO_VAL_INT;
354be9e6229STiberiu Breana 	case IIO_CHAN_INFO_INT_TIME:
355be9e6229STiberiu Breana 		if (chan->type == IIO_LIGHT)
3567c7a9eeaSHartmut Knaack 			ret = regmap_field_read(data->reg_als_it, &index);
357be9e6229STiberiu Breana 		else
3587c7a9eeaSHartmut Knaack 			ret = regmap_field_read(data->reg_ps_it, &index);
3597c7a9eeaSHartmut Knaack 		if (ret < 0)
3607c7a9eeaSHartmut Knaack 			return ret;
3617c7a9eeaSHartmut Knaack 
362be9e6229STiberiu Breana 		*val = stk3310_it_table[index][0];
363be9e6229STiberiu Breana 		*val2 = stk3310_it_table[index][1];
364be9e6229STiberiu Breana 		return IIO_VAL_INT_PLUS_MICRO;
365be9e6229STiberiu Breana 	case IIO_CHAN_INFO_SCALE:
366be9e6229STiberiu Breana 		if (chan->type == IIO_LIGHT)
3677c7a9eeaSHartmut Knaack 			ret = regmap_field_read(data->reg_als_gain, &index);
368be9e6229STiberiu Breana 		else
3697c7a9eeaSHartmut Knaack 			ret = regmap_field_read(data->reg_ps_gain, &index);
3707c7a9eeaSHartmut Knaack 		if (ret < 0)
3717c7a9eeaSHartmut Knaack 			return ret;
3727c7a9eeaSHartmut Knaack 
373be9e6229STiberiu Breana 		*val = stk3310_scale_table[index][0];
374be9e6229STiberiu Breana 		*val2 = stk3310_scale_table[index][1];
375be9e6229STiberiu Breana 		return IIO_VAL_INT_PLUS_MICRO;
376be9e6229STiberiu Breana 	}
377be9e6229STiberiu Breana 
378be9e6229STiberiu Breana 	return -EINVAL;
379be9e6229STiberiu Breana }
380be9e6229STiberiu Breana 
stk3310_write_raw(struct iio_dev * indio_dev,struct iio_chan_spec const * chan,int val,int val2,long mask)381be9e6229STiberiu Breana static int stk3310_write_raw(struct iio_dev *indio_dev,
382be9e6229STiberiu Breana 			     struct iio_chan_spec const *chan,
383be9e6229STiberiu Breana 			     int val, int val2, long mask)
384be9e6229STiberiu Breana {
385be9e6229STiberiu Breana 	int ret;
386ed6e75c7SDan Carpenter 	int index;
387be9e6229STiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
388be9e6229STiberiu Breana 
3897c7a9eeaSHartmut Knaack 	if (chan->type != IIO_LIGHT && chan->type != IIO_PROXIMITY)
3907c7a9eeaSHartmut Knaack 		return -EINVAL;
3917c7a9eeaSHartmut Knaack 
392be9e6229STiberiu Breana 	switch (mask) {
393be9e6229STiberiu Breana 	case IIO_CHAN_INFO_INT_TIME:
394be9e6229STiberiu Breana 		index = stk3310_get_index(stk3310_it_table,
395be9e6229STiberiu Breana 					  ARRAY_SIZE(stk3310_it_table),
396be9e6229STiberiu Breana 					  val, val2);
397be9e6229STiberiu Breana 		if (index < 0)
398be9e6229STiberiu Breana 			return -EINVAL;
399be9e6229STiberiu Breana 		mutex_lock(&data->lock);
400be9e6229STiberiu Breana 		if (chan->type == IIO_LIGHT)
401be9e6229STiberiu Breana 			ret = regmap_field_write(data->reg_als_it, index);
402be9e6229STiberiu Breana 		else
403be9e6229STiberiu Breana 			ret = regmap_field_write(data->reg_ps_it, index);
404be9e6229STiberiu Breana 		if (ret < 0)
405be9e6229STiberiu Breana 			dev_err(&data->client->dev,
406be9e6229STiberiu Breana 				"sensor configuration failed\n");
407be9e6229STiberiu Breana 		mutex_unlock(&data->lock);
408be9e6229STiberiu Breana 		return ret;
409be9e6229STiberiu Breana 
410be9e6229STiberiu Breana 	case IIO_CHAN_INFO_SCALE:
411be9e6229STiberiu Breana 		index = stk3310_get_index(stk3310_scale_table,
412be9e6229STiberiu Breana 					  ARRAY_SIZE(stk3310_scale_table),
413be9e6229STiberiu Breana 					  val, val2);
414be9e6229STiberiu Breana 		if (index < 0)
415be9e6229STiberiu Breana 			return -EINVAL;
416be9e6229STiberiu Breana 		mutex_lock(&data->lock);
417be9e6229STiberiu Breana 		if (chan->type == IIO_LIGHT)
418be9e6229STiberiu Breana 			ret = regmap_field_write(data->reg_als_gain, index);
419be9e6229STiberiu Breana 		else
420be9e6229STiberiu Breana 			ret = regmap_field_write(data->reg_ps_gain, index);
421be9e6229STiberiu Breana 		if (ret < 0)
422be9e6229STiberiu Breana 			dev_err(&data->client->dev,
423be9e6229STiberiu Breana 				"sensor configuration failed\n");
424be9e6229STiberiu Breana 		mutex_unlock(&data->lock);
425be9e6229STiberiu Breana 		return ret;
426be9e6229STiberiu Breana 	}
427be9e6229STiberiu Breana 
428be9e6229STiberiu Breana 	return -EINVAL;
429be9e6229STiberiu Breana }
430be9e6229STiberiu Breana 
431be9e6229STiberiu Breana static const struct iio_info stk3310_info = {
432be9e6229STiberiu Breana 	.read_raw		= stk3310_read_raw,
433be9e6229STiberiu Breana 	.write_raw		= stk3310_write_raw,
434be9e6229STiberiu Breana 	.attrs			= &stk3310_attribute_group,
4353dd477acSTiberiu Breana 	.read_event_value	= stk3310_read_event,
4363dd477acSTiberiu Breana 	.write_event_value	= stk3310_write_event,
4373dd477acSTiberiu Breana 	.read_event_config	= stk3310_read_event_config,
4383dd477acSTiberiu Breana 	.write_event_config	= stk3310_write_event_config,
439be9e6229STiberiu Breana };
440be9e6229STiberiu Breana 
stk3310_set_state(struct stk3310_data * data,u8 state)441be9e6229STiberiu Breana static int stk3310_set_state(struct stk3310_data *data, u8 state)
442be9e6229STiberiu Breana {
443be9e6229STiberiu Breana 	int ret;
444be9e6229STiberiu Breana 	struct i2c_client *client = data->client;
445be9e6229STiberiu Breana 
446be9e6229STiberiu Breana 	/* 3-bit state; 0b100 is not supported. */
447be9e6229STiberiu Breana 	if (state > 7 || state == 4)
448be9e6229STiberiu Breana 		return -EINVAL;
449be9e6229STiberiu Breana 
450be9e6229STiberiu Breana 	mutex_lock(&data->lock);
451be9e6229STiberiu Breana 	ret = regmap_field_write(data->reg_state, state);
452be9e6229STiberiu Breana 	if (ret < 0) {
453be9e6229STiberiu Breana 		dev_err(&client->dev, "failed to change sensor state\n");
454be9e6229STiberiu Breana 	} else if (state != STK3310_STATE_STANDBY) {
455be9e6229STiberiu Breana 		/* Don't reset the 'enabled' flags if we're going in standby */
456952c3aa3SHartmut Knaack 		data->ps_enabled  = !!(state & STK3310_STATE_EN_PS);
457952c3aa3SHartmut Knaack 		data->als_enabled = !!(state & STK3310_STATE_EN_ALS);
458be9e6229STiberiu Breana 	}
459be9e6229STiberiu Breana 	mutex_unlock(&data->lock);
460be9e6229STiberiu Breana 
461be9e6229STiberiu Breana 	return ret;
462be9e6229STiberiu Breana }
463be9e6229STiberiu Breana 
stk3310_init(struct iio_dev * indio_dev)464be9e6229STiberiu Breana static int stk3310_init(struct iio_dev *indio_dev)
465be9e6229STiberiu Breana {
466be9e6229STiberiu Breana 	int ret;
467be9e6229STiberiu Breana 	int chipid;
468be9e6229STiberiu Breana 	u8 state;
469be9e6229STiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
470be9e6229STiberiu Breana 	struct i2c_client *client = data->client;
471be9e6229STiberiu Breana 
4727c7a9eeaSHartmut Knaack 	ret = regmap_read(data->regmap, STK3310_REG_ID, &chipid);
4737c7a9eeaSHartmut Knaack 	if (ret < 0)
4747c7a9eeaSHartmut Knaack 		return ret;
4757c7a9eeaSHartmut Knaack 
476be9e6229STiberiu Breana 	if (chipid != STK3310_CHIP_ID_VAL &&
477677f1681SMartijn Braam 	    chipid != STK3311_CHIP_ID_VAL &&
4785ef8f84aSIcenowy Zheng 	    chipid != STK3311X_CHIP_ID_VAL &&
479677f1681SMartijn Braam 	    chipid != STK3335_CHIP_ID_VAL) {
480be9e6229STiberiu Breana 		dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid);
481be9e6229STiberiu Breana 		return -ENODEV;
482be9e6229STiberiu Breana 	}
483be9e6229STiberiu Breana 
484be9e6229STiberiu Breana 	state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS;
485be9e6229STiberiu Breana 	ret = stk3310_set_state(data, state);
4863dd477acSTiberiu Breana 	if (ret < 0) {
487be9e6229STiberiu Breana 		dev_err(&client->dev, "failed to enable sensor");
4883dd477acSTiberiu Breana 		return ret;
4893dd477acSTiberiu Breana 	}
4903dd477acSTiberiu Breana 
4913dd477acSTiberiu Breana 	/* Enable PS interrupts */
4923dd477acSTiberiu Breana 	ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN);
4933dd477acSTiberiu Breana 	if (ret < 0)
4943dd477acSTiberiu Breana 		dev_err(&client->dev, "failed to enable interrupts!\n");
4953dd477acSTiberiu Breana 
4963dd477acSTiberiu Breana 	return ret;
4973dd477acSTiberiu Breana }
4983dd477acSTiberiu Breana 
stk3310_is_volatile_reg(struct device * dev,unsigned int reg)499be9e6229STiberiu Breana static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg)
500be9e6229STiberiu Breana {
501be9e6229STiberiu Breana 	switch (reg) {
502be9e6229STiberiu Breana 	case STK3310_REG_ALS_DATA_MSB:
503be9e6229STiberiu Breana 	case STK3310_REG_ALS_DATA_LSB:
504be9e6229STiberiu Breana 	case STK3310_REG_PS_DATA_LSB:
505be9e6229STiberiu Breana 	case STK3310_REG_PS_DATA_MSB:
5063dd477acSTiberiu Breana 	case STK3310_REG_FLAG:
507be9e6229STiberiu Breana 		return true;
508be9e6229STiberiu Breana 	default:
509be9e6229STiberiu Breana 		return false;
510be9e6229STiberiu Breana 	}
511be9e6229STiberiu Breana }
512be9e6229STiberiu Breana 
513893acabfSRikard Falkeborn static const struct regmap_config stk3310_regmap_config = {
514be9e6229STiberiu Breana 	.name = STK3310_REGMAP_NAME,
515be9e6229STiberiu Breana 	.reg_bits = 8,
516be9e6229STiberiu Breana 	.val_bits = 8,
517be9e6229STiberiu Breana 	.max_register = STK3310_MAX_REG,
518be9e6229STiberiu Breana 	.cache_type = REGCACHE_RBTREE,
519be9e6229STiberiu Breana 	.volatile_reg = stk3310_is_volatile_reg,
520be9e6229STiberiu Breana };
521be9e6229STiberiu Breana 
stk3310_regmap_init(struct stk3310_data * data)522be9e6229STiberiu Breana static int stk3310_regmap_init(struct stk3310_data *data)
523be9e6229STiberiu Breana {
524be9e6229STiberiu Breana 	struct regmap *regmap;
525be9e6229STiberiu Breana 	struct i2c_client *client;
526be9e6229STiberiu Breana 
527be9e6229STiberiu Breana 	client = data->client;
528be9e6229STiberiu Breana 	regmap = devm_regmap_init_i2c(client, &stk3310_regmap_config);
529be9e6229STiberiu Breana 	if (IS_ERR(regmap)) {
530be9e6229STiberiu Breana 		dev_err(&client->dev, "regmap initialization failed.\n");
531be9e6229STiberiu Breana 		return PTR_ERR(regmap);
532be9e6229STiberiu Breana 	}
533be9e6229STiberiu Breana 	data->regmap = regmap;
534be9e6229STiberiu Breana 
535be9e6229STiberiu Breana 	STK3310_REGFIELD(state);
536be9e6229STiberiu Breana 	STK3310_REGFIELD(als_gain);
537be9e6229STiberiu Breana 	STK3310_REGFIELD(ps_gain);
538be9e6229STiberiu Breana 	STK3310_REGFIELD(als_it);
539be9e6229STiberiu Breana 	STK3310_REGFIELD(ps_it);
5403dd477acSTiberiu Breana 	STK3310_REGFIELD(int_ps);
5413dd477acSTiberiu Breana 	STK3310_REGFIELD(flag_psint);
5423dd477acSTiberiu Breana 	STK3310_REGFIELD(flag_nf);
543be9e6229STiberiu Breana 
544be9e6229STiberiu Breana 	return 0;
545be9e6229STiberiu Breana }
546be9e6229STiberiu Breana 
stk3310_irq_handler(int irq,void * private)5473dd477acSTiberiu Breana static irqreturn_t stk3310_irq_handler(int irq, void *private)
5483dd477acSTiberiu Breana {
5493dd477acSTiberiu Breana 	struct iio_dev *indio_dev = private;
5503dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
5513dd477acSTiberiu Breana 
552bc2b7dabSGregor Boirie 	data->timestamp = iio_get_time_ns(indio_dev);
5533dd477acSTiberiu Breana 
5543dd477acSTiberiu Breana 	return IRQ_WAKE_THREAD;
5553dd477acSTiberiu Breana }
5563dd477acSTiberiu Breana 
stk3310_irq_event_handler(int irq,void * private)5573dd477acSTiberiu Breana static irqreturn_t stk3310_irq_event_handler(int irq, void *private)
5583dd477acSTiberiu Breana {
5593dd477acSTiberiu Breana 	int ret;
5603dd477acSTiberiu Breana 	unsigned int dir;
5613dd477acSTiberiu Breana 	u64 event;
5623dd477acSTiberiu Breana 
5633dd477acSTiberiu Breana 	struct iio_dev *indio_dev = private;
5643dd477acSTiberiu Breana 	struct stk3310_data *data = iio_priv(indio_dev);
5653dd477acSTiberiu Breana 
5663dd477acSTiberiu Breana 	/* Read FLAG_NF to figure out what threshold has been met. */
5673dd477acSTiberiu Breana 	mutex_lock(&data->lock);
5683dd477acSTiberiu Breana 	ret = regmap_field_read(data->reg_flag_nf, &dir);
5693dd477acSTiberiu Breana 	if (ret < 0) {
5708e1eeca5SLars-Peter Clausen 		dev_err(&data->client->dev, "register read failed: %d\n", ret);
5718e1eeca5SLars-Peter Clausen 		goto out;
5723dd477acSTiberiu Breana 	}
5733dd477acSTiberiu Breana 	event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1,
5743dd477acSTiberiu Breana 				     IIO_EV_TYPE_THRESH,
5750f16fc8bSTiberiu Breana 				     (dir ? IIO_EV_DIR_FALLING :
5760f16fc8bSTiberiu Breana 					    IIO_EV_DIR_RISING));
5773dd477acSTiberiu Breana 	iio_push_event(indio_dev, event, data->timestamp);
5783dd477acSTiberiu Breana 
5793dd477acSTiberiu Breana 	/* Reset the interrupt flag */
5803dd477acSTiberiu Breana 	ret = regmap_field_write(data->reg_flag_psint, 0);
5813dd477acSTiberiu Breana 	if (ret < 0)
5823dd477acSTiberiu Breana 		dev_err(&data->client->dev, "failed to reset interrupts\n");
5838e1eeca5SLars-Peter Clausen out:
5843dd477acSTiberiu Breana 	mutex_unlock(&data->lock);
5853dd477acSTiberiu Breana 
5863dd477acSTiberiu Breana 	return IRQ_HANDLED;
5873dd477acSTiberiu Breana }
5883dd477acSTiberiu Breana 
stk3310_probe(struct i2c_client * client)5899046d80dSUwe Kleine-König static int stk3310_probe(struct i2c_client *client)
590be9e6229STiberiu Breana {
591be9e6229STiberiu Breana 	int ret;
592be9e6229STiberiu Breana 	struct iio_dev *indio_dev;
593be9e6229STiberiu Breana 	struct stk3310_data *data;
594be9e6229STiberiu Breana 
595be9e6229STiberiu Breana 	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
596be9e6229STiberiu Breana 	if (!indio_dev) {
597be9e6229STiberiu Breana 		dev_err(&client->dev, "iio allocation failed!\n");
598be9e6229STiberiu Breana 		return -ENOMEM;
599be9e6229STiberiu Breana 	}
600be9e6229STiberiu Breana 
601be9e6229STiberiu Breana 	data = iio_priv(indio_dev);
602be9e6229STiberiu Breana 	data->client = client;
603be9e6229STiberiu Breana 	i2c_set_clientdata(client, indio_dev);
604d6ecb015SArnaud Ferraris 
605d6ecb015SArnaud Ferraris 	device_property_read_u32(&client->dev, "proximity-near-level",
606d6ecb015SArnaud Ferraris 				 &data->ps_near_level);
607d6ecb015SArnaud Ferraris 
608be9e6229STiberiu Breana 	mutex_init(&data->lock);
609be9e6229STiberiu Breana 
610be9e6229STiberiu Breana 	ret = stk3310_regmap_init(data);
611be9e6229STiberiu Breana 	if (ret < 0)
612be9e6229STiberiu Breana 		return ret;
613be9e6229STiberiu Breana 
614be9e6229STiberiu Breana 	indio_dev->info = &stk3310_info;
615be9e6229STiberiu Breana 	indio_dev->name = STK3310_DRIVER_NAME;
616be9e6229STiberiu Breana 	indio_dev->modes = INDIO_DIRECT_MODE;
617be9e6229STiberiu Breana 	indio_dev->channels = stk3310_channels;
618be9e6229STiberiu Breana 	indio_dev->num_channels = ARRAY_SIZE(stk3310_channels);
619be9e6229STiberiu Breana 
620be9e6229STiberiu Breana 	ret = stk3310_init(indio_dev);
621be9e6229STiberiu Breana 	if (ret < 0)
622be9e6229STiberiu Breana 		return ret;
623be9e6229STiberiu Breana 
6246839c1b0SOctavian Purdila 	if (client->irq > 0) {
6253dd477acSTiberiu Breana 		ret = devm_request_threaded_irq(&client->dev, client->irq,
6263dd477acSTiberiu Breana 						stk3310_irq_handler,
6273dd477acSTiberiu Breana 						stk3310_irq_event_handler,
6283dd477acSTiberiu Breana 						IRQF_TRIGGER_FALLING |
6293dd477acSTiberiu Breana 						IRQF_ONESHOT,
6303dd477acSTiberiu Breana 						STK3310_EVENT, indio_dev);
6317c7a9eeaSHartmut Knaack 		if (ret < 0) {
6323dd477acSTiberiu Breana 			dev_err(&client->dev, "request irq %d failed\n",
6333dd477acSTiberiu Breana 				client->irq);
6347c7a9eeaSHartmut Knaack 			goto err_standby;
6357c7a9eeaSHartmut Knaack 		}
6363dd477acSTiberiu Breana 	}
6373dd477acSTiberiu Breana 
638037e966fSHartmut Knaack 	ret = iio_device_register(indio_dev);
639037e966fSHartmut Knaack 	if (ret < 0) {
640037e966fSHartmut Knaack 		dev_err(&client->dev, "device_register failed\n");
6417c7a9eeaSHartmut Knaack 		goto err_standby;
642037e966fSHartmut Knaack 	}
643037e966fSHartmut Knaack 
6447c7a9eeaSHartmut Knaack 	return 0;
6457c7a9eeaSHartmut Knaack 
6467c7a9eeaSHartmut Knaack err_standby:
6477c7a9eeaSHartmut Knaack 	stk3310_set_state(data, STK3310_STATE_STANDBY);
648be9e6229STiberiu Breana 	return ret;
649be9e6229STiberiu Breana }
650be9e6229STiberiu Breana 
stk3310_remove(struct i2c_client * client)651ed5c2f5fSUwe Kleine-König static void stk3310_remove(struct i2c_client *client)
652be9e6229STiberiu Breana {
653be9e6229STiberiu Breana 	struct iio_dev *indio_dev = i2c_get_clientdata(client);
654be9e6229STiberiu Breana 
655be9e6229STiberiu Breana 	iio_device_unregister(indio_dev);
65658a6df55SUwe Kleine-König 	stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY);
657be9e6229STiberiu Breana }
658be9e6229STiberiu Breana 
stk3310_suspend(struct device * dev)659be9e6229STiberiu Breana static int stk3310_suspend(struct device *dev)
660be9e6229STiberiu Breana {
661be9e6229STiberiu Breana 	struct stk3310_data *data;
662be9e6229STiberiu Breana 
663be9e6229STiberiu Breana 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
664be9e6229STiberiu Breana 
665be9e6229STiberiu Breana 	return stk3310_set_state(data, STK3310_STATE_STANDBY);
666be9e6229STiberiu Breana }
667be9e6229STiberiu Breana 
stk3310_resume(struct device * dev)668be9e6229STiberiu Breana static int stk3310_resume(struct device *dev)
669be9e6229STiberiu Breana {
670952c3aa3SHartmut Knaack 	u8 state = 0;
671be9e6229STiberiu Breana 	struct stk3310_data *data;
672be9e6229STiberiu Breana 
673be9e6229STiberiu Breana 	data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
674be9e6229STiberiu Breana 	if (data->ps_enabled)
675be9e6229STiberiu Breana 		state |= STK3310_STATE_EN_PS;
676be9e6229STiberiu Breana 	if (data->als_enabled)
677be9e6229STiberiu Breana 		state |= STK3310_STATE_EN_ALS;
678be9e6229STiberiu Breana 
679be9e6229STiberiu Breana 	return stk3310_set_state(data, state);
680be9e6229STiberiu Breana }
681be9e6229STiberiu Breana 
68220cadda3SJonathan Cameron static DEFINE_SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend,
68320cadda3SJonathan Cameron 				stk3310_resume);
684be9e6229STiberiu Breana 
685be9e6229STiberiu Breana static const struct i2c_device_id stk3310_i2c_id[] = {
686be9e6229STiberiu Breana 	{"STK3310", 0},
687be9e6229STiberiu Breana 	{"STK3311", 0},
688677f1681SMartijn Braam 	{"STK3335", 0},
689be9e6229STiberiu Breana 	{}
690be9e6229STiberiu Breana };
69158e446fcSJavier Martinez Canillas MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id);
692be9e6229STiberiu Breana 
693be9e6229STiberiu Breana static const struct acpi_device_id stk3310_acpi_id[] = {
694be9e6229STiberiu Breana 	{"STK3310", 0},
695be9e6229STiberiu Breana 	{"STK3311", 0},
696677f1681SMartijn Braam 	{"STK3335", 0},
697be9e6229STiberiu Breana 	{}
698be9e6229STiberiu Breana };
699be9e6229STiberiu Breana 
700be9e6229STiberiu Breana MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id);
701be9e6229STiberiu Breana 
702c3a68607SLuca Weiss static const struct of_device_id stk3310_of_match[] = {
703c3a68607SLuca Weiss 	{ .compatible = "sensortek,stk3310", },
704c3a68607SLuca Weiss 	{ .compatible = "sensortek,stk3311", },
705c3a68607SLuca Weiss 	{ .compatible = "sensortek,stk3335", },
706c3a68607SLuca Weiss 	{}
707c3a68607SLuca Weiss };
708c3a68607SLuca Weiss MODULE_DEVICE_TABLE(of, stk3310_of_match);
709c3a68607SLuca Weiss 
710be9e6229STiberiu Breana static struct i2c_driver stk3310_driver = {
711be9e6229STiberiu Breana 	.driver = {
712be9e6229STiberiu Breana 		.name = "stk3310",
713c3a68607SLuca Weiss 		.of_match_table = stk3310_of_match,
71420cadda3SJonathan Cameron 		.pm = pm_sleep_ptr(&stk3310_pm_ops),
715be9e6229STiberiu Breana 		.acpi_match_table = ACPI_PTR(stk3310_acpi_id),
716be9e6229STiberiu Breana 	},
717*7cf15f42SUwe Kleine-König 	.probe =        stk3310_probe,
718be9e6229STiberiu Breana 	.remove =           stk3310_remove,
719be9e6229STiberiu Breana 	.id_table =         stk3310_i2c_id,
720be9e6229STiberiu Breana };
721be9e6229STiberiu Breana 
722be9e6229STiberiu Breana module_i2c_driver(stk3310_driver);
723be9e6229STiberiu Breana 
724be9e6229STiberiu Breana MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>");
725be9e6229STiberiu Breana MODULE_DESCRIPTION("STK3310 Ambient Light and Proximity Sensor driver");
726be9e6229STiberiu Breana MODULE_LICENSE("GPL v2");
727