af865a2277257eecdb314fdeba9ba3780693e97f
[firefly-linux-kernel-4.4.55.git] / drivers / input / sensors / pressure / pr_ms5607.c
1 /* drivers/input/sensors/pressure/ms5607.c\r
2  *\r
3  * Copyright (C) 2012-2015 ROCKCHIP.\r
4  * Author: luowei <lw@rock-chips.com>\r
5  *\r
6  * This software is licensed under the terms of the GNU General Public\r
7  * License version 2, as published by the Free Software Foundation, and\r
8  * may be copied, distributed, and modified under those terms.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  */\r
16 #include <linux/interrupt.h>\r
17 #include <linux/i2c.h>\r
18 #include <linux/slab.h>\r
19 #include <linux/irq.h>\r
20 #include <linux/miscdevice.h>\r
21 #include <linux/gpio.h>\r
22 #include <asm/uaccess.h>\r
23 #include <asm/atomic.h>\r
24 #include <linux/delay.h>\r
25 #include <linux/input.h>\r
26 #include <linux/workqueue.h>\r
27 #include <linux/freezer.h>\r
28 #include <mach/gpio.h>\r
29 #include <mach/board.h> \r
30 #ifdef CONFIG_HAS_EARLYSUSPEND\r
31 #include <linux/earlysuspend.h>\r
32 #endif\r
33 #include <linux/sensor-dev.h>\r
34 \r
35 \r
36 #define CMD_RESET   0x1E  // ADC reset command \r
37 #define CMD_ADC_READ 0x00  // ADC read command \r
38 #define CMD_ADC_CONV 0x40  // ADC conversion command \r
39 #define CMD_ADC_D1   0x00    // ADC D1 conversion \r
40 #define CMD_ADC_D2   0x10    // ADC D2 conversion \r
41 #define CMD_ADC_256  0x00    // ADC OSR=256 \r
42 #define CMD_ADC_512  0x02    // ADC OSR=512 \r
43 #define CMD_ADC_1024 0x04    // ADC OSR=1024 \r
44 #define CMD_ADC_2048 0x06    // ADC OSR=2048 \r
45 #define CMD_ADC_4096 0x08    // ADC OSR=4096 \r
46 #define CMD_PROM_RD  0xA0  // Prom read command \r
47 \r
48 \r
49 /****************operate according to sensor chip:start************/\r
50 \r
51 static int C[8] = {0};\r
52 int g_ms5607_temp;\r
53 int g_ms5607_pr_status;\r
54 \r
55 #if defined(CONFIG_TMP_MS5607)\r
56 extern int g_ms5607_temp_status;\r
57 #else\r
58 static int g_ms5607_temp_status = SENSOR_OFF;\r
59 #endif\r
60 \r
61 \r
62 static int sensor_active(struct i2c_client *client, int enable, int rate)\r
63 {\r
64         int result = 0;\r
65         int i = 0;\r
66         char prom[16];\r
67 \r
68         if((enable) && (g_ms5607_temp_status == SENSOR_OFF))\r
69         {\r
70                 result = sensor_write_reg_normal(client, CMD_RESET);\r
71                 if(result)              \r
72                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
73 \r
74                 //Read PROM (128 bit of calibration words)  \r
75                 memset(prom, 0, 16);\r
76                 prom[0]= CMD_PROM_RD;//CMD_PROM_RD;   \r
77                 for(i=0; i<8; i++)\r
78                 {\r
79                         prom[i*2]= CMD_PROM_RD + i*2;\r
80                         result = sensor_rx_data(client, &prom[i*2], 2);\r
81                         if(result)\r
82                         {\r
83                                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
84                                 return result;\r
85                         }\r
86                 }\r
87 \r
88                 for (i=0;i<8;i++) \r
89                 {\r
90                         C[i] = prom[2*i] << 8 | prom[2*i + 1];\r
91                         //printk("prom[%d]=0x%x,prom[%d]=0x%x",2*i,prom[2*i],(2*i + 1),prom[2*i + 1]);\r
92                         //printk("\nC[%d]=%d,",i+1,C[i]);\r
93                 } \r
94 \r
95         }\r
96         \r
97         g_ms5607_pr_status = enable;\r
98         \r
99         return result;\r
100 }\r
101 \r
102 static int sensor_init(struct i2c_client *client)\r
103 {       \r
104         struct sensor_private_data *sensor =\r
105             (struct sensor_private_data *) i2c_get_clientdata(client);  \r
106         int result = 0;\r
107         \r
108         result = sensor->ops->active(client,0,0);\r
109         if(result)\r
110         {\r
111                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
112                 return result;\r
113         }\r
114         \r
115         sensor->status_cur = SENSOR_OFF;\r
116         g_ms5607_pr_status = sensor->status_cur;\r
117         \r
118         //Reset\r
119         //result = sensor_write_reg_normal(client, CMD_RESET);\r
120         //if(result)            \r
121         //printk("%s:line=%d,error\n",__func__,__LINE__);       \r
122     \r
123         return result;\r
124 }\r
125 \r
126 \r
127 static int pressure_report_value(struct input_dev *input, int data)\r
128 {\r
129         //get pressure, high and temperature from register data\r
130 \r
131         input_report_abs(input, ABS_PRESSURE, data);\r
132         input_sync(input);\r
133         \r
134         return 0;\r
135 }\r
136 \r
137 \r
138 static int sensor_report_value(struct i2c_client *client)\r
139 {\r
140         struct sensor_private_data *sensor =\r
141             (struct sensor_private_data *) i2c_get_clientdata(client);  \r
142     \r
143         int result = 0;\r
144         char buffer[3]; \r
145         char index = 0;\r
146         unsigned int  D1=0, D2=0;\r
147 \r
148         int T2 = 0;\r
149         long long OFF = 0;      // offset at actual temperature \r
150         long long SENS = 0;     // sensitivity at actual temperature \r
151         int dT = 0;             // difference between actual and measured temperature\r
152         long long OFF2 = 0;\r
153         long long SENS2 = 0;\r
154         int P = 0;              // compensated pressure value \r
155 \r
156 \r
157         memset(buffer, 0, 3);\r
158         if(sensor->ops->read_len < 3)   //sensor->ops->read_len = 3\r
159         {\r
160                 printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);\r
161                 return -1;\r
162         }\r
163 \r
164         //D1 conversion\r
165         sensor_write_reg_normal(client,  CMD_ADC_CONV + CMD_ADC_D1 + CMD_ADC_4096);\r
166         msleep(10);\r
167 \r
168         memset(buffer, 0, 3);\r
169         buffer[0] = CMD_ADC_READ;\r
170         result = sensor_rx_data(client, &buffer[0], 3);\r
171         if(result)\r
172         {\r
173                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
174                 return result;\r
175         }\r
176 \r
177         D1 = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];\r
178         DBG("\nD1=%d :buffer[0]=0x%x,buffer[1]=0x%x,buffer2]=0x%x\n",D1,buffer[0],buffer[1],buffer[2]);\r
179 \r
180         //D2 conversion\r
181         sensor_write_reg_normal(client,  CMD_ADC_CONV + CMD_ADC_D2 + CMD_ADC_4096);\r
182         msleep(10);\r
183 \r
184         memset(buffer, 0, 3);\r
185         buffer[0] = CMD_ADC_READ;\r
186         result = sensor_rx_data(client, &buffer[0], 3);\r
187         if(result)\r
188         {\r
189                 printk("%s:line=%d,error\n",__func__,__LINE__);\r
190                 return result;\r
191         }\r
192 \r
193         D2 = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];\r
194         DBG("D2=%d:buffer[0]=0x%x,buffer[1]=0x%x,buffer2]=0x%x\n",D2,buffer[0],buffer[1],buffer[2]);\r
195 \r
196         dT = D2 - ((unsigned int)C[5] << 8);\r
197 \r
198         g_ms5607_temp = (int)(2000 + ((long long)dT * C[6] >> 23));\r
199 \r
200         OFF = ((unsigned long long)C[2] << 17) + (C[4] * (long long)dT >> 6);\r
201 \r
202         SENS = ((long long)C[1] << 16) + (C[3] * (long long)dT >> 7);\r
203 \r
204         /*calcualte 2nd order pressure and temperature (BP5607 2nd order algorithm)*/\r
205         if (g_ms5607_temp < -4000 || g_ms5607_temp > 8500)\r
206         {\r
207                 printk("%s:temperature is error\n",__func__);\r
208                 return -1;\r
209         }\r
210 \r
211         if (g_ms5607_temp < 2000)\r
212         {\r
213                 int tmp;\r
214                 tmp = (g_ms5607_temp - 2000) * (g_ms5607_temp - 2000);\r
215 \r
216                 T2 = (int)((long long)(dT * dT) >> 31);\r
217                 OFF2 = (((long long)tmp * 61)*((long long)tmp * 61)) >> 4;\r
218                 SENS2 = (long long)((tmp*tmp) << 1);\r
219 \r
220                 if (g_ms5607_temp < -1500)\r
221                 {\r
222                         tmp = (g_ms5607_temp + 1500) * (g_ms5607_temp + 1500);\r
223                         OFF2 += 15 * tmp;\r
224                         SENS2 += 8 * tmp;\r
225                 }\r
226         }\r
227         else\r
228         {\r
229                 T2=0;\r
230                 OFF2 = 0;\r
231                 SENS2 = 0;\r
232         }\r
233 \r
234         g_ms5607_temp -= T2;\r
235         OFF -= OFF2;\r
236         SENS -= SENS2;    \r
237         P = (int)((((D1 * SENS) >> 21) - OFF) >> 15);\r
238 \r
239         index = pressure_report_value(sensor->input_dev, P);\r
240 \r
241         DBG("%s:pressure=%d,temperature=%d\n",__func__,P,g_ms5607_temp);\r
242         \r
243         return result;\r
244 }\r
245 \r
246 struct sensor_operate pressure_ms5607_ops = {\r
247         .name                           = "pr_ms5607",\r
248         .type                           = SENSOR_TYPE_PRESSURE, //sensor type and it should be correct\r
249         .id_i2c                         = PRESSURE_ID_MS5607,   //i2c id number\r
250         .read_reg                       = SENSOR_UNKNOW_DATA,   //read data\r
251         .read_len                       = 3,                    //data length\r
252         .id_reg                         = SENSOR_UNKNOW_DATA,   //read device id from this register\r
253         .id_data                        = SENSOR_UNKNOW_DATA,   //device id\r
254         .precision                      = 24,                   //8 bits\r
255         .ctrl_reg                       = SENSOR_UNKNOW_DATA,   //enable or disable \r
256         .int_status_reg                 = SENSOR_UNKNOW_DATA,   //intterupt status register\r
257         .range                          = {100,65535},          //range\r
258         .brightness                     = {10,255},             //brightness\r
259         .trig                           = IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,                \r
260         .active                         = sensor_active,        \r
261         .init                           = sensor_init,\r
262         .report                         = sensor_report_value,\r
263 };\r
264 \r
265 /****************operate according to sensor chip:end************/\r
266 \r
267 //function name should not be changed\r
268 static struct sensor_operate *pressure_get_ops(void)\r
269 {\r
270         return &pressure_ms5607_ops;\r
271 }\r
272 \r
273 \r
274 static int __init pressure_ms5607_init(void)\r
275 {\r
276         struct sensor_operate *ops = pressure_get_ops();\r
277         int result = 0;\r
278         int type = ops->type;\r
279         result = sensor_register_slave(type, NULL, NULL, pressure_get_ops);\r
280         return result;\r
281 }\r
282 \r
283 static void __exit pressure_ms5607_exit(void)\r
284 {\r
285         struct sensor_operate *ops = pressure_get_ops();\r
286         int type = ops->type;\r
287         sensor_unregister_slave(type, NULL, NULL, pressure_get_ops);\r
288 }\r
289 \r
290 \r
291 module_init(pressure_ms5607_init);\r
292 module_exit(pressure_ms5607_exit);\r
293 \r