-
-
Notifications
You must be signed in to change notification settings - Fork 80
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Apply temporary patch to add WM8960 support
Closes #273.
- Loading branch information
Showing
2 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
From cb2b3843b3efa84d9ccf4d2f1c739b95b1404ec3 Mon Sep 17 00:00:00 2001 | ||
From: =?UTF-8?q?Maciej=20Soko=C5=82owski?= <matemaciek@gmail.com> | ||
Date: Thu, 21 Apr 2022 19:01:29 +0200 | ||
Subject: [PATCH] Add support for WM8960 to CI2SSoundBaseDevice | ||
|
||
--- | ||
include/circle/i2ssoundbasedevice.h | 6 +- | ||
lib/i2ssoundbasedevice.cpp | 121 ++++++++++++++++++++++++---- | ||
2 files changed, 109 insertions(+), 18 deletions(-) | ||
|
||
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, 0x170), | ||
+ SHIFT_BIT(41, 0x170), | ||
+ SHIFT_BIT(51, 0x0CD), | ||
+ // 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; |