From 2ed840237916263c952d738df1176b2450e18b16 Mon Sep 17 00:00:00 2001 From: Markinus Date: Tue, 31 Aug 2010 14:04:06 +0200 Subject: [PATCH] htcleo: add headset driver There is a problem with the Mic GPIO. This isnt comming.. This has to be fixed. --- arch/arm/configs/htcleo_defconfig | 12 +- arch/arm/mach-msm/atmega_microp_common.c | 41 +++++ arch/arm/mach-msm/board-htcleo-microp.c | 18 -- arch/arm/mach-msm/board-htcleo.c | 46 +++++- arch/arm/mach-msm/htc_headset_gpio.c | 154 +++++++++++++++++- .../arm/mach-msm/include/mach/atmega_microp.h | 3 + .../mach-msm/include/mach/htc_headset_gpio.h | 2 + 7 files changed, 252 insertions(+), 24 deletions(-) diff --git a/arch/arm/configs/htcleo_defconfig b/arch/arm/configs/htcleo_defconfig index 314cbe67..1cf84c47 100644 --- a/arch/arm/configs/htcleo_defconfig +++ b/arch/arm/configs/htcleo_defconfig @@ -209,16 +209,26 @@ CONFIG_MSM_DEBUG_UART_NONE=y # CONFIG_MSM_DEBUG_UART2 is not set # CONFIG_MSM_DEBUG_UART3 is not set +# +# HTC headset driver +# +CONFIG_HTC_HEADSET_MGR=y +# CONFIG_HTC_HEADSET_H2W is not set +CONFIG_HTC_HEADSET_GPIO=y +# CONFIG_HTC_HEADSET_MICROP is not set +# CONFIG_HTC_HEADSET_PMIC is not set + # # MSM Board Type # CONFIG_AAT1271_FLASHLIGHT=y +CONFIG_MICROP_COMMON=y CONFIG_MACH_HTCLEO=y # CONFIG_MACH_SWORDFISH is not set # CONFIG_MACH_MAHIMAHI is not set # CONFIG_MACH_QSD8X50_FFA is not set # CONFIG_HTC_HEADSET is not set -CONFIG_HTC_35MM_JACK=y +# CONFIG_HTC_35MM_JACK is not set # CONFIG_HTC_PWRSPLY is not set # CONFIG_HTC_PWRSINK is not set # CONFIG_MSM_DALRPC_TEST is not set diff --git a/arch/arm/mach-msm/atmega_microp_common.c b/arch/arm/mach-msm/atmega_microp_common.c index 6f4ef098..c7b3f72f 100644 --- a/arch/arm/mach-msm/atmega_microp_common.c +++ b/arch/arm/mach-msm/atmega_microp_common.c @@ -234,6 +234,47 @@ int microp_write_interrupt(struct i2c_client *client, return ret; } +int microp_set_adc_req(uint8_t value) +{ + struct i2c_client *client; + int ret; + uint8_t cmd[1]; + + client = private_microp_client; + cmd[0] = value; + ret = i2c_write_block(client, MICROP_I2C_WCMD_ADC_REQ, cmd, 1); + if (ret < 0) + { + dev_err(&client->dev, "%s: request adc fail\n", __func__); + return -EIO; + } + + return 0; +} + +int microp_get_remote_adc(uint32_t *val) +{ + struct i2c_client *client; + int ret; + uint8_t data[4]; + + if (!val) + return -EIO; + + client = private_microp_client; + ret = i2c_read_block(client, MICROP_I2C_RCMD_ADC_VALUE, data, 2); + if (ret < 0) + { + dev_err(&client->dev, "%s: request adc fail\n", __func__); + return -EIO; + } + +// printk("%x %x\n", data[0], data[1]); + *val = data[1] | (data[0] << 8); + printk("remote adc %d\n", *val); + return 0; +} + int microp_read_adc(uint8_t *data) { struct i2c_client *client; diff --git a/arch/arm/mach-msm/board-htcleo-microp.c b/arch/arm/mach-msm/board-htcleo-microp.c index 1ce7c19c..25bbb29c 100644 --- a/arch/arm/mach-msm/board-htcleo-microp.c +++ b/arch/arm/mach-msm/board-htcleo-microp.c @@ -38,24 +38,6 @@ static int htcleo_microp_function_init(struct i2c_client *client) pdata = client->dev.platform_data; cdata = i2c_get_clientdata(client); - /* Headset remote key */ - ret = microp_function_check(client, MICROP_FUNCTION_REMOTEKEY); - if (ret >= 0) { - i = ret; - pdata->function_node[MICROP_FUNCTION_REMOTEKEY] = i; - cdata->int_pin.int_remotekey = - pdata->microp_function[i].int_pin; - - for (j = 0; j < 6; j++) { - data[j] = (uint8_t)(pdata->microp_function[i].levels[j] >> 8); - data[j + 6] = (uint8_t)(pdata->microp_function[i].levels[j]); - } - ret = microp_i2c_write(MICROP_I2C_WCMD_REMOTEKEY_TABLE, - data, 12); - if (ret) - goto exit; - } - /* Reset button interrupt */ ret = microp_write_interrupt(client, (1<<8), 1); if (ret) diff --git a/arch/arm/mach-msm/board-htcleo.c b/arch/arm/mach-msm/board-htcleo.c index 7c25b212..e8277e94 100644 --- a/arch/arm/mach-msm/board-htcleo.c +++ b/arch/arm/mach-msm/board-htcleo.c @@ -46,16 +46,20 @@ #include #include #include +#include +#include + +#ifdef CONFIG_MICROP_COMMON +#include +void __init htcleo_microp_init(void); +#endif + #include "board-htcleo.h" #include "board-htcleo-ts.h" #include "devices.h" #include "proc_comm.h" #include "dex_comm.h" -#ifdef CONFIG_MICROP_COMMON -#include -void __init htcleo_microp_init(void); -#endif extern int __init htcleo_init_mmc(unsigned debug_uart); extern void __init htcleo_audio_init(void); @@ -124,6 +128,38 @@ static struct regulator_init_data tps65023_data[5] = }, }, }; +/////////////////////////////////////////////////////////////////////// +// Headset +/////////////////////////////////////////////////////////////////////// + +static struct htc_headset_mgr_platform_data htc_headset_mgr_data = { +}; + +static struct platform_device htc_headset_mgr = { + .name = "HTC_HEADSET_MGR", + .id = -1, + .dev = { + .platform_data = &htc_headset_mgr_data, + }, +}; + +static struct htc_headset_gpio_platform_data htc_headset_gpio_data = { + .hpin_gpio = HTCLEO_GPIO_HDS_DET, + .mic_detect_gpio = HTCLEO_GPIO_HDS_MIC, + .microp_channel = 1, + .key_enable_gpio = NULL, + .mic_select_gpio = NULL, +}; + +static struct platform_device htc_headset_gpio = { + .name = "HTC_HEADSET_GPIO", + .id = -1, + .dev = { + .platform_data = &htc_headset_gpio_data, + }, +}; + + /////////////////////////////////////////////////////////////////////// // Compass @@ -610,6 +646,8 @@ static struct platform_device *devices[] __initdata = &htcleo_flashlight_device, &htcleo_power, &qsd_device_spi, + &htc_headset_mgr, + &htc_headset_gpio, }; /////////////////////////////////////////////////////////////////////// // Vibrator diff --git a/arch/arm/mach-msm/htc_headset_gpio.c b/arch/arm/mach-msm/htc_headset_gpio.c index f84a95e3..ea324535 100644 --- a/arch/arm/mach-msm/htc_headset_gpio.c +++ b/arch/arm/mach-msm/htc_headset_gpio.c @@ -33,6 +33,7 @@ #include #include +#include #include #include @@ -49,16 +50,20 @@ struct audio_jack_info { unsigned int irq_jack; + unsigned int irq_mic; int audio_jack_detect; int key_enable_gpio; int mic_select_gpio; int audio_jack_flag; + int mic_detect; + int last_pressed_key; + int microp_channel; struct hrtimer detection_timer; ktime_t debounce_time; struct work_struct work; - + struct work_struct mic_work; spinlock_t spin_lock; struct wake_lock audiojack_wake_lock; @@ -66,6 +71,25 @@ struct audio_jack_info { static struct audio_jack_info *pjack_info; +static int hs_gpio_get_mic(void) +{ + int value; + value = !gpio_get_value(pjack_info->mic_detect); + + printk("hs_gpio_get_mic: %d\n", value); + return value; +} + +static int hs_enable_key_irq(int status) +{ + printk("hs_enable_key_irq: %d\n", status); + if(status) + enable_irq(pjack_info->irq_mic); + else + disable_irq(pjack_info->irq_mic); + return 0; +} + void hs_gpio_key_enable(int enable) { DBG_MSG(); @@ -82,8 +106,72 @@ void hs_gpio_mic_select(int enable) gpio_set_value(pjack_info->mic_select_gpio, enable); } +static int get_remote_keycode(int *keycode) +{ + uint32_t val; + uint32_t btn = 0; + + microp_set_adc_req(pjack_info->microp_channel); + if (microp_get_remote_adc(&val)) + { + // failed. who know why? ignore + *keycode = 0; + return 1; + } + + if((val >= 0) && (val <= 33)) + { + btn = 1; + } + else if((val >= 38) && (val <= 82)) + { + btn = 2; + } + else if((val >= 95) && (val <= 200)) + { + btn = 3; + } + else if(val > 200) + { + // check previous key + if (pjack_info->last_pressed_key) + { + *keycode = pjack_info->last_pressed_key | 0x80; + pjack_info->last_pressed_key = 0; + return 0; + } + *keycode = 0; + return 1; + } + + pjack_info->last_pressed_key = btn; + *keycode = btn; + return 0; +} + +static irqreturn_t mic_irq_handler(int irq, void *dev_id) +{ + pr_info("MIC IRQ Handler\n"); + int value1, value2; + int retry_limit = 10; + + AJ_DBG(""); + + do { + value1 = gpio_get_value(pjack_info->mic_detect); + set_irq_type(pjack_info->irq_mic, value1 ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH); + value2 = gpio_get_value(pjack_info->mic_detect); + } while (value1 != value2 && retry_limit-- > 0); + + AJ_DBG("value2 = %d (%d retries)", value2, (10-retry_limit)); + + schedule_work(&pjack_info->mic_work); + return IRQ_HANDLED; +} + static irqreturn_t detect_irq_handler(int irq, void *dev_id) { + pr_info("DET IRQ Handler\n"); int value1, value2; int retry_limit = 10; @@ -125,9 +213,26 @@ static enum hrtimer_restart detect_35mm_event_timer_func(struct hrtimer *data) return HRTIMER_NORESTART; } +static void mic_work_func(struct work_struct *work) +{ + pr_info("MIC Schedule Work\n"); + int keycode = 0; + + printk("mic_intr_work_func\n"); + if (get_remote_keycode(&keycode) == 0) + { + printk("keycode %d\n", keycode); + htc_35mm_remote_notify_button_status(keycode); + } + else + printk("mic error keycode\n"); + +} + static void audiojack_work_func(struct work_struct *work) { int is_insert; + pr_info("DET Schedule Work\n"); unsigned long flags = 0; spin_lock_irqsave(&pjack_info->spin_lock, flags); @@ -157,6 +262,16 @@ static void hs_gpio_register(void) notifier.func = hs_gpio_key_enable; headset_notifier_register(¬ifier); } + + if (pjack_info->mic_detect) { + notifier.id = HEADSET_REG_MIC_STATUS; + notifier.func = hs_gpio_get_mic; + headset_notifier_register(¬ifier); + + notifier.id = HEADSET_REG_KEY_INT_ENABLE; + notifier.func = hs_enable_key_irq; + headset_notifier_register(¬ifier); + } } static int audiojack_probe(struct platform_device *pdev) @@ -173,7 +288,10 @@ static int audiojack_probe(struct platform_device *pdev) pjack_info->audio_jack_detect = pdata->hpin_gpio; pjack_info->key_enable_gpio = pdata->key_enable_gpio; pjack_info->mic_select_gpio = pdata->mic_select_gpio; + pjack_info->mic_detect = pdata->mic_detect_gpio; + pjack_info->microp_channel = pdata->microp_channel; pjack_info->audio_jack_flag = 0; + pjack_info->last_pressed_key = 0; pjack_info->debounce_time = ktime_set(0, 500000000); hrtimer_init(&pjack_info->detection_timer, @@ -181,6 +299,7 @@ static int audiojack_probe(struct platform_device *pdev) pjack_info->detection_timer.function = detect_35mm_event_timer_func; INIT_WORK(&pjack_info->work, audiojack_work_func); + INIT_WORK(&pjack_info->mic_work, mic_work_func); spin_lock_init(&pjack_info->spin_lock); wake_lock_init(&pjack_info->audiojack_wake_lock, @@ -212,8 +331,35 @@ static int audiojack_probe(struct platform_device *pdev) ret = set_irq_wake(pjack_info->irq_jack, 1); if (ret < 0) goto err_set_irq_wake; + pr_info("DET IRQ Registered!"); } + + if (pjack_info->mic_detect) { + ret = gpio_request(pjack_info->mic_detect, + "mic_detect"); + if (ret < 0) + goto err_request_detect_gpio; + + ret = gpio_direction_input(pjack_info->mic_detect); + if (ret < 0) + goto err_set_detect_gpio; + + pjack_info->irq_mic = + gpio_to_irq(pjack_info->mic_detect); + if (pjack_info->irq_mic < 0) { + ret = pjack_info->irq_mic; + goto err_request_detect_irq; + } + + ret = request_irq(pjack_info->irq_mic, + mic_irq_handler, IRQF_DISABLED | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW, "mic_headset", NULL); + if (ret < 0) + goto err_request_detect_irq; + + disable_irq(pjack_info->irq_mic); + pr_info("MIC IRQ Registered!"); + } hs_gpio_register(); SYS_MSG("--------------------"); @@ -238,9 +384,15 @@ static int audiojack_remove(struct platform_device *pdev) if (pjack_info->audio_jack_detect) free_irq(pjack_info->irq_jack, 0); + if (pjack_info->audio_jack_detect) + free_irq(pjack_info->irq_mic, 0); + if (pjack_info->audio_jack_detect) gpio_free(pjack_info->audio_jack_detect); + if (pjack_info->audio_jack_detect) + gpio_free(pjack_info->mic_detect); + return 0; } diff --git a/arch/arm/mach-msm/include/mach/atmega_microp.h b/arch/arm/mach-msm/include/mach/atmega_microp.h index 2b04dc58..46ff647b 100644 --- a/arch/arm/mach-msm/include/mach/atmega_microp.h +++ b/arch/arm/mach-msm/include/mach/atmega_microp.h @@ -91,6 +91,7 @@ #define MICROP_I2C_WCMD_READ_ADC_VALUE_REQ 0x60 #define MICROP_I2C_RCMD_ADC_VALUE 0x62 #define MICROP_I2C_WCMD_REMOTEKEY_TABLE 0x63 +#define MICROP_I2C_WCMD_ADC_REQ 0x64 #define MICROP_I2C_WCMD_LCM_BURST 0x6A #define MICROP_I2C_WCMD_LCM_BURST_EN 0x6B #define MICROP_I2C_WCMD_LCM_REGISTER 0x70 @@ -259,6 +260,8 @@ void microp_get_als_kvalue(int i); int microp_spi_vote_enable(int spi_device, uint8_t enable); void microp_register_ops(struct microp_ops *ops); +int microp_set_adc_req(uint8_t value); +int microp_get_remote_adc(uint32_t *val); int microp_read_adc(uint8_t *data); void microp_mobeam_enable(int enable); diff --git a/arch/arm/mach-msm/include/mach/htc_headset_gpio.h b/arch/arm/mach-msm/include/mach/htc_headset_gpio.h index f18ba47a..36e6af69 100644 --- a/arch/arm/mach-msm/include/mach/htc_headset_gpio.h +++ b/arch/arm/mach-msm/include/mach/htc_headset_gpio.h @@ -22,8 +22,10 @@ struct htc_headset_gpio_platform_data { unsigned int hpin_gpio; + unsigned int mic_detect_gpio; unsigned int key_enable_gpio; unsigned int mic_select_gpio; + unsigned int microp_channel; }; #endif