mirror of
https://github.com/smaeul/u-boot.git
synced 2025-10-14 04:46:01 +01:00
dm: sound: Add conversion to driver model
Move the existing hardware drivers over to use driver model. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
6c986cfef4
commit
d6cadd5918
@ -62,6 +62,7 @@
|
|||||||
i2c@12C70000 {
|
i2c@12C70000 {
|
||||||
soundcodec@1a {
|
soundcodec@1a {
|
||||||
reg = <0x1a>;
|
reg = <0x1a>;
|
||||||
|
u-boot,i2c-offset-len = <2>;
|
||||||
compatible = "wolfson,wm8994-codec";
|
compatible = "wolfson,wm8994-codec";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -84,6 +84,7 @@
|
|||||||
i2c@12C70000 {
|
i2c@12C70000 {
|
||||||
soundcodec@1a {
|
soundcodec@1a {
|
||||||
reg = <0x1a>;
|
reg = <0x1a>;
|
||||||
|
u-boot,i2c-offset-len = <2>;
|
||||||
compatible = "wolfson,wm8994-codec";
|
compatible = "wolfson,wm8994-codec";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -6,9 +6,13 @@
|
|||||||
obj-$(CONFIG_SOUND) += sound.o
|
obj-$(CONFIG_SOUND) += sound.o
|
||||||
obj-$(CONFIG_DM_SOUND) += codec-uclass.o
|
obj-$(CONFIG_DM_SOUND) += codec-uclass.o
|
||||||
obj-$(CONFIG_DM_SOUND) += i2s-uclass.o
|
obj-$(CONFIG_DM_SOUND) += i2s-uclass.o
|
||||||
obj-$(CONFIG_I2S) += sound-i2s.o
|
|
||||||
obj-$(CONFIG_DM_SOUND) += sound-uclass.o
|
obj-$(CONFIG_DM_SOUND) += sound-uclass.o
|
||||||
obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
|
obj-$(CONFIG_I2S_SAMSUNG) += samsung-i2s.o
|
||||||
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
|
obj-$(CONFIG_SOUND_SANDBOX) += sandbox.o
|
||||||
|
ifdef CONFIG_DM_SOUND
|
||||||
|
obj-$(CONFIG_I2S_SAMSUNG) += samsung_sound.o
|
||||||
|
else
|
||||||
|
obj-$(CONFIG_I2S) += sound-i2s.o
|
||||||
|
endif
|
||||||
obj-$(CONFIG_SOUND_WM8994) += wm8994.o
|
obj-$(CONFIG_SOUND_WM8994) += wm8994.o
|
||||||
obj-$(CONFIG_SOUND_MAX98095) += max98095.o
|
obj-$(CONFIG_SOUND_MAX98095) += max98095.o
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <audio_codec.h>
|
||||||
|
#include <dm.h>
|
||||||
#include <div64.h>
|
#include <div64.h>
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
@ -28,6 +30,7 @@ struct max98095_priv {
|
|||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
unsigned int fmt;
|
unsigned int fmt;
|
||||||
int i2c_addr;
|
int i2c_addr;
|
||||||
|
struct udevice *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Index 0 is reserved. */
|
/* Index 0 is reserved. */
|
||||||
@ -48,7 +51,12 @@ static int max98095_i2c_write(struct max98095_priv *priv, unsigned int reg,
|
|||||||
{
|
{
|
||||||
debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
|
debug("%s: Write Addr : 0x%02X, Data : 0x%02X\n",
|
||||||
__func__, reg, data);
|
__func__, reg, data);
|
||||||
|
#ifdef CONFIG_DM_SOUND
|
||||||
|
debug("dev = %s\n", priv->dev->name);
|
||||||
|
return dm_i2c_write(priv->dev, reg, &data, 1);
|
||||||
|
#else
|
||||||
return i2c_write(priv->i2c_addr, reg, 1, &data, 1);
|
return i2c_write(priv->i2c_addr, reg, 1, &data, 1);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -65,7 +73,11 @@ static unsigned int max98095_i2c_read(struct max98095_priv *priv,
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DM_SOUND
|
||||||
|
return dm_i2c_read(priv->dev, reg, data, 1);
|
||||||
|
#else
|
||||||
ret = i2c_read(priv->i2c_addr, reg, 1, data, 1);
|
ret = i2c_read(priv->i2c_addr, reg, 1, data, 1);
|
||||||
|
#endif
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
debug("%s: Error while reading register %#04x\n",
|
debug("%s: Error while reading register %#04x\n",
|
||||||
__func__, reg);
|
__func__, reg);
|
||||||
@ -484,7 +496,7 @@ static int max98095_do_init(struct max98095_priv *priv,
|
|||||||
|
|
||||||
ret = max98095_setup_interface(priv, aif_id);
|
ret = max98095_setup_interface(priv, aif_id);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
debug("%s: max98095 codec chip init failed\n", __func__);
|
debug("%s: max98095 setup interface failed\n", __func__);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -507,6 +519,7 @@ static int max98095_do_init(struct max98095_priv *priv,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_DM_SOUND
|
||||||
static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
|
static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
|
||||||
const void *blob)
|
const void *blob)
|
||||||
{
|
{
|
||||||
@ -582,3 +595,47 @@ int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
|
|||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int max98095_set_params(struct udevice *dev, int interface, int rate,
|
||||||
|
int mclk_freq, int bits_per_sample,
|
||||||
|
uint channels)
|
||||||
|
{
|
||||||
|
struct max98095_priv *priv = dev_get_priv(dev);
|
||||||
|
|
||||||
|
return max98095_do_init(priv, interface, rate, mclk_freq,
|
||||||
|
bits_per_sample);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int max98095_probe(struct udevice *dev)
|
||||||
|
{
|
||||||
|
struct max98095_priv *priv = dev_get_priv(dev);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
priv->dev = dev;
|
||||||
|
ret = max98095_device_init(priv);
|
||||||
|
if (ret < 0) {
|
||||||
|
debug("%s: max98095 codec chip init failed\n", __func__);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct audio_codec_ops max98095_ops = {
|
||||||
|
.set_params = max98095_set_params,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct udevice_id max98095_ids[] = {
|
||||||
|
{ .compatible = "maxim,max98095" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
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 max98095_priv),
|
||||||
|
};
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <dm.h>
|
||||||
#include <i2s.h>
|
#include <i2s.h>
|
||||||
#include <sound.h>
|
#include <sound.h>
|
||||||
#include <asm/arch/clk.h>
|
#include <asm/arch/clk.h>
|
||||||
@ -255,13 +256,13 @@ static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
|
int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
|
||||||
unsigned long data_size)
|
uint data_size)
|
||||||
{
|
{
|
||||||
|
struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
|
||||||
|
u32 *ptr;
|
||||||
int i;
|
int i;
|
||||||
int start;
|
int start;
|
||||||
struct i2s_reg *i2s_reg =
|
|
||||||
(struct i2s_reg *)pi2s_tx->base_address;
|
|
||||||
|
|
||||||
if (data_size < FIFO_LENGTH) {
|
if (data_size < FIFO_LENGTH) {
|
||||||
debug("%s : Invalid data size\n", __func__);
|
debug("%s : Invalid data size\n", __func__);
|
||||||
@ -269,17 +270,17 @@ int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* fill the tx buffer before stating the tx transmit */
|
/* fill the tx buffer before stating the tx transmit */
|
||||||
for (i = 0; i < FIFO_LENGTH; i++)
|
for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
|
||||||
writel(*data++, &i2s_reg->txd);
|
writel(*ptr++, &i2s_reg->txd);
|
||||||
|
|
||||||
data_size -= FIFO_LENGTH;
|
data_size -= sizeof(*ptr) * FIFO_LENGTH;
|
||||||
i2s_txctrl(i2s_reg, I2S_TX_ON);
|
i2s_txctrl(i2s_reg, I2S_TX_ON);
|
||||||
|
|
||||||
while (data_size > 0) {
|
while (data_size > 0) {
|
||||||
start = get_timer(0);
|
start = get_timer(0);
|
||||||
if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
|
if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
|
||||||
writel(*data++, &i2s_reg->txd);
|
writel(*ptr++, &i2s_reg->txd);
|
||||||
data_size--;
|
data_size -= sizeof(*ptr);
|
||||||
} else {
|
} else {
|
||||||
if (get_timer(start) > TIMEOUT_I2S_TX) {
|
if (get_timer(start) > TIMEOUT_I2S_TX) {
|
||||||
i2s_txctrl(i2s_reg, I2S_TX_OFF);
|
i2s_txctrl(i2s_reg, I2S_TX_OFF);
|
||||||
@ -296,8 +297,8 @@ int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, unsigned int *data,
|
|||||||
int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
|
int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct i2s_reg *i2s_reg =
|
struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
|
||||||
(struct i2s_reg *)pi2s_tx->base_address;
|
|
||||||
if (pi2s_tx->id == 0) {
|
if (pi2s_tx->id == 0) {
|
||||||
/* Initialize GPIO for I2S-0 */
|
/* Initialize GPIO for I2S-0 */
|
||||||
exynos_pinmux_config(PERIPH_ID_I2S0, 0);
|
exynos_pinmux_config(PERIPH_ID_I2S0, 0);
|
||||||
@ -348,8 +349,8 @@ int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure I2s format */
|
/* Configure I2s format */
|
||||||
ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
ret = i2s_set_fmt(i2s_reg, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
|
||||||
SND_SOC_DAIFMT_CBM_CFM));
|
SND_SOC_DAIFMT_CBM_CFM);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
|
i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
|
||||||
ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
|
ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
|
||||||
@ -368,3 +369,87 @@ int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
|
|||||||
|
|
||||||
return ret;
|
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,
|
||||||
|
};
|
||||||
|
101
drivers/sound/samsung_sound.c
Normal file
101
drivers/sound/samsung_sound.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
// 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" },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
U_BOOT_DRIVER(samsung_sound) = {
|
||||||
|
.name = "samsung_sound",
|
||||||
|
.id = UCLASS_SOUND,
|
||||||
|
.of_match = samsung_sound_ids,
|
||||||
|
.probe = samsung_sound_probe,
|
||||||
|
.ops = &samsung_sound_ops,
|
||||||
|
};
|
@ -118,7 +118,10 @@ static int sandbox_i2s_probe(struct udevice *dev)
|
|||||||
uc_priv->channels = 2;
|
uc_priv->channels = 2;
|
||||||
uc_priv->id = 1;
|
uc_priv->id = 1;
|
||||||
|
|
||||||
return sandbox_sdl_sound_init();
|
/* Ignore any error here - we'll just have no sound */
|
||||||
|
sandbox_sdl_sound_init();
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sandbox_sound_setup(struct udevice *dev)
|
static int sandbox_sound_setup(struct udevice *dev)
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
* R. Chandrasekar <rcsekar@samsung.com>
|
* R. Chandrasekar <rcsekar@samsung.com>
|
||||||
*/
|
*/
|
||||||
#include <common.h>
|
#include <common.h>
|
||||||
|
#include <audio_codec.h>
|
||||||
|
#include <dm.h>
|
||||||
#include <div64.h>
|
#include <div64.h>
|
||||||
#include <fdtdec.h>
|
#include <fdtdec.h>
|
||||||
#include <i2c.h>
|
#include <i2c.h>
|
||||||
@ -39,6 +41,7 @@ struct wm8994_priv {
|
|||||||
int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */
|
int aifclk[WM8994_MAX_AIF]; /* audio interface clock in Hz */
|
||||||
struct wm8994_fll_config fll[2]; /* fll config to configure fll */
|
struct wm8994_fll_config fll[2]; /* fll config to configure fll */
|
||||||
int i2c_addr;
|
int i2c_addr;
|
||||||
|
struct udevice *dev;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* wm 8994 supported sampling rate values */
|
/* wm 8994 supported sampling rate values */
|
||||||
@ -79,7 +82,12 @@ static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
|
|||||||
val[1] = (unsigned char)(data & 0xff);
|
val[1] = (unsigned char)(data & 0xff);
|
||||||
debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data);
|
debug("Write Addr : 0x%04X, Data : 0x%04X\n", reg, data);
|
||||||
|
|
||||||
|
#ifdef CONFIG_DM_SOUND
|
||||||
|
debug("dev = %s\n", priv->dev->name);
|
||||||
|
return dm_i2c_write(priv->dev, reg, val, 2);
|
||||||
|
#else
|
||||||
return i2c_write(priv->i2c_addr, reg, 2, val, 2);
|
return i2c_write(priv->i2c_addr, reg, 2, val, 2);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -97,7 +105,11 @@ static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
|
|||||||
unsigned char val[2];
|
unsigned char val[2];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
#ifdef CONFIG_DM_SOUND
|
||||||
|
ret = dm_i2c_read(priv->dev, reg, val, 1);
|
||||||
|
#else
|
||||||
ret = i2c_read(priv->i2c_addr, reg, 2, val, 2);
|
ret = i2c_read(priv->i2c_addr, reg, 2, val, 2);
|
||||||
|
#endif
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
debug("%s: Error while reading register %#04x\n",
|
debug("%s: Error while reading register %#04x\n",
|
||||||
__func__, reg);
|
__func__, reg);
|
||||||
@ -807,6 +819,7 @@ err:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_DM_SOUND
|
||||||
/*
|
/*
|
||||||
* Gets fdt values for wm8994 config parameters
|
* Gets fdt values for wm8994 config parameters
|
||||||
*
|
*
|
||||||
@ -859,6 +872,7 @@ static int get_codec_values(struct sound_codec_info *pcodec_info,
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int _wm8994_init(struct wm8994_priv *priv,
|
static int _wm8994_init(struct wm8994_priv *priv,
|
||||||
enum en_audio_interface aif_id, int sampling_rate,
|
enum en_audio_interface aif_id, int sampling_rate,
|
||||||
@ -891,6 +905,7 @@ static int _wm8994_init(struct wm8994_priv *priv,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef CONFIG_DM_SOUND
|
||||||
/* WM8994 Device Initialisation */
|
/* WM8994 Device Initialisation */
|
||||||
int wm8994_init(const void *blob, enum en_audio_interface aif_id,
|
int wm8994_init(const void *blob, enum en_audio_interface aif_id,
|
||||||
int sampling_rate, int mclk_freq, int bits_per_sample,
|
int sampling_rate, int mclk_freq, int bits_per_sample,
|
||||||
@ -918,3 +933,39 @@ int wm8994_init(const void *blob, enum en_audio_interface aif_id,
|
|||||||
return _wm8994_init(&wm8994_info, aif_id, sampling_rate, mclk_freq,
|
return _wm8994_init(&wm8994_info, aif_id, sampling_rate, mclk_freq,
|
||||||
bits_per_sample, channels);
|
bits_per_sample, channels);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user