aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCrestez Dan Leonard <leonard.crestez@intel.com>2016-04-18 10:31:53 -0400
committerJonathan Cameron <jic23@kernel.org>2016-04-24 05:06:55 -0400
commitb9567e6664643eb99367fb88d14fdba863b1688a (patch)
treef478f8c9e57bb6f60857a3595a841e3110285eba
parent0d96d5ead3f7f1303a6a445051f29bba7c7f4e47 (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/Kconfig11
-rw-r--r--drivers/iio/light/Makefile1
-rw-r--r--drivers/iio/light/max44000.c324
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
237config 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
237config OPT3001 248config 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
21obj-$(CONFIG_JSA1212) += jsa1212.o 21obj-$(CONFIG_JSA1212) += jsa1212.o
22obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o 22obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
23obj-$(CONFIG_LTR501) += ltr501.o 23obj-$(CONFIG_LTR501) += ltr501.o
24obj-$(CONFIG_MAX44000) += max44000.o
24obj-$(CONFIG_OPT3001) += opt3001.o 25obj-$(CONFIG_OPT3001) += opt3001.o
25obj-$(CONFIG_PA12203001) += pa12203001.o 26obj-$(CONFIG_PA12203001) += pa12203001.o
26obj-$(CONFIG_RPR0521) += rpr0521.o 27obj-$(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
64struct 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
72static 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
80static 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 &regval, 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
107static 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
146static const struct iio_info max44000_info = {
147 .driver_module = THIS_MODULE,
148 .read_raw = max44000_read_raw,
149};
150
151static 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
176static 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
197static 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
210static bool max44000_precious_reg(struct device *dev, unsigned int reg)
211{
212 return reg == MAX44000_REG_STATUS;
213}
214
215static 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
229static 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, &reg);
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
287static 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
296static const struct i2c_device_id max44000_id[] = {
297 {"max44000", 0},
298 { }
299};
300MODULE_DEVICE_TABLE(i2c, max44000_id);
301
302#ifdef CONFIG_ACPI
303static const struct acpi_device_id max44000_acpi_match[] = {
304 {"MAX44000", 0},
305 { }
306};
307MODULE_DEVICE_TABLE(acpi, max44000_acpi_match);
308#endif
309
310static 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
320module_i2c_driver(max44000_driver);
321
322MODULE_AUTHOR("Crestez Dan Leonard <leonard.crestez@intel.com>");
323MODULE_DESCRIPTION("MAX44000 Ambient and Infrared Proximity Sensor");
324MODULE_LICENSE("GPL v2");