mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-18 13:11:31 +00:00
Complete conversion of sound to driver model
-----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEslwAIq+Gp8wWVbYnfxc6PpAIreYFAlwTzzsACgkQfxc6PpAI reYztgf+I1jVm7q/pPAMqtUWArQaXabcHIbqR/if+ZTssK/RRJQXd0ZmZa/WbVLS FdORnuPNrUY+M4NEHQPAce2bclLxb6P0TFbfE5FRoCRxkaZdjSCglibpWe4qWu1m rmifPRGoSKqzMhuC+Xb2qRSyT40J0gjCMuKd053TIcblMvus0foavxq8JMk5iiMD vmUlaCdacYH2BSltFTExkAH/6AVspSIhkXl5TSGk8zEpOkRDeEiuOf+DGmBEE+aa Qpw8DqUhC0EOqyxGWfpT1IiqYWF+JqJDrrfKEViTZ0U/fSBP3suMewarBXAZrEuw UFXNa0luFHMoeVarhk4bbbDTPnNEeQ== =Y3Tt -----END PGP SIGNATURE----- Merge tag 'dm-pull-14dec18' of git://git.denx.de/u-boot-dm Complete conversion of sound to driver model
This commit is contained in:
commit
8fc26fce41
65 changed files with 2914 additions and 926 deletions
2
Kconfig
2
Kconfig
|
@ -126,6 +126,7 @@ config SYS_BOOT_GET_KBD
|
|||
config SYS_MALLOC_F
|
||||
bool "Enable malloc() pool before relocation"
|
||||
default y if DM
|
||||
|
||||
help
|
||||
Before relocation, memory is very limited on many platforms. Still,
|
||||
we can provide a small malloc() pool if needed. Driver model in
|
||||
|
@ -136,6 +137,7 @@ config SYS_MALLOC_F_LEN
|
|||
hex "Size of malloc() pool before relocation"
|
||||
depends on SYS_MALLOC_F
|
||||
default 0x1000 if AM33XX
|
||||
default 0x2800 if SANDBOX
|
||||
default 0x400
|
||||
help
|
||||
Before relocation, memory is very limited on many platforms. Still,
|
||||
|
|
|
@ -116,6 +116,7 @@ config SANDBOX
|
|||
imply VIRTIO_SANDBOX
|
||||
imply VIRTIO_BLK
|
||||
imply VIRTIO_NET
|
||||
imply DM_SOUND
|
||||
|
||||
config SH
|
||||
bool "SuperH architecture"
|
||||
|
|
|
@ -60,9 +60,26 @@
|
|||
};
|
||||
|
||||
i2c@12C70000 {
|
||||
soundcodec@1a {
|
||||
wm8994: soundcodec@1a {
|
||||
reg = <0x1a>;
|
||||
compatible = "wolfson,wm8994-codec";
|
||||
u-boot,i2c-offset-len = <2>;
|
||||
compatible = "wolfson,wm8994";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "google,smdk5250-audio-wm8994";
|
||||
|
||||
samsung,model = "SMDK5250-I2S-WM8994";
|
||||
samsung,audio-codec = <&wm8994>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&wm8994 0>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@
|
|||
mmc3 = "/mmc@12230000";
|
||||
serial0 = "/serial@12C30000";
|
||||
console = "/serial@12C30000";
|
||||
i2s = "/sound@3830000";
|
||||
};
|
||||
|
||||
memory {
|
||||
|
@ -88,7 +87,7 @@
|
|||
|
||||
ro-boot {
|
||||
label = "u-boot";
|
||||
reg = <0x6000 0x9a000>;
|
||||
reg = <0x6000 0xb0000>;
|
||||
read-only;
|
||||
type = "blob boot,dtb";
|
||||
required;
|
||||
|
@ -214,9 +213,10 @@
|
|||
};
|
||||
};
|
||||
|
||||
soundcodec@22 {
|
||||
reg = <0x22>;
|
||||
compatible = "maxim,max98095-codec";
|
||||
max98095: codec@11 {
|
||||
compatible = "maxim,max98095";
|
||||
reg = <0x11>;
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -273,9 +273,20 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound@3830000 {
|
||||
samsung,codec-type = "max98095";
|
||||
sound {
|
||||
compatible = "google,snow-audio-max98095";
|
||||
|
||||
samsung,model = "Snow-I2S-MAX98095";
|
||||
samsung,audio-codec = <&max98095>;
|
||||
codec-enable-gpio = <&gpx1 7 GPIO_ACTIVE_HIGH>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&max98095 0>;
|
||||
};
|
||||
};
|
||||
|
||||
sound@12d60000 {
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
mmc0 = "/mmc@12200000";
|
||||
serial0 = "/serial@12C30000";
|
||||
console = "/serial@12C30000";
|
||||
i2s = "/sound@3830000";
|
||||
};
|
||||
|
||||
memory {
|
||||
|
@ -639,10 +638,27 @@
|
|||
};
|
||||
};
|
||||
|
||||
soundcodec@20 {
|
||||
reg = <0x20>;
|
||||
compatible = "maxim,max98088-codec";
|
||||
max98095: soundcodec@10 {
|
||||
reg = <0x10>;
|
||||
compatible = "maxim,max98095";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "google,spring-audio-max98095";
|
||||
|
||||
samsung,model = "Spring-I2S-MAX98095";
|
||||
samsung,audio-codec = <&max98095>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&max98095 0>;
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
#include "cros-ec-keyboard.dtsi"
|
||||
|
|
|
@ -78,9 +78,12 @@
|
|||
#size-cells = <0>;
|
||||
};
|
||||
|
||||
sound@3830000 {
|
||||
compatible = "samsung,exynos-sound";
|
||||
reg = <0x3830000 0x50>;
|
||||
i2s0: i2s@3830000 {
|
||||
compatible = "samsung,s5pv210-i2s";
|
||||
reg = <0x03830000 0x100>;
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
#clock-cells = <1>;
|
||||
#sound-dai-cells = <1>;
|
||||
samsung,i2s-epll-clock-frequency = <192000000>;
|
||||
samsung,i2s-sampling-rate = <48000>;
|
||||
samsung,i2s-bits-per-sample = <16>;
|
||||
|
@ -90,9 +93,11 @@
|
|||
samsung,i2s-id = <0>;
|
||||
};
|
||||
|
||||
sound@12d60000 {
|
||||
compatible = "samsung,exynos-sound";
|
||||
i2s1: i2s@12d60000 {
|
||||
compatible = "samsung,s5pv210-i2s";
|
||||
reg = <0x12d60000 0x20>;
|
||||
#clock-cells = <1>;
|
||||
#sound-dai-cells = <1>;
|
||||
samsung,i2s-epll-clock-frequency = <192000000>;
|
||||
samsung,i2s-sampling-rate = <48000>;
|
||||
samsung,i2s-bits-per-sample = <16>;
|
||||
|
|
|
@ -67,12 +67,28 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "google,peach-audio-max98090";
|
||||
|
||||
samsung,model = "PEACH-I2S-MAX98090";
|
||||
samsung,audio-codec = <&max98090>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&max98090 0>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@12CD0000 { /* i2c7 */
|
||||
clock-frequency = <100000>;
|
||||
soundcodec@20 {
|
||||
reg = <0x20>;
|
||||
compatible = "maxim,max98090-codec";
|
||||
};
|
||||
max98090: soundcodec@10 {
|
||||
reg = <0x10>;
|
||||
compatible = "maxim,max98090";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
edp-lvds-bridge@48 {
|
||||
compatible = "parade,ps8625";
|
||||
|
|
|
@ -82,9 +82,26 @@
|
|||
};
|
||||
|
||||
i2c@12C70000 {
|
||||
soundcodec@1a {
|
||||
wm8994: soundcodec@1a {
|
||||
reg = <0x1a>;
|
||||
compatible = "wolfson,wm8994-codec";
|
||||
u-boot,i2c-offset-len = <2>;
|
||||
compatible = "wolfson,wm8994";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "samsung,smdk5420-audio-wm8994";
|
||||
|
||||
samsung,model = "Snow-I2S-MAX98095";
|
||||
samsung,audio-codec = <&wm8994>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&wm8994 0>;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -104,6 +104,20 @@
|
|||
interrupts = <0 203 0>;
|
||||
};
|
||||
|
||||
i2s0: i2s@3830000 {
|
||||
compatible = "samsung,s5pv210-i2s";
|
||||
reg = <0x03830000 0x100>;
|
||||
#sound-dai-cells = <1>;
|
||||
samsung,idma-addr = <0x03000000>;
|
||||
samsung,i2s-epll-clock-frequency = <192000000>;
|
||||
samsung,i2s-sampling-rate = <48000>;
|
||||
samsung,i2s-bits-per-sample = <16>;
|
||||
samsung,i2s-channels = <2>;
|
||||
samsung,i2s-lr-clk-framesize = <256>;
|
||||
samsung,i2s-bit-clk-framesize = <32>;
|
||||
samsung,i2s-id = <0>;
|
||||
};
|
||||
|
||||
mmc@12200000 {
|
||||
samsung,bus-width = <8>;
|
||||
samsung,timing = <1 3 3>;
|
||||
|
|
|
@ -79,12 +79,28 @@
|
|||
};
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "google,peach-audio-max98090";
|
||||
|
||||
samsung,model = "PEACH-I2S-MAX98090";
|
||||
samsung,audio-codec = <&max98090>;
|
||||
|
||||
cpu {
|
||||
sound-dai = <&i2s0 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&max98090 0>;
|
||||
};
|
||||
};
|
||||
|
||||
i2c@12CD0000 { /* i2c7 */
|
||||
clock-frequency = <100000>;
|
||||
soundcodec@20 {
|
||||
reg = <0x20>;
|
||||
compatible = "maxim,max98090-codec";
|
||||
};
|
||||
max98090: soundcodec@10 {
|
||||
reg = <0x10>;
|
||||
compatible = "maxim,max98090";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
};
|
||||
|
||||
sound@3830000 {
|
||||
|
|
|
@ -345,7 +345,7 @@ static struct clk_bit_info *get_clk_bit_info(int peripheral)
|
|||
int i;
|
||||
struct clk_bit_info *info;
|
||||
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
info = exynos542x_bit_info;
|
||||
else
|
||||
info = exynos5_bit_info;
|
||||
|
@ -557,7 +557,7 @@ static unsigned long exynos542x_get_periph_rate(int peripheral)
|
|||
unsigned long clock_get_periph_rate(int peripheral)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return exynos542x_get_periph_rate(peripheral);
|
||||
return exynos5_get_periph_rate(peripheral);
|
||||
} else {
|
||||
|
@ -1317,6 +1317,19 @@ int exynos5_set_epll_clk(unsigned long rate)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int exynos5420_set_i2s_clk_source(void)
|
||||
{
|
||||
struct exynos5420_clock *clk =
|
||||
(struct exynos5420_clock *)samsung_get_base_clock();
|
||||
|
||||
setbits_le32(&clk->src_top6, EXYNOS5420_CLK_SRC_MOUT_EPLL);
|
||||
clrsetbits_le32(&clk->src_mau, EXYNOS5420_AUDIO0_SEL_MASK,
|
||||
(EXYNOS5420_CLK_SRC_SCLK_EPLL));
|
||||
setbits_le32(EXYNOS5_AUDIOSS_BASE, 1 << 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exynos5_set_i2s_clk_source(unsigned int i2s_id)
|
||||
{
|
||||
struct exynos5_clock *clk =
|
||||
|
@ -1575,7 +1588,7 @@ static unsigned long exynos4_get_i2c_clk(void)
|
|||
unsigned long get_pll_clk(int pllreg)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return exynos542x_get_pll_clk(pllreg);
|
||||
return exynos5_get_pll_clk(pllreg);
|
||||
} else if (cpu_is_exynos4()) {
|
||||
|
@ -1691,7 +1704,7 @@ void set_mmc_clk(int dev_index, unsigned int div)
|
|||
div -= 1;
|
||||
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
exynos5420_set_mmc_clk(dev_index, div);
|
||||
else
|
||||
exynos5_set_mmc_clk(dev_index, div);
|
||||
|
@ -1739,7 +1752,7 @@ void set_mipi_clk(void)
|
|||
int set_spi_clk(int periph_id, unsigned int rate)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return exynos5420_set_spi_clk(periph_id, rate);
|
||||
return exynos5_set_spi_clk(periph_id, rate);
|
||||
}
|
||||
|
@ -1758,8 +1771,12 @@ int set_i2s_clk_prescaler(unsigned int src_frq, unsigned int dst_frq,
|
|||
|
||||
int set_i2s_clk_source(unsigned int i2s_id)
|
||||
{
|
||||
if (cpu_is_exynos5())
|
||||
return exynos5_set_i2s_clk_source(i2s_id);
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos542x())
|
||||
return exynos5420_set_i2s_clk_source();
|
||||
else
|
||||
return exynos5_set_i2s_clk_source(i2s_id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -968,7 +968,7 @@ static void exynos5420_system_clock_init(void)
|
|||
|
||||
void system_clock_init(void)
|
||||
{
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
exynos5420_system_clock_init();
|
||||
else
|
||||
exynos5250_system_clock_init();
|
||||
|
|
|
@ -78,7 +78,7 @@ static inline void configure_l2_ctlr(void)
|
|||
CACHE_TAG_RAM_LATENCY_2_CYCLES |
|
||||
CACHE_DATA_RAM_LATENCY_2_CYCLES;
|
||||
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422()) {
|
||||
if (proid_is_exynos542x()) {
|
||||
val |= CACHE_ECC_AND_PARITY |
|
||||
CACHE_TAG_RAM_LATENCY_3_CYCLES |
|
||||
CACHE_DATA_RAM_LATENCY_3_CYCLES;
|
||||
|
@ -97,7 +97,7 @@ static inline void configure_l2_actlr(void)
|
|||
{
|
||||
uint32_t val;
|
||||
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422()) {
|
||||
if (proid_is_exynos542x()) {
|
||||
mrc_l2_aux_ctlr(val);
|
||||
val |= CACHE_ENABLE_FORCE_L2_LOGIC |
|
||||
CACHE_DISABLE_CLEAN_EVICT;
|
||||
|
|
|
@ -1370,10 +1370,13 @@ struct set_epll_con_val {
|
|||
#define AUDIO_1_RATIO_MASK 0x0f
|
||||
|
||||
#define AUDIO0_SEL_MASK 0xf
|
||||
#define EXYNOS5420_AUDIO0_SEL_MASK (0x3 << 28)
|
||||
#define AUDIO1_SEL_MASK 0xf
|
||||
|
||||
#define CLK_SRC_SCLK_EPLL 0x7
|
||||
#define EXYNOS5420_CLK_SRC_SCLK_EPLL (0x6 << 28)
|
||||
#define CLK_SRC_MOUT_EPLL (1<<12)
|
||||
#define EXYNOS5420_CLK_SRC_MOUT_EPLL BIT(20)
|
||||
#define AUDIO_CLKMUX_ASS (1<<0)
|
||||
|
||||
/* CON0 bit-fields */
|
||||
|
|
|
@ -268,6 +268,8 @@ IS_EXYNOS_TYPE(exynos5250, 0x5250)
|
|||
IS_EXYNOS_TYPE(exynos5420, 0x5420)
|
||||
IS_EXYNOS_TYPE(exynos5422, 0x5422)
|
||||
|
||||
#define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
|
||||
#define SAMSUNG_BASE(device, base) \
|
||||
static inline unsigned long __attribute__((no_instrument_function)) \
|
||||
samsung_get_base_##device(void) \
|
||||
|
@ -277,7 +279,7 @@ static inline unsigned long __attribute__((no_instrument_function)) \
|
|||
return EXYNOS4X12_##base; \
|
||||
return EXYNOS4_##base; \
|
||||
} else if (cpu_is_exynos5()) { \
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422()) \
|
||||
if (proid_is_exynos542x()) \
|
||||
return EXYNOS5420_##base; \
|
||||
return EXYNOS5_##base; \
|
||||
} \
|
||||
|
|
|
@ -1397,7 +1397,7 @@ static struct gpio_info exynos5420_gpio_data[EXYNOS5420_GPIO_NUM_PARTS] = {
|
|||
static inline struct gpio_info *get_gpio_data(void)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return exynos5420_gpio_data;
|
||||
else
|
||||
return exynos5_gpio_data;
|
||||
|
@ -1414,7 +1414,7 @@ static inline struct gpio_info *get_gpio_data(void)
|
|||
static inline unsigned int get_bank_num(void)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return EXYNOS5420_GPIO_NUM_PARTS;
|
||||
else
|
||||
return EXYNOS5_GPIO_NUM_PARTS;
|
||||
|
|
|
@ -378,6 +378,20 @@ static void exynos5_i2s_config(int peripheral)
|
|||
}
|
||||
}
|
||||
|
||||
static void exynos5420_i2s_config(int peripheral)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch (peripheral) {
|
||||
case PERIPH_ID_I2S0:
|
||||
for (i = 0; i < 5; i++)
|
||||
gpio_cfg_pin(EXYNOS5420_GPIO_Z0 + i,
|
||||
S5P_GPIO_FUNC(0x02));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void exynos5_spi_config(int peripheral)
|
||||
{
|
||||
int cfg = 0, pin = 0, i;
|
||||
|
@ -550,6 +564,9 @@ static int exynos5420_pinmux_config(int peripheral, int flags)
|
|||
case PERIPH_ID_I2C10:
|
||||
exynos5420_i2c_config(peripheral);
|
||||
break;
|
||||
case PERIPH_ID_I2S0:
|
||||
exynos5420_i2s_config(peripheral);
|
||||
break;
|
||||
case PERIPH_ID_PWM0:
|
||||
gpio_cfg_pin(EXYNOS5420_GPIO_B20, S5P_GPIO_FUNC(2));
|
||||
break;
|
||||
|
@ -863,7 +880,7 @@ static int exynos4x12_pinmux_config(int peripheral, int flags)
|
|||
int exynos_pinmux_config(int peripheral, int flags)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
return exynos5420_pinmux_config(peripheral, flags);
|
||||
else if (proid_is_exynos5250())
|
||||
return exynos5_pinmux_config(peripheral, flags);
|
||||
|
|
|
@ -124,7 +124,7 @@ static void exynos5420_set_usbdev_phy_ctrl(unsigned int enable)
|
|||
void set_usbdrd_phy_ctrl(unsigned int enable)
|
||||
{
|
||||
if (cpu_is_exynos5()) {
|
||||
if (proid_is_exynos5420() || proid_is_exynos5422())
|
||||
if (proid_is_exynos542x())
|
||||
exynos5420_set_usbdev_phy_ctrl(enable);
|
||||
else
|
||||
exynos5_set_usbdrd_phy_ctrl(enable);
|
||||
|
|
|
@ -4,13 +4,24 @@
|
|||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/input.h>
|
||||
#include <SDL/SDL.h>
|
||||
#include <sound.h>
|
||||
#include <asm/state.h>
|
||||
|
||||
enum {
|
||||
SAMPLE_RATE = 22050,
|
||||
/**
|
||||
* struct buf_info - a data buffer holding audio data
|
||||
*
|
||||
* @pos: Current position playing in audio buffer
|
||||
* @size: Size of data in audio buffer (0=empty)
|
||||
* @alloced: Allocated size of audio buffer (max size it can hold)
|
||||
* @data: Audio data
|
||||
*/
|
||||
struct buf_info {
|
||||
uint pos;
|
||||
uint size;
|
||||
uint alloced;
|
||||
uint8_t *data;
|
||||
};
|
||||
|
||||
static struct sdl_info {
|
||||
|
@ -20,12 +31,12 @@ static struct sdl_info {
|
|||
int depth;
|
||||
int pitch;
|
||||
uint frequency;
|
||||
uint audio_pos;
|
||||
uint audio_size;
|
||||
uint sample_rate;
|
||||
uint8_t *audio_data;
|
||||
bool audio_active;
|
||||
bool inited;
|
||||
int cur_buf;
|
||||
struct buf_info buf[2];
|
||||
bool running;
|
||||
} sdl;
|
||||
|
||||
static void sandbox_sdl_poll_events(void)
|
||||
|
@ -243,24 +254,37 @@ int sandbox_sdl_key_pressed(int keycode)
|
|||
|
||||
void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
|
||||
{
|
||||
struct buf_info *buf;
|
||||
int avail;
|
||||
int i;
|
||||
|
||||
avail = sdl.audio_size - sdl.audio_pos;
|
||||
if (avail < len)
|
||||
len = avail;
|
||||
for (i = 0; i < 2; i++) {
|
||||
buf = &sdl.buf[sdl.cur_buf];
|
||||
avail = buf->size - buf->pos;
|
||||
if (avail <= 0) {
|
||||
sdl.cur_buf = 1 - sdl.cur_buf;
|
||||
continue;
|
||||
}
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
|
||||
SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len,
|
||||
SDL_MIX_MAXVOLUME);
|
||||
sdl.audio_pos += len;
|
||||
SDL_MixAudio(stream, buf->data + buf->pos, avail,
|
||||
SDL_MIX_MAXVOLUME);
|
||||
buf->pos += avail;
|
||||
len -= avail;
|
||||
|
||||
/* Loop if we are at the end */
|
||||
if (sdl.audio_pos == sdl.audio_size)
|
||||
sdl.audio_pos = 0;
|
||||
/* Move to next buffer if we are at the end */
|
||||
if (buf->pos == buf->size)
|
||||
buf->size = 0;
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int sandbox_sdl_sound_init(void)
|
||||
int sandbox_sdl_sound_init(int rate, int channels)
|
||||
{
|
||||
SDL_AudioSpec wanted;
|
||||
int i;
|
||||
|
||||
if (sandbox_sdl_ensure_init())
|
||||
return -1;
|
||||
|
@ -269,20 +293,27 @@ int sandbox_sdl_sound_init(void)
|
|||
return 0;
|
||||
|
||||
/* Set the audio format */
|
||||
wanted.freq = SAMPLE_RATE;
|
||||
wanted.freq = rate;
|
||||
wanted.format = AUDIO_S16;
|
||||
wanted.channels = 1; /* 1 = mono, 2 = stereo */
|
||||
wanted.channels = channels;
|
||||
wanted.samples = 1024; /* Good low-latency value for callback */
|
||||
wanted.callback = sandbox_sdl_fill_audio;
|
||||
wanted.userdata = NULL;
|
||||
|
||||
sdl.audio_size = sizeof(uint16_t) * wanted.freq;
|
||||
sdl.audio_data = malloc(sdl.audio_size);
|
||||
if (!sdl.audio_data) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
return -1;
|
||||
for (i = 0; i < 2; i++) {
|
||||
struct buf_info *buf = &sdl.buf[i];
|
||||
|
||||
buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels;
|
||||
buf->data = malloc(buf->alloced);
|
||||
if (!buf->data) {
|
||||
printf("%s: Out of memory\n", __func__);
|
||||
if (i == 1)
|
||||
free(sdl.buf[0].data);
|
||||
return -1;
|
||||
}
|
||||
buf->pos = 0;
|
||||
buf->size = 0;
|
||||
}
|
||||
sdl.audio_pos = 0;
|
||||
|
||||
if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
|
||||
printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
|
||||
|
@ -296,33 +327,50 @@ int sandbox_sdl_sound_init(void)
|
|||
}
|
||||
sdl.audio_active = true;
|
||||
sdl.sample_rate = wanted.freq;
|
||||
sdl.cur_buf = 0;
|
||||
sdl.running = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
free(sdl.audio_data);
|
||||
for (i = 0; i < 2; i++)
|
||||
free(sdl.buf[i].data);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sandbox_sdl_sound_start(uint frequency)
|
||||
int sandbox_sdl_sound_play(const void *data, uint size)
|
||||
{
|
||||
struct buf_info *buf;
|
||||
|
||||
if (!sdl.audio_active)
|
||||
return -1;
|
||||
sdl.frequency = frequency;
|
||||
sound_create_square_wave(sdl.sample_rate,
|
||||
(unsigned short *)sdl.audio_data,
|
||||
sdl.audio_size, frequency);
|
||||
sdl.audio_pos = 0;
|
||||
SDL_PauseAudio(0);
|
||||
return 0;
|
||||
|
||||
buf = &sdl.buf[0];
|
||||
if (buf->size)
|
||||
buf = &sdl.buf[1];
|
||||
while (buf->size)
|
||||
usleep(1000);
|
||||
|
||||
if (size > buf->alloced)
|
||||
return -E2BIG;
|
||||
|
||||
memcpy(buf->data, data, size);
|
||||
buf->size = size;
|
||||
buf->pos = 0;
|
||||
if (!sdl.running) {
|
||||
SDL_PauseAudio(0);
|
||||
sdl.running = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sandbox_sdl_sound_stop(void)
|
||||
{
|
||||
if (!sdl.audio_active)
|
||||
return -1;
|
||||
SDL_PauseAudio(1);
|
||||
if (sdl.running) {
|
||||
SDL_PauseAudio(1);
|
||||
sdl.running = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
stdout-path = "/serial";
|
||||
};
|
||||
|
||||
audio: audio-codec {
|
||||
compatible = "sandbox,audio-codec";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
cros_ec: cros-ec {
|
||||
reg = <0 0>;
|
||||
u-boot,dm-pre-reloc;
|
||||
|
@ -127,6 +132,11 @@
|
|||
};
|
||||
};
|
||||
|
||||
i2s: i2s {
|
||||
compatible = "sandbox,i2s";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
lcd {
|
||||
u-boot,dm-pre-reloc;
|
||||
compatible = "sandbox,lcd-sdl";
|
||||
|
@ -190,6 +200,17 @@
|
|||
compatible = "sandbox,reset";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "sandbox,sound";
|
||||
cpu {
|
||||
sound-dai = <&i2s 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&audio 0>;
|
||||
};
|
||||
};
|
||||
|
||||
spi@0 {
|
||||
u-boot,dm-pre-reloc;
|
||||
#address-cells = <1>;
|
||||
|
|
|
@ -42,6 +42,11 @@
|
|||
osd0 = "/osd";
|
||||
};
|
||||
|
||||
audio: audio-codec {
|
||||
compatible = "sandbox,audio-codec";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
cros_ec: cros-ec {
|
||||
reg = <0 0>;
|
||||
compatible = "google,cros-ec-sandbox";
|
||||
|
@ -82,6 +87,8 @@
|
|||
test2-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 6 1 3 2 1>,
|
||||
<&gpio_b 7 2 3 2 1>, <&gpio_b 8 4 3 2 1>,
|
||||
<&gpio_b 9 0xc 3 2 1>;
|
||||
int-value = <1234>;
|
||||
uint-value = <(-1234)>;
|
||||
};
|
||||
|
||||
junk {
|
||||
|
@ -373,6 +380,11 @@
|
|||
u-boot,dm-pre-reloc;
|
||||
};
|
||||
|
||||
i2s: i2s {
|
||||
compatible = "sandbox,i2s";
|
||||
#sound-dai-cells = <1>;
|
||||
};
|
||||
|
||||
misc-test {
|
||||
compatible = "sandbox,misc_sandbox";
|
||||
};
|
||||
|
@ -528,6 +540,17 @@
|
|||
compatible = "sandbox,smem";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "sandbox,sound";
|
||||
cpu {
|
||||
sound-dai = <&i2s 0>;
|
||||
};
|
||||
|
||||
codec {
|
||||
sound-dai = <&audio 0>;
|
||||
};
|
||||
};
|
||||
|
||||
spi@0 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
|
|
@ -54,12 +54,12 @@ int sandbox_sdl_scan_keys(int key[], int max_keys);
|
|||
int sandbox_sdl_key_pressed(int keycode);
|
||||
|
||||
/**
|
||||
* sandbox_sdl_sound_start() - start playing a sound
|
||||
* sandbox_sdl_sound_play() - Play a sound
|
||||
*
|
||||
* @frequency: Frequency of sounds in Hertz
|
||||
* @return 0 if OK, -ENODEV if no sound is available
|
||||
* @data: Data to play (typically 16-bit)
|
||||
* @count: Number of bytes in data
|
||||
*/
|
||||
int sandbox_sdl_sound_start(uint frequency);
|
||||
int sandbox_sdl_sound_play(const void *data, uint count);
|
||||
|
||||
/**
|
||||
* sandbox_sdl_sound_stop() - stop playing a sound
|
||||
|
@ -71,9 +71,11 @@ int sandbox_sdl_sound_stop(void);
|
|||
/**
|
||||
* sandbox_sdl_sound_init() - set up the sound system
|
||||
*
|
||||
* @rate: Sample rate to use
|
||||
* @channels: Number of channels to use (1=mono, 2=stereo)
|
||||
* @return 0 if OK, -ENODEV if no sound is available
|
||||
*/
|
||||
int sandbox_sdl_sound_init(void);
|
||||
int sandbox_sdl_sound_init(int rate, int channels);
|
||||
|
||||
#else
|
||||
static inline int sandbox_sdl_init_display(int width, int height,
|
||||
|
@ -102,12 +104,17 @@ static inline int sandbox_sdl_sound_start(uint frequency)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
int sandbox_sdl_sound_play(const void *data, uint count)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int sandbox_sdl_sound_stop(void)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static inline int sandbox_sdl_sound_init(void)
|
||||
int sandbox_sdl_sound_init(int rate, int channels)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright (c) 2013 Google, Inc
|
||||
*/
|
||||
|
||||
#ifndef __SANDBOX_SOUND_H
|
||||
#define __SANDBOX_SOUND_H
|
||||
|
||||
int sound_play(unsigned int msec, unsigned int frequency);
|
||||
|
||||
int sound_init(const void *blob);
|
||||
|
||||
#endif
|
|
@ -121,4 +121,44 @@ int sandbox_pwm_get_config(struct udevice *dev, uint channel, uint *period_nsp,
|
|||
*/
|
||||
void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask);
|
||||
|
||||
/**
|
||||
* sandbox_get_codec_params() - Read back codec parameters
|
||||
*
|
||||
* This reads back the parameters set by audio_codec_set_params() for the
|
||||
* sandbox audio driver. Arguments are as for that function.
|
||||
*/
|
||||
void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
|
||||
int *mclk_freqp, int *bits_per_samplep,
|
||||
uint *channelsp);
|
||||
|
||||
/**
|
||||
* sandbox_get_i2s_sum() - Read back the sum of the audio data so far
|
||||
*
|
||||
* This data is provided to the sandbox driver by the I2S tx_data() method.
|
||||
*
|
||||
* @dev: Device to check
|
||||
* @return sum of audio data
|
||||
*/
|
||||
int sandbox_get_i2s_sum(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_get_setup_called() - Returns the number of times setup(*) was called
|
||||
*
|
||||
* This is used in the sound test
|
||||
*
|
||||
* @dev: Device to check
|
||||
* @return call count for the setup() method
|
||||
*/
|
||||
int sandbox_get_setup_called(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* sandbox_get_sound_sum() - Read back the sum of the sound data so far
|
||||
*
|
||||
* This data is provided to the sandbox driver by the sound play() method.
|
||||
*
|
||||
* @dev: Device to check
|
||||
* @return sum of audio data
|
||||
*/
|
||||
int sandbox_get_sound_sum(struct udevice *dev);
|
||||
|
||||
#endif
|
||||
|
|
15
cmd/sound.c
15
cmd/sound.c
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <common.h>
|
||||
#include <command.h>
|
||||
#include <dm.h>
|
||||
#include <fdtdec.h>
|
||||
#include <sound.h>
|
||||
|
||||
|
@ -14,11 +15,14 @@ DECLARE_GLOBAL_DATA_PTR;
|
|||
/* Initilaise sound subsystem */
|
||||
static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret;
|
||||
|
||||
ret = sound_init(gd->fdt_blob);
|
||||
ret = uclass_first_device_err(UCLASS_SOUND, &dev);
|
||||
if (!ret)
|
||||
ret = sound_setup(dev);
|
||||
if (ret) {
|
||||
printf("Initialise Audio driver failed\n");
|
||||
printf("Initialise Audio driver failed (ret=%d)\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -28,6 +32,7 @@ static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
|||
/* play sound from buffer */
|
||||
static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
||||
{
|
||||
struct udevice *dev;
|
||||
int ret = 0;
|
||||
int msec = 1000;
|
||||
int freq = 400;
|
||||
|
@ -37,9 +42,11 @@ static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
|
|||
if (argc > 2)
|
||||
freq = simple_strtoul(argv[2], NULL, 10);
|
||||
|
||||
ret = sound_play(msec, freq);
|
||||
ret = uclass_first_device_err(UCLASS_SOUND, &dev);
|
||||
if (!ret)
|
||||
ret = sound_beep(dev, msec, freq);
|
||||
if (ret) {
|
||||
printf("play failed");
|
||||
printf("Sound device failed to play (err=%d)\n", ret);
|
||||
return CMD_RET_FAILURE;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@ CONFIG_CMD_USB=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_CMD_CACHE=y
|
||||
CONFIG_CMD_TIME=y
|
||||
CONFIG_CMD_SOUND=y
|
||||
CONFIG_CMD_PMIC=y
|
||||
CONFIG_CMD_REGULATOR=y
|
||||
CONFIG_CMD_TPM=y
|
||||
|
@ -28,7 +29,6 @@ CONFIG_CMD_TPM_TEST=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5800-peach-pi"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_I2C_CROS_EC_TUNNEL=y
|
||||
CONFIG_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
|
@ -52,6 +52,7 @@ CONFIG_PWM_EXYNOS=y
|
|||
CONFIG_SOUND=y
|
||||
CONFIG_I2S=y
|
||||
CONFIG_I2S_SAMSUNG=y
|
||||
CONFIG_SOUND_MAX98090=y
|
||||
CONFIG_SOUND_MAX98095=y
|
||||
CONFIG_SOUND_WM8994=y
|
||||
CONFIG_EXYNOS_SPI=y
|
||||
|
|
|
@ -20,6 +20,7 @@ CONFIG_CMD_USB=y
|
|||
# CONFIG_CMD_SETEXPR is not set
|
||||
CONFIG_CMD_CACHE=y
|
||||
CONFIG_CMD_TIME=y
|
||||
CONFIG_CMD_SOUND=y
|
||||
CONFIG_CMD_PMIC=y
|
||||
CONFIG_CMD_REGULATOR=y
|
||||
CONFIG_CMD_TPM=y
|
||||
|
@ -27,7 +28,6 @@ CONFIG_CMD_TPM_TEST=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5420-peach-pit"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_I2C_CROS_EC_TUNNEL=y
|
||||
CONFIG_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
|
@ -51,6 +51,7 @@ CONFIG_PWM_EXYNOS=y
|
|||
CONFIG_SOUND=y
|
||||
CONFIG_I2S=y
|
||||
CONFIG_I2S_SAMSUNG=y
|
||||
CONFIG_SOUND_MAX98090=y
|
||||
CONFIG_SOUND_MAX98095=y
|
||||
CONFIG_SOUND_WM8994=y
|
||||
CONFIG_EXYNOS_SPI=y
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
CONFIG_SYS_TEXT_BASE=0
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_SANDBOX64=y
|
||||
CONFIG_DISTRO_DEFAULTS=y
|
||||
CONFIG_NR_DRAM_BANKS=1
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
CONFIG_SYS_TEXT_BASE=0
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_DEBUG_UART=y
|
||||
CONFIG_DISTRO_DEFAULTS=y
|
||||
CONFIG_NR_DRAM_BANKS=1
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
CONFIG_SYS_TEXT_BASE=0
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_DISTRO_DEFAULTS=y
|
||||
CONFIG_NR_DRAM_BANKS=1
|
||||
CONFIG_FIT=y
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
CONFIG_SYS_TEXT_BASE=0
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_DISTRO_DEFAULTS=y
|
||||
CONFIG_NR_DRAM_BANKS=1
|
||||
CONFIG_FIT=y
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
CONFIG_SYS_TEXT_BASE=0
|
||||
CONFIG_SPL_LIBCOMMON_SUPPORT=y
|
||||
CONFIG_SPL_LIBGENERIC_SUPPORT=y
|
||||
CONFIG_SYS_MALLOC_F_LEN=0x2000
|
||||
CONFIG_SPL_SERIAL_SUPPORT=y
|
||||
CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
|
||||
CONFIG_SPL=y
|
||||
|
|
|
@ -30,7 +30,6 @@ CONFIG_CMD_REGULATOR=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5250-smdk5250"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_MMC_DW=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_S5P=y
|
||||
|
|
|
@ -25,7 +25,6 @@ CONFIG_CMD_TIME=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5420-smdk5420"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_MMC_DW=y
|
||||
CONFIG_MMC_SDHCI=y
|
||||
CONFIG_MMC_SDHCI_S5P=y
|
||||
|
|
|
@ -34,7 +34,6 @@ CONFIG_CMD_TPM_TEST=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5250-snow"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_I2C_CROS_EC_LDO=y
|
||||
CONFIG_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
|
|
|
@ -34,7 +34,6 @@ CONFIG_CMD_TPM_TEST=y
|
|||
CONFIG_CMD_EXT4_WRITE=y
|
||||
CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring"
|
||||
CONFIG_ENV_IS_IN_SPI_FLASH=y
|
||||
CONFIG_DM_I2C_COMPAT=y
|
||||
CONFIG_I2C_CROS_EC_LDO=y
|
||||
CONFIG_I2C_MUX=y
|
||||
CONFIG_I2C_ARB_GPIO_CHALLENGE=y
|
||||
|
|
|
@ -21,6 +21,29 @@ int dev_read_u32_default(struct udevice *dev, const char *propname, int def)
|
|||
return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
|
||||
}
|
||||
|
||||
int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp)
|
||||
{
|
||||
return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp);
|
||||
}
|
||||
|
||||
int dev_read_s32_default(struct udevice *dev, const char *propname, int def)
|
||||
{
|
||||
return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
|
||||
}
|
||||
|
||||
int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*outp = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *dev_read_string(struct udevice *dev, const char *propname)
|
||||
{
|
||||
return ofnode_read_string(dev_ofnode(dev), propname);
|
||||
|
|
|
@ -31,6 +31,14 @@ config I2S_SAMSUNG
|
|||
option provides an implementation for sound_init() and
|
||||
sound_play().
|
||||
|
||||
config SOUND_MAX98090
|
||||
bool "Support Maxim max98090 audio codec"
|
||||
depends on I2S_SAMSUNG
|
||||
help
|
||||
Enable the max98090 audio codec. This is connected via I2S for
|
||||
audio data and I2C for codec control. At present it only works
|
||||
with the Samsung I2S driver.
|
||||
|
||||
config SOUND_MAX98095
|
||||
bool "Support Maxim max98095 audio codec"
|
||||
depends on I2S_SAMSUNG
|
||||
|
|
|
@ -4,8 +4,12 @@
|
|||
# R. Chandrasekar <rcsekar@samsung.com>
|
||||
|
||||
obj-$(CONFIG_SOUND) += sound.o
|
||||
obj-$(CONFIG_I2S) += sound-i2s.o
|
||||
obj-$(CONFIG_SOUND) += codec-uclass.o
|
||||
obj-$(CONFIG_SOUND) += i2s-uclass.o
|
||||
obj-$(CONFIG_SOUND) += sound-uclass.o
|
||||
obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
|
||||
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
|
||||
obj-$(CONFIG_I2S_SAMSUNG) += samsung_sound.o
|
||||
obj-$(CONFIG_SOUND_WM8994) += wm8994.o
|
||||
obj-$(CONFIG_SOUND_MAX98095) += max98095.o
|
||||
obj-$(CONFIG_SOUND_MAX98090) += max98090.o maxim_codec.o
|
||||
obj-$(CONFIG_SOUND_MAX98095) += max98095.o maxim_codec.o
|
||||
|
|
26
drivers/sound/codec-uclass.c
Normal file
26
drivers/sound/codec-uclass.c
Normal file
|
@ -0,0 +1,26 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <audio_codec.h>
|
||||
|
||||
int audio_codec_set_params(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample, uint channels)
|
||||
{
|
||||
struct audio_codec_ops *ops = audio_codec_get_ops(dev);
|
||||
|
||||
if (!ops->set_params)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->set_params(dev, interface, rate, mclk_freq, bits_per_sample,
|
||||
channels);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(audio_codec) = {
|
||||
.id = UCLASS_AUDIO_CODEC,
|
||||
.name = "audio-codec",
|
||||
};
|
25
drivers/sound/i2s-uclass.c
Normal file
25
drivers/sound/i2s-uclass.c
Normal file
|
@ -0,0 +1,25 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
|
||||
int i2s_tx_data(struct udevice *dev, void *data, uint data_size)
|
||||
{
|
||||
struct i2s_ops *ops = i2s_get_ops(dev);
|
||||
|
||||
if (!ops->tx_data)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->tx_data(dev, data, data_size);
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(i2s) = {
|
||||
.id = UCLASS_I2S,
|
||||
.name = "i2s",
|
||||
.per_device_auto_alloc_size = sizeof(struct i2s_uc_priv),
|
||||
};
|
377
drivers/sound/max98090.c
Normal file
377
drivers/sound/max98090.c
Normal file
|
@ -0,0 +1,377 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* max98090.c -- MAX98090 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <audio_codec.h>
|
||||
#include <div64.h>
|
||||
#include <dm.h>
|
||||
#include <i2c.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include "maxim_codec.h"
|
||||
#include "max98090.h"
|
||||
|
||||
/*
|
||||
* Sets hw params for max98090
|
||||
*
|
||||
* @priv: max98090 information pointer
|
||||
* @rate: Sampling rate
|
||||
* @bits_per_sample: Bits per sample
|
||||
*
|
||||
* @return -EIO for error, 0 for success.
|
||||
*/
|
||||
int max98090_hw_params(struct maxim_priv *priv, unsigned int rate,
|
||||
unsigned int bits_per_sample)
|
||||
{
|
||||
int error;
|
||||
unsigned char value;
|
||||
|
||||
switch (bits_per_sample) {
|
||||
case 16:
|
||||
maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
|
||||
error = maxim_bic_or(priv, M98090_REG_INTERFACE_FORMAT,
|
||||
M98090_WS_MASK, 0);
|
||||
maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Illegal bits per sample %d.\n",
|
||||
__func__, bits_per_sample);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update filter mode */
|
||||
if (rate < 240000)
|
||||
error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
|
||||
M98090_MODE_MASK, 0);
|
||||
else
|
||||
error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
|
||||
M98090_MODE_MASK, M98090_MODE_MASK);
|
||||
|
||||
/* Update sample rate mode */
|
||||
if (rate < 50000)
|
||||
error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
|
||||
M98090_DHF_MASK, 0);
|
||||
else
|
||||
error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
|
||||
M98090_DHF_MASK, M98090_DHF_MASK);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting hardware params.\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
priv->rate = rate;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Configures Audio interface system clock for the given frequency
|
||||
*
|
||||
* @priv: max98090 information
|
||||
* @freq: Sampling frequency in Hz
|
||||
*
|
||||
* @return -EIO for error, 0 for success.
|
||||
*/
|
||||
int max98090_set_sysclk(struct maxim_priv *priv, unsigned int freq)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Requested clock frequency is already setup */
|
||||
if (freq == priv->sysclk)
|
||||
return 0;
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
* PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
|
||||
* 0x02 (when master clk is 20MHz to 40MHz)..
|
||||
* 0x03 (when master clk is 40MHz to 60MHz)..
|
||||
*/
|
||||
if (freq >= 10000000 && freq < 20000000) {
|
||||
error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV1);
|
||||
} else if (freq >= 20000000 && freq < 40000000) {
|
||||
error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV2);
|
||||
} else if (freq >= 40000000 && freq < 60000000) {
|
||||
error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
|
||||
M98090_PSCLK_DIV4);
|
||||
} else {
|
||||
debug("%s: Invalid master clock frequency\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
debug("%s: Clock at %uHz\n", __func__, freq);
|
||||
|
||||
if (error < 0)
|
||||
return -1;
|
||||
|
||||
priv->sysclk = freq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets Max98090 I2S format
|
||||
*
|
||||
* @priv: max98090 information
|
||||
* @fmt: i2S format - supports a subset of the options defined in i2s.h.
|
||||
*
|
||||
* @return -EIO for error, 0 for success.
|
||||
*/
|
||||
int max98090_set_fmt(struct maxim_priv *priv, int fmt)
|
||||
{
|
||||
u8 regval = 0;
|
||||
int error = 0;
|
||||
|
||||
if (fmt == priv->fmt)
|
||||
return 0;
|
||||
|
||||
priv->fmt = fmt;
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
/* Set to slave mode PLL - MAS mode off */
|
||||
error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB,
|
||||
0x00);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB,
|
||||
0x00);
|
||||
error |= maxim_bic_or(priv, M98090_REG_CLOCK_MODE,
|
||||
M98090_USE_M1_MASK, 0);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* Set to master mode */
|
||||
debug("Master mode not supported\n");
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBS_CFM:
|
||||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
default:
|
||||
debug("%s: Clock mode unsupported\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, regval);
|
||||
|
||||
regval = 0;
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
case SND_SOC_DAIFMT_I2S:
|
||||
regval |= M98090_DLY_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_LEFT_J:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_RIGHT_J:
|
||||
regval |= M98090_RJ_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_DSP_A:
|
||||
/* Not supported mode */
|
||||
default:
|
||||
debug("%s: Unrecognized format.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
case SND_SOC_DAIFMT_NB_NF:
|
||||
break;
|
||||
case SND_SOC_DAIFMT_NB_IF:
|
||||
regval |= M98090_WCI_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_NF:
|
||||
regval |= M98090_BCI_MASK;
|
||||
break;
|
||||
case SND_SOC_DAIFMT_IB_IF:
|
||||
regval |= M98090_BCI_MASK | M98090_WCI_MASK;
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unrecognized inversion settings.\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, regval);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting i2s format.\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* resets the audio codec
|
||||
*
|
||||
* @priv: max98090 information
|
||||
* @return -EIO for error, 0 for success.
|
||||
*/
|
||||
static int max98090_reset(struct maxim_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Gracefully reset the DSP core and the codec hardware in a proper
|
||||
* sequence.
|
||||
*/
|
||||
ret = maxim_i2c_write(priv, M98090_REG_SOFTWARE_RESET,
|
||||
M98090_SWRESET_MASK);
|
||||
if (ret != 0) {
|
||||
debug("%s: Failed to reset DSP: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
mdelay(20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise max98090 codec device
|
||||
*
|
||||
* @priv: max98090 information
|
||||
*
|
||||
* @return -EIO for error, 0 for success.
|
||||
*/
|
||||
int max98090_device_init(struct maxim_priv *priv)
|
||||
{
|
||||
unsigned char id;
|
||||
int error = 0;
|
||||
|
||||
/* Enable codec clock */
|
||||
set_xclkout();
|
||||
|
||||
/* reset the codec, the DSP core, and disable all interrupts */
|
||||
error = max98090_reset(priv);
|
||||
if (error != 0) {
|
||||
debug("Reset\n");
|
||||
return error;
|
||||
}
|
||||
|
||||
/* initialize private data */
|
||||
priv->sysclk = -1U;
|
||||
priv->rate = -1U;
|
||||
priv->fmt = -1U;
|
||||
|
||||
error = maxim_i2c_read(priv, M98090_REG_REVISION_ID, &id);
|
||||
if (error < 0) {
|
||||
debug("%s: Failure reading hardware revision: %d\n",
|
||||
__func__, id);
|
||||
return -EIO;
|
||||
}
|
||||
debug("%s: Hardware revision: %d\n", __func__, id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98090_setup_interface(struct maxim_priv *priv)
|
||||
{
|
||||
unsigned char id;
|
||||
int error;
|
||||
|
||||
/* Reading interrupt status to clear them */
|
||||
error = maxim_i2c_read(priv, M98090_REG_DEVICE_STATUS, &id);
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_DAC_CONTROL,
|
||||
M98090_DACHP_MASK);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_BIAS_CONTROL,
|
||||
M98090_VCM_MODE_MASK);
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_MIXER, 0x1);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_MIXER, 0x2);
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_VOLUME, 0x25);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_VOLUME, 0x25);
|
||||
|
||||
error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB, 0x0);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB, 0x0);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, 0x0);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, 0x0);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
|
||||
M98090_SDIEN_MASK);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_DEVICE_SHUTDOWN,
|
||||
M98090_SHDNN_MASK);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_OUTPUT_ENABLE,
|
||||
M98090_HPREN_MASK | M98090_HPLEN_MASK |
|
||||
M98090_SPREN_MASK | M98090_SPLEN_MASK |
|
||||
M98090_DAREN_MASK | M98090_DALEN_MASK);
|
||||
error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
|
||||
M98090_SDOEN_MASK | M98090_SDIEN_MASK);
|
||||
|
||||
if (error < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98090_do_init(struct maxim_priv *priv, int sampling_rate,
|
||||
int mclk_freq, int bits_per_sample)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = max98090_setup_interface(priv);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98090 setup interface failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98090_set_sysclk(priv, mclk_freq);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98090 codec set sys clock failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98090_hw_params(priv, sampling_rate, bits_per_sample);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = max98090_set_fmt(priv, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int max98090_set_params(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample,
|
||||
uint channels)
|
||||
{
|
||||
struct maxim_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return max98090_do_init(priv, rate, mclk_freq, bits_per_sample);
|
||||
}
|
||||
|
||||
static int max98090_probe(struct udevice *dev)
|
||||
{
|
||||
struct maxim_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
priv->dev = dev;
|
||||
ret = max98090_device_init(priv);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98090 codec chip init failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct audio_codec_ops max98090_ops = {
|
||||
.set_params = max98090_set_params,
|
||||
};
|
||||
|
||||
static const struct udevice_id max98090_ids[] = {
|
||||
{ .compatible = "maxim,max98090" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(max98090) = {
|
||||
.name = "max98090",
|
||||
.id = UCLASS_AUDIO_CODEC,
|
||||
.of_match = max98090_ids,
|
||||
.probe = max98090_probe,
|
||||
.ops = &max98090_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct maxim_priv),
|
||||
};
|
663
drivers/sound/max98090.h
Normal file
663
drivers/sound/max98090.h
Normal file
|
@ -0,0 +1,663 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* max98090.h -- MAX98090 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*/
|
||||
|
||||
#ifndef _MAX98090_H
|
||||
#define _MAX98090_H
|
||||
|
||||
#include "maxim_codec.h"
|
||||
|
||||
/* MAX98090 Registers Definition */
|
||||
|
||||
#define M98090_REG_SOFTWARE_RESET 0x00
|
||||
#define M98090_REG_DEVICE_STATUS 0x01
|
||||
|
||||
#define M98090_REG_QUICK_SAMPLE_RATE 0x05
|
||||
#define M98090_REG_DAI_INTERFACE 0x06
|
||||
#define M98090_REG_DAC_PATH 0x07
|
||||
|
||||
#define M98090_REG_MIC_BIAS_VOLTAGE 0x12
|
||||
#define M98090_REG_DIGITAL_MIC_ENABLE 0x13
|
||||
#define M98090_REG_DIGITAL_MIC_CONFIG 0x14
|
||||
#define M98090_REG_SYSTEM_CLOCK 0x1B
|
||||
#define M98090_REG_CLOCK_RATIO_NI_MSB 0x1D
|
||||
#define M98090_REG_CLOCK_MODE 0x1C
|
||||
#define M98090_REG_CLOCK_RATIO_NI_LSB 0x1E
|
||||
|
||||
#define M98090_REG_MASTER_MODE 0x21
|
||||
#define M98090_REG_INTERFACE_FORMAT 0x22
|
||||
#define M98090_REG_IO_CONFIGURATION 0x25
|
||||
#define M98090_REG_FILTER_CONFIG 0x26
|
||||
|
||||
#define M98090_REG_LEFT_HP_MIXER 0x29
|
||||
#define M98090_REG_RIGHT_HP_MIXER 0x2a
|
||||
#define M98090_REG_HP_CONTROL 0x2b
|
||||
#define M98090_REG_LEFT_HP_VOLUME 0x2c
|
||||
#define M98090_REG_RIGHT_HP_VOLUME 0x2d
|
||||
#define M98090_REG_LEFT_SPK_MIXER 0x2e
|
||||
#define M98090_REG_RIGHT_SPK_MIXER 0x2f
|
||||
#define M98090_REG_SPK_CONTROL 0x30
|
||||
#define M98090_REG_LEFT_SPK_VOLUME 0x31
|
||||
#define M98090_REG_RIGHT_SPK_VOLUME 0x32
|
||||
|
||||
#define M98090_REG_RCV_LOUTL_CONTROL 0x38
|
||||
#define M98090_REG_RCV_LOUTL_VOLUME 0x39
|
||||
#define M98090_REG_LOUTR_MIXER 0x3a
|
||||
#define M98090_REG_LOUTR_CONTROL 0x3b
|
||||
#define M98090_REG_LOUTR_VOLUME 0x3c
|
||||
#define M98090_REG_JACK_DETECT 0x3d
|
||||
#define M98090_REG_INPUT_ENABLE 0x3e
|
||||
#define M98090_REG_OUTPUT_ENABLE 0x3f
|
||||
#define M98090_REG_LEVEL_CONTROL 0x40
|
||||
#define M98090_REG_DSP_FILTER_ENABLE 0x41
|
||||
#define M98090_REG_BIAS_CONTROL 0x42
|
||||
#define M98090_REG_DAC_CONTROL 0x43
|
||||
#define M98090_REG_ADC_CONTROL 0x44
|
||||
#define M98090_REG_DEVICE_SHUTDOWN 0x45
|
||||
|
||||
#define M98090_REG_REVISION_ID 0xff
|
||||
|
||||
#define M98090_REG_CNT (0xff + 1)
|
||||
#define M98090_REG_MAX_CACHed 0x45
|
||||
|
||||
/* MAX98090 Registers Bit Fields */
|
||||
|
||||
/*
|
||||
* M98090_REG_SOFTWARE_RESET 0x00
|
||||
*/
|
||||
#define M98090_SWRESET_MASK BIT(7)
|
||||
|
||||
/*
|
||||
* M98090_REG_QUICK_SAMPLE_RATE 0x05
|
||||
*/
|
||||
#define M98090_SR_96K_MASK BIT(5)
|
||||
#define M98090_SR_96K_SHIFT 5
|
||||
#define M98090_SR_96K_WIDTH 1
|
||||
#define M98090_SR_32K_MASK BIT(4)
|
||||
#define M98090_SR_32K_SHIFT 4
|
||||
#define M98090_SR_32K_WIDTH 1
|
||||
#define M98090_SR_48K_MASK BIT(3)
|
||||
#define M98090_SR_48K_SHIFT 3
|
||||
#define M98090_SR_48K_WIDTH 1
|
||||
#define M98090_SR_44K1_MASK BIT(2)
|
||||
#define M98090_SR_44K1_SHIFT 2
|
||||
#define M98090_SR_44K1_WIDTH 1
|
||||
#define M98090_SR_16K_MASK BIT(1)
|
||||
#define M98090_SR_16K_SHIFT 1
|
||||
#define M98090_SR_16K_WIDTH 1
|
||||
#define M98090_SR_8K_MASK BIT(0)
|
||||
#define M98090_SR_8K_SHIFT 0
|
||||
#define M98090_SR_8K_WIDTH 1
|
||||
#define M98090_SR_MASK 0x3F
|
||||
#define M98090_SR_ALL_SHIFT 0
|
||||
#define M98090_SR_ALL_WIDTH 8
|
||||
#define M98090_SR_ALL_NUM BIT(M98090_SR_ALL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_DAI_INTERFACE 0x06
|
||||
*/
|
||||
#define M98090_RJ_M_MASK BIT(5)
|
||||
#define M98090_RJ_M_SHIFT 5
|
||||
#define M98090_RJ_M_WIDTH 1
|
||||
#define M98090_RJ_S_MASK BIT(4)
|
||||
#define M98090_RJ_S_SHIFT 4
|
||||
#define M98090_RJ_S_WIDTH 1
|
||||
#define M98090_LJ_M_MASK BIT(3)
|
||||
#define M98090_LJ_M_SHIFT 3
|
||||
#define M98090_LJ_M_WIDTH 1
|
||||
#define M98090_LJ_S_MASK BIT(2)
|
||||
#define M98090_LJ_S_SHIFT 2
|
||||
#define M98090_LJ_S_WIDTH 1
|
||||
#define M98090_I2S_M_MASK BIT(1)
|
||||
#define M98090_I2S_M_SHIFT 1
|
||||
#define M98090_I2S_M_WIDTH 1
|
||||
#define M98090_I2S_S_MASK BIT(0)
|
||||
#define M98090_I2S_S_SHIFT 0
|
||||
#define M98090_I2S_S_WIDTH 1
|
||||
#define M98090_DAI_ALL_SHIFT 0
|
||||
#define M98090_DAI_ALL_WIDTH 8
|
||||
#define M98090_DAI_ALL_NUM BIT(M98090_DAI_ALL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_DAC_PATH 0x07
|
||||
*/
|
||||
#define M98090_DIG2_HP_MASK BIT(7)
|
||||
#define M98090_DIG2_HP_SHIFT 7
|
||||
#define M98090_DIG2_HP_WIDTH 1
|
||||
#define M98090_DIG2_EAR_MASK BIT(6)
|
||||
#define M98090_DIG2_EAR_SHIFT 6
|
||||
#define M98090_DIG2_EAR_WIDTH 1
|
||||
#define M98090_DIG2_SPK_MASK BIT(5)
|
||||
#define M98090_DIG2_SPK_SHIFT 5
|
||||
#define M98090_DIG2_SPK_WIDTH 1
|
||||
#define M98090_DIG2_LOUT_MASK BIT(4)
|
||||
#define M98090_DIG2_LOUT_SHIFT 4
|
||||
#define M98090_DIG2_LOUT_WIDTH 1
|
||||
#define M98090_DIG2_ALL_SHIFT 0
|
||||
#define M98090_DIG2_ALL_WIDTH 8
|
||||
#define M98090_DIG2_ALL_NUM BIT(M98090_DIG2_ALL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_MIC_BIAS_VOLTAGE 0x12
|
||||
*/
|
||||
#define M98090_MBVSEL_MASK (3 << 0)
|
||||
#define M98090_MBVSEL_SHIFT 0
|
||||
#define M98090_MBVSEL_WIDTH 2
|
||||
#define M98090_MBVSEL_2V8 (3 << 0)
|
||||
#define M98090_MBVSEL_2V55 (2 << 0)
|
||||
#define M98090_MBVSEL_2V4 BIT(0)
|
||||
#define M98090_MBVSEL_2V2 (0 << 0)
|
||||
|
||||
/*
|
||||
* M98090_REG_DIGITAL_MIC_ENABLE 0x13
|
||||
*/
|
||||
#define M98090_MICCLK_MASK (7 << 4)
|
||||
#define M98090_MICCLK_SHIFT 4
|
||||
#define M98090_MICCLK_WIDTH 3
|
||||
#define M98090_DIGMIC4_MASK BIT(3)
|
||||
#define M98090_DIGMIC4_SHIFT 3
|
||||
#define M98090_DIGMIC4_WIDTH 1
|
||||
#define M98090_DIGMIC4_NUM BIT(M98090_DIGMIC4_WIDTH)
|
||||
#define M98090_DIGMIC3_MASK BIT(2)
|
||||
#define M98090_DIGMIC3_SHIFT 2
|
||||
#define M98090_DIGMIC3_WIDTH 1
|
||||
#define M98090_DIGMIC3_NUM BIT(M98090_DIGMIC3_WIDTH)
|
||||
#define M98090_DIGMICR_MASK BIT(1)
|
||||
#define M98090_DIGMICR_SHIFT 1
|
||||
#define M98090_DIGMICR_WIDTH 1
|
||||
#define M98090_DIGMICR_NUM BIT(M98090_DIGMICR_WIDTH)
|
||||
#define M98090_DIGMICL_MASK BIT(0)
|
||||
#define M98090_DIGMICL_SHIFT 0
|
||||
#define M98090_DIGMICL_WIDTH 1
|
||||
#define M98090_DIGMICL_NUM BIT(M98090_DIGMICL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_DIGITAL_MIC_CONFIG 0x14
|
||||
*/
|
||||
#define M98090_DMIC_COMP_MASK (15 << 4)
|
||||
#define M98090_DMIC_COMP_SHIFT 4
|
||||
#define M98090_DMIC_COMP_WIDTH 4
|
||||
#define M98090_DMIC_COMP_NUM BIT(M98090_DMIC_COMP_WIDTH)
|
||||
#define M98090_DMIC_FREQ_MASK (3 << 0)
|
||||
#define M98090_DMIC_FREQ_SHIFT 0
|
||||
#define M98090_DMIC_FREQ_WIDTH 2
|
||||
|
||||
/*
|
||||
* M98090_REG_CLOCK_MODE 0x1B
|
||||
*/
|
||||
#define M98090_PSCLK_MASK (3 << 4)
|
||||
#define M98090_PSCLK_SHIFT 4
|
||||
#define M98090_PSCLK_WIDTH 2
|
||||
#define M98090_PSCLK_DISABLED (0 << 4)
|
||||
#define M98090_PSCLK_DIV1 BIT(4)
|
||||
#define M98090_PSCLK_DIV2 (2 << 4)
|
||||
#define M98090_PSCLK_DIV4 (3 << 4)
|
||||
|
||||
/*
|
||||
* M98090_REG_INTERFACE_FORMAT 0x22
|
||||
*/
|
||||
#define M98090_RJ_MASK BIT(5)
|
||||
#define M98090_RJ_SHIFT 5
|
||||
#define M98090_RJ_WIDTH 1
|
||||
#define M98090_WCI_MASK BIT(4)
|
||||
#define M98090_WCI_SHIFT 4
|
||||
#define M98090_WCI_WIDTH 1
|
||||
#define M98090_BCI_MASK BIT(3)
|
||||
#define M98090_BCI_SHIFT 3
|
||||
#define M98090_BCI_WIDTH 1
|
||||
#define M98090_DLY_MASK BIT(2)
|
||||
#define M98090_DLY_SHIFT 2
|
||||
#define M98090_DLY_WIDTH 1
|
||||
#define M98090_WS_MASK (3 << 0)
|
||||
#define M98090_WS_SHIFT 0
|
||||
#define M98090_WS_WIDTH 2
|
||||
#define M98090_WS_NUM BIT(M98090_WS_WIDTH)
|
||||
|
||||
/* M98090_REG_IO_CONFIGURATION 0x25 */
|
||||
#define M98090_LTEN_MASK BIT(5)
|
||||
#define M98090_LTEN_SHIFT 5
|
||||
#define M98090_LTEN_WIDTH 1
|
||||
#define M98090_LTEN_NUM BIT(M98090_LTEN_WIDTH)
|
||||
#define M98090_LBEN_MASK BIT(4)
|
||||
#define M98090_LBEN_SHIFT 4
|
||||
#define M98090_LBEN_WIDTH 1
|
||||
#define M98090_LBEN_NUM BIT(M98090_LBEN_WIDTH)
|
||||
#define M98090_DMONO_MASK BIT(3)
|
||||
#define M98090_DMONO_SHIFT 3
|
||||
#define M98090_DMONO_WIDTH 1
|
||||
#define M98090_DMONO_NUM BIT(M98090_DMONO_WIDTH)
|
||||
#define M98090_HIZOFF_MASK BIT(2)
|
||||
#define M98090_HIZOFF_SHIFT 2
|
||||
#define M98090_HIZOFF_WIDTH 1
|
||||
#define M98090_HIZOFF_NUM BIT(M98090_HIZOFF_WIDTH)
|
||||
#define M98090_SDOEN_MASK BIT(1)
|
||||
#define M98090_SDOEN_SHIFT 1
|
||||
#define M98090_SDOEN_WIDTH 1
|
||||
#define M98090_SDOEN_NUM BIT(M98090_SDOEN_WIDTH)
|
||||
#define M98090_SDIEN_MASK BIT(0)
|
||||
#define M98090_SDIEN_SHIFT 0
|
||||
#define M98090_SDIEN_WIDTH 1
|
||||
#define M98090_SDIEN_NUM BIT(M98090_SDIEN_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_FILTER_CONFIG 0x26
|
||||
*/
|
||||
#define M98090_MODE_MASK BIT(7)
|
||||
#define M98090_MODE_SHIFT 7
|
||||
#define M98090_MODE_WIDTH 1
|
||||
#define M98090_AHPF_MASK BIT(6)
|
||||
#define M98090_AHPF_SHIFT 6
|
||||
#define M98090_AHPF_WIDTH 1
|
||||
#define M98090_AHPF_NUM BIT(M98090_AHPF_WIDTH)
|
||||
#define M98090_DHPF_MASK BIT(5)
|
||||
#define M98090_DHPF_SHIFT 5
|
||||
#define M98090_DHPF_WIDTH 1
|
||||
#define M98090_DHPF_NUM BIT(M98090_DHPF_WIDTH)
|
||||
#define M98090_DHF_MASK BIT(4)
|
||||
#define M98090_DHF_SHIFT 4
|
||||
#define M98090_DHF_WIDTH 1
|
||||
#define M98090_FLT_DMIC34MODE_MASK BIT(3)
|
||||
#define M98090_FLT_DMIC34MODE_SHIFT 3
|
||||
#define M98090_FLT_DMIC34MODE_WIDTH 1
|
||||
#define M98090_FLT_DMIC34HPF_MASK BIT(2)
|
||||
#define M98090_FLT_DMIC34HPF_SHIFT 2
|
||||
#define M98090_FLT_DMIC34HPF_WIDTH 1
|
||||
#define M98090_FLT_DMIC34HPF_NUM BIT(M98090_FLT_DMIC34HPF_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_CLOCK_MODE
|
||||
*/
|
||||
#define M98090_FREQ_MASK (15 << 4)
|
||||
#define M98090_FREQ_SHIFT 4
|
||||
#define M98090_FREQ_WIDTH 4
|
||||
#define M98090_USE_M1_MASK BIT(0)
|
||||
#define M98090_USE_M1_SHIFT 0
|
||||
#define M98090_USE_M1_WIDTH 1
|
||||
#define M98090_USE_M1_NUM BIT(M98090_USE_M1_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_LEFT_HP_MIXER 0x29
|
||||
*/
|
||||
#define M98090_MIXHPL_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXHPL_MIC2_SHIFT 5
|
||||
#define M98090_MIXHPL_MIC2_WIDTH 1
|
||||
#define M98090_MIXHPL_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXHPL_MIC1_SHIFT 4
|
||||
#define M98090_MIXHPL_MIC1_WIDTH 1
|
||||
#define M98090_MIXHPL_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXHPL_LINEB_SHIFT 3
|
||||
#define M98090_MIXHPL_LINEB_WIDTH 1
|
||||
#define M98090_MIXHPL_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXHPL_LINEA_SHIFT 2
|
||||
#define M98090_MIXHPL_LINEA_WIDTH 1
|
||||
#define M98090_MIXHPL_DACR_MASK BIT(1)
|
||||
#define M98090_MIXHPL_DACR_SHIFT 1
|
||||
#define M98090_MIXHPL_DACR_WIDTH 1
|
||||
#define M98090_MIXHPL_DACL_MASK BIT(0)
|
||||
#define M98090_MIXHPL_DACL_SHIFT 0
|
||||
#define M98090_MIXHPL_DACL_WIDTH 1
|
||||
#define M98090_MIXHPL_MASK (63 << 0)
|
||||
#define M98090_MIXHPL_SHIFT 0
|
||||
#define M98090_MIXHPL_WIDTH 6
|
||||
|
||||
/*
|
||||
* M98090_REG_RIGHT_HP_MIXER 0x2A
|
||||
*/
|
||||
#define M98090_MIXHPR_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXHPR_MIC2_SHIFT 5
|
||||
#define M98090_MIXHPR_MIC2_WIDTH 1
|
||||
#define M98090_MIXHPR_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXHPR_MIC1_SHIFT 4
|
||||
#define M98090_MIXHPR_MIC1_WIDTH 1
|
||||
#define M98090_MIXHPR_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXHPR_LINEB_SHIFT 3
|
||||
#define M98090_MIXHPR_LINEB_WIDTH 1
|
||||
#define M98090_MIXHPR_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXHPR_LINEA_SHIFT 2
|
||||
#define M98090_MIXHPR_LINEA_WIDTH 1
|
||||
#define M98090_MIXHPR_DACR_MASK BIT(1)
|
||||
#define M98090_MIXHPR_DACR_SHIFT 1
|
||||
#define M98090_MIXHPR_DACR_WIDTH 1
|
||||
#define M98090_MIXHPR_DACL_MASK BIT(0)
|
||||
#define M98090_MIXHPR_DACL_SHIFT 0
|
||||
#define M98090_MIXHPR_DACL_WIDTH 1
|
||||
#define M98090_MIXHPR_MASK (63 << 0)
|
||||
#define M98090_MIXHPR_SHIFT 0
|
||||
#define M98090_MIXHPR_WIDTH 6
|
||||
|
||||
/*
|
||||
* M98090_REG_LEFT_HP_VOLUME 0x2C
|
||||
*/
|
||||
#define M98090_HPLM_MASK BIT(7)
|
||||
#define M98090_HPLM_SHIFT 7
|
||||
#define M98090_HPLM_WIDTH 1
|
||||
#define M98090_HPVOLL_MASK (31 << 0)
|
||||
#define M98090_HPVOLL_SHIFT 0
|
||||
#define M98090_HPVOLL_WIDTH 5
|
||||
#define M98090_HPVOLL_NUM BIT(M98090_HPVOLL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_RIGHT_HP_VOLUME 0x2D
|
||||
*/
|
||||
#define M98090_HPRM_MASK BIT(7)
|
||||
#define M98090_HPRM_SHIFT 7
|
||||
#define M98090_HPRM_WIDTH 1
|
||||
#define M98090_HPVOLR_MASK (31 << 0)
|
||||
#define M98090_HPVOLR_SHIFT 0
|
||||
#define M98090_HPVOLR_WIDTH 5
|
||||
#define M98090_HPVOLR_NUM BIT(M98090_HPVOLR_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_LEFT_SPK_MIXER 0x2E
|
||||
*/
|
||||
#define M98090_MIXSPL_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXSPL_MIC2_SHIFT 5
|
||||
#define M98090_MIXSPL_MIC2_WIDTH 1
|
||||
#define M98090_MIXSPL_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXSPL_MIC1_SHIFT 4
|
||||
#define M98090_MIXSPL_MIC1_WIDTH 1
|
||||
#define M98090_MIXSPL_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXSPL_LINEB_SHIFT 3
|
||||
#define M98090_MIXSPL_LINEB_WIDTH 1
|
||||
#define M98090_MIXSPL_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXSPL_LINEA_SHIFT 2
|
||||
#define M98090_MIXSPL_LINEA_WIDTH 1
|
||||
#define M98090_MIXSPL_DACR_MASK BIT(1)
|
||||
#define M98090_MIXSPL_DACR_SHIFT 1
|
||||
#define M98090_MIXSPL_DACR_WIDTH 1
|
||||
#define M98090_MIXSPL_DACL_MASK BIT(0)
|
||||
#define M98090_MIXSPL_DACL_SHIFT 0
|
||||
#define M98090_MIXSPL_DACL_WIDTH 1
|
||||
#define M98090_MIXSPL_MASK (63 << 0)
|
||||
#define M98090_MIXSPL_SHIFT 0
|
||||
#define M98090_MIXSPL_WIDTH 6
|
||||
#define M98090_MIXSPR_DACR_MASK BIT(1)
|
||||
#define M98090_MIXSPR_DACR_SHIFT 1
|
||||
#define M98090_MIXSPR_DACR_WIDTH 1
|
||||
|
||||
/*
|
||||
* M98090_REG_RIGHT_SPK_MIXER 0x2F
|
||||
*/
|
||||
#define M98090_SPK_SLAVE_MASK BIT(6)
|
||||
#define M98090_SPK_SLAVE_SHIFT 6
|
||||
#define M98090_SPK_SLAVE_WIDTH 1
|
||||
#define M98090_MIXSPR_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXSPR_MIC2_SHIFT 5
|
||||
#define M98090_MIXSPR_MIC2_WIDTH 1
|
||||
#define M98090_MIXSPR_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXSPR_MIC1_SHIFT 4
|
||||
#define M98090_MIXSPR_MIC1_WIDTH 1
|
||||
#define M98090_MIXSPR_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXSPR_LINEB_SHIFT 3
|
||||
#define M98090_MIXSPR_LINEB_WIDTH 1
|
||||
#define M98090_MIXSPR_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXSPR_LINEA_SHIFT 2
|
||||
#define M98090_MIXSPR_LINEA_WIDTH 1
|
||||
#define M98090_MIXSPR_DACR_MASK BIT(1)
|
||||
#define M98090_MIXSPR_DACR_SHIFT 1
|
||||
#define M98090_MIXSPR_DACR_WIDTH 1
|
||||
#define M98090_MIXSPR_DACL_MASK BIT(0)
|
||||
#define M98090_MIXSPR_DACL_SHIFT 0
|
||||
#define M98090_MIXSPR_DACL_WIDTH 1
|
||||
#define M98090_MIXSPR_MASK (63 << 0)
|
||||
#define M98090_MIXSPR_SHIFT 0
|
||||
#define M98090_MIXSPR_WIDTH 6
|
||||
|
||||
/*
|
||||
* M98090_REG_LEFT_SPK_VOLUME 0x31
|
||||
*/
|
||||
#define M98090_SPLM_MASK BIT(7)
|
||||
#define M98090_SPLM_SHIFT 7
|
||||
#define M98090_SPLM_WIDTH 1
|
||||
#define M98090_SPVOLL_MASK (63 << 0)
|
||||
#define M98090_SPVOLL_SHIFT 0
|
||||
#define M98090_SPVOLL_WIDTH 6
|
||||
#define M98090_SPVOLL_NUM 40
|
||||
|
||||
/*
|
||||
* M98090_REG_RIGHT_SPK_VOLUME 0x32
|
||||
*/
|
||||
#define M98090_SPRM_MASK BIT(7)
|
||||
#define M98090_SPRM_SHIFT 7
|
||||
#define M98090_SPRM_WIDTH 1
|
||||
#define M98090_SPVOLR_MASK (63 << 0)
|
||||
#define M98090_SPVOLR_SHIFT 0
|
||||
#define M98090_SPVOLR_WIDTH 6
|
||||
#define M98090_SPVOLR_NUM 40
|
||||
|
||||
/*
|
||||
* M98090_REG_RCV_LOUTL_MIXER 0x37
|
||||
*/
|
||||
#define M98090_MIXRCVL_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXRCVL_MIC2_SHIFT 5
|
||||
#define M98090_MIXRCVL_MIC2_WIDTH 1
|
||||
#define M98090_MIXRCVL_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXRCVL_MIC1_SHIFT 4
|
||||
#define M98090_MIXRCVL_MIC1_WIDTH 1
|
||||
#define M98090_MIXRCVL_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXRCVL_LINEB_SHIFT 3
|
||||
#define M98090_MIXRCVL_LINEB_WIDTH 1
|
||||
#define M98090_MIXRCVL_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXRCVL_LINEA_SHIFT 2
|
||||
#define M98090_MIXRCVL_LINEA_WIDTH 1
|
||||
#define M98090_MIXRCVL_DACR_MASK BIT(1)
|
||||
#define M98090_MIXRCVL_DACR_SHIFT 1
|
||||
#define M98090_MIXRCVL_DACR_WIDTH 1
|
||||
#define M98090_MIXRCVL_DACL_MASK BIT(0)
|
||||
#define M98090_MIXRCVL_DACL_SHIFT 0
|
||||
#define M98090_MIXRCVL_DACL_WIDTH 1
|
||||
#define M98090_MIXRCVL_MASK (63 << 0)
|
||||
#define M98090_MIXRCVL_SHIFT 0
|
||||
#define M98090_MIXRCVL_WIDTH 6
|
||||
|
||||
/*
|
||||
* M98090_REG_RCV_LOUTL_CONTROL 0x38
|
||||
*/
|
||||
#define M98090_MIXRCVLG_MASK (3 << 0)
|
||||
#define M98090_MIXRCVLG_SHIFT 0
|
||||
#define M98090_MIXRCVLG_WIDTH 2
|
||||
#define M98090_MIXRCVLG_NUM BIT(M98090_MIXRCVLG_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_RCV_LOUTL_VOLUME 0x39
|
||||
*/
|
||||
#define M98090_RCVLM_MASK BIT(7)
|
||||
#define M98090_RCVLM_SHIFT 7
|
||||
#define M98090_RCVLM_WIDTH 1
|
||||
#define M98090_RCVLVOL_MASK (31 << 0)
|
||||
#define M98090_RCVLVOL_SHIFT 0
|
||||
#define M98090_RCVLVOL_WIDTH 5
|
||||
#define M98090_RCVLVOL_NUM BIT(M98090_RCVLVOL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_LOUTR_MIXER 0x3A
|
||||
*/
|
||||
#define M98090_LINMOD_MASK BIT(7)
|
||||
#define M98090_LINMOD_SHIFT 7
|
||||
#define M98090_LINMOD_WIDTH 1
|
||||
#define M98090_MIXRCVR_MIC2_MASK BIT(5)
|
||||
#define M98090_MIXRCVR_MIC2_SHIFT 5
|
||||
#define M98090_MIXRCVR_MIC2_WIDTH 1
|
||||
#define M98090_MIXRCVR_MIC1_MASK BIT(4)
|
||||
#define M98090_MIXRCVR_MIC1_SHIFT 4
|
||||
#define M98090_MIXRCVR_MIC1_WIDTH 1
|
||||
#define M98090_MIXRCVR_LINEB_MASK BIT(3)
|
||||
#define M98090_MIXRCVR_LINEB_SHIFT 3
|
||||
#define M98090_MIXRCVR_LINEB_WIDTH 1
|
||||
#define M98090_MIXRCVR_LINEA_MASK BIT(2)
|
||||
#define M98090_MIXRCVR_LINEA_SHIFT 2
|
||||
#define M98090_MIXRCVR_LINEA_WIDTH 1
|
||||
#define M98090_MIXRCVR_DACR_MASK BIT(1)
|
||||
#define M98090_MIXRCVR_DACR_SHIFT 1
|
||||
#define M98090_MIXRCVR_DACR_WIDTH 1
|
||||
#define M98090_MIXRCVR_DACL_MASK BIT(0)
|
||||
#define M98090_MIXRCVR_DACL_SHIFT 0
|
||||
#define M98090_MIXRCVR_DACL_WIDTH 1
|
||||
#define M98090_MIXRCVR_MASK (63 << 0)
|
||||
#define M98090_MIXRCVR_SHIFT 0
|
||||
#define M98090_MIXRCVR_WIDTH 6
|
||||
|
||||
/*
|
||||
* M98090_REG_LOUTR_VOLUME 0x3C
|
||||
*/
|
||||
#define M98090_RCVRM_MASK BIT(7)
|
||||
#define M98090_RCVRM_SHIFT 7
|
||||
#define M98090_RCVRM_WIDTH 1
|
||||
#define M98090_RCVRVOL_MASK (31 << 0)
|
||||
#define M98090_RCVRVOL_SHIFT 0
|
||||
#define M98090_RCVRVOL_WIDTH 5
|
||||
#define M98090_RCVRVOL_NUM BIT(M98090_RCVRVOL_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_JACK_DETECT 0x3D
|
||||
*/
|
||||
#define M98090_JDETEN_MASK BIT(7)
|
||||
#define M98090_JDETEN_SHIFT 7
|
||||
#define M98090_JDETEN_WIDTH 1
|
||||
#define M98090_JDWK_MASK BIT(6)
|
||||
#define M98090_JDWK_SHIFT 6
|
||||
#define M98090_JDWK_WIDTH 1
|
||||
#define M98090_JDEB_MASK (3 << 0)
|
||||
#define M98090_JDEB_SHIFT 0
|
||||
#define M98090_JDEB_WIDTH 2
|
||||
#define M98090_JDEB_25MS (0 << 0)
|
||||
#define M98090_JDEB_50MS BIT(0)
|
||||
#define M98090_JDEB_100MS (2 << 0)
|
||||
#define M98090_JDEB_200MS (3 << 0)
|
||||
|
||||
/*
|
||||
* M98090_REG_INPUT_ENABLE 0x3E
|
||||
*/
|
||||
#define M98090_MBEN_MASK BIT(4)
|
||||
#define M98090_MBEN_SHIFT 4
|
||||
#define M98090_MBEN_WIDTH 1
|
||||
#define M98090_LINEAEN_MASK BIT(3)
|
||||
#define M98090_LINEAEN_SHIFT 3
|
||||
#define M98090_LINEAEN_WIDTH 1
|
||||
#define M98090_LINEBEN_MASK BIT(2)
|
||||
#define M98090_LINEBEN_SHIFT 2
|
||||
#define M98090_LINEBEN_WIDTH 1
|
||||
#define M98090_ADREN_MASK BIT(1)
|
||||
#define M98090_ADREN_SHIFT 1
|
||||
#define M98090_ADREN_WIDTH 1
|
||||
#define M98090_ADLEN_MASK BIT(0)
|
||||
#define M98090_ADLEN_SHIFT 0
|
||||
#define M98090_ADLEN_WIDTH 1
|
||||
|
||||
/*
|
||||
* M98090_REG_OUTPUT_ENABLE 0x3F
|
||||
*/
|
||||
#define M98090_HPREN_MASK BIT(7)
|
||||
#define M98090_HPREN_SHIFT 7
|
||||
#define M98090_HPREN_WIDTH 1
|
||||
#define M98090_HPLEN_MASK BIT(6)
|
||||
#define M98090_HPLEN_SHIFT 6
|
||||
#define M98090_HPLEN_WIDTH 1
|
||||
#define M98090_SPREN_MASK BIT(5)
|
||||
#define M98090_SPREN_SHIFT 5
|
||||
#define M98090_SPREN_WIDTH 1
|
||||
#define M98090_SPLEN_MASK BIT(4)
|
||||
#define M98090_SPLEN_SHIFT 4
|
||||
#define M98090_SPLEN_WIDTH 1
|
||||
#define M98090_RCVLEN_MASK BIT(3)
|
||||
#define M98090_RCVLEN_SHIFT 3
|
||||
#define M98090_RCVLEN_WIDTH 1
|
||||
#define M98090_RCVREN_MASK BIT(2)
|
||||
#define M98090_RCVREN_SHIFT 2
|
||||
#define M98090_RCVREN_WIDTH 1
|
||||
#define M98090_DAREN_MASK BIT(1)
|
||||
#define M98090_DAREN_SHIFT 1
|
||||
#define M98090_DAREN_WIDTH 1
|
||||
#define M98090_DALEN_MASK BIT(0)
|
||||
#define M98090_DALEN_SHIFT 0
|
||||
#define M98090_DALEN_WIDTH 1
|
||||
|
||||
/*
|
||||
* M98090_REG_LEVEL_CONTROL 0x40
|
||||
*/
|
||||
#define M98090_ZDENN_MASK BIT(2)
|
||||
#define M98090_ZDENN_SHIFT 2
|
||||
#define M98090_ZDENN_WIDTH 1
|
||||
#define M98090_ZDENN_NUM BIT(M98090_ZDENN_WIDTH)
|
||||
#define M98090_VS2ENN_MASK BIT(1)
|
||||
#define M98090_VS2ENN_SHIFT 1
|
||||
#define M98090_VS2ENN_WIDTH 1
|
||||
#define M98090_VS2ENN_NUM BIT(M98090_VS2ENN_WIDTH)
|
||||
#define M98090_VSENN_MASK BIT(0)
|
||||
#define M98090_VSENN_SHIFT 0
|
||||
#define M98090_VSENN_WIDTH 1
|
||||
#define M98090_VSENN_NUM BIT(M98090_VSENN_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_BIAS_CONTROL 0x42
|
||||
*/
|
||||
#define M98090_VCM_MODE_MASK BIT(0)
|
||||
#define M98090_VCM_MODE_SHIFT 0
|
||||
#define M98090_VCM_MODE_WIDTH 1
|
||||
#define M98090_VCM_MODE_NUM BIT(M98090_VCM_MODE_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_DAC_CONTROL 0x43
|
||||
*/
|
||||
#define M98090_PERFMODE_MASK BIT(1)
|
||||
#define M98090_PERFMODE_SHIFT 1
|
||||
#define M98090_PERFMODE_WIDTH 1
|
||||
#define M98090_PERFMODE_NUM BIT(M98090_PERFMODE_WIDTH)
|
||||
#define M98090_DACHP_MASK BIT(0)
|
||||
#define M98090_DACHP_SHIFT 0
|
||||
#define M98090_DACHP_WIDTH 1
|
||||
#define M98090_DACHP_NUM BIT(M98090_DACHP_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_ADC_CONTROL 0x44
|
||||
*/
|
||||
#define M98090_OSR128_MASK BIT(2)
|
||||
#define M98090_OSR128_SHIFT 2
|
||||
#define M98090_OSR128_WIDTH 1
|
||||
#define M98090_ADCDITHER_MASK BIT(1)
|
||||
#define M98090_ADCDITHER_SHIFT 1
|
||||
#define M98090_ADCDITHER_WIDTH 1
|
||||
#define M98090_ADCDITHER_NUM BIT(M98090_ADCDITHER_WIDTH)
|
||||
#define M98090_ADCHP_MASK BIT(0)
|
||||
#define M98090_ADCHP_SHIFT 0
|
||||
#define M98090_ADCHP_WIDTH 1
|
||||
#define M98090_ADCHP_NUM BIT(M98090_ADCHP_WIDTH)
|
||||
|
||||
/*
|
||||
* M98090_REG_DEVICE_SHUTDOWN 0x45
|
||||
*/
|
||||
#define M98090_SHDNN_MASK BIT(7)
|
||||
#define M98090_SHDNN_SHIFT 7
|
||||
#define M98090_SHDNN_WIDTH 1
|
||||
|
||||
/*
|
||||
* M98090_REG_REVISION_ID 0xFF
|
||||
*/
|
||||
#define M98090_REVID_MASK (255 << 0)
|
||||
#define M98090_REVID_SHIFT 0
|
||||
#define M98090_REVID_WIDTH 8
|
||||
#define M98090_REVID_NUM BIT(M98090_REVID_WIDTH)
|
||||
|
||||
/* function prototype */
|
||||
|
||||
/*
|
||||
* initialise max98090 sound codec device for the given configuration
|
||||
*
|
||||
* @param blob FDT node for codec values
|
||||
* @param sampling_rate Sampling rate (Hz)
|
||||
* @param mclk_freq MCLK Frequency (Hz)
|
||||
* @param bits_per_sample bits per Sample (must be 16 or 24)
|
||||
*
|
||||
* @returns -1 for error and 0 Success.
|
||||
*/
|
||||
int max98090_init(const void *blob, int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample);
|
||||
int max98090_set_sysclk(struct maxim_priv *max98090, uint freq);
|
||||
int max98090_hw_params(struct maxim_priv *max98090, uint rate,
|
||||
uint bits_per_sample);
|
||||
int max98090_device_init(struct maxim_priv *max98090);
|
||||
int max98090_set_fmt(struct maxim_priv *max98090, int fmt);
|
||||
#endif
|
|
@ -1,112 +1,31 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* max98095.c -- MAX98095 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*
|
||||
* Modified for uboot by R. Chandrasekar (rcsekar@samsung.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
* Modified for U-Boot by R. Chandrasekar (rcsekar@samsung.com)
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <common.h>
|
||||
#include <audio_codec.h>
|
||||
#include <dm.h>
|
||||
#include <div64.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <sound.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include "i2s.h"
|
||||
#include "max98095.h"
|
||||
|
||||
enum max98095_type {
|
||||
MAX98095,
|
||||
};
|
||||
|
||||
struct max98095_priv {
|
||||
enum max98095_type devtype;
|
||||
unsigned int sysclk;
|
||||
unsigned int rate;
|
||||
unsigned int fmt;
|
||||
};
|
||||
|
||||
static struct sound_codec_info g_codec_info;
|
||||
struct max98095_priv g_max98095_info;
|
||||
unsigned int g_max98095_i2c_dev_addr;
|
||||
|
||||
/* Index 0 is reserved. */
|
||||
int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
|
||||
88200, 96000};
|
||||
|
||||
/*
|
||||
* Writes value to a device register through i2c
|
||||
*
|
||||
* @param reg reg number to be write
|
||||
* @param data data to be writen to the above registor
|
||||
*
|
||||
* @return int value 1 for change, 0 for no change or negative error code.
|
||||
*/
|
||||
static int max98095_i2c_write(unsigned int reg, unsigned char data)
|
||||
{
|
||||
debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
|
||||
__func__, reg, data);
|
||||
return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a value from a device register through i2c
|
||||
*
|
||||
* @param reg reg number to be read
|
||||
* @param data address of read data to be stored
|
||||
*
|
||||
* @return int value 0 for success, -1 in case of error.
|
||||
*/
|
||||
static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1);
|
||||
if (ret != 0) {
|
||||
debug("%s: Error while reading register %#04x\n",
|
||||
__func__, reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* update device register bits through i2c
|
||||
*
|
||||
* @param reg codec register
|
||||
* @param mask register mask
|
||||
* @param value new value
|
||||
*
|
||||
* @return int value 0 for success, non-zero error code.
|
||||
*/
|
||||
static int max98095_update_bits(unsigned int reg, unsigned char mask,
|
||||
unsigned char value)
|
||||
{
|
||||
int change, ret = 0;
|
||||
unsigned char old, new;
|
||||
|
||||
if (max98095_i2c_read(reg, &old) != 0)
|
||||
return -1;
|
||||
new = (old & ~mask) | (value & mask);
|
||||
change = (old != new) ? 1 : 0;
|
||||
if (change)
|
||||
ret = max98095_i2c_write(reg, new);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
/*
|
||||
* codec mclk clock divider coefficients based on sampling rate
|
||||
*
|
||||
|
@ -127,19 +46,19 @@ static int rate_value(int rate, u8 *value)
|
|||
}
|
||||
*value = 1;
|
||||
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets hw params for max98095
|
||||
*
|
||||
* @param max98095 max98095 information pointer
|
||||
* @param priv max98095 information pointer
|
||||
* @param rate Sampling rate
|
||||
* @param bits_per_sample Bits per sample
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int max98095_hw_params(struct max98095_priv *max98095,
|
||||
static int max98095_hw_params(struct maxim_priv *priv,
|
||||
enum en_max_audio_interface aif_id,
|
||||
unsigned int rate, unsigned int bits_per_sample)
|
||||
{
|
||||
|
@ -161,40 +80,39 @@ static int max98095_hw_params(struct max98095_priv *max98095,
|
|||
|
||||
switch (bits_per_sample) {
|
||||
case 16:
|
||||
error = max98095_update_bits(M98095_DAI_FORMAT,
|
||||
M98095_DAI_WS, 0);
|
||||
error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS, 0);
|
||||
break;
|
||||
case 24:
|
||||
error = max98095_update_bits(M98095_DAI_FORMAT,
|
||||
M98095_DAI_WS, M98095_DAI_WS);
|
||||
error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS,
|
||||
M98095_DAI_WS);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Illegal bits per sample %d.\n",
|
||||
__func__, bits_per_sample);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (rate_value(rate, ®val)) {
|
||||
debug("%s: Failed to set sample rate to %d.\n",
|
||||
__func__, rate);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
max98095->rate = rate;
|
||||
priv->rate = rate;
|
||||
|
||||
error |= max98095_update_bits(M98095_DAI_CLKMODE,
|
||||
M98095_CLKMODE_MASK, regval);
|
||||
error |= maxim_bic_or(priv, M98095_DAI_CLKMODE, M98095_CLKMODE_MASK,
|
||||
regval);
|
||||
|
||||
/* Update sample rate mode */
|
||||
if (rate < 50000)
|
||||
error |= max98095_update_bits(M98095_DAI_FILTERS,
|
||||
M98095_DAI_DHF, 0);
|
||||
error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
|
||||
M98095_DAI_DHF, 0);
|
||||
else
|
||||
error |= max98095_update_bits(M98095_DAI_FILTERS,
|
||||
M98095_DAI_DHF, M98095_DAI_DHF);
|
||||
error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
|
||||
M98095_DAI_DHF, M98095_DAI_DHF);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting hardware params.\n", __func__);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -203,18 +121,17 @@ static int max98095_hw_params(struct max98095_priv *max98095,
|
|||
/*
|
||||
* Configures Audio interface system clock for the given frequency
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
* @param priv max98095 information
|
||||
* @param freq Sampling frequency in Hz
|
||||
*
|
||||
* @return -1 for error and 0 success.
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int max98095_set_sysclk(struct max98095_priv *max98095,
|
||||
unsigned int freq)
|
||||
static int max98095_set_sysclk(struct maxim_priv *priv, unsigned int freq)
|
||||
{
|
||||
int error = 0;
|
||||
|
||||
/* Requested clock frequency is already setup */
|
||||
if (freq == max98095->sysclk)
|
||||
if (freq == priv->sysclk)
|
||||
return 0;
|
||||
|
||||
/* Setup clocks for slave mode, and using the PLL
|
||||
|
@ -223,35 +140,35 @@ static int max98095_set_sysclk(struct max98095_priv *max98095,
|
|||
* 0x03 (when master clk is 40MHz to 60MHz)..
|
||||
*/
|
||||
if ((freq >= 10000000) && (freq < 20000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
|
||||
error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x10);
|
||||
} else if ((freq >= 20000000) && (freq < 40000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
|
||||
error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x20);
|
||||
} else if ((freq >= 40000000) && (freq < 60000000)) {
|
||||
error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
|
||||
error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x30);
|
||||
} else {
|
||||
debug("%s: Invalid master clock frequency\n", __func__);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
debug("%s: Clock at %uHz\n", __func__, freq);
|
||||
|
||||
if (error < 0)
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
max98095->sysclk = freq;
|
||||
priv->sysclk = freq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets Max98095 I2S format
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
* @param priv max98095 information
|
||||
* @param fmt i2S format - supports a subset of the options defined
|
||||
* in i2s.h.
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
||||
static int max98095_set_fmt(struct maxim_priv *priv, int fmt,
|
||||
enum en_max_audio_interface aif_id)
|
||||
{
|
||||
u8 regval = 0;
|
||||
|
@ -261,10 +178,10 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
unsigned short M98095_DAI_FORMAT;
|
||||
unsigned short M98095_DAI_CLOCK;
|
||||
|
||||
if (fmt == max98095->fmt)
|
||||
if (fmt == priv->fmt)
|
||||
return 0;
|
||||
|
||||
max98095->fmt = fmt;
|
||||
priv->fmt = fmt;
|
||||
|
||||
if (aif_id == AIF1) {
|
||||
M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI;
|
||||
|
@ -281,10 +198,8 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
case SND_SOC_DAIFMT_CBS_CFS:
|
||||
/* Slave mode PLL */
|
||||
error |= max98095_i2c_write(M98095_DAI_CLKCFG_HI,
|
||||
0x80);
|
||||
error |= max98095_i2c_write(M98095_DAI_CLKCFG_LO,
|
||||
0x00);
|
||||
error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_HI, 0x80);
|
||||
error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_LO, 0x00);
|
||||
break;
|
||||
case SND_SOC_DAIFMT_CBM_CFM:
|
||||
/* Set to master mode */
|
||||
|
@ -294,7 +209,7 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
case SND_SOC_DAIFMT_CBM_CFS:
|
||||
default:
|
||||
debug("%s: Clock mode unsupported\n", __func__);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
|
||||
|
@ -305,7 +220,7 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
break;
|
||||
default:
|
||||
debug("%s: Unrecognized format.\n", __func__);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
|
||||
|
@ -322,20 +237,18 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
break;
|
||||
default:
|
||||
debug("%s: Unrecognized inversion settings.\n", __func__);
|
||||
return -1;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
error |= max98095_update_bits(M98095_DAI_FORMAT,
|
||||
M98095_DAI_MAS | M98095_DAI_DLY |
|
||||
M98095_DAI_BCI | M98095_DAI_WCI,
|
||||
regval);
|
||||
error |= maxim_bic_or(priv, M98095_DAI_FORMAT,
|
||||
M98095_DAI_MAS | M98095_DAI_DLY |
|
||||
M98095_DAI_BCI | M98095_DAI_WCI, regval);
|
||||
|
||||
error |= max98095_i2c_write(M98095_DAI_CLOCK,
|
||||
M98095_DAI_BSEL64);
|
||||
error |= maxim_i2c_write(priv, M98095_DAI_CLOCK, M98095_DAI_BSEL64);
|
||||
|
||||
if (error < 0) {
|
||||
debug("%s: Error setting i2s format.\n", __func__);
|
||||
return -1;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -344,9 +257,10 @@ static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
|
|||
/*
|
||||
* resets the audio codec
|
||||
*
|
||||
* @return -1 for error and 0 success.
|
||||
* @param priv Private data for driver
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int max98095_reset(void)
|
||||
static int max98095_reset(struct maxim_priv *priv)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
|
@ -354,13 +268,13 @@ static int max98095_reset(void)
|
|||
* Gracefully reset the DSP core and the codec hardware in a proper
|
||||
* sequence.
|
||||
*/
|
||||
ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
|
||||
ret = maxim_i2c_write(priv, M98095_00F_HOST_CFG, 0);
|
||||
if (ret != 0) {
|
||||
debug("%s: Failed to reset DSP: %d\n", __func__, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_i2c_write(M98095_097_PWR_SYS, 0);
|
||||
ret = maxim_i2c_write(priv, M98095_097_PWR_SYS, 0);
|
||||
if (ret != 0) {
|
||||
debug("%s: Failed to reset codec: %d\n", __func__, ret);
|
||||
return ret;
|
||||
|
@ -371,7 +285,7 @@ static int max98095_reset(void)
|
|||
* reset hardware control register.
|
||||
*/
|
||||
for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
|
||||
ret = max98095_i2c_write(i, 0);
|
||||
ret = maxim_i2c_write(priv, i, 0);
|
||||
if (ret < 0) {
|
||||
debug("%s: Failed to reset: %d\n", __func__, ret);
|
||||
return ret;
|
||||
|
@ -384,132 +298,128 @@ static int max98095_reset(void)
|
|||
/*
|
||||
* Intialise max98095 codec device
|
||||
*
|
||||
* @param max98095 max98095 information
|
||||
*
|
||||
* @returns -1 for error and 0 Success.
|
||||
* @param priv max98095 information
|
||||
* @return 0 for success or negative error code.
|
||||
*/
|
||||
static int max98095_device_init(struct max98095_priv *max98095,
|
||||
enum en_max_audio_interface aif_id)
|
||||
static int max98095_device_init(struct maxim_priv *priv)
|
||||
{
|
||||
unsigned char id;
|
||||
int error = 0;
|
||||
int ret;
|
||||
|
||||
/* Enable codec clock */
|
||||
set_xclkout();
|
||||
|
||||
/* reset the codec, the DSP core, and disable all interrupts */
|
||||
error = max98095_reset();
|
||||
if (error != 0) {
|
||||
ret = max98095_reset(priv);
|
||||
if (ret != 0) {
|
||||
debug("Reset\n");
|
||||
return error;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* initialize private data */
|
||||
max98095->sysclk = -1U;
|
||||
max98095->rate = -1U;
|
||||
max98095->fmt = -1U;
|
||||
priv->sysclk = -1U;
|
||||
priv->rate = -1U;
|
||||
priv->fmt = -1U;
|
||||
|
||||
error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
|
||||
if (error < 0) {
|
||||
ret = maxim_i2c_read(priv, M98095_0FF_REV_ID, &id);
|
||||
if (ret < 0) {
|
||||
debug("%s: Failure reading hardware revision: %d\n",
|
||||
__func__, id);
|
||||
goto err_access;
|
||||
return ret;
|
||||
}
|
||||
debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
|
||||
|
||||
error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98095_setup_interface(struct maxim_priv *priv,
|
||||
enum en_max_audio_interface aif_id)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = maxim_i2c_write(priv, M98095_097_PWR_SYS, M98095_PWRSV);
|
||||
|
||||
/*
|
||||
* initialize registers to hardware default configuring audio
|
||||
* interface2 to DAC
|
||||
*/
|
||||
if (aif_id == AIF1)
|
||||
error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
|
||||
error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
|
||||
M98095_DAI1L_TO_DACL |
|
||||
M98095_DAI1R_TO_DACR);
|
||||
else
|
||||
error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
|
||||
error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
|
||||
M98095_DAI2M_TO_DACL |
|
||||
M98095_DAI2M_TO_DACR);
|
||||
|
||||
error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
|
||||
error |= maxim_i2c_write(priv, M98095_092_PWR_EN_OUT,
|
||||
M98095_SPK_SPREADSPECTRUM);
|
||||
error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
|
||||
error |= maxim_i2c_write(priv, M98095_04E_CFG_HP, M98095_HPNORMAL);
|
||||
if (aif_id == AIF1)
|
||||
error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
|
||||
error |= maxim_i2c_write(priv, M98095_02C_DAI1_IOCFG,
|
||||
M98095_S1NORMAL | M98095_SDATA);
|
||||
else
|
||||
error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
|
||||
error |= maxim_i2c_write(priv, M98095_036_DAI2_IOCFG,
|
||||
M98095_S2NORMAL | M98095_SDATA);
|
||||
|
||||
/* take the codec out of the shut down */
|
||||
error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN,
|
||||
M98095_SHDNRUN);
|
||||
/* route DACL and DACR output to HO and Spekers */
|
||||
error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */
|
||||
error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */
|
||||
error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01); /* DACL */
|
||||
error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */
|
||||
error |= maxim_bic_or(priv, M98095_097_PWR_SYS, M98095_SHDNRUN,
|
||||
M98095_SHDNRUN);
|
||||
/*
|
||||
* route DACL and DACR output to HO and Speakers
|
||||
* Ordering: DACL, DACR, DACL, DACR
|
||||
*/
|
||||
error |= maxim_i2c_write(priv, M98095_050_MIX_SPK_LEFT, 0x01);
|
||||
error |= maxim_i2c_write(priv, M98095_051_MIX_SPK_RIGHT, 0x01);
|
||||
error |= maxim_i2c_write(priv, M98095_04C_MIX_HP_LEFT, 0x01);
|
||||
error |= maxim_i2c_write(priv, M98095_04D_MIX_HP_RIGHT, 0x01);
|
||||
|
||||
/* power Enable */
|
||||
error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
|
||||
error |= maxim_i2c_write(priv, M98095_091_PWR_EN_OUT, 0xF3);
|
||||
|
||||
/* set Volume */
|
||||
error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15);
|
||||
error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15);
|
||||
error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16);
|
||||
error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16);
|
||||
error |= maxim_i2c_write(priv, M98095_064_LVL_HP_L, 15);
|
||||
error |= maxim_i2c_write(priv, M98095_065_LVL_HP_R, 15);
|
||||
error |= maxim_i2c_write(priv, M98095_067_LVL_SPK_L, 16);
|
||||
error |= maxim_i2c_write(priv, M98095_068_LVL_SPK_R, 16);
|
||||
|
||||
/* Enable DAIs */
|
||||
error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
|
||||
error |= maxim_i2c_write(priv, M98095_093_BIAS_CTRL, 0x30);
|
||||
if (aif_id == AIF1)
|
||||
error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01);
|
||||
error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x01);
|
||||
else
|
||||
error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
|
||||
error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x07);
|
||||
|
||||
err_access:
|
||||
if (error < 0)
|
||||
return -1;
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int max98095_do_init(struct sound_codec_info *pcodec_info,
|
||||
static int max98095_do_init(struct maxim_priv *priv,
|
||||
enum en_max_audio_interface aif_id,
|
||||
int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Enable codec clock */
|
||||
set_xclkout();
|
||||
|
||||
/* shift the device address by 1 for 7 bit addressing */
|
||||
g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
|
||||
|
||||
if (pcodec_info->codec_type == CODEC_MAX_98095) {
|
||||
g_max98095_info.devtype = MAX98095;
|
||||
} else {
|
||||
debug("%s: Codec id [%d] not defined\n", __func__,
|
||||
pcodec_info->codec_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = max98095_device_init(&g_max98095_info, aif_id);
|
||||
ret = max98095_setup_interface(priv, aif_id);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98095 codec chip init failed\n", __func__);
|
||||
debug("%s: max98095 setup interface failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
|
||||
ret = max98095_set_sysclk(priv, mclk_freq);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98095 codec set sys clock failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = max98095_hw_params(&g_max98095_info, aif_id, sampling_rate,
|
||||
ret = max98095_hw_params(priv, aif_id, sampling_rate,
|
||||
bits_per_sample);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = max98095_set_fmt(&g_max98095_info,
|
||||
SND_SOC_DAIFMT_I2S |
|
||||
ret = max98095_set_fmt(priv, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS,
|
||||
aif_id);
|
||||
|
@ -518,76 +428,45 @@ static int max98095_do_init(struct sound_codec_info *pcodec_info,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
|
||||
const void *blob)
|
||||
static int max98095_set_params(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample,
|
||||
uint channels)
|
||||
{
|
||||
int error = 0;
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
enum fdt_compat_id compat;
|
||||
int node;
|
||||
int parent;
|
||||
struct maxim_priv *priv = dev_get_priv(dev);
|
||||
|
||||
/* Get the node from FDT for codec */
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC);
|
||||
if (node <= 0) {
|
||||
debug("EXYNOS_SOUND: No node for codec in device tree\n");
|
||||
debug("node = %d\n", node);
|
||||
return -1;
|
||||
}
|
||||
return max98095_do_init(priv, interface, rate, mclk_freq,
|
||||
bits_per_sample);
|
||||
}
|
||||
|
||||
parent = fdt_parent_offset(blob, node);
|
||||
if (parent < 0) {
|
||||
debug("%s: Cannot find node parent\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
static int max98095_probe(struct udevice *dev)
|
||||
{
|
||||
struct maxim_priv *priv = dev_get_priv(dev);
|
||||
int ret;
|
||||
|
||||
compat = fdtdec_lookup(blob, parent);
|
||||
switch (compat) {
|
||||
case COMPAT_SAMSUNG_S3C2440_I2C:
|
||||
pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
|
||||
error |= pcodec_info->i2c_bus;
|
||||
debug("i2c bus = %d\n", pcodec_info->i2c_bus);
|
||||
pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
|
||||
"reg", 0);
|
||||
error |= pcodec_info->i2c_dev_addr;
|
||||
debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unknown compat id %d\n", __func__, compat);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
pcodec_info->i2c_bus = AUDIO_I2C_BUS;
|
||||
pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
|
||||
debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
|
||||
#endif
|
||||
pcodec_info->codec_type = CODEC_MAX_98095;
|
||||
if (error == -1) {
|
||||
debug("fail to get max98095 codec node properties\n");
|
||||
return -1;
|
||||
priv->dev = dev;
|
||||
ret = max98095_device_init(priv);
|
||||
if (ret < 0) {
|
||||
debug("%s: max98095 codec chip init failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* max98095 Device Initialisation */
|
||||
int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
|
||||
int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample)
|
||||
{
|
||||
int ret;
|
||||
int old_bus = i2c_get_bus_num();
|
||||
struct sound_codec_info *pcodec_info = &g_codec_info;
|
||||
static const struct audio_codec_ops max98095_ops = {
|
||||
.set_params = max98095_set_params,
|
||||
};
|
||||
|
||||
if (get_max98095_codec_values(pcodec_info, blob) < 0) {
|
||||
debug("FDT Codec values failed\n");
|
||||
return -1;
|
||||
}
|
||||
static const struct udevice_id max98095_ids[] = {
|
||||
{ .compatible = "maxim,max98095" },
|
||||
{ }
|
||||
};
|
||||
|
||||
i2c_set_bus_num(pcodec_info->i2c_bus);
|
||||
ret = max98095_do_init(pcodec_info, aif_id, sampling_rate, mclk_freq,
|
||||
bits_per_sample);
|
||||
i2c_set_bus_num(old_bus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
U_BOOT_DRIVER(max98095) = {
|
||||
.name = "max98095",
|
||||
.id = UCLASS_AUDIO_CODEC,
|
||||
.of_match = max98095_ids,
|
||||
.probe = max98095_probe,
|
||||
.ops = &max98095_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct maxim_priv),
|
||||
};
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* max98095.h -- MAX98095 ALSA SoC Audio driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#ifndef _MAX98095_H
|
||||
#define _MAX98095_H
|
||||
|
||||
#include "maxim_codec.h"
|
||||
|
||||
/* Available audio interface ports in wm8994 codec */
|
||||
enum en_max_audio_interface {
|
||||
AIF1 = 1,
|
||||
AIF1,
|
||||
AIF2,
|
||||
};
|
||||
|
||||
|
|
87
drivers/sound/maxim_codec.c
Normal file
87
drivers/sound/maxim_codec.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* maxim_codec.c -- MAXIM CODEC Common driver
|
||||
*
|
||||
* Copyright 2011 Maxim Integrated Products
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <div64.h>
|
||||
#include <i2c.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/power.h>
|
||||
#include "maxim_codec.h"
|
||||
|
||||
/*
|
||||
* Writes value to a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be write
|
||||
* @param data data to be writen to the above registor
|
||||
*
|
||||
* @return int value 1 for change, 0 for no change or negative error code.
|
||||
*/
|
||||
int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
|
||||
unsigned char data)
|
||||
{
|
||||
debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
|
||||
__func__, reg, data);
|
||||
return dm_i2c_write(priv->dev, reg, &data, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a value from a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be read
|
||||
* @param data address of read data to be stored
|
||||
*
|
||||
* @return int value 0 for success, -1 in case of error.
|
||||
*/
|
||||
unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
|
||||
unsigned char *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
return dm_i2c_read(priv->dev, reg, data, 1);
|
||||
if (ret != 0) {
|
||||
debug("%s: Error while reading register %#04x\n",
|
||||
__func__, reg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* update device register bits through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg codec register
|
||||
* @param mask register mask
|
||||
* @param value new value
|
||||
*
|
||||
* @return int value 0 for success, non-zero error code.
|
||||
*/
|
||||
int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
|
||||
unsigned char value)
|
||||
{
|
||||
int change, ret = 0;
|
||||
unsigned char old, new;
|
||||
|
||||
if (maxim_i2c_read(priv, reg, &old) != 0)
|
||||
return -1;
|
||||
new = (old & ~mask) | (value & mask);
|
||||
change = (old != new) ? 1 : 0;
|
||||
if (change)
|
||||
ret = maxim_i2c_write(priv, reg, new);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return change;
|
||||
}
|
67
drivers/sound/maxim_codec.h
Normal file
67
drivers/sound/maxim_codec.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* maxim_codec.h -- MAXIM codec common interface file
|
||||
*
|
||||
* Copyright (C) 2013 Samsung Electronics
|
||||
* D Krishna Mohan <krishna.md@samsung.com>
|
||||
*/
|
||||
|
||||
#ifndef __MAXIM_COMMON_H__
|
||||
#define __MAXIM_COMMON_H__
|
||||
|
||||
enum maxim_codec_type {
|
||||
MAX98095,
|
||||
MAX98090,
|
||||
};
|
||||
|
||||
struct maxim_priv {
|
||||
enum maxim_codec_type devtype;
|
||||
unsigned int sysclk;
|
||||
unsigned int rate;
|
||||
unsigned int fmt;
|
||||
struct udevice *dev;
|
||||
};
|
||||
|
||||
#define MAXIM_AUDIO_I2C_BUS 7
|
||||
#define MAXIM_AUDIO_I2C_REG_98095 0x22
|
||||
|
||||
#define MAXIM_AUDIO_I2C_REG MAXIM_AUDIO_I2C_REG_98095
|
||||
|
||||
/*
|
||||
* Writes value to a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be write
|
||||
* @param data data to be writen to the above registor
|
||||
*
|
||||
* @return int value 1 for change, 0 for no change or negative error code.
|
||||
*/
|
||||
int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
|
||||
unsigned char data);
|
||||
|
||||
/*
|
||||
* Read a value from a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be read
|
||||
* @param data address of read data to be stored
|
||||
*
|
||||
* @return int value 0 for success, -1 in case of error.
|
||||
*/
|
||||
unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
|
||||
unsigned char *data);
|
||||
|
||||
/*
|
||||
* update device register bits through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg codec register
|
||||
* @param mask register mask
|
||||
* @param value new value
|
||||
*
|
||||
* @return int value 0 for success, non-zero error code.
|
||||
*/
|
||||
int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
|
||||
unsigned char value);
|
||||
|
||||
#endif /* __MAXIM_COMMON_H__ */
|
|
@ -4,13 +4,14 @@
|
|||
* R. Chandrasekar <rcsekar@samsung.com>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/pinmux.h>
|
||||
#include <asm/arch/i2s-regs.h>
|
||||
#include <asm/io.h>
|
||||
#include <common.h>
|
||||
#include <sound.h>
|
||||
#include <i2s.h>
|
||||
|
||||
#define FIC_TX2COUNT(x) (((x) >> 24) & 0xf)
|
||||
#define FIC_TX1COUNT(x) (((x) >> 16) & 0xf)
|
||||
|
@ -111,7 +112,7 @@ static void i2s_set_bitclk_framesize(struct i2s_reg *i2s_reg, unsigned bfs)
|
|||
* @param flush Tx fifo flush command (0x00 - do not flush
|
||||
* 0x80 - flush tx fifo)
|
||||
*/
|
||||
void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
|
||||
static void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
|
||||
{
|
||||
/* Flush the FIFO */
|
||||
setbits_le32(&i2s_reg->fic, flush);
|
||||
|
@ -126,7 +127,7 @@ void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
|
|||
*
|
||||
* @return int value 0 for success, -1 in case of error
|
||||
*/
|
||||
int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
|
||||
static int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
|
||||
{
|
||||
unsigned int mod = readl(&i2s_reg->mod);
|
||||
|
||||
|
@ -148,7 +149,7 @@ int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
|
|||
*
|
||||
* @return int value 0 for success, -1 in case of error
|
||||
*/
|
||||
int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
||||
static int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
||||
{
|
||||
unsigned int mod = readl(&i2s_reg->mod);
|
||||
unsigned int tmp = 0;
|
||||
|
@ -170,7 +171,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
|||
default:
|
||||
debug("%s: Invalid format priority [0x%x]\n", __func__,
|
||||
(fmt & SND_SOC_DAIFMT_FORMAT_MASK));
|
||||
return -1;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -189,7 +190,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
|||
default:
|
||||
debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
|
||||
(fmt & SND_SOC_DAIFMT_INV_MASK));
|
||||
return -1;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
|
||||
|
@ -201,13 +202,13 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
|||
ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
|
||||
if (ret != 0) {
|
||||
debug("%s:set i2s clock direction failed\n", __func__);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
debug("%s: Invalid master selection [0x%x]\n", __func__,
|
||||
(fmt & SND_SOC_DAIFMT_MASTER_MASK));
|
||||
return -1;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
|
||||
|
@ -225,7 +226,7 @@ int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
|
|||
*
|
||||
* @return int value 0 for success, -1 in case of error
|
||||
*/
|
||||
int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
|
||||
static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
|
||||
{
|
||||
unsigned int mod = readl(&i2s_reg->mod);
|
||||
|
||||
|
@ -248,43 +249,43 @@ int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
|
|||
default:
|
||||
debug("%s: Invalid sample size input [0x%x]\n",
|
||||
__func__, blc);
|
||||
return -1;
|
||||
return -ERANGE;
|
||||
}
|
||||
writel(mod, &i2s_reg->mod);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
|
||||
unsigned long data_size)
|
||||
int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
|
||||
uint data_size)
|
||||
{
|
||||
struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
|
||||
u32 *ptr;
|
||||
int i;
|
||||
int start;
|
||||
struct i2s_reg *i2s_reg =
|
||||
(struct i2s_reg *)pi2s_tx->base_address;
|
||||
|
||||
if (data_size < FIFO_LENGTH) {
|
||||
debug("%s : Invalid data size\n", __func__);
|
||||
return -1; /* invalid pcm data size */
|
||||
return -ENODATA; /* invalid pcm data size */
|
||||
}
|
||||
|
||||
/* fill the tx buffer before stating the tx transmit */
|
||||
for (i = 0; i < FIFO_LENGTH; i++)
|
||||
writel(*data++, &i2s_reg->txd);
|
||||
for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
|
||||
writel(*ptr++, &i2s_reg->txd);
|
||||
|
||||
data_size -= FIFO_LENGTH;
|
||||
data_size -= sizeof(*ptr) * FIFO_LENGTH;
|
||||
i2s_txctrl(i2s_reg, I2S_TX_ON);
|
||||
|
||||
while (data_size > 0) {
|
||||
start = get_timer(0);
|
||||
if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
|
||||
writel(*data++, &i2s_reg->txd);
|
||||
data_size--;
|
||||
writel(*ptr++, &i2s_reg->txd);
|
||||
data_size -= sizeof(*ptr);
|
||||
} else {
|
||||
if (get_timer(start) > TIMEOUT_I2S_TX) {
|
||||
i2s_txctrl(i2s_reg, I2S_TX_OFF);
|
||||
debug("%s: I2S Transfer Timeout\n", __func__);
|
||||
return -1;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,11 +294,11 @@ int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int i2s_tx_init(struct i2stx_info *pi2s_tx)
|
||||
int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
|
||||
{
|
||||
int ret;
|
||||
struct i2s_reg *i2s_reg =
|
||||
(struct i2s_reg *)pi2s_tx->base_address;
|
||||
struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
|
||||
|
||||
if (pi2s_tx->id == 0) {
|
||||
/* Initialize GPIO for I2S-0 */
|
||||
exynos_pinmux_config(PERIPH_ID_I2S0, 0);
|
||||
|
@ -312,20 +313,20 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
|
|||
ret = set_epll_clk(pi2s_tx->audio_pll_clk);
|
||||
} else {
|
||||
debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
|
||||
return -1;
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
if (ret) {
|
||||
debug("%s: epll clock set rate failed\n", __func__);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Select Clk Source for Audio 0 or 1 */
|
||||
ret = set_i2s_clk_source(pi2s_tx->id);
|
||||
if (ret == -1) {
|
||||
if (ret) {
|
||||
debug("%s: unsupported clock for i2s-%d\n", __func__,
|
||||
pi2s_tx->id);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (pi2s_tx->id == 0) {
|
||||
|
@ -341,21 +342,21 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
|
|||
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
|
||||
pi2s_tx->id);
|
||||
}
|
||||
if (ret == -1) {
|
||||
if (ret) {
|
||||
debug("%s: unsupported prescalar for i2s-%d\n", __func__,
|
||||
pi2s_tx->id);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure I2s format */
|
||||
ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM));
|
||||
ret = i2s_set_fmt(i2s_reg, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBM_CFM);
|
||||
if (ret == 0) {
|
||||
i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
|
||||
ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
|
||||
if (ret != 0) {
|
||||
debug("%s:set sample rate failed\n", __func__);
|
||||
return -1;
|
||||
return ret;
|
||||
}
|
||||
|
||||
i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
|
||||
|
@ -368,3 +369,87 @@ int i2s_tx_init(struct i2stx_info *pi2s_tx)
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int samsung_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
|
||||
{
|
||||
struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
|
||||
|
||||
return i2s_transfer_tx_data(priv, data, data_size);
|
||||
}
|
||||
|
||||
static int samsung_i2s_probe(struct udevice *dev)
|
||||
{
|
||||
struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
|
||||
|
||||
return i2s_tx_init(priv);
|
||||
}
|
||||
|
||||
static int samsung_i2s_ofdata_to_platdata(struct udevice *dev)
|
||||
{
|
||||
struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
|
||||
ulong base;
|
||||
|
||||
/*
|
||||
* Get the pre-defined sound specific values from FDT.
|
||||
* All of these are expected to be correct otherwise
|
||||
* wrong register values in i2s setup parameters
|
||||
* may result in no sound play.
|
||||
*/
|
||||
base = dev_read_addr(dev);
|
||||
if (base == FDT_ADDR_T_NONE) {
|
||||
debug("%s: Missing i2s base\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
priv->base_address = base;
|
||||
|
||||
if (dev_read_u32u(dev, "samsung,i2s-epll-clock-frequency",
|
||||
&priv->audio_pll_clk))
|
||||
goto err;
|
||||
debug("audio_pll_clk = %d\n", priv->audio_pll_clk);
|
||||
if (dev_read_u32u(dev, "samsung,i2s-sampling-rate",
|
||||
&priv->samplingrate))
|
||||
goto err;
|
||||
debug("samplingrate = %d\n", priv->samplingrate);
|
||||
if (dev_read_u32u(dev, "samsung,i2s-bits-per-sample",
|
||||
&priv->bitspersample))
|
||||
goto err;
|
||||
debug("bitspersample = %d\n", priv->bitspersample);
|
||||
if (dev_read_u32u(dev, "samsung,i2s-channels", &priv->channels))
|
||||
goto err;
|
||||
debug("channels = %d\n", priv->channels);
|
||||
if (dev_read_u32u(dev, "samsung,i2s-lr-clk-framesize", &priv->rfs))
|
||||
goto err;
|
||||
debug("rfs = %d\n", priv->rfs);
|
||||
if (dev_read_u32u(dev, "samsung,i2s-bit-clk-framesize", &priv->bfs))
|
||||
goto err;
|
||||
debug("bfs = %d\n", priv->bfs);
|
||||
|
||||
if (dev_read_u32u(dev, "samsung,i2s-id", &priv->id))
|
||||
goto err;
|
||||
debug("id = %d\n", priv->id);
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
debug("fail to get sound i2s node properties\n");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static const struct i2s_ops samsung_i2s_ops = {
|
||||
.tx_data = samsung_i2s_tx_data,
|
||||
};
|
||||
|
||||
static const struct udevice_id samsung_i2s_ids[] = {
|
||||
{ .compatible = "samsung,s5pv210-i2s" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(samsung_i2s) = {
|
||||
.name = "samsung_i2s",
|
||||
.id = UCLASS_I2S,
|
||||
.of_match = samsung_i2s_ids,
|
||||
.probe = samsung_i2s_probe,
|
||||
.ofdata_to_platdata = samsung_i2s_ofdata_to_platdata,
|
||||
.ops = &samsung_i2s_ops,
|
||||
};
|
||||
|
|
104
drivers/sound/samsung_sound.c
Normal file
104
drivers/sound/samsung_sound.c
Normal file
|
@ -0,0 +1,104 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google, LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <audio_codec.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/gpio.h>
|
||||
|
||||
static int samsung_sound_setup(struct udevice *dev)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
|
||||
int ret;
|
||||
|
||||
if (uc_priv->setup_done)
|
||||
return -EALREADY;
|
||||
ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
|
||||
i2c_priv->samplingrate,
|
||||
i2c_priv->samplingrate * i2c_priv->rfs,
|
||||
i2c_priv->bitspersample,
|
||||
i2c_priv->channels);
|
||||
if (ret)
|
||||
return ret;
|
||||
uc_priv->setup_done = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
return i2s_tx_data(uc_priv->i2s, data, data_size);
|
||||
}
|
||||
|
||||
static int samsung_sound_probe(struct udevice *dev)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct ofnode_phandle_args args;
|
||||
struct gpio_desc en_gpio;
|
||||
ofnode node;
|
||||
int ret;
|
||||
|
||||
ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
|
||||
|
||||
/* Turn on the GPIO which connects to the codec's "enable" line. */
|
||||
if (!ret)
|
||||
gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
|
||||
|
||||
ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
|
||||
"samsung,audio-codec",
|
||||
&uc_priv->codec);
|
||||
if (ret) {
|
||||
debug("Failed to probe audio codec\n");
|
||||
return ret;
|
||||
}
|
||||
node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
|
||||
if (!ofnode_valid(node)) {
|
||||
debug("Failed to find /cpu subnode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ofnode_parse_phandle_with_args(node, "sound-dai",
|
||||
"#sound-dai-cells", 0, 0, &args);
|
||||
if (ret) {
|
||||
debug("Cannot find phandle: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
|
||||
if (ret) {
|
||||
debug("Cannot find i2s: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
|
||||
uc_priv->codec->name, uc_priv->i2s->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct sound_ops samsung_sound_ops = {
|
||||
.setup = samsung_sound_setup,
|
||||
.play = samsung_sound_play,
|
||||
};
|
||||
|
||||
static const struct udevice_id samsung_sound_ids[] = {
|
||||
{ .compatible = "google,snow-audio-max98095" },
|
||||
{ .compatible = "google,spring-audio-max98095" },
|
||||
{ .compatible = "samsung,smdk5420-audio-wm8994" },
|
||||
{ .compatible = "google,peach-audio-max98090" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(samsung_sound) = {
|
||||
.name = "samsung_sound",
|
||||
.id = UCLASS_SOUND,
|
||||
.of_match = samsung_sound_ids,
|
||||
.probe = samsung_sound_probe,
|
||||
.ops = &samsung_sound_ops,
|
||||
};
|
|
@ -4,19 +4,185 @@
|
|||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <asm/sound.h>
|
||||
#include <audio_codec.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/sdl.h>
|
||||
|
||||
int sound_play(uint32_t msec, uint32_t frequency)
|
||||
struct sandbox_codec_priv {
|
||||
int interface;
|
||||
int rate;
|
||||
int mclk_freq;
|
||||
int bits_per_sample;
|
||||
uint channels;
|
||||
};
|
||||
|
||||
struct sandbox_i2s_priv {
|
||||
int sum; /* Use to sum the provided audio data */
|
||||
};
|
||||
|
||||
struct sandbox_sound_priv {
|
||||
int setup_called;
|
||||
int sum; /* Use to sum the provided audio data */
|
||||
};
|
||||
|
||||
void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
|
||||
int *mclk_freqp, int *bits_per_samplep,
|
||||
uint *channelsp)
|
||||
{
|
||||
sandbox_sdl_sound_start(frequency);
|
||||
mdelay(msec);
|
||||
sandbox_sdl_sound_stop();
|
||||
struct sandbox_codec_priv *priv = dev_get_priv(dev);
|
||||
|
||||
*interfacep = priv->interface;
|
||||
*ratep = priv->rate;
|
||||
*mclk_freqp = priv->mclk_freq;
|
||||
*bits_per_samplep = priv->bits_per_sample;
|
||||
*channelsp = priv->channels;
|
||||
}
|
||||
|
||||
int sandbox_get_i2s_sum(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_i2s_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->sum;
|
||||
}
|
||||
|
||||
int sandbox_get_setup_called(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->setup_called;
|
||||
}
|
||||
|
||||
int sandbox_get_sound_sum(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return priv->sum;
|
||||
}
|
||||
|
||||
static int sandbox_codec_set_params(struct udevice *dev, int interface,
|
||||
int rate, int mclk_freq,
|
||||
int bits_per_sample, uint channels)
|
||||
{
|
||||
struct sandbox_codec_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->interface = interface;
|
||||
priv->rate = rate;
|
||||
priv->mclk_freq = mclk_freq;
|
||||
priv->bits_per_sample = bits_per_sample;
|
||||
priv->channels = channels;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sound_init(const void *blob)
|
||||
static int sandbox_i2s_tx_data(struct udevice *dev, void *data,
|
||||
uint data_size)
|
||||
{
|
||||
return sandbox_sdl_sound_init();
|
||||
struct sandbox_i2s_priv *priv = dev_get_priv(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data_size; i++)
|
||||
priv->sum += ((uint8_t *)data)[i];
|
||||
|
||||
return sandbox_sdl_sound_play(data, data_size);
|
||||
}
|
||||
|
||||
static int sandbox_i2s_probe(struct udevice *dev)
|
||||
{
|
||||
struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
|
||||
/* Use hard-coded values here */
|
||||
uc_priv->rfs = 256;
|
||||
uc_priv->bfs = 32;
|
||||
uc_priv->audio_pll_clk = 192000000;
|
||||
uc_priv->samplingrate = 48000;
|
||||
uc_priv->bitspersample = 16;
|
||||
uc_priv->channels = 2;
|
||||
uc_priv->id = 1;
|
||||
|
||||
/* Ignore any error here - we'll just have no sound */
|
||||
sandbox_sdl_sound_init(uc_priv->samplingrate, uc_priv->channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_sound_setup(struct udevice *dev)
|
||||
{
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->setup_called++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct sandbox_sound_priv *priv = dev_get_priv(dev);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < data_size; i++)
|
||||
priv->sum += ((uint8_t *)data)[i];
|
||||
|
||||
return i2s_tx_data(uc_priv->i2s, data, data_size);
|
||||
}
|
||||
|
||||
static int sandbox_sound_probe(struct udevice *dev)
|
||||
{
|
||||
return sound_find_codec_i2s(dev);
|
||||
}
|
||||
|
||||
static const struct audio_codec_ops sandbox_codec_ops = {
|
||||
.set_params = sandbox_codec_set_params,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_codec_ids[] = {
|
||||
{ .compatible = "sandbox,audio-codec" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sandbox_codec) = {
|
||||
.name = "sandbox_codec",
|
||||
.id = UCLASS_AUDIO_CODEC,
|
||||
.of_match = sandbox_codec_ids,
|
||||
.ops = &sandbox_codec_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_codec_priv),
|
||||
};
|
||||
|
||||
static const struct i2s_ops sandbox_i2s_ops = {
|
||||
.tx_data = sandbox_i2s_tx_data,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_i2s_ids[] = {
|
||||
{ .compatible = "sandbox,i2s" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sandbox_i2s) = {
|
||||
.name = "sandbox_i2s",
|
||||
.id = UCLASS_I2S,
|
||||
.of_match = sandbox_i2s_ids,
|
||||
.ops = &sandbox_i2s_ops,
|
||||
.probe = sandbox_i2s_probe,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_i2s_priv),
|
||||
};
|
||||
|
||||
static const struct sound_ops sandbox_sound_ops = {
|
||||
.setup = sandbox_sound_setup,
|
||||
.play = sandbox_sound_play,
|
||||
};
|
||||
|
||||
static const struct udevice_id sandbox_sound_ids[] = {
|
||||
{ .compatible = "sandbox,sound" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(sandbox_sound) = {
|
||||
.name = "sandbox_sound",
|
||||
.id = UCLASS_SOUND,
|
||||
.of_match = sandbox_sound_ids,
|
||||
.ops = &sandbox_sound_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct sandbox_sound_priv),
|
||||
.probe = sandbox_sound_probe,
|
||||
};
|
||||
|
|
|
@ -1,208 +0,0 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright (C) 2012 Samsung Electronics
|
||||
* R. Chandrasekar <rcsekar@samsung.com>
|
||||
*/
|
||||
|
||||
#include <malloc.h>
|
||||
#include <common.h>
|
||||
#include <asm/io.h>
|
||||
#include <linux/libfdt.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/arch/sound.h>
|
||||
#include "wm8994.h"
|
||||
#include "max98095.h"
|
||||
|
||||
/* defines */
|
||||
#define SOUND_400_HZ 400
|
||||
#define SOUND_BITS_IN_BYTE 8
|
||||
|
||||
static struct i2stx_info g_i2stx_pri;
|
||||
|
||||
/*
|
||||
* get_sound_i2s_values gets values for i2s parameters
|
||||
*
|
||||
* @param i2stx_info i2s transmitter transfer param structure
|
||||
* @param blob FDT blob if enabled else NULL
|
||||
*/
|
||||
static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)
|
||||
{
|
||||
int node;
|
||||
int error = 0;
|
||||
int base;
|
||||
|
||||
node = fdt_path_offset(blob, "i2s");
|
||||
if (node <= 0) {
|
||||
debug("EXYNOS_SOUND: No node for sound in device tree\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the pre-defined sound specific values from FDT.
|
||||
* All of these are expected to be correct otherwise
|
||||
* wrong register values in i2s setup parameters
|
||||
* may result in no sound play.
|
||||
*/
|
||||
base = fdtdec_get_addr(blob, node, "reg");
|
||||
if (base == FDT_ADDR_T_NONE) {
|
||||
debug("%s: Missing i2s base\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
i2s->base_address = base;
|
||||
|
||||
i2s->audio_pll_clk = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-epll-clock-frequency", -1);
|
||||
error |= i2s->audio_pll_clk;
|
||||
debug("audio_pll_clk = %d\n", i2s->audio_pll_clk);
|
||||
i2s->samplingrate = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-sampling-rate", -1);
|
||||
error |= i2s->samplingrate;
|
||||
debug("samplingrate = %d\n", i2s->samplingrate);
|
||||
i2s->bitspersample = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-bits-per-sample", -1);
|
||||
error |= i2s->bitspersample;
|
||||
debug("bitspersample = %d\n", i2s->bitspersample);
|
||||
i2s->channels = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-channels", -1);
|
||||
error |= i2s->channels;
|
||||
debug("channels = %d\n", i2s->channels);
|
||||
i2s->rfs = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-lr-clk-framesize", -1);
|
||||
error |= i2s->rfs;
|
||||
debug("rfs = %d\n", i2s->rfs);
|
||||
i2s->bfs = fdtdec_get_int(blob,
|
||||
node, "samsung,i2s-bit-clk-framesize", -1);
|
||||
error |= i2s->bfs;
|
||||
debug("bfs = %d\n", i2s->bfs);
|
||||
|
||||
i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1);
|
||||
error |= i2s->id;
|
||||
debug("id = %d\n", i2s->id);
|
||||
|
||||
if (error == -1) {
|
||||
debug("fail to get sound i2s node properties\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Init codec
|
||||
*
|
||||
* @param blob FDT blob
|
||||
* @param pi2s_tx i2s parameters required by codec
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
|
||||
{
|
||||
int ret;
|
||||
const char *codectype;
|
||||
int node;
|
||||
|
||||
/* Get the node from FDT for sound */
|
||||
node = fdt_path_offset(blob, "i2s");
|
||||
if (node <= 0) {
|
||||
debug("EXYNOS_SOUND: No node for sound in device tree\n");
|
||||
debug("node = %d\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the pre-defined sound codec specific values from FDT.
|
||||
* All of these are expected to be correct otherwise sound
|
||||
* can not be played
|
||||
*/
|
||||
codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL);
|
||||
debug("device = %s\n", codectype);
|
||||
if (!strcmp(codectype, "wm8994")) {
|
||||
/* Check the codec type and initialise the same */
|
||||
ret = wm8994_init(blob, pi2s_tx->id + 1,
|
||||
pi2s_tx->samplingrate,
|
||||
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
|
||||
pi2s_tx->bitspersample, pi2s_tx->channels);
|
||||
} else if (!strcmp(codectype, "max98095")) {
|
||||
ret = max98095_init(blob, pi2s_tx->id + 1,
|
||||
pi2s_tx->samplingrate,
|
||||
(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
|
||||
pi2s_tx->bitspersample);
|
||||
} else {
|
||||
debug("%s: Unknown codec type %s\n", __func__, codectype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
debug("%s: Codec init failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sound_init(const void *blob)
|
||||
{
|
||||
int ret;
|
||||
struct i2stx_info *pi2s_tx = &g_i2stx_pri;
|
||||
|
||||
/* Get the I2S Values */
|
||||
if (get_sound_i2s_values(pi2s_tx, blob) < 0) {
|
||||
debug(" FDT I2S values failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (codec_init(blob, pi2s_tx) < 0) {
|
||||
debug(" Codec init failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = i2s_tx_init(pi2s_tx);
|
||||
if (ret) {
|
||||
debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sound_play(uint32_t msec, uint32_t frequency)
|
||||
{
|
||||
unsigned int *data;
|
||||
unsigned long data_size;
|
||||
unsigned int ret = 0;
|
||||
|
||||
/*Buffer length computation */
|
||||
data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
|
||||
data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
|
||||
data = malloc(data_size);
|
||||
|
||||
if (data == NULL) {
|
||||
debug("%s: malloc failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sound_create_square_wave(g_i2stx_pri.samplingrate,
|
||||
(unsigned short *)data,
|
||||
data_size / sizeof(unsigned short),
|
||||
frequency);
|
||||
|
||||
while (msec >= 1000) {
|
||||
ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
|
||||
(data_size / sizeof(int)));
|
||||
msec -= 1000;
|
||||
}
|
||||
if (msec) {
|
||||
unsigned long size =
|
||||
(data_size * msec) / (sizeof(int) * 1000);
|
||||
|
||||
ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size);
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
return ret;
|
||||
}
|
127
drivers/sound/sound-uclass.c
Normal file
127
drivers/sound/sound-uclass.c
Normal file
|
@ -0,0 +1,127 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
|
||||
#define SOUND_BITS_IN_BYTE 8
|
||||
|
||||
int sound_setup(struct udevice *dev)
|
||||
{
|
||||
struct sound_ops *ops = sound_get_ops(dev);
|
||||
|
||||
if (!ops->setup)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->setup(dev);
|
||||
}
|
||||
|
||||
int sound_play(struct udevice *dev, void *data, uint data_size)
|
||||
{
|
||||
struct sound_ops *ops = sound_get_ops(dev);
|
||||
|
||||
if (!ops->play)
|
||||
return -ENOSYS;
|
||||
|
||||
return ops->play(dev, data, data_size);
|
||||
}
|
||||
|
||||
int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
|
||||
unsigned short *data;
|
||||
uint data_size;
|
||||
int ret;
|
||||
|
||||
ret = sound_setup(dev);
|
||||
if (ret && ret != -EALREADY)
|
||||
return ret;
|
||||
|
||||
/* Buffer length computation */
|
||||
data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
|
||||
data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
|
||||
data = malloc(data_size);
|
||||
if (!data) {
|
||||
debug("%s: malloc failed\n", __func__);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
|
||||
frequency_hz, i2s_uc_priv->channels);
|
||||
|
||||
while (msecs >= 1000) {
|
||||
ret = sound_play(dev, data, data_size);
|
||||
msecs -= 1000;
|
||||
}
|
||||
if (msecs) {
|
||||
unsigned long size =
|
||||
(data_size * msecs) / (sizeof(int) * 1000);
|
||||
|
||||
ret = sound_play(dev, data, size);
|
||||
}
|
||||
|
||||
free(data);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sound_find_codec_i2s(struct udevice *dev)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct ofnode_phandle_args args;
|
||||
ofnode node;
|
||||
int ret;
|
||||
|
||||
/* First the codec */
|
||||
node = ofnode_find_subnode(dev_ofnode(dev), "codec");
|
||||
if (!ofnode_valid(node)) {
|
||||
debug("Failed to find /cpu subnode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ofnode_parse_phandle_with_args(node, "sound-dai",
|
||||
"#sound-dai-cells", 0, 0, &args);
|
||||
if (ret) {
|
||||
debug("Cannot find phandle: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node,
|
||||
&uc_priv->codec);
|
||||
if (ret) {
|
||||
debug("Cannot find codec: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Now the i2s */
|
||||
node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
|
||||
if (!ofnode_valid(node)) {
|
||||
debug("Failed to find /cpu subnode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = ofnode_parse_phandle_with_args(node, "sound-dai",
|
||||
"#sound-dai-cells", 0, 0, &args);
|
||||
if (ret) {
|
||||
debug("Cannot find phandle: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
|
||||
if (ret) {
|
||||
debug("Cannot find i2s: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
|
||||
uc_priv->codec->name, uc_priv->i2s->name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(sound) = {
|
||||
.id = UCLASS_SOUND,
|
||||
.name = "sound",
|
||||
.per_device_auto_alloc_size = sizeof(struct sound_uc_priv),
|
||||
};
|
|
@ -8,7 +8,7 @@
|
|||
#include <sound.h>
|
||||
|
||||
void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
|
||||
uint freq)
|
||||
uint freq, uint channels)
|
||||
{
|
||||
const unsigned short amplitude = 16000; /* between 1 and 32767 */
|
||||
const int period = freq ? sample_rate / freq : 0;
|
||||
|
@ -21,14 +21,17 @@ void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
|
|||
size--;
|
||||
|
||||
while (size) {
|
||||
int i;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; size && i < half; i++) {
|
||||
size -= 2;
|
||||
*data++ = amplitude;
|
||||
for (j = 0; j < channels; j++)
|
||||
*data++ = amplitude;
|
||||
}
|
||||
for (i = 0; size && i < period - half; i++) {
|
||||
size -= 2;
|
||||
*data++ = -amplitude;
|
||||
for (j = 0; j < channels; j++)
|
||||
*data++ = -amplitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
* R. Chandrasekar <rcsekar@samsung.com>
|
||||
*/
|
||||
#include <common.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <audio_codec.h>
|
||||
#include <dm.h>
|
||||
#include <div64.h>
|
||||
#include <fdtdec.h>
|
||||
#include <i2c.h>
|
||||
#include <i2s.h>
|
||||
#include <sound.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/arch/clk.h>
|
||||
#include <asm/arch/cpu.h>
|
||||
#include <asm/arch/sound.h>
|
||||
#include "wm8994.h"
|
||||
#include "wm8994_registers.h"
|
||||
|
@ -38,6 +40,7 @@ struct wm8994_priv {
|
|||
int mclk[WM8994_MAX_AIF]; /* master clock frequency in Hz */
|
||||
int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */
|
||||
struct wm8994_fll_config fll[2]; /* fll config to configure fll */
|
||||
struct udevice *dev;
|
||||
};
|
||||
|
||||
/* wm 8994 supported sampling rate values */
|
||||
|
@ -60,29 +63,17 @@ static int bclk_divs[] = {
|
|||
640, 880, 960, 1280, 1760, 1920
|
||||
};
|
||||
|
||||
static struct wm8994_priv g_wm8994_info;
|
||||
static unsigned char g_wm8994_i2c_dev_addr;
|
||||
static struct sound_codec_info g_codec_info;
|
||||
|
||||
/*
|
||||
* Initialise I2C for wm 8994
|
||||
*
|
||||
* @param bus no i2c bus number in which wm8994 is connected
|
||||
*/
|
||||
static void wm8994_i2c_init(int bus_no)
|
||||
{
|
||||
i2c_set_bus_num(bus_no);
|
||||
}
|
||||
|
||||
/*
|
||||
* Writes value to a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be write
|
||||
* @param data data to be writen to the above registor
|
||||
*
|
||||
* @return int value 1 for change, 0 for no change or negative error code.
|
||||
*/
|
||||
static int wm8994_i2c_write(unsigned int reg, unsigned short data)
|
||||
static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
|
||||
unsigned short data)
|
||||
{
|
||||
unsigned char val[2];
|
||||
|
||||
|
@ -90,23 +81,25 @@ static int wm8994_i2c_write(unsigned int reg, unsigned short data)
|
|||
val[1] = (unsigned char)(data & 0xff);
|
||||
debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data);
|
||||
|
||||
return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
|
||||
return dm_i2c_write(priv->dev, reg, val, 2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a value from a device register through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg reg number to be read
|
||||
* @param data address of read data to be stored
|
||||
*
|
||||
* @return int value 0 for success, -1 in case of error.
|
||||
*/
|
||||
static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
|
||||
static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
|
||||
unsigned short *data)
|
||||
{
|
||||
unsigned char val[2];
|
||||
int ret;
|
||||
|
||||
ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
|
||||
ret = dm_i2c_read(priv->dev, reg, val, 1);
|
||||
if (ret != 0) {
|
||||
debug("%s: Error while reading register %#04x\n",
|
||||
__func__, reg);
|
||||
|
@ -123,6 +116,7 @@ static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
|
|||
/*
|
||||
* update device register bits through i2c
|
||||
*
|
||||
* @param priv Private data for driver
|
||||
* @param reg codec register
|
||||
* @param mask register mask
|
||||
* @param value new value
|
||||
|
@ -130,18 +124,18 @@ static unsigned int wm8994_i2c_read(unsigned int reg , unsigned short *data)
|
|||
* @return int value 1 if change in the register value,
|
||||
* 0 for no change or negative error code.
|
||||
*/
|
||||
static int wm8994_update_bits(unsigned int reg, unsigned short mask,
|
||||
unsigned short value)
|
||||
static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg,
|
||||
unsigned short mask, unsigned short value)
|
||||
{
|
||||
int change , ret = 0;
|
||||
unsigned short old, new;
|
||||
|
||||
if (wm8994_i2c_read(reg, &old) != 0)
|
||||
if (wm8994_i2c_read(priv, reg, &old) != 0)
|
||||
return -1;
|
||||
new = (old & ~mask) | (value & mask);
|
||||
change = (old != new) ? 1 : 0;
|
||||
if (change)
|
||||
ret = wm8994_i2c_write(reg, new);
|
||||
ret = wm8994_i2c_write(priv, reg, new);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
|
@ -151,12 +145,13 @@ static int wm8994_update_bits(unsigned int reg, unsigned short mask,
|
|||
/*
|
||||
* Sets i2s set format
|
||||
*
|
||||
* @param priv wm8994 information
|
||||
* @param aif_id Interface ID
|
||||
* @param fmt i2S format
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
*/
|
||||
int wm8994_set_fmt(int aif_id, unsigned int fmt)
|
||||
static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt)
|
||||
{
|
||||
int ms_reg;
|
||||
int aif_reg;
|
||||
|
@ -254,12 +249,13 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
|
|||
return -1;
|
||||
}
|
||||
|
||||
error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
|
||||
WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
|
||||
error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV |
|
||||
WM8994_AIF1_LRCLK_INV_MASK |
|
||||
WM8994_AIF1_FMT_MASK, aif);
|
||||
|
||||
error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms);
|
||||
error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK,
|
||||
WM8994_AIF1CLK_ENA);
|
||||
error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms);
|
||||
error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK,
|
||||
WM8994_AIF1CLK_ENA);
|
||||
if (error < 0) {
|
||||
debug("%s: codec register access error\n", __func__);
|
||||
return -1;
|
||||
|
@ -271,7 +267,7 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
|
|||
/*
|
||||
* Sets hw params FOR WM8994
|
||||
*
|
||||
* @param wm8994 wm8994 information pointer
|
||||
* @param priv wm8994 information pointer
|
||||
* @param aif_id Audio interface ID
|
||||
* @param sampling_rate Sampling rate
|
||||
* @param bits_per_sample Bits per sample
|
||||
|
@ -279,9 +275,9 @@ int wm8994_set_fmt(int aif_id, unsigned int fmt)
|
|||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
*/
|
||||
static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
||||
unsigned int sampling_rate, unsigned int bits_per_sample,
|
||||
unsigned int channels)
|
||||
static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id,
|
||||
uint sampling_rate, uint bits_per_sample,
|
||||
uint channels)
|
||||
{
|
||||
int aif1_reg;
|
||||
int aif2_reg;
|
||||
|
@ -349,12 +345,10 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
|||
|
||||
/* AIFCLK/fs ratio; look for a close match in either direction */
|
||||
best = 0;
|
||||
best_val = abs((fs_ratios[0] * sampling_rate)
|
||||
- wm8994->aifclk[id]);
|
||||
best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]);
|
||||
|
||||
for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
|
||||
cur_val = abs((fs_ratios[i] * sampling_rate)
|
||||
- wm8994->aifclk[id]);
|
||||
cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]);
|
||||
if (cur_val >= best_val)
|
||||
continue;
|
||||
best = i;
|
||||
|
@ -371,7 +365,7 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
|||
*/
|
||||
best = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
|
||||
cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
|
||||
cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
|
||||
if (cur_val < 0) /* BCLK table is sorted */
|
||||
break;
|
||||
best = i;
|
||||
|
@ -383,10 +377,10 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
|||
return -1;
|
||||
}
|
||||
|
||||
bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
|
||||
bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best];
|
||||
bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
|
||||
|
||||
if (wm8994_i2c_read(aif1_reg, ®_data) != 0) {
|
||||
if (wm8994_i2c_read(priv, aif1_reg, ®_data) != 0) {
|
||||
debug("%s: AIF1 register read Failed\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
@ -394,16 +388,17 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
|||
if ((channels == 1) && ((reg_data & 0x18) == 0x18))
|
||||
aif2 |= WM8994_AIF1_MONO;
|
||||
|
||||
if (wm8994->aifclk[id] == 0) {
|
||||
if (priv->aifclk[id] == 0) {
|
||||
debug("%s:Audio interface clock not set\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1);
|
||||
ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2);
|
||||
ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
|
||||
ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK |
|
||||
WM8994_AIF1CLK_RATE_MASK, rate_val);
|
||||
ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
|
||||
ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2);
|
||||
ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK,
|
||||
bclk);
|
||||
ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK |
|
||||
WM8994_AIF1CLK_RATE_MASK, rate_val);
|
||||
|
||||
debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
|
||||
|
||||
|
@ -418,12 +413,12 @@ static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
|
|||
/*
|
||||
* Configures Audio interface Clock
|
||||
*
|
||||
* @param wm8994 wm8994 information pointer
|
||||
* @param priv wm8994 information pointer
|
||||
* @param aif Audio Interface ID
|
||||
*
|
||||
* @return -1 for error and 0 Success.
|
||||
*/
|
||||
static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
|
||||
static int configure_aif_clock(struct wm8994_priv *priv, int aif)
|
||||
{
|
||||
int rate;
|
||||
int reg1 = 0;
|
||||
|
@ -436,30 +431,30 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
|
|||
else
|
||||
offset = 0;
|
||||
|
||||
switch (wm8994->sysclk[aif-1]) {
|
||||
switch (priv->sysclk[aif - 1]) {
|
||||
case WM8994_SYSCLK_MCLK1:
|
||||
reg1 |= SEL_MCLK1;
|
||||
rate = wm8994->mclk[0];
|
||||
rate = priv->mclk[0];
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_MCLK2:
|
||||
reg1 |= SEL_MCLK2;
|
||||
rate = wm8994->mclk[1];
|
||||
rate = priv->mclk[1];
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_FLL1:
|
||||
reg1 |= SEL_FLL1;
|
||||
rate = wm8994->fll[0].out;
|
||||
rate = priv->fll[0].out;
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_FLL2:
|
||||
reg1 |= SEL_FLL2;
|
||||
rate = wm8994->fll[1].out;
|
||||
rate = priv->fll[1].out;
|
||||
break;
|
||||
|
||||
default:
|
||||
debug("%s: Invalid input clock selection [%d]\n",
|
||||
__func__, wm8994->sysclk[aif-1]);
|
||||
__func__, priv->sysclk[aif - 1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -469,18 +464,18 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
|
|||
reg1 |= WM8994_AIF1CLK_DIV;
|
||||
}
|
||||
|
||||
wm8994->aifclk[aif-1] = rate;
|
||||
priv->aifclk[aif - 1] = rate;
|
||||
|
||||
ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,
|
||||
WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
|
||||
reg1);
|
||||
ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset,
|
||||
WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
|
||||
reg1);
|
||||
|
||||
if (aif == WM8994_AIF1)
|
||||
ret |= wm8994_update_bits(WM8994_CLOCKING_1,
|
||||
ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
|
||||
WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK,
|
||||
WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
|
||||
else if (aif == WM8994_AIF2)
|
||||
ret |= wm8994_update_bits(WM8994_CLOCKING_1,
|
||||
ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
|
||||
WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
|
||||
WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
|
||||
WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
|
||||
|
@ -496,33 +491,33 @@ static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
|
|||
/*
|
||||
* Configures Audio interface for the given frequency
|
||||
*
|
||||
* @param wm8994 wm8994 information
|
||||
* @param priv wm8994 information
|
||||
* @param aif_id Audio Interface
|
||||
* @param clk_id Input Clock ID
|
||||
* @param freq Sampling frequency in Hz
|
||||
*
|
||||
* @return -1 for error and 0 success.
|
||||
*/
|
||||
static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
|
||||
int clk_id, unsigned int freq)
|
||||
static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id,
|
||||
unsigned int freq)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
|
||||
wm8994->sysclk[aif_id - 1] = clk_id;
|
||||
priv->sysclk[aif_id - 1] = clk_id;
|
||||
|
||||
switch (clk_id) {
|
||||
case WM8994_SYSCLK_MCLK1:
|
||||
wm8994->mclk[0] = freq;
|
||||
priv->mclk[0] = freq;
|
||||
if (aif_id == 2) {
|
||||
ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
|
||||
WM8994_AIF2DAC_DIV_MASK , 0);
|
||||
ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2,
|
||||
WM8994_AIF2DAC_DIV_MASK, 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_MCLK2:
|
||||
/* TODO: Set GPIO AF */
|
||||
wm8994->mclk[1] = freq;
|
||||
priv->mclk[1] = freq;
|
||||
break;
|
||||
|
||||
case WM8994_SYSCLK_FLL1:
|
||||
|
@ -543,13 +538,14 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
|
|||
__func__);
|
||||
return -1;
|
||||
}
|
||||
ret = wm8994_update_bits(WM8994_CLOCKING_2,
|
||||
ret = wm8994_bic_or(priv, WM8994_CLOCKING_2,
|
||||
WM8994_OPCLK_DIV_MASK, i);
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
|
||||
ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_OPCLK_ENA,
|
||||
WM8994_OPCLK_ENA);
|
||||
} else {
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_OPCLK_ENA, 0);
|
||||
ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_OPCLK_ENA, 0);
|
||||
}
|
||||
|
||||
default:
|
||||
|
@ -558,7 +554,7 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
|
|||
return -1;
|
||||
}
|
||||
|
||||
ret |= configure_aif_clock(wm8994, aif_id);
|
||||
ret |= configure_aif_clock(priv, aif_id);
|
||||
|
||||
if (ret < 0) {
|
||||
debug("%s: codec register access error\n", __func__);
|
||||
|
@ -571,37 +567,38 @@ static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
|
|||
/*
|
||||
* Initializes Volume for AIF2 to HP path
|
||||
*
|
||||
* @param priv wm8994 information
|
||||
* @returns -1 for error and 0 Success.
|
||||
*
|
||||
*/
|
||||
static int wm8994_init_volume_aif2_dac1(void)
|
||||
static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Unmute AIF2DAC */
|
||||
ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
|
||||
WM8994_AIF2DAC_MUTE_MASK, 0);
|
||||
ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1,
|
||||
WM8994_AIF2DAC_MUTE_MASK, 0);
|
||||
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME,
|
||||
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
|
||||
WM8994_AIF2DAC_VU | 0xff);
|
||||
ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME,
|
||||
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
|
||||
WM8994_AIF2DAC_VU | 0xff);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME,
|
||||
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
|
||||
WM8994_AIF2DAC_VU | 0xff);
|
||||
ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME,
|
||||
WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
|
||||
WM8994_AIF2DAC_VU | 0xff);
|
||||
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
|
||||
WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
|
||||
WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
|
||||
WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
|
||||
WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
/* Head Phone Volume */
|
||||
ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
|
||||
|
||||
if (ret < 0) {
|
||||
debug("%s: codec register access error\n", __func__);
|
||||
|
@ -614,26 +611,27 @@ static int wm8994_init_volume_aif2_dac1(void)
|
|||
/*
|
||||
* Initializes Volume for AIF1 to HP path
|
||||
*
|
||||
* @param priv wm8994 information
|
||||
* @returns -1 for error and 0 Success.
|
||||
*
|
||||
*/
|
||||
static int wm8994_init_volume_aif1_dac1(void)
|
||||
static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Unmute AIF1DAC */
|
||||
ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
|
||||
WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
|
||||
WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
|
||||
WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
|
||||
WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
|
||||
WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
|
||||
/* Head Phone Volume */
|
||||
ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
|
||||
|
||||
if (ret < 0) {
|
||||
debug("%s: codec register access error\n", __func__);
|
||||
|
@ -646,93 +644,99 @@ static int wm8994_init_volume_aif1_dac1(void)
|
|||
/*
|
||||
* Intialise wm8994 codec device
|
||||
*
|
||||
* @param wm8994 wm8994 information
|
||||
* @param priv wm8994 information
|
||||
*
|
||||
* @returns -1 for error and 0 Success.
|
||||
*/
|
||||
static int wm8994_device_init(struct wm8994_priv *wm8994,
|
||||
enum en_audio_interface aif_id)
|
||||
static int wm8994_device_init(struct wm8994_priv *priv)
|
||||
{
|
||||
const char *devname;
|
||||
unsigned short reg_data;
|
||||
int ret;
|
||||
|
||||
wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
|
||||
wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET);
|
||||
|
||||
ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, ®_data);
|
||||
ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, ®_data);
|
||||
if (ret < 0) {
|
||||
debug("Failed to read ID register\n");
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (reg_data == WM8994_ID) {
|
||||
devname = "WM8994";
|
||||
debug("Device registered as type %d\n", wm8994->type);
|
||||
wm8994->type = WM8994;
|
||||
debug("Device registered as type %d\n", priv->type);
|
||||
priv->type = WM8994;
|
||||
} else {
|
||||
debug("Device is not a WM8994, ID is %x\n", ret);
|
||||
ret = -1;
|
||||
goto err;
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = wm8994_i2c_read(WM8994_CHIP_REVISION, ®_data);
|
||||
ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, ®_data);
|
||||
if (ret < 0) {
|
||||
debug("Failed to read revision register: %d\n", ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
wm8994->revision = reg_data;
|
||||
debug("%s revision %c\n", devname, 'A' + wm8994->revision);
|
||||
priv->revision = reg_data;
|
||||
debug("%s revision %c\n", devname, 'A' + priv->revision);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wm8994_setup_interface(struct wm8994_priv *priv,
|
||||
enum en_audio_interface aif_id)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* VMID Selection */
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
|
||||
ret = wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
|
||||
|
||||
/* Charge Pump Enable */
|
||||
ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
|
||||
WM8994_CP_ENA);
|
||||
ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
|
||||
WM8994_CP_ENA);
|
||||
|
||||
/* Head Phone Power Enable */
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
|
||||
ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
|
||||
ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
|
||||
WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
|
||||
|
||||
if (aif_id == WM8994_AIF1) {
|
||||
ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2,
|
||||
ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2,
|
||||
WM8994_TSHUT_ENA | WM8994_MIXINL_ENA |
|
||||
WM8994_MIXINR_ENA | WM8994_IN2L_ENA |
|
||||
WM8994_IN2R_ENA);
|
||||
|
||||
ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_4,
|
||||
ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4,
|
||||
WM8994_ADCL_ENA | WM8994_ADCR_ENA |
|
||||
WM8994_AIF1ADC1R_ENA |
|
||||
WM8994_AIF1ADC1L_ENA);
|
||||
|
||||
/* Power enable for AIF1 and DAC1 */
|
||||
ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_5,
|
||||
ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5,
|
||||
WM8994_AIF1DACL_ENA |
|
||||
WM8994_AIF1DACR_ENA |
|
||||
WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
|
||||
} else if (aif_id == WM8994_AIF2) {
|
||||
/* Power enable for AIF2 and DAC1 */
|
||||
ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5,
|
||||
ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5,
|
||||
WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK |
|
||||
WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK,
|
||||
WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
|
||||
WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
|
||||
}
|
||||
/* Head Phone Initialisation */
|
||||
ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
|
||||
ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
|
||||
WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
|
||||
WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DC_SERVO_1,
|
||||
ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1,
|
||||
WM8994_DCS_ENA_CHAN_0_MASK |
|
||||
WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
|
||||
WM8994_DCS_ENA_CHAN_1);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
|
||||
ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
|
||||
WM8994_HPOUT1L_DLY_MASK |
|
||||
WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
|
||||
WM8994_HPOUT1R_OUTP_MASK |
|
||||
|
@ -743,172 +747,130 @@ static int wm8994_device_init(struct wm8994_priv *wm8994,
|
|||
WM8994_HPOUT1R_RMV_SHORT);
|
||||
|
||||
/* MIXER Config DAC1 to HP */
|
||||
ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1,
|
||||
WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L);
|
||||
ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1,
|
||||
WM8994_DAC1L_TO_HPOUT1L_MASK,
|
||||
WM8994_DAC1L_TO_HPOUT1L);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2,
|
||||
WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R);
|
||||
ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2,
|
||||
WM8994_DAC1R_TO_HPOUT1R_MASK,
|
||||
WM8994_DAC1R_TO_HPOUT1R);
|
||||
|
||||
if (aif_id == WM8994_AIF1) {
|
||||
/* Routing AIF1 to DAC1 */
|
||||
ret |= wm8994_i2c_write(WM8994_DAC1_LEFT_MIXER_ROUTING,
|
||||
WM8994_AIF1DAC1L_TO_DAC1L);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
|
||||
WM8994_AIF1DAC1L_TO_DAC1L);
|
||||
|
||||
ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
|
||||
ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
|
||||
WM8994_AIF1DAC1R_TO_DAC1R);
|
||||
|
||||
/* GPIO Settings for AIF1 */
|
||||
ret |= wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT
|
||||
| WM8994_GPIO_FUNCTION_I2S_CLK
|
||||
| WM8994_GPIO_INPUT_DEBOUNCE);
|
||||
ret |= wm8994_i2c_write(priv, WM8994_GPIO_1,
|
||||
WM8994_GPIO_DIR_OUTPUT |
|
||||
WM8994_GPIO_FUNCTION_I2S_CLK |
|
||||
WM8994_GPIO_INPUT_DEBOUNCE);
|
||||
|
||||
ret |= wm8994_init_volume_aif1_dac1();
|
||||
ret |= wm8994_init_volume_aif1_dac1(priv);
|
||||
} else if (aif_id == WM8994_AIF2) {
|
||||
/* Routing AIF2 to DAC1 */
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING,
|
||||
WM8994_AIF2DACL_TO_DAC1L_MASK,
|
||||
WM8994_AIF2DACL_TO_DAC1L);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
|
||||
WM8994_AIF2DACL_TO_DAC1L_MASK,
|
||||
WM8994_AIF2DACL_TO_DAC1L);
|
||||
|
||||
ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
|
||||
WM8994_AIF2DACR_TO_DAC1R_MASK,
|
||||
WM8994_AIF2DACR_TO_DAC1R);
|
||||
ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
|
||||
WM8994_AIF2DACR_TO_DAC1R_MASK,
|
||||
WM8994_AIF2DACR_TO_DAC1R);
|
||||
|
||||
/* GPIO Settings for AIF2 */
|
||||
/* B CLK */
|
||||
ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK ,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
|
||||
/* LR CLK */
|
||||
ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
|
||||
/* DATA */
|
||||
ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
|
||||
WM8994_GPIO_FUNCTION_MASK,
|
||||
WM8994_GPIO_DIR_OUTPUT);
|
||||
|
||||
ret |= wm8994_init_volume_aif2_dac1();
|
||||
ret |= wm8994_init_volume_aif2_dac1(priv);
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
debug("%s: Codec chip init ok\n", __func__);
|
||||
debug("%s: Codec chip setup ok\n", __func__);
|
||||
return 0;
|
||||
err:
|
||||
debug("%s: Codec chip init error\n", __func__);
|
||||
debug("%s: Codec chip setup error\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets fdt values for wm8994 config parameters
|
||||
*
|
||||
* @param pcodec_info codec information structure
|
||||
* @param blob FDT blob
|
||||
* @return int value, 0 for success
|
||||
*/
|
||||
static int get_codec_values(struct sound_codec_info *pcodec_info,
|
||||
const void *blob)
|
||||
static int _wm8994_init(struct wm8994_priv *priv,
|
||||
enum en_audio_interface aif_id, int sampling_rate,
|
||||
int mclk_freq, int bits_per_sample,
|
||||
unsigned int channels)
|
||||
{
|
||||
int error = 0;
|
||||
#if CONFIG_IS_ENABLED(OF_CONTROL)
|
||||
enum fdt_compat_id compat;
|
||||
int node;
|
||||
int parent;
|
||||
int ret;
|
||||
|
||||
/* Get the node from FDT for codec */
|
||||
node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC);
|
||||
if (node <= 0) {
|
||||
debug("EXYNOS_SOUND: No node for codec in device tree\n");
|
||||
debug("node = %d\n", node);
|
||||
return -1;
|
||||
}
|
||||
|
||||
parent = fdt_parent_offset(blob, node);
|
||||
if (parent < 0) {
|
||||
debug("%s: Cannot find node parent\n", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
compat = fdtdec_lookup(blob, parent);
|
||||
switch (compat) {
|
||||
case COMPAT_SAMSUNG_S3C2440_I2C:
|
||||
pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
|
||||
error |= pcodec_info->i2c_bus;
|
||||
debug("i2c bus = %d\n", pcodec_info->i2c_bus);
|
||||
pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
|
||||
"reg", 0);
|
||||
error |= pcodec_info->i2c_dev_addr;
|
||||
debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
|
||||
break;
|
||||
default:
|
||||
debug("%s: Unknown compat id %d\n", __func__, compat);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
pcodec_info->i2c_bus = AUDIO_I2C_BUS;
|
||||
pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
|
||||
debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
|
||||
#endif
|
||||
|
||||
pcodec_info->codec_type = CODEC_WM_8994;
|
||||
|
||||
if (error == -1) {
|
||||
debug("fail to get wm8994 codec node properties\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* WM8994 Device Initialisation */
|
||||
int wm8994_init(const void *blob, enum en_audio_interface aif_id,
|
||||
int sampling_rate, int mclk_freq,
|
||||
int bits_per_sample, unsigned int channels)
|
||||
{
|
||||
int ret = 0;
|
||||
struct sound_codec_info *pcodec_info = &g_codec_info;
|
||||
|
||||
/* Get the codec Values */
|
||||
if (get_codec_values(pcodec_info, blob) < 0) {
|
||||
debug("FDT Codec values failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* shift the device address by 1 for 7 bit addressing */
|
||||
g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr;
|
||||
wm8994_i2c_init(pcodec_info->i2c_bus);
|
||||
|
||||
if (pcodec_info->codec_type == CODEC_WM_8994) {
|
||||
g_wm8994_info.type = WM8994;
|
||||
} else {
|
||||
debug("%s: Codec id [%d] not defined\n", __func__,
|
||||
pcodec_info->codec_type);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = wm8994_device_init(&g_wm8994_info, aif_id);
|
||||
ret = wm8994_setup_interface(priv, aif_id);
|
||||
if (ret < 0) {
|
||||
debug("%s: wm8994 codec chip init failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1,
|
||||
mclk_freq);
|
||||
ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
|
||||
if (ret < 0) {
|
||||
debug("%s: wm8994 codec set sys clock failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
|
||||
bits_per_sample, channels);
|
||||
ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample,
|
||||
channels);
|
||||
|
||||
if (ret == 0) {
|
||||
ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S |
|
||||
SND_SOC_DAIFMT_NB_NF |
|
||||
SND_SOC_DAIFMT_CBS_CFS);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int wm8994_set_params(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample, uint channels)
|
||||
{
|
||||
struct wm8994_priv *priv = dev_get_priv(dev);
|
||||
|
||||
return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
|
||||
channels);
|
||||
}
|
||||
|
||||
static int wm8994_probe(struct udevice *dev)
|
||||
{
|
||||
struct wm8994_priv *priv = dev_get_priv(dev);
|
||||
|
||||
priv->dev = dev;
|
||||
return wm8994_device_init(priv);
|
||||
}
|
||||
|
||||
static const struct audio_codec_ops wm8994_ops = {
|
||||
.set_params = wm8994_set_params,
|
||||
};
|
||||
|
||||
static const struct udevice_id wm8994_ids[] = {
|
||||
{ .compatible = "wolfson,wm8994" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(wm8994) = {
|
||||
.name = "wm8994",
|
||||
.id = UCLASS_AUDIO_CODEC,
|
||||
.of_match = wm8994_ids,
|
||||
.probe = wm8994_probe,
|
||||
.ops = &wm8994_ops,
|
||||
.priv_auto_alloc_size = sizeof(struct wm8994_priv),
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
/* Avilable audi interface ports in wm8994 codec */
|
||||
enum en_audio_interface {
|
||||
WM8994_AIF1 = 1,
|
||||
WM8994_AIF1,
|
||||
WM8994_AIF2,
|
||||
WM8994_AIF3
|
||||
};
|
||||
|
|
48
include/audio_codec.h
Normal file
48
include/audio_codec.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#ifndef __AUDIO_CODEC_H__
|
||||
#define __AUDIO_CODEC_H__
|
||||
|
||||
/*
|
||||
* An audio codec turns digital data into sound with various parameters to
|
||||
* control its operation.
|
||||
*/
|
||||
|
||||
/* Operations for sound */
|
||||
struct audio_codec_ops {
|
||||
/**
|
||||
* set_params() - Set audio codec parameters
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @inteface: Interface number to use on codec
|
||||
* @rate: Sampling rate in Hz
|
||||
* @mclk_freq: Codec clock frequency in Hz
|
||||
* @bits_per_sample: Must be 16 or 24
|
||||
* @channels: Number of channels to use (1=mono, 2=stereo)
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*set_params)(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample, uint channels);
|
||||
};
|
||||
|
||||
#define audio_codec_get_ops(dev) ((struct audio_codec_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* audio_codec_set_params() - Set audio codec parameters
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @inteface: Interface number to use on codec
|
||||
* @rate: Sampling rate in Hz
|
||||
* @mclk_freq: Codec clock frequency in Hz
|
||||
* @bits_per_sample: Must be 16 or 24
|
||||
* @channels: Number of channels to use (1=mono, 2=stereo)
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int audio_codec_set_params(struct udevice *dev, int interface, int rate,
|
||||
int mclk_freq, int bits_per_sample, uint channels);
|
||||
|
||||
#endif /* __AUDIO_CODEC_H__ */
|
|
@ -64,6 +64,38 @@ int dev_read_u32(struct udevice *dev, const char *propname, u32 *outp);
|
|||
*/
|
||||
int dev_read_u32_default(struct udevice *dev, const char *propname, int def);
|
||||
|
||||
/**
|
||||
* dev_read_s32() - read a signed 32-bit integer from a device's DT property
|
||||
*
|
||||
* @dev: device to read DT property from
|
||||
* @propname: name of the property to read from
|
||||
* @outp: place to put value (if found)
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp);
|
||||
|
||||
/**
|
||||
* dev_read_s32_default() - read a signed 32-bit int from a device's DT property
|
||||
*
|
||||
* @dev: device to read DT property from
|
||||
* @propname: name of the property to read from
|
||||
* @def: default value to return if the property has no value
|
||||
* @return property value, or @def if not found
|
||||
*/
|
||||
int dev_read_s32_default(struct udevice *dev, const char *propname, int def);
|
||||
|
||||
/**
|
||||
* dev_read_u32u() - read a 32-bit integer from a device's DT property
|
||||
*
|
||||
* This version uses a standard uint type.
|
||||
*
|
||||
* @dev: device to read DT property from
|
||||
* @propname: name of the property to read from
|
||||
* @outp: place to put value (if found)
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp);
|
||||
|
||||
/**
|
||||
* dev_read_string() - Read a string from a device's DT property
|
||||
*
|
||||
|
@ -492,6 +524,32 @@ static inline int dev_read_u32_default(struct udevice *dev,
|
|||
return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
|
||||
}
|
||||
|
||||
static inline int dev_read_s32(struct udevice *dev,
|
||||
const char *propname, s32 *outp)
|
||||
{
|
||||
return ofnode_read_s32(dev_ofnode(dev), propname, outp);
|
||||
}
|
||||
|
||||
static inline int dev_read_s32_default(struct udevice *dev,
|
||||
const char *propname, int def)
|
||||
{
|
||||
return ofnode_read_s32_default(dev_ofnode(dev), propname, def);
|
||||
}
|
||||
|
||||
static inline int dev_read_u32u(struct udevice *dev,
|
||||
const char *propname, uint *outp)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
*outp = val;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline const char *dev_read_string(struct udevice *dev,
|
||||
const char *propname)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ enum uclass_id {
|
|||
/* U-Boot uclasses start here - in alphabetical order */
|
||||
UCLASS_ADC, /* Analog-to-digital converter */
|
||||
UCLASS_AHCI, /* SATA disk controller */
|
||||
UCLASS_AUDIO_CODEC, /* Audio codec with control and data path */
|
||||
UCLASS_AXI, /* AXI bus */
|
||||
UCLASS_BLK, /* Block device */
|
||||
UCLASS_BOARD, /* Device information from hardware */
|
||||
|
@ -48,6 +49,7 @@ enum uclass_id {
|
|||
UCLASS_I2C_EEPROM, /* I2C EEPROM device */
|
||||
UCLASS_I2C_GENERIC, /* Generic I2C device */
|
||||
UCLASS_I2C_MUX, /* I2C multiplexer */
|
||||
UCLASS_I2S, /* I2S bus */
|
||||
UCLASS_IDE, /* IDE device */
|
||||
UCLASS_IRQ, /* Interrupt controller */
|
||||
UCLASS_KEYBOARD, /* Keyboard input device */
|
||||
|
@ -82,6 +84,7 @@ enum uclass_id {
|
|||
UCLASS_SERIAL, /* Serial UART */
|
||||
UCLASS_SIMPLE_BUS, /* Bus with child devices */
|
||||
UCLASS_SMEM, /* Shared memory interface */
|
||||
UCLASS_SOUND, /* Playing simple sounds */
|
||||
UCLASS_SPI, /* SPI bus */
|
||||
UCLASS_SPI_FLASH, /* SPI flash */
|
||||
UCLASS_SPI_GENERIC, /* Generic SPI flash target */
|
||||
|
|
|
@ -76,7 +76,7 @@ struct i2s_reg {
|
|||
};
|
||||
|
||||
/* This structure stores the i2s related information */
|
||||
struct i2stx_info {
|
||||
struct i2s_uc_priv {
|
||||
unsigned int rfs; /* LR clock frame size */
|
||||
unsigned int bfs; /* Bit slock frame size */
|
||||
unsigned int audio_pll_clk; /* Audio pll frequency in Hz */
|
||||
|
@ -87,17 +87,41 @@ struct i2stx_info {
|
|||
unsigned int id; /* I2S controller id */
|
||||
};
|
||||
|
||||
/* Operations for i2s devices */
|
||||
struct i2s_ops {
|
||||
/**
|
||||
* tx_data() - Transmit audio data
|
||||
*
|
||||
* @dev: I2C device
|
||||
* @data: Data buffer to play
|
||||
* @data_size: Size of data buffer in bytes
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*tx_data)(struct udevice *dev, void *data, uint data_size);
|
||||
};
|
||||
|
||||
#define i2s_get_ops(dev) ((struct i2s_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* i2s_tx_data() - Transmit audio data
|
||||
*
|
||||
* @dev: I2C device
|
||||
* @data: Data buffer to play
|
||||
* @data_size: Size of data buffer in bytes
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int i2s_tx_data(struct udevice *dev, void *data, uint data_size);
|
||||
|
||||
/*
|
||||
* Sends the given data through i2s tx
|
||||
*
|
||||
* @param pi2s_tx pointer of i2s transmitter parameter structure.
|
||||
* @param data address of the data buffer
|
||||
* @param data_size array size of the int buffer (total size / size of int)
|
||||
*
|
||||
* @param data_size size of the data (in bytes)
|
||||
* @return int value 0 for success, -1 in case of error
|
||||
*/
|
||||
int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data,
|
||||
unsigned long data_size);
|
||||
int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
|
||||
uint data_size);
|
||||
|
||||
/*
|
||||
* Initialise i2s transmiter
|
||||
|
@ -106,6 +130,6 @@ int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data,
|
|||
*
|
||||
* @return int value 0 for success, -1 in case of error
|
||||
*/
|
||||
int i2s_tx_init(struct i2stx_info *pi2s_tx);
|
||||
int i2s_tx_init(struct i2s_uc_priv *pi2s_tx);
|
||||
|
||||
#endif /* __I2S_H__ */
|
||||
|
|
|
@ -7,14 +7,6 @@
|
|||
#ifndef __SOUND_H__
|
||||
#define __SOUND_H__
|
||||
|
||||
/* sound codec enum */
|
||||
enum en_sound_codec {
|
||||
CODEC_WM_8994,
|
||||
CODEC_WM_8995,
|
||||
CODEC_MAX_98095,
|
||||
CODEC_MAX
|
||||
};
|
||||
|
||||
/* sound codec enum */
|
||||
enum sound_compat {
|
||||
AUDIO_COMPAT_SPI,
|
||||
|
@ -25,33 +17,81 @@ enum sound_compat {
|
|||
struct sound_codec_info {
|
||||
int i2c_bus;
|
||||
int i2c_dev_addr;
|
||||
enum en_sound_codec codec_type;
|
||||
};
|
||||
|
||||
/*
|
||||
/**
|
||||
* struct sound_uc_priv - private uclass information about each sound device
|
||||
*
|
||||
* This is used to line the codec and i2s together
|
||||
*
|
||||
* @codec: Codec that is used for this sound device
|
||||
* @i2s: I2S bus that is used for this sound device
|
||||
* @setup_done: true if setup() has been called
|
||||
*/
|
||||
struct sound_uc_priv {
|
||||
struct udevice *codec;
|
||||
struct udevice *i2s;
|
||||
int setup_done;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates square wave sound data for 1 second
|
||||
*
|
||||
* @param sample_rate Sample rate in Hz
|
||||
* @param data data buffer pointer
|
||||
* @param size size of the buffer
|
||||
* @param freq frequency of the wave
|
||||
* @sample_rate: Sample rate in Hz
|
||||
* @data: data buffer pointer
|
||||
* @size: size of the buffer in bytes
|
||||
* @freq: frequency of the wave
|
||||
* @channels: Number of channels to use
|
||||
*/
|
||||
void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
|
||||
uint freq);
|
||||
uint freq, uint channels);
|
||||
|
||||
/*
|
||||
* Initialises audio sub system
|
||||
* @param blob Pointer of device tree node or NULL if none.
|
||||
* @return int value 0 for success, -1 for error
|
||||
* The sound uclass brings together a data transport (currently only I2C) and a
|
||||
* codec (currently connected over I2C).
|
||||
*/
|
||||
int sound_init(const void *blob);
|
||||
|
||||
/*
|
||||
* plays the pcm data buffer in pcm_data.h through i2s1 to make the
|
||||
* sine wave sound
|
||||
/* Operations for sound */
|
||||
struct sound_ops {
|
||||
/**
|
||||
* setup() - Set up to play a sound
|
||||
*/
|
||||
int (*setup)(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* play() - Play a beep
|
||||
*
|
||||
* @dev: Sound device
|
||||
* @data: Data buffer to play
|
||||
* @data_size: Size of data buffer in bytes
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*play)(struct udevice *dev, void *data, uint data_size);
|
||||
};
|
||||
|
||||
#define sound_get_ops(dev) ((struct sound_ops *)(dev)->driver->ops)
|
||||
|
||||
/**
|
||||
* setup() - Set up to play a sound
|
||||
*/
|
||||
int sound_setup(struct udevice *dev);
|
||||
|
||||
/**
|
||||
* play() - Play a beep
|
||||
*
|
||||
* @return int 0 for success, -1 for error
|
||||
* @dev: Sound device
|
||||
* @msecs: Duration of beep in milliseconds
|
||||
* @frequency_hz: Frequency of the beep in Hertz
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int sound_play(uint32_t msec, uint32_t frequency);
|
||||
int sound_beep(struct udevice *dev, int msecs, int frequency_hz);
|
||||
|
||||
/**
|
||||
* sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s
|
||||
*
|
||||
* This finds the audio codec and i2s devices and puts them in the uclass's
|
||||
* private data for this device.
|
||||
*/
|
||||
int sound_find_codec_i2s(struct udevice *dev);
|
||||
|
||||
#endif /* __SOUND__H__ */
|
||||
|
|
|
@ -13,6 +13,7 @@ obj-$(CONFIG_UT_DM) += test-uclass.o
|
|||
# subsystem you must add sandbox tests here.
|
||||
obj-$(CONFIG_UT_DM) += core.o
|
||||
ifneq ($(CONFIG_SANDBOX),)
|
||||
obj-$(CONFIG_SOUND) += audio.o
|
||||
obj-$(CONFIG_BLK) += blk.o
|
||||
obj-$(CONFIG_BOARD) += board.o
|
||||
obj-$(CONFIG_CLK) += clk.o
|
||||
|
@ -21,6 +22,7 @@ obj-$(CONFIG_FIRMWARE) += firmware.o
|
|||
obj-$(CONFIG_DM_GPIO) += gpio.o
|
||||
obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
|
||||
obj-$(CONFIG_DM_I2C) += i2c.o
|
||||
obj-$(CONFIG_SOUND) += i2s.o
|
||||
obj-$(CONFIG_LED) += led.o
|
||||
obj-$(CONFIG_DM_MAILBOX) += mailbox.o
|
||||
obj-$(CONFIG_DM_MMC) += mmc.o
|
||||
|
@ -53,6 +55,7 @@ obj-$(CONFIG_AXI) += axi.o
|
|||
obj-$(CONFIG_MISC) += misc.o
|
||||
obj-$(CONFIG_DM_SERIAL) += serial.o
|
||||
obj-$(CONFIG_CPU) += cpu.o
|
||||
obj-$(CONFIG_SOUND) += sound.o
|
||||
obj-$(CONFIG_TEE) += tee.o
|
||||
obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
|
||||
obj-$(CONFIG_DMA) += dma.o
|
||||
|
|
34
test/dm/audio.c
Normal file
34
test/dm/audio.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <audio_codec.h>
|
||||
#include <dm.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/ut.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
/* Basic test of the audio codec uclass */
|
||||
static int dm_test_audio(struct unit_test_state *uts)
|
||||
{
|
||||
int interface, rate, mclk_freq, bits_per_sample;
|
||||
struct udevice *dev;
|
||||
uint channels;
|
||||
|
||||
/* check probe success */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_AUDIO_CODEC, &dev));
|
||||
ut_assertok(audio_codec_set_params(dev, 1, 2, 3, 4, 5));
|
||||
sandbox_get_codec_params(dev, &interface, &rate, &mclk_freq,
|
||||
&bits_per_sample, &channels);
|
||||
ut_asserteq(1, interface);
|
||||
ut_asserteq(2, rate);
|
||||
ut_asserteq(3, mclk_freq);
|
||||
ut_asserteq(4, bits_per_sample);
|
||||
ut_asserteq(5, channels);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_audio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
32
test/dm/i2s.c
Normal file
32
test/dm/i2s.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <i2s.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/ut.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
/* Basic test of the i2s codec uclass */
|
||||
static int dm_test_i2s(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
u8 data[3];
|
||||
|
||||
/* check probe success */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_I2S, &dev));
|
||||
data[0] = 1;
|
||||
data[1] = 4;
|
||||
data[2] = 6;
|
||||
ut_assertok(i2s_tx_data(dev, data, ARRAY_SIZE(data)));
|
||||
ut_asserteq(11, sandbox_get_i2s_sum(dev));
|
||||
ut_assertok(i2s_tx_data(dev, data, 1));
|
||||
ut_asserteq(12, sandbox_get_i2s_sum(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_i2s, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
34
test/dm/sound.c
Normal file
34
test/dm/sound.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Copyright 2018 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <sound.h>
|
||||
#include <dm/test.h>
|
||||
#include <test/ut.h>
|
||||
#include <asm/test.h>
|
||||
|
||||
/* Basic test of the sound codec uclass */
|
||||
static int dm_test_sound(struct unit_test_state *uts)
|
||||
{
|
||||
struct sound_uc_priv *uc_priv;
|
||||
struct udevice *dev;
|
||||
|
||||
/* check probe success */
|
||||
ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev));
|
||||
uc_priv = dev_get_uclass_priv(dev);
|
||||
ut_asserteq_str("audio-codec", uc_priv->codec->name);
|
||||
ut_asserteq_str("i2s", uc_priv->i2s->name);
|
||||
ut_asserteq(0, sandbox_get_setup_called(dev));
|
||||
|
||||
ut_assertok(sound_beep(dev, 1, 100));
|
||||
ut_asserteq(4560, sandbox_get_sound_sum(dev));
|
||||
ut_assertok(sound_beep(dev, 1, 100));
|
||||
ut_asserteq(9120, sandbox_get_sound_sum(dev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
|
@ -736,3 +736,38 @@ static int dm_test_first_child(struct unit_test_state *uts)
|
|||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_first_child, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
||||
/* Test integer functions in dm_read_...() */
|
||||
static int dm_test_read_int(struct unit_test_state *uts)
|
||||
{
|
||||
struct udevice *dev;
|
||||
u32 val32;
|
||||
s32 sval;
|
||||
uint val;
|
||||
|
||||
ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
|
||||
ut_asserteq_str("a-test", dev->name);
|
||||
ut_assertok(dev_read_u32(dev, "int-value", &val32));
|
||||
ut_asserteq(1234, val32);
|
||||
|
||||
ut_asserteq(-EINVAL, dev_read_u32(dev, "missing", &val32));
|
||||
ut_asserteq(6, dev_read_u32_default(dev, "missing", 6));
|
||||
|
||||
ut_asserteq(1234, dev_read_u32_default(dev, "int-value", 6));
|
||||
ut_asserteq(1234, val32);
|
||||
|
||||
ut_asserteq(-EINVAL, dev_read_s32(dev, "missing", &sval));
|
||||
ut_asserteq(6, dev_read_s32_default(dev, "missing", 6));
|
||||
|
||||
ut_asserteq(-1234, dev_read_s32_default(dev, "uint-value", 6));
|
||||
ut_assertok(dev_read_s32(dev, "uint-value", &sval));
|
||||
ut_asserteq(-1234, sval);
|
||||
|
||||
val = 0;
|
||||
ut_asserteq(-EINVAL, dev_read_u32u(dev, "missing", &val));
|
||||
ut_assertok(dev_read_u32u(dev, "uint-value", &val));
|
||||
ut_asserteq(-1234, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
|
||||
|
|
Loading…
Add table
Reference in a new issue