mirror of https://github.com/probonopd/MiniDexed
Add WM8960 support (#133)
Patch in WM8960 support by using Circle ae22928 from the develop branch Thanks @matemaciek and @rsta2pull/159/head
parent
901151a001
commit
addbd45282
@ -0,0 +1,182 @@ |
|||||||
|
diff --git a/include/circle/i2ssoundbasedevice.h b/include/circle/i2ssoundbasedevice.h
|
||||||
|
index 3cfe21a3..39dea460 100644
|
||||||
|
--- a/include/circle/i2ssoundbasedevice.h
|
||||||
|
+++ b/include/circle/i2ssoundbasedevice.h
|
||||||
|
@@ -26,6 +26,7 @@
|
||||||
|
#include <circle/gpiopin.h>
|
||||||
|
#include <circle/gpioclock.h>
|
||||||
|
#include <circle/dmasoundbuffers.h>
|
||||||
|
+#include <circle/logger.h>
|
||||||
|
#include <circle/types.h>
|
||||||
|
|
||||||
|
class CI2SSoundBaseDevice : public CSoundBaseDevice /// Low level access to the I2S sound device
|
||||||
|
@@ -98,7 +99,10 @@ class CI2SSoundBaseDevice : public CSoundBaseDevice /// Low level access to the
|
||||||
|
static unsigned RXCompletedHandler (boolean bStatus, u32 *pBuffer,
|
||||||
|
unsigned nChunkSize, void *pParam);
|
||||||
|
|
||||||
|
- boolean InitPCM51xx (u8 ucI2CAddress);
|
||||||
|
+ void LogWrite (TLogSeverity Severity, const char *pMessage, ...);
|
||||||
|
+ void DetectDAC ();
|
||||||
|
+ boolean InitDAC ();
|
||||||
|
+ template <size_t N> boolean SendAll (const u8 (&initBytes)[N][2]);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CInterruptSystem *m_pInterruptSystem;
|
||||||
|
diff --git a/lib/i2ssoundbasedevice.cpp b/lib/i2ssoundbasedevice.cpp
|
||||||
|
index c5df60a1..0825031b 100644
|
||||||
|
--- a/lib/i2ssoundbasedevice.cpp
|
||||||
|
+++ b/lib/i2ssoundbasedevice.cpp
|
||||||
|
@@ -164,21 +164,13 @@ boolean CI2SSoundBaseDevice::Start (void)
|
||||||
|
&& m_pI2CMaster != 0
|
||||||
|
&& !m_bI2CInited)
|
||||||
|
{
|
||||||
|
- if (m_ucI2CAddress != 0)
|
||||||
|
- {
|
||||||
|
- if (!InitPCM51xx (m_ucI2CAddress)) // fixed address, must succeed
|
||||||
|
- {
|
||||||
|
- m_bError = TRUE;
|
||||||
|
+ DetectDAC ();
|
||||||
|
|
||||||
|
- return FALSE;
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- else
|
||||||
|
+ if (!InitDAC ())
|
||||||
|
{
|
||||||
|
- if (!InitPCM51xx (0x4C)) // auto probing, ignore failure
|
||||||
|
- {
|
||||||
|
- InitPCM51xx (0x4D);
|
||||||
|
- }
|
||||||
|
+ m_bError = TRUE;
|
||||||
|
+
|
||||||
|
+ return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_bI2CInited = TRUE;
|
||||||
|
@@ -422,17 +414,51 @@ unsigned CI2SSoundBaseDevice::RXCompletedHandler (boolean bStatus, u32 *pBuffer,
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void CI2SSoundBaseDevice::LogWrite (TLogSeverity Severity, const char *pMessage, ...)
|
||||||
|
+{
|
||||||
|
+ va_list var;
|
||||||
|
+ va_start (var, pMessage);
|
||||||
|
+ CLogger::Get ()->WriteV ("CI2SSoundBaseDevice", Severity, pMessage, var);
|
||||||
|
+ va_end (var);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void CI2SSoundBaseDevice::DetectDAC () {
|
||||||
|
+ if (m_ucI2CAddress != 0)
|
||||||
|
+ {
|
||||||
|
+ return; // No need to guess if address is provided
|
||||||
|
+ }
|
||||||
|
+ static const u8 knownAddresses[] = {0x1A, 0x4C, 0x4D};
|
||||||
|
+ for (auto &address : knownAddresses)
|
||||||
|
+ {
|
||||||
|
+ int written = m_pI2CMaster->Write (address, nullptr, 0);
|
||||||
|
+ LogWrite (LogNotice, "Scan result at i2c address %u: %d", address, written);
|
||||||
|
+ if (written == 0) {
|
||||||
|
+ m_ucI2CAddress = address;
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+// For WM8960 i2c register is 7 bits and value is 9 bits,
|
||||||
|
+// so let's have a helper for packing this into two bytes
|
||||||
|
+#define SHIFT_BIT(r, v) {((v&0x0100)>>8) | (r<<1), (v&0xff)}
|
||||||
|
+
|
||||||
|
//
|
||||||
|
-// Taken from the file mt32pi.cpp from this project:
|
||||||
|
+// Based on the file mt32pi.cpp from this project:
|
||||||
|
//
|
||||||
|
// mt32-pi - A baremetal MIDI synthesizer for Raspberry Pi
|
||||||
|
// Copyright (C) 2020-2021 Dale Whinham <daleyo@gmail.com>
|
||||||
|
//
|
||||||
|
// Licensed under GPLv3
|
||||||
|
//
|
||||||
|
-boolean CI2SSoundBaseDevice::InitPCM51xx (u8 ucI2CAddress)
|
||||||
|
+boolean CI2SSoundBaseDevice::InitDAC ()
|
||||||
|
{
|
||||||
|
- static const u8 initBytes[][2] =
|
||||||
|
+ if (m_ucI2CAddress == 0)
|
||||||
|
+ {
|
||||||
|
+ return TRUE; // No DAC, no need to init
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ static const u8 initBytesPCM51xx[][2] =
|
||||||
|
{
|
||||||
|
// Set PLL reference clock to BCK (set SREF to 001b)
|
||||||
|
{ 0x0d, 0x10 },
|
||||||
|
@@ -444,9 +470,70 @@ boolean CI2SSoundBaseDevice::InitPCM51xx (u8 ucI2CAddress)
|
||||||
|
{ 0x41, 0x04 }
|
||||||
|
};
|
||||||
|
|
||||||
|
+ // based on https://github.com/RASPIAUDIO/ULTRA/blob/main/ultra.c
|
||||||
|
+ static const u8 initBytesWM8960[][2] =
|
||||||
|
+ {
|
||||||
|
+ // reset
|
||||||
|
+ SHIFT_BIT(15, 0x000),
|
||||||
|
+ // Power
|
||||||
|
+ SHIFT_BIT(25, 0x1FC),
|
||||||
|
+ SHIFT_BIT(26, 0x1F9),
|
||||||
|
+ SHIFT_BIT(47, 0x03C),
|
||||||
|
+ // Clock PLL
|
||||||
|
+ SHIFT_BIT(4, 0x001),
|
||||||
|
+ SHIFT_BIT(52, 0x027),
|
||||||
|
+ SHIFT_BIT(53, 0x086),
|
||||||
|
+ SHIFT_BIT(54, 0x0C2),
|
||||||
|
+ SHIFT_BIT(55, 0x026),
|
||||||
|
+ // ADC/DAC
|
||||||
|
+ SHIFT_BIT(5, 0x000),
|
||||||
|
+ SHIFT_BIT(7, 0x002),
|
||||||
|
+ // ALC and Noise control
|
||||||
|
+ SHIFT_BIT(20, 0x0F9),
|
||||||
|
+ SHIFT_BIT(17, 0x1FB),
|
||||||
|
+ SHIFT_BIT(18, 0x000),
|
||||||
|
+ SHIFT_BIT(19, 0x032),
|
||||||
|
+ // OUT1 volume
|
||||||
|
+ SHIFT_BIT(2, 0x16F),
|
||||||
|
+ SHIFT_BIT(3, 0x16F),
|
||||||
|
+ //SPK volume
|
||||||
|
+ SHIFT_BIT(40, 0x17F),
|
||||||
|
+ SHIFT_BIT(41, 0x178),
|
||||||
|
+ SHIFT_BIT(51, 0x08D),
|
||||||
|
+ // input volume
|
||||||
|
+ SHIFT_BIT(0, 0x13F),
|
||||||
|
+ SHIFT_BIT(1, 0x13F),
|
||||||
|
+ // INPUTS
|
||||||
|
+ SHIFT_BIT(32, 0x138),
|
||||||
|
+ SHIFT_BIT(33, 0x138),
|
||||||
|
+ // OUTPUTS
|
||||||
|
+ SHIFT_BIT(49, 0x0F7),
|
||||||
|
+ SHIFT_BIT(10, 0x1FF),
|
||||||
|
+ SHIFT_BIT(11, 0x1FF),
|
||||||
|
+ SHIFT_BIT(34, 0x100),
|
||||||
|
+ SHIFT_BIT(37, 0x100)
|
||||||
|
+ };
|
||||||
|
+
|
||||||
|
+ switch (m_ucI2CAddress)
|
||||||
|
+ {
|
||||||
|
+ case 0x4C:
|
||||||
|
+ case 0x4D:
|
||||||
|
+ return SendAll(initBytesPCM51xx);
|
||||||
|
+
|
||||||
|
+ case 0x1A:
|
||||||
|
+ return SendAll(initBytesWM8960);
|
||||||
|
+
|
||||||
|
+ default:
|
||||||
|
+ LogWrite (LogError, "Don't know how to init device at i2c address %u", m_ucI2CAddress);
|
||||||
|
+ return FALSE;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+template <size_t N> boolean CI2SSoundBaseDevice::SendAll (const u8 (&initBytes)[N][2])
|
||||||
|
+{
|
||||||
|
for (auto &command : initBytes)
|
||||||
|
{
|
||||||
|
- if ( m_pI2CMaster->Write (ucI2CAddress, &command, sizeof (command))
|
||||||
|
+ if ( m_pI2CMaster->Write (m_ucI2CAddress, &command, sizeof (command))
|
||||||
|
!= sizeof (command))
|
||||||
|
{
|
||||||
|
return FALSE;
|
Loading…
Reference in new issue