From d24edc605b9b52d3610efbb9cf691c437ea00746 Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Thu, 3 Jan 2019 20:46:54 -0500 Subject: Add HAVE_LINEOUT_DETECTION and associated logic This allows targets to automatically switch audio settings when the line out is plugged/unplugged. Only hooked up on the xDuoo X3, but there are other potential users. Change-Id: Ic46a329bc955cca2e2ad0335ca16295eab24ad59 --- apps/misc.c | 31 ++++++++++--- firmware/drivers/button.c | 52 ++++++++++++++++------ firmware/export/button.h | 5 ++- firmware/export/config/xduoox3.h | 3 ++ firmware/kernel/include/queue.h | 2 + firmware/target/mips/ingenic_jz47xx/codec-jz4760.c | 32 ++++++++++--- .../mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c | 11 ++++- 7 files changed, 109 insertions(+), 27 deletions(-) diff --git a/apps/misc.c b/apps/misc.c index 90865859cf..2106d11164 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -157,11 +157,11 @@ char *output_dyn_value(char *buf, value_abs /= scale; unit_no++; } - + value = (value < 0) ? -value_abs : value_abs; /* preserve sign */ fraction = (fraction * 1000 / scale) / 10; - if (value_abs >= 100 || fraction >= 100 || !unit_no) + if (value_abs >= 100 || fraction >= 100 || !unit_no) tbuf[0] = '\0'; else if (value_abs >= 10) snprintf(tbuf, sizeof(tbuf), "%01u", fraction / 10); @@ -521,7 +521,7 @@ void car_adapter_mode_init(void) #endif #ifdef HAVE_HEADPHONE_DETECTION -static void unplug_change(bool inserted) +static void hp_unplug_change(bool inserted) { static bool headphone_caused_pause = false; @@ -553,6 +553,18 @@ static void unplug_change(bool inserted) } #endif +#ifdef HAVE_LINEOUT_DETECTION +static void lo_unplug_change(bool inserted) +{ +#ifdef HAVE_LINEOUT_POWEROFF + lineout_set(inserted); +#else + (void)inserted; + audiohw_set_lineout_volume(0,0); +#endif +} +#endif + long default_event_handler_ex(long event, void (*callback)(void *), void *parameter) { #if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO) @@ -632,13 +644,22 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame #endif #ifdef HAVE_HEADPHONE_DETECTION case SYS_PHONE_PLUGGED: - unplug_change(true); + hp_unplug_change(true); return SYS_PHONE_PLUGGED; case SYS_PHONE_UNPLUGGED: - unplug_change(false); + hp_unplug_change(false); return SYS_PHONE_UNPLUGGED; #endif +#ifdef HAVE_LINEOUT_DETECTION + case SYS_LINEOUT_PLUGGED: + lo_unplug_change(true); + return SYS_LINEOUT_PLUGGED; + + case SYS_LINEOUT_UNPLUGGED: + lo_unplug_change(false); + return SYS_LINEOUT_UNPLUGGED; +#endif #if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO) /* stop playback if we receive a call */ case SYS_CALL_INCOMING: diff --git a/firmware/drivers/button.c b/firmware/drivers/button.c index 64668b4ebf..608fe7e33a 100644 --- a/firmware/drivers/button.c +++ b/firmware/drivers/button.c @@ -59,6 +59,9 @@ static bool remote_filter_first_keypress; #ifdef HAVE_HEADPHONE_DETECTION static bool phones_present = false; #endif +#ifdef HAVE_LINEOUT_DETECTION +static bool lineout_present = false; +#endif /* how long until repeat kicks in, in centiseconds */ #define REPEAT_START (30*HZ/100) @@ -94,12 +97,11 @@ static int button_read(void); #ifdef HAVE_TOUCHSCREEN static int last_touchscreen_touch; -#endif +#endif #if defined(HAVE_HEADPHONE_DETECTION) static struct timeout hp_detect_timeout; /* Debouncer for headphone plug/unplug */ -/* This callback can be used for many different functions if needed - - just check to which object tmo points */ -static int btn_detect_callback(struct timeout *tmo) + +static int hp_detect_callback(struct timeout *tmo) { /* Try to post only transistions */ const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED; @@ -109,6 +111,19 @@ static int btn_detect_callback(struct timeout *tmo) } #endif +#if defined(HAVE_LINEOUT_DETECTION) +static struct timeout lo_detect_timeout; /* Debouncer for lineout plug/unplug */ + +static int lo_detect_callback(struct timeout *tmo) +{ + /* Try to post only transistions */ + const long id = tmo->data ? SYS_LINEOUT_PLUGGED : SYS_LINEOUT_UNPLUGGED; + queue_remove_from_head(&button_queue, id); + queue_post(&button_queue, id, 0); + return 0; +} +#endif + static bool button_try_post(int button, int data) { #ifdef HAVE_TOUCHSCREEN @@ -176,10 +191,19 @@ static void button_tick(void) { /* Use the autoresetting oneshot to debounce the detection signal */ phones_present = !phones_present; - timeout_register(&hp_detect_timeout, btn_detect_callback, + timeout_register(&hp_detect_timeout, hp_detect_callback, HZ/2, phones_present); } #endif +#if defined(HAVE_LINEOUT_DETECTION) + if (lineout_inserted() != lineout_present) + { + /* Use the autoresetting oneshot to debounce the detection signal */ + lineout_present = !lineout_present; + timeout_register(&lo_detect_timeout, lo_detect_callback, + HZ/2, lineout_present); + } +#endif /* Find out if a key has been released */ diff = btn ^ lastbtn; @@ -318,7 +342,7 @@ static void button_tick(void) #ifdef HAVE_BACKLIGHT #ifdef HAVE_REMOTE_LCD if (btn & BUTTON_REMOTE) { - if (!remote_filter_first_keypress + if (!remote_filter_first_keypress || is_remote_backlight_on(false) #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) || (remote_type()==REMOTETYPE_H300_NONLCD) @@ -427,7 +451,7 @@ static void button_queue_wait(struct queue_event *evp, int timeout) #endif button_boost(true); - break; + break; } if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick)) @@ -462,7 +486,7 @@ long button_get(bool block) long button_get_w_tmo(int ticks) { - struct queue_event ev; + struct queue_event ev; button_queue_wait(&ev, ticks); if (ev.id == SYS_TIMEOUT) @@ -496,7 +520,7 @@ void button_init(void) button_read(); lastbtn = button_read(); #endif - + reset_poweroff_timer(); #ifdef HAVE_LCD_BITMAP @@ -506,11 +530,11 @@ void button_init(void) filter_first_keypress = false; #ifdef HAVE_REMOTE_LCD remote_filter_first_keypress = false; -#endif +#endif #endif #ifdef HAVE_TOUCHSCREEN last_touchscreen_touch = 0xffff; -#endif +#endif /* Start polling last */ tick_add_task(button_tick); } @@ -647,7 +671,7 @@ static int button_read(void) #ifdef HAVE_TOUCHSCREEN if (btn & BUTTON_TOUCHSCREEN) last_touchscreen_touch = current_tick; -#endif +#endif /* Filter the button status. It is only accepted if we get the same status twice in a row. */ #ifndef HAVE_TOUCHSCREEN @@ -696,8 +720,8 @@ int touchscreen_last_touch(void) * [23:0] Velocity - degree/sec * * WHEEL_ACCEL_FACTOR: - * Value in degree/sec -- configurable via settings -- above which - * the accelerated scrolling starts. Factor is internally scaled by + * Value in degree/sec -- configurable via settings -- above which + * the accelerated scrolling starts. Factor is internally scaled by * 1<<16 in respect to the following 32bit integer operations. */ int button_apply_acceleration(const unsigned int data) diff --git a/firmware/export/button.h b/firmware/export/button.h index 7109c00f97..d9732ebe8b 100644 --- a/firmware/export/button.h +++ b/firmware/export/button.h @@ -44,7 +44,7 @@ int button_read_device(void); #ifdef HAS_BUTTON_HOLD bool button_hold(void); #endif -#ifdef HAS_REMOTE_BUTTON_HOLD +#ifdef HAS_REMOTE_BUTTON_HOLD bool remote_button_hold(void); #endif @@ -72,6 +72,9 @@ void set_remote_backlight_filter_keypress(bool value); #ifdef HAVE_HEADPHONE_DETECTION bool headphones_inserted(void); #endif +#ifdef HAVE_LINEOUT_DETECTION +bool lineout_inserted(void); +#endif #ifdef HAVE_WHEEL_POSITION int wheel_status(void); void wheel_send_events(bool send); diff --git a/firmware/export/config/xduoox3.h b/firmware/export/config/xduoox3.h index d4d6f2ee2f..b2c8930531 100644 --- a/firmware/export/config/xduoox3.h +++ b/firmware/export/config/xduoox3.h @@ -73,6 +73,9 @@ /* Define this if you can detect headphones */ #define HAVE_HEADPHONE_DETECTION +/* Define this if you can detect lineout */ +#define HAVE_LINEOUT_DETECTION + #define CONFIG_KEYPAD XDUOO_X3_PAD /* Define this if a programmable hotkey is mapped */ diff --git a/firmware/kernel/include/queue.h b/firmware/kernel/include/queue.h index afee4c90ff..515a7e43a8 100644 --- a/firmware/kernel/include/queue.h +++ b/firmware/kernel/include/queue.h @@ -65,6 +65,8 @@ #define SYS_PHONE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 3) #define SYS_REMOTE_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 4) #define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5) +#define SYS_LINEOUT_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 6) +#define SYS_LINEOUT_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 7) #define SYS_CAR_ADAPTER_RESUME MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 0) #define SYS_CALL_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3) #define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4) diff --git a/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c b/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c index 09d4858b34..a2de80a914 100644 --- a/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/codec-jz4760.c @@ -26,6 +26,7 @@ #include "pcm_sw_volume.h" #include "cs4398.h" #include "kernel.h" +#include "button.h" #define PIN_CS_RST (32*1+10) #define PIN_CODEC_PWRON (32*1+13) @@ -140,7 +141,11 @@ static int vol_tenthdb2hw(const int tdb) } } -void audiohw_set_volume(int vol_l, int vol_r) +#ifdef HAVE_LINEOUT_DETECTION +static int real_vol_l, real_vol_r; +#endif + +static void jz4760_set_vol(int vol_l, int vol_r) { uint8_t val = cs4398_read_reg(CS4398_REG_MISC) &~ CS4398_FREEZE; cs4398_write_reg(CS4398_REG_MISC, val | CS4398_FREEZE); @@ -149,14 +154,31 @@ void audiohw_set_volume(int vol_l, int vol_r) cs4398_write_reg(CS4398_REG_MISC, val); } +void audiohw_set_volume(int vol_l, int vol_r) +{ +#ifdef HAVE_LINEOUT_DETECTION + real_vol_l = vol_l; + real_vol_r = vol_r; + + if (lineout_inserted()) { + vol_l = 0; + vol_r = 0; + } +#endif + jz4760_set_vol(vol_l, vol_r); +} + void audiohw_set_lineout_volume(int vol_l, int vol_r) { -#if 0 /* unused */ - cs4398_write_reg(CS4398_REG_VOL_A, vol_tenthdb2hw(vol_l)); - cs4398_write_reg(CS4398_REG_VOL_B, vol_tenthdb2hw(vol_r)); -#else (void)vol_l; (void)vol_r; + +#ifdef HAVE_LINEOUT_DETECTION + if (lineout_inserted()) { + jz4760_set_vol(0, 0); + } else { + jz4760_set_vol(real_vol_l, real_vol_r); + } #endif } diff --git a/firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c index be02167a5d..d227255b8a 100644 --- a/firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c +++ b/firmware/target/mips/ingenic_jz47xx/xduoo_x3/sadc-xduoo_x3.c @@ -53,6 +53,13 @@ bool headphones_inserted(void) return (__gpio_get_pin(PIN_PH_DECT) != 0); } +bool lineout_inserted(void) +{ + /* We want to prevent LO being "enabled" if HP is attached + to avoid potential eardrum damage */ + return (__gpio_get_pin(PIN_LO_DECT) == 0) && !headphones_inserted(); +} + void button_init_device(void) { key_val = 0xfff; @@ -72,11 +79,11 @@ void button_init_device(void) __gpio_set_pin(PIN_CHARGE_CON); /* 0.7 A */ __gpio_as_output(PIN_CHARGE_CON); - __gpio_as_input(PIN_LO_DECT); __gpio_as_input(PIN_PH_DECT); + __gpio_disable_pull(PIN_PH_DECT); + __gpio_as_input(PIN_LO_DECT); __gpio_disable_pull(PIN_LO_DECT); - __gpio_disable_pull(PIN_PH_DECT); } bool button_hold(void) -- cgit v1.2.3