blob: 3f95ff2bb6d6584080fef3964fec52af04cb70a9 [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/htc_35mm_jack.c
2 *
3 * Copyright (C) 2009 HTC, Inc.
4 * Author: Arec Kao <Arec_Kao@htc.com>
5 * Copyright (C) 2009 Google, Inc.
6 * Author: Eric Olsen <eolsen@android.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/module.h>
20#include <linux/sysdev.h>
21#include <linux/fs.h>
22#include <linux/interrupt.h>
23#include <linux/workqueue.h>
24#include <linux/irq.h>
25#include <linux/delay.h>
26#include <linux/types.h>
27#include <linux/platform_device.h>
28#include <linux/mutex.h>
29#include <linux/errno.h>
30#include <linux/err.h>
31#include <linux/hrtimer.h>
32#include <linux/debugfs.h>
33#include <linux/jiffies.h>
34#include <linux/switch.h>
35#include <linux/input.h>
36#include <linux/wakelock.h>
37#include <asm/gpio.h>
38#include <asm/atomic.h>
39#include <mach/board.h>
40#include <mach/vreg.h>
41#include <asm/mach-types.h>
42#include <mach/htc_acoustic_qsd.h>
43#include <mach/htc_35mm_jack.h>
44#include <mach/htc_headset.h>
45
46#ifdef CONFIG_HTC_AUDIOJACK
47#include <mach/audio_jack.h>
48#endif
49
50/* #define CONFIG_DEBUG_H2W */
51
52#define H2WI(fmt, arg...) \
53 printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
54#define H2WE(fmt, arg...) \
55 printk(KERN_ERR "[H2W] %s " fmt "\r\n", __func__, ## arg)
56
57#ifdef CONFIG_DEBUG_H2W
58#define H2W_DBG(fmt, arg...) \
59 printk(KERN_INFO "[H2W] %s " fmt "\r\n", __func__, ## arg)
60#else
61#define H2W_DBG(fmt, arg...) do {} while (0)
62#endif
63
64void detect_h2w_do_work(struct work_struct *w);
65
66static struct workqueue_struct *detect_wq;
67static struct workqueue_struct *button_wq;
68
69static DECLARE_DELAYED_WORK(detect_h2w_work, detect_h2w_do_work);
70
71static void insert_35mm_do_work(struct work_struct *work);
72static DECLARE_WORK(insert_35mm_work, insert_35mm_do_work);
73static void remove_35mm_do_work(struct work_struct *work);
74static DECLARE_WORK(remove_35mm_work, remove_35mm_do_work);
75static void button_35mm_do_work(struct work_struct *work);
76static DECLARE_WORK(button_35mm_work, button_35mm_do_work);
77
78struct h35_info {
79 struct mutex mutex_lock;
80 struct switch_dev hs_change;
81 unsigned long insert_jiffies;
82 int ext_35mm_status;
83 int is_ext_insert;
84 int key_code;
85 int mic_bias_state;
86 int *is_hpin_stable;
87 struct input_dev *input;
88
89 struct wake_lock headset_wake_lock;
90};
91
92static struct h35mm_platform_data *pd;
93static struct h35_info *hi;
94
95static ssize_t h35mm_print_name(struct switch_dev *sdev, char *buf)
96{
97 return sprintf(buf, "Headset\n");
98}
99
100static void button_35mm_do_work(struct work_struct *work)
101{
102 int key = 0;
103 int pressed = 0;
104
105 if (!hi->is_ext_insert) {
106 /* no headset ignor key event */
107 H2WI("3.5mm headset is plugged out, skip report key event");
108 return;
109 }
110
111 switch (hi->key_code) {
112 case 0x1: /* Play/Pause */
113 H2WI("3.5mm RC: Play Pressed");
114 key = KEY_MEDIA;
115 pressed = 1;
116 break;
117 case 0x2:
118 H2WI("3.5mm RC: BACKWARD Pressed");
119 key = KEY_PREVIOUSSONG;
120 pressed = 1;
121 break;
122 case 0x3:
123 H2WI("3.5mm RC: FORWARD Pressed");
124 key = KEY_NEXTSONG;
125 pressed = 1;
126 break;
127 case 0x81: /* Play/Pause */
128 H2WI("3.5mm RC: Play Released");
129 key = KEY_MEDIA;
130 pressed = 0;
131 break;
132 case 0x82:
133 H2WI("3.5mm RC: BACKWARD Released");
134 key = KEY_PREVIOUSSONG;
135 pressed = 0;
136 break;
137 case 0x83:
138 H2WI("3.5mm RC: FORWARD Released");
139 key = KEY_NEXTSONG;
140 pressed = 0;
141 break;
142 default:
143 H2WI("3.5mm RC: Unknown Button (0x%x) Pressed", hi->key_code);
144 return;
145 }
146 input_report_key(hi->input, key, pressed);
147 input_sync(hi->input);
148
149 wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
150}
151
152static void remove_35mm_do_work(struct work_struct *work)
153{
154 wake_lock_timeout(&hi->headset_wake_lock, 2.5*HZ);
155
156 H2W_DBG("");
157 /*To solve the insert, remove, insert headset problem*/
158 if (time_before_eq(jiffies, hi->insert_jiffies))
159 msleep(800);
160
161 if (hi->is_ext_insert) {
162 H2WI("Skip 3.5mm headset plug out!!!");
163 if (hi->is_hpin_stable)
164 *(hi->is_hpin_stable) = 1;
165 return;
166 }
167
168 pr_info("3.5mm_headset plug out\n");
169
170 if (pd->key_event_disable != NULL)
171 pd->key_event_disable();
172
173 if (hi->mic_bias_state) {
174 turn_mic_bias_on(0);
175 hi->mic_bias_state = 0;
176 }
177 hi->ext_35mm_status = 0;
178 if (hi->is_hpin_stable)
179 *(hi->is_hpin_stable) = 0;
180
181 /* Notify framework via switch class */
182 mutex_lock(&hi->mutex_lock);
183 switch_set_state(&hi->hs_change, hi->ext_35mm_status);
184 mutex_unlock(&hi->mutex_lock);
185}
186
187static void insert_35mm_do_work(struct work_struct *work)
188{
189 H2W_DBG("");
190 hi->insert_jiffies = jiffies + 1*HZ;
191
192 wake_lock_timeout(&hi->headset_wake_lock, 1.5*HZ);
193
194 if (hi->is_ext_insert) {
195 pr_info("3.5mm_headset plug in\n");
196
197 if (pd->key_event_enable != NULL)
198 pd->key_event_enable();
199
200 /* Turn On Mic Bias */
201 if (!hi->mic_bias_state) {
202 turn_mic_bias_on(1);
203 hi->mic_bias_state = 1;
204 /* Wait for pin stable */
205 msleep(300);
206 }
207
208 /* Detect headset with or without microphone */
209 if(pd->headset_has_mic) {
210 if (pd->headset_has_mic() == 0) {
211 /* without microphone */
212 pr_info("3.5mm without microphone\n");
213 hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
214 } else { /* with microphone */
215 pr_info("3.5mm with microphone\n");
216 hi->ext_35mm_status = BIT_HEADSET;
217 }
218 } else {
219 /* Assume no mic */
220 pr_info("3.5mm without microphone\n");
221 hi->ext_35mm_status = BIT_HEADSET_NO_MIC;
222 }
223 hi->ext_35mm_status |= BIT_35MM_HEADSET;
224
225 /* Notify framework via switch class */
226 mutex_lock(&hi->mutex_lock);
227 switch_set_state(&hi->hs_change, hi->ext_35mm_status);
228 mutex_unlock(&hi->mutex_lock);
229
230 if (hi->is_hpin_stable)
231 *(hi->is_hpin_stable) = 1;
232 }
233}
234
235int htc_35mm_key_event(int keycode, int *hpin_stable)
236{
237 hi->key_code = keycode;
238 hi->is_hpin_stable = hpin_stable;
239
240 if ((hi->ext_35mm_status & BIT_HEADSET) == 0) {
241 *(hi->is_hpin_stable) = 0;
242
243 pr_info("Key press with no mic. Retrying detection\n");
244 queue_work(detect_wq, &insert_35mm_work);
245 } else
246 queue_work(button_wq, &button_35mm_work);
247
248 return 0;
249}
250
251int htc_35mm_jack_plug_event(int insert, int *hpin_stable)
252{
253 if (!hi) {
254 pr_err("Plug event before driver init\n");
255 return -1;
256 }
257
258 mutex_lock(&hi->mutex_lock);
259 hi->is_ext_insert = insert;
260 hi->is_hpin_stable = hpin_stable;
261 mutex_unlock(&hi->mutex_lock);
262
263 H2WI(" %d", hi->is_ext_insert);
264 if (!hi->is_ext_insert)
265 queue_work(detect_wq, &remove_35mm_work);
266 else
267 queue_work(detect_wq, &insert_35mm_work);
268 return 1;
269}
270
271static int htc_35mm_probe(struct platform_device *pdev)
272{
273 int ret;
274
275 pd = pdev->dev.platform_data;
276
277 pr_info("H2W: htc_35mm_jack driver register\n");
278
279 hi = kzalloc(sizeof(struct h35_info), GFP_KERNEL);
280 if (!hi)
281 return -ENOMEM;
282
283 hi->ext_35mm_status = 0;
284 hi->is_ext_insert = 0;
285 hi->mic_bias_state = 0;
286
287 mutex_init(&hi->mutex_lock);
288
289 wake_lock_init(&hi->headset_wake_lock, WAKE_LOCK_SUSPEND, "headset");
290
291 hi->hs_change.name = "h2w";
292 hi->hs_change.print_name = h35mm_print_name;
293 ret = switch_dev_register(&hi->hs_change);
294 if (ret < 0)
295 goto err_switch_dev_register;
296
297 detect_wq = create_workqueue("detection");
298 if (detect_wq == NULL) {
299 ret = -ENOMEM;
300 goto err_create_detect_work_queue;
301 }
302
303 button_wq = create_workqueue("button");
304 if (button_wq == NULL) {
305 ret = -ENOMEM;
306 goto err_create_button_work_queue;
307 }
308
309 hi->input = input_allocate_device();
310 if (!hi->input) {
311 ret = -ENOMEM;
312 goto err_request_input_dev;
313 }
314
315 hi->input->name = "h2w headset";
316 set_bit(EV_SYN, hi->input->evbit);
317 set_bit(EV_KEY, hi->input->evbit);
318 set_bit(KEY_MEDIA, hi->input->keybit);
319 set_bit(KEY_NEXTSONG, hi->input->keybit);
320 set_bit(KEY_PLAYPAUSE, hi->input->keybit);
321 set_bit(KEY_PREVIOUSSONG, hi->input->keybit);
322 set_bit(KEY_MUTE, hi->input->keybit);
323 set_bit(KEY_VOLUMEUP, hi->input->keybit);
324 set_bit(KEY_VOLUMEDOWN, hi->input->keybit);
325 set_bit(KEY_END, hi->input->keybit);
326 set_bit(KEY_SEND, hi->input->keybit);
327
328 ret = input_register_device(hi->input);
329 if (ret < 0)
330 goto err_register_input_dev;
331
332 /* Enable plug events*/
333 if (pd->plug_event_enable == NULL) {
334 ret = -ENOMEM;
335 goto err_enable_plug_event;
336 }
337 if (pd->plug_event_enable() != 1) {
338 ret = -ENOMEM;
339 goto err_enable_plug_event;
340 }
341
342 return 0;
343
344err_enable_plug_event:
345err_register_input_dev:
346 input_free_device(hi->input);
347err_request_input_dev:
348 destroy_workqueue(button_wq);
349err_create_button_work_queue:
350 destroy_workqueue(detect_wq);
351err_create_detect_work_queue:
352 switch_dev_unregister(&hi->hs_change);
353err_switch_dev_register:
354 kzfree(hi);
355 pr_err("H2W: Failed to register driver\n");
356
357 return ret;
358}
359
360static int htc_35mm_remove(struct platform_device *pdev)
361{
362 H2W_DBG("");
363 switch_dev_unregister(&hi->hs_change);
364 kzfree(hi);
365
366#if 0 /* Add keys later */
367 input_unregister_device(hi->input);
368#endif
369 return 0;
370}
371
372static struct platform_driver htc_35mm_driver = {
373 .probe = htc_35mm_probe,
374 .remove = htc_35mm_remove,
375 .driver = {
376 .name = "htc_headset",
377 .owner = THIS_MODULE,
378 },
379};
380
381static int __init htc_35mm_init(void)
382{
383 H2W_DBG("");
384 return platform_driver_register(&htc_35mm_driver);
385}
386
387static void __exit htc_35mm_exit(void)
388{
389 platform_driver_unregister(&htc_35mm_driver);
390}
391
392module_init(htc_35mm_init);
393module_exit(htc_35mm_exit);
394
395MODULE_AUTHOR("Eric Olsen <eolsen@android.com>");
396MODULE_DESCRIPTION("HTC 3.5MM Driver");
397MODULE_LICENSE("GPL");