1 /* s62x.c - s62x compass driver
3 * This software is licensed under the terms of the GNU General Public
4 * License version 2, as published by the Free Software Foundation, and
5 * may be copied, distributed, and modified under those terms.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
13 #include <linux/version.h>
14 #include <linux/interrupt.h>
15 #include <linux/i2c.h>
16 #include <linux/slab.h>
17 #include <linux/irq.h>
18 #include <linux/miscdevice.h>
19 #include <asm/uaccess.h>
20 #include <asm/atomic.h>
21 #include <linux/delay.h>
22 #include <linux/input.h>
23 #include <linux/workqueue.h>
24 #include <linux/kobject.h>
25 #include <linux/platform_device.h>
26 #include <linux/earlysuspend.h>
28 #include <linux/hwmsensor.h>
29 #include <linux/hwmsen_dev.h>
30 #include <linux/sensors_io.h>
32 #include <mach/mt_devs.h>
33 #include <mach/mt_typedefs.h>
34 #include <mach/mt_gpio.h>
35 #include <mach/mt_pm_ldo.h>
39 #include <linux/hwmsen_helper.h>
42 /*-------------------------MT6516&MT6573 define-------------------------------*/
43 #define POWER_NONE_MACRO MT65XX_POWER_NONE
45 /*----------------------------------------------------------------------------*/
47 /****** Begin of Customization ****/
48 //#define USE_ALTERNATE_ADDRESS //can change i2c address when the first(0x0c<<1) conflig whit other devices
49 //#define FORCE_KERNEL2X_STYLE //auto fit android version(cause the different i2c flow)
50 /****** End of Customization ******/
52 #ifndef FORCE_KERNEL2X_STYLE
53 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(3,0,0))
59 #define PLATFORM_DRIVER_NAME "msensor"
62 /* The following items are for internal testing only.
63 -USE_ALTERNATE_ADDRESS: (--)default (+*)test S
64 +USE_ALTERNATE_ADDRESS: (--)default (+-)test S (-+)test A
66 //#define _MAGIC_KPT_COMMAND
67 //#define _FORCE_PROBE_ERROR
69 /*----------------------------------------------------------------------------*/
71 #define S62X_I2C_ADDR1 (0x0C<<1)
72 #define S62X_I2C_ADDR2 (0x1E<<1)
74 #define S62X_I2C_ADDR1 (0x0C)
75 #define S62X_I2C_ADDR2 (0x1E)
78 #ifdef USE_ALTERNATE_ADDRESS
79 #define S62X_I2C_ADDRESS S62X_I2C_ADDR2
81 #define S62X_I2C_ADDRESS S62X_I2C_ADDR1
83 #define S62X_DEV_NAME "s62x"
84 #define DRIVER_VERSION "2.0.0"
86 /*----------------------------------------------------------------------------*/
89 #define S62X_DEBUG_MSG 1
90 #define S62X_DEBUG_FUNC 1
91 #define S62X_DEBUG_DATA 1
92 #define S62X_RETRY_COUNT 9
93 #define S62X_DEFAULT_DELAY 100
96 #define SSMDBG(format, ...) printk(KERN_INFO "S62X " format "\n", ## __VA_ARGS__)
98 #define SSMDBG(format, ...)
102 #define SSMFUNC(func) printk(KERN_INFO "S62X " func " is called\n")
104 #define SSMFUNC(func)
107 //Don't change this if you don't know why! (refer comment:ticket:35:2)
108 #define PROJECT_ID "S628"
110 /*----------------------------------------------------------------------------*/
111 #define SENSOR_DATA_SIZE 6
112 #define SENSOR_DATA_COUNT (SENSOR_DATA_SIZE/sizeof(short))
113 #define CALIBRATION_DATA_SIZE 12
115 #define RWBUF_SIZE 32
116 #define S62X_BUFSIZE 32
119 #define CONVERT_O_DIV 1
121 #define CONVERT_M_DIV 28
123 /*----------------------------------------------------------------------------*/
124 #define SS_SENSOR_MODE_OFF 0
125 #define SS_SENSOR_MODE_MEASURE 1
127 /*----------------------------------------------------------------------------*/
128 #define S62X_IDX_DEVICE_ID 0x00
129 #define DEVICE_ID_VALUE 0x21
131 #define S62X_IDX_DEVICE_INFO 0x01
132 #define DEVICE_INFO_VALUE 0x10
134 #define S62X_IDX_STA1 0x02
135 #define STA1_DRDY 0x01
137 #define S62X_IDX_X_LSB 0x03
138 #define S62X_IDX_STA2 0x09
140 #define S62X_IDX_MODE 0x0A
141 #define MODE_TRIGGER 0x01
143 #define S62X_IDX_I2CDIS 0x0F
144 #define I2CDIS_CIC 0x00
145 #define I2CDIS_ADC 0x01
147 #define S62X_IDX_SET_RESET 0x1A
148 #define SET_RESET_SET 0x01
149 #define SET_RESET_RESET 0x02
151 #define S62X_IDX_SET_RESET_CON 0x1C
152 #define S62X_IDX_VBGSEL 0x1D
153 #define S62X_IDX_OSC_TRIM 0x1E
155 #define S62X_IDX_ECO1 0x1F
156 #ifdef USE_ALTERNATE_ADDRESS
157 #define ECO1_DEFAULT 0x44
159 #define ECO1_DEFAULT 0x40
162 #define S62X_IDX_ECO2 0x20
163 #define ECO2_MRAS_NO_RST 0x80
165 #define S62X_IDX_CHOP 0x21
166 #define S62X_IDX_BIAS 0x23
167 #define S62X_IDX_LDO_SEL 0x24
168 #define S62X_IDX_DATA_POL 0x25
169 #define S62X_IDX_ADC_RDY_CNT 0x27
170 #define S62X_IDX_W2 0x28
171 #define S62X_IDX_PW_VALUE 0x35
173 #define S62X_IDX_PROBE_OE 0x37
174 #define PROBE_OE_WATCHDOG 0x10
176 /*----------------------------------------------------------------------------*/
177 static struct i2c_client
*this_client
= NULL
;
179 static short last_m_data
[SENSOR_DATA_COUNT
];
180 static struct mutex last_m_data_mutex
;
182 static short sensor_data
[CALIBRATION_DATA_SIZE
];
183 static struct mutex sensor_data_mutex
;
184 static DECLARE_WAIT_QUEUE_HEAD(open_wq
);
186 static short ssmd_delay
= S62X_DEFAULT_DELAY
;
187 static char ssmd_status
[RWBUF_SIZE
];
189 static atomic_t open_flag
= ATOMIC_INIT(0);
190 static atomic_t m_flag
= ATOMIC_INIT(0);
191 static atomic_t o_flag
= ATOMIC_INIT(0);
192 static atomic_t m_get_data
;
193 static atomic_t o_get_data
;
194 static atomic_t dev_open_count
;
195 static atomic_t init_phase
= ATOMIC_INIT(2); // 1 = id check ok, 0 = init ok
197 /*----------------------------------------------------------------------------*/
198 static const struct i2c_device_id s62x_i2c_id
[] = { { S62X_DEV_NAME
, 0}, {} };
199 #ifndef MTK_ANDROID_4
200 static unsigned short s62x_force
[] = { 0x00, S62X_I2C_ADDRESS
, I2C_CLIENT_END
, I2C_CLIENT_END
};
201 static const unsigned short *const s62x_forces
[] = { s62x_force
, NULL
};
202 static struct i2c_client_address_data s62x_addr_data
= { .forces
= s62x_forces
};
204 static struct i2c_board_info __initdata i2c_s62x
= { I2C_BOARD_INFO(S62X_DEV_NAME
, S62X_I2C_ADDRESS
) };
207 /*----------------------------------------------------------------------------*/
208 static int s62x_i2c_probe(struct i2c_client
*client
, const struct i2c_device_id
*id
);
209 static int s62x_i2c_remove(struct i2c_client
*client
);
210 #ifndef MTK_ANDROID_4
211 static int s62x_i2c_detect(struct i2c_client
*client
, int kind
, struct i2c_board_info
*info
);
213 static int s62x_i2c_detect(struct i2c_client
*client
, struct i2c_board_info
*info
);
215 static int ssm_probe(struct platform_device
*pdev
);
216 static int ssm_remove(struct platform_device
*pdev
);
218 /*----------------------------------------------------------------------------*/
221 SS_DATA_DEBUG
= 0X02,
227 /*----------------------------------------------------------------------------*/
228 struct s62x_i2c_data
{
229 struct i2c_client
*client
;
233 struct hwmsen_convert cvt
;
234 #if defined(CONFIG_HAS_EARLYSUSPEND)
235 struct early_suspend early_drv
;
239 #define L2CHIP(x) ((x)/10) //layout to chip id
240 #define L2CVTI(x) ((x)%10) //layout to cvt index
242 /*----------------------------------------------------------------------------*/
243 static struct i2c_driver s62x_i2c_driver
= {
245 #ifndef MTK_ANDROID_4
246 .owner
= THIS_MODULE
,
248 .name
= S62X_DEV_NAME
,
250 .probe
= s62x_i2c_probe
,
251 .remove
= s62x_i2c_remove
,
252 .detect
= s62x_i2c_detect
,
253 #if !defined(CONFIG_HAS_EARLYSUSPEND)
254 .suspend
= s62x_suspend
,
255 .resume
= s62x_resume
,
257 .id_table
= s62x_i2c_id
,
258 #ifndef MTK_ANDROID_4
259 .address_data
= &s62x_addr_data
,
263 /*----------------------------------------------------------------------------*/
265 static struct platform_driver ssm_sensor_driver
= {
267 .remove
= ssm_remove
,
269 .name
= PLATFORM_DRIVER_NAME
,
270 #ifndef MTK_ANDROID_4
271 .owner
= THIS_MODULE
,
278 static const struct of_device_id ssm_of_match
[] = {
279 { .compatible
= "mediatek,msensor", },
284 static struct platform_driver ssm_sensor_driver
=
287 .remove
= ssm_remove
,
292 .of_match_table
= ssm_of_match
,
297 /*----------------------------------------------------------------------------*/
298 static void s62x_power(struct mag_hw
*hw
, unsigned int on
)
300 static unsigned int power_on
= 0;
302 if (hw
->power_id
!= POWER_NONE_MACRO
) {
303 SSMDBG("power %s", on
? "on" : "off");
304 if (power_on
== on
) {
305 SSMDBG("ignore power control: %d", on
);
307 if (!hwPowerOn(hw
->power_id
, hw
->power_vol
, S62X_DEV_NAME
)) {
308 printk(KERN_ERR
"S62X power on fail\n");
311 if (!hwPowerDown(hw
->power_id
, S62X_DEV_NAME
)) {
312 printk(KERN_ERR
"S62X power off fail\n");
320 /*----------------------------------------------------------------------------*/
321 static int I2C_RxData(char *rxData
, int length
)
327 struct i2c_client
*client
= this_client
;
328 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
329 char addr
= rxData
[0];
332 /* Caller should check parameter validity.*/
333 if ((rxData
== NULL
) || (length
< 1)) {
337 for (loop_i
= 0; loop_i
< S62X_RETRY_COUNT
; loop_i
++) {
338 this_client
->addr
= (this_client
->addr
& I2C_MASK_FLAG
) | I2C_WR_FLAG
;
339 if (i2c_master_send(this_client
, (const char*)rxData
, ((length
<<0X08) | 0X01))) {
345 if (loop_i
>= S62X_RETRY_COUNT
) {
346 printk(KERN_ERR
"S62X %s retry over %d\n", __func__
, S62X_RETRY_COUNT
);
351 if (atomic_read(&data
->trace
) & SS_I2C_DEBUG
) {
352 printk(KERN_INFO
"S62X RxData len=%02x addr=%02x\n data=", length
, addr
);
353 for (i
= 0; i
< length
; i
++) {
354 printk(KERN_INFO
" %02x", rxData
[i
]);
356 printk(KERN_INFO
"\n");
362 static int I2C_TxData(char *txData
, int length
)
368 struct i2c_client
*client
= this_client
;
369 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
372 /* Caller should check parameter validity.*/
373 if ((txData
== NULL
) || (length
< 2)) {
377 this_client
->addr
= this_client
->addr
& I2C_MASK_FLAG
;
378 for (loop_i
= 0; loop_i
< S62X_RETRY_COUNT
; loop_i
++) {
379 if (i2c_master_send(this_client
, (const char*)txData
, length
) > 0) {
385 if (loop_i
>= S62X_RETRY_COUNT
) {
386 printk(KERN_ERR
"S62X %s retry over %d\n", __func__
, S62X_RETRY_COUNT
);
391 if (atomic_read(&data
->trace
) & SS_I2C_DEBUG
) {
392 printk(KERN_INFO
"S62X TxData len=%02x addr=%02x\n data=", length
, txData
[0]);
393 for (i
= 0; i
< (length
-1); i
++) {
394 printk(KERN_INFO
" %02x", txData
[i
+ 1]);
396 printk(KERN_INFO
"\n");
402 static int I2C_TxData2(unsigned char c1
, unsigned char c2
)
404 unsigned char data
[2];
409 return I2C_TxData(data
, 2);
412 static int ECS_InitDevice(void)
414 char *err_desc
= NULL
;
416 if (I2C_TxData2(S62X_IDX_BIAS
, 0x00) < 0) {
421 if (I2C_TxData2(S62X_IDX_VBGSEL
, 0x70) < 0) {
426 if (I2C_TxData2(S62X_IDX_OSC_TRIM
, 0x00) < 0) {
427 err_desc
= "OSC_TRIM";
431 if (I2C_TxData2(S62X_IDX_ECO1
, ECO1_DEFAULT
) < 0) {
436 if (I2C_TxData2(S62X_IDX_ECO2
, 0x04) < 0) {
441 if (I2C_TxData2(S62X_IDX_CHOP
, 0x05) < 0) {
446 if (I2C_TxData2(S62X_IDX_LDO_SEL
, 0x13) < 0) {
447 err_desc
= "LDO_SEL";
451 if (I2C_TxData2(S62X_IDX_PW_VALUE
, 0x5f) < 0) {
452 err_desc
= "PW_VALUE";
456 if (I2C_TxData2(S62X_IDX_SET_RESET_CON
, 0x80) < 0) {
457 err_desc
= "SET_RESET_CON";
461 if (I2C_TxData2(S62X_IDX_DATA_POL
, 0x00) < 0) {
462 err_desc
= "DATA_POL";
466 if (I2C_TxData2(S62X_IDX_ADC_RDY_CNT
, 0x03) < 0) {
467 err_desc
= "ADC_RDY_CNT";
471 if (I2C_TxData2(S62X_IDX_W2
, 0x20) < 0) {
476 if (I2C_TxData2(S62X_IDX_PROBE_OE
, 0x20|PROBE_OE_WATCHDOG
) < 0) {
477 err_desc
= "PROBE_OE";
484 printk(KERN_ERR
"S62X_IDX_%s failed\n", err_desc
);
490 struct i2c_client
*client
= this_client
;
491 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
493 if ((atomic_read(&data
->trace
) & 0xF000) == 0x9000) return -EFAULT
;
494 else atomic_set(&init_phase
, 0);
500 static int ECS_SetMode_Off(void)
502 char *err_desc
= NULL
;
504 if (I2C_TxData2(S62X_IDX_MODE
, 0x00) < 0) {
509 if (I2C_TxData2(S62X_IDX_ECO2
, 0x04) < 0) {
514 if (I2C_TxData2(S62X_IDX_I2CDIS
, I2CDIS_CIC
) < 0) {
522 printk(KERN_ERR
"S62X_IDX_%s failed\n", err_desc
);
529 static int ECS_SetMode_Measure(void)
531 char *err_desc
= NULL
;
533 if (I2C_TxData2(S62X_IDX_I2CDIS
, I2CDIS_ADC
) < 0) {
538 if (I2C_TxData2(S62X_IDX_ECO2
, 0x04|ECO2_MRAS_NO_RST
) < 0) {
543 if (I2C_TxData2(S62X_IDX_MODE
, MODE_TRIGGER
) < 0) {
551 printk(KERN_ERR
"S62X_IDX_%s failed\n", err_desc
);
558 static int ECS_SetMode(char mode
)
564 case SS_SENSOR_MODE_OFF
:
565 ret
= ECS_SetMode_Off();
568 case SS_SENSOR_MODE_MEASURE
:
569 ret
= ECS_SetMode_Measure();
573 SSMDBG("%s: Unknown mode(%d)", __func__
, mode
);
580 static int ECS_CheckDevice(void)
585 id1
= S62X_IDX_DEVICE_ID
;
586 err
= I2C_RxData(&id1
, 1);
591 id2
= S62X_IDX_DEVICE_INFO
;
592 err
= I2C_RxData(&id2
, 1);
599 struct i2c_client
*client
= this_client
;
600 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
602 if ((atomic_read(&data
->trace
) & 0xF000) == 0x8000) id1
= 0x00, id2
= 0x01;
603 else atomic_set(&init_phase
, 1);
606 if (id1
!= DEVICE_ID_VALUE
|| id2
!= DEVICE_INFO_VALUE
) {
607 printk(KERN_ERR
"S62X incorrect id %02X:%02X\n", id1
, id2
);
614 static int ECS_SaveData(short *buf
)
617 struct i2c_client
*client
= this_client
;
618 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
621 mutex_lock(&sensor_data_mutex
);
622 memcpy(sensor_data
, buf
, sizeof(sensor_data
));
623 mutex_unlock(&sensor_data_mutex
);
626 if (atomic_read(&data
->trace
) & SS_HWM_DEBUG
) {
627 SSMDBG("Get daemon data: %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d!",
628 sensor_data
[0],sensor_data
[1],sensor_data
[2],sensor_data
[3],
629 sensor_data
[4],sensor_data
[5],sensor_data
[6],sensor_data
[7],
630 sensor_data
[8],sensor_data
[9],sensor_data
[10],sensor_data
[11]);
636 #define V(c1,c2) (int)(((((unsigned)(c1))<<8)|((unsigned)(c2)))&0x0fff)
638 static int ECS_GetData(short *mag
)
641 struct i2c_client
*client
= this_client
;
642 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
646 for (loop_i
= 0; loop_i
< S62X_RETRY_COUNT
; loop_i
++) {
647 buf
[0] = S62X_IDX_STA1
;
648 if (I2C_RxData(buf
, 1)) {
649 printk(KERN_ERR
"S62X_IDX_STA1 %s fail\n", __func__
);
653 if (buf
[0] == STA1_DRDY
) {
659 if (loop_i
>= S62X_RETRY_COUNT
) {
660 printk(KERN_ERR
"S62X %s retry over\n", __func__
);
664 buf
[0] = S62X_IDX_X_LSB
;
665 ret
= I2C_RxData(buf
, sizeof(buf
));
667 printk(KERN_ERR
"S62X_IDX_X_LSB %s fail\n", __func__
);
670 v
= V(buf
[1], buf
[0]), mag
[data
->cvt
.map
[0]] = (data
->cvt
.sign
[0] > 0) ? v
: (4095 - v
);
671 v
= V(buf
[5], buf
[4]), mag
[data
->cvt
.map
[1]] = (data
->cvt
.sign
[1] > 0) ? v
: (4095 - v
);
672 v
= V(buf
[3], buf
[2]), mag
[data
->cvt
.map
[2]] = (data
->cvt
.sign
[2] > 0) ? v
: (4095 - v
);
675 mutex_lock(&last_m_data_mutex
);
676 memcpy(last_m_data
, mag
, sizeof(last_m_data
));
677 mutex_unlock(&last_m_data_mutex
);
680 if (atomic_read(&data
->trace
) & SS_DATA_DEBUG
) {
681 SSMDBG("Get device data: (%d,%d,%d)", mag
[0], mag
[1], mag
[2]);
688 static int ECS_GetOpenStatus(void)
690 wait_event_interruptible(open_wq
, (atomic_read(&open_flag
) != 0));
691 return atomic_read(&open_flag
);
694 static int ECS_GetCloseStatus(void)
696 wait_event_interruptible(open_wq
, (atomic_read(&open_flag
) <= 0));
697 return atomic_read(&open_flag
);
700 /*----------------------------------------------------------------------------*/
701 static int ECS_ReadChipInfo(char *buf
, int bufsize
)
703 static const char *supported_chip
[] = { "S628", "S628A", "S625A" };
704 int phase
= atomic_read(&init_phase
);
705 struct i2c_client
*client
= this_client
;
706 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
707 unsigned chip
= L2CHIP(atomic_read(&data
->layout
));
724 if (chip
< sizeof(supported_chip
)/sizeof(char*)) {
725 ret
= sprintf(buf
, supported_chip
[chip
]);
728 ret
= sprintf(buf
, "?");
734 /*----------------------------------------------------------------------------*/
735 static ssize_t
show_daemon_value(struct device_driver
*ddri
, char *buf
)
737 char strbuf
[S62X_BUFSIZE
];
738 sprintf(strbuf
, "s62xd");
739 return sprintf(buf
, "%s", strbuf
);
742 /*----------------------------------------------------------------------------*/
743 static ssize_t
show_chipinfo_value(struct device_driver
*ddri
, char *buf
)
745 char strbuf
[S62X_BUFSIZE
];
746 ECS_ReadChipInfo(strbuf
, S62X_BUFSIZE
);
747 return sprintf(buf
, "%s\n", strbuf
);
750 /*----------------------------------------------------------------------------*/
751 static ssize_t
show_sensordata_value(struct device_driver
*ddri
, char *buf
)
753 short mdata
[SENSOR_DATA_COUNT
];
755 mutex_lock(&last_m_data_mutex
);
756 memcpy(mdata
, last_m_data
, sizeof(mdata
));
757 mutex_unlock(&last_m_data_mutex
);
759 return sprintf(buf
, "%d %d %d\n", mdata
[0], mdata
[1], mdata
[2]);
762 /*----------------------------------------------------------------------------*/
763 static ssize_t
show_posturedata_value(struct device_driver
*ddri
, char *buf
)
767 tmp
[0] = sensor_data
[0] * CONVERT_O
/ CONVERT_O_DIV
;
768 tmp
[1] = sensor_data
[1] * CONVERT_O
/ CONVERT_O_DIV
;
769 tmp
[2] = sensor_data
[2] * CONVERT_O
/ CONVERT_O_DIV
;
771 return sprintf(buf
, "%d, %d, %d\n", tmp
[0], tmp
[1], tmp
[2]);
774 /*----------------------------------------------------------------------------*/
775 static ssize_t
show_layout_value(struct device_driver
*ddri
, char *buf
)
777 struct i2c_client
*client
= this_client
;
778 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
780 return sprintf(buf
, "(%d, %d)\n[%+2d %+2d %+2d]\n[%+2d %+2d %+2d]\n",
781 data
->hw
->direction
, atomic_read(&data
->layout
), data
->cvt
.sign
[0], data
->cvt
.sign
[1],
782 data
->cvt
.sign
[2],data
->cvt
.map
[0], data
->cvt
.map
[1], data
->cvt
.map
[2]);
784 /*----------------------------------------------------------------------------*/
785 static ssize_t
store_layout_value(struct device_driver
*ddri
, const char *buf
, size_t count
)
787 struct i2c_client
*client
= this_client
;
788 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
791 if (sscanf(buf
, "%d", &layout
) == 1) {
792 atomic_set(&data
->layout
, layout
);
793 if (!hwmsen_get_convert(L2CVTI(layout
), &data
->cvt
)) {
794 printk(KERN_ERR
"HWMSEN_GET_CONVERT function error!\n");
795 } else if (!hwmsen_get_convert(L2CVTI(data
->hw
->direction
), &data
->cvt
)) {
796 printk(KERN_ERR
"invalid layout: %d, restore to %d\n", layout
, data
->hw
->direction
);
798 printk(KERN_ERR
"invalid layout: (%d, %d)\n", layout
, data
->hw
->direction
);
799 hwmsen_get_convert(0, &data
->cvt
);
802 printk(KERN_ERR
"invalid format = '%s'\n", buf
);
808 /*----------------------------------------------------------------------------*/
809 static ssize_t
show_status_value(struct device_driver
*ddri
, char *buf
)
811 struct i2c_client
*client
= this_client
;
812 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
815 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "VERS: %s (%s)\n", DRIVER_VERSION
, ssmd_status
);
818 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "CUST: %d %d (%d %d)\n",
819 data
->hw
->i2c_num
, data
->hw
->direction
, data
->hw
->power_id
, data
->hw
->power_vol
);
821 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "CUST: NULL\n");
824 switch (atomic_read(&init_phase
)) {
827 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "IDCK: %d\n", ECS_CheckDevice());
831 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "INIT: %d\n", ECS_InitDevice());
835 len
+= snprintf(buf
+len
, PAGE_SIZE
-len
, "OPEN: %d (%d/%d)\n",
836 atomic_read(&dev_open_count
), atomic_read(&m_get_data
), atomic_read(&o_get_data
));
843 /*----------------------------------------------------------------------------*/
844 static ssize_t
show_trace_value(struct device_driver
*ddri
, char *buf
)
847 struct s62x_i2c_data
*obj
= i2c_get_clientdata(this_client
);
849 printk(KERN_ERR
"S62X data is null!!\n");
853 res
= snprintf(buf
, PAGE_SIZE
, "0x%04X\n", atomic_read(&obj
->trace
));
857 /*----------------------------------------------------------------------------*/
858 static ssize_t
store_trace_value(struct device_driver
*ddri
, const char *buf
, size_t count
)
860 struct s62x_i2c_data
*obj
= i2c_get_clientdata(this_client
);
863 printk(KERN_ERR
"S62X data is null!!\n");
867 if (1 == sscanf(buf
, "0x%x", &trace
)) {
868 atomic_set(&obj
->trace
, trace
);
870 printk(KERN_ERR
"S62X invalid content: '%s', length = %d\n", buf
, count
);
876 /*----------------------------------------------------------------------------*/
877 static DRIVER_ATTR(daemon
, S_IRUGO
, show_daemon_value
, NULL
);
878 static DRIVER_ATTR(chipinfo
, S_IRUGO
, show_chipinfo_value
, NULL
);
879 static DRIVER_ATTR(sensordata
, S_IRUGO
, show_sensordata_value
, NULL
);
880 static DRIVER_ATTR(posturedata
, S_IRUGO
, show_posturedata_value
, NULL
);
881 static DRIVER_ATTR(status
, S_IRUGO
, show_status_value
, NULL
);
882 static DRIVER_ATTR(layout
, S_IRUGO
| S_IWUSR
, show_layout_value
, store_layout_value
);
883 static DRIVER_ATTR(trace
, S_IRUGO
| S_IWUSR
, show_trace_value
, store_trace_value
);
885 /*----------------------------------------------------------------------------*/
886 static struct driver_attribute
*s62x_attr_list
[] = {
888 &driver_attr_chipinfo
,
889 &driver_attr_sensordata
,
890 &driver_attr_posturedata
,
896 /*----------------------------------------------------------------------------*/
897 static int s62x_create_attr(struct device_driver
*driver
)
900 int num
= (int)(sizeof(s62x_attr_list
)/sizeof(s62x_attr_list
[0]));
901 if (driver
== NULL
) {
905 for (idx
= 0; idx
< num
; idx
++) {
906 if ((err
= driver_create_file(driver
, s62x_attr_list
[idx
])) !=0 ) {
907 printk(KERN_ERR
"S62X driver_create_file (%s) = %d\n", s62x_attr_list
[idx
]->attr
.name
, err
);
914 /*----------------------------------------------------------------------------*/
915 static int s62x_delete_attr(struct device_driver
*driver
)
918 int num
= (int)(sizeof(s62x_attr_list
)/sizeof(s62x_attr_list
[0]));
920 if (driver
== NULL
) {
924 for (idx
= 0; idx
< num
; idx
++) {
925 driver_remove_file(driver
, s62x_attr_list
[idx
]);
931 /*----------------------------------------------------------------------------*/
932 static int s62x_open(struct inode
*inode
, struct file
*file
)
936 struct s62x_i2c_data
*obj
= i2c_get_clientdata(this_client
);
938 if (atomic_read(&obj
->trace
) & SS_CTR_DEBUG
) {
939 SSMDBG("open device node");
943 atomic_inc(&dev_open_count
);
944 ret
= nonseekable_open(inode
, file
);
949 /*----------------------------------------------------------------------------*/
950 static int s62x_release(struct inode
*inode
, struct file
*file
)
953 struct s62x_i2c_data
*obj
= i2c_get_clientdata(this_client
);
955 if (atomic_read(&obj
->trace
) & SS_CTR_DEBUG
) {
956 SSMDBG("release device node");
959 atomic_dec(&dev_open_count
);
964 /*----------------------------------------------------------------------------*/
965 #ifndef MTK_ANDROID_4
966 static int s62x_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
968 static long s62x_unlocked_ioctl(struct file
*file
, unsigned int cmd
, unsigned long arg
)
971 void __user
*argp
= (void __user
*)arg
;
973 /* NOTE: In this function the size of "char" should be 1-byte. */
974 short mdata
[SENSOR_DATA_COUNT
];
975 char rwbuf
[RWBUF_SIZE
];
976 char buff
[S62X_BUFSIZE
];
985 case ECS_IOCTL_WRITE
:
987 SSMDBG("invalid argument.");
990 if (copy_from_user(rwbuf
, argp
, sizeof(rwbuf
))) {
991 SSMDBG("copy_from_user failed.");
996 memset(ssmd_status
, 0, sizeof(ssmd_status
));
997 strncpy(ssmd_status
, &rwbuf
[1], sizeof(ssmd_status
)-1);
1001 if ((rwbuf
[0] < 2) || (rwbuf
[0] > (RWBUF_SIZE
-1))) {
1002 SSMDBG("invalid argument.");
1005 ret
= I2C_TxData(&rwbuf
[1], rwbuf
[0]);
1011 case ECS_IOCTL_READ
:
1013 SSMDBG("invalid argument.");
1017 if (copy_from_user(rwbuf
, argp
, sizeof(rwbuf
))) {
1018 SSMDBG("copy_from_user failed.");
1022 if ((rwbuf
[0] < 1) || (rwbuf
[0] > (RWBUF_SIZE
-1))) {
1023 SSMDBG("invalid argument.");
1026 ret
= I2C_RxData(&rwbuf
[1], rwbuf
[0]);
1030 if (copy_to_user(argp
, rwbuf
, rwbuf
[0]+1)) {
1031 SSMDBG("copy_to_user failed.");
1036 case ECS_IOCTL_SET_MODE
:
1038 SSMDBG("invalid argument.");
1041 if (copy_from_user(&mode
, argp
, sizeof(mode
))) {
1042 SSMDBG("copy_from_user failed.");
1045 ret
= ECS_SetMode(mode
);
1051 case ECS_IOCTL_GETDATA
:
1052 ret
= ECS_GetData(mdata
);
1057 if (copy_to_user(argp
, mdata
, sizeof(mdata
))) {
1058 SSMDBG("copy_to_user failed.");
1063 case ECS_IOCTL_SET_YPR
:
1065 SSMDBG("invalid argument.");
1068 if (copy_from_user(value
, argp
, sizeof(value
))) {
1069 SSMDBG("copy_from_user failed.");
1072 ECS_SaveData(value
);
1075 case ECS_IOCTL_GET_OPEN_STATUS
:
1076 status
= ECS_GetOpenStatus();
1077 SSMDBG("ECS_GetOpenStatus returned (%d)", status
);
1078 if (copy_to_user(argp
, &status
, sizeof(status
))) {
1079 SSMDBG("copy_to_user failed.");
1084 case ECS_IOCTL_GET_CLOSE_STATUS
:
1085 status
= ECS_GetCloseStatus();
1086 SSMDBG("ECS_GetCloseStatus returned (%d)", status
);
1087 if (copy_to_user(argp
, &status
, sizeof(status
))) {
1088 SSMDBG("copy_to_user failed.");
1093 case ECS_IOCTL_GET_DELAY
:
1095 if (copy_to_user(argp
, &delay
, sizeof(delay
))) {
1096 SSMDBG("copy_to_user failed.");
1101 case ECS_IOCTL_GET_PROJECT_NAME
:
1103 printk(KERN_ERR
"S62X IO parameter pointer is NULL!\n");
1107 sprintf(buff
, PROJECT_ID
);
1108 status
= ECS_ReadChipInfo(buff
+ sizeof(PROJECT_ID
), S62X_BUFSIZE
- sizeof(PROJECT_ID
));
1109 status
= status
< 0 ? sizeof(PROJECT_ID
) : sizeof(PROJECT_ID
) + status
+ 1;
1110 if (copy_to_user(argp
, buff
, status
)) {
1116 printk(KERN_ERR
"S62X %s not supported = 0x%04x\n", __FUNCTION__
, cmd
);
1117 return -ENOIOCTLCMD
;
1124 /*----------------------------------------------------------------------------*/
1125 static struct file_operations s62x_fops
= {
1126 #ifndef MTK_ANDROID_4
1127 .owner
= THIS_MODULE
,
1130 .release
= s62x_release
,
1131 #ifndef MTK_ANDROID_4
1132 .ioctl
= s62x_ioctl
,
1134 .unlocked_ioctl
= s62x_unlocked_ioctl
,
1138 /*----------------------------------------------------------------------------*/
1139 static struct miscdevice s62x_device
= {
1140 .minor
= MISC_DYNAMIC_MINOR
,
1145 /*----------------------------------------------------------------------------*/
1146 int s62x_operate(void* self
, uint32_t command
, void* buff_in
, int size_in
,
1147 void* buff_out
, int size_out
, int* actualout
)
1151 hwm_sensor_data
* msensor_data
;
1154 struct i2c_client
*client
= this_client
;
1155 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
1159 if (atomic_read(&data
->trace
) & SS_FUN_DEBUG
) {
1160 SSMFUNC("s62x_operate");
1166 if ((buff_in
== NULL
) || (size_in
< sizeof(int))) {
1167 printk(KERN_ERR
"S62X Set delay parameter error!\n");
1170 value
= *(int *)buff_in
;
1179 if ((buff_in
== NULL
) || (size_in
< sizeof(int))) {
1180 printk(KERN_ERR
"S62X Enable sensor parameter error!\n");
1184 value
= *(int *)buff_in
;
1187 atomic_set(&m_flag
, 1);
1188 atomic_set(&open_flag
, 1);
1190 atomic_set(&m_get_data
, 0);
1191 atomic_set(&m_flag
, 0);
1192 if (atomic_read(&o_flag
) == 0) {
1193 atomic_set(&open_flag
, 0);
1200 case SENSOR_GET_DATA
:
1201 atomic_inc(&m_get_data
);
1202 if ((buff_out
== NULL
) || (size_out
< sizeof(hwm_sensor_data
))) {
1203 printk(KERN_ERR
"S62X get sensor data parameter error!\n");
1206 msensor_data
= (hwm_sensor_data
*)buff_out
;
1207 mutex_lock(&sensor_data_mutex
);
1209 msensor_data
->values
[0] = sensor_data
[9] * CONVERT_M
;
1210 msensor_data
->values
[1] = sensor_data
[10] * CONVERT_M
;
1211 msensor_data
->values
[2] = sensor_data
[11] * CONVERT_M
;
1212 msensor_data
->status
= sensor_data
[4];
1213 msensor_data
->value_divide
= CONVERT_M_DIV
;
1215 mutex_unlock(&sensor_data_mutex
);
1217 if (atomic_read(&data
->trace
) & SS_HWM_DEBUG
) {
1218 SSMDBG("Hwm get m-sensor data: %d, %d, %d. divide %d, status %d!",
1219 msensor_data
->values
[0],msensor_data
->values
[1],msensor_data
->values
[2],
1220 msensor_data
->value_divide
,msensor_data
->status
);
1227 printk(KERN_ERR
"S62X msensor operate function no this parameter %d!\n", command
);
1235 /*----------------------------------------------------------------------------*/
1236 int s62x_orientation_operate(void* self
, uint32_t command
, void* buff_in
, int size_in
,
1237 void* buff_out
, int size_out
, int* actualout
)
1241 hwm_sensor_data
* osensor_data
;
1243 struct i2c_client
*client
= this_client
;
1244 struct s62x_i2c_data
*data
= i2c_get_clientdata(client
);
1248 if (atomic_read(&data
->trace
) & SS_FUN_DEBUG
) {
1249 SSMFUNC("s62x_orientation_operate");
1256 if ((buff_in
== NULL
) || (size_in
< sizeof(int))) {
1257 printk(KERN_ERR
"S62X Set delay parameter error!\n");
1260 value
= *(int *)buff_in
;
1269 if ((buff_in
== NULL
) || (size_in
< sizeof(int))) {
1270 printk(KERN_ERR
"S62X Enable sensor parameter error!\n");
1274 value
= *(int *)buff_in
;
1277 atomic_set(&o_flag
, 1);
1278 atomic_set(&open_flag
, 1);
1280 atomic_set(&o_get_data
, 0);
1281 atomic_set(&o_flag
, 0);
1282 if (atomic_read(&m_flag
) == 0) {
1283 atomic_set(&open_flag
, 0);
1290 case SENSOR_GET_DATA
:
1291 atomic_inc(&o_get_data
);
1292 if ((buff_out
== NULL
) || (size_out
< sizeof(hwm_sensor_data
))) {
1293 printk(KERN_ERR
"S62X get sensor data parameter error!\n");
1296 osensor_data
= (hwm_sensor_data
*)buff_out
;
1297 mutex_lock(&sensor_data_mutex
);
1299 osensor_data
->values
[0] = sensor_data
[0] * CONVERT_O
;
1300 osensor_data
->values
[1] = sensor_data
[1] * CONVERT_O
;
1301 osensor_data
->values
[2] = sensor_data
[2] * CONVERT_O
;
1302 osensor_data
->status
= sensor_data
[4];
1303 osensor_data
->value_divide
= CONVERT_O_DIV
;
1305 mutex_unlock(&sensor_data_mutex
);
1307 if (atomic_read(&data
->trace
) & SS_HWM_DEBUG
) {
1308 SSMDBG("Hwm get o-sensor data: %d, %d, %d. divide %d, status %d!",
1309 osensor_data
->values
[0],osensor_data
->values
[1],osensor_data
->values
[2],
1310 osensor_data
->value_divide
,osensor_data
->status
);
1316 printk(KERN_ERR
"S62X gsensor operate function no this parameter %d!\n", command
);
1324 #ifndef CONFIG_HAS_EARLYSUSPEND
1326 /*----------------------------------------------------------------------------*/
1327 static int s62x_suspend(struct i2c_client
*client
, pm_message_t msg
)
1330 struct s62x_i2c_data
*obj
= i2c_get_clientdata(client
)
1333 if (msg
.event
== PM_EVENT_SUSPEND
) {
1334 s62x_power(obj
->hw
, 0);
1339 /*----------------------------------------------------------------------------*/
1340 static int s62x_resume(struct i2c_client
*client
)
1343 struct s62x_i2c_data
*obj
= i2c_get_clientdata(client
)
1346 s62x_power(obj
->hw
, 1);
1352 #else /*CONFIG_HAS_EARLY_SUSPEND is defined*/
1354 /*----------------------------------------------------------------------------*/
1355 static void s62x_early_suspend(struct early_suspend
*h
)
1357 struct s62x_i2c_data
*obj
= container_of(h
, struct s62x_i2c_data
, early_drv
);
1360 printk(KERN_ERR
"S62X null pointer!!\n");
1365 /*----------------------------------------------------------------------------*/
1366 static void s62x_late_resume(struct early_suspend
*h
)
1368 struct s62x_i2c_data
*obj
= container_of(h
, struct s62x_i2c_data
, early_drv
);
1371 printk(KERN_ERR
"S62X null pointer!!\n");
1375 s62x_power(obj
->hw
, 1);
1378 #endif /*CONFIG_HAS_EARLYSUSPEND*/
1380 /*----------------------------------------------------------------------------*/
1381 #ifndef MTK_ANDROID_4
1382 static int s62x_i2c_detect(struct i2c_client
*client
, int kind
, struct i2c_board_info
*info
)
1384 static int s62x_i2c_detect(struct i2c_client
*client
, struct i2c_board_info
*info
)
1387 strcpy(info
->type
, S62X_DEV_NAME
);
1391 /*----------------------------------------------------------------------------*/
1392 #ifdef _MAGIC_KPT_COMMAND
1393 static int magic_kpt_command(const struct i2c_client
*client
)
1395 char cmd1
[] = { 0x0A, 0x00 };
1396 char cmd2
[] = { 0x0F, 0x1B };
1397 struct i2c_msg msg
[] = {
1399 .addr
= S62X_I2C_ADDR1
,
1401 .len
= sizeof(cmd1
),
1405 .addr
= S62X_I2C_ADDR1
,
1407 .len
= sizeof(cmd2
),
1412 return i2c_transfer(client
->adapter
, msg
, 2);
1416 /*----------------------------------------------------------------------------*/
1417 #ifdef USE_ALTERNATE_ADDRESS
1418 static int s62x_change_address(const struct i2c_client
*client
)
1421 char cmd
[] = { S62X_IDX_ECO1
, ECO1_DEFAULT
};
1422 struct i2c_msg msg
[] = {
1424 .addr
= S62X_I2C_ADDR1
,
1431 for (loop_i
= 0; loop_i
< 3; loop_i
++) {
1432 if (i2c_transfer(client
->adapter
, msg
, 1) > 0) {
1438 //printk(KERN_ERR "S62X change address retry over %d\n", loop_i);
1443 /*----------------------------------------------------------------------------*/
1444 static int s62x_i2c_probe(struct i2c_client
*client
, const struct i2c_device_id
*id
)
1446 struct i2c_client
*new_client
;
1447 struct s62x_i2c_data
*data
;
1449 struct hwmsen_object sobj_m
, sobj_o
;
1451 if (!(data
= kmalloc(sizeof(struct s62x_i2c_data
), GFP_KERNEL
))) {
1455 memset(data
, 0, sizeof(struct s62x_i2c_data
));
1456 data
->hw
= get_cust_mag_hw();
1458 if (hwmsen_get_convert(L2CVTI(data
->hw
->direction
), &data
->cvt
)) {
1459 printk(KERN_ERR
"S62X invalid direction: %d\n", data
->hw
->direction
);
1460 goto exit_init_failed
;
1463 atomic_set(&data
->layout
, data
->hw
->direction
);
1464 atomic_set(&data
->trace
, 0x0000);
1466 mutex_init(&last_m_data_mutex
);
1467 mutex_init(&sensor_data_mutex
);
1469 init_waitqueue_head(&open_wq
);
1471 data
->client
= client
;
1472 new_client
= data
->client
;
1473 i2c_set_clientdata(new_client
, data
);
1475 this_client
= new_client
;
1476 this_client
->timing
= 100;
1478 #ifdef _MAGIC_KPT_COMMAND
1479 magic_kpt_command(client
);
1482 #ifdef USE_ALTERNATE_ADDRESS
1483 err
= s62x_change_address(client
);
1484 printk(KERN_ERR
"S62X address change %s\n", err
== 0 ? "OK" : "NG");
1487 #ifdef _FORCE_PROBE_ERROR
1488 printk(KERN_ERR
"S62X force probe error\n");
1492 /* Check connection */
1493 if (ECS_CheckDevice() != 0) {
1494 printk(KERN_ERR
"S62X check device connect error\n");
1496 atomic_set(&init_phase
, 1);
1497 if (ECS_InitDevice() != 0) {
1498 printk(KERN_ERR
"S62X init device error\n");
1499 } else atomic_set(&init_phase
, 0);
1502 /* Register sysfs attribute */
1503 if ((err
= s62x_create_attr(&ssm_sensor_driver
.driver
)) != 0) {
1504 printk(KERN_ERR
"S62X create attribute err = %d\n", err
);
1505 goto exit_sysfs_create_group_failed
;
1508 #ifdef ENABLE_DUALSTACK_MODE
1509 if (atomic_read(&init_phase
) == 2) {
1510 printk(KERN_ERR
"S62X dual stack mode exit\n");
1511 goto exit_init_failed
;
1515 if ((err
= misc_register(&s62x_device
)) != 0) {
1516 printk(KERN_ERR
"S62X device register failed\n");
1517 goto exit_misc_device_register_failed
;
1522 sobj_m
.sensor_operate
= s62x_operate
;
1523 if ((err
= hwmsen_attach(ID_MAGNETIC
, &sobj_m
)) != 0) {
1524 printk(KERN_ERR
"S62X attach fail = %d\n", err
);
1530 sobj_o
.sensor_operate
= s62x_orientation_operate
;
1531 if ((err
= hwmsen_attach(ID_ORIENTATION
, &sobj_o
)) != 0) {
1532 printk(KERN_ERR
"S62X attach fail = %d\n", err
);
1536 #if CONFIG_HAS_EARLYSUSPEND
1537 data
->early_drv
.level
= EARLY_SUSPEND_LEVEL_DISABLE_FB
- 1,
1538 data
->early_drv
.suspend
= s62x_early_suspend
,
1539 data
->early_drv
.resume
= s62x_late_resume
,
1540 register_early_suspend(&data
->early_drv
);
1543 SSMDBG("%s: %s", __func__
, atomic_read(&init_phase
) ? "NG" : "OK");
1546 exit_sysfs_create_group_failed
:
1548 exit_misc_device_register_failed
:
1553 printk(KERN_ERR
"S62X %s: err = %d\n", __func__
, err
);
1557 /*----------------------------------------------------------------------------*/
1558 static int s62x_i2c_remove(struct i2c_client
*client
)
1562 if ((err
= s62x_delete_attr(&ssm_sensor_driver
.driver
)) != 0) {
1563 printk(KERN_ERR
"S62X delete_attr fail: %d\n", err
);
1567 i2c_unregister_device(client
);
1568 kfree(i2c_get_clientdata(client
));
1569 misc_deregister(&s62x_device
);
1573 /*----------------------------------------------------------------------------*/
1574 static int ssm_probe(struct platform_device
*pdev
)
1576 struct mag_hw
*hw
= get_cust_mag_hw();
1580 atomic_set(&dev_open_count
, 0);
1581 #ifndef MTK_ANDROID_4
1582 s62x_force
[0] = hw
->i2c_num
;
1585 if (i2c_add_driver(&s62x_i2c_driver
)) {
1586 printk(KERN_ERR
"S62X add driver error\n");
1592 /*----------------------------------------------------------------------------*/
1593 static int ssm_remove(struct platform_device
*pdev
)
1595 struct mag_hw
*hw
= get_cust_mag_hw();
1598 atomic_set(&dev_open_count
, 0);
1599 i2c_del_driver(&s62x_i2c_driver
);
1603 /*----------------------------------------------------------------------------*/
1604 static int __init
s62x_init(void)
1606 #ifdef MTK_ANDROID_4
1607 struct mag_hw
*hw
= get_cust_mag_hw();
1608 printk("%s: i2c_number=%d\n", __func__
,hw
->i2c_num
);
1609 i2c_register_board_info(hw
->i2c_num
, &i2c_s62x
, 1);
1611 if (platform_driver_register(&ssm_sensor_driver
)) {
1612 printk(KERN_ERR
"S62X failed to register driver\n");
1618 /*----------------------------------------------------------------------------*/
1619 static void __exit
s62x_exit(void)
1621 platform_driver_unregister(&ssm_sensor_driver
);
1624 /*----------------------------------------------------------------------------*/
1625 module_init(s62x_init
);
1626 module_exit(s62x_exit
);
1628 MODULE_DESCRIPTION("S62X Compass Driver");
1629 MODULE_LICENSE("GPL");
1630 MODULE_VERSION(DRIVER_VERSION
);