1 /* drivers/input/sensors/lsensor/cm3218.c
2 *
3 * Copyright (C) 2012-2016 ROCKCHIP.
4 * Author: luowei <lw@rock-chips.com>
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 */
16 #include <linux/interrupt.h>
17 #include <linux/i2c.h>
18 #include <linux/slab.h>
19 #include <linux/irq.h>
20 #include <linux/miscdevice.h>
21 #include <linux/gpio.h>
22 #include <linux/uaccess.h>
23 #include <linux/atomic.h>
24 #include <linux/delay.h>
25 #include <linux/input.h>
26 #include <linux/workqueue.h>
27 #include <linux/freezer.h>
28 #include <linux/of_gpio.h>
29 #ifdef CONFIG_HAS_EARLYSUSPEND
30 #include <linux/earlysuspend.h>
31 #endif
32 #include <linux/sensor-dev.h>
33
34 #define LENSFACTOR 1000
35
36 /* SMBus ARA Address */
37 #define CM3218_ADDR_ARA 0x0C
38
39 /* CM3218 CMD Registers */
40 #define CM3218_REG_ADDR_CMD 0x00
41 #define CM3218_CMD_ALS_SD 0x0001
42 #define CM3218_CMD_ALS_INT_EN 0x0002
43 #define CM3218_CMD_ALS_INT_DISABLE 0x0000
44
45 #define CM3218_CMD_ALS_IT_SHIFT 6
46 #define CM3218_CMD_ALS_IT_MASK (3 << CM3218_CMD_ALS_IT_SHIFT)
47 #define CM3218_CMD_ALS_IT_05T (0 << CM3218_CMD_ALS_IT_SHIFT)
48 #define CM3218_CMD_ALS_IT_1T (1 << CM3218_CMD_ALS_IT_SHIFT)
49 #define CM3218_CMD_ALS_IT_2T (2 << CM3218_CMD_ALS_IT_SHIFT)
50 #define CM3218_CMD_ALS_IT_4T (3 << CM3218_CMD_ALS_IT_SHIFT)
51 #define CM3218_DEFAULT_CMD (CM3218_CMD_ALS_IT_1T)
52
53 #define CM3218_ALS_PERS 0x0020
54
55 #define CM3218_REG_ADDR_ALS_WH 0x01
56 #define CM3218_DEFAULT_ALS_WH 0x000C
57
58 #define CM3218_REG_ADDR_ALS_WL 0x02
59 #define CM3218_DEFAULT_ALS_WL 0x000A
60
61 #define CM3218_REG_ADDR_ALS 0x04
62
63 #define CM3218_REG_ADDR_STATUS 0x06
64
65 #define CM3218_REG_ADDR_ID 0x07
66
67 /* Software parameters */
68 #define CM3218_MAX_CACHE_REGS (0x03 + 1) /* Reg.0x00 to 0x03 */
69
70 static int als_code = 20;
71 static int change_sensitivity = 50;
72 static int if_sensor_init;
73
cm3218_read_ara(struct i2c_client * client)74 static int cm3218_read_ara(struct i2c_client *client)
75 {
76 int status;
77 unsigned short addr;
78
79 addr = client->addr;
80 client->addr = CM3218_ADDR_ARA;
81 status = i2c_smbus_read_byte(client);
82 client->addr = addr;
83
84 if (status < 0)
85 return -ENODEV;
86
87 return 0;
88 }
89
cm3218_write(struct i2c_client * client,u8 reg,u16 value)90 static int cm3218_write(struct i2c_client *client, u8 reg, u16 value)
91 {
92 u16 regval;
93 int ret;
94
95 dev_dbg(&client->dev,
96 "Write to device register 0x%02X with 0x%04X\n", reg, value);
97 regval = cpu_to_le16(value);
98 ret = i2c_smbus_write_word_data(client, reg, regval);
99 if (ret)
100 dev_err(&client->dev, "Write to device fails: 0x%x\n", ret);
101
102 return ret;
103 }
104
cm3218_read(struct i2c_client * client,u8 reg)105 static int cm3218_read(struct i2c_client *client, u8 reg)
106 {
107 int regval;
108 int status;
109
110 status = i2c_smbus_read_word_data(client, reg);
111 if (status < 0) {
112 dev_err(&client->dev,
113 "Error in reading Reg.0x%02X\n", reg);
114 return status;
115 }
116 regval = le16_to_cpu(status);
117
118 dev_dbg(&client->dev,
119 "Read from device register 0x%02X = 0x%04X\n",
120 reg, regval);
121
122 return regval;
123 }
124
clear_interrupt(struct i2c_client * client)125 static int clear_interrupt(struct i2c_client *client)
126 {
127 int status = 0;
128
129 status = cm3218_read(client, CM3218_REG_ADDR_STATUS);
130 if (status < 0) {
131 dev_err(&client->dev, "CM3218: clean interrupt flag fail\n");
132 return status;
133 }
134
135 return status;
136 }
137
enable_interrupt(struct i2c_client * client)138 static int enable_interrupt(struct i2c_client *client)
139 {
140 int status = 0;
141
142 status = cm3218_write(
143 client,
144 CM3218_REG_ADDR_CMD,
145 CM3218_DEFAULT_CMD |
146 CM3218_CMD_ALS_INT_EN |
147 CM3218_ALS_PERS);
148
149 if (status < 0) {
150 dev_err(&client->dev, "CM3128 enable interrut fails\n");
151 return status;
152 }
153
154 return status;
155 }
156
disable_interrupt(struct i2c_client * client)157 static int disable_interrupt(struct i2c_client *client)
158 {
159 int status = 0;
160
161 status = cm3218_write(
162 client,
163 CM3218_REG_ADDR_CMD,
164 CM3218_DEFAULT_CMD |
165 CM3218_CMD_ALS_INT_DISABLE);
166
167 if (status < 0) {
168 dev_err(&client->dev, "CM3218: disable interrput fail\n");
169 return status;
170 }
171
172 return status;
173 }
174
set_als_int_threshold(struct i2c_client * client)175 static int set_als_int_threshold(struct i2c_client *client)
176 {
177 int threshold_high, threshold_low;
178 int status = 0;
179
180 /* Set ALS high threshold */
181 threshold_high = als_code * (100 + change_sensitivity) / 100;
182 if (threshold_high > 65535)
183 threshold_high = 65535;
184 status = cm3218_write(client, CM3218_REG_ADDR_ALS_WH, threshold_high);
185 if (status < 0) {
186 dev_err(&client->dev, "Init CM3218 CMD fails, set als wh error\n");
187 return status;
188 }
189
190 /* Set ALS low threshold */
191 threshold_low = als_code * (100 - change_sensitivity) / 100;
192 status = cm3218_write(client, CM3218_REG_ADDR_ALS_WL, threshold_low);
193 if (status < 0) {
194 dev_err(&client->dev, "Init CM3218 CMD fails, set als wh error\n");
195 return status;
196 }
197
198 return status;
199 }
200
201 /****************operate according to sensor chip:start************/
202
sensor_active(struct i2c_client * client,int enable,int rate)203 static int sensor_active(struct i2c_client *client, int enable, int rate)
204 {
205 struct sensor_private_data *sensor =
206 (struct sensor_private_data *)i2c_get_clientdata(client);
207 int result = 0;
208 int status = 0;
209
210 if (if_sensor_init)
211 return 0;
212
213 sensor->client->addr = sensor->ops->ctrl_reg;
214 sensor->ops->ctrl_data = cm3218_read(client, sensor->client->addr);
215
216 /* register setting according to chip datasheet */
217 if (!enable) {
218 status = CM3218_CMD_ALS_SD; /* cm3218 */
219 sensor->ops->ctrl_data |= status;
220 } else {
221 status = ~CM3218_CMD_ALS_SD; /* cm3218 */
222 sensor->ops->ctrl_data &= status;
223 }
224
225 DBG("%s:reg=0x%x, reg_ctrl=0x%x, enable=%d\n",
226 __func__,
227 sensor->ops->ctrl_reg,
228 sensor->ops->ctrl_data,
229 enable);
230
231 result = cm3218_write(
232 client,
233 sensor->client->addr,
234 sensor->ops->ctrl_data);
235
236 if (result)
237 dev_err(&client->dev, "%s:fail to active sensor\n", __func__);
238
239 return result;
240 }
241
sensor_init(struct i2c_client * client)242 static int sensor_init(struct i2c_client *client)
243 {
244 int status, i;
245 struct sensor_private_data *sensor =
246 (struct sensor_private_data *)i2c_get_clientdata(client);
247
248 if (if_sensor_init)
249 return 0;
250
251 for (i = 0; i < 5; i++) {
252 status = cm3218_write(
253 client, CM3218_REG_ADDR_CMD,
254 CM3218_CMD_ALS_SD);
255
256 if (status >= 0)
257 break;
258 cm3218_read_ara(client);
259 }
260
261 status = cm3218_write(client, CM3218_REG_ADDR_CMD, CM3218_DEFAULT_CMD);
262 if (status < 0) {
263 dev_err(&client->dev, "Init CM3218 CMD fails\n");
264 return status;
265 }
266
267 if (sensor->pdata->irq_enable) {
268 set_als_int_threshold(client);
269
270 enable_interrupt(client);
271 }
272
273 if_sensor_init = 1;
274 msleep(250);
275
276 return status;
277 }
278
light_report_value(struct input_dev * input,int data)279 static int light_report_value(struct input_dev *input, int data)
280 {
281 unsigned char index = 0;
282
283 if (data <= 700) {
284 index = 0;
285 } else if (data <= 1400) {
286 index = 1;
287 } else if (data <= 2800) {
288 index = 2;
289 } else if (data <= 5600) {
290 index = 3;
291 } else if (data <= 11200) {
292 index = 4;
293 } else if (data <= 22400) {
294 index = 5;
295 } else if (data <= 44800) {
296 index = 6;
297 } else {
298 index = 7;
299 }
300
301 input_report_abs(input, ABS_MISC, index);
302 input_sync(input);
303
304 return index;
305 }
306
cm3218_read_lux(struct i2c_client * client,int * lux)307 static int cm3218_read_lux(struct i2c_client *client, int *lux)
308 {
309 int lux_data;
310
311 lux_data = cm3218_read(client, CM3218_REG_ADDR_ALS);
312 if (lux_data < 0) {
313 dev_err(&client->dev, "Error in reading Lux DATA\n");
314 return lux_data;
315 }
316
317 dev_vdbg(&client->dev, "lux = %u\n", lux_data);
318
319 if (lux_data < 0)
320 return lux_data;
321
322 *lux = lux_data * LENSFACTOR;
323 *lux /= 1000;
324 return 0;
325 }
326
sensor_report_value(struct i2c_client * client)327 static int sensor_report_value(struct i2c_client *client)
328 {
329 struct sensor_private_data *sensor =
330 (struct sensor_private_data *)i2c_get_clientdata(client);
331 int result = 0;
332 int index = 0;
333
334 /* clean interrupt flag and disable it during reading data */
335 if (sensor->pdata->irq_enable) {
336 clear_interrupt(client);
337 disable_interrupt(client);
338 }
339
340 cm3218_read_lux(client, &result);
341 als_code = result;
342 index = light_report_value(sensor->input_dev, 200 * result);
343
344 /* enable interrupt after read data */
345 if (sensor->pdata->irq_enable) {
346 set_als_int_threshold(client);
347 enable_interrupt(client);
348 }
349
350 return 0;
351 }
352
353 static struct sensor_operate light_cm3218_ops = {
354 .name = "cm3218",
355 /* sensor type and it should be correct */
356 .type = SENSOR_TYPE_LIGHT,
357 /* i2c id number */
358 .id_i2c = LIGHT_ID_CM3218,
359 /* read data */
360 .read_reg = CM3218_REG_ADDR_ALS,
361 .read_len = 2, /* data length */
362 /* read device id from this register */
363 .id_reg = SENSOR_UNKNOW_DATA,
364 /* device id */
365 .id_data = SENSOR_UNKNOW_DATA,
366 .precision = 16, /* 8 bits */
367 /* enable or disable */
368 .ctrl_reg = CM3218_REG_ADDR_CMD,
369 /* intterupt status register */
370 .int_status_reg = CM3218_REG_ADDR_STATUS,
371 /* range */
372 .range = {0, 65535},
373 /* brightness */
374 .brightness = {10, 255},
375 .trig = SENSOR_UNKNOW_DATA,
376 .active = sensor_active,
377 .init = sensor_init,
378 .report = sensor_report_value,
379 };
380
381 /****************operate according to sensor chip:end************/
light_cm3218_probe(struct i2c_client * client,const struct i2c_device_id * devid)382 static int light_cm3218_probe(struct i2c_client *client,
383 const struct i2c_device_id *devid)
384 {
385 return sensor_register_device(client, NULL, devid, &light_cm3218_ops);
386 }
387
light_cm3218_remove(struct i2c_client * client)388 static int light_cm3218_remove(struct i2c_client *client)
389 {
390 return sensor_unregister_device(client, NULL, &light_cm3218_ops);
391 }
392
393 static const struct i2c_device_id light_cm3218_id[] = {
394 {"light_cm3218", LIGHT_ID_CM3218},
395 {}
396 };
397
398 static struct i2c_driver light_cm3218_driver = {
399 .probe = light_cm3218_probe,
400 .remove = light_cm3218_remove,
401 .shutdown = sensor_shutdown,
402 .id_table = light_cm3218_id,
403 .driver = {
404 .name = "light_cm3218",
405 #ifdef CONFIG_PM
406 .pm = &sensor_pm_ops,
407 #endif
408 },
409 };
410
411 module_i2c_driver(light_cm3218_driver);
412
413 MODULE_AUTHOR("luowei <lw@rock-chips.com>");
414 MODULE_DESCRIPTION("cm3218 light driver");
415 MODULE_LICENSE("GPL");
416