diff --git a/services/codec/src/api.rs b/services/codec/src/api.rs index 3cefec0f5..c19f5fafe 100644 --- a/services/codec/src/api.rs +++ b/services/codec/src/api.rs @@ -44,10 +44,21 @@ pub(crate) enum Opcode { /// set headphone volume -- L&R channels are ganged together in this API, but codec can do separately SetHeadphoneVolume, + /// get headphone type code + GetHeadphoneCode, + /// Suspend/resume callback SuspendResume, } +#[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)] +pub enum HeadphoneState { + NotPresent = 0, + PresentWithMic = 1, + PresentWithoutMic = 2, + Reserved = 3, + CodecOff = 4, +} #[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive)] pub enum VolumeOps { diff --git a/services/codec/src/backend/tlv320aic3100.rs b/services/codec/src/backend/tlv320aic3100.rs index 65f93a13e..041d00e40 100644 --- a/services/codec/src/backend/tlv320aic3100.rs +++ b/services/codec/src/backend/tlv320aic3100.rs @@ -310,7 +310,9 @@ impl Codec { pub fn get_headset_code(&mut self) -> u8 { self.w(0, &[0]); let mut code: [u8; 1] = [0; 1]; - self.r(67, &mut code); + if !self.r(67, &mut code) { + log::warn!("headset code read unsuccessful"); + }; code[0] } diff --git a/services/codec/src/lib.rs b/services/codec/src/lib.rs index 28a7f429e..97e1b4e4c 100644 --- a/services/codec/src/lib.rs +++ b/services/codec/src/lib.rs @@ -142,6 +142,20 @@ impl Codec { _ => Err(xous::Error::InternalError) } } + pub fn poll_headphone_state(&self) -> Result { + match send_message(self.conn, + Message::new_blocking_scalar(Opcode::GetHeadphoneCode.to_usize().unwrap(), 0, 0, 0, 0) + ) { + Ok(xous::Result::Scalar1(code)) => { + let retcode: Option = FromPrimitive::from_usize(code); + match retcode { + Some(code) => Ok(code), + None => Err(xous::Error::InternalError), + } + } + _ => Err(xous::Error::InternalError) + } + } } use core::sync::atomic::{AtomicU32, Ordering}; diff --git a/services/codec/src/main.rs b/services/codec/src/main.rs index d37153d47..545e845ac 100644 --- a/services/codec/src/main.rs +++ b/services/codec/src/main.rs @@ -218,6 +218,29 @@ fn main() -> ! { }; codec.set_headphone_gain_db(headphone_analog_gain_db, headphone_analog_gain_db); }), + Some(api::Opcode::GetHeadphoneCode) => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { + if codec.is_init() && codec.is_on() { + let hp_code = codec.get_headset_code(); + if hp_code & 0x80 != 0x80 { + log::warn!("Headphone detection polled, but detection is not enabled in hardware!"); + } + log::debug!("headset code: 0x{:x}", hp_code); + let code = if hp_code == 0xff { // kind of a hack, we could also check codec power state + HeadphoneState::CodecOff + } else { + match (hp_code >> 5) & 0x3 { + 0b00 => HeadphoneState::NotPresent, + 0b01 => HeadphoneState::PresentWithoutMic, + 0b10 => HeadphoneState::Reserved, + 0b11 => HeadphoneState::PresentWithMic, + _ => HeadphoneState::Reserved, + } + }; + xous::return_scalar(msg.sender, code as usize).ok(); + } else { + xous::return_scalar(msg.sender, HeadphoneState::CodecOff as usize).ok(); + } + }), None => { log::error!("couldn't convert opcode"); break