add simple wm8994 codec driver

This commit is contained in:
Chaochao Cui 2020-11-28 17:02:11 +08:00 committed by Alan Carvalho de Assis
parent b1a042734f
commit fbb3cd660b
15 changed files with 4923 additions and 114 deletions

View File

@ -82,8 +82,8 @@ extern uint32_t _vectors[]; /* See stm32_vectors.S */
* Name: stm32_mco1config
*
* Description:
* Selects the clock source to output on MCO1 pin (PA8). PA8 should be configured in
* alternate function mode.
* Selects the clock source to output on MCO1 pin (PA8). PA8 should be configured
* in alternate function mode.
*
* Input Parameters:
* source - One of the definitions for the RCC_CFGR_MCO1 definitions from
@ -103,7 +103,7 @@ static inline void stm32_mco1config(uint32_t source, uint32_t div)
uint32_t regval;
regval = getreg32(STM32_RCC_CFGR);
regval &= ~(RCC_CFGR_MCO1_MASK|RCC_CFGR_MCO1PRE_MASK);
regval &= ~(RCC_CFGR_MCO1_MASK | RCC_CFGR_MCO1PRE_MASK);
regval |= (source | div);
putreg32(regval, STM32_RCC_CFGR);
}
@ -112,8 +112,8 @@ static inline void stm32_mco1config(uint32_t source, uint32_t div)
* Name: stm32_mco2config
*
* Description:
* Selects the clock source to output on MCO2 pin (PC9). PC9 should be configured in
* alternate function mode.
* Selects the clock source to output on MCO2 pin (PC9). PC9 should be configured
* in alternate function mode.
*
* Input Parameters:
* source - One of the definitions for the RCC_CFGR_MCO2 definitions from
@ -133,7 +133,7 @@ static inline void stm32_mco2config(uint32_t source, uint32_t div)
uint32_t regval;
regval = getreg32(STM32_RCC_CFGR);
regval &= ~(RCC_CFGR_MCO2_MASK|RCC_CFGR_MCO2PRE_MASK);
regval &= ~(RCC_CFGR_MCO2_MASK | RCC_CFGR_MCO2PRE_MASK);
regval |= (source | div);
putreg32(regval, STM32_RCC_CFGR);
}
@ -223,44 +223,44 @@ void stm32_clockenable(void);
void stm32_rcc_enablelse(void);
/****************************************************************************
/************************************************************************************
* Name: stm32_rcc_enablelsi
*
* Description:
* Enable the Internal Low-Speed (LSI) RC Oscillator.
*
****************************************************************************/
************************************************************************************/
void stm32_rcc_enablelsi(void);
/****************************************************************************
/************************************************************************************
* Name: stm32_rcc_disablelsi
*
* Description:
* Disable the Internal Low-Speed (LSI) RC Oscillator.
*
****************************************************************************/
************************************************************************************/
void stm32_rcc_disablelsi(void);
#if defined(CONFIG_STM32F7_STM32F76XX) || defined(CONFIG_STM32F7_STM32F77XX)
/****************************************************************************
/************************************************************************************
* Name: stm32f7x9_rcc_dsisrcphy
*
* Description:
* Set DSI clock source to DSI PHY
*
****************************************************************************/
************************************************************************************/
void stm32f7x9_rcc_dsisrcphy(void);
/****************************************************************************
/************************************************************************************
* Name: stm32f7x9_rcc_dsisrcpllr
*
* Description:
* Set DSI clock source to PLLR
*
****************************************************************************/
************************************************************************************/
void stm32f7x9_rcc_dsisrcpllr(void);
#endif

View File

@ -236,10 +236,8 @@ struct stm32f7_sai_s
#ifdef CONFIG_DEBUG_I2S_INFO
static void sai_dump_regs(struct stm32f7_sai_s *priv, const char *msg);
static void rcc_dump_regs(const char *msg);
#else
# define sai_dump_regs(s,m)
# define rcc_dump_regs(m)
#endif
/* Semaphore helpers */
@ -704,51 +702,6 @@ static void sai_dump_regs(struct stm32f7_sai_s *priv, const char *msg)
}
#endif
/****************************************************************************
* Name: rcc_dump_regs
*
* Description:
* Dump the contents of all rcc block registers
*
* Input Parameters:
* msg - Message to print before the register data
*
* Returned Value:
* None
*
****************************************************************************/
#ifdef CONFIG_DEBUG_I2S_INFO
static void rcc_dump_regs(const char *msg)
{
if (msg)
{
i2sinfo("%s\n", msg);
}
#if 0
/* RCC_PLLSAICFGR */
uint32_t pll_sai_cfgr = getreg32(STM32_RCC_PLLSAICFGR);
i2sinfo("PLLSAICFGR = %08x\n", pll_sai_cfgr);
uint32_t pllsain = (pll_sai_cfgr & RCC_PLLSAICFGR_PLLSAIN_MASK) >>
RCC_PLLSAICFGR_PLLSAIN_SHIFT;
i2sinfo("\t\tPLLSAICFGR PLLSAIN[14:6] = %d\n", pllsain);
uint32_t pllsaip = (pll_sai_cfgr & RCC_PLLSAICFGR_PLLSAIP_MASK) >>
RCC_PLLSAICFGR_PLLSAIP_SHIFT;
i2sinfo("\t\tPLLSAICFGR PLLSAIP[17:16] = %d\n", pllsaip);
uint32_t pllsaiq = (pll_sai_cfgr & RCC_PLLSAICFGR_PLLSAIQ_MASK) >>
RCC_PLLSAICFGQ_PLLSAIP_SHIFT;
i2sinfo("\t\tPLLSAICFGR PLLSAIQ[27:24] = %d\n", pllsaiq);
uint32_t pllsair = (pll_sai_cfgr & RCC_PLLSAICFGR_PLLSAIR_MASK) >>
RCC_PLLSAICFGR_PLLSAIP_SHIFT;
i2sinfo("\t\tPLLSAICFGR PLLSAIR[30:28] = %d\n", pllsair);
#endif
}
#endif
/****************************************************************************
* Name: sai_exclsem_take
*

View File

@ -241,7 +241,7 @@ static inline void rcc_enableahb1(void)
regval |= RCC_AHB1ENR_OTGHSEN;
#endif
#endif /* CONFIG_STM32F7_OTGFSHS */
#endif /* CONFIG_STM32F7_OTGFSHS */
putreg32(regval, STM32_RCC_AHB1ENR); /* Enable peripherals */
}
@ -857,7 +857,8 @@ static void stm32_stdclockconfig(void)
/* Wait until the PLL source is used as the system clock source */
while ((getreg32(STM32_RCC_CFGR) & RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL)
while ((getreg32(STM32_RCC_CFGR)
& RCC_CFGR_SWS_MASK) != RCC_CFGR_SWS_PLL)
{
}
@ -1001,7 +1002,3 @@ static inline void rcc_enableperipherals(void)
rcc_enableapb1();
rcc_enableapb2();
}
/****************************************************************************
* Public Functions
****************************************************************************/

View File

@ -0,0 +1,82 @@
#
# This file is autogenerated: PLEASE DO NOT EDIT IT.
#
# You can use "make menuconfig" to make any modifications to the installed .config file.
# You can then do "make savedefconfig" to generate a new defconfig file that includes your
# modifications.
#
# CONFIG_ARCH_FPU is not set
# CONFIG_SPI_CALLBACK is not set
CONFIG_ARCH="arm"
CONFIG_ARCH_BOARD="stm32f746g-disco"
CONFIG_ARCH_BOARD_STM32F746G_DISCO=y
CONFIG_ARCH_BUTTONS=y
CONFIG_ARCH_CHIP="stm32f7"
CONFIG_ARCH_CHIP_STM32F746NG=y
CONFIG_ARCH_CHIP_STM32F7=y
CONFIG_ARCH_STACKDUMP=y
CONFIG_ARMV7M_DCACHE=y
CONFIG_ARMV7M_DCACHE_WRITETHROUGH=y
CONFIG_ARMV7M_DTCM=y
CONFIG_ARMV7M_ICACHE=y
CONFIG_AUDIO_I2S=y
CONFIG_AUDIO_WM8994=y
CONFIG_BOARD_LATE_INITIALIZE=y
CONFIG_BOARD_LOOPSPERMSEC=43103
CONFIG_BUILTIN=y
CONFIG_DEBUG_ASSERTIONS=y
CONFIG_DEBUG_AUDIO=y
CONFIG_DEBUG_AUDIO_ERROR=y
CONFIG_DEBUG_AUDIO_INFO=y
CONFIG_DEBUG_AUDIO_WARN=y
CONFIG_DEBUG_ERROR=y
CONFIG_DEBUG_FEATURES=y
CONFIG_DEBUG_I2C=y
CONFIG_DEBUG_INFO=y
CONFIG_DEBUG_MEMCARD=y
CONFIG_DEBUG_MEMCARD_ERROR=y
CONFIG_DEBUG_SYMBOLS=y
CONFIG_DEBUG_WARN=y
CONFIG_DRIVERS_AUDIO=y
CONFIG_FS_PROCFS=y
CONFIG_FS_PROCFS_REGISTER=y
CONFIG_HAVE_CXX=y
CONFIG_HAVE_CXXINITIALIZE=y
CONFIG_I2C=y
CONFIG_INTELHEX_BINARY=y
CONFIG_MAX_TASKS=16
CONFIG_MMCSD=y
CONFIG_MM_REGIONS=3
CONFIG_NFILE_DESCRIPTORS=8
CONFIG_NSH_BUILTIN_APPS=y
CONFIG_NSH_DISABLE_IFUPDOWN=y
CONFIG_NSH_FILEIOSIZE=512
CONFIG_NSH_LINELEN=64
CONFIG_NSH_READLINE=y
CONFIG_PREALLOC_TIMERS=4
CONFIG_RAM_SIZE=245760
CONFIG_RAM_START=0x20010000
CONFIG_RAW_BINARY=y
CONFIG_RR_INTERVAL=200
CONFIG_SCHED_LPWORK=y
CONFIG_SCHED_WAITPID=y
CONFIG_SDCLONE_DISABLE=y
CONFIG_SPI=y
CONFIG_START_DAY=6
CONFIG_START_MONTH=12
CONFIG_START_YEAR=2011
CONFIG_STM32F7_DMA2=y
CONFIG_STM32F7_I2C3=y
CONFIG_STM32F7_SAI2=y
CONFIG_STM32F7_SAI2_A=y
CONFIG_STM32F7_SAI2_B=y
CONFIG_STM32F7_SAI2_B_SYNC_WITH_A=y
CONFIG_STM32F7_USART1=y
CONFIG_SYSLOG_CHAR=y
CONFIG_SYSLOG_DEVPATH="/dev/ttyS0"
CONFIG_SYSTEM_NSH=y
CONFIG_SYSTEM_VI=y
CONFIG_TASK_NAME_SIZE=0
CONFIG_USART1_SERIAL_CONSOLE=y
CONFIG_USER_ENTRYPOINT="nsh_main"
CONFIG_WM8994_REGDUMP=y

View File

@ -1,7 +1,7 @@
/****************************************************************************
/*****************************************************************************************
* boards/arm/stm32f7/stm32f746g-disco/include/board.h
*
* Copyright (C) 2015 Gregory Nutt. All rights reserved.
* Copyright (C) 2019 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -31,14 +31,14 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
*****************************************************************************************/
#ifndef __BOARDS_ARM_STM32F7_STM32F746G_DISCO_INCLUDE_BOARD_H
#define __BOARDS_ARM_STM32F7_STM32F746G_DISCO_INCLUDE_BOARD_H
/****************************************************************************
/*****************************************************************************************
* Included Files
****************************************************************************/
*****************************************************************************************/
#include <nuttx/config.h>
@ -48,11 +48,11 @@
/* No not include STM32 F7 header files here. */
/****************************************************************************
/*****************************************************************************************
* Pre-processor Definitions
****************************************************************************/
*****************************************************************************************/
/* Clocking *****************************************************************/
/* Clocking */
/* The STM32F7 Discovery board provides the following clock sources:
*
@ -154,15 +154,22 @@
/* Configure factors for PLLSAI clock */
#define CONFIG_STM32F7_PLLSAI 1
#define STM32_RCC_PLLSAICFGR_PLLSAIN RCC_PLLSAICFGR_PLLSAIN(BOARD_LTDC_PLLSAIN)
#define STM32_RCC_PLLSAICFGR_PLLSAIP RCC_PLLSAICFGR_PLLSAIP(2)
#define STM32_RCC_PLLSAICFGR_PLLSAIQ RCC_PLLSAICFGR_PLLSAIQ(2)
#define STM32_RCC_PLLSAICFGR_PLLSAIR RCC_PLLSAICFGR_PLLSAIR(BOARD_LTDC_PLLSAIR)
/* SAIx input frequency = 25 / M * N / Q / P
* 25000000 / 25 * 192 / 2 / 1
*/
#define STM32F7_SAI1_FREQUENCY (96000000)
#define STM32F7_SAI2_FREQUENCY (96000000)
/* Configure Dedicated Clock Configuration Register */
#define STM32_RCC_DCKCFGR1_PLLI2SDIVQ RCC_DCKCFGR1_PLLI2SDIVQ(1)
#define STM32_RCC_DCKCFGR1_PLLSAIDIVQ RCC_DCKCFGR1_PLLSAIDIVQ(1)
#define STM32_RCC_DCKCFGR1_PLLSAIDIVQ RCC_DCKCFGR1_PLLSAIDIVQ(0)
#define STM32_RCC_DCKCFGR1_PLLSAIDIVR RCC_DCKCFGR1_PLLSAIDIVR(1)
#define STM32_RCC_DCKCFGR1_SAI1SRC RCC_DCKCFGR1_SAI1SEL(0)
#define STM32_RCC_DCKCFGR1_SAI2SRC RCC_DCKCFGR1_SAI2SEL(0)
@ -172,6 +179,7 @@
/* Configure factors for PLLI2S clock */
#define CONFIG_STM32F7_PLLI2S 1
#define STM32_RCC_PLLI2SCFGR_PLLI2SN RCC_PLLI2SCFGR_PLLI2SN(192)
#define STM32_RCC_PLLI2SCFGR_PLLI2SP RCC_PLLI2SCFGR_PLLI2SP(2)
#define STM32_RCC_PLLI2SCFGR_PLLI2SQ RCC_PLLI2SCFGR_PLLI2SQ(2)
@ -253,7 +261,7 @@
#define BOARD_FLASH_WAITSTATES 7
/* LED definitions **********************************************************/
/* LED definitions */
/* The STM32F746G-DISCO board has numerous LEDs but only one, LD1 located
* near the reset button, that can be controlled by software (LD2 is a power
@ -306,7 +314,7 @@
#define LED_ASSERTION 2 /* LD1=no change */
#define LED_PANIC 3 /* LD1=flashing */
/* Button definitions *******************************************************/
/* Button definitions */
/* The STM32F7 Discovery supports one button:
* Pushbutton B1, labelled "User", is connected to GPIO PI11.
@ -317,7 +325,7 @@
#define NUM_BUTTONS 1
#define BUTTON_USER_BIT (1 << BUTTON_USER)
/* Alternate function pin selections ****************************************/
/* Alternate function pin selections */
/* USART6:
*
@ -361,12 +369,13 @@
/* I2C - There is a FT5336 TouchPanel on I2C3 using these pins: */
#define GPIO_I2C3_SCL GPIO_I2C3_SCL_2
#define GPIO_I2C3_SDA GPIO_I2C3_SDA_2
#define ADJ_SLEW_RATE(p) (((p) & ~GPIO_SPEED_MASK) | (GPIO_SPEED_100MHz))
#define GPIO_I2C3_SCL ADJ_SLEW_RATE(GPIO_I2C3_SCL_2)
#define GPIO_I2C3_SDA ADJ_SLEW_RATE(GPIO_I2C3_SDA_2)
#define GPIO_TP_INT (GPIO_INPUT|GPIO_FLOAT|GPIO_EXTI|GPIO_PORTI|GPIO_PIN13)
#define FT5x06_I2C_ADDRESS 0x38
#define FT5x06_I2C_ADDRESS (0x70 >> 1)
/* The STM32 F7 connects to a SMSC LAN8742A PHY using these pins:
*
@ -394,7 +403,7 @@
#define GPIO_ETH_RMII_TXD0 GPIO_ETH_RMII_TXD0_2
#define GPIO_ETH_RMII_TXD1 GPIO_ETH_RMII_TXD1_2
/* LCD definitions **********************************************************/
/* LCD definitions */
#define BOARD_LTDC_WIDTH 480
#define BOARD_LTDC_HEIGHT 272
@ -513,4 +522,21 @@
# define STM32_SDMMC_SDXFR_CLKDIV (2 << STM32_SDMMC_CLKCR_CLKDIV_SHIFT)
#endif
#endif /* __BOARDS_ARM_STM32F7_STM32F746G_DISCO_INCLUDE_BOARD_H */
/* SAI2 pinset */
#if defined(CONFIG_STM32F7_SAI2) && defined(CONFIG_STM32F7_SAI2_A)
#define GPIO_SAI2_SD_A GPIO_SAI2_SD_A_2
#define GPIO_SAI2_FS_A GPIO_SAI2_FS_A_2
#define GPIO_SAI2_SCK_A GPIO_SAI2_SCK_A_2
#define GPIO_SAI2_MCLK_A GPIO_SAI2_MCLK_A_2
#define GPIO_SAI2_SD_B GPIO_SAI2_SD_B_4
#define DMACHAN_SAI2_A DMAMAP_SAI2_A
#define DMACHAN_SAI2_B DMAMAP_SAI2_B
#else
#define GPIO_SAI1_SD_B GPIO_SAI1_SD_B_1
#define DMACHAN_SAI1_B DMAMAP_SAI1_B
#endif
#endif

View File

@ -1,7 +1,7 @@
############################################################################
# boards/arm/stm32f7/stm32f746g-disco/src/Makefile
#
# Copyright (C) 2015 Gregory Nutt. All rights reserved.
# Copyright (C) 2019 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
@ -83,4 +83,8 @@ ifeq ($(CONFIG_STM32F7_SDMMC), y)
CSRCS += stm32_sdmmc.c
endif
ifeq ($(CONFIG_AUDIO_WM8994), y)
CSRCS += stm32_wm8994.c
endif
include $(TOPDIR)/boards/Board.mk

View File

@ -154,6 +154,14 @@ int stm32_bringup(void)
}
#endif
#ifdef CONFIG_AUDIO_WM8994
ret = stm32_wm8994_initialize(0);
if (ret < 0)
{
syslog(LOG_ERR, "ERROR: stm32_wm8994_initialize failed: %d\n", ret);
}
#endif
UNUSED(ret); /* May not be used */
return OK;
}

View File

@ -0,0 +1,216 @@
/****************************************************************************
* boards/arm/stm32f7/stm32f746g-disco/src/stm32_wm8994.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <stdbool.h>
#include <stdio.h>
#include <debug.h>
#include <assert.h>
#include <errno.h>
#include <nuttx/irq.h>
#include <nuttx/i2c/i2c_master.h>
#include <nuttx/audio/i2s.h>
#include <nuttx/audio/wm8994.h>
#include <arch/board/board.h>
#include "stm32f746g-disco.h"
#include "stm32_i2c.h"
#include "stm32_sai.h"
#define HAVE_WM8994
#define WM8994_I2C_ADDRESS (0x34 >> 1)
#define WM8994_I2C_BUS 3
#define WM8994_SAI_BUS 2
#ifdef HAVE_WM8994
/****************************************************************************
* Private Types
****************************************************************************/
struct stm32_mwinfo_s
{
/* Standard ADAU1961 interface */
struct wm8994_lower_s lower;
};
/****************************************************************************
* Private Functions
****************************************************************************/
static int wm8994_attach(FAR const struct wm8994_lower_s *lower,
wm8994_handler_t isr, FAR void *arg)
{
audinfo("TODO\n");
return 0;
}
static bool wm8994_enable(FAR const struct wm8994_lower_s *lower,
bool enable)
{
audinfo("TODO\n");
return 0;
}
#if 0
static void wm8994_hw_reset(FAR const struct wm8994_lower_s *lower)
{
audinfo("TODO\n");
}
#endif
/****************************************************************************
* Private Data
****************************************************************************/
/* A reference to a structure of this type must be passed to the ADAU1961
* driver. This structure provides information about the configuration
* of the ADAU1961 and provides some board-specific hooks.
*
* Memory for this structure is provided by the caller. It is not copied
* by the driver and is presumed to persist while the driver is active.
*/
static struct stm32_mwinfo_s g_wm8994 =
{
.lower =
{
.address = WM8994_I2C_ADDRESS,
.frequency = I2C_SPEED_FAST, /* 100 kHz */
.mclk = 12000000, /* see MCO1 configuration */
.attach = wm8994_attach,
.enable = wm8994_enable,
}
};
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: stm32_wm8994_initialize
*
* Description:
* This function is called by platform-specific, setup logic to configure
* and register the ADAU1961 device. This function will register the driver
* as /dev/audio/pcm[x] where x is determined by the minor device number.
*
* Input Parameters:
* minor - The input device minor number
*
* Returned Value:
* Zero is returned on success. Otherwise, a negated errno value is
* returned to indicate the nature of the failure.
*
****************************************************************************/
int stm32_wm8994_initialize(int minor)
{
FAR struct audio_lowerhalf_s *wm8994;
FAR struct i2c_master_s *i2c;
FAR struct i2s_dev_s *i2s;
static bool initialized = false;
char devname[12];
int ret;
audinfo("minor %d\n", minor);
DEBUGASSERT(minor >= 0 && minor <= 25);
/* Initialize the CODEC if we have not already done so */
if (!initialized)
{
/* Configure MC01 to drive the master clock of the CODEC at 8MHz */
/* stm32_configgpio(GPIO_MCO1);
* stm32_mco1config(RCC_CFGR_MCO1_HSE, RCC_CFGR_MCO1PRE_NONE);
*/
/* Get an instance of the I2C interface for the CODEC */
i2c = stm32_i2cbus_initialize(WM8994_I2C_BUS);
if (!i2c)
{
auderr("stm32_i2cbus_initialize failed\n");
ret = -ENODEV;
goto error;
}
/* Get an instance of the I2S interface for the CODEC data streams */
i2s = stm32_sai_initialize(WM8994_SAI_BUS);
if (!i2s)
{
auderr("stm32_sai_initialize failed\n");
ret = -ENODEV;
goto error;
}
/* Now we can use these I2C and I2S interfaces to initialize the
* CODEC which will return an audio interface.
*/
wm8994 = wm8994_initialize(i2c, i2s, &g_wm8994.lower);
if (!wm8994)
{
auderr("wm8994_initialize failed\n");
ret = -ENODEV;
goto error;
}
/* Create a device name */
snprintf(devname, 12, "pcm%d", minor);
#if 0
/* Finally, we can register the ADAU1961/I2C/I2S audio device. */
ret = audio_register(devname, wm8994);
if (ret < 0)
{
auderr("failed to register /dev/%s device: %d\n", devname, ret);
goto error;
}
#endif
/* Now we are initialized */
initialized = true;
}
return OK;
/* Error exits. Unfortunately there is no mechanism in place now to
* recover resources from most errors on initialization failures.
*/
error:
return ret;
}
#endif /* HAVE_WM8994 */

View File

@ -1,4 +1,4 @@
/****************************************************************************
/*******************************************************************************
* boards/arm/stm32f7/stm32f746g-disco/src/stm32f746g-disco.h
*
* Copyright (C) 2015, 2017 Gregory Nutt. All rights reserved.
@ -31,22 +31,22 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
*******************************************************************************/
#ifndef __BOARDS_ARM_STM32F7_STM32F746G_DISCO_SRC_STM32F746G_DISCO__H
#define __BOARDS_ARM_STM32F7_STM32F746G_DISCO_SRC_STM32F746G_DISCO__H
/****************************************************************************
/*******************************************************************************
* Included Files
****************************************************************************/
*******************************************************************************/
#include <nuttx/config.h>
#include <nuttx/compiler.h>
#include <stdint.h>
/****************************************************************************
/*******************************************************************************
* Pre-processor Definitions
****************************************************************************/
*******************************************************************************/
/* procfs File System */
@ -64,7 +64,7 @@
#undef HAVE_SDIO
#endif
/* STM32F736G Discovery GPIOs ***********************************************/
/* STM32F736G Discovery GPIOs */
/* The STM32F746G-DISCO board has numerous LEDs but only one,
* LD1 located near the reset button, that can be controlled by software
@ -120,17 +120,13 @@
#define SDIO_SLOTNO 0
#define SDIO_MINOR 0
/****************************************************************************
/*******************************************************************************
* Public data
****************************************************************************/
*******************************************************************************/
#ifndef __ASSEMBLY__
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
/*******************************************************************************
* Name: stm32_bringup
*
* Description:
@ -142,70 +138,72 @@
* CONFIG_BOARD_LATE_INITIALIZE=n && CONFIG_LIB_BOARDCTL=y :
* Called from the NSH library
*
****************************************************************************/
*******************************************************************************/
int stm32_bringup(void);
/****************************************************************************
/*******************************************************************************
* Name: stm32_adc_setup
*
* Description:
* Initialize ADC and register the ADC driver.
*
****************************************************************************/
*******************************************************************************/
#ifdef CONFIG_ADC
int stm32_adc_setup(void);
#endif
/****************************************************************************
/*******************************************************************************
* Name: stm32_spidev_initialize
*
* Description:
* Called to configure SPI chip select GPIO pins for the stm32f746g-disco board.
* Called to configure SPI chip select GPIO pins for the
* stm32f746g-disco board.
*
****************************************************************************/
*******************************************************************************/
void weak_function stm32_spidev_initialize(void);
/****************************************************************************
/*******************************************************************************
* Name: arch_sporadic_initialize
*
* Description:
* This configuration has been used for evaluating the NuttX sporadic scheduler.
* This configuration has been used for evaluating the NuttX sporadic
* scheduler.
*
****************************************************************************/
*******************************************************************************/
#ifdef CONFIG_SPORADIC_INSTRUMENTATION
void arch_sporadic_initialize(void);
#endif
/****************************************************************************
/*******************************************************************************
* Name: stm32_enablefmc
*
* Description:
* enable clocking to the FMC module
*
****************************************************************************/
*******************************************************************************/
#ifdef CONFIG_STM32F7_FMC
void stm32_enablefmc(void);
#endif
/****************************************************************************
/*******************************************************************************
* Name: stm32_disablefmc
*
* Description:
* disable clocking to the FMC module
*
****************************************************************************/
*******************************************************************************/
#ifdef CONFIG_STM32F7_FMC
void stm32_disablefmc(void);
#endif
/****************************************************************************
/*******************************************************************************
* Name: stm32_tsc_setup
*
* Description:
@ -220,7 +218,7 @@ void stm32_disablefmc(void);
* Zero is returned on success. Otherwise, a negated errno value is
* returned to indicate the nature of the failure.
*
****************************************************************************/
*******************************************************************************/
#ifdef CONFIG_INPUT_FT5X06
int stm32_tsc_setup(int minor);
@ -234,6 +232,10 @@ int stm32_n25qxxx_setup(void);
int stm32_sdio_initialize(void);
#endif
#ifdef CONFIG_AUDIO_WM8994
int stm32_wm8994_initialize(int minor);
#endif
#endif /* __ASSEMBLY__ */
#endif /* __BOARDS_ARM_STM32F7_STM32F746G_DISCO_SRC_STM32F746G_DISCO_H */

View File

@ -234,6 +234,67 @@ config WM8776_SWAP_HPOUT
endif # AUDIO_WM8776
config AUDIO_WM8994
bool "WM8994 audio chip"
default n
depends on AUDIO
---help---
Select to enable support for the WM8994 Audio codec by Wolfson
Microelectonics. This chip is a lower level audio chip.. basically
an exotic D-to-A. It includes no built-in support for audio CODECS
The WM8994 provides:
- Low power consumption
- High SNR
- Stereo digital microphone input
- Digital Dynamic Range Controller (compressor / limiter)
- Digital sidetone mixing
- Ground-referenced headphone driver
- Ground-referenced line outputs
NOTE: This driver also depends on both I2C and I2S support although
that dependency is not explicit here.
if AUDIO_WM8994
config WM8994_INITVOLUME
int "WM8994 initial volume setting"
default 250
config WM8994_INFLIGHT
int "WM8994 maximum in-flight audio buffers"
default 2
config WM8994_MSG_PRIO
int "WM8994 message priority"
default 1
config WM8994_BUFFER_SIZE
int "WM8994 preferred buffer size"
default 8192
config WM8994_NUM_BUFFERS
int "WM8994 preferred number of buffers"
default 4
config WM8994_WORKER_STACKSIZE
int "WM8994 worker thread stack size"
default 768
config WM8994_REGDUMP
bool "WM8994 register dump"
default n
---help---
Enable logic to dump the contents of all WM8994 registers.
config WM8994_CLKDEBUG
bool "WM8994 clock analysis"
default n
---help---
Enable logic to analyze WM8994 clock configuation.
endif # AUDIO_WM8994
config AUDIO_WM8904
bool "WM8904 audio chip"
default n

View File

@ -65,6 +65,17 @@ ifeq ($(CONFIG_AUDIO_CS4344),y)
CSRCS += cs4344.c
endif
ifeq ($(CONFIG_AUDIO_WM8994),y)
CSRCS += wm8994.c
ifeq ($(CONFIG_WM8994_REGDUMP),y)
CSRCS += wm8994_debug.c
else
ifeq ($(CONFIG_WM8994_CLKDEBUG),y)
CSRCS += wm8994_debug.c
endif
endif
endif
ifeq ($(CONFIG_AUDIO_WM8904),y)
CSRCS += wm8904.c
ifeq ($(CONFIG_WM8904_REGDUMP),y)

2011
drivers/audio/wm8994.c Normal file

File diff suppressed because it is too large Load Diff

1635
drivers/audio/wm8994.h Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,543 @@
/*****************************************************************************************
* drivers/audio/wm8994_debug.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
*****************************************************************************************/
/*****************************************************************************************
* Included Files
*****************************************************************************************/
#include <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <fixedmath.h>
#include <syslog.h>
#include <nuttx/audio/audio.h>
#include <nuttx/audio/wm8904.h>
#include "wm8994.h"
/*****************************************************************************************
* Pre-processor Definitions
*****************************************************************************************/
/*****************************************************************************************
* Private Types
*****************************************************************************************/
#ifdef CONFIG_WM8994_REGDUMP
struct wb8994_regdump_s
{
FAR const char *regname;
uint16_t regaddr;
};
#endif
/*****************************************************************************************
* Private Function Prototypes
*****************************************************************************************/
/*****************************************************************************************
* Private Data
*****************************************************************************************/
#ifdef CONFIG_WM8994_REGDUMP
static const struct wb8994_regdump_s g_wm8994_debug[] =
{
{"ID", WM8994_ID},
{"PM1", WM8994_PM1},
{"PM2", WM8994_PM2},
{"PM3", WM8994_PM3},
{"PM4", WM8994_PM4},
{"PM5", WM8994_PM5},
{"PM6", WM8994_PM6},
{"INPUT_MIXER1", WM8994_INPUT_MIXER1},
{"LEFTLINE_12_VOL", WM8994_LEFTLINE_12_VOL},
{"LEFTLINE_34_VOL", WM8994_LEFTLINE_34_VOL},
{"RIGHTLINE_12_VOL", WM8994_RIGHTLINE_12_VOL},
{"RIGHTLINE_34_VOL", WM8994_RIGHTLINE_34_VOL},
{"LEFT_OUTPUT_VOL", WM8994_LEFT_OUTPUT_VOL},
{"RIGHT_OUTPUT_VOL", WM8994_RIGHT_OUTPUT_VOL},
{"LINE_OUTPUTS_VOL", WM8994_LINE_OUTPUTS_VOL},
{"HPOUT2_VOL", WM8994_HPOUT2_VOL},
{"LEFT_OPGA_VOL", WM8994_LEFT_OPGA_VOL},
{"RIGHT_OPGA_VOL", WM8994_RIGHT_OPGA_VOL},
{"SPKMIXL_ATT", WM8994_SPKMIXL_ATT},
{"SPKMIXR_ATT", WM8994_SPKMIXR_ATT},
{"SPKOUT_MIXERS", WM8994_SPKOUT_MIXERS},
{"CLASS_D", WM8994_CLASS_D},
{"SPEAKER_VOL_LEFT", WM8994_SPEAKER_VOL_LEFT},
{"SPEAKER_VOL_RIGHT", WM8994_SPEAKER_VOL_RIGHT},
{"INPUT_MIXER2", WM8994_INPUT_MIXER2},
{"INPUT_MIXER3", WM8994_INPUT_MIXER3},
{"INPUT_MIXER4", WM8994_INPUT_MIXER4},
{"INPUT_MIXER5", WM8994_INPUT_MIXER5},
{"INPUT_MIXER6", WM8994_INPUT_MIXER6},
{"OUTPUT_MIXER1", WM8994_OUTPUT_MIXER1},
{"OUTPUT_MIXER2", WM8994_OUTPUT_MIXER2},
{"OUTPUT_MIXER3", WM8994_OUTPUT_MIXER3},
{"OUTPUT_MIXER4", WM8994_OUTPUT_MIXER4},
{"OUTPUT_MIXER5", WM8994_OUTPUT_MIXER5},
{"OUTPUT_MIXER6", WM8994_OUTPUT_MIXER6},
{"HPOUT2_MIXER", WM8994_HPOUT2_MIXER},
{"LINE_MIXER1", WM8994_LINE_MIXER1},
{"LINE_MIXER2", WM8994_LINE_MIXER2},
{"SPEAKER_MIXER", WM8994_SPEAKER_MIXER},
{"ADDITIONAL_CTL", WM8994_ADDITIONAL_CTL},
{"ANTI_POP1", WM8994_ANTI_POP1},
{"ANTI_POP2", WM8994_ANTI_POP2},
{"MIC_BIAS", WM8994_MIC_BIAS},
{"LDO_1", WM8994_LDO_1},
{"LDO_2", WM8994_LDO_2},
{"CHARGE_PUMP1", WM8994_CHARGE_PUMP1},
{"CHARGE_PUMP2", WM8994_CHARGE_PUMP2},
{"CLASS_W_1", WM8994_CLASS_W_1},
{"DC_SERVO1", WM8994_DC_SERVO1},
{"DC_SERVO2", WM8994_DC_SERVO2},
{"DC_SERVO_BB", WM8994_DC_SERVO_RB},
{"DC_SERVO4", WM8994_DC_SERVO4},
{"ANA_HP1", WM8994_ANA_HP1},
{"CHIP_REV", WM8994_CHIP_REV},
{"CTL_IF", WM8994_CTL_IF},
{"WR_CTL_SEQ1", WM8994_WR_CTL_SEQ1},
{"WR_CTL_SEQ2", WM8994_WR_CTL_SEQ2},
{"AIF1_CLK1", WM8994_AIF1_CLK1},
{"AIF1_CLK2", WM8994_AIF1_CLK2},
{"AIF2_CLK1", WM8994_AIF2_CLK1},
{"AIF2_CLK2", WM8994_AIF2_CLK2},
{"CLK1", WM8994_CLK1},
{"CLK2", WM8994_CLK2},
{"AIF1_RATE", WM8994_AIF1_RATE},
{"AIF2_RATE", WM8994_AIF2_RATE},
{"RATE_STATUS", WM8994_RATE_STATUS},
{"PLL1_CTL1", WM8994_PLL1_CTL1},
{"PLL1_CTL2", WM8994_PLL1_CTL2},
{"PLL1_CTL3", WM8994_PLL1_CTL3},
{"PLL1_CTL4", WM8994_PLL1_CTL4},
{"PLL1_CTL5", WM8994_PLL1_CTL5},
{"PLL2_CTL1", WM8994_PLL2_CTL1},
{"PLL2_CTL2", WM8994_PLL2_CTL2},
{"PLL2_CTL3", WM8994_PLL2_CTL3},
{"PLL2_CTL4", WM8994_PLL2_CTL4},
{"PLL2_CTL5", WM8994_PLL2_CTL5},
{"AIF1_CTL1", WM8994_AIF1_CTL1},
{"AIF1_CTL2", WM8994_AIF1_CTL2},
{"AIF1_MASTER_SLAVE", WM8994_AIF1_MASTER_SLAVE},
{"AIF1_BCLK", WM8994_AIF1_BCLK},
{"AIF1_ADC_LRCLK", WM8994_AIF1_ADC_LRCLK},
{"AIF1_DAC_LRCLK", WM8994_AIF1_DAC_LRCLK},
{"AIF1_DAC_DATA", WM8994_AIF1_DAC_DATA},
{"AIF1_ADC_DATA", WM8994_AIF1_ADC_DATA},
{"AIF2_CTL1", WM8994_AIF2_CTL1},
{"AIF2_CTL2", WM8994_AIF2_CTL2},
{"AIF2_MASTER_SLAVE", WM8994_AIF2_MASTER_SLAVE},
{"AIF2_BCLKK", WM8994_AIF2_BCLK},
{"AIF2_ADC_LRCLK", WM8994_AIF2_ADC_LRCLK},
{"AIF2_DAC_LRCLK", WM8994_AIF2_DAC_LRCLK},
{"AIF2_DAC_DATA", WM8994_AIF2_DAC_DATA},
{"AIF2_ADC_DATA", WM8994_AIF2_ADC_DATA},
{"AIF1_ADC1_LEFT_VOL", WM8994_AIF1_ADC1_LEFT_VOL},
{"AIF1_ADC1_RIGHT_VOL", WM8994_AIF1_ADC1_RIGHT_VOL},
{"AIF1_DAC1_LEFT_VOL", WM8994_AIF1_DAC1_LEFT_VOL},
{"AIF1_DAC1_RIGHT_VOL", WM8994_AIF1_DAC1_RIGHT_VOL},
{"AIF1_ADC2_LEFT_VOL", WM8994_AIF1_ADC2_LEFT_VOL},
{"AIF1_ADC2_RIGHT_VOL", WM8994_AIF1_ADC2_RIGHT_VOL},
{"AIF1_DAC2_LEFT_VOL", WM8994_AIF1_DAC2_LEFT_VOL},
{"AIF1_DAC2_RIGHT_VOL", WM8994_AIF1_DAC2_RIGHT_VOL},
{"AIF1_ADC1_FILTERS", WM8994_AIF1_ADC1_FILTERS},
{"AIF1_ADC2_FILTERS", WM8994_AIF1_ADC2_FILTERS},
{"AIF1_DAC1_FILTERS1", WM8994_AIF1_DAC1_FILTERS1},
{"AIF1_DAC1_FILTERS2", WM8994_AIF1_DAC1_FILTERS2},
{"AIF1_DAC2_FILTERS1", WM8994_AIF1_DAC2_FILTERS1},
{"AIF1_DAC2_FILTERS2", WM8994_AIF1_DAC2_FILTERS2},
{"AIF1_DRC1_1", WM8994_AIF1_DRC1_1},
{"AIF1_DRC1_2", WM8994_AIF1_DRC1_2},
{"AIF1_DRC1_3", WM8994_AIF1_DRC1_3},
{"AIF1_DRC1_4", WM8994_AIF1_DRC1_4},
{"AIF1_DRC1_5", WM8994_AIF1_DRC1_5},
{"AIF1_DRC2_1", WM8994_AIF1_DRC2_1},
{"AIF1_DRC2_2", WM8994_AIF1_DRC2_2},
{"AIF1_DRC2_3", WM8994_AIF1_DRC2_3},
{"AIF1_DRC2_4", WM8994_AIF1_DRC2_4},
{"AIF1_DRC2_5", WM8994_AIF1_DRC2_5},
{"AIF1_DAC1_EQ_GAINS_1", WM8994_AIF1_DAC1_EQ_GAINS_1},
{"AIF1_DAC1_EQ_GAINS_2", WM8994_AIF1_DAC1_EQ_GAINS_2},
{"AIF1_DAC1_EQ_BAND_1A", WM8994_AIF1_DAC1_EQ_BAND_1A},
{"AIF1_DAC1_EQ_BAND_1B", WM8994_AIF1_DAC1_EQ_BAND_1B},
{"AIF1_DAC1_EQ_BAND_1PG", WM8994_AIF1_DAC1_EQ_BAND_1PG},
{"AIF1_DAC1_EQ_BAND_2A", WM8994_AIF1_DAC1_EQ_BAND_2A},
{"AIF1_DAC1_EQ_BAND_2B", WM8994_AIF1_DAC1_EQ_BAND_2B},
{"AIF1_DAC1_EQ_BAND_2C", WM8994_AIF1_DAC1_EQ_BAND_2C},
{"AIF1_DAC1_EQ_BAND_2PG", WM8994_AIF1_DAC1_EQ_BAND_2PG},
{"AIF1_DAC1_EQ_BAND_3A", WM8994_AIF1_DAC1_EQ_BAND_3A},
{"AIF1_DAC1_EQ_BAND_3B", WM8994_AIF1_DAC1_EQ_BAND_3B},
{"AIF1_DAC1_EQ_BAND_3C", WM8994_AIF1_DAC1_EQ_BAND_3C},
{"AIF1_DAC1_EQ_BAND_3PG", WM8994_AIF1_DAC1_EQ_BAND_3PG},
{"AIF1_DAC1_EQ_BAND_4A", WM8994_AIF1_DAC1_EQ_BAND_4A},
{"AIF1_DAC1_EQ_BAND_4B", WM8994_AIF1_DAC1_EQ_BAND_4B},
{"AIF1_DAC1_EQ_BAND_4C", WM8994_AIF1_DAC1_EQ_BAND_4C},
{"AIF1_DAC1_EQ_BAND_4PG", WM8994_AIF1_DAC1_EQ_BAND_4PG},
{"AIF1_DAC1_EQ_BAND_5A", WM8994_AIF1_DAC1_EQ_BAND_5A},
{"AIF1_DAC1_EQ_BAND_5B", WM8994_AIF1_DAC1_EQ_BAND_5B},
{"AIF1_DAC1_EQ_BAND_5PG", WM8994_AIF1_DAC1_EQ_BAND_5PG},
{"AIF1_DAC2_EQ_GAINS_1", WM8994_AIF1_DAC2_EQ_GAINS_1},
{"AIF1_DAC2_EQ_GAINS_2", WM8994_AIF1_DAC2_EQ_GAINS_2},
{"AIF1_DAC2_EQ_BAND_1A", WM8994_AIF1_DAC2_EQ_BAND_1A},
{"AIF1_DAC2_EQ_BAND_1B", WM8994_AIF1_DAC2_EQ_BAND_1B},
{"AIF1_DAC2_EQ_BAND_1PG", WM8994_AIF1_DAC2_EQ_BAND_1PG},
{"AIF1_DAC2_EQ_BAND_2A", WM8994_AIF1_DAC2_EQ_BAND_2A},
{"AIF1_DAC2_EQ_BAND_2B", WM8994_AIF1_DAC2_EQ_BAND_2B},
{"AIF1_DAC2_EQ_BAND_2C", WM8994_AIF1_DAC2_EQ_BAND_2C},
{"AIF1_DAC2_EQ_BAND_2PG", WM8994_AIF1_DAC2_EQ_BAND_2PG},
{"AIF1_DAC2_EQ_BAND_3A", WM8994_AIF1_DAC2_EQ_BAND_3A},
{"AIF1_DAC2_EQ_BAND_3B", WM8994_AIF1_DAC2_EQ_BAND_3B},
{"AIF1_DAC2_EQ_BAND_3C", WM8994_AIF1_DAC2_EQ_BAND_3C},
{"AIF1_DAC2_EQ_BAND_3PG", WM8994_AIF1_DAC2_EQ_BAND_3PG},
{"AIF1_DAC2_EQ_BAND_4A", WM8994_AIF1_DAC2_EQ_BAND_4A},
{"AIF1_DAC2_EQ_BAND_4B", WM8994_AIF1_DAC2_EQ_BAND_4B},
{"AIF1_DAC2_EQ_BAND_4C", WM8994_AIF1_DAC2_EQ_BAND_4C},
{"AIF1_DAC2_EQ_BAND_4PG", WM8994_AIF1_DAC2_EQ_BAND_4PG},
{"AIF1_DAC2_EQ_BAND_5A", WM8994_AIF1_DAC2_EQ_BAND_5A},
{"AIF1_DAC2_EQ_BAND_5B", WM8994_AIF1_DAC2_EQ_BAND_5B},
{"AIF1_DAC2_EQ_BAND_5PG", WM8994_AIF1_DAC2_EQ_BAND_5PG},
{"AIF2_ADC1_LEFT_VOL", WM8994_AIF2_ADC1_LEFT_VOL},
{"AIF2_ADC1_RIGHT_VOL", WM8994_AIF2_ADC1_RIGHT_VOL},
{"AIF2_DAC1_LEFT_VOL", WM8994_AIF2_DAC1_LEFT_VOL},
{"AIF2_DAC1_RIGHT_VOL", WM8994_AIF2_DAC1_RIGHT_VOL},
{"AIF2_ADC_FILTERS", WM8994_AIF2_ADC_FILTERS},
{"AIF2_DAC_FILTERS1", WM8994_AIF2_DAC_FILTERS1},
{"AIF2_DAC_FILTERS2", WM8994_AIF2_DAC_FILTERS2},
{"AIF2_DRC_1", WM8994_AIF2_DRC_1},
{"AIF2_DRC_2", WM8994_AIF2_DRC_2},
{"AIF2_DRC_3", WM8994_AIF2_DRC_3},
{"AIF2_DRC_4", WM8994_AIF2_DRC_4},
{"AIF2_DRC_5", WM8994_AIF2_DRC_5},
{"AIF2_EQ_GAINS_1", WM8994_AIF2_EQ_GAINS_1},
{"AIF2_EQ_GAINS_2", WM8994_AIF2_EQ_GAINS_2},
{"AIF2_EQ_BAND_1A", WM8994_AIF2_EQ_BAND_1A},
{"AIF2_EQ_BAND_1B", WM8994_AIF2_EQ_BAND_1B},
{"AIF2_EQ_BAND_1PG", WM8994_AIF2_EQ_BAND_1PG},
{"AIF2_EQ_BAND_2A", WM8994_AIF2_EQ_BAND_2A},
{"AIF2_EQ_BAND_2B", WM8994_AIF2_EQ_BAND_2B},
{"AIF2_EQ_BAND_2C", WM8994_AIF2_EQ_BAND_2C},
{"AIF2_EQ_BAND_2PG", WM8994_AIF2_EQ_BAND_2PG},
{"AIF2_EQ_BAND_3A", WM8994_AIF2_EQ_BAND_3A},
{"AIF2_EQ_BAND_3B", WM8994_AIF2_EQ_BAND_3B},
{"AIF2_EQ_BAND_3C", WM8994_AIF2_EQ_BAND_3C},
{"AIF2_EQ_BAND_3PG", WM8994_AIF2_EQ_BAND_3PG},
{"AIF2_EQ_BAND_4A", WM8994_AIF2_EQ_BAND_4A},
{"AIF2_EQ_BAND_4B", WM8994_AIF2_EQ_BAND_4B},
{"AIF2_EQ_BAND_4C", WM8994_AIF2_EQ_BAND_4C},
{"AIF2_EQ_BAND_4PG", WM8994_AIF2_EQ_BAND_4PG},
{"AIF2_EQ_BAND_5A", WM8994_AIF2_EQ_BAND_5A},
{"AIF2_EQ_BAND_5B", WM8994_AIF2_EQ_BAND_5B},
{"AIF2_EQ_BAND_5PG", WM8994_AIF2_EQ_BAND_5PG},
{"DAC1_MIXER_VOLS", WM8994_DAC1_MIXER_VOLS},
{"DAC1_LEFT_MIXER_ROUTING", WM8994_DAC1_LEFT_MIXER_ROUTING},
{"DAC1_RIGHT_MIXER_ROUTING", WM8994_DAC1_RIGHT_MIXER_ROUTING},
{"DAC2_MIXER_VOLS", WM8994_DAC2_MIXER_VOLS},
{"DAC2_LEFT_MIXER_ROUTING", WM8994_DAC2_LEFT_MIXER_ROUTING},
{"DAC2_RIGHT_MIXER_ROUTING", WM8994_DAC2_RIGHT_MIXER_ROUTING},
{"ADC1_LEFT_MIXER_ROUTING", WM8994_ADC1_LEFT_MIXER_ROUTING},
{"ADC1_RIGHT_MIXER_ROUTING", WM8994_ADC1_RIGHT_MIXER_ROUTING},
{"ADC2_LEFT_MIXER_ROUTING", WM8994_ADC2_LEFT_MIXER_ROUTING},
{"ADC2_RIGHT_MIXER_ROUTING", WM8994_ADC2_RIGHT_MIXER_ROUTING},
{"DAC1_LEFT_VOL", WM8994_DAC1_LEFT_VOL},
{"DAC1_RIGHT_VOL", WM8994_DAC1_RIGHT_VOL},
{"DAC2_LEFT_VOL", WM8994_DAC2_LEFT_VOL},
{"DAC2_RIGHT_VOL", WM8994_DAC2_RIGHT_VOL},
{"DAC_SOFT_MUTE", WM8994_DAC_SOFT_MUTE},
{"OVER_SAMPLING", WM8994_OVER_SAMPLING},
{"SIDE_TONE", WM8994_SIDE_TONE},
{"GPIO1", WM8994_GPIO1},
{"GPIO2", WM8994_GPIO2},
{"GPIO3", WM8994_GPIO3},
{"GPIO4", WM8994_GPIO4},
{"GPIO5", WM8994_GPIO5},
{"GPIO6", WM8994_GPIO6},
{"GPIO7", WM8994_GPIO7},
{"GPIO8", WM8994_GPIO8},
{"GPIO9", WM8994_GPIO9},
{"GPIO10", WM8994_GPIO10},
{"GPIO11", WM8994_GPIO11},
{"PULL_CTL1", WM8994_PULL_CTL1},
{"PULL_CTL2", WM8994_PULL_CTL2},
{"INT_STATUS1", WM8994_INT_STATUS1},
{"INT_STATUS2", WM8994_INT_STATUS2},
{"INT_RAW_STATUS2", WM8994_INT_RAW_STATUS2},
{"INT_STATUS1_MASK", WM8994_INT_STATUS1_MASK},
{"INT_STATUS2_MASK", WM8994_INT_STATUS2_MASK},
{"INT_CTL", WM8994_INT_CTL},
{"INT_DEBOUNCE", WM8994_INT_DEBOUNCE},
};
# define WM8994_NREGISTERS (sizeof(g_wm8994_debug)/sizeof(struct wb8994_regdump_s))
#endif /* CONFIG_WM8994_REGDUMP */
/*****************************************************************************************
* Private Functions
*****************************************************************************************/
/*****************************************************************************************
* Public Functions
*****************************************************************************************/
/*****************************************************************************************
* Name: wm8994_dump_registers
*
* Description:
* Dump the contents of all WM8994 registers to the syslog device
*
* Input Parameters:
* dev - The device instance returned by wm8994_initialize
*
* Returned Value:
* None.
*
*****************************************************************************************/
#ifdef CONFIG_WM8994_REGDUMP
void wm8994_dump_registers(FAR struct audio_lowerhalf_s *dev,
FAR const char *msg)
{
int i;
syslog(LOG_INFO, "WM8994 Registers: %s\n", msg);
for (i = 0; i < WM8994_NREGISTERS; i++)
{
syslog(LOG_INFO, "%24s[%04x]: %04x\n",
g_wm8994_debug[i].regname, g_wm8994_debug[i].regaddr,
wm8994_readreg((FAR struct wm8994_dev_s *)dev,
g_wm8994_debug[i].regaddr));
}
}
#endif /* CONFIG_WM8994_REGDUMP */
/*****************************************************************************************
* Name: wm8994_clock_analysis
*
* Description:
* Analyze the settings in the clock chain and dump to syslog.
*
* Input Parameters:
* dev - The device instance returned by wm8994_initialize
*
* Returned Value:
* None.
*
*****************************************************************************************/
#ifdef CONFIG_WM8994_CLKDEBUG
void wm8994_clock_analysis(FAR struct audio_lowerhalf_s *dev,
FAR const char *msg)
{
FAR struct wm8994_dev_s *priv = (FAR struct wm8994_dev_s *)dev;
uint32_t sysclk;
uint32_t bclk;
uint32_t lrclk;
uint16_t regval;
unsigned int tmp;
double ftmp;
syslog(LOG_INFO, "WM8994 Clock Analysis: %s\n", msg);
DEBUGASSERT(priv && priv->lower);
syslog(LOG_INFO, " MCLK: %lu Hz\n",
(unsigned long)priv->lower->mclk);
/* Is the SYSCLK source the FLL? Or MCK? */
regval = wm8994_readreg(priv, WM8994_CLKRATE2);
if ((regval & WM8994_SYSCLK_SRC) == WM8994_SYSCLK_SRCMCLK)
{
/* The SYSCLK divider bypasses the FLL and takes its input
* directly from MCLK.
*/
sysclk = priv->lower->mclk;
syslog(LOG_INFO, " SYSCLK Source: MCLK (%s)\n",
(regval & WM8994_MCLK_INV) != 0 ? "inverted" : "not inverted");
}
else
{
uint32_t fref;
uint32_t fvco;
uint32_t fout;
unsigned int outdiv;
unsigned int frndx;
unsigned int flln;
unsigned int fllk;
unsigned int fratio;
double nk;
/* Assume that the Fref input to the FLL is MCLK */
fref = priv->lower->mclk;
/* Now get the real FLL input source */
regval = wm8994_readreg(priv, WM8994_FLL_CTRL5);
switch (regval & WM8994_FLL_CLK_REF_SRC_MASK)
{
case WM8994_FLL_CLK_REF_SRC_MCLK:
syslog(LOG_INFO, " FLL Source: MCLK\n");
break;
case WM8994_FLL_CLK_REF_SRC_BCLK:
syslog(LOG_INFO, " ERROR: FLL source is BCLK: %04x\n",
regval);
break;
case WM8994_FLL_CLK_REF_SRC_LRCLK:
syslog(LOG_INFO, " ERROR: FLL source is LRCLK: %04x\n",
regval);
break;
default:
syslog(LOG_INFO, " ERROR: Unrecognized FLL source: %04x\n",
regval);
}
syslog(LOG_INFO, " Fref: %lu Hz (before divider)\n",
fref);
switch (regval & WM8994_FLL_CLK_REF_DIV_MASK)
{
case WM8994_FLL_CLK_REF_DIV1:
syslog(LOG_INFO, " FLL_CLK_REF_DIV: 1\n");
break;
case WM8994_FLL_CLK_REF_DIV2:
syslog(LOG_INFO, " FLL_CLK_REF_DIV: 2\n");
fref >>= 1;
break;
case WM8994_FLL_CLK_REF_DIV4:
syslog(LOG_INFO, " FLL_CLK_REF_DIV: 4\n");
fref >>= 2;
break;
case WM8994_FLL_CLK_REF_DIV8:
syslog(LOG_INFO, " FLL_CLK_REF_DIV: 8\n");
fref >>= 3;
break;
}
syslog(LOG_INFO, " Fref: %lu Hz (after divider)\n", fref);
regval = wm8994_readreg(priv, WM8994_FLL_CTRL2);
frndx = (regval & WM8994_FLL_FRATIO_MASK) >> WM8994_FLL_FRATIO_SHIFT;
tmp = (regval & WM8994_FLL_CTRL_RATE_MASK) >> WM8994_FLL_CTRL_RATE_SHIFT;
outdiv = ((regval & WM8994_FLL_OUTDIV_MASK) >> WM8994_FLL_OUTDIV_SHIFT) + 1;
syslog(LOG_INFO, " FLL_CTRL_RATE: Fvco / %u\n", tmp + 1);
regval = wm8904_readreg(priv, WM8994_FLL_CTRL4);
flln = (regval & WM8994_FLL_N_MASK) >> WM8994_FLL_N_SHIFT;
tmp = (regval & WM8994_FLL_GAIN_MASK) >> WM8994_FLL_GAIN_SHIFT;
syslog(LOG_INFO, " FLL_GAIN: %u\n", (1 << tmp));
fllk = wm8994_readreg(priv, WM8994_FLL_CTRL3);
nk = (double)flln + ((double)fllk / 65536.0);
fratio = g_fllratio[frndx];
syslog(LOG_INFO, " FLL_FRATIO: %u\n", fratio);
syslog(LOG_INFO, " FLL_OUTDIV: %u\n", outdiv);
syslog(LOG_INFO, " FLL_N.K: %u.%05u\n", flln, fllk);
ftmp = nk * (double)fref * (double)fratio;
fvco = (uint32_t)ftmp;
syslog(LOG_INFO, " Fvco: %lu Hz\n", (unsigned long)fvco);
fout = fvco / outdiv;
syslog(LOG_INFO, " Fout: %lu Hz\n", (unsigned long)fout);
regval = wm8994_readreg(priv, WM8994_FLL_CTRL1);
syslog(LOG_INFO, " FLL_FRACN_ENA: %s\n",
(regval & WM8994_FLL_FRACN_ENA) != 0 ? "Enabled" : "Disabled");
syslog(LOG_INFO, " FLL_OSC_ENA: %s\n",
(regval & WM8994_FLL_OSC_ENA) != 0 ? "Enabled" : "Disabled");
syslog(LOG_INFO, " FLL_ENA: %s\n",
(regval & WM8994_FLL_ENA) != 0 ? "Enabled" : "Disabled");
if ((regval & WM8994_FLL_ENA) == 0)
{
syslog(LOG_INFO, " No SYSCLK\n");
return;
}
sysclk = fout;
}
syslog(LOG_INFO, " SYSCLK: %lu Hz (before divider)\n",
(unsigned long)sysclk);
regval = wm8994_readreg(priv, WM8994_CLKRATE0);
if ((regval & WM8994_MCLK_DIV) == WM8994_MCLK_DIV1)
{
syslog(LOG_INFO, " MCLK_DIV: 1\n");
}
else
{
syslog(LOG_INFO, " MCLK_DIV: 2\n");
sysclk >>= 1;
}
syslog(LOG_INFO, " SYSCLK: %lu (after divider)\n", (unsigned long)sysclk);
regval = wm8994_readreg(priv, WM8994_CLKRATE2);
syslog(LOG_INFO, " CLK_SYS_ENA: %s\n",
(regval & WM8994_CLK_SYS_ENA) != 0 ? "Enabled" : "Disabled");
if ((regval & WM8994_CLK_SYS_ENA) == 0)
{
syslog(LOG_INFO, " No SYSCLK\n");
return;
}
regval = wm8994_readreg(priv, WM8994_AIF2);
tmp = (regval & WM8994_BCLK_DIV_MASK) >> WM8994_BCLK_DIV_SHIFT;
tmp = g_sysclk_scaleb1[tmp];
ftmp = (double)tmp / 2.0;
syslog(LOG_INFO, " BCLK_DIV: SYSCLK / %u.%01u\n",
(unsigned int)(tmp >> 1), (unsigned int)(5 * (tmp & 1)));
bclk = (uint32_t)(sysclk / ftmp);
syslog(LOG_INFO, " BCLK: %lu Hz\n", (unsigned long)bclk);
regval = wm8994_readreg(priv, WM8994_AIF1);
syslog(LOG_INFO, " BCLK_DIR: %s\n",
(regval & WM8994_BCLK_DIR) != 0 ? "Output" : "Input");
regval = wm8994_readreg(priv, WM8994_AIF3);
tmp = (regval & WM8994_LRCLK_RATE_MASK) >> WM8994_LRCLK_RATE_SHIFT;
lrclk = bclk / tmp;
syslog(LOG_INFO, " LRCLK_RATE: BCLK / %lu\n", (unsigned long)tmp);
syslog(LOG_INFO, " LRCLK: %lu Hz\n", (unsigned long)lrclk);
syslog(LOG_INFO, " LRCLK_DIR: %s\n",
(regval & WM8994_LRCLK_DIR) != 0 ? "Output" : "Input");
}
#endif /* CONFIG_WM8994_CLKDEBUG */

View File

@ -0,0 +1,260 @@
/****************************************************************************
* include/nuttx/audio/wm8994.h
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_AUDIO_WM8994_H
#define __INCLUDE_NUTTX_AUDIO_WM8994_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <stdint.h>
#include <stdbool.h>
#include <nuttx/irq.h>
#ifdef CONFIG_AUDIO_WM8994
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************
*
* CONFIG_AUDIO_WM8994 - Enables WM8994 support
* CONFIG_WM8994_INITVOLUME - The initial volume level in the range {0..1000}
* CONFIG_WM8994_INFLIGHT - Maximum number of buffers that the WM8994 driver
* will send to the I2S driver before any have completed.
* CONFIG_WM8994_MSG_PRIO - Priority of messages sent to the WM8994 worker
* thread.
* CONFIG_WM8994_BUFFER_SIZE - Preferred buffer size
* CONFIG_WM8994_NUM_BUFFERS - Preferred number of buffers
* CONFIG_WM8994_WORKER_STACKSIZE - Stack size to use when creating the
* WM8994 worker thread.
* CONFIG_WM8994_REGDUMP - Enable logic to dump all WM8994 registers to
* the SYSLOG device.
*/
/* Pre-requisites */
#ifndef CONFIG_AUDIO
# error CONFIG_AUDIO is required for audio subsystem support
#endif
#ifndef CONFIG_I2S
# error CONFIG_I2S is required by the WM8994 driver
#endif
#ifndef CONFIG_I2C
# error CONFIG_I2C is required by the WM8994 driver
#endif
#ifndef CONFIG_SCHED_WORKQUEUE
# error CONFIG_SCHED_WORKQUEUE is required by the WM8994 driver
#endif
/* Default configuration values */
#ifndef CONFIG_WM8994_INITVOLUME
# define CONFIG_WM8994_INITVOLUME 250
#endif
#ifndef CONFIG_WM8994_INFLIGHT
# define CONFIG_WM8994_INFLIGHT 2
#endif
#if CONFIG_WM8994_INFLIGHT > 255
# error CONFIG_WM8994_INFLIGHT must fit in a uint8_t
#endif
#ifndef CONFIG_WM8994_MSG_PRIO
# define CONFIG_WM8994_MSG_PRIO 1
#endif
#ifndef CONFIG_WM8994_BUFFER_SIZE
# define CONFIG_WM8994_BUFFER_SIZE 8192
#endif
#ifndef CONFIG_WM8994_NUM_BUFFERS
# define CONFIG_WM8994_NUM_BUFFERS 4
#endif
#ifndef CONFIG_WM8994_WORKER_STACKSIZE
# define CONFIG_WM8994_WORKER_STACKSIZE 768
#endif
/* Helper macros ************************************************************/
#define WM8994_ATTACH(s,isr,arg) ((s)->attach(s,isr,arg))
#define WM8994_DETACH(s) ((s)->attach(s,NULL,NULL))
#define WM8994_ENABLE(s) ((s)->enable(s,true))
#define WM8994_DISABLE(s) ((s)->enable(s,false))
#define WM8994_RESTORE(s,e) ((s)->enable(s,e))
/****************************************************************************
* Public Types
****************************************************************************/
/* This is the type of the WM8994 interrupt handler. The lower level code
* will intercept the interrupt and provide the upper level with the private
* data that was provided when the interrupt was attached.
*/
struct wm8994_lower_s; /* Forward reference. Defined below */
typedef CODE int (*wm8994_handler_t)(FAR const struct wm8994_lower_s *lower,
FAR void *arg);
/* A reference to a structure of this type must be passed to the WM8994
* driver. This structure provides information about the configuration
* of the WM8994 and provides some board-specific hooks.
*
* Memory for this structure is provided by the caller. It is not copied
* by the driver and is presumed to persist while the driver is active.
*/
struct wm8994_lower_s
{
/* I2C characterization */
uint32_t frequency; /* Initial I2C frequency */
uint8_t address; /* 7-bit I2C address (only bits 0-6 used) */
/* Clocking is provided via MCLK. The WM8994 driver will need to know
* the frequency of MCLK in order to generate the correct bitrates.
*/
uint32_t mclk; /* W8994 Master clock frequency */
/* IRQ/GPIO access callbacks. These operations all hidden behind
* callbacks to isolate the WM8994 driver from differences in GPIO
* interrupt handling by varying boards and MCUs. If possible,
* interrupts should be configured on both rising and falling edges
* so that contact and loss-of-contact events can be detected.
*
* attach - Attach or detach the WM8994 interrupt handler to the GPIO
* interrupt
* enable - Enable or disable the GPIO interrupt. Returns the
* previous interrupt state.
*/
CODE int (*attach)(FAR const struct wm8994_lower_s *lower,
wm8994_handler_t isr, FAR void *arg);
CODE bool (*enable)(FAR const struct wm8994_lower_s *lower, bool enable);
};
/****************************************************************************
* Public Data
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/****************************************************************************
* Name: wm8994_initialize
*
* Description:
* Initialize the WM8994 device.
*
* Input Parameters:
* i2c - An I2C driver instance
* i2s - An I2S driver instance
* lower - Persistent board configuration data
*
* Returned Value:
* A new lower half audio interface for the WM8994 device is returned on
* success; NULL is returned on failure.
*
****************************************************************************/
struct i2c_master_s; /* Forward reference. Defined in include/nuttx/i2c/i2c_master.h */
struct i2s_dev_s; /* Forward reference. Defined in include/nuttx/audio/i2s.h */
struct audio_lowerhalf_s; /* Forward reference. Defined in nuttx/audio/audio.h */
FAR struct audio_lowerhalf_s *
wm8994_initialize(FAR struct i2c_master_s *i2c, FAR struct i2s_dev_s *i2s,
FAR const struct wm8994_lower_s *lower);
/****************************************************************************
* Name: wm8994_dump_registers
*
* Description:
* Dump the contents of all WM8994 registers to the syslog device
*
* Input Parameters:
* dev - The device instance returned by wm8994_initialize
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_WM8994_REGDUMP
void wm8994_dump_registers(FAR struct audio_lowerhalf_s *dev,
FAR const char *msg);
#else
/* This eliminates the need for any conditional compilation in the
* including file.
*/
# define wm8994_dump_registers(d,m)
#endif
/****************************************************************************
* Name: wm8994_clock_analysis
*
* Description:
* Analyze the settings in the clock chain and dump to syslog.
*
* Input Parameters:
* dev - The device instance returned by wm8994_initialize
*
* Returned Value:
* None.
*
****************************************************************************/
#ifdef CONFIG_WM8994_CLKDEBUG
void wm8994_clock_analysis(FAR struct audio_lowerhalf_s *dev,
FAR const char *msg);
#else
/* This eliminates the need for any conditional compilation in the
* including file.
*/
# define wm8994_clock_analysis(d,m)
#endif
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_AUDIO_WM8994 */
#endif /* __INCLUDE_NUTTX_AUDIO_WM8994_H */