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
This commit is contained in:
Solomon Peachy 2019-01-03 20:46:54 -05:00
parent 100f4338de
commit d24edc605b
7 changed files with 110 additions and 28 deletions

View file

@ -157,11 +157,11 @@ char *output_dyn_value(char *buf,
value_abs /= scale; value_abs /= scale;
unit_no++; unit_no++;
} }
value = (value < 0) ? -value_abs : value_abs; /* preserve sign */ value = (value < 0) ? -value_abs : value_abs; /* preserve sign */
fraction = (fraction * 1000 / scale) / 10; fraction = (fraction * 1000 / scale) / 10;
if (value_abs >= 100 || fraction >= 100 || !unit_no) if (value_abs >= 100 || fraction >= 100 || !unit_no)
tbuf[0] = '\0'; tbuf[0] = '\0';
else if (value_abs >= 10) else if (value_abs >= 10)
snprintf(tbuf, sizeof(tbuf), "%01u", fraction / 10); snprintf(tbuf, sizeof(tbuf), "%01u", fraction / 10);
@ -521,7 +521,7 @@ void car_adapter_mode_init(void)
#endif #endif
#ifdef HAVE_HEADPHONE_DETECTION #ifdef HAVE_HEADPHONE_DETECTION
static void unplug_change(bool inserted) static void hp_unplug_change(bool inserted)
{ {
static bool headphone_caused_pause = false; static bool headphone_caused_pause = false;
@ -553,6 +553,18 @@ static void unplug_change(bool inserted)
} }
#endif #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) long default_event_handler_ex(long event, void (*callback)(void *), void *parameter)
{ {
#if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO) #if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO)
@ -632,13 +644,22 @@ long default_event_handler_ex(long event, void (*callback)(void *), void *parame
#endif #endif
#ifdef HAVE_HEADPHONE_DETECTION #ifdef HAVE_HEADPHONE_DETECTION
case SYS_PHONE_PLUGGED: case SYS_PHONE_PLUGGED:
unplug_change(true); hp_unplug_change(true);
return SYS_PHONE_PLUGGED; return SYS_PHONE_PLUGGED;
case SYS_PHONE_UNPLUGGED: case SYS_PHONE_UNPLUGGED:
unplug_change(false); hp_unplug_change(false);
return SYS_PHONE_UNPLUGGED; return SYS_PHONE_UNPLUGGED;
#endif #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) #if CONFIG_PLATFORM & (PLATFORM_ANDROID|PLATFORM_MAEMO)
/* stop playback if we receive a call */ /* stop playback if we receive a call */
case SYS_CALL_INCOMING: case SYS_CALL_INCOMING:

View file

@ -59,6 +59,9 @@ static bool remote_filter_first_keypress;
#ifdef HAVE_HEADPHONE_DETECTION #ifdef HAVE_HEADPHONE_DETECTION
static bool phones_present = false; static bool phones_present = false;
#endif #endif
#ifdef HAVE_LINEOUT_DETECTION
static bool lineout_present = false;
#endif
/* how long until repeat kicks in, in centiseconds */ /* how long until repeat kicks in, in centiseconds */
#define REPEAT_START (30*HZ/100) #define REPEAT_START (30*HZ/100)
@ -94,12 +97,11 @@ static int button_read(void);
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
static int last_touchscreen_touch; static int last_touchscreen_touch;
#endif #endif
#if defined(HAVE_HEADPHONE_DETECTION) #if defined(HAVE_HEADPHONE_DETECTION)
static struct timeout hp_detect_timeout; /* Debouncer for headphone plug/unplug */ 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 hp_detect_callback(struct timeout *tmo)
static int btn_detect_callback(struct timeout *tmo)
{ {
/* Try to post only transistions */ /* Try to post only transistions */
const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED; const long id = tmo->data ? SYS_PHONE_PLUGGED : SYS_PHONE_UNPLUGGED;
@ -109,6 +111,19 @@ static int btn_detect_callback(struct timeout *tmo)
} }
#endif #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) static bool button_try_post(int button, int data)
{ {
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
@ -176,10 +191,19 @@ static void button_tick(void)
{ {
/* Use the autoresetting oneshot to debounce the detection signal */ /* Use the autoresetting oneshot to debounce the detection signal */
phones_present = !phones_present; phones_present = !phones_present;
timeout_register(&hp_detect_timeout, btn_detect_callback, timeout_register(&hp_detect_timeout, hp_detect_callback,
HZ/2, phones_present); HZ/2, phones_present);
} }
#endif #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 */ /* Find out if a key has been released */
diff = btn ^ lastbtn; diff = btn ^ lastbtn;
@ -318,7 +342,7 @@ static void button_tick(void)
#ifdef HAVE_BACKLIGHT #ifdef HAVE_BACKLIGHT
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
if (btn & BUTTON_REMOTE) { if (btn & BUTTON_REMOTE) {
if (!remote_filter_first_keypress if (!remote_filter_first_keypress
|| is_remote_backlight_on(false) || is_remote_backlight_on(false)
#if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES) #if defined(IRIVER_H100_SERIES) || defined(IRIVER_H300_SERIES)
|| (remote_type()==REMOTETYPE_H300_NONLCD) || (remote_type()==REMOTETYPE_H300_NONLCD)
@ -427,7 +451,7 @@ static void button_queue_wait(struct queue_event *evp, int timeout)
#endif #endif
button_boost(true); button_boost(true);
break; break;
} }
if (button_boosted && TIME_AFTER(current_tick, button_unboost_tick)) 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) long button_get_w_tmo(int ticks)
{ {
struct queue_event ev; struct queue_event ev;
button_queue_wait(&ev, ticks); button_queue_wait(&ev, ticks);
if (ev.id == SYS_TIMEOUT) if (ev.id == SYS_TIMEOUT)
@ -496,7 +520,7 @@ void button_init(void)
button_read(); button_read();
lastbtn = button_read(); lastbtn = button_read();
#endif #endif
reset_poweroff_timer(); reset_poweroff_timer();
#ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_BITMAP
@ -506,11 +530,11 @@ void button_init(void)
filter_first_keypress = false; filter_first_keypress = false;
#ifdef HAVE_REMOTE_LCD #ifdef HAVE_REMOTE_LCD
remote_filter_first_keypress = false; remote_filter_first_keypress = false;
#endif #endif
#endif #endif
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
last_touchscreen_touch = 0xffff; last_touchscreen_touch = 0xffff;
#endif #endif
/* Start polling last */ /* Start polling last */
tick_add_task(button_tick); tick_add_task(button_tick);
} }
@ -647,7 +671,7 @@ static int button_read(void)
#ifdef HAVE_TOUCHSCREEN #ifdef HAVE_TOUCHSCREEN
if (btn & BUTTON_TOUCHSCREEN) if (btn & BUTTON_TOUCHSCREEN)
last_touchscreen_touch = current_tick; last_touchscreen_touch = current_tick;
#endif #endif
/* Filter the button status. It is only accepted if we get the same /* Filter the button status. It is only accepted if we get the same
status twice in a row. */ status twice in a row. */
#ifndef HAVE_TOUCHSCREEN #ifndef HAVE_TOUCHSCREEN
@ -696,8 +720,8 @@ int touchscreen_last_touch(void)
* [23:0] Velocity - degree/sec * [23:0] Velocity - degree/sec
* *
* WHEEL_ACCEL_FACTOR: * WHEEL_ACCEL_FACTOR:
* Value in degree/sec -- configurable via settings -- above which * Value in degree/sec -- configurable via settings -- above which
* the accelerated scrolling starts. Factor is internally scaled by * the accelerated scrolling starts. Factor is internally scaled by
* 1<<16 in respect to the following 32bit integer operations. * 1<<16 in respect to the following 32bit integer operations.
*/ */
int button_apply_acceleration(const unsigned int data) int button_apply_acceleration(const unsigned int data)

View file

@ -44,7 +44,7 @@ int button_read_device(void);
#ifdef HAS_BUTTON_HOLD #ifdef HAS_BUTTON_HOLD
bool button_hold(void); bool button_hold(void);
#endif #endif
#ifdef HAS_REMOTE_BUTTON_HOLD #ifdef HAS_REMOTE_BUTTON_HOLD
bool remote_button_hold(void); bool remote_button_hold(void);
#endif #endif
@ -72,6 +72,9 @@ void set_remote_backlight_filter_keypress(bool value);
#ifdef HAVE_HEADPHONE_DETECTION #ifdef HAVE_HEADPHONE_DETECTION
bool headphones_inserted(void); bool headphones_inserted(void);
#endif #endif
#ifdef HAVE_LINEOUT_DETECTION
bool lineout_inserted(void);
#endif
#ifdef HAVE_WHEEL_POSITION #ifdef HAVE_WHEEL_POSITION
int wheel_status(void); int wheel_status(void);
void wheel_send_events(bool send); void wheel_send_events(bool send);

View file

@ -73,6 +73,9 @@
/* Define this if you can detect headphones */ /* Define this if you can detect headphones */
#define HAVE_HEADPHONE_DETECTION #define HAVE_HEADPHONE_DETECTION
/* Define this if you can detect lineout */
#define HAVE_LINEOUT_DETECTION
#define CONFIG_KEYPAD XDUOO_X3_PAD #define CONFIG_KEYPAD XDUOO_X3_PAD
/* Define this if a programmable hotkey is mapped */ /* Define this if a programmable hotkey is mapped */

View file

@ -65,6 +65,8 @@
#define SYS_PHONE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 3) #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_PLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 4)
#define SYS_REMOTE_UNPLUGGED MAKE_SYS_EVENT(SYS_EVENT_CLS_PLUG, 5) #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_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_INCOMING MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 3)
#define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4) #define SYS_CALL_HUNG_UP MAKE_SYS_EVENT(SYS_EVENT_CLS_MISC, 4)

View file

@ -26,6 +26,7 @@
#include "pcm_sw_volume.h" #include "pcm_sw_volume.h"
#include "cs4398.h" #include "cs4398.h"
#include "kernel.h" #include "kernel.h"
#include "button.h"
#define PIN_CS_RST (32*1+10) #define PIN_CS_RST (32*1+10)
#define PIN_CODEC_PWRON (32*1+13) #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; uint8_t val = cs4398_read_reg(CS4398_REG_MISC) &~ CS4398_FREEZE;
cs4398_write_reg(CS4398_REG_MISC, val | 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); 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) 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_l;
(void)vol_r; (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 #endif
} }

View file

@ -53,6 +53,13 @@ bool headphones_inserted(void)
return (__gpio_get_pin(PIN_PH_DECT) != 0); 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) void button_init_device(void)
{ {
key_val = 0xfff; key_val = 0xfff;
@ -72,11 +79,11 @@ void button_init_device(void)
__gpio_set_pin(PIN_CHARGE_CON); /* 0.7 A */ __gpio_set_pin(PIN_CHARGE_CON); /* 0.7 A */
__gpio_as_output(PIN_CHARGE_CON); __gpio_as_output(PIN_CHARGE_CON);
__gpio_as_input(PIN_LO_DECT);
__gpio_as_input(PIN_PH_DECT); __gpio_as_input(PIN_PH_DECT);
__gpio_disable_pull(PIN_LO_DECT);
__gpio_disable_pull(PIN_PH_DECT); __gpio_disable_pull(PIN_PH_DECT);
__gpio_as_input(PIN_LO_DECT);
__gpio_disable_pull(PIN_LO_DECT);
} }
bool button_hold(void) bool button_hold(void)