Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | #include "accdet.h" |
2 | ||
3 | //#include <mach/mt_boot.h> | |
4 | #include <cust_eint.h> | |
5 | #include <cust_gpio_usage.h> | |
6 | #include <mach/mt_gpio.h> | |
7 | #include <mach/eint.h> | |
8 | ||
9 | ||
10 | #define SW_WORK_AROUND_ACCDET_REMOTE_BUTTON_ISSUE | |
11 | #define DEBUG_THREAD 1 | |
12 | ||
13 | /*---------------------------------------------------------------------- | |
14 | static variable defination | |
15 | ----------------------------------------------------------------------*/ | |
16 | ||
17 | #define REGISTER_VALUE(x) (x - 1) | |
18 | ||
19 | ||
20 | static int button_press_debounce = 0x400; | |
21 | ||
22 | static int debug_enable = 1; | |
23 | ||
24 | struct headset_mode_settings *cust_headset_settings = NULL; | |
25 | ||
26 | #define ACCDET_DEBUG(format, args...) do{ \ | |
27 | if(debug_enable) \ | |
28 | {\ | |
29 | printk(KERN_WARNING format,##args);\ | |
30 | }\ | |
31 | }while(0) | |
32 | ||
33 | static struct switch_dev accdet_data; | |
34 | static struct input_dev *kpd_accdet_dev; | |
35 | static struct cdev *accdet_cdev; | |
36 | static struct class *accdet_class = NULL; | |
37 | static struct device *accdet_nor_device = NULL; | |
38 | ||
39 | static dev_t accdet_devno; | |
40 | ||
41 | static int pre_status = 0; | |
42 | static int pre_state_swctrl = 0; | |
43 | static int accdet_status = PLUG_OUT; | |
44 | static int cable_type = 0; | |
45 | #if defined ACCDET_EINT && defined ACCDET_PIN_RECOGNIZATION | |
46 | //add for new feature PIN recognition | |
47 | static int cable_pin_recognition = 0; | |
48 | static int show_icon_delay = 0; | |
49 | #endif | |
50 | ||
51 | //ALPS443614: EINT trigger during accdet irq flow running, need add sync method | |
52 | //between both | |
53 | static int eint_accdet_sync_flag = 0; | |
54 | ||
55 | static s64 long_press_time_ns = 0 ; | |
56 | ||
57 | static int g_accdet_first = 1; | |
58 | static bool IRQ_CLR_FLAG = FALSE; | |
59 | static volatile int call_status =0; | |
60 | static volatile int button_status = 0; | |
61 | ||
62 | ||
63 | struct wake_lock accdet_suspend_lock; | |
64 | struct wake_lock accdet_irq_lock; | |
65 | struct wake_lock accdet_key_lock; | |
66 | struct wake_lock accdet_timer_lock; | |
67 | ||
68 | ||
69 | static struct work_struct accdet_work; | |
70 | static struct workqueue_struct * accdet_workqueue = NULL; | |
71 | ||
72 | static int long_press_time; | |
73 | ||
74 | static DEFINE_MUTEX(accdet_eint_irq_sync_mutex); | |
75 | ||
76 | static inline void clear_accdet_interrupt(void); | |
77 | ||
78 | #ifdef ACCDET_EINT | |
79 | ||
80 | #ifndef ACCDET_MULTI_KEY_FEATURE | |
81 | static int g_accdet_working_in_suspend =0; | |
82 | #endif | |
83 | ||
84 | static struct work_struct accdet_eint_work; | |
85 | static struct workqueue_struct * accdet_eint_workqueue = NULL; | |
86 | ||
87 | static inline void accdet_init(void); | |
88 | ||
89 | ||
90 | #ifdef ACCDET_LOW_POWER | |
91 | ||
92 | #include <linux/timer.h> | |
93 | #define MICBIAS_DISABLE_TIMER (6 *HZ) //6 seconds | |
94 | struct timer_list micbias_timer; | |
95 | static void disable_micbias(unsigned long a); | |
96 | /* Used to let accdet know if the pin has been fully plugged-in */ | |
97 | #define EINT_PIN_PLUG_IN (1) | |
98 | #define EINT_PIN_PLUG_OUT (0) | |
99 | int cur_eint_state = EINT_PIN_PLUG_OUT; | |
100 | static struct work_struct accdet_disable_work; | |
101 | static struct workqueue_struct * accdet_disable_workqueue = NULL; | |
102 | ||
103 | #endif | |
104 | ||
105 | #endif//end ACCDET_EINT | |
106 | ||
107 | extern S32 pwrap_read( U32 adr, U32 *rdata ); | |
108 | extern S32 pwrap_write( U32 adr, U32 wdata ); | |
109 | extern struct headset_mode_settings* get_cust_headset_settings(void); | |
110 | extern struct headset_key_custom* get_headset_key_custom_setting(void); | |
111 | extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); | |
112 | extern struct file_operations *accdet_get_fops(void);//from accdet_drv.c | |
113 | extern struct platform_driver accdet_driver_func(void);//from accdet_drv.c | |
114 | ||
115 | #ifdef DEBUG_THREAD | |
116 | extern void accdet_create_attr_func(void); //from accdet_drv.c | |
117 | #endif | |
118 | static U32 pmic_pwrap_read(U32 addr); | |
119 | static void pmic_pwrap_write(U32 addr, unsigned int wdata); | |
120 | ||
121 | ||
122 | /****************************************************************/ | |
123 | /*** export function **/ | |
124 | /****************************************************************/ | |
125 | ||
126 | void accdet_detect(void) | |
127 | { | |
128 | int ret = 0 ; | |
129 | ||
130 | ACCDET_DEBUG("[Accdet]accdet_detect\n"); | |
131 | ||
132 | accdet_status = PLUG_OUT; | |
133 | ret = queue_work(accdet_workqueue, &accdet_work); | |
134 | if(!ret) | |
135 | { | |
136 | ACCDET_DEBUG("[Accdet]accdet_detect:accdet_work return:%d!\n", ret); | |
137 | } | |
138 | ||
139 | return; | |
140 | } | |
141 | EXPORT_SYMBOL(accdet_detect); | |
142 | ||
143 | void accdet_state_reset(void) | |
144 | { | |
145 | ||
146 | ACCDET_DEBUG("[Accdet]accdet_state_reset\n"); | |
147 | ||
148 | accdet_status = PLUG_OUT; | |
149 | cable_type = NO_DEVICE; | |
150 | ||
151 | return; | |
152 | } | |
153 | EXPORT_SYMBOL(accdet_state_reset); | |
154 | ||
155 | int accdet_get_cable_type(void) | |
156 | { | |
157 | return cable_type; | |
158 | } | |
159 | void accdet_auxadc_switch(int enable) | |
160 | { | |
161 | if (enable) { | |
162 | #ifndef ACCDET_28V_MODE | |
163 | pmic_pwrap_write(ACCDET_RSV, ACCDET_1V9_MODE_ON); | |
164 | ACCDET_DEBUG("ACCDET enable switch in 1.9v mode \n"); | |
165 | #else | |
166 | #ifdef CONFIG_MTK_PMIC_MT6397 | |
167 | pmic_pwrap_write(0x732, ACCDET_2V8_MODE_ON); | |
168 | #else | |
169 | pmic_pwrap_write(ACCDET_RSV, ACCDET_2V8_MODE_ON); | |
170 | #endif | |
171 | ACCDET_DEBUG("ACCDET enable switch in 2.8v mode \n"); | |
172 | #endif | |
173 | }else { | |
174 | #ifndef ACCDET_28V_MODE | |
175 | pmic_pwrap_write(ACCDET_RSV, ACCDET_1V9_MODE_OFF); | |
176 | ACCDET_DEBUG("ACCDET diable switch in 1.9v mode \n"); | |
177 | #else | |
178 | #ifdef CONFIG_MTK_PMIC_MT6397 | |
179 | pmic_pwrap_write(0x732, 0); | |
180 | #else | |
181 | pmic_pwrap_write(ACCDET_RSV, ACCDET_2V8_MODE_OFF); | |
182 | #endif | |
183 | ACCDET_DEBUG("ACCDET diable switch in 2.8v mode \n"); | |
184 | #endif | |
185 | } | |
186 | ||
187 | } | |
188 | ||
189 | /****************************************************************/ | |
190 | /*******static function defination **/ | |
191 | /****************************************************************/ | |
192 | // pmic wrap read and write func | |
193 | static U32 pmic_pwrap_read(U32 addr) | |
194 | { | |
195 | ||
196 | U32 val =0; | |
197 | pwrap_read(addr, &val); | |
198 | //ACCDET_DEBUG("[Accdet]wrap write func addr=0x%x, val=0x%x\n", addr, val); | |
199 | return val; | |
200 | ||
201 | } | |
202 | ||
203 | static void pmic_pwrap_write(unsigned int addr, unsigned int wdata) | |
204 | ||
205 | { | |
206 | pwrap_write(addr, wdata); | |
207 | //ACCDET_DEBUG("[Accdet]wrap write func addr=0x%x, wdate=0x%x\n", addr, wdata); | |
208 | } | |
209 | #ifndef ACCDET_MULTI_KEY_FEATURE | |
210 | //detect if remote button is short pressed or long pressed | |
211 | static bool is_long_press(void) | |
212 | { | |
213 | int current_status = 0; | |
214 | int index = 0; | |
215 | int count = long_press_time / 100; | |
216 | while(index++ < count) | |
217 | { | |
218 | current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); | |
219 | if(current_status != 0) | |
220 | { | |
221 | return false; | |
222 | } | |
223 | ||
224 | msleep(100); | |
225 | } | |
226 | ||
227 | return true; | |
228 | } | |
229 | #endif | |
230 | #ifdef ACCDET_PIN_RECOGNIZATION | |
231 | static void headset_standard_judge_message(void) | |
232 | { | |
233 | ACCDET_DEBUG("[Accdet]Dear user: You plug in a headset which this phone doesn't support!!\n"); | |
234 | ||
235 | } | |
236 | #endif | |
237 | ||
238 | #ifdef ACCDET_PIN_SWAP | |
239 | ||
240 | static void accdet_FSA8049_enable(void) | |
241 | { | |
242 | #ifndef MTK_ALPS_BOX_SUPPORT | |
243 | mt_set_gpio_mode(GPIO_FSA8049_PIN, GPIO_FSA8049_PIN_M_GPIO); | |
244 | mt_set_gpio_dir(GPIO_FSA8049_PIN, GPIO_DIR_OUT); | |
245 | mt_set_gpio_out(GPIO_FSA8049_PIN, GPIO_OUT_ONE); | |
246 | #endif | |
247 | } | |
248 | ||
249 | static void accdet_FSA8049_disable(void) | |
250 | { | |
251 | #ifndef MTK_ALPS_BOX_SUPPORT | |
252 | mt_set_gpio_mode(GPIO_FSA8049_PIN, GPIO_FSA8049_PIN_M_GPIO); | |
253 | mt_set_gpio_dir(GPIO_FSA8049_PIN, GPIO_DIR_OUT); | |
254 | mt_set_gpio_out(GPIO_FSA8049_PIN, GPIO_OUT_ZERO); | |
255 | #endif | |
256 | } | |
257 | ||
258 | ||
259 | #endif | |
260 | static void inline headset_plug_out(void) | |
261 | { | |
262 | accdet_status = PLUG_OUT; | |
263 | cable_type = NO_DEVICE; | |
264 | //update the cable_type | |
265 | switch_set_state((struct switch_dev *)&accdet_data, cable_type); | |
266 | ACCDET_DEBUG( " [accdet] set state in cable_type = NO_DEVICE\n"); | |
267 | ||
268 | } | |
269 | ||
270 | //Accdet only need this func | |
271 | static void inline enable_accdet(u32 state_swctrl) | |
272 | { | |
273 | // enable ACCDET unit | |
274 | ACCDET_DEBUG("accdet: enable_accdet\n"); | |
275 | //enable clock | |
276 | pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR); | |
277 | ||
278 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL)|state_swctrl); | |
279 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_ENABLE); | |
280 | ||
281 | ||
282 | } | |
283 | ||
284 | #ifdef ACCDET_EINT | |
285 | static void inline disable_accdet(void) | |
286 | { | |
287 | int irq_temp = 0; | |
288 | //sync with accdet_irq_handler set clear accdet irq bit to avoid set clear accdet irq bit after disable accdet | |
289 | ||
290 | //disable accdet irq | |
291 | pmic_pwrap_write(INT_CON_ACCDET_CLR, RG_ACCDET_IRQ_CLR); | |
292 | clear_accdet_interrupt(); | |
293 | udelay(200); | |
294 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
295 | while(pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) | |
296 | { | |
297 | ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going....\n"); | |
298 | msleep(5); | |
299 | } | |
300 | irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); | |
301 | irq_temp = irq_temp & (~IRQ_CLR_BIT); | |
302 | pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); | |
303 | ACCDET_DEBUG("[Accdet]disable_accdet:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
304 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
305 | // disable ACCDET unit | |
306 | ACCDET_DEBUG("accdet: disable_accdet\n"); | |
307 | pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL); | |
308 | ||
309 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE); | |
310 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0); | |
311 | //disable clock | |
312 | pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET); | |
313 | } | |
314 | static void disable_micbias(unsigned long a) | |
315 | { | |
316 | int ret = 0; | |
317 | ret = queue_work(accdet_disable_workqueue, &accdet_disable_work); | |
318 | if(!ret) | |
319 | { | |
320 | ACCDET_DEBUG("[Accdet]disable_micbias:accdet_work return:%d!\n", ret); | |
321 | } | |
322 | } | |
323 | static void disable_micbias_callback(struct work_struct *work) | |
324 | { | |
325 | ||
326 | if(cable_type == HEADSET_NO_MIC) { | |
327 | #ifdef ACCDET_PIN_RECOGNIZATION | |
328 | show_icon_delay = 0; | |
329 | cable_pin_recognition = 0; | |
330 | ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); | |
331 | pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); | |
332 | pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh); | |
333 | #endif | |
334 | // setting pwm idle; | |
335 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
336 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, pmic_pwrap_read(ACCDET_STATE_SWCTRL)&~ACCDET_SWCTRL_IDLE_EN); | |
337 | #endif | |
338 | #ifdef ACCDET_PIN_SWAP | |
339 | //accdet_FSA8049_disable(); //disable GPIO209 for PIN swap | |
340 | //ACCDET_DEBUG("[Accdet] FSA8049 disable!\n"); | |
341 | #endif | |
342 | disable_accdet(); | |
343 | ACCDET_DEBUG("[Accdet] more than 5s MICBIAS : Disabled\n"); | |
344 | } | |
345 | #ifdef ACCDET_PIN_RECOGNIZATION | |
346 | else if(cable_type == HEADSET_MIC) { | |
347 | pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); | |
348 | pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_thresh); | |
349 | ACCDET_DEBUG("[Accdet]pin recog after 5s recover micbias polling!\n"); | |
350 | } | |
351 | #endif | |
352 | } | |
353 | ||
354 | static void accdet_eint_work_callback(struct work_struct *work) | |
355 | { | |
356 | #ifndef MTK_ALPS_BOX_SUPPORT | |
357 | //KE under fastly plug in and plug out | |
358 | mt_eint_mask(CUST_EINT_ACCDET_NUM); | |
359 | #endif | |
360 | ||
361 | if (cur_eint_state == EINT_PIN_PLUG_IN) { | |
362 | ACCDET_DEBUG("[Accdet]EINT func :plug-in\n"); | |
363 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
364 | eint_accdet_sync_flag = 1; | |
365 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
366 | #ifdef ACCDET_LOW_POWER | |
367 | wake_lock_timeout(&accdet_timer_lock, 7*HZ); | |
368 | #endif | |
369 | #ifdef ACCDET_28V_MODE | |
370 | pmic_pwrap_write(ACCDET_RSV, ACCDET_2V8_MODE_OFF); | |
371 | ACCDET_DEBUG("ACCDET use in 2.8V mode!! \n"); | |
372 | #endif | |
373 | #ifdef ACCDET_PIN_SWAP | |
374 | pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)|(1<<14)); | |
375 | msleep(800); | |
376 | accdet_FSA8049_enable(); //enable GPIO209 for PIN swap | |
377 | ACCDET_DEBUG("[Accdet] FSA8049 enable!\n"); | |
378 | msleep(250); //PIN swap need ms | |
379 | #endif | |
380 | ||
381 | accdet_init();// do set pwm_idle on in accdet_init | |
382 | ||
383 | #ifdef ACCDET_PIN_RECOGNIZATION | |
384 | show_icon_delay = 1; | |
385 | //micbias always on during detected PIN recognition | |
386 | pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); | |
387 | pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width); | |
388 | ACCDET_DEBUG("[Accdet]pin recog start! micbias always on!\n"); | |
389 | #endif | |
390 | //set PWM IDLE on | |
391 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
392 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL)|ACCDET_SWCTRL_IDLE_EN)); | |
393 | #endif | |
394 | //enable ACCDET unit | |
395 | enable_accdet(ACCDET_SWCTRL_EN); | |
396 | } else { | |
397 | //EINT_PIN_PLUG_OUT | |
398 | //Disable ACCDET | |
399 | ACCDET_DEBUG("[Accdet]EINT func :plug-out\n"); | |
400 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
401 | eint_accdet_sync_flag = 0; | |
402 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
403 | ||
404 | #ifdef ACCDET_LOW_POWER | |
405 | del_timer_sync(&micbias_timer); | |
406 | #endif | |
407 | #ifdef ACCDET_PIN_RECOGNIZATION | |
408 | show_icon_delay = 0; | |
409 | cable_pin_recognition = 0; | |
410 | #endif | |
411 | #ifdef ACCDET_PIN_SWAP | |
412 | pmic_pwrap_write(0x0400, pmic_pwrap_read(0x0400)&~(1<<14)); | |
413 | accdet_FSA8049_disable(); //disable GPIO209 for PIN swap | |
414 | ACCDET_DEBUG("[Accdet] FSA8049 disable!\n"); | |
415 | #endif | |
416 | accdet_auxadc_switch(0); | |
417 | disable_accdet(); | |
418 | headset_plug_out(); | |
419 | #ifdef ACCDET_28V_MODE | |
420 | pmic_pwrap_write(ACCDET_RSV, ACCDET_1V9_MODE_OFF); | |
421 | ACCDET_DEBUG("ACCDET use in 1.9V mode!! \n"); | |
422 | #endif | |
423 | ||
424 | } | |
425 | //unmask EINT | |
426 | //msleep(500); | |
427 | #ifndef MTK_ALPS_BOX_SUPPORT | |
428 | mt_eint_unmask(CUST_EINT_ACCDET_NUM); | |
429 | #endif | |
430 | ACCDET_DEBUG("[Accdet]eint unmask !!!!!!\n"); | |
431 | ||
432 | } | |
433 | ||
434 | ||
435 | static void accdet_eint_func(void) | |
436 | { | |
437 | int ret=0; | |
438 | if(cur_eint_state == EINT_PIN_PLUG_IN ) | |
439 | { | |
440 | #ifndef MTK_ALPS_BOX_SUPPORT | |
441 | /* | |
442 | To trigger EINT when the headset was plugged in | |
443 | We set the polarity back as we initialed. | |
444 | */ | |
445 | if (CUST_EINT_ACCDET_TYPE == CUST_EINTF_TRIGGER_HIGH){ | |
446 | mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, (1)); | |
447 | }else{ | |
448 | mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, (0)); | |
449 | } | |
450 | ||
451 | #ifdef ACCDET_SHORT_PLUGOUT_DEBOUNCE | |
452 | mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_CN); | |
453 | #endif | |
454 | ||
455 | #endif | |
456 | /* update the eint status */ | |
457 | cur_eint_state = EINT_PIN_PLUG_OUT; | |
458 | //#ifdef ACCDET_LOW_POWER | |
459 | // del_timer_sync(&micbias_timer); | |
460 | //#endif | |
461 | } | |
462 | else | |
463 | { | |
464 | #ifndef MTK_ALPS_BOX_SUPPORT | |
465 | /* | |
466 | To trigger EINT when the headset was plugged out | |
467 | We set the opposite polarity to what we initialed. | |
468 | */ | |
469 | if (CUST_EINT_ACCDET_TYPE == CUST_EINTF_TRIGGER_HIGH){ | |
470 | mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, !(1)); | |
471 | }else{ | |
472 | mt_eint_set_polarity(CUST_EINT_ACCDET_NUM, !(0)); | |
473 | } | |
474 | /* update the eint status */ | |
475 | #ifdef ACCDET_SHORT_PLUGOUT_DEBOUNCE | |
476 | mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, ACCDET_SHORT_PLUGOUT_DEBOUNCE_CN); | |
477 | #endif | |
478 | #endif | |
479 | cur_eint_state = EINT_PIN_PLUG_IN; | |
480 | ||
481 | #ifdef ACCDET_LOW_POWER | |
482 | //INIT the timer to disable micbias. | |
483 | ||
484 | init_timer(&micbias_timer); | |
485 | micbias_timer.expires = jiffies + MICBIAS_DISABLE_TIMER; | |
486 | micbias_timer.function = &disable_micbias; | |
487 | micbias_timer.data = ((unsigned long) 0 ); | |
488 | add_timer(&micbias_timer); | |
489 | ||
490 | #endif | |
491 | } | |
492 | ||
493 | ret = queue_work(accdet_eint_workqueue, &accdet_eint_work); | |
494 | if(!ret) | |
495 | { | |
496 | //ACCDET_DEBUG("[Accdet]accdet_eint_func:accdet_work return:%d!\n", ret); | |
497 | } | |
498 | } | |
499 | ||
500 | ||
501 | static inline int accdet_setup_eint(void) | |
502 | { | |
503 | ||
504 | /*configure to GPIO function, external interrupt*/ | |
505 | ACCDET_DEBUG("[Accdet]accdet_setup_eint\n"); | |
506 | ||
507 | #ifndef MTK_ALPS_BOX_SUPPORT | |
508 | mt_set_gpio_mode(GPIO_ACCDET_EINT_PIN, GPIO_ACCDET_EINT_PIN_M_EINT); | |
509 | mt_set_gpio_dir(GPIO_ACCDET_EINT_PIN, GPIO_DIR_IN); | |
510 | mt_set_gpio_pull_enable(GPIO_ACCDET_EINT_PIN, GPIO_PULL_DISABLE); //To disable GPIO PULL. | |
511 | ||
512 | mt_eint_set_hw_debounce(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_CN); | |
513 | mt_eint_registration(CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_TYPE, accdet_eint_func, 0); | |
514 | ACCDET_DEBUG("[Accdet]accdet set EINT finished, accdet_eint_num=%d, accdet_eint_debounce_en=%d, accdet_eint_polarity=%d\n", CUST_EINT_ACCDET_NUM, CUST_EINT_ACCDET_DEBOUNCE_EN, CUST_EINT_ACCDET_TYPE); | |
515 | ||
516 | mt_eint_unmask(CUST_EINT_ACCDET_NUM); | |
517 | #endif | |
518 | return 0; | |
519 | } | |
520 | ||
521 | #endif//endif ACCDET_EINT | |
522 | ||
523 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
524 | extern int PMIC_IMM_GetOneChannelValue(int dwChannel, int deCount, int trimd); | |
525 | ||
526 | #define KEY_SAMPLE_PERIOD (60) //ms | |
527 | #ifdef CONFIG_MTK_PMIC_MT6397 | |
528 | #define MULTIKEY_ADC_CHANNEL (5) | |
529 | #else | |
530 | #define MULTIKEY_ADC_CHANNEL (8) | |
531 | #endif | |
532 | ||
533 | #define NO_KEY (0x0) | |
534 | #define UP_KEY (0x01) | |
535 | #define MD_KEY (0x02) | |
536 | #define DW_KEY (0x04) | |
537 | ||
538 | #define SHORT_PRESS (0x0) | |
539 | #define LONG_PRESS (0x10) | |
540 | #define SHORT_UP ((UP_KEY) | SHORT_PRESS) | |
541 | #define SHORT_MD ((MD_KEY) | SHORT_PRESS) | |
542 | #define SHORT_DW ((DW_KEY) | SHORT_PRESS) | |
543 | #define LONG_UP ((UP_KEY) | LONG_PRESS) | |
544 | #define LONG_MD ((MD_KEY) | LONG_PRESS) | |
545 | #define LONG_DW ((DW_KEY) | LONG_PRESS) | |
546 | ||
547 | #define KEYDOWN_FLAG 1 | |
548 | #define KEYUP_FLAG 0 | |
549 | //static int g_adcMic_channel_num =0; | |
550 | ||
551 | ||
552 | static DEFINE_MUTEX(accdet_multikey_mutex); | |
553 | ||
554 | ||
555 | ||
556 | /* | |
557 | ||
558 | MD UP DW | |
559 | |---------|-----------|----------| | |
560 | 0V<=MD< 0.09V<= UP<0.24V<=DW <0.5V | |
561 | ||
562 | */ | |
563 | ||
564 | #define DW_KEY_HIGH_THR (500) //0.50v=500000uv | |
565 | #define DW_KEY_THR (240) //0.24v=240000uv | |
566 | #define UP_KEY_THR (90) //0.09v=90000uv | |
567 | #define MD_KEY_THR (0) | |
568 | ||
569 | static int key_check(int b) | |
570 | { | |
571 | //ACCDET_DEBUG("adc_data: %d v\n",b); | |
572 | ||
573 | /* 0.24V ~ */ | |
574 | ACCDET_DEBUG("accdet: come in key_check!!\n"); | |
575 | if((b<DW_KEY_HIGH_THR)&&(b >= DW_KEY_THR)) | |
576 | { | |
577 | ACCDET_DEBUG("adc_data: %d mv\n",b); | |
578 | return DW_KEY; | |
579 | } | |
580 | else if ((b < DW_KEY_THR)&& (b >= UP_KEY_THR)) | |
581 | { | |
582 | ACCDET_DEBUG("adc_data: %d mv\n",b); | |
583 | return UP_KEY; | |
584 | } | |
585 | else if ((b < UP_KEY_THR) && (b >= MD_KEY_THR)) | |
586 | { | |
587 | ACCDET_DEBUG("adc_data: %d mv\n",b); | |
588 | return MD_KEY; | |
589 | } | |
590 | ACCDET_DEBUG("accdet: leave key_check!!\n"); | |
591 | return NO_KEY; | |
592 | } | |
593 | ||
594 | static void send_key_event(int keycode,int flag) | |
595 | { | |
596 | if(call_status == 0) | |
597 | { | |
598 | switch (keycode) | |
599 | { | |
600 | case DW_KEY: | |
601 | input_report_key(kpd_accdet_dev, KEY_NEXTSONG, flag); | |
602 | input_sync(kpd_accdet_dev); | |
603 | ACCDET_DEBUG("KEY_NEXTSONG %d\n",flag); | |
604 | break; | |
605 | case UP_KEY: | |
606 | input_report_key(kpd_accdet_dev, KEY_PREVIOUSSONG, flag); | |
607 | input_sync(kpd_accdet_dev); | |
608 | ACCDET_DEBUG("KEY_PREVIOUSSONG %d\n",flag); | |
609 | break; | |
610 | } | |
611 | } | |
612 | else | |
613 | { | |
614 | switch (keycode) | |
615 | { | |
616 | case DW_KEY: | |
617 | input_report_key(kpd_accdet_dev, KEY_VOLUMEDOWN, flag); | |
618 | input_sync(kpd_accdet_dev); | |
619 | ACCDET_DEBUG("KEY_VOLUMEDOWN %d\n",flag); | |
620 | break; | |
621 | case UP_KEY: | |
622 | input_report_key(kpd_accdet_dev, KEY_VOLUMEUP, flag); | |
623 | input_sync(kpd_accdet_dev); | |
624 | ACCDET_DEBUG("KEY_VOLUMEUP %d\n",flag); | |
625 | break; | |
626 | } | |
627 | } | |
628 | } | |
629 | static int multi_key_detection(void) | |
630 | { | |
631 | int current_status = 0; | |
632 | int index = 0; | |
633 | int count = long_press_time / (KEY_SAMPLE_PERIOD + 40 ); //ADC delay | |
634 | int m_key = 0; | |
635 | int cur_key = 0; | |
636 | int cali_voltage=0; | |
637 | ||
638 | cali_voltage = PMIC_IMM_GetOneChannelValue(MULTIKEY_ADC_CHANNEL,1,1); | |
639 | ACCDET_DEBUG("[Accdet]adc cali_voltage1 = %d mv\n", cali_voltage); | |
640 | m_key = cur_key = key_check(cali_voltage); | |
641 | ||
642 | send_key_event(m_key, KEYDOWN_FLAG); | |
643 | ||
644 | while(index++ < count) | |
645 | { | |
646 | ||
647 | /* Check if the current state has been changed */ | |
648 | current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); | |
649 | ACCDET_DEBUG("[Accdet]accdet current_status = %d\n", current_status); | |
650 | if(current_status != 0) | |
651 | { | |
652 | send_key_event(m_key, KEYUP_FLAG); | |
653 | return (m_key | SHORT_PRESS); | |
654 | } | |
655 | ||
656 | /* Check if the voltage has been changed (press one key and another) */ | |
657 | //IMM_GetOneChannelValue(g_adcMic_channel_num, adc_data, &adc_raw); | |
658 | cali_voltage = PMIC_IMM_GetOneChannelValue(MULTIKEY_ADC_CHANNEL,1,1); | |
659 | ACCDET_DEBUG("[Accdet]adc in while loop [%d]= %d mv\n", index, cali_voltage); | |
660 | cur_key = key_check(cali_voltage); | |
661 | if(m_key != cur_key) | |
662 | { | |
663 | send_key_event(m_key, KEYUP_FLAG); | |
664 | ACCDET_DEBUG("[Accdet]accdet press one key and another happen!!\n"); | |
665 | return (m_key | SHORT_PRESS); | |
666 | } | |
667 | else | |
668 | { | |
669 | m_key = cur_key; | |
670 | } | |
671 | ||
672 | msleep(KEY_SAMPLE_PERIOD); | |
673 | } | |
674 | ||
675 | return (m_key | LONG_PRESS); | |
676 | } | |
677 | ||
678 | #endif | |
679 | static void accdet_workqueue_func(void) | |
680 | { | |
681 | int ret; | |
682 | ret = queue_work(accdet_workqueue, &accdet_work); | |
683 | if(!ret) | |
684 | { | |
685 | ACCDET_DEBUG("[Accdet]accdet_work return:%d!\n", ret); | |
686 | } | |
687 | ||
688 | } | |
689 | ||
690 | int accdet_irq_handler(void) | |
691 | { | |
692 | int i = 0; | |
693 | if((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT)) { | |
694 | clear_accdet_interrupt(); | |
695 | } | |
696 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
697 | if (accdet_status == MIC_BIAS){ | |
698 | accdet_auxadc_switch(1); | |
699 | pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
700 | pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
701 | } | |
702 | #endif | |
703 | accdet_workqueue_func(); | |
704 | while(((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && i<10)) { | |
705 | i++; | |
706 | udelay(200); | |
707 | } | |
708 | return 1; | |
709 | } | |
710 | ||
711 | //clear ACCDET IRQ in accdet register | |
712 | static inline void clear_accdet_interrupt(void) | |
713 | { | |
714 | ||
715 | //it is safe by using polling to adjust when to clear IRQ_CLR_BIT | |
716 | pmic_pwrap_write(ACCDET_IRQ_STS, (IRQ_CLR_BIT)); | |
717 | ACCDET_DEBUG("[Accdet]clear_accdet_interrupt: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
718 | } | |
719 | ||
720 | #ifdef SW_WORK_AROUND_ACCDET_REMOTE_BUTTON_ISSUE | |
721 | ||
722 | ||
723 | #define ACC_ANSWER_CALL 1 | |
724 | #define ACC_END_CALL 2 | |
725 | #define ACC_MEDIA_PLAYPAUSE 3 | |
726 | ||
727 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
728 | #define ACC_MEDIA_STOP 4 | |
729 | #define ACC_MEDIA_NEXT 5 | |
730 | #define ACC_MEDIA_PREVIOUS 6 | |
731 | #define ACC_VOLUMEUP 7 | |
732 | #define ACC_VOLUMEDOWN 8 | |
733 | #endif | |
734 | ||
735 | static atomic_t send_event_flag = ATOMIC_INIT(0); | |
736 | ||
737 | static DECLARE_WAIT_QUEUE_HEAD(send_event_wq); | |
738 | ||
739 | ||
740 | static int accdet_key_event=0; | |
741 | ||
742 | static int sendKeyEvent(void *unuse) | |
743 | { | |
744 | while(1) | |
745 | { | |
746 | ACCDET_DEBUG( " accdet:sendKeyEvent wait\n"); | |
747 | //wait for signal | |
748 | wait_event_interruptible(send_event_wq, (atomic_read(&send_event_flag) != 0)); | |
749 | ||
750 | wake_lock_timeout(&accdet_key_lock, 2*HZ); //set the wake lock. | |
751 | ACCDET_DEBUG( " accdet:going to send event %d\n", accdet_key_event); | |
752 | ||
753 | if(PLUG_OUT !=accdet_status) | |
754 | { | |
755 | //send key event | |
756 | if(ACC_END_CALL == accdet_key_event) | |
757 | { | |
758 | ACCDET_DEBUG("[Accdet] end call!\n"); | |
759 | input_report_key(kpd_accdet_dev, KEY_ENDCALL, 1); | |
760 | input_report_key(kpd_accdet_dev, KEY_ENDCALL, 0); | |
761 | input_sync(kpd_accdet_dev); | |
762 | } | |
763 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
764 | if(ACC_MEDIA_PLAYPAUSE == accdet_key_event) | |
765 | { | |
766 | ACCDET_DEBUG("[Accdet] PLAY_PAUSE !\n"); | |
767 | input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 1); | |
768 | input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 0); | |
769 | input_sync(kpd_accdet_dev); | |
770 | } | |
771 | // next, previous, volumeup, volumedown send key in multi_key_detection() | |
772 | if(ACC_MEDIA_NEXT == accdet_key_event) | |
773 | { | |
774 | ACCDET_DEBUG("[Accdet] NEXT ..\n"); | |
775 | ||
776 | } | |
777 | if(ACC_MEDIA_PREVIOUS == accdet_key_event) | |
778 | { | |
779 | ACCDET_DEBUG("[Accdet] PREVIOUS..\n"); | |
780 | ||
781 | } | |
782 | if(ACC_VOLUMEUP== accdet_key_event) | |
783 | { | |
784 | ACCDET_DEBUG("[Accdet] VOLUMUP ..\n"); | |
785 | ||
786 | } | |
787 | if(ACC_VOLUMEDOWN== accdet_key_event) | |
788 | { | |
789 | ACCDET_DEBUG("[Accdet] VOLUMDOWN..\n"); | |
790 | ||
791 | } | |
792 | ||
793 | #else | |
794 | if(ACC_MEDIA_PLAYPAUSE == accdet_key_event) | |
795 | { | |
796 | ACCDET_DEBUG("[Accdet] PLAY_PAUSE !\n"); | |
797 | input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 1); | |
798 | input_report_key(kpd_accdet_dev, KEY_PLAYPAUSE, 0); | |
799 | input_sync(kpd_accdet_dev); | |
800 | } | |
801 | #endif | |
802 | } | |
803 | atomic_set(&send_event_flag, 0); | |
804 | ||
805 | // wake_unlock(&accdet_key_lock); //unlock wake lock | |
806 | } | |
807 | return 0; | |
808 | } | |
809 | ||
810 | static ssize_t notify_sendKeyEvent(int event) | |
811 | { | |
812 | ||
813 | accdet_key_event = event; | |
814 | atomic_set(&send_event_flag, 1); | |
815 | wake_up(&send_event_wq); | |
816 | ACCDET_DEBUG( " accdet:notify_sendKeyEvent !\n"); | |
817 | return 0; | |
818 | } | |
819 | ||
820 | ||
821 | #endif | |
822 | ||
823 | static inline void check_cable_type(void) | |
824 | { | |
825 | int current_status = 0; | |
826 | int irq_temp = 0; //for clear IRQ_bit | |
827 | int wait_clear_irq_times = 0; | |
828 | #ifdef ACCDET_PIN_RECOGNIZATION | |
829 | int pin_adc_value = 0; | |
830 | #define PIN_ADC_CHANNEL 5 | |
831 | #endif | |
832 | ||
833 | current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //A=bit1; B=bit0 | |
834 | ACCDET_DEBUG("[Accdet]accdet interrupt happen:[%s]current AB = %d\n", | |
835 | accdet_status_string[accdet_status], current_status); | |
836 | ||
837 | button_status = 0; | |
838 | pre_status = accdet_status; | |
839 | ||
840 | ACCDET_DEBUG("[Accdet]check_cable_type: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
841 | IRQ_CLR_FLAG = FALSE; | |
842 | switch(accdet_status) | |
843 | { | |
844 | case PLUG_OUT: | |
845 | #ifdef ACCDET_PIN_RECOGNIZATION | |
846 | pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1); | |
847 | #endif | |
848 | if(current_status == 0) | |
849 | { | |
850 | #ifdef ACCDET_PIN_RECOGNIZATION | |
851 | //micbias always on during detected PIN recognition | |
852 | pmic_pwrap_write(ACCDET_PWM_WIDTH, cust_headset_settings->pwm_width); | |
853 | pmic_pwrap_write(ACCDET_PWM_THRESH, cust_headset_settings->pwm_width); | |
854 | ACCDET_DEBUG("[Accdet]PIN recognition micbias always on!\n"); | |
855 | ACCDET_DEBUG("[Accdet]before adc read, pin_adc_value = %d mv!\n", pin_adc_value); | |
856 | msleep(1000); | |
857 | current_status = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //A=bit1; B=bit0 | |
858 | if (current_status == 0 && show_icon_delay != 0) | |
859 | { | |
860 | accdet_auxadc_switch(1);//switch on when need to use auxadc read voltage | |
861 | pin_adc_value = PMIC_IMM_GetOneChannelValue(MULTIKEY_ADC_CHANNEL,1,1); | |
862 | ACCDET_DEBUG("[Accdet]pin_adc_value = %d mv!\n", pin_adc_value); | |
863 | accdet_auxadc_switch(0); | |
864 | if (200 > pin_adc_value && pin_adc_value> 100) //100mv ilegal headset | |
865 | { | |
866 | headset_standard_judge_message(); | |
867 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
868 | if(1 == eint_accdet_sync_flag) { | |
869 | cable_type = HEADSET_NO_MIC; | |
870 | accdet_status = HOOK_SWITCH; | |
871 | cable_pin_recognition = 1; | |
872 | ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); | |
873 | }else { | |
874 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
875 | } | |
876 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
877 | } | |
878 | else | |
879 | { | |
880 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
881 | if(1 == eint_accdet_sync_flag) { | |
882 | cable_type = HEADSET_NO_MIC; | |
883 | accdet_status = HOOK_SWITCH; | |
884 | }else { | |
885 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
886 | } | |
887 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
888 | } | |
889 | } | |
890 | #else | |
891 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
892 | if(1 == eint_accdet_sync_flag) { | |
893 | cable_type = HEADSET_NO_MIC; | |
894 | accdet_status = HOOK_SWITCH; | |
895 | }else { | |
896 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
897 | } | |
898 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
899 | #endif | |
900 | } | |
901 | else if(current_status == 1) | |
902 | { | |
903 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
904 | if(1 == eint_accdet_sync_flag) { | |
905 | accdet_status = MIC_BIAS; | |
906 | cable_type = HEADSET_MIC; | |
907 | }else { | |
908 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
909 | } | |
910 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
911 | //ALPS00038030:reduce the time of remote button pressed during incoming call | |
912 | //solution: reduce hook switch debounce time to 0x400 | |
913 | pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); | |
914 | //recover polling set AB 00-01 | |
915 | #ifdef ACCDET_PIN_RECOGNIZATION | |
916 | pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
917 | pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); | |
918 | #endif | |
919 | //#ifdef ACCDET_LOW_POWER | |
920 | //wake_unlock(&accdet_timer_lock);//add for suspend disable accdet more than 5S | |
921 | //#endif | |
922 | } | |
923 | else if(current_status == 3) | |
924 | { | |
925 | ACCDET_DEBUG("[Accdet]PLUG_OUT state not change!\n"); | |
926 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
927 | ACCDET_DEBUG("[Accdet] do not send plug out event in plug out\n"); | |
928 | #else | |
929 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
930 | if(1 == eint_accdet_sync_flag) { | |
931 | accdet_status = PLUG_OUT; | |
932 | cable_type = NO_DEVICE; | |
933 | }else { | |
934 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
935 | } | |
936 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
937 | #ifdef ACCDET_EINT | |
938 | disable_accdet(); | |
939 | #endif | |
940 | #endif | |
941 | } | |
942 | else | |
943 | { | |
944 | ACCDET_DEBUG("[Accdet]PLUG_OUT can't change to this state!\n"); | |
945 | } | |
946 | break; | |
947 | ||
948 | case MIC_BIAS: | |
949 | //ALPS00038030:reduce the time of remote button pressed during incoming call | |
950 | //solution: resume hook switch debounce time | |
951 | pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0); | |
952 | ||
953 | if(current_status == 0) | |
954 | { | |
955 | ||
956 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
957 | if(1 == eint_accdet_sync_flag) { | |
958 | while((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times<3)) | |
959 | { | |
960 | ACCDET_DEBUG("[Accdet]check_cable_type: MIC BIAS clear IRQ on-going1....\n"); | |
961 | wait_clear_irq_times++; | |
962 | msleep(5); | |
963 | } | |
964 | irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); | |
965 | irq_temp = irq_temp & (~IRQ_CLR_BIT); | |
966 | pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); | |
967 | IRQ_CLR_FLAG = TRUE; | |
968 | accdet_status = HOOK_SWITCH; | |
969 | }else { | |
970 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
971 | } | |
972 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
973 | button_status = 1; | |
974 | if(button_status) | |
975 | { | |
976 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
977 | int multi_key = NO_KEY; | |
978 | //mdelay(10); | |
979 | //if plug out don't send key | |
980 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
981 | if(1 == eint_accdet_sync_flag) { | |
982 | multi_key = multi_key_detection(); | |
983 | }else { | |
984 | ACCDET_DEBUG("[Accdet] multi_key_detection: Headset has plugged out\n"); | |
985 | } | |
986 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
987 | accdet_auxadc_switch(0); | |
988 | //recover pwm frequency and duty | |
989 | pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
990 | pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); | |
991 | switch (multi_key) | |
992 | { | |
993 | case SHORT_UP: | |
994 | ACCDET_DEBUG("[Accdet] Short press up (0x%x)\n", multi_key); | |
995 | if(call_status == 0) | |
996 | { | |
997 | notify_sendKeyEvent(ACC_MEDIA_PREVIOUS); | |
998 | } | |
999 | else | |
1000 | { | |
1001 | notify_sendKeyEvent(ACC_VOLUMEUP); | |
1002 | } | |
1003 | break; | |
1004 | case SHORT_MD: | |
1005 | ACCDET_DEBUG("[Accdet] Short press middle (0x%x)\n", multi_key); | |
1006 | notify_sendKeyEvent(ACC_MEDIA_PLAYPAUSE); | |
1007 | break; | |
1008 | case SHORT_DW: | |
1009 | ACCDET_DEBUG("[Accdet] Short press down (0x%x)\n", multi_key); | |
1010 | if(call_status == 0) | |
1011 | { | |
1012 | notify_sendKeyEvent(ACC_MEDIA_NEXT); | |
1013 | } | |
1014 | else | |
1015 | { | |
1016 | notify_sendKeyEvent(ACC_VOLUMEDOWN); | |
1017 | } | |
1018 | break; | |
1019 | case LONG_UP: | |
1020 | ACCDET_DEBUG("[Accdet] Long press up (0x%x)\n", multi_key); | |
1021 | send_key_event(UP_KEY, KEYUP_FLAG); | |
1022 | ||
1023 | break; | |
1024 | case LONG_MD: | |
1025 | ACCDET_DEBUG("[Accdet] Long press middle (0x%x)\n", multi_key); | |
1026 | notify_sendKeyEvent(ACC_END_CALL); | |
1027 | break; | |
1028 | case LONG_DW: | |
1029 | ACCDET_DEBUG("[Accdet] Long press down (0x%x)\n", multi_key); | |
1030 | send_key_event(DW_KEY, KEYUP_FLAG); | |
1031 | ||
1032 | break; | |
1033 | default: | |
1034 | ACCDET_DEBUG("[Accdet] unkown key (0x%x)\n", multi_key); | |
1035 | break; | |
1036 | } | |
1037 | #else | |
1038 | if(call_status != 0) | |
1039 | { | |
1040 | if(is_long_press()) | |
1041 | { | |
1042 | ACCDET_DEBUG("[Accdet]send long press remote button event %d \n",ACC_END_CALL); | |
1043 | notify_sendKeyEvent(ACC_END_CALL); | |
1044 | } else { | |
1045 | ACCDET_DEBUG("[Accdet]send short press remote button event %d\n",ACC_ANSWER_CALL); | |
1046 | notify_sendKeyEvent(ACC_MEDIA_PLAYPAUSE); | |
1047 | } | |
1048 | } | |
1049 | #endif////end ifdef ACCDET_MULTI_KEY_FEATURE else | |
1050 | } | |
1051 | } | |
1052 | else if(current_status == 1) | |
1053 | { | |
1054 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1055 | if(1 == eint_accdet_sync_flag) { | |
1056 | accdet_status = MIC_BIAS; | |
1057 | cable_type = HEADSET_MIC; | |
1058 | ACCDET_DEBUG("[Accdet]MIC_BIAS state not change!\n"); | |
1059 | }else { | |
1060 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1061 | } | |
1062 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1063 | } | |
1064 | else if(current_status == 3) | |
1065 | { | |
1066 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
1067 | ACCDET_DEBUG("[Accdet]do not send plug ou in micbiast\n"); | |
1068 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1069 | if(1 == eint_accdet_sync_flag) { | |
1070 | accdet_status = PLUG_OUT; | |
1071 | }else { | |
1072 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1073 | } | |
1074 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1075 | #else | |
1076 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1077 | if(1 == eint_accdet_sync_flag) { | |
1078 | accdet_status = PLUG_OUT; | |
1079 | cable_type = NO_DEVICE; | |
1080 | }else { | |
1081 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1082 | } | |
1083 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1084 | #ifdef ACCDET_EINT | |
1085 | disable_accdet(); | |
1086 | #endif | |
1087 | #endif | |
1088 | } | |
1089 | else | |
1090 | { | |
1091 | ACCDET_DEBUG("[Accdet]MIC_BIAS can't change to this state!\n"); | |
1092 | } | |
1093 | break; | |
1094 | ||
1095 | case HOOK_SWITCH: | |
1096 | if(current_status == 0) | |
1097 | { | |
1098 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1099 | if(1 == eint_accdet_sync_flag) { | |
1100 | //for avoid 01->00 framework of Headset will report press key info for Audio | |
1101 | //cable_type = HEADSET_NO_MIC; | |
1102 | //accdet_status = HOOK_SWITCH; | |
1103 | ACCDET_DEBUG("[Accdet]HOOK_SWITCH state not change!\n"); | |
1104 | }else { | |
1105 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1106 | } | |
1107 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1108 | } | |
1109 | else if(current_status == 1) | |
1110 | { | |
1111 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1112 | if(1 == eint_accdet_sync_flag) { | |
1113 | accdet_status = MIC_BIAS; | |
1114 | cable_type = HEADSET_MIC; | |
1115 | }else { | |
1116 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1117 | } | |
1118 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1119 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1120 | cable_pin_recognition = 0; | |
1121 | ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); | |
1122 | pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
1123 | pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); | |
1124 | #endif | |
1125 | //ALPS00038030:reduce the time of remote button pressed during incoming call | |
1126 | //solution: reduce hook switch debounce time to 0x400 | |
1127 | pmic_pwrap_write(ACCDET_DEBOUNCE0, button_press_debounce); | |
1128 | //#ifdef ACCDET_LOW_POWER | |
1129 | //wake_unlock(&accdet_timer_lock);//add for suspend disable accdet more than 5S | |
1130 | //#endif | |
1131 | } | |
1132 | else if(current_status == 3) | |
1133 | { | |
1134 | ||
1135 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1136 | cable_pin_recognition = 0; | |
1137 | ACCDET_DEBUG("[Accdet] cable_pin_recognition = %d\n", cable_pin_recognition); | |
1138 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1139 | if(1 == eint_accdet_sync_flag) { | |
1140 | accdet_status = PLUG_OUT; | |
1141 | }else { | |
1142 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1143 | } | |
1144 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1145 | #endif | |
1146 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
1147 | ACCDET_DEBUG("[Accdet] do not send plug out event in hook switch\n"); | |
1148 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1149 | if(1 == eint_accdet_sync_flag) { | |
1150 | accdet_status = PLUG_OUT; | |
1151 | }else { | |
1152 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1153 | } | |
1154 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1155 | #else | |
1156 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1157 | if(1 == eint_accdet_sync_flag) { | |
1158 | accdet_status = PLUG_OUT; | |
1159 | cable_type = NO_DEVICE; | |
1160 | }else { | |
1161 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1162 | } | |
1163 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1164 | #ifdef ACCDET_EINT | |
1165 | disable_accdet(); | |
1166 | #endif | |
1167 | #endif | |
1168 | } | |
1169 | else | |
1170 | { | |
1171 | ACCDET_DEBUG("[Accdet]HOOK_SWITCH can't change to this state!\n"); | |
1172 | } | |
1173 | break; | |
1174 | ||
1175 | case STAND_BY: | |
1176 | if(current_status == 3) | |
1177 | { | |
1178 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
1179 | ACCDET_DEBUG("[Accdet]accdet do not send plug out event in stand by!\n"); | |
1180 | #else | |
1181 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1182 | if(1 == eint_accdet_sync_flag) { | |
1183 | accdet_status = PLUG_OUT; | |
1184 | cable_type = NO_DEVICE; | |
1185 | }else { | |
1186 | ACCDET_DEBUG("[Accdet] Headset has plugged out\n"); | |
1187 | } | |
1188 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1189 | #ifdef ACCDET_EINT | |
1190 | disable_accdet(); | |
1191 | #endif | |
1192 | #endif | |
1193 | } | |
1194 | else | |
1195 | { | |
1196 | ACCDET_DEBUG("[Accdet]STAND_BY can't change to this state!\n"); | |
1197 | } | |
1198 | break; | |
1199 | ||
1200 | default: | |
1201 | ACCDET_DEBUG("[Accdet]check_cable_type: accdet current status error!\n"); | |
1202 | break; | |
1203 | ||
1204 | } | |
1205 | ||
1206 | if(!IRQ_CLR_FLAG) | |
1207 | { | |
1208 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1209 | if(1 == eint_accdet_sync_flag) { | |
1210 | while((pmic_pwrap_read(ACCDET_IRQ_STS) & IRQ_STATUS_BIT) && (wait_clear_irq_times<3)) | |
1211 | { | |
1212 | ACCDET_DEBUG("[Accdet]check_cable_type: Clear interrupt on-going2....\n"); | |
1213 | wait_clear_irq_times++; | |
1214 | msleep(5); | |
1215 | } | |
1216 | } | |
1217 | irq_temp = pmic_pwrap_read(ACCDET_IRQ_STS); | |
1218 | irq_temp = irq_temp & (~IRQ_CLR_BIT); | |
1219 | pmic_pwrap_write(ACCDET_IRQ_STS, irq_temp); | |
1220 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1221 | IRQ_CLR_FLAG = TRUE; | |
1222 | ACCDET_DEBUG("[Accdet]check_cable_type:Clear interrupt:Done[0x%x]!\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
1223 | ||
1224 | } | |
1225 | else | |
1226 | { | |
1227 | IRQ_CLR_FLAG = FALSE; | |
1228 | } | |
1229 | ||
1230 | ACCDET_DEBUG("[Accdet]cable type:[%s], status switch:[%s]->[%s]\n", | |
1231 | accdet_report_string[cable_type], accdet_status_string[pre_status], | |
1232 | accdet_status_string[accdet_status]); | |
1233 | } | |
1234 | static void accdet_work_callback(struct work_struct *work) | |
1235 | { | |
1236 | ||
1237 | wake_lock(&accdet_irq_lock); | |
1238 | check_cable_type(); | |
1239 | ||
1240 | mutex_lock(&accdet_eint_irq_sync_mutex); | |
1241 | if(1 == eint_accdet_sync_flag) { | |
1242 | switch_set_state((struct switch_dev *)&accdet_data, cable_type); | |
1243 | }else { | |
1244 | ACCDET_DEBUG("[Accdet] Headset has plugged out don't set accdet state\n"); | |
1245 | } | |
1246 | mutex_unlock(&accdet_eint_irq_sync_mutex); | |
1247 | ACCDET_DEBUG( " [accdet] set state in cable_type status\n"); | |
1248 | ||
1249 | wake_unlock(&accdet_irq_lock); | |
1250 | } | |
1251 | ||
1252 | //ACCDET hardware initial | |
1253 | static inline void accdet_init(void) | |
1254 | { | |
1255 | ACCDET_DEBUG("[Accdet]accdet hardware init\n"); | |
1256 | ||
1257 | pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR); | |
1258 | ACCDET_DEBUG("[Accdet]accdet TOP_CKPDN=0x%x!\n", pmic_pwrap_read(TOP_CKPDN)); | |
1259 | //reset the accdet unit | |
1260 | ||
1261 | ACCDET_DEBUG("ACCDET reset : reset start!! \n\r"); | |
1262 | pmic_pwrap_write(TOP_RST_ACCDET_SET, ACCDET_RESET_SET); | |
1263 | ||
1264 | ACCDET_DEBUG("ACCDET reset function test: reset finished!! \n\r"); | |
1265 | pmic_pwrap_write(TOP_RST_ACCDET_CLR, ACCDET_RESET_CLR); | |
1266 | ||
1267 | //init pwm frequency and duty | |
1268 | pmic_pwrap_write(ACCDET_PWM_WIDTH, REGISTER_VALUE(cust_headset_settings->pwm_width)); | |
1269 | pmic_pwrap_write(ACCDET_PWM_THRESH, REGISTER_VALUE(cust_headset_settings->pwm_thresh)); | |
1270 | ||
1271 | ||
1272 | pwrap_write(ACCDET_STATE_SWCTRL, 0x07); | |
1273 | ||
1274 | ||
1275 | pmic_pwrap_write(ACCDET_EN_DELAY_NUM, | |
1276 | (cust_headset_settings->fall_delay << 15 | cust_headset_settings->rise_delay)); | |
1277 | ||
1278 | // init the debounce time | |
1279 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1280 | pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0); | |
1281 | pmic_pwrap_write(ACCDET_DEBOUNCE1, 0xFFFF); | |
1282 | pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3); | |
1283 | #else | |
1284 | pmic_pwrap_write(ACCDET_DEBOUNCE0, cust_headset_settings->debounce0); | |
1285 | pmic_pwrap_write(ACCDET_DEBOUNCE1, cust_headset_settings->debounce1); | |
1286 | pmic_pwrap_write(ACCDET_DEBOUNCE3, cust_headset_settings->debounce3); | |
1287 | #endif | |
1288 | pmic_pwrap_write(ACCDET_IRQ_STS, pmic_pwrap_read(ACCDET_IRQ_STS)&(~IRQ_CLR_BIT)); | |
1289 | pmic_pwrap_write(INT_CON_ACCDET_SET, RG_ACCDET_IRQ_SET); | |
1290 | #ifdef ACCDET_EINT | |
1291 | // disable ACCDET unit | |
1292 | pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL); | |
1293 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE); | |
1294 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0x0); | |
1295 | pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET); | |
1296 | #else | |
1297 | ||
1298 | // enable ACCDET unit | |
1299 | // pmic_pwrap_write(ACCDET_STATE_SWCTRL, ACCDET_SWCTRL_EN); | |
1300 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_ENABLE); | |
1301 | #endif | |
1302 | ||
1303 | #ifdef GPIO_FSA8049_PIN | |
1304 | //mt_set_gpio_out(GPIO_FSA8049_PIN, GPIO_OUT_ONE); | |
1305 | #endif | |
1306 | #ifdef FSA8049_V_POWER | |
1307 | hwPowerOn(FSA8049_V_POWER, VOL_2800, "ACCDET"); | |
1308 | #endif | |
1309 | ||
1310 | } | |
1311 | /*-----------------------------------sysfs-----------------------------------------*/ | |
1312 | #if DEBUG_THREAD | |
1313 | #ifdef CONFIG_MTK_PMIC_MT6397 | |
1314 | int dump_register(void) | |
1315 | { | |
1316 | ||
1317 | int i=0; | |
1318 | for (i=0x0582; i<= 0x05A4; i+=2) | |
1319 | { | |
1320 | ACCDET_DEBUG(" ACCDET_BASE + %x=%x\n",i,pmic_pwrap_read(ACCDET_BASE + i)); | |
1321 | } | |
1322 | ||
1323 | ACCDET_DEBUG(" TOP_RST_ACCDET =%x\n",pmic_pwrap_read(TOP_RST_ACCDET));// reset register in 6397 | |
1324 | ACCDET_DEBUG(" INT_CON_ACCDET =%x\n",pmic_pwrap_read(INT_CON_ACCDET));//INT register in 6397 | |
1325 | ACCDET_DEBUG(" TOP_CKPDN =%x\n",pmic_pwrap_read(TOP_CKPDN));// clock register in 6397 | |
1326 | ACCDET_DEBUG(" 0x0732 =%x\n",pmic_pwrap_read(0x0732)); | |
1327 | ACCDET_DEBUG(" MULTIKEY_ADC_CHANNEL(%x) is %x\n",MULTIKEY_ADC_CHANNEL, PMIC_IMM_GetOneChannelValue(MULTIKEY_ADC_CHANNEL,1,1)); | |
1328 | #ifdef ACCDET_PIN_SWAP | |
1329 | //ACCDET_DEBUG(" 0x00004000 =%x\n",pmic_pwrap_read(0x00004000));//VRF28 power for PIN swap feature | |
1330 | #endif | |
1331 | return 0; | |
1332 | } | |
1333 | #else | |
1334 | static int dump_register(void) | |
1335 | { | |
1336 | int i=0; | |
1337 | for (i=0x077A; i<= 0x079A; i+=2) | |
1338 | { | |
1339 | ACCDET_DEBUG(" ACCDET_BASE + %x=%x\n",i,pmic_pwrap_read(ACCDET_BASE + i)); | |
1340 | } | |
1341 | ||
1342 | ACCDET_DEBUG(" TOP_RST_ACCDET =%x\n",pmic_pwrap_read(TOP_RST_ACCDET));// reset register in 6320 | |
1343 | ACCDET_DEBUG(" INT_CON_ACCDET =%x\n",pmic_pwrap_read(INT_CON_ACCDET));//INT register in 6320 | |
1344 | ACCDET_DEBUG(" TOP_CKPDN =%x\n",pmic_pwrap_read(TOP_CKPDN));// clock register in 6320 | |
1345 | #ifdef ACCDET_PIN_SWAP | |
1346 | //ACCDET_DEBUG(" 0x00004000 =%x\n",pmic_pwrap_read(0x00004000));//VRF28 power for PIN swap feature | |
1347 | #endif | |
1348 | return 0; | |
1349 | } | |
1350 | #endif | |
1351 | ||
1352 | static ssize_t accdet_store_call_state(struct device_driver *ddri, const char *buf, size_t count) | |
1353 | { | |
1354 | if (sscanf(buf, "%u", &call_status) != 1) { | |
1355 | ACCDET_DEBUG("accdet: Invalid values\n"); | |
1356 | return -EINVAL; | |
1357 | } | |
1358 | ||
1359 | switch(call_status) | |
1360 | { | |
1361 | case CALL_IDLE : | |
1362 | ACCDET_DEBUG("[Accdet]accdet call: Idle state!\n"); | |
1363 | break; | |
1364 | ||
1365 | case CALL_RINGING : | |
1366 | ||
1367 | ACCDET_DEBUG("[Accdet]accdet call: ringing state!\n"); | |
1368 | break; | |
1369 | ||
1370 | case CALL_ACTIVE : | |
1371 | ACCDET_DEBUG("[Accdet]accdet call: active or hold state!\n"); | |
1372 | ACCDET_DEBUG("[Accdet]accdet_ioctl : Button_Status=%d (state:%d)\n", button_status, accdet_data.state); | |
1373 | //return button_status; | |
1374 | break; | |
1375 | ||
1376 | default: | |
1377 | ACCDET_DEBUG("[Accdet]accdet call : Invalid values\n"); | |
1378 | break; | |
1379 | } | |
1380 | return count; | |
1381 | } | |
1382 | ||
1383 | //#ifdef ACCDET_PIN_RECOGNIZATION | |
1384 | ||
1385 | static ssize_t show_pin_recognition_state(struct device_driver *ddri, char *buf) | |
1386 | { | |
1387 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1388 | ACCDET_DEBUG("ACCDET show_pin_recognition_state = %d\n", cable_pin_recognition); | |
1389 | return sprintf(buf, "%u\n", cable_pin_recognition); | |
1390 | #else | |
1391 | return sprintf(buf, "%u\n", 0); | |
1392 | #endif | |
1393 | } | |
1394 | ||
1395 | static DRIVER_ATTR(accdet_pin_recognition, 0664, show_pin_recognition_state, NULL); | |
1396 | static DRIVER_ATTR(accdet_call_state, 0664, NULL, accdet_store_call_state); | |
1397 | ||
1398 | static int g_start_debug_thread =0; | |
1399 | static struct task_struct *thread = NULL; | |
1400 | static int g_dump_register=0; | |
1401 | static int dbug_thread(void *unused) | |
1402 | { | |
1403 | while(g_start_debug_thread) | |
1404 | { | |
1405 | if(g_dump_register) | |
1406 | { | |
1407 | dump_register(); | |
1408 | //dump_pmic_register(); | |
1409 | } | |
1410 | ||
1411 | msleep(500); | |
1412 | ||
1413 | } | |
1414 | return 0; | |
1415 | } | |
1416 | //static ssize_t store_trace_value(struct device_driver *ddri, const char *buf, size_t count) | |
1417 | static ssize_t store_accdet_start_debug_thread(struct device_driver *ddri, const char *buf, size_t count) | |
1418 | { | |
1419 | ||
1420 | unsigned int start_flag; | |
1421 | int error; | |
1422 | ||
1423 | if (sscanf(buf, "%u", &start_flag) != 1) { | |
1424 | ACCDET_DEBUG("accdet: Invalid values\n"); | |
1425 | return -EINVAL; | |
1426 | } | |
1427 | ||
1428 | ACCDET_DEBUG("[Accdet] start flag =%d \n",start_flag); | |
1429 | ||
1430 | g_start_debug_thread = start_flag; | |
1431 | ||
1432 | if(1 == start_flag) | |
1433 | { | |
1434 | thread = kthread_run(dbug_thread, 0, "ACCDET"); | |
1435 | if (IS_ERR(thread)) | |
1436 | { | |
1437 | error = PTR_ERR(thread); | |
1438 | ACCDET_DEBUG( " failed to create kernel thread: %d\n", error); | |
1439 | } | |
1440 | } | |
1441 | ||
1442 | return count; | |
1443 | } | |
1444 | static ssize_t store_accdet_set_headset_mode(struct device_driver *ddri, const char *buf, size_t count) | |
1445 | { | |
1446 | ||
1447 | unsigned int value; | |
1448 | //int error; | |
1449 | ||
1450 | if (sscanf(buf, "%u", &value) != 1) { | |
1451 | ACCDET_DEBUG("accdet: Invalid values\n"); | |
1452 | return -EINVAL; | |
1453 | } | |
1454 | ||
1455 | ACCDET_DEBUG("[Accdet]store_accdet_set_headset_mode value =%d \n",value); | |
1456 | ||
1457 | return count; | |
1458 | } | |
1459 | ||
1460 | static ssize_t store_accdet_dump_register(struct device_driver *ddri, const char *buf, size_t count) | |
1461 | { | |
1462 | unsigned int value; | |
1463 | // int error; | |
1464 | ||
1465 | if (sscanf(buf, "%u", &value) != 1) | |
1466 | { | |
1467 | ACCDET_DEBUG("accdet: Invalid values\n"); | |
1468 | return -EINVAL; | |
1469 | } | |
1470 | ||
1471 | g_dump_register = value; | |
1472 | ||
1473 | ACCDET_DEBUG("[Accdet]store_accdet_dump_register value =%d \n",value); | |
1474 | ||
1475 | return count; | |
1476 | } | |
1477 | ||
1478 | /*----------------------------------------------------------------------------*/ | |
1479 | static DRIVER_ATTR(dump_register, S_IWUSR | S_IRUGO, NULL, store_accdet_dump_register); | |
1480 | ||
1481 | static DRIVER_ATTR(set_headset_mode, S_IWUSR | S_IRUGO, NULL, store_accdet_set_headset_mode); | |
1482 | ||
1483 | static DRIVER_ATTR(start_debug, S_IWUSR | S_IRUGO, NULL, store_accdet_start_debug_thread); | |
1484 | ||
1485 | /*----------------------------------------------------------------------------*/ | |
1486 | static struct driver_attribute *accdet_attr_list[] = { | |
1487 | &driver_attr_start_debug, | |
1488 | &driver_attr_set_headset_mode, | |
1489 | &driver_attr_dump_register, | |
1490 | &driver_attr_accdet_call_state, | |
1491 | //#ifdef ACCDET_PIN_RECOGNIZATION | |
1492 | &driver_attr_accdet_pin_recognition, | |
1493 | //#endif | |
1494 | }; | |
1495 | ||
1496 | static int accdet_create_attr(struct device_driver *driver) | |
1497 | { | |
1498 | int idx, err = 0; | |
1499 | int num = (int)(sizeof(accdet_attr_list)/sizeof(accdet_attr_list[0])); | |
1500 | if (driver == NULL) | |
1501 | { | |
1502 | return -EINVAL; | |
1503 | } | |
1504 | ||
1505 | for(idx = 0; idx < num; idx++) | |
1506 | { | |
1507 | if((err = driver_create_file(driver, accdet_attr_list[idx]))) | |
1508 | { | |
1509 | ACCDET_DEBUG("driver_create_file (%s) = %d\n", accdet_attr_list[idx]->attr.name, err); | |
1510 | break; | |
1511 | } | |
1512 | } | |
1513 | return err; | |
1514 | } | |
1515 | ||
1516 | #endif | |
1517 | ||
1518 | int mt_accdet_probe(void) | |
1519 | { | |
1520 | int ret = 0; | |
1521 | #ifdef SW_WORK_AROUND_ACCDET_REMOTE_BUTTON_ISSUE | |
1522 | struct task_struct *keyEvent_thread = NULL; | |
1523 | int error=0; | |
1524 | #endif | |
1525 | #if DEBUG_THREAD | |
1526 | struct platform_driver accdet_driver_hal = accdet_driver_func(); | |
1527 | #endif | |
1528 | ||
1529 | struct headset_key_custom* press_key_time = get_headset_key_custom_setting(); | |
1530 | ||
1531 | ACCDET_DEBUG("[Accdet]accdet_probe begin!\n"); | |
1532 | ||
1533 | ||
1534 | //------------------------------------------------------------------ | |
1535 | // below register accdet as switch class | |
1536 | //------------------------------------------------------------------ | |
1537 | accdet_data.name = "h2w"; | |
1538 | accdet_data.index = 0; | |
1539 | accdet_data.state = NO_DEVICE; | |
1540 | ||
1541 | cust_headset_settings = get_cust_headset_settings(); | |
1542 | ||
1543 | ret = switch_dev_register(&accdet_data); | |
1544 | if(ret) | |
1545 | { | |
1546 | ACCDET_DEBUG("[Accdet]switch_dev_register returned:%d!\n", ret); | |
1547 | return 1; | |
1548 | } | |
1549 | ||
1550 | //------------------------------------------------------------------ | |
1551 | // Create normal device for auido use | |
1552 | //------------------------------------------------------------------ | |
1553 | ret = alloc_chrdev_region(&accdet_devno, 0, 1, ACCDET_DEVNAME); | |
1554 | if (ret) | |
1555 | { | |
1556 | ACCDET_DEBUG("[Accdet]alloc_chrdev_region: Get Major number error!\n"); | |
1557 | } | |
1558 | ||
1559 | accdet_cdev = cdev_alloc(); | |
1560 | accdet_cdev->owner = THIS_MODULE; | |
1561 | accdet_cdev->ops = accdet_get_fops(); | |
1562 | ret = cdev_add(accdet_cdev, accdet_devno, 1); | |
1563 | if(ret) | |
1564 | { | |
1565 | ACCDET_DEBUG("[Accdet]accdet error: cdev_add\n"); | |
1566 | } | |
1567 | ||
1568 | accdet_class = class_create(THIS_MODULE, ACCDET_DEVNAME); | |
1569 | ||
1570 | // if we want auto creat device node, we must call this | |
1571 | accdet_nor_device = device_create(accdet_class, NULL, accdet_devno, NULL, ACCDET_DEVNAME); | |
1572 | ||
1573 | //------------------------------------------------------------------ | |
1574 | // Create input device | |
1575 | //------------------------------------------------------------------ | |
1576 | kpd_accdet_dev = input_allocate_device(); | |
1577 | if (!kpd_accdet_dev) | |
1578 | { | |
1579 | ACCDET_DEBUG("[Accdet]kpd_accdet_dev : fail!\n"); | |
1580 | return -ENOMEM; | |
1581 | } | |
1582 | ||
1583 | //define multi-key keycode | |
1584 | __set_bit(EV_KEY, kpd_accdet_dev->evbit); | |
1585 | __set_bit(KEY_CALL, kpd_accdet_dev->keybit); | |
1586 | __set_bit(KEY_ENDCALL, kpd_accdet_dev->keybit); | |
1587 | __set_bit(KEY_NEXTSONG, kpd_accdet_dev->keybit); | |
1588 | __set_bit(KEY_PREVIOUSSONG, kpd_accdet_dev->keybit); | |
1589 | __set_bit(KEY_PLAYPAUSE, kpd_accdet_dev->keybit); | |
1590 | __set_bit(KEY_STOPCD, kpd_accdet_dev->keybit); | |
1591 | __set_bit(KEY_VOLUMEDOWN, kpd_accdet_dev->keybit); | |
1592 | __set_bit(KEY_VOLUMEUP, kpd_accdet_dev->keybit); | |
1593 | ||
1594 | kpd_accdet_dev->id.bustype = BUS_HOST; | |
1595 | kpd_accdet_dev->name = "ACCDET"; | |
1596 | if(input_register_device(kpd_accdet_dev)) | |
1597 | { | |
1598 | ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : fail!\n"); | |
1599 | }else | |
1600 | { | |
1601 | ACCDET_DEBUG("[Accdet]kpd_accdet_dev register : success!!\n"); | |
1602 | } | |
1603 | //------------------------------------------------------------------ | |
1604 | // Create workqueue | |
1605 | //------------------------------------------------------------------ | |
1606 | accdet_workqueue = create_singlethread_workqueue("accdet"); | |
1607 | INIT_WORK(&accdet_work, accdet_work_callback); | |
1608 | ||
1609 | ||
1610 | //------------------------------------------------------------------ | |
1611 | // wake lock | |
1612 | //------------------------------------------------------------------ | |
1613 | wake_lock_init(&accdet_suspend_lock, WAKE_LOCK_SUSPEND, "accdet wakelock"); | |
1614 | wake_lock_init(&accdet_irq_lock, WAKE_LOCK_SUSPEND, "accdet irq wakelock"); | |
1615 | wake_lock_init(&accdet_key_lock, WAKE_LOCK_SUSPEND, "accdet key wakelock"); | |
1616 | wake_lock_init(&accdet_timer_lock, WAKE_LOCK_SUSPEND, "accdet timer wakelock"); | |
1617 | #ifdef SW_WORK_AROUND_ACCDET_REMOTE_BUTTON_ISSUE | |
1618 | init_waitqueue_head(&send_event_wq); | |
1619 | //start send key event thread | |
1620 | keyEvent_thread = kthread_run(sendKeyEvent, 0, "keyEvent_send"); | |
1621 | if (IS_ERR(keyEvent_thread)) | |
1622 | { | |
1623 | error = PTR_ERR(keyEvent_thread); | |
1624 | ACCDET_DEBUG( " failed to create kernel thread: %d\n", error); | |
1625 | } | |
1626 | #endif | |
1627 | ||
1628 | #if DEBUG_THREAD | |
1629 | if((ret = accdet_create_attr(&accdet_driver_hal.driver))!=0) | |
1630 | { | |
1631 | ACCDET_DEBUG("create attribute err = %d\n", ret); | |
1632 | ||
1633 | } | |
1634 | #endif | |
1635 | ||
1636 | long_press_time = press_key_time->headset_long_press_time; | |
1637 | ||
1638 | ACCDET_DEBUG("[Accdet]accdet_probe : ACCDET_INIT\n"); | |
1639 | if (g_accdet_first == 1) | |
1640 | { | |
1641 | long_press_time_ns = (s64)long_press_time * NSEC_PER_MSEC; | |
1642 | ||
1643 | eint_accdet_sync_flag = 1; | |
1644 | ||
1645 | //Accdet Hardware Init | |
1646 | pmic_pwrap_write(ACCDET_RSV, ACCDET_1V9_MODE_OFF); | |
1647 | ACCDET_DEBUG("ACCDET use in 1.9V mode!! \n"); | |
1648 | accdet_init(); | |
1649 | #ifndef MTK_ALPS_BOX_SUPPORT | |
1650 | queue_work(accdet_workqueue, &accdet_work); //schedule a work for the first detection | |
1651 | #endif | |
1652 | #ifdef ACCDET_EINT | |
1653 | ||
1654 | accdet_eint_workqueue = create_singlethread_workqueue("accdet_eint"); | |
1655 | INIT_WORK(&accdet_eint_work, accdet_eint_work_callback); | |
1656 | accdet_setup_eint(); | |
1657 | accdet_disable_workqueue = create_singlethread_workqueue("accdet_disable"); | |
1658 | INIT_WORK(&accdet_disable_work, disable_micbias_callback); | |
1659 | ||
1660 | #endif | |
1661 | g_accdet_first = 0; | |
1662 | } | |
1663 | ||
1664 | ACCDET_DEBUG("[Accdet]accdet_probe done!\n"); | |
1665 | //#ifdef ACCDET_PIN_SWAP | |
1666 | //pmic_pwrap_write(0x0400, 0x1000); | |
1667 | //ACCDET_DEBUG("[Accdet]accdet enable VRF28 power!\n"); | |
1668 | //#endif | |
1669 | ||
1670 | return 0; | |
1671 | } | |
1672 | ||
1673 | void mt_accdet_remove(void) | |
1674 | { | |
1675 | ACCDET_DEBUG("[Accdet]accdet_remove begin!\n"); | |
1676 | ||
1677 | //cancel_delayed_work(&accdet_work); | |
1678 | #ifdef ACCDET_EINT | |
1679 | destroy_workqueue(accdet_eint_workqueue); | |
1680 | #endif | |
1681 | destroy_workqueue(accdet_workqueue); | |
1682 | switch_dev_unregister(&accdet_data); | |
1683 | device_del(accdet_nor_device); | |
1684 | class_destroy(accdet_class); | |
1685 | cdev_del(accdet_cdev); | |
1686 | unregister_chrdev_region(accdet_devno,1); | |
1687 | input_unregister_device(kpd_accdet_dev); | |
1688 | ACCDET_DEBUG("[Accdet]accdet_remove Done!\n"); | |
1689 | ||
1690 | } | |
1691 | ||
1692 | void mt_accdet_suspend(void) // only one suspend mode | |
1693 | { | |
1694 | ||
1695 | //#ifdef ACCDET_PIN_SWAP | |
1696 | // pmic_pwrap_write(0x0400, 0x0); | |
1697 | // accdet_FSA8049_disable(); | |
1698 | //#endif | |
1699 | ||
1700 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
1701 | ACCDET_DEBUG("[Accdet] in suspend1: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
1702 | #else | |
1703 | ||
1704 | #if 0 | |
1705 | #ifdef ACCDET_EINT | |
1706 | if(accdet_get_enable_RG()&& call_status == 0) | |
1707 | { | |
1708 | //record accdet status | |
1709 | //ACCDET_DEBUG("[Accdet]accdet_working_in_suspend\n"); | |
1710 | printk(KERN_DEBUG "[Accdet]accdet_working_in_suspend\n"); | |
1711 | g_accdet_working_in_suspend = 1; | |
1712 | pre_state_swctrl = accdet_get_swctrl(); | |
1713 | // disable ACCDET unit | |
1714 | accdet_disable_hal(); | |
1715 | //disable_clock | |
1716 | accdet_disable_clk(); | |
1717 | } | |
1718 | #else | |
1719 | // disable ACCDET unit | |
1720 | if(call_status == 0) | |
1721 | { | |
1722 | pre_state_swctrl = accdet_get_swctrl(); | |
1723 | accdet_disable_hal(); | |
1724 | //disable_clock | |
1725 | accdet_disable_clk(); | |
1726 | } | |
1727 | #endif | |
1728 | #endif | |
1729 | printk(KERN_DEBUG "[Accdet]accdet_suspend: ACCDET_CTRL=[0x%x], STATE=[0x%x]->[0x%x]\n", pmic_pwrap_read(ACCDET_CTRL), pre_state_swctrl, pmic_pwrap_read(ACCDET_STATE_SWCTRL)); | |
1730 | #endif | |
1731 | } | |
1732 | ||
1733 | void mt_accdet_resume(void) // wake up | |
1734 | { | |
1735 | //#ifdef ACCDET_PIN_SWAP | |
1736 | // pmic_pwrap_write(0x0400, 0x1000); | |
1737 | // accdet_FSA8049_enable(); | |
1738 | //#endif | |
1739 | ||
1740 | #ifdef ACCDET_MULTI_KEY_FEATURE | |
1741 | ACCDET_DEBUG("[Accdet] in resume1: ACCDET_IRQ_STS = 0x%x\n", pmic_pwrap_read(ACCDET_IRQ_STS)); | |
1742 | #else | |
1743 | #if 0 | |
1744 | #ifdef ACCDET_EINT | |
1745 | ||
1746 | if(1==g_accdet_working_in_suspend && 0== call_status) | |
1747 | { | |
1748 | ||
1749 | //enable_clock | |
1750 | accdet_enable_hal(pre_state_swctrl); | |
1751 | //clear g_accdet_working_in_suspend | |
1752 | g_accdet_working_in_suspend =0; | |
1753 | ACCDET_DEBUG("[Accdet]accdet_resume : recovery accdet register\n"); | |
1754 | ||
1755 | } | |
1756 | #else | |
1757 | if(call_status == 0) | |
1758 | { | |
1759 | accdet_enable_hal(pre_state_swctrl); | |
1760 | } | |
1761 | #endif | |
1762 | #endif | |
1763 | printk(KERN_DEBUG "[Accdet]accdet_resume: ACCDET_CTRL=[0x%x], STATE_SWCTRL=[0x%x]\n", pmic_pwrap_read(ACCDET_CTRL), pmic_pwrap_read(ACCDET_STATE_SWCTRL)); | |
1764 | ||
1765 | #endif | |
1766 | ||
1767 | } | |
1768 | /********************************************************************** | |
1769 | //add for IPO-H need update headset state when resume | |
1770 | ||
1771 | ***********************************************************************/ | |
1772 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1773 | struct timer_list accdet_disable_ipoh_timer; | |
1774 | static void mt_accdet_pm_disable(unsigned long a) | |
1775 | { | |
1776 | if (cable_type == NO_DEVICE && eint_accdet_sync_flag ==0) { | |
1777 | //disable accdet | |
1778 | pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL); | |
1779 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE); | |
1780 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0); | |
1781 | //disable clock | |
1782 | pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET); | |
1783 | printk("[Accdet]daccdet_pm_disable: disable!\n"); | |
1784 | } | |
1785 | else | |
1786 | { | |
1787 | printk("[Accdet]daccdet_pm_disable: enable!\n"); | |
1788 | } | |
1789 | } | |
1790 | #endif | |
1791 | void mt_accdet_pm_restore_noirq(void) | |
1792 | { | |
1793 | int current_status_restore = 0; | |
1794 | printk("[Accdet]accdet_pm_restore_noirq start!\n"); | |
1795 | //enable accdet | |
1796 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, (pmic_pwrap_read(ACCDET_STATE_SWCTRL)|ACCDET_SWCTRL_IDLE_EN)); | |
1797 | // enable ACCDET unit | |
1798 | ACCDET_DEBUG("accdet: enable_accdet\n"); | |
1799 | //enable clock | |
1800 | pmic_pwrap_write(TOP_CKPDN_CLR, RG_ACCDET_CLK_CLR); | |
1801 | enable_accdet(ACCDET_SWCTRL_EN); | |
1802 | eint_accdet_sync_flag = 1; | |
1803 | current_status_restore = ((pmic_pwrap_read(ACCDET_STATE_RG) & 0xc0)>>6); //AB | |
1804 | ||
1805 | switch (current_status_restore) { | |
1806 | case 0: //AB=0 | |
1807 | cable_type = HEADSET_NO_MIC; | |
1808 | accdet_status = HOOK_SWITCH; | |
1809 | break; | |
1810 | case 1: //AB=1 | |
1811 | cable_type = HEADSET_MIC; | |
1812 | accdet_status = MIC_BIAS; | |
1813 | break; | |
1814 | case 3: //AB=3 | |
1815 | cable_type = NO_DEVICE; | |
1816 | accdet_status = PLUG_OUT; | |
1817 | break; | |
1818 | default: | |
1819 | printk("[Accdet]accdet_pm_restore_noirq: accdet current status error!\n"); | |
1820 | break; | |
1821 | } | |
1822 | switch_set_state((struct switch_dev *)&accdet_data, cable_type); | |
1823 | if (cable_type == NO_DEVICE) { | |
1824 | #ifdef ACCDET_PIN_RECOGNIZATION | |
1825 | init_timer(&accdet_disable_ipoh_timer); | |
1826 | accdet_disable_ipoh_timer.expires = jiffies + 3*HZ; | |
1827 | accdet_disable_ipoh_timer.function = &mt_accdet_pm_disable; | |
1828 | accdet_disable_ipoh_timer.data = ((unsigned long) 0 ); | |
1829 | add_timer(&accdet_disable_ipoh_timer); | |
1830 | printk("[Accdet]enable! pm timer\n"); | |
1831 | ||
1832 | #else | |
1833 | //eint_accdet_sync_flag = 0; | |
1834 | //disable accdet | |
1835 | pre_state_swctrl = pmic_pwrap_read(ACCDET_STATE_SWCTRL); | |
1836 | pmic_pwrap_write(ACCDET_CTRL, ACCDET_DISABLE); | |
1837 | pmic_pwrap_write(ACCDET_STATE_SWCTRL, 0); | |
1838 | //disable clock | |
1839 | pmic_pwrap_write(TOP_CKPDN_SET, RG_ACCDET_CLK_SET); | |
1840 | #endif | |
1841 | } | |
1842 | ||
1843 | } | |
1844 | ////////////////////////////////////IPO_H end///////////////////////////////////////////// | |
1845 | long mt_accdet_unlocked_ioctl(unsigned int cmd, unsigned long arg) | |
1846 | { | |
1847 | // bool ret = true; | |
1848 | ||
1849 | switch(cmd) | |
1850 | { | |
1851 | case ACCDET_INIT : | |
1852 | break; | |
1853 | ||
1854 | case SET_CALL_STATE : | |
1855 | call_status = (int)arg; | |
1856 | ACCDET_DEBUG("[Accdet]accdet_ioctl : CALL_STATE=%d \n", call_status); | |
1857 | break; | |
1858 | ||
1859 | case GET_BUTTON_STATUS : | |
1860 | ACCDET_DEBUG("[Accdet]accdet_ioctl : Button_Status=%d (state:%d)\n", button_status, accdet_data.state); | |
1861 | return button_status; | |
1862 | ||
1863 | default: | |
1864 | ACCDET_DEBUG("[Accdet]accdet_ioctl : default\n"); | |
1865 | break; | |
1866 | } | |
1867 | return 0; | |
1868 | } | |
1869 |