]>
Commit | Line | Data |
---|---|---|
971672c0 KT |
1 | /* |
2 | * Copyright (C) 2013 Capella Microsystems Inc. | |
3 | * Author: Kevin Tsai <ktsai@capellamicro.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify it | |
6 | * under the terms of the GNU General Public License version 2, as published | |
7 | * by the Free Software Foundation. | |
8 | */ | |
9 | ||
10 | #include <linux/delay.h> | |
11 | #include <linux/err.h> | |
12 | #include <linux/i2c.h> | |
13 | #include <linux/mutex.h> | |
14 | #include <linux/module.h> | |
15 | #include <linux/interrupt.h> | |
16 | #include <linux/regulator/consumer.h> | |
17 | #include <linux/iio/iio.h> | |
18 | #include <linux/iio/sysfs.h> | |
19 | #include <linux/iio/events.h> | |
20 | #include <linux/init.h> | |
21 | ||
22 | /* Registers Address */ | |
23 | #define CM32181_REG_ADDR_CMD 0x00 | |
24 | #define CM32181_REG_ADDR_ALS 0x04 | |
25 | #define CM32181_REG_ADDR_STATUS 0x06 | |
26 | #define CM32181_REG_ADDR_ID 0x07 | |
27 | ||
28 | /* Number of Configurable Registers */ | |
29 | #define CM32181_CONF_REG_NUM 0x01 | |
30 | ||
31 | /* CMD register */ | |
32 | #define CM32181_CMD_ALS_ENABLE 0x00 | |
33 | #define CM32181_CMD_ALS_DISABLE 0x01 | |
34 | #define CM32181_CMD_ALS_INT_EN 0x02 | |
35 | ||
36 | #define CM32181_CMD_ALS_IT_SHIFT 6 | |
37 | #define CM32181_CMD_ALS_IT_MASK (0x0F << CM32181_CMD_ALS_IT_SHIFT) | |
38 | #define CM32181_CMD_ALS_IT_DEFAULT (0x00 << CM32181_CMD_ALS_IT_SHIFT) | |
39 | ||
40 | #define CM32181_CMD_ALS_SM_SHIFT 11 | |
41 | #define CM32181_CMD_ALS_SM_MASK (0x03 << CM32181_CMD_ALS_SM_SHIFT) | |
42 | #define CM32181_CMD_ALS_SM_DEFAULT (0x01 << CM32181_CMD_ALS_SM_SHIFT) | |
43 | ||
44 | #define CM32181_MLUX_PER_BIT 5 /* ALS_SM=01 IT=800ms */ | |
45 | #define CM32181_MLUX_PER_BIT_BASE_IT 800000 /* Based on IT=800ms */ | |
46 | #define CM32181_CALIBSCALE_DEFAULT 1000 | |
47 | #define CM32181_CALIBSCALE_RESOLUTION 1000 | |
48 | #define MLUX_PER_LUX 1000 | |
49 | ||
50 | static const u8 cm32181_reg[CM32181_CONF_REG_NUM] = { | |
51 | CM32181_REG_ADDR_CMD, | |
52 | }; | |
53 | ||
54 | static const int als_it_bits[] = {12, 8, 0, 1, 2, 3}; | |
55 | static const int als_it_value[] = {25000, 50000, 100000, 200000, 400000, | |
56 | 800000}; | |
57 | ||
58 | struct cm32181_chip { | |
59 | struct i2c_client *client; | |
60 | struct mutex lock; | |
61 | u16 conf_regs[CM32181_CONF_REG_NUM]; | |
62 | int calibscale; | |
63 | }; | |
64 | ||
65 | /** | |
66 | * cm32181_reg_init() - Initialize CM32181 registers | |
67 | * @cm32181: pointer of struct cm32181. | |
68 | * | |
69 | * Initialize CM32181 ambient light sensor register to default values. | |
70 | * | |
71 | * Return: 0 for success; otherwise for error code. | |
72 | */ | |
73 | static int cm32181_reg_init(struct cm32181_chip *cm32181) | |
74 | { | |
75 | struct i2c_client *client = cm32181->client; | |
76 | int i; | |
77 | s32 ret; | |
78 | ||
79 | ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ID); | |
80 | if (ret < 0) | |
81 | return ret; | |
82 | ||
83 | /* check device ID */ | |
84 | if ((ret & 0xFF) != 0x81) | |
85 | return -ENODEV; | |
86 | ||
87 | /* Default Values */ | |
88 | cm32181->conf_regs[CM32181_REG_ADDR_CMD] = CM32181_CMD_ALS_ENABLE | | |
89 | CM32181_CMD_ALS_IT_DEFAULT | CM32181_CMD_ALS_SM_DEFAULT; | |
90 | cm32181->calibscale = CM32181_CALIBSCALE_DEFAULT; | |
91 | ||
92 | /* Initialize registers*/ | |
93 | for (i = 0; i < CM32181_CONF_REG_NUM; i++) { | |
94 | ret = i2c_smbus_write_word_data(client, cm32181_reg[i], | |
95 | cm32181->conf_regs[i]); | |
96 | if (ret < 0) | |
97 | return ret; | |
98 | } | |
99 | ||
100 | return 0; | |
101 | } | |
102 | ||
103 | /** | |
104 | * cm32181_read_als_it() - Get sensor integration time (ms) | |
105 | * @cm32181: pointer of struct cm32181 | |
1463a166 | 106 | * @val2: pointer of int to load the als_it value. |
971672c0 KT |
107 | * |
108 | * Report the current integartion time by millisecond. | |
109 | * | |
1463a166 | 110 | * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL. |
971672c0 | 111 | */ |
1463a166 | 112 | static int cm32181_read_als_it(struct cm32181_chip *cm32181, int *val2) |
971672c0 KT |
113 | { |
114 | u16 als_it; | |
115 | int i; | |
116 | ||
117 | als_it = cm32181->conf_regs[CM32181_REG_ADDR_CMD]; | |
118 | als_it &= CM32181_CMD_ALS_IT_MASK; | |
119 | als_it >>= CM32181_CMD_ALS_IT_SHIFT; | |
120 | for (i = 0; i < ARRAY_SIZE(als_it_bits); i++) { | |
121 | if (als_it == als_it_bits[i]) { | |
1463a166 BS |
122 | *val2 = als_it_value[i]; |
123 | return IIO_VAL_INT_PLUS_MICRO; | |
971672c0 KT |
124 | } |
125 | } | |
126 | ||
127 | return -EINVAL; | |
128 | } | |
129 | ||
130 | /** | |
131 | * cm32181_write_als_it() - Write sensor integration time | |
132 | * @cm32181: pointer of struct cm32181. | |
133 | * @val: integration time by millisecond. | |
134 | * | |
135 | * Convert integration time (ms) to sensor value. | |
136 | * | |
137 | * Return: i2c_smbus_write_word_data command return value. | |
138 | */ | |
139 | static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val) | |
140 | { | |
141 | struct i2c_client *client = cm32181->client; | |
142 | u16 als_it; | |
143 | int ret, i, n; | |
144 | ||
145 | n = ARRAY_SIZE(als_it_value); | |
146 | for (i = 0; i < n; i++) | |
147 | if (val <= als_it_value[i]) | |
148 | break; | |
149 | if (i >= n) | |
150 | i = n - 1; | |
151 | ||
152 | als_it = als_it_bits[i]; | |
153 | als_it <<= CM32181_CMD_ALS_IT_SHIFT; | |
154 | ||
155 | mutex_lock(&cm32181->lock); | |
156 | cm32181->conf_regs[CM32181_REG_ADDR_CMD] &= | |
157 | ~CM32181_CMD_ALS_IT_MASK; | |
158 | cm32181->conf_regs[CM32181_REG_ADDR_CMD] |= | |
159 | als_it; | |
160 | ret = i2c_smbus_write_word_data(client, CM32181_REG_ADDR_CMD, | |
161 | cm32181->conf_regs[CM32181_REG_ADDR_CMD]); | |
162 | mutex_unlock(&cm32181->lock); | |
163 | ||
164 | return ret; | |
165 | } | |
166 | ||
167 | /** | |
168 | * cm32181_get_lux() - report current lux value | |
169 | * @cm32181: pointer of struct cm32181. | |
170 | * | |
171 | * Convert sensor raw data to lux. It depends on integration | |
a86ea557 | 172 | * time and calibscale variable. |
971672c0 KT |
173 | * |
174 | * Return: Positive value is lux, otherwise is error code. | |
175 | */ | |
176 | static int cm32181_get_lux(struct cm32181_chip *cm32181) | |
177 | { | |
178 | struct i2c_client *client = cm32181->client; | |
179 | int ret; | |
180 | int als_it; | |
181 | unsigned long lux; | |
182 | ||
183 | ret = cm32181_read_als_it(cm32181, &als_it); | |
184 | if (ret < 0) | |
185 | return -EINVAL; | |
186 | ||
187 | lux = CM32181_MLUX_PER_BIT; | |
188 | lux *= CM32181_MLUX_PER_BIT_BASE_IT; | |
189 | lux /= als_it; | |
190 | ||
191 | ret = i2c_smbus_read_word_data(client, CM32181_REG_ADDR_ALS); | |
192 | if (ret < 0) | |
193 | return ret; | |
194 | ||
195 | lux *= ret; | |
196 | lux *= cm32181->calibscale; | |
197 | lux /= CM32181_CALIBSCALE_RESOLUTION; | |
198 | lux /= MLUX_PER_LUX; | |
199 | ||
200 | if (lux > 0xFFFF) | |
201 | lux = 0xFFFF; | |
202 | ||
203 | return lux; | |
204 | } | |
205 | ||
206 | static int cm32181_read_raw(struct iio_dev *indio_dev, | |
207 | struct iio_chan_spec const *chan, | |
208 | int *val, int *val2, long mask) | |
209 | { | |
210 | struct cm32181_chip *cm32181 = iio_priv(indio_dev); | |
211 | int ret; | |
212 | ||
213 | switch (mask) { | |
214 | case IIO_CHAN_INFO_PROCESSED: | |
215 | ret = cm32181_get_lux(cm32181); | |
216 | if (ret < 0) | |
217 | return ret; | |
218 | *val = ret; | |
219 | return IIO_VAL_INT; | |
220 | case IIO_CHAN_INFO_CALIBSCALE: | |
221 | *val = cm32181->calibscale; | |
222 | return IIO_VAL_INT; | |
223 | case IIO_CHAN_INFO_INT_TIME: | |
41c897f8 | 224 | *val = 0; |
1463a166 | 225 | ret = cm32181_read_als_it(cm32181, val2); |
971672c0 KT |
226 | return ret; |
227 | } | |
228 | ||
229 | return -EINVAL; | |
230 | } | |
231 | ||
232 | static int cm32181_write_raw(struct iio_dev *indio_dev, | |
233 | struct iio_chan_spec const *chan, | |
234 | int val, int val2, long mask) | |
235 | { | |
236 | struct cm32181_chip *cm32181 = iio_priv(indio_dev); | |
237 | int ret; | |
238 | ||
239 | switch (mask) { | |
240 | case IIO_CHAN_INFO_CALIBSCALE: | |
241 | cm32181->calibscale = val; | |
242 | return val; | |
243 | case IIO_CHAN_INFO_INT_TIME: | |
1463a166 | 244 | ret = cm32181_write_als_it(cm32181, val2); |
971672c0 KT |
245 | return ret; |
246 | } | |
247 | ||
248 | return -EINVAL; | |
249 | } | |
250 | ||
251 | /** | |
252 | * cm32181_get_it_available() - Get available ALS IT value | |
253 | * @dev: pointer of struct device. | |
254 | * @attr: pointer of struct device_attribute. | |
255 | * @buf: pointer of return string buffer. | |
256 | * | |
257 | * Display the available integration time values by millisecond. | |
258 | * | |
259 | * Return: string length. | |
260 | */ | |
261 | static ssize_t cm32181_get_it_available(struct device *dev, | |
262 | struct device_attribute *attr, char *buf) | |
263 | { | |
264 | int i, n, len; | |
265 | ||
266 | n = ARRAY_SIZE(als_it_value); | |
267 | for (i = 0, len = 0; i < n; i++) | |
1463a166 | 268 | len += sprintf(buf + len, "0.%06u ", als_it_value[i]); |
971672c0 KT |
269 | return len + sprintf(buf + len, "\n"); |
270 | } | |
271 | ||
272 | static const struct iio_chan_spec cm32181_channels[] = { | |
273 | { | |
274 | .type = IIO_LIGHT, | |
275 | .info_mask_separate = | |
276 | BIT(IIO_CHAN_INFO_PROCESSED) | | |
277 | BIT(IIO_CHAN_INFO_CALIBSCALE) | | |
278 | BIT(IIO_CHAN_INFO_INT_TIME), | |
279 | } | |
280 | }; | |
281 | ||
282 | static IIO_DEVICE_ATTR(in_illuminance_integration_time_available, | |
283 | S_IRUGO, cm32181_get_it_available, NULL, 0); | |
284 | ||
285 | static struct attribute *cm32181_attributes[] = { | |
286 | &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr, | |
287 | NULL, | |
288 | }; | |
289 | ||
290 | static const struct attribute_group cm32181_attribute_group = { | |
291 | .attrs = cm32181_attributes | |
292 | }; | |
293 | ||
294 | static const struct iio_info cm32181_info = { | |
971672c0 KT |
295 | .read_raw = &cm32181_read_raw, |
296 | .write_raw = &cm32181_write_raw, | |
297 | .attrs = &cm32181_attribute_group, | |
298 | }; | |
299 | ||
300 | static int cm32181_probe(struct i2c_client *client, | |
301 | const struct i2c_device_id *id) | |
302 | { | |
303 | struct cm32181_chip *cm32181; | |
304 | struct iio_dev *indio_dev; | |
305 | int ret; | |
306 | ||
307 | indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*cm32181)); | |
308 | if (!indio_dev) { | |
309 | dev_err(&client->dev, "devm_iio_device_alloc failed\n"); | |
310 | return -ENOMEM; | |
311 | } | |
312 | ||
313 | cm32181 = iio_priv(indio_dev); | |
314 | i2c_set_clientdata(client, indio_dev); | |
315 | cm32181->client = client; | |
316 | ||
317 | mutex_init(&cm32181->lock); | |
318 | indio_dev->dev.parent = &client->dev; | |
319 | indio_dev->channels = cm32181_channels; | |
320 | indio_dev->num_channels = ARRAY_SIZE(cm32181_channels); | |
321 | indio_dev->info = &cm32181_info; | |
322 | indio_dev->name = id->name; | |
323 | indio_dev->modes = INDIO_DIRECT_MODE; | |
324 | ||
325 | ret = cm32181_reg_init(cm32181); | |
326 | if (ret) { | |
327 | dev_err(&client->dev, | |
328 | "%s: register init failed\n", | |
329 | __func__); | |
330 | return ret; | |
331 | } | |
332 | ||
b9785535 | 333 | ret = devm_iio_device_register(&client->dev, indio_dev); |
971672c0 KT |
334 | if (ret) { |
335 | dev_err(&client->dev, | |
336 | "%s: regist device failed\n", | |
337 | __func__); | |
338 | return ret; | |
339 | } | |
340 | ||
341 | return 0; | |
342 | } | |
343 | ||
971672c0 KT |
344 | static const struct i2c_device_id cm32181_id[] = { |
345 | { "cm32181", 0 }, | |
346 | { } | |
347 | }; | |
348 | ||
349 | MODULE_DEVICE_TABLE(i2c, cm32181_id); | |
350 | ||
351 | static const struct of_device_id cm32181_of_match[] = { | |
352 | { .compatible = "capella,cm32181" }, | |
353 | { } | |
354 | }; | |
119c4fce | 355 | MODULE_DEVICE_TABLE(of, cm32181_of_match); |
971672c0 KT |
356 | |
357 | static struct i2c_driver cm32181_driver = { | |
358 | .driver = { | |
359 | .name = "cm32181", | |
360 | .of_match_table = of_match_ptr(cm32181_of_match), | |
971672c0 KT |
361 | }, |
362 | .id_table = cm32181_id, | |
363 | .probe = cm32181_probe, | |
971672c0 KT |
364 | }; |
365 | ||
366 | module_i2c_driver(cm32181_driver); | |
367 | ||
368 | MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>"); | |
369 | MODULE_DESCRIPTION("CM32181 ambient light sensor driver"); | |
370 | MODULE_LICENSE("GPL"); |