From c7cd7bb82d51e283c04eca2947e9f06aaebdd878 Mon Sep 17 00:00:00 2001 From: "jerry.zhang" Date: Wed, 17 Aug 2016 16:19:57 +0800 Subject: [PATCH] input: make light sensor cm32181 works on rk3399 tablet product Change-Id: I6a3e93ea5480ab66f2b67a826a88ac7e7f1416c8 Signed-off-by: jerry.zhang --- drivers/input/sensors/lsensor/cm3218.c | 306 ++++++++++++++++--------- 1 file changed, 197 insertions(+), 109 deletions(-) diff --git a/drivers/input/sensors/lsensor/cm3218.c b/drivers/input/sensors/lsensor/cm3218.c index b6201d6b8a95..39a29ec88d0a 100644 --- a/drivers/input/sensors/lsensor/cm3218.c +++ b/drivers/input/sensors/lsensor/cm3218.c @@ -1,6 +1,6 @@ -/* drivers/input/sensors/access/kxtik.c +/* drivers/input/sensors/lsensor/cm3218.c * - * Copyright (C) 2012-2015 ROCKCHIP. + * Copyright (C) 2012-2016 ROCKCHIP. * Author: luowei * * This software is licensed under the terms of the GNU General Public @@ -19,13 +19,13 @@ #include #include #include -#include -#include +#include +#include #include #include #include #include -#include +#include #ifdef CONFIG_HAS_EARLYSUSPEND #include #endif @@ -40,6 +40,8 @@ #define CM3218_REG_ADDR_CMD 0x00 #define CM3218_CMD_ALS_SD 0x0001 #define CM3218_CMD_ALS_INT_EN 0x0002 +#define CM3218_CMD_ALS_INT_DISABLE 0x0000 + #define CM3218_CMD_ALS_IT_SHIFT 6 #define CM3218_CMD_ALS_IT_MASK (3 << CM3218_CMD_ALS_IT_SHIFT) #define CM3218_CMD_ALS_IT_05T (0 << CM3218_CMD_ALS_IT_SHIFT) @@ -48,11 +50,13 @@ #define CM3218_CMD_ALS_IT_4T (3 << CM3218_CMD_ALS_IT_SHIFT) #define CM3218_DEFAULT_CMD (CM3218_CMD_ALS_IT_1T) +#define CM3218_ALS_PERS 0x0020 + #define CM3218_REG_ADDR_ALS_WH 0x01 -#define CM3218_DEFAULT_ALS_WH 0xFFFF +#define CM3218_DEFAULT_ALS_WH 0x000C #define CM3218_REG_ADDR_ALS_WL 0x02 -#define CM3218_DEFAULT_ALS_WL 0x0000 +#define CM3218_DEFAULT_ALS_WL 0x000A #define CM3218_REG_ADDR_ALS 0x04 @@ -61,8 +65,11 @@ #define CM3218_REG_ADDR_ID 0x07 /* Software parameters */ -#define CM3218_MAX_CACHE_REGS (0x03+1) /* Reg.0x00 to 0x03 */ +#define CM3218_MAX_CACHE_REGS (0x03 + 1) /* Reg.0x00 to 0x03 */ +static int als_code = 20; +static int change_sensitivity = 50; +static int if_sensor_init; static int cm3218_read_ara(struct i2c_client *client) { @@ -89,11 +96,8 @@ static int cm3218_write(struct i2c_client *client, u8 reg, u16 value) "Write to device register 0x%02X with 0x%04X\n", reg, value); regval = cpu_to_le16(value); ret = i2c_smbus_write_word_data(client, reg, regval); - if (ret) { + if (ret) dev_err(&client->dev, "Write to device fails: 0x%x\n", ret); - } else { - - } return ret; } @@ -102,7 +106,7 @@ static int cm3218_read(struct i2c_client *client, u8 reg) { int regval; int status; - + status = i2c_smbus_read_word_data(client, reg); if (status < 0) { dev_err(&client->dev, @@ -118,49 +122,137 @@ static int cm3218_read(struct i2c_client *client, u8 reg) return regval; } +static int clear_interrupt(struct i2c_client *client) +{ + int status = 0; + + status = cm3218_read(client, CM3218_REG_ADDR_STATUS); + if (status < 0) { + dev_err(&client->dev, "CM3218: clean interrupt flag fail\n"); + return status; + } + + return status; +} + +static int enable_interrupt(struct i2c_client *client) +{ + int status = 0; + + status = cm3218_write( + client, + CM3218_REG_ADDR_CMD, + CM3218_DEFAULT_CMD | + CM3218_CMD_ALS_INT_EN | + CM3218_ALS_PERS); + + if (status < 0) { + dev_err(&client->dev, "CM3128 enable interrut fails\n"); + return status; + } + + return status; +} + +static int disable_interrupt(struct i2c_client *client) +{ + int status = 0; + + status = cm3218_write( + client, + CM3218_REG_ADDR_CMD, + CM3218_DEFAULT_CMD | + CM3218_CMD_ALS_INT_DISABLE); + + if (status < 0) { + dev_err(&client->dev, "CM3218: disable interrput fail\n"); + return status; + } + + return status; +} + +static int set_als_int_threshold(struct i2c_client *client) +{ + int threshold_high, threshold_low; + int status = 0; + + /* Set ALS high threshold */ + threshold_high = als_code * (100 + change_sensitivity) / 100; + if (threshold_high > 65535) + threshold_high = 65535; + status = cm3218_write(client, CM3218_REG_ADDR_ALS_WH, threshold_high); + if (status < 0) { + dev_err(&client->dev, "Init CM3218 CMD fails, set als wh error\n"); + return status; + } + + /* Set ALS low threshold */ + threshold_low = als_code * (100 - change_sensitivity) / 100; + status = cm3218_write(client, CM3218_REG_ADDR_ALS_WL, threshold_low); + if (status < 0) { + dev_err(&client->dev, "Init CM3218 CMD fails, set als wh error\n"); + return status; + } + + return status; +} + /****************operate according to sensor chip:start************/ static int sensor_active(struct i2c_client *client, int enable, int rate) { struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); + (struct sensor_private_data *)i2c_get_clientdata(client); int result = 0; int status = 0; - - sensor->client->addr = sensor->ops->ctrl_reg; - sensor->ops->ctrl_data = cm3218_read(client,sensor->client->addr); - - //register setting according to chip datasheet - if(!enable) - { - status = CM3218_CMD_ALS_SD; //cm3218 - sensor->ops->ctrl_data |= status; - } - else - { - status = ~CM3218_CMD_ALS_SD; //cm3218 + + if (if_sensor_init) + return 0; + + sensor->client->addr = sensor->ops->ctrl_reg; + sensor->ops->ctrl_data = cm3218_read(client, sensor->client->addr); + + /* register setting according to chip datasheet */ + if (!enable) { + status = CM3218_CMD_ALS_SD; /* cm3218 */ + sensor->ops->ctrl_data |= status; + } else { + status = ~CM3218_CMD_ALS_SD; /* cm3218 */ sensor->ops->ctrl_data &= status; } - DBG("%s:reg=0x%x,reg_ctrl=0x%x,enable=%d\n",__func__,sensor->ops->ctrl_reg, sensor->ops->ctrl_data, enable); - result = cm3218_write(client,sensor->client->addr, sensor->ops->ctrl_data); - if(result) - printk("%s:fail to active sensor\n",__func__); - - return result; + DBG("%s:reg=0x%x, reg_ctrl=0x%x, enable=%d\n", + __func__, + sensor->ops->ctrl_reg, + sensor->ops->ctrl_data, + enable); -} + result = cm3218_write( + client, + sensor->client->addr, + sensor->ops->ctrl_data); + + if (result) + dev_err(&client->dev, "%s:fail to active sensor\n", __func__); + return result; +} static int sensor_init(struct i2c_client *client) -{ +{ int status, i; struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); + (struct sensor_private_data *)i2c_get_clientdata(client); + + if (if_sensor_init) + return 0; for (i = 0; i < 5; i++) { - status = cm3218_write(client, CM3218_REG_ADDR_CMD, - CM3218_CMD_ALS_SD); + status = cm3218_write( + client, CM3218_REG_ADDR_CMD, + CM3218_CMD_ALS_SD); + if (status >= 0) break; cm3218_read_ara(client); @@ -172,52 +264,40 @@ static int sensor_init(struct i2c_client *client) return status; } - if(sensor->pdata->irq_enable) - { - status = cm3218_write(client, CM3218_REG_ADDR_CMD, CM3218_DEFAULT_CMD | CM3218_CMD_ALS_INT_EN); - if (status < 0) { - dev_err(&client->dev, "Init CM3218 CMD fails\n"); - return status; - } + if (sensor->pdata->irq_enable) { + set_als_int_threshold(client); + + enable_interrupt(client); } - /* Clean interrupt status */ - cm3218_read(client, CM3218_REG_ADDR_STATUS); - + if_sensor_init = 1; + msleep(250); + return status; } - static int light_report_value(struct input_dev *input, int data) { unsigned char index = 0; - - if(data <= 700){ - index = 0;goto report; - } - else if(data <= 1400){ - index = 1;goto report; - } - else if(data <= 2800){ - index = 2;goto report; - } - else if(data <= 5600){ - index = 3;goto report; - } - else if(data <= 11200){ - index = 4;goto report; - } - else if(data <= 22400){ - index = 5;goto report; - } - else if(data <= 44800){ - index = 6;goto report; - } - else{ - index = 7;goto report; + + if (data <= 700) { + index = 0; + } else if (data <= 1400) { + index = 1; + } else if (data <= 2800) { + index = 2; + } else if (data <= 5600) { + index = 3; + } else if (data <= 11200) { + index = 4; + } else if (data <= 22400) { + index = 5; + } else if (data <= 44800) { + index = 6; + } else { + index = 7; } -report: input_report_abs(input, ABS_MISC, index); input_sync(input); @@ -247,63 +327,73 @@ static int cm3218_read_lux(struct i2c_client *client, int *lux) static int sensor_report_value(struct i2c_client *client) { struct sensor_private_data *sensor = - (struct sensor_private_data *) i2c_get_clientdata(client); + (struct sensor_private_data *)i2c_get_clientdata(client); int result = 0; int index = 0; - cm3218_read_lux(client,&result); - - index = light_report_value(sensor->input_dev, result); - DBG("%s:%s result=0x%x,index=%d\n",__func__,sensor->ops->name, result,index); - - if((sensor->pdata->irq_enable)&& (sensor->ops->int_status_reg >= 0)) //read sensor intterupt status register - { - - result= sensor_read_reg(client, sensor->ops->int_status_reg); - if(result) - { - printk("%s:fail to clear sensor int status,ret=0x%x\n",__func__,result); - } + /* clean interrupt flag and disable it during reading data */ + if (sensor->pdata->irq_enable) { + clear_interrupt(client); + disable_interrupt(client); } - - return result; -} + cm3218_read_lux(client, &result); + als_code = result; + index = light_report_value(sensor->input_dev, 200 * result); + + /* enable interrupt after read data */ + if (sensor->pdata->irq_enable) { + set_als_int_threshold(client); + enable_interrupt(client); + } + + return 0; +} struct sensor_operate light_cm3218_ops = { .name = "cm3218", - .type = SENSOR_TYPE_LIGHT, //sensor type and it should be correct - .id_i2c = LIGHT_ID_CM3218, //i2c id number - .read_reg = CM3218_REG_ADDR_ALS, //read data - .read_len = 2, //data length - .id_reg = SENSOR_UNKNOW_DATA, //read device id from this register - .id_data = SENSOR_UNKNOW_DATA, //device id - .precision = 16, //8 bits - .ctrl_reg = CM3218_REG_ADDR_CMD, //enable or disable - .int_status_reg = CM3218_REG_ADDR_STATUS, //intterupt status register - .range = {0,65535}, //range - .brightness ={10,255}, // brightness - .trig = SENSOR_UNKNOW_DATA, - .active = sensor_active, + /* sensor type and it should be correct */ + .type = SENSOR_TYPE_LIGHT, + /* i2c id number */ + .id_i2c = LIGHT_ID_CM3218, + /* read data */ + .read_reg = CM3218_REG_ADDR_ALS, + .read_len = 2, /* data length */ + /* read device id from this register */ + .id_reg = SENSOR_UNKNOW_DATA, + /* device id */ + .id_data = SENSOR_UNKNOW_DATA, + .precision = 16, /* 8 bits */ + /* enable or disable */ + .ctrl_reg = CM3218_REG_ADDR_CMD, + /* intterupt status register */ + .int_status_reg = CM3218_REG_ADDR_STATUS, + /* range */ + .range = {0, 65535}, + /* brightness */ + .brightness = {10, 255}, + .trig = SENSOR_UNKNOW_DATA, + .active = sensor_active, .init = sensor_init, .report = sensor_report_value, }; /****************operate according to sensor chip:end************/ -//function name should not be changed +/* function name should not be changed */ static struct sensor_operate *light_get_ops(void) { return &light_cm3218_ops; } - static int __init light_cm3218_init(void) { struct sensor_operate *ops = light_get_ops(); int result = 0; int type = ops->type; + result = sensor_register_slave(type, NULL, NULL, light_get_ops); + return result; } @@ -311,11 +401,9 @@ static void __exit light_cm3218_exit(void) { struct sensor_operate *ops = light_get_ops(); int type = ops->type; + sensor_unregister_slave(type, NULL, NULL, light_get_ops); } - module_init(light_cm3218_init); module_exit(light_cm3218_exit); - - -- 2.34.1