Commit | Line | Data |
---|---|---|
be9e6229 TB |
1 | /** |
2 | * Sensortek STK3310/STK3311 Ambient Light and Proximity Sensor | |
3 | * | |
4 | * Copyright (c) 2015, Intel Corporation. | |
5 | * | |
6 | * This file is subject to the terms and conditions of version 2 of | |
7 | * the GNU General Public License. See the file COPYING in the main | |
8 | * directory of this archive for more details. | |
9 | * | |
10 | * IIO driver for STK3310/STK3311. 7-bit I2C address: 0x48. | |
11 | */ | |
12 | ||
13 | #include <linux/acpi.h> | |
14 | #include <linux/i2c.h> | |
3dd477ac | 15 | #include <linux/interrupt.h> |
be9e6229 TB |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> | |
18 | #include <linux/regmap.h> | |
3dd477ac TB |
19 | #include <linux/gpio/consumer.h> |
20 | #include <linux/iio/events.h> | |
be9e6229 TB |
21 | #include <linux/iio/iio.h> |
22 | #include <linux/iio/sysfs.h> | |
23 | ||
24 | #define STK3310_REG_STATE 0x00 | |
25 | #define STK3310_REG_PSCTRL 0x01 | |
26 | #define STK3310_REG_ALSCTRL 0x02 | |
3dd477ac TB |
27 | #define STK3310_REG_INT 0x04 |
28 | #define STK3310_REG_THDH_PS 0x06 | |
29 | #define STK3310_REG_THDL_PS 0x08 | |
30 | #define STK3310_REG_FLAG 0x10 | |
be9e6229 TB |
31 | #define STK3310_REG_PS_DATA_MSB 0x11 |
32 | #define STK3310_REG_PS_DATA_LSB 0x12 | |
33 | #define STK3310_REG_ALS_DATA_MSB 0x13 | |
34 | #define STK3310_REG_ALS_DATA_LSB 0x14 | |
35 | #define STK3310_REG_ID 0x3E | |
36 | #define STK3310_MAX_REG 0x80 | |
37 | ||
38 | #define STK3310_STATE_EN_PS 0x01 | |
39 | #define STK3310_STATE_EN_ALS 0x02 | |
40 | #define STK3310_STATE_STANDBY 0x00 | |
41 | ||
42 | #define STK3310_CHIP_ID_VAL 0x13 | |
43 | #define STK3311_CHIP_ID_VAL 0x1D | |
3dd477ac | 44 | #define STK3310_PSINT_EN 0x01 |
be9e6229 TB |
45 | #define STK3310_PS_MAX_VAL 0xFFFF |
46 | ||
47 | #define STK3310_DRIVER_NAME "stk3310" | |
48 | #define STK3310_REGMAP_NAME "stk3310_regmap" | |
3dd477ac TB |
49 | #define STK3310_EVENT "stk3310_event" |
50 | #define STK3310_GPIO "stk3310_gpio" | |
be9e6229 TB |
51 | |
52 | #define STK3310_SCALE_AVAILABLE "6.4 1.6 0.4 0.1" | |
53 | ||
54 | #define STK3310_IT_AVAILABLE \ | |
55 | "0.000185 0.000370 0.000741 0.001480 0.002960 0.005920 0.011840 " \ | |
56 | "0.023680 0.047360 0.094720 0.189440 0.378880 0.757760 1.515520 " \ | |
57 | "3.031040 6.062080" | |
58 | ||
59 | #define STK3310_REGFIELD(name) \ | |
60 | do { \ | |
61 | data->reg_##name = \ | |
62 | devm_regmap_field_alloc(&client->dev, regmap, \ | |
63 | stk3310_reg_field_##name); \ | |
64 | if (IS_ERR(data->reg_##name)) { \ | |
65 | dev_err(&client->dev, "reg field alloc failed.\n"); \ | |
66 | return PTR_ERR(data->reg_##name); \ | |
67 | } \ | |
68 | } while (0) | |
69 | ||
70 | static const struct reg_field stk3310_reg_field_state = | |
71 | REG_FIELD(STK3310_REG_STATE, 0, 2); | |
72 | static const struct reg_field stk3310_reg_field_als_gain = | |
73 | REG_FIELD(STK3310_REG_ALSCTRL, 4, 5); | |
74 | static const struct reg_field stk3310_reg_field_ps_gain = | |
75 | REG_FIELD(STK3310_REG_PSCTRL, 4, 5); | |
76 | static const struct reg_field stk3310_reg_field_als_it = | |
77 | REG_FIELD(STK3310_REG_ALSCTRL, 0, 3); | |
78 | static const struct reg_field stk3310_reg_field_ps_it = | |
79 | REG_FIELD(STK3310_REG_PSCTRL, 0, 3); | |
3dd477ac TB |
80 | static const struct reg_field stk3310_reg_field_int_ps = |
81 | REG_FIELD(STK3310_REG_INT, 0, 2); | |
82 | static const struct reg_field stk3310_reg_field_flag_psint = | |
83 | REG_FIELD(STK3310_REG_FLAG, 4, 4); | |
84 | static const struct reg_field stk3310_reg_field_flag_nf = | |
85 | REG_FIELD(STK3310_REG_FLAG, 0, 0); | |
0f16fc8b TB |
86 | |
87 | /* Estimate maximum proximity values with regard to measurement scale. */ | |
be9e6229 | 88 | static const int stk3310_ps_max[4] = { |
0f16fc8b TB |
89 | STK3310_PS_MAX_VAL / 640, |
90 | STK3310_PS_MAX_VAL / 160, | |
91 | STK3310_PS_MAX_VAL / 40, | |
92 | STK3310_PS_MAX_VAL / 10 | |
be9e6229 TB |
93 | }; |
94 | ||
95 | static const int stk3310_scale_table[][2] = { | |
96 | {6, 400000}, {1, 600000}, {0, 400000}, {0, 100000} | |
97 | }; | |
98 | ||
99 | /* Integration time in seconds, microseconds */ | |
100 | static const int stk3310_it_table[][2] = { | |
101 | {0, 185}, {0, 370}, {0, 741}, {0, 1480}, | |
102 | {0, 2960}, {0, 5920}, {0, 11840}, {0, 23680}, | |
103 | {0, 47360}, {0, 94720}, {0, 189440}, {0, 378880}, | |
104 | {0, 757760}, {1, 515520}, {3, 31040}, {6, 62080}, | |
105 | }; | |
106 | ||
107 | struct stk3310_data { | |
108 | struct i2c_client *client; | |
109 | struct mutex lock; | |
110 | bool als_enabled; | |
111 | bool ps_enabled; | |
3dd477ac | 112 | u64 timestamp; |
be9e6229 TB |
113 | struct regmap *regmap; |
114 | struct regmap_field *reg_state; | |
115 | struct regmap_field *reg_als_gain; | |
116 | struct regmap_field *reg_ps_gain; | |
117 | struct regmap_field *reg_als_it; | |
118 | struct regmap_field *reg_ps_it; | |
3dd477ac TB |
119 | struct regmap_field *reg_int_ps; |
120 | struct regmap_field *reg_flag_psint; | |
121 | struct regmap_field *reg_flag_nf; | |
122 | }; | |
123 | ||
124 | static const struct iio_event_spec stk3310_events[] = { | |
125 | /* Proximity event */ | |
126 | { | |
127 | .type = IIO_EV_TYPE_THRESH, | |
0f16fc8b | 128 | .dir = IIO_EV_DIR_RISING, |
3dd477ac TB |
129 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | |
130 | BIT(IIO_EV_INFO_ENABLE), | |
131 | }, | |
132 | /* Out-of-proximity event */ | |
133 | { | |
134 | .type = IIO_EV_TYPE_THRESH, | |
0f16fc8b | 135 | .dir = IIO_EV_DIR_FALLING, |
3dd477ac TB |
136 | .mask_separate = BIT(IIO_EV_INFO_VALUE) | |
137 | BIT(IIO_EV_INFO_ENABLE), | |
138 | }, | |
be9e6229 TB |
139 | }; |
140 | ||
141 | static const struct iio_chan_spec stk3310_channels[] = { | |
142 | { | |
143 | .type = IIO_LIGHT, | |
144 | .info_mask_separate = | |
145 | BIT(IIO_CHAN_INFO_RAW) | | |
146 | BIT(IIO_CHAN_INFO_SCALE) | | |
147 | BIT(IIO_CHAN_INFO_INT_TIME), | |
148 | }, | |
149 | { | |
150 | .type = IIO_PROXIMITY, | |
151 | .info_mask_separate = | |
152 | BIT(IIO_CHAN_INFO_RAW) | | |
153 | BIT(IIO_CHAN_INFO_SCALE) | | |
154 | BIT(IIO_CHAN_INFO_INT_TIME), | |
3dd477ac TB |
155 | .event_spec = stk3310_events, |
156 | .num_event_specs = ARRAY_SIZE(stk3310_events), | |
be9e6229 TB |
157 | } |
158 | }; | |
159 | ||
160 | static IIO_CONST_ATTR(in_illuminance_scale_available, STK3310_SCALE_AVAILABLE); | |
161 | ||
162 | static IIO_CONST_ATTR(in_proximity_scale_available, STK3310_SCALE_AVAILABLE); | |
163 | ||
164 | static IIO_CONST_ATTR(in_illuminance_integration_time_available, | |
165 | STK3310_IT_AVAILABLE); | |
166 | ||
167 | static IIO_CONST_ATTR(in_proximity_integration_time_available, | |
168 | STK3310_IT_AVAILABLE); | |
169 | ||
170 | static struct attribute *stk3310_attributes[] = { | |
171 | &iio_const_attr_in_illuminance_scale_available.dev_attr.attr, | |
172 | &iio_const_attr_in_proximity_scale_available.dev_attr.attr, | |
173 | &iio_const_attr_in_illuminance_integration_time_available.dev_attr.attr, | |
174 | &iio_const_attr_in_proximity_integration_time_available.dev_attr.attr, | |
175 | NULL, | |
176 | }; | |
177 | ||
178 | static const struct attribute_group stk3310_attribute_group = { | |
179 | .attrs = stk3310_attributes | |
180 | }; | |
181 | ||
182 | static int stk3310_get_index(const int table[][2], int table_size, | |
183 | int val, int val2) | |
184 | { | |
185 | int i; | |
186 | ||
187 | for (i = 0; i < table_size; i++) { | |
188 | if (val == table[i][0] && val2 == table[i][1]) | |
189 | return i; | |
190 | } | |
191 | ||
192 | return -EINVAL; | |
193 | } | |
194 | ||
3dd477ac TB |
195 | static int stk3310_read_event(struct iio_dev *indio_dev, |
196 | const struct iio_chan_spec *chan, | |
197 | enum iio_event_type type, | |
198 | enum iio_event_direction dir, | |
199 | enum iio_event_info info, | |
200 | int *val, int *val2) | |
201 | { | |
202 | u8 reg; | |
423ad0c4 | 203 | __be16 buf; |
3dd477ac | 204 | int ret; |
3dd477ac TB |
205 | struct stk3310_data *data = iio_priv(indio_dev); |
206 | ||
207 | if (info != IIO_EV_INFO_VALUE) | |
208 | return -EINVAL; | |
209 | ||
0f16fc8b | 210 | /* Only proximity interrupts are implemented at the moment. */ |
3dd477ac | 211 | if (dir == IIO_EV_DIR_RISING) |
3dd477ac | 212 | reg = STK3310_REG_THDH_PS; |
0f16fc8b TB |
213 | else if (dir == IIO_EV_DIR_FALLING) |
214 | reg = STK3310_REG_THDL_PS; | |
3dd477ac TB |
215 | else |
216 | return -EINVAL; | |
217 | ||
218 | mutex_lock(&data->lock); | |
219 | ret = regmap_bulk_read(data->regmap, reg, &buf, 2); | |
220 | mutex_unlock(&data->lock); | |
221 | if (ret < 0) { | |
222 | dev_err(&data->client->dev, "register read failed\n"); | |
223 | return ret; | |
224 | } | |
423ad0c4 | 225 | *val = be16_to_cpu(buf); |
3dd477ac TB |
226 | |
227 | return IIO_VAL_INT; | |
228 | } | |
229 | ||
230 | static int stk3310_write_event(struct iio_dev *indio_dev, | |
231 | const struct iio_chan_spec *chan, | |
232 | enum iio_event_type type, | |
233 | enum iio_event_direction dir, | |
234 | enum iio_event_info info, | |
235 | int val, int val2) | |
236 | { | |
237 | u8 reg; | |
423ad0c4 | 238 | __be16 buf; |
3dd477ac TB |
239 | int ret; |
240 | unsigned int index; | |
241 | struct stk3310_data *data = iio_priv(indio_dev); | |
242 | struct i2c_client *client = data->client; | |
243 | ||
244 | regmap_field_read(data->reg_ps_gain, &index); | |
245 | if (val > stk3310_ps_max[index]) | |
246 | return -EINVAL; | |
247 | ||
248 | if (dir == IIO_EV_DIR_RISING) | |
3dd477ac | 249 | reg = STK3310_REG_THDH_PS; |
0f16fc8b TB |
250 | else if (dir == IIO_EV_DIR_FALLING) |
251 | reg = STK3310_REG_THDL_PS; | |
3dd477ac TB |
252 | else |
253 | return -EINVAL; | |
254 | ||
423ad0c4 | 255 | buf = cpu_to_be16(val); |
3dd477ac TB |
256 | ret = regmap_bulk_write(data->regmap, reg, &buf, 2); |
257 | if (ret < 0) | |
258 | dev_err(&client->dev, "failed to set PS threshold!\n"); | |
259 | ||
260 | return ret; | |
261 | } | |
262 | ||
263 | static int stk3310_read_event_config(struct iio_dev *indio_dev, | |
264 | const struct iio_chan_spec *chan, | |
265 | enum iio_event_type type, | |
266 | enum iio_event_direction dir) | |
267 | { | |
268 | unsigned int event_val; | |
269 | struct stk3310_data *data = iio_priv(indio_dev); | |
270 | ||
271 | regmap_field_read(data->reg_int_ps, &event_val); | |
272 | ||
273 | return event_val; | |
274 | } | |
275 | ||
276 | static int stk3310_write_event_config(struct iio_dev *indio_dev, | |
277 | const struct iio_chan_spec *chan, | |
278 | enum iio_event_type type, | |
279 | enum iio_event_direction dir, | |
280 | int state) | |
281 | { | |
282 | int ret; | |
283 | struct stk3310_data *data = iio_priv(indio_dev); | |
284 | struct i2c_client *client = data->client; | |
285 | ||
286 | if (state < 0 || state > 7) | |
287 | return -EINVAL; | |
288 | ||
289 | /* Set INT_PS value */ | |
290 | mutex_lock(&data->lock); | |
291 | ret = regmap_field_write(data->reg_int_ps, state); | |
292 | if (ret < 0) | |
293 | dev_err(&client->dev, "failed to set interrupt mode\n"); | |
294 | mutex_unlock(&data->lock); | |
295 | ||
296 | return ret; | |
297 | } | |
298 | ||
be9e6229 TB |
299 | static int stk3310_read_raw(struct iio_dev *indio_dev, |
300 | struct iio_chan_spec const *chan, | |
301 | int *val, int *val2, long mask) | |
302 | { | |
303 | u8 reg; | |
423ad0c4 | 304 | __be16 buf; |
be9e6229 TB |
305 | int ret; |
306 | unsigned int index; | |
307 | struct stk3310_data *data = iio_priv(indio_dev); | |
308 | struct i2c_client *client = data->client; | |
309 | ||
310 | switch (mask) { | |
311 | case IIO_CHAN_INFO_RAW: | |
312 | if (chan->type == IIO_LIGHT) | |
313 | reg = STK3310_REG_ALS_DATA_MSB; | |
314 | else if (chan->type == IIO_PROXIMITY) | |
315 | reg = STK3310_REG_PS_DATA_MSB; | |
316 | else | |
317 | return -EINVAL; | |
318 | mutex_lock(&data->lock); | |
319 | ret = regmap_bulk_read(data->regmap, reg, &buf, 2); | |
320 | if (ret < 0) { | |
321 | dev_err(&client->dev, "register read failed\n"); | |
322 | mutex_unlock(&data->lock); | |
323 | return ret; | |
324 | } | |
423ad0c4 | 325 | *val = be16_to_cpu(buf); |
be9e6229 TB |
326 | mutex_unlock(&data->lock); |
327 | return IIO_VAL_INT; | |
328 | case IIO_CHAN_INFO_INT_TIME: | |
329 | if (chan->type == IIO_LIGHT) | |
330 | regmap_field_read(data->reg_als_it, &index); | |
331 | else | |
332 | regmap_field_read(data->reg_ps_it, &index); | |
333 | *val = stk3310_it_table[index][0]; | |
334 | *val2 = stk3310_it_table[index][1]; | |
335 | return IIO_VAL_INT_PLUS_MICRO; | |
336 | case IIO_CHAN_INFO_SCALE: | |
337 | if (chan->type == IIO_LIGHT) | |
338 | regmap_field_read(data->reg_als_gain, &index); | |
339 | else | |
340 | regmap_field_read(data->reg_ps_gain, &index); | |
341 | *val = stk3310_scale_table[index][0]; | |
342 | *val2 = stk3310_scale_table[index][1]; | |
343 | return IIO_VAL_INT_PLUS_MICRO; | |
344 | } | |
345 | ||
346 | return -EINVAL; | |
347 | } | |
348 | ||
349 | static int stk3310_write_raw(struct iio_dev *indio_dev, | |
350 | struct iio_chan_spec const *chan, | |
351 | int val, int val2, long mask) | |
352 | { | |
353 | int ret; | |
ed6e75c7 | 354 | int index; |
be9e6229 TB |
355 | struct stk3310_data *data = iio_priv(indio_dev); |
356 | ||
357 | switch (mask) { | |
358 | case IIO_CHAN_INFO_INT_TIME: | |
359 | index = stk3310_get_index(stk3310_it_table, | |
360 | ARRAY_SIZE(stk3310_it_table), | |
361 | val, val2); | |
362 | if (index < 0) | |
363 | return -EINVAL; | |
364 | mutex_lock(&data->lock); | |
365 | if (chan->type == IIO_LIGHT) | |
366 | ret = regmap_field_write(data->reg_als_it, index); | |
367 | else | |
368 | ret = regmap_field_write(data->reg_ps_it, index); | |
369 | if (ret < 0) | |
370 | dev_err(&data->client->dev, | |
371 | "sensor configuration failed\n"); | |
372 | mutex_unlock(&data->lock); | |
373 | return ret; | |
374 | ||
375 | case IIO_CHAN_INFO_SCALE: | |
376 | index = stk3310_get_index(stk3310_scale_table, | |
377 | ARRAY_SIZE(stk3310_scale_table), | |
378 | val, val2); | |
379 | if (index < 0) | |
380 | return -EINVAL; | |
381 | mutex_lock(&data->lock); | |
382 | if (chan->type == IIO_LIGHT) | |
383 | ret = regmap_field_write(data->reg_als_gain, index); | |
384 | else | |
385 | ret = regmap_field_write(data->reg_ps_gain, index); | |
386 | if (ret < 0) | |
387 | dev_err(&data->client->dev, | |
388 | "sensor configuration failed\n"); | |
389 | mutex_unlock(&data->lock); | |
390 | return ret; | |
391 | } | |
392 | ||
393 | return -EINVAL; | |
394 | } | |
395 | ||
396 | static const struct iio_info stk3310_info = { | |
397 | .driver_module = THIS_MODULE, | |
398 | .read_raw = stk3310_read_raw, | |
399 | .write_raw = stk3310_write_raw, | |
400 | .attrs = &stk3310_attribute_group, | |
3dd477ac TB |
401 | .read_event_value = stk3310_read_event, |
402 | .write_event_value = stk3310_write_event, | |
403 | .read_event_config = stk3310_read_event_config, | |
404 | .write_event_config = stk3310_write_event_config, | |
be9e6229 TB |
405 | }; |
406 | ||
407 | static int stk3310_set_state(struct stk3310_data *data, u8 state) | |
408 | { | |
409 | int ret; | |
410 | struct i2c_client *client = data->client; | |
411 | ||
412 | /* 3-bit state; 0b100 is not supported. */ | |
413 | if (state > 7 || state == 4) | |
414 | return -EINVAL; | |
415 | ||
416 | mutex_lock(&data->lock); | |
417 | ret = regmap_field_write(data->reg_state, state); | |
418 | if (ret < 0) { | |
419 | dev_err(&client->dev, "failed to change sensor state\n"); | |
420 | } else if (state != STK3310_STATE_STANDBY) { | |
421 | /* Don't reset the 'enabled' flags if we're going in standby */ | |
422 | data->ps_enabled = !!(state & 0x01); | |
423 | data->als_enabled = !!(state & 0x02); | |
424 | } | |
425 | mutex_unlock(&data->lock); | |
426 | ||
427 | return ret; | |
428 | } | |
429 | ||
430 | static int stk3310_init(struct iio_dev *indio_dev) | |
431 | { | |
432 | int ret; | |
433 | int chipid; | |
434 | u8 state; | |
435 | struct stk3310_data *data = iio_priv(indio_dev); | |
436 | struct i2c_client *client = data->client; | |
437 | ||
438 | regmap_read(data->regmap, STK3310_REG_ID, &chipid); | |
439 | if (chipid != STK3310_CHIP_ID_VAL && | |
440 | chipid != STK3311_CHIP_ID_VAL) { | |
441 | dev_err(&client->dev, "invalid chip id: 0x%x\n", chipid); | |
442 | return -ENODEV; | |
443 | } | |
444 | ||
445 | state = STK3310_STATE_EN_ALS | STK3310_STATE_EN_PS; | |
446 | ret = stk3310_set_state(data, state); | |
3dd477ac | 447 | if (ret < 0) { |
be9e6229 | 448 | dev_err(&client->dev, "failed to enable sensor"); |
3dd477ac TB |
449 | return ret; |
450 | } | |
451 | ||
452 | /* Enable PS interrupts */ | |
453 | ret = regmap_field_write(data->reg_int_ps, STK3310_PSINT_EN); | |
454 | if (ret < 0) | |
455 | dev_err(&client->dev, "failed to enable interrupts!\n"); | |
456 | ||
457 | return ret; | |
458 | } | |
459 | ||
460 | static int stk3310_gpio_probe(struct i2c_client *client) | |
461 | { | |
462 | struct device *dev; | |
463 | struct gpio_desc *gpio; | |
464 | int ret; | |
465 | ||
466 | if (!client) | |
467 | return -EINVAL; | |
468 | ||
469 | dev = &client->dev; | |
470 | ||
471 | /* gpio interrupt pin */ | |
7d4eb6f2 | 472 | gpio = devm_gpiod_get_index(dev, STK3310_GPIO, 0, GPIOD_IN); |
3dd477ac TB |
473 | if (IS_ERR(gpio)) { |
474 | dev_err(dev, "acpi gpio get index failed\n"); | |
475 | return PTR_ERR(gpio); | |
476 | } | |
477 | ||
3dd477ac TB |
478 | ret = gpiod_to_irq(gpio); |
479 | dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret); | |
be9e6229 TB |
480 | |
481 | return ret; | |
482 | } | |
483 | ||
484 | static bool stk3310_is_volatile_reg(struct device *dev, unsigned int reg) | |
485 | { | |
486 | switch (reg) { | |
487 | case STK3310_REG_ALS_DATA_MSB: | |
488 | case STK3310_REG_ALS_DATA_LSB: | |
489 | case STK3310_REG_PS_DATA_LSB: | |
490 | case STK3310_REG_PS_DATA_MSB: | |
3dd477ac | 491 | case STK3310_REG_FLAG: |
be9e6229 TB |
492 | return true; |
493 | default: | |
494 | return false; | |
495 | } | |
496 | } | |
497 | ||
498 | static struct regmap_config stk3310_regmap_config = { | |
499 | .name = STK3310_REGMAP_NAME, | |
500 | .reg_bits = 8, | |
501 | .val_bits = 8, | |
502 | .max_register = STK3310_MAX_REG, | |
503 | .cache_type = REGCACHE_RBTREE, | |
504 | .volatile_reg = stk3310_is_volatile_reg, | |
505 | }; | |
506 | ||
507 | static int stk3310_regmap_init(struct stk3310_data *data) | |
508 | { | |
509 | struct regmap *regmap; | |
510 | struct i2c_client *client; | |
511 | ||
512 | client = data->client; | |
513 | regmap = devm_regmap_init_i2c(client, &stk3310_regmap_config); | |
514 | if (IS_ERR(regmap)) { | |
515 | dev_err(&client->dev, "regmap initialization failed.\n"); | |
516 | return PTR_ERR(regmap); | |
517 | } | |
518 | data->regmap = regmap; | |
519 | ||
520 | STK3310_REGFIELD(state); | |
521 | STK3310_REGFIELD(als_gain); | |
522 | STK3310_REGFIELD(ps_gain); | |
523 | STK3310_REGFIELD(als_it); | |
524 | STK3310_REGFIELD(ps_it); | |
3dd477ac TB |
525 | STK3310_REGFIELD(int_ps); |
526 | STK3310_REGFIELD(flag_psint); | |
527 | STK3310_REGFIELD(flag_nf); | |
be9e6229 TB |
528 | |
529 | return 0; | |
530 | } | |
531 | ||
3dd477ac TB |
532 | static irqreturn_t stk3310_irq_handler(int irq, void *private) |
533 | { | |
534 | struct iio_dev *indio_dev = private; | |
535 | struct stk3310_data *data = iio_priv(indio_dev); | |
536 | ||
537 | data->timestamp = iio_get_time_ns(); | |
538 | ||
539 | return IRQ_WAKE_THREAD; | |
540 | } | |
541 | ||
542 | static irqreturn_t stk3310_irq_event_handler(int irq, void *private) | |
543 | { | |
544 | int ret; | |
545 | unsigned int dir; | |
546 | u64 event; | |
547 | ||
548 | struct iio_dev *indio_dev = private; | |
549 | struct stk3310_data *data = iio_priv(indio_dev); | |
550 | ||
551 | /* Read FLAG_NF to figure out what threshold has been met. */ | |
552 | mutex_lock(&data->lock); | |
553 | ret = regmap_field_read(data->reg_flag_nf, &dir); | |
554 | if (ret < 0) { | |
555 | dev_err(&data->client->dev, "register read failed\n"); | |
556 | mutex_unlock(&data->lock); | |
557 | return ret; | |
558 | } | |
559 | event = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY, 1, | |
560 | IIO_EV_TYPE_THRESH, | |
0f16fc8b TB |
561 | (dir ? IIO_EV_DIR_FALLING : |
562 | IIO_EV_DIR_RISING)); | |
3dd477ac TB |
563 | iio_push_event(indio_dev, event, data->timestamp); |
564 | ||
565 | /* Reset the interrupt flag */ | |
566 | ret = regmap_field_write(data->reg_flag_psint, 0); | |
567 | if (ret < 0) | |
568 | dev_err(&data->client->dev, "failed to reset interrupts\n"); | |
569 | mutex_unlock(&data->lock); | |
570 | ||
571 | return IRQ_HANDLED; | |
572 | } | |
573 | ||
be9e6229 TB |
574 | static int stk3310_probe(struct i2c_client *client, |
575 | const struct i2c_device_id *id) | |
576 | { | |
577 | int ret; | |
578 | struct iio_dev *indio_dev; | |
579 | struct stk3310_data *data; | |
580 | ||
581 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | |
582 | if (!indio_dev) { | |
583 | dev_err(&client->dev, "iio allocation failed!\n"); | |
584 | return -ENOMEM; | |
585 | } | |
586 | ||
587 | data = iio_priv(indio_dev); | |
588 | data->client = client; | |
589 | i2c_set_clientdata(client, indio_dev); | |
590 | mutex_init(&data->lock); | |
591 | ||
592 | ret = stk3310_regmap_init(data); | |
593 | if (ret < 0) | |
594 | return ret; | |
595 | ||
596 | indio_dev->dev.parent = &client->dev; | |
597 | indio_dev->info = &stk3310_info; | |
598 | indio_dev->name = STK3310_DRIVER_NAME; | |
599 | indio_dev->modes = INDIO_DIRECT_MODE; | |
600 | indio_dev->channels = stk3310_channels; | |
601 | indio_dev->num_channels = ARRAY_SIZE(stk3310_channels); | |
602 | ||
603 | ret = stk3310_init(indio_dev); | |
604 | if (ret < 0) | |
605 | return ret; | |
606 | ||
037e966f | 607 | if (client->irq < 0) |
3dd477ac TB |
608 | client->irq = stk3310_gpio_probe(client); |
609 | ||
610 | if (client->irq >= 0) { | |
611 | ret = devm_request_threaded_irq(&client->dev, client->irq, | |
612 | stk3310_irq_handler, | |
613 | stk3310_irq_event_handler, | |
614 | IRQF_TRIGGER_FALLING | | |
615 | IRQF_ONESHOT, | |
616 | STK3310_EVENT, indio_dev); | |
617 | if (ret < 0) | |
618 | dev_err(&client->dev, "request irq %d failed\n", | |
619 | client->irq); | |
620 | } | |
621 | ||
037e966f HK |
622 | ret = iio_device_register(indio_dev); |
623 | if (ret < 0) { | |
624 | dev_err(&client->dev, "device_register failed\n"); | |
625 | stk3310_set_state(data, STK3310_STATE_STANDBY); | |
626 | } | |
627 | ||
be9e6229 TB |
628 | return ret; |
629 | } | |
630 | ||
631 | static int stk3310_remove(struct i2c_client *client) | |
632 | { | |
633 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | |
634 | ||
635 | iio_device_unregister(indio_dev); | |
636 | return stk3310_set_state(iio_priv(indio_dev), STK3310_STATE_STANDBY); | |
637 | } | |
638 | ||
639 | #ifdef CONFIG_PM_SLEEP | |
640 | static int stk3310_suspend(struct device *dev) | |
641 | { | |
642 | struct stk3310_data *data; | |
643 | ||
644 | data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
645 | ||
646 | return stk3310_set_state(data, STK3310_STATE_STANDBY); | |
647 | } | |
648 | ||
649 | static int stk3310_resume(struct device *dev) | |
650 | { | |
651 | int state = 0; | |
652 | struct stk3310_data *data; | |
653 | ||
654 | data = iio_priv(i2c_get_clientdata(to_i2c_client(dev))); | |
655 | if (data->ps_enabled) | |
656 | state |= STK3310_STATE_EN_PS; | |
657 | if (data->als_enabled) | |
658 | state |= STK3310_STATE_EN_ALS; | |
659 | ||
660 | return stk3310_set_state(data, state); | |
661 | } | |
662 | ||
663 | static SIMPLE_DEV_PM_OPS(stk3310_pm_ops, stk3310_suspend, stk3310_resume); | |
664 | ||
665 | #define STK3310_PM_OPS (&stk3310_pm_ops) | |
666 | #else | |
667 | #define STK3310_PM_OPS NULL | |
668 | #endif | |
669 | ||
670 | static const struct i2c_device_id stk3310_i2c_id[] = { | |
671 | {"STK3310", 0}, | |
672 | {"STK3311", 0}, | |
673 | {} | |
674 | }; | |
58e446fc | 675 | MODULE_DEVICE_TABLE(i2c, stk3310_i2c_id); |
be9e6229 TB |
676 | |
677 | static const struct acpi_device_id stk3310_acpi_id[] = { | |
678 | {"STK3310", 0}, | |
679 | {"STK3311", 0}, | |
680 | {} | |
681 | }; | |
682 | ||
683 | MODULE_DEVICE_TABLE(acpi, stk3310_acpi_id); | |
684 | ||
685 | static struct i2c_driver stk3310_driver = { | |
686 | .driver = { | |
687 | .name = "stk3310", | |
688 | .pm = STK3310_PM_OPS, | |
689 | .acpi_match_table = ACPI_PTR(stk3310_acpi_id), | |
690 | }, | |
691 | .probe = stk3310_probe, | |
692 | .remove = stk3310_remove, | |
693 | .id_table = stk3310_i2c_id, | |
694 | }; | |
695 | ||
696 | module_i2c_driver(stk3310_driver); | |
697 | ||
698 | MODULE_AUTHOR("Tiberiu Breana <tiberiu.a.breana@intel.com>"); | |
699 | MODULE_DESCRIPTION("STK3310 Ambient Light and Proximity Sensor driver"); | |
700 | MODULE_LICENSE("GPL v2"); |