diff options
author | Crestez Dan Leonard <leonard.crestez@intel.com> | 2016-04-18 10:31:53 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2016-04-24 05:06:55 -0400 |
commit | b9567e6664643eb99367fb88d14fdba863b1688a (patch) | |
tree | f478f8c9e57bb6f60857a3595a841e3110285eba | |
parent | 0d96d5ead3f7f1303a6a445051f29bba7c7f4e47 (diff) |
max44000: Initial support
This just adds support for reporting illuminance with default settings.
Important default registers are written on probe because the device
otherwise lacks a reset function.
Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
-rw-r--r-- | drivers/iio/light/Kconfig | 11 | ||||
-rw-r--r-- | drivers/iio/light/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/light/max44000.c | 324 |
3 files changed, 336 insertions, 0 deletions
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index cbd723236e38..7c566f516572 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig | |||
@@ -234,6 +234,17 @@ config LTR501 | |||
234 | This driver can also be built as a module. If so, the module | 234 | This driver can also be built as a module. If so, the module |
235 | will be called ltr501. | 235 | will be called ltr501. |
236 | 236 | ||
237 | config MAX44000 | ||
238 | tristate "MAX44000 Ambient and Infrared Proximity Sensor" | ||
239 | depends on I2C | ||
240 | select REGMAP_I2C | ||
241 | help | ||
242 | Say Y here if you want to build support for Maxim Integrated's | ||
243 | MAX44000 ambient and infrared proximity sensor device. | ||
244 | |||
245 | To compile this driver as a module, choose M here: | ||
246 | the module will be called max44000. | ||
247 | |||
237 | config OPT3001 | 248 | config OPT3001 |
238 | tristate "Texas Instruments OPT3001 Light Sensor" | 249 | tristate "Texas Instruments OPT3001 Light Sensor" |
239 | depends on I2C | 250 | depends on I2C |
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 8b246a604a92..6f2a3c62de27 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile | |||
@@ -21,6 +21,7 @@ obj-$(CONFIG_ISL29125) += isl29125.o | |||
21 | obj-$(CONFIG_JSA1212) += jsa1212.o | 21 | obj-$(CONFIG_JSA1212) += jsa1212.o |
22 | obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o | 22 | obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o |
23 | obj-$(CONFIG_LTR501) += ltr501.o | 23 | obj-$(CONFIG_LTR501) += ltr501.o |
24 | obj-$(CONFIG_MAX44000) += max44000.o | ||
24 | obj-$(CONFIG_OPT3001) += opt3001.o | 25 | obj-$(CONFIG_OPT3001) += opt3001.o |
25 | obj-$(CONFIG_PA12203001) += pa12203001.o | 26 | obj-$(CONFIG_PA12203001) += pa12203001.o |
26 | obj-$(CONFIG_RPR0521) += rpr0521.o | 27 | obj-$(CONFIG_RPR0521) += rpr0521.o |
diff --git a/drivers/iio/light/max44000.c b/drivers/iio/light/max44000.c new file mode 100644 index 000000000000..5ed79345bb42 --- /dev/null +++ b/drivers/iio/light/max44000.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * MAX44000 Ambient and Infrared Proximity Sensor | ||
3 | * | ||
4 | * Copyright (c) 2016, 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 | * Data sheet: https://datasheets.maximintegrated.com/en/ds/MAX44000.pdf | ||
11 | * | ||
12 | * 7-bit I2C slave address 0x4a | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/i2c.h> | ||
18 | #include <linux/regmap.h> | ||
19 | #include <linux/util_macros.h> | ||
20 | #include <linux/iio/iio.h> | ||
21 | #include <linux/iio/sysfs.h> | ||
22 | #include <linux/acpi.h> | ||
23 | |||
24 | #define MAX44000_DRV_NAME "max44000" | ||
25 | |||
26 | /* Registers in datasheet order */ | ||
27 | #define MAX44000_REG_STATUS 0x00 | ||
28 | #define MAX44000_REG_CFG_MAIN 0x01 | ||
29 | #define MAX44000_REG_CFG_RX 0x02 | ||
30 | #define MAX44000_REG_CFG_TX 0x03 | ||
31 | #define MAX44000_REG_ALS_DATA_HI 0x04 | ||
32 | #define MAX44000_REG_ALS_DATA_LO 0x05 | ||
33 | #define MAX44000_REG_PRX_DATA 0x16 | ||
34 | #define MAX44000_REG_ALS_UPTHR_HI 0x06 | ||
35 | #define MAX44000_REG_ALS_UPTHR_LO 0x07 | ||
36 | #define MAX44000_REG_ALS_LOTHR_HI 0x08 | ||
37 | #define MAX44000_REG_ALS_LOTHR_LO 0x09 | ||
38 | #define MAX44000_REG_PST 0x0a | ||
39 | #define MAX44000_REG_PRX_IND 0x0b | ||
40 | #define MAX44000_REG_PRX_THR 0x0c | ||
41 | #define MAX44000_REG_TRIM_GAIN_GREEN 0x0f | ||
42 | #define MAX44000_REG_TRIM_GAIN_IR 0x10 | ||
43 | |||
44 | /* REG_CFG bits */ | ||
45 | #define MAX44000_CFG_ALSINTE 0x01 | ||
46 | #define MAX44000_CFG_PRXINTE 0x02 | ||
47 | #define MAX44000_CFG_MASK 0x1c | ||
48 | #define MAX44000_CFG_MODE_SHUTDOWN 0x00 | ||
49 | #define MAX44000_CFG_MODE_ALS_GIR 0x04 | ||
50 | #define MAX44000_CFG_MODE_ALS_G 0x08 | ||
51 | #define MAX44000_CFG_MODE_ALS_IR 0x0c | ||
52 | #define MAX44000_CFG_MODE_ALS_PRX 0x10 | ||
53 | #define MAX44000_CFG_MODE_PRX 0x14 | ||
54 | #define MAX44000_CFG_TRIM 0x20 | ||
55 | |||
56 | /* | ||
57 | * Upper 4 bits are not documented but start as 1 on powerup | ||
58 | * Setting them to 0 causes proximity to misbehave so set them to 1 | ||
59 | */ | ||
60 | #define MAX44000_REG_CFG_RX_DEFAULT 0xf0 | ||
61 | |||
62 | #define MAX44000_ALSDATA_OVERFLOW 0x4000 | ||
63 | |||
64 | struct max44000_data { | ||
65 | struct mutex lock; | ||
66 | struct regmap *regmap; | ||
67 | }; | ||
68 | |||
69 | /* Default scale is set to the minimum of 0.03125 or 1 / (1 << 5) lux */ | ||
70 | #define MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2 5 | ||
71 | |||
72 | static const struct iio_chan_spec max44000_channels[] = { | ||
73 | { | ||
74 | .type = IIO_LIGHT, | ||
75 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), | ||
76 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), | ||
77 | }, | ||
78 | }; | ||
79 | |||
80 | static int max44000_read_alsval(struct max44000_data *data) | ||
81 | { | ||
82 | u16 regval; | ||
83 | int ret; | ||
84 | |||
85 | ret = regmap_bulk_read(data->regmap, MAX44000_REG_ALS_DATA_HI, | ||
86 | ®val, sizeof(regval)); | ||
87 | if (ret < 0) | ||
88 | return ret; | ||
89 | |||
90 | regval = be16_to_cpu(regval); | ||
91 | |||
92 | /* | ||
93 | * Overflow is explained on datasheet page 17. | ||
94 | * | ||
95 | * It's a warning that either the G or IR channel has become saturated | ||
96 | * and that the value in the register is likely incorrect. | ||
97 | * | ||
98 | * The recommendation is to change the scale (ALSPGA). | ||
99 | * The driver just returns the max representable value. | ||
100 | */ | ||
101 | if (regval & MAX44000_ALSDATA_OVERFLOW) | ||
102 | return 0x3FFF; | ||
103 | |||
104 | return regval; | ||
105 | } | ||
106 | |||
107 | static int max44000_read_raw(struct iio_dev *indio_dev, | ||
108 | struct iio_chan_spec const *chan, | ||
109 | int *val, int *val2, long mask) | ||
110 | { | ||
111 | struct max44000_data *data = iio_priv(indio_dev); | ||
112 | int ret; | ||
113 | |||
114 | switch (mask) { | ||
115 | case IIO_CHAN_INFO_RAW: | ||
116 | switch (chan->type) { | ||
117 | case IIO_LIGHT: | ||
118 | mutex_lock(&data->lock); | ||
119 | ret = max44000_read_alsval(data); | ||
120 | mutex_unlock(&data->lock); | ||
121 | if (ret < 0) | ||
122 | return ret; | ||
123 | *val = ret; | ||
124 | return IIO_VAL_INT; | ||
125 | |||
126 | default: | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | case IIO_CHAN_INFO_SCALE: | ||
131 | switch (chan->type) { | ||
132 | case IIO_LIGHT: | ||
133 | *val = 1; | ||
134 | *val2 = MAX44000_ALS_TO_LUX_DEFAULT_FRACTION_LOG2; | ||
135 | return IIO_VAL_FRACTIONAL_LOG2; | ||
136 | |||
137 | default: | ||
138 | return -EINVAL; | ||
139 | } | ||
140 | |||
141 | default: | ||
142 | return -EINVAL; | ||
143 | } | ||
144 | } | ||
145 | |||
146 | static const struct iio_info max44000_info = { | ||
147 | .driver_module = THIS_MODULE, | ||
148 | .read_raw = max44000_read_raw, | ||
149 | }; | ||
150 | |||
151 | static bool max44000_readable_reg(struct device *dev, unsigned int reg) | ||
152 | { | ||
153 | switch (reg) { | ||
154 | case MAX44000_REG_STATUS: | ||
155 | case MAX44000_REG_CFG_MAIN: | ||
156 | case MAX44000_REG_CFG_RX: | ||
157 | case MAX44000_REG_CFG_TX: | ||
158 | case MAX44000_REG_ALS_DATA_HI: | ||
159 | case MAX44000_REG_ALS_DATA_LO: | ||
160 | case MAX44000_REG_PRX_DATA: | ||
161 | case MAX44000_REG_ALS_UPTHR_HI: | ||
162 | case MAX44000_REG_ALS_UPTHR_LO: | ||
163 | case MAX44000_REG_ALS_LOTHR_HI: | ||
164 | case MAX44000_REG_ALS_LOTHR_LO: | ||
165 | case MAX44000_REG_PST: | ||
166 | case MAX44000_REG_PRX_IND: | ||
167 | case MAX44000_REG_PRX_THR: | ||
168 | case MAX44000_REG_TRIM_GAIN_GREEN: | ||
169 | case MAX44000_REG_TRIM_GAIN_IR: | ||
170 | return true; | ||
171 | default: | ||
172 | return false; | ||
173 | } | ||
174 | } | ||
175 | |||
176 | static bool max44000_writeable_reg(struct device *dev, unsigned int reg) | ||
177 | { | ||
178 | switch (reg) { | ||
179 | case MAX44000_REG_CFG_MAIN: | ||
180 | case MAX44000_REG_CFG_RX: | ||
181 | case MAX44000_REG_CFG_TX: | ||
182 | case MAX44000_REG_ALS_UPTHR_HI: | ||
183 | case MAX44000_REG_ALS_UPTHR_LO: | ||
184 | case MAX44000_REG_ALS_LOTHR_HI: | ||
185 | case MAX44000_REG_ALS_LOTHR_LO: | ||
186 | case MAX44000_REG_PST: | ||
187 | case MAX44000_REG_PRX_IND: | ||
188 | case MAX44000_REG_PRX_THR: | ||
189 | case MAX44000_REG_TRIM_GAIN_GREEN: | ||
190 | case MAX44000_REG_TRIM_GAIN_IR: | ||
191 | return true; | ||
192 | default: | ||
193 | return false; | ||
194 | } | ||
195 | } | ||
196 | |||
197 | static bool max44000_volatile_reg(struct device *dev, unsigned int reg) | ||
198 | { | ||
199 | switch (reg) { | ||
200 | case MAX44000_REG_STATUS: | ||
201 | case MAX44000_REG_ALS_DATA_HI: | ||
202 | case MAX44000_REG_ALS_DATA_LO: | ||
203 | case MAX44000_REG_PRX_DATA: | ||
204 | return true; | ||
205 | default: | ||
206 | return false; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | static bool max44000_precious_reg(struct device *dev, unsigned int reg) | ||
211 | { | ||
212 | return reg == MAX44000_REG_STATUS; | ||
213 | } | ||
214 | |||
215 | static const struct regmap_config max44000_regmap_config = { | ||
216 | .reg_bits = 8, | ||
217 | .val_bits = 8, | ||
218 | |||
219 | .max_register = MAX44000_REG_PRX_DATA, | ||
220 | .readable_reg = max44000_readable_reg, | ||
221 | .writeable_reg = max44000_writeable_reg, | ||
222 | .volatile_reg = max44000_volatile_reg, | ||
223 | .precious_reg = max44000_precious_reg, | ||
224 | |||
225 | .use_single_rw = 1, | ||
226 | .cache_type = REGCACHE_RBTREE, | ||
227 | }; | ||
228 | |||
229 | static int max44000_probe(struct i2c_client *client, | ||
230 | const struct i2c_device_id *id) | ||
231 | { | ||
232 | struct max44000_data *data; | ||
233 | struct iio_dev *indio_dev; | ||
234 | int ret, reg; | ||
235 | |||
236 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); | ||
237 | if (!indio_dev) | ||
238 | return -ENOMEM; | ||
239 | data = iio_priv(indio_dev); | ||
240 | data->regmap = devm_regmap_init_i2c(client, &max44000_regmap_config); | ||
241 | if (IS_ERR(data->regmap)) { | ||
242 | dev_err(&client->dev, "regmap_init failed!\n"); | ||
243 | return PTR_ERR(data->regmap); | ||
244 | } | ||
245 | |||
246 | i2c_set_clientdata(client, indio_dev); | ||
247 | mutex_init(&data->lock); | ||
248 | indio_dev->dev.parent = &client->dev; | ||
249 | indio_dev->info = &max44000_info; | ||
250 | indio_dev->name = MAX44000_DRV_NAME; | ||
251 | indio_dev->channels = max44000_channels; | ||
252 | indio_dev->num_channels = ARRAY_SIZE(max44000_channels); | ||
253 | |||
254 | /* | ||
255 | * The device doesn't have a reset function so we just clear some | ||
256 | * important bits at probe time to ensure sane operation. | ||
257 | * | ||
258 | * Since we don't support interrupts/events the threshold values are | ||
259 | * not important. We also don't touch trim values. | ||
260 | */ | ||
261 | |||
262 | /* Reset ALS scaling bits */ | ||
263 | ret = regmap_write(data->regmap, MAX44000_REG_CFG_RX, MAX44000_REG_CFG_RX_DEFAULT); | ||
264 | if (ret < 0) { | ||
265 | dev_err(&client->dev, "failed to write default CFG_RX: %d\n", ret); | ||
266 | return ret; | ||
267 | } | ||
268 | |||
269 | /* Reset CFG bits to ALS-only mode and no interrupts */ | ||
270 | reg = MAX44000_CFG_TRIM | MAX44000_CFG_MODE_ALS_GIR; | ||
271 | ret = regmap_write(data->regmap, MAX44000_REG_CFG_MAIN, reg); | ||
272 | if (ret < 0) { | ||
273 | dev_err(&client->dev, "failed to write init config: %d\n", ret); | ||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | /* Read status at least once to clear any stale interrupt bits. */ | ||
278 | ret = regmap_read(data->regmap, MAX44000_REG_STATUS, ®); | ||
279 | if (ret < 0) { | ||
280 | dev_err(&client->dev, "failed to read init status: %d\n", ret); | ||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | return iio_device_register(indio_dev); | ||
285 | } | ||
286 | |||
287 | static int max44000_remove(struct i2c_client *client) | ||
288 | { | ||
289 | struct iio_dev *indio_dev = i2c_get_clientdata(client); | ||
290 | |||
291 | iio_device_unregister(indio_dev); | ||
292 | |||
293 | return 0; | ||
294 | } | ||
295 | |||
296 | static const struct i2c_device_id max44000_id[] = { | ||
297 | {"max44000", 0}, | ||
298 | { } | ||
299 | }; | ||
300 | MODULE_DEVICE_TABLE(i2c, max44000_id); | ||
301 | |||
302 | #ifdef CONFIG_ACPI | ||
303 | static const struct acpi_device_id max44000_acpi_match[] = { | ||
304 | {"MAX44000", 0}, | ||
305 | { } | ||
306 | }; | ||
307 | MODULE_DEVICE_TABLE(acpi, max44000_acpi_match); | ||
308 | #endif | ||
309 | |||
310 | static struct i2c_driver max44000_driver = { | ||
311 | .driver = { | ||
312 | .name = MAX44000_DRV_NAME, | ||
313 | .acpi_match_table = ACPI_PTR(max44000_acpi_match), | ||
314 | }, | ||
315 | .probe = max44000_probe, | ||
316 | .remove = max44000_remove, | ||
317 | .id_table = max44000_id, | ||
318 | }; | ||
319 | |||
320 | module_i2c_driver(max44000_driver); | ||
321 | |||
322 | MODULE_AUTHOR("Crestez Dan Leonard <leonard.crestez@intel.com>"); | ||
323 | MODULE_DESCRIPTION("MAX44000 Ambient and Infrared Proximity Sensor"); | ||
324 | MODULE_LICENSE("GPL v2"); | ||