1 /* drivers/input/sensors/pressure/ms5607.c
\r
3 * Copyright (C) 2012-2015 ROCKCHIP.
\r
4 * Author: luowei <lw@rock-chips.com>
\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
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
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
33 #include <linux/sensor-dev.h>
\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
49 /****************operate according to sensor chip:start************/
\r
51 static int C[8] = {0};
\r
53 int g_ms5607_pr_status;
\r
55 #if defined(CONFIG_TMP_MS5607)
\r
56 extern int g_ms5607_temp_status;
\r
58 static int g_ms5607_temp_status = SENSOR_OFF;
\r
62 static int sensor_active(struct i2c_client *client, int enable, int rate)
\r
68 if((enable) && (g_ms5607_temp_status == SENSOR_OFF))
\r
70 result = sensor_write_reg_normal(client, CMD_RESET);
\r
72 printk("%s:line=%d,error\n",__func__,__LINE__);
\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
79 prom[i*2]= CMD_PROM_RD + i*2;
\r
80 result = sensor_rx_data(client, &prom[i*2], 2);
\r
83 printk("%s:line=%d,error\n",__func__,__LINE__);
\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
97 g_ms5607_pr_status = enable;
\r
102 static int sensor_init(struct i2c_client *client)
\r
104 struct sensor_private_data *sensor =
\r
105 (struct sensor_private_data *) i2c_get_clientdata(client);
\r
108 result = sensor->ops->active(client,0,0);
\r
111 printk("%s:line=%d,error\n",__func__,__LINE__);
\r
115 sensor->status_cur = SENSOR_OFF;
\r
116 g_ms5607_pr_status = sensor->status_cur;
\r
119 //result = sensor_write_reg_normal(client, CMD_RESET);
\r
121 //printk("%s:line=%d,error\n",__func__,__LINE__);
\r
127 static int pressure_report_value(struct input_dev *input, int data)
\r
129 //get pressure, high and temperature from register data
\r
131 input_report_abs(input, ABS_PRESSURE, data);
\r
138 static int sensor_report_value(struct i2c_client *client)
\r
140 struct sensor_private_data *sensor =
\r
141 (struct sensor_private_data *) i2c_get_clientdata(client);
\r
146 unsigned int D1=0, D2=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
157 memset(buffer, 0, 3);
\r
158 if(sensor->ops->read_len < 3) //sensor->ops->read_len = 3
\r
160 printk("%s:lenth is error,len=%d\n",__func__,sensor->ops->read_len);
\r
165 sensor_write_reg_normal(client, CMD_ADC_CONV + CMD_ADC_D1 + CMD_ADC_4096);
\r
168 memset(buffer, 0, 3);
\r
169 buffer[0] = CMD_ADC_READ;
\r
170 result = sensor_rx_data(client, &buffer[0], 3);
\r
173 printk("%s:line=%d,error\n",__func__,__LINE__);
\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
181 sensor_write_reg_normal(client, CMD_ADC_CONV + CMD_ADC_D2 + CMD_ADC_4096);
\r
184 memset(buffer, 0, 3);
\r
185 buffer[0] = CMD_ADC_READ;
\r
186 result = sensor_rx_data(client, &buffer[0], 3);
\r
189 printk("%s:line=%d,error\n",__func__,__LINE__);
\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
196 dT = D2 - ((unsigned int)C[5] << 8);
\r
198 g_ms5607_temp = (int)(2000 + ((long long)dT * C[6] >> 23));
\r
200 OFF = ((unsigned long long)C[2] << 17) + (C[4] * (long long)dT >> 6);
\r
202 SENS = ((long long)C[1] << 16) + (C[3] * (long long)dT >> 7);
\r
204 /*calcualte 2nd order pressure and temperature (BP5607 2nd order algorithm)*/
\r
205 if (g_ms5607_temp < -4000 || g_ms5607_temp > 8500)
\r
207 printk("%s:temperature is error\n",__func__);
\r
211 if (g_ms5607_temp < 2000)
\r
214 tmp = (g_ms5607_temp - 2000) * (g_ms5607_temp - 2000);
\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
220 if (g_ms5607_temp < -1500)
\r
222 tmp = (g_ms5607_temp + 1500) * (g_ms5607_temp + 1500);
\r
234 g_ms5607_temp -= T2;
\r
237 P = (int)((((D1 * SENS) >> 21) - OFF) >> 15);
\r
239 index = pressure_report_value(sensor->input_dev, P);
\r
241 DBG("%s:pressure=%d,temperature=%d\n",__func__,P,g_ms5607_temp);
\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
265 /****************operate according to sensor chip:end************/
\r
267 //function name should not be changed
\r
268 static struct sensor_operate *pressure_get_ops(void)
\r
270 return &pressure_ms5607_ops;
\r
274 static int __init pressure_ms5607_init(void)
\r
276 struct sensor_operate *ops = pressure_get_ops();
\r
278 int type = ops->type;
\r
279 result = sensor_register_slave(type, NULL, NULL, pressure_get_ops);
\r
283 static void __exit pressure_ms5607_exit(void)
\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
291 module_init(pressure_ms5607_init);
\r
292 module_exit(pressure_ms5607_exit);
\r