diff options
author | Michael Sevakis <jethead71@rockbox.org> | 2009-01-23 20:55:17 +0000 |
---|---|---|
committer | Michael Sevakis <jethead71@rockbox.org> | 2009-01-23 20:55:17 +0000 |
commit | 753b7a90e192dbfd1b268a78e200c103dcca80da (patch) | |
tree | f5b6526fe72e1e2203663d69ac9b34368daedffb /firmware/target/arm | |
parent | 34314b1993c0744922754fab1206413441367aea (diff) |
Gigabeat S: Add remote control reading and proper headphone insert detection. We need keymaps! A few were copied straight from Gigabeat F/X just to get things worked out.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@19830 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
3 files changed, 224 insertions, 22 deletions
diff --git a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c index 587e66e0bc..dec0aa108f 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-imx31.c +++ b/firmware/target/arm/imx31/gigabeat-s/button-imx31.c @@ -32,9 +32,6 @@ /* Most code in here is taken from the Linux BSP provided by Freescale * Copyright 2004-2006 Freescale Semiconductor, Inc. All Rights Reserved. */ -#ifdef HAVE_HEADPHONE_DETECTION -static bool headphones_detect = false; -#endif static uint32_t int_btn = BUTTON_NONE; static bool hold_button = false; #ifdef BOOTLOADER @@ -123,6 +120,16 @@ bool button_hold(void) return _button_hold(); } +#ifdef HAVE_HEADPHONE_DETECTION +/* Headphone driver pushes the data here */ +void button_headphone_set(int button) +{ + int oldstatus = disable_irq_save(); + int_btn = (int_btn & ~BUTTON_REMOTE) | button; + restore_irq(oldstatus); +} +#endif + int button_read_device(void) { /* Simple poll of GPIO status */ @@ -168,21 +175,6 @@ void button_power_event(void) restore_irq(oldlevel); } -#ifdef HAVE_HEADPHONE_DETECTION -/* This is called from the mc13783 interrupt thread */ -void headphone_detect_event(void) -{ - /* FIXME: Not really the correct method */ - headphones_detect = - (mc13783_read(MC13783_INTERRUPT_SENSE1) & MC13783_ONOFD2S) == 0; -} - -bool headphones_inserted(void) -{ - return headphones_detect; -} -#endif /* HAVE_HEADPHONE_DETECTION */ - void button_init_device(void) { #ifdef BOOTLOADER @@ -223,8 +215,7 @@ void button_init_device(void) mc13783_enable_event(MC13783_ONOFD1_EVENT); #ifdef HAVE_HEADPHONE_DETECTION - headphone_detect_event(); - mc13783_enable_event(MC13783_ONOFD2_EVENT); + headphone_init(); #endif } diff --git a/firmware/target/arm/imx31/gigabeat-s/button-target.h b/firmware/target/arm/imx31/gigabeat-s/button-target.h index 754694eee5..d970e9983c 100644 --- a/firmware/target/arm/imx31/gigabeat-s/button-target.h +++ b/firmware/target/arm/imx31/gigabeat-s/button-target.h @@ -37,6 +37,8 @@ int button_read_device(void); void button_power_event(void); void headphone_detect_event(void); bool headphones_inserted(void); +void headphone_init(void); +void button_headphone_set(int button); /* Toshiba Gigabeat S-specific button codes */ @@ -55,9 +57,17 @@ bool headphones_inserted(void); #define BUTTON_NEXT (1 << 11) #define BUTTON_POWER (1 << 12) /* Read from PMIC */ -#define BUTTON_MAIN (0x1fff) +#define BUTTON_MAIN (0x00001fff) -#define BUTTON_REMOTE 0 +/* Remote control buttons */ +#define BUTTON_RC_VOL_UP (1 << 13) +#define BUTTON_RC_VOL_DOWN (1 << 14) +#define BUTTON_RC_FF (1 << 15) +#define BUTTON_RC_REW (1 << 16) +#define BUTTON_RC_PLAY (1 << 17) +#define BUTTON_RC_DSP (1 << 18) + +#define BUTTON_REMOTE (0x0007e000) #define POWEROFF_BUTTON BUTTON_POWER #define POWEROFF_COUNT 10 diff --git a/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c new file mode 100644 index 0000000000..6043d00bf5 --- /dev/null +++ b/firmware/target/arm/imx31/gigabeat-s/headphone-gigabeat-s.c @@ -0,0 +1,201 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (c) 2009 by Michael Sevakis + * + * Driver to handle headphone jack events + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include "config.h" +#include "system.h" +#include "kernel.h" +#include "thread.h" +#include "mc13783.h" +#include "mc13783-target.h" +#include "adc.h" +#include "button.h" + +static struct wakeup headphone_wakeup; +static unsigned int headphone_thread_id; +static int headphone_stack[160/sizeof(int)]; /* Not much stack needed */ +static const char * const headphone_thread_name = "headphone"; +static bool headphones_detect = false; + +/* Convert ADC reading into a button value. */ +static int adc_data_to_button(unsigned int data) +{ + int btn = BUTTON_NONE; + + if (data < 505) + { + if (data < 252) + { + if (data < 149) + { + if (data >= 64) + { + /* Play/Pause */ + btn = BUTTON_RC_PLAY; + } + /* else headphone direct */ + } + else + { + /* DSP */ + btn = BUTTON_RC_DSP; + } + } + else + { + if (data < 370) + { + /* RW */ + btn = BUTTON_RC_REW; + } + else + { + /* FF */ + btn = BUTTON_RC_FF; + } + } + } + else + { + if (data < 870) + { + if (data < 675) + { + /* Vol + */ + btn = BUTTON_RC_VOL_UP; + } + else + { + /* Vol - */ + btn = BUTTON_RC_VOL_DOWN; + } + } +#if 0 + else + { + + if (data < 951) + { + /* No buttons */ + } + else + { + /* Not inserted */ + + } + } +#endif + } + + return btn; +} + +static void headphone_thread(void) +{ + int headphone_sleep_countdown = 0; + int headphone_wait_timeout = TIMEOUT_BLOCK; + + while (1) + { + int rc = wakeup_wait(&headphone_wakeup, headphone_wait_timeout); + unsigned int data = adc_read(ADC_HPREMOTE); + + if (rc == OBJ_WAIT_TIMEDOUT) + { + if (headphone_sleep_countdown <= 0) + { + /* Polling ADC */ + int btn, btn2; + + btn = adc_data_to_button(data); + sleep(HZ/50); + data = adc_read(ADC_HPREMOTE); + btn2 = adc_data_to_button(data); + + if (btn != btn2) + { + /* If the buttons dont agree twice in a row, then it's + * none (from meg-fx remote reader). */ + btn = BUTTON_NONE; + } + + button_headphone_set(btn); + continue; + } + + if (--headphone_sleep_countdown == 0) + { + /* Nothing has changed and remote is not present - + * go to sleep. */ + headphone_wait_timeout = TIMEOUT_BLOCK; + continue; + } + } + + headphones_detect = data <= 951; /* Max remote value */ + + /* Cancel any buttons if jack readings are unstable. */ + button_headphone_set(BUTTON_NONE); + + if (data >= 64 && data <= 951) + { + /* Should be a remote control - accelerate */ + headphone_wait_timeout = HZ/20-HZ/50; + headphone_sleep_countdown = 0; + } + else if (rc == OBJ_WAIT_SUCCEEDED) + { + /* Got signaled - something is being plugged/unplugged. Set + * countdown until we just give up and go to sleep (~10s). */ + headphone_wait_timeout = HZ/2; + headphone_sleep_countdown = 10*2; + } + } +} + +/* This is called from the mc13783 interrupt thread */ +void headphone_detect_event(void) +{ + /* Trigger the thread immediately. */ + wakeup_signal(&headphone_wakeup); +} + +/* Tell if anything is in the jack. */ +bool headphones_inserted(void) +{ + return headphones_detect; +} + +void headphone_init(void) +{ + /* A thread is required to monitor the remote ADC and jack state. */ + wakeup_init(&headphone_wakeup); + headphone_thread_id = create_thread(headphone_thread, + headphone_stack, + sizeof(headphone_stack), + 0, headphone_thread_name + IF_PRIO(, PRIORITY_REALTIME) + IF_COP(, CPU)); + + /* Initially poll and then enable PMIC event */ + headphone_detect_event(); + mc13783_enable_event(MC13783_ONOFD2_EVENT); +} |