1
0
Fork 0
forked from len0rd/rockbox

Sansa Connect: Properly setup internal speaker

Switch to internal speaker when headphones are disconnected.

Change-Id: I7c04ac139ad540d85f960e9dadc2faaf4f856055
This commit is contained in:
Tomasz Moń 2021-06-14 14:44:24 +02:00
parent 756c0d2ac8
commit 02c4ec294c
2 changed files with 60 additions and 56 deletions

View file

@ -305,8 +305,8 @@ void aic3x_switch_output(bool stereo)
{ {
if (stereo) if (stereo)
{ {
/* mute MONO_LOP/M */ /* MONO_LOP/M not fully powered up */
aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x00, 0xF6); aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x00, 0xFE);
/* HPLOUT fully powered up */ /* HPLOUT fully powered up */
aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x01, 0xFF); aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x01, 0xFF);
/* HPROUT fully powered up */ /* HPROUT fully powered up */
@ -316,8 +316,8 @@ void aic3x_switch_output(bool stereo)
} }
else else
{ {
/* MONO_LOP/M not muted */ /* MONO_LOP/M fully powered up */
aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x09, 0xFF); aic3x_change_reg(AIC3X_MONO_LOP_M_LVL, 0x01, 0xFF);
/* HPLOUT not fully powered up */ /* HPLOUT not fully powered up */
aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x00, 0xFE); aic3x_change_reg(AIC3X_HPLOUT_LVL, 0x00, 0xFE);
/* HPROUT not fully powered up */ /* HPROUT not fully powered up */

View file

@ -7,7 +7,7 @@
* \/ \/ \/ \/ \/ * \/ \/ \/ \/ \/
* $Id: $ * $Id: $
* *
* Copyright (C) 2011 by Tomasz Moń * Copyright (C) 2011-2021 by Tomasz Moń
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -61,6 +61,7 @@
#define CMD_WHEEL_EN 0xD0 #define CMD_WHEEL_EN 0xD0
#define CMD_SET_INTCHRG 0xD1 #define CMD_SET_INTCHRG 0xD1
#define CMD_CODEC_RESET 0xD7 #define CMD_CODEC_RESET 0xD7
#define CMD_AMP_ENABLE 0xCA
#define CMD_FILL 0xFF #define CMD_FILL 0xFF
#define CMD_SYS_CTRL 0xDA #define CMD_SYS_CTRL 0xDA
@ -74,9 +75,9 @@ static struct mutex avr_mtx;
static int btn = 0; static int btn = 0;
static bool hold_switch; static bool hold_switch;
#ifndef BOOTLOADER #ifndef BOOTLOADER
static long btn_stack[DEFAULT_STACK_SIZE/sizeof(long)]; static long avr_stack[DEFAULT_STACK_SIZE/sizeof(long)];
static const char btn_thread_name[] = "buttons"; static const char avr_thread_name[] = "avr";
static struct event_queue btn_queue; static struct semaphore avr_thread_trigger;
#endif #endif
static int current_battery_level = 100; static int current_battery_level = 100;
@ -365,6 +366,13 @@ void avr_hid_reset_codec(void)
spi_txrx(codec_reset, NULL, sizeof(codec_reset)); spi_txrx(codec_reset, NULL, sizeof(codec_reset));
} }
void avr_hid_set_amp_enable(unsigned char enable)
{
unsigned char amp_enable[4] = {CMD_SYNC, CMD_AMP_ENABLE, enable, CMD_CLOSE};
spi_txrx(amp_enable, NULL, sizeof(amp_enable));
}
void avr_hid_power_off(void) void avr_hid_power_off(void)
{ {
unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE}; unsigned char prg[4] = {CMD_SYNC, CMD_SYS_CTRL, SYS_CTRL_POWEROFF, CMD_CLOSE};
@ -373,36 +381,54 @@ void avr_hid_power_off(void)
} }
#ifndef BOOTLOADER #ifndef BOOTLOADER
void btn_thread(void) static bool avr_state_changed(void)
{ {
struct queue_event ev; return (IO_GIO_BITSET0 & 0x1) ? false : true;
}
static bool headphones_inserted(void)
{
return (IO_GIO_BITSET0 & 0x04) ? false : true;
}
static void set_audio_output(bool headphones)
{
if (headphones)
{
/* Stereo output on headphones */
avr_hid_set_amp_enable(0);
aic3x_switch_output(true);
}
else
{
/* Mono output on built-in speaker */
aic3x_switch_output(false);
avr_hid_set_amp_enable(1);
}
}
void avr_thread(void)
{
bool headphones_active_state = headphones_inserted();
bool headphones_state;
set_audio_output(headphones_active_state);
while (1) while (1)
{ {
queue_wait(&btn_queue, &ev); semaphore_wait(&avr_thread_trigger, TIMEOUT_BLOCK);
if (ev.id == SYS_USB_CONNECTED) if (avr_state_changed())
{ {
/* Allow USB to gain exclusive storage access */
usb_acknowledge(SYS_USB_CONNECTED_ACK);
}
/* Ignore all messages except BTN_INTERRUPT */
if (ev.id != BTN_INTERRUPT)
continue;
/* Enable back button interrupt */
IO_INTC_EINT1 |= INTR_EINT1_EXT0;
/* Read buttons state */ /* Read buttons state */
avr_hid_get_state(); avr_hid_get_state();
}
yield(); headphones_state = headphones_inserted();
if (headphones_state != headphones_active_state)
if (queue_empty(&btn_queue) && ((IO_GIO_BITSET0 & 0x1) == 0))
{ {
/* for some reason we have lost next interrupt */ set_audio_output(headphones_state);
queue_post(&btn_queue, BTN_INTERRUPT, 0); headphones_active_state = headphones_state;
} }
} }
} }
@ -412,39 +438,17 @@ void GIO0(void)
{ {
/* Clear interrupt */ /* Clear interrupt */
IO_INTC_IRQ1 = (1 << 5); IO_INTC_IRQ1 = (1 << 5);
/* Disable interrupt */
IO_INTC_EINT1 &= ~INTR_EINT1_EXT0;
/* interrupt will be enabled back after button read */ semaphore_release(&avr_thread_trigger);
queue_post(&btn_queue, BTN_INTERRUPT, 0);
}
static int headphones_inserted_callback(struct timeout *tmo)
{
(void)tmo;
if (IO_GIO_BITSET0 & 0x04)
{
aic3x_switch_output(false);
}
else
{
aic3x_switch_output(true);
}
return 0;
} }
void GIO2(void) __attribute__ ((section(".icode"))); void GIO2(void) __attribute__ ((section(".icode")));
void GIO2(void) void GIO2(void)
{ {
static struct timeout headphones_oneshot;
/* Clear interrupt */ /* Clear interrupt */
IO_INTC_IRQ1 = (1 << 7); IO_INTC_IRQ1 = (1 << 7);
timeout_register(&headphones_oneshot, headphones_inserted_callback, semaphore_release(&avr_thread_trigger);
HZ/2, 0);
} }
#endif #endif
@ -453,9 +457,9 @@ void button_init_device(void)
btn = 0; btn = 0;
hold_switch = false; hold_switch = false;
#ifndef BOOTLOADER #ifndef BOOTLOADER
queue_init(&btn_queue, true); semaphore_init(&avr_thread_trigger, 1, 1);
create_thread(btn_thread, btn_stack, sizeof(btn_stack), 0, create_thread(avr_thread, avr_stack, sizeof(avr_stack), 0,
btn_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE) avr_thread_name IF_PRIO(, PRIORITY_USER_INTERFACE)
IF_COP(, CPU)); IF_COP(, CPU));
#endif #endif
IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */ IO_GIO_DIR0 |= 0x01; /* Set GIO0 as input */