status = "disabled";
};
- i2srx_3ch: i2srx-3ch@100e0000 {
+ i2srx_3ch: i2srx_3ch@100e0000 {
compatible = "snps,designware-i2srx";
reg = <0x0 0x100e0000 0x0 0x1000>;
- clocks = <&apb0clk>;
- clock-names = "i2sclk";
+ clocks = <&clkgen JH7110_APB0>,
+ <&clkgen JH7110_I2SRX0_3CH_CLK_APB>,
+ <&clkgen JH7110_I2SRX_3CH_BCLK_MST>;
+ clock-names = "apb0", "3ch-apb",
+ "3ch-bclk";
+ resets = <&rstgen RSTN_U0_I2SRX_3CH_APB>,
+ <&rstgen RSTN_U0_I2SRX_3CH_BCLK>;
+ reset-names = "rst_apb_rx", "rst_bclk_rx";
interrupts = <42>;
interrupt-names = "rx";
+ dmas = <&dma 24 1>;
+ dma-names = "rx";
#sound-dai-cells = <0>;
status = "disabled";
};
- i2stx_4ch0: i2stx-4ch0@120b0000 {
+ i2stx_4ch0: i2stx_4ch0@120b0000 {
compatible = "snps,designware-i2stx-4ch0";
reg = <0x0 0x120b0000 0x0 0x1000>;
- clocks = <&apb0clk>;
- clock-names = "i2sclk";
+ clocks = <&clkgen JH7110_MCLK_INNER>,
+ <&clkgen JH7110_I2STX_4CH0_BCLK_MST>,
+ <&clkgen JH7110_I2STX_4CH0_LRCK_MST>,
+ <&clkgen JH7110_MCLK>,
+ <&clkgen JH7110_I2STX0_4CHBCLK>,
+ <&clkgen JH7110_I2STX0_4CHLRCK>;
+ clock-names = "inner", "bclk-mst",
+ "lrck-mst", "mclk",
+ "bclk0", "lrck0";
+ resets = <&rstgen RSTN_U0_I2STX_4CH_APB>,
+ <&rstgen RSTN_U0_I2STX_4CH_BCLK>;
+ reset-names = "rst_apb0", "rst_bclk0";
interrupts = <58>;
interrupt-names = "tx";
+ dmas = <&dma 47 1>;
+ dma-names = "tx";
#sound-dai-cells = <0>;
status = "disabled";
};
- i2stx_4ch1: i2sdac1@120c0000 {
+ i2stx_4ch1: i2stx_4ch1@120c0000 {
compatible = "snps,designware-i2stx-4ch1";
reg = <0x0 0x120c0000 0x0 0x1000>;
- clocks = <&apb0clk>;
- clock-names = "i2sclk";
+ clocks = <&clkgen JH7110_MCLK_INNER>,
+ <&clkgen JH7110_I2STX_4CH1_BCLK_MST>,
+ <&clkgen JH7110_I2STX_4CH1_LRCK_MST>,
+ <&clkgen JH7110_MCLK>,
+ <&clkgen JH7110_I2STX1_4CHBCLK>,
+ <&clkgen JH7110_I2STX1_4CHLRCK>;
+ clock-names = "inner", "bclk-mst1",
+ "lrck-mst1", "mclk",
+ "bclk1", "lrck1";
+ resets = <&rstgen RSTN_U1_I2STX_4CH_APB>,
+ <&rstgen RSTN_U1_I2STX_4CH_BCLK>;
+ reset-names = "rst_apb1", "rst_bclk1";
interrupts = <59>;
interrupt-names = "tx";
+ dmas = <&dma 48 1>;
+ dma-names = "tx";
#sound-dai-cells = <0>;
status = "disabled";
};
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/wm8960.h>
+#include <linux/debugfs.h>
#include "wm8960.h"
-#define WM8960_MCLK 4096000
+#define WM8960_MCLK 51200000//4096000
/* R25 - Power 1 */
#define WM8960_VMID_MASK 0x180
#define WM8960_VREF 0x40
int freq_in;
bool is_stream_in_use[2];
struct wm8960_data pdata;
+ struct dentry *debug_file;
};
#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0)
lrclk = wm8960->lrclk;
closest = freq_in;
+ /* Judge whether the lr clock is 0, if equal to 0, there is
+ * no need to perform the following steps*/
+ if (!lrclk)
+ {
+ return 0;
+ }
+
best_freq_out = -EINVAL;
*sysclk_idx = *dac_idx = *bclk_idx = -1;
int i, j, k;
int ret;
- /*
- * For Slave mode clocking should still be configured,
- * so this if statement should be removed, but some platform
- * may not work if the sysclk is not configured, to avoid such
- * compatible issue, just add '!wm8960->sysclk' condition in
- * this if statement.
- */
- if (!(iface1 & (1 << 6)) && !wm8960->sysclk) {
- dev_warn(component->dev,
- "slave mode, but proceeding with no clock configuration\n");
+ if (!(iface1 & (1<<6))) {
+ dev_dbg(component->dev,
+ "Codec is slave mode, no need to configure clock\n");
return 0;
}
{
struct snd_soc_component *component = dai->component;
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
- clk_id = WM8960_SYSCLK_MCLK;
-
+ clk_id = WM8960_SYSCLK_PLL;
switch (clk_id) {
case WM8960_SYSCLK_MCLK:
.symmetric_rate = 1,
};
+static int wm8960_reg_debug_show(struct seq_file *s, void *data)
+{
+ struct snd_soc_component *component = s->private;
+ int i, reg;
+ for (i = 0; i < WM8960_REG_MAX; i++)
+ {
+ reg = snd_soc_component_read(component, i);
+ printk("wm8960 reg:0x%x: 0x%x\n", i, reg);
+ }
+ return 0;
+}
+DEFINE_SHOW_ATTRIBUTE(wm8960_reg_debug);
+
+static void wm8960_create_debugfs(struct snd_soc_component *component)
+{
+ struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+ wm8960->debug_file = debugfs_create_file("wm8960_reg", 0666, NULL,
+ component, &wm8960_reg_debug_fops);
+}
static int wm8960_probe(struct snd_soc_component *component)
{
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
snd_soc_add_component_controls(component, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
wm8960_add_widgets(component);
+ wm8960_create_debugfs(component);
return 0;
}
if (wm8960 == NULL)
return -ENOMEM;
- wm8960->clk_id = WM8960_SYSCLK_MCLK;
+ wm8960->clk_id = WM8960_SYSCLK_PLL;
wm8960->mclk = devm_clk_get(&i2c->dev, "mclk");
if (IS_ERR(wm8960->mclk)) {
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/dmaengine_pcm.h>
+#include <linux/reset.h>
#include "local.h"
+static const char * const rst_name[RST_AUDIO_NUM] = {
+ [RST_APB0_BUS] = "rst_apb0",
+ [RST_BCLK_0] = "rst_bclk0",
+ [RST_APB1_BUS] = "rst_apb1",
+ [RST_BCLK_1] = "rst_bclk1",
+ [RST_APB_RX] = "rst_apb_rx",
+ [RST_BCLK_RX] = "rst_bclk_rx",
+};
+
static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
{
writel(val, io_base + reg);
struct snd_soc_dai *cpu_dai)
{
struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
union dw_i2s_snd_dma_data *dma_data = NULL;
+#endif
if (!(dev->capability & DWC_I2S_RECORD) &&
(substream->stream == SNDRV_PCM_STREAM_CAPTURE))
(substream->stream == SNDRV_PCM_STREAM_PLAYBACK))
return -EINVAL;
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
dma_data = &dev->play_dma_data;
else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
dma_data = &dev->capture_dma_data;
snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
-
+#endif
return 0;
}
static void dw_i2s_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
+#ifndef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
snd_soc_dai_set_dma_data(dai, substream, NULL);
+#endif
}
static int dw_i2s_prepare(struct snd_pcm_substream *substream,
.resume = dw_i2s_resume,
};
+static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ int ret = 0;
+
+ static struct clk_bulk_data clks[] = {
+ { .id = "apb0" }, //clock-names in dts file
+ { .id = "3ch-apb" },
+ { .id = "3ch-bclk" },
+ };
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
+ if (ret) {
+ dev_err(&pdev->dev,"%s: failed to get audio_subsys clocks\n", __func__);
+ goto err_out_clock;
+ }
+ dev->clks[CLK_ADC_APB0] = clks[0].clk;
+ dev->clks[CLK_ADC_APB] = clks[1].clk;
+ dev->clks[CLK_ADC_LRCLK] = clks[2].clk;
+
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_APB0]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB0\n", __func__);
+ goto err_out_clock;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_APB]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_APB\n", __func__);
+ goto err_out_clock;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_LRCLK\n", __func__);
+ goto err_out_clock;
+ }
+
+ dev->rstc[RST_APB_RX] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB_RX]);
+ if (IS_ERR(dev->rstc[RST_APB_RX])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2srx reset control,ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB_RX]);
+ }
+
+ dev->rstc[RST_BCLK_RX] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_RX]);
+ if (IS_ERR(dev->rstc[RST_BCLK_RX])) {
+ dev_err(&pdev->dev, "%s: failed to get i2s bclk rx reset control,ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_BCLK_RX]);
+ }
+
+ reset_control_deassert(dev->rstc[RST_APB_RX]);
+ reset_control_deassert(dev->rstc[RST_BCLK_RX]);
+
+
+ return 0;
+
+err_out_clock:
+ return ret;
+}
+
+static int dw_i2stx_4ch0_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data i2sclk[] = {
+ { .id = "inner" }, //clock-names in dts file
+ { .id = "bclk-mst" },
+ { .id = "lrck-mst" },
+ { .id = "mclk" },
+ { .id = "bclk0" },
+ { .id = "lrck0" },
+ };
+
+ int ret = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+ if (ret) {
+ printk(KERN_INFO "%s: failed to get i2stx 4ch0 clocks\n", __func__);
+ return ret;
+ }
+
+ dev->clks[CLK_DAC_INNER] = i2sclk[0].clk;
+ dev->clks[CLK_DAC_BCLK_MST] = i2sclk[1].clk;
+ dev->clks[CLK_DAC_LRCLK_MST] = i2sclk[2].clk;
+ dev->clks[CLK_MCLK] = i2sclk[3].clk;
+ dev->clks[CLK_DAC_BCLK0] = i2sclk[4].clk;
+ dev->clks[CLK_DAC_LRCLK0] = i2sclk[5].clk;
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_INNER]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_INNER\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_MST]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_MST\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_MST]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_MST\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_MCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_MCLK\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK0]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK0\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK0]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK0\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ dev->rstc[RST_APB0_BUS] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB0_BUS]);
+ if (IS_ERR(dev->rstc[RST_APB0_BUS])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2stx reset control, ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB0_BUS]);
+ }
+
+ dev->rstc[RST_BCLK_0] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_0]);
+ if (IS_ERR(dev->rstc[RST_BCLK_0])) {
+ dev_err(&pdev->dev, "%s: failed to get i2s bclk0 reset control, ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_BCLK_0]);
+ }
+
+ reset_control_deassert(dev->rstc[RST_APB0_BUS]);
+ reset_control_deassert(dev->rstc[RST_BCLK_0]);
+
+err_clk_i2s:
+ return ret;
+}
+
+static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_dev *dev)
+{
+ static struct clk_bulk_data i2sclk[] = {
+ { .id = "inner" }, //clock-names in dts file
+ { .id = "bclk-mst1" },
+ { .id = "lrck-mst1" },
+ { .id = "mclk" },
+ { .id = "bclk1" },
+ { .id = "lrck1" },
+ };
+
+ int ret = 0;
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(i2sclk), i2sclk);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to get i2stx 4ch0 clocks\n", __func__);
+ return ret;
+ }
+
+ dev->clks[CLK_DAC_INNER] = i2sclk[0].clk;
+ dev->clks[CLK_DAC_BCLK_MST_1] = i2sclk[1].clk;
+ dev->clks[CLK_DAC_LRCLK_MST_1] = i2sclk[2].clk;
+ dev->clks[CLK_MCLK] = i2sclk[3].clk;
+ dev->clks[CLK_DAC_BCLK_1] = i2sclk[4].clk;
+ dev->clks[CLK_DAC_LRCLK_1] = i2sclk[5].clk;
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_INNER]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_INNER\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_MST_1]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_MST_1\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_MST_1]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_MST_1\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_MCLK]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_MCLK\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_BCLK_1]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_BCLK_1\n", __func__);
+ goto err_clk_i2s;
+ }
+
+ ret = clk_prepare_enable(dev->clks[CLK_DAC_LRCLK_1]);
+ if (ret) {
+ dev_err(&pdev->dev, "%s: failed to enable CLK_DAC_LRCLK_1\n", __func__);
+ goto err_clk_i2s;
+ }
+ dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_INNER] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_INNER]));
+ dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_BCLK_MST_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_BCLK_MST_1]));
+ dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_LRCLK_MST_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_LRCLK_MST_1]));
+ dev_dbg(&pdev->dev, "dev->clks[CLK_MCLK] = %lu \n", clk_get_rate(dev->clks[CLK_MCLK]));
+ dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_BCLK_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_BCLK_1]));
+ dev_dbg(&pdev->dev, "dev->clks[CLK_DAC_LRCLK_1] = %lu \n", clk_get_rate(dev->clks[CLK_DAC_LRCLK_1]));
+
+ dev->rstc[RST_APB1_BUS] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_APB1_BUS]);
+ if (IS_ERR(dev->rstc[RST_APB1_BUS])) {
+ dev_err(&pdev->dev, "%s: failed to get apb_i2stx reset control, ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_APB1_BUS]);
+ }
+
+ dev->rstc[RST_BCLK_1] = devm_reset_control_get_exclusive(&pdev->dev, rst_name[RST_BCLK_1]);
+ if (IS_ERR(dev->rstc[RST_BCLK_1])) {
+ dev_err(&pdev->dev, "%s: failed to get i2s bclk1 reset control, ret = %d\n", __func__);
+ return PTR_ERR(dev->rstc[RST_BCLK_1]);
+ }
+
+ reset_control_assert(dev->rstc[RST_APB1_BUS]);
+ reset_control_assert(dev->rstc[RST_BCLK_1]);
+
+ udelay(5);
+
+ reset_control_deassert(dev->rstc[RST_APB1_BUS]);
+ reset_control_deassert(dev->rstc[RST_BCLK_1]);
+
+err_clk_i2s:
+ return ret;
+}
+
/*
* The following tables allow a direct lookup of various parameters
* defined in the I2S block's configuration in terms of sound system
}
+#ifdef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
+static int dw_i2s_dai_probe(struct snd_soc_dai *dai)
+{
+ struct dw_i2s_dev *dev = snd_soc_dai_get_drvdata(dai);
+
+ snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
+ return 0;
+}
+#endif
+
static int dw_i2s_probe(struct platform_device *pdev)
{
const struct i2s_platform_data *pdata = pdev->dev.platform_data;
+ struct device_node *np = pdev->dev.of_node;
struct dw_i2s_dev *dev;
struct resource *res;
int ret, irq;
return -ENOMEM;
dw_i2s_dai->ops = &dw_i2s_dai_ops;
+#ifdef CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110
+ dw_i2s_dai->probe = dw_i2s_dai_probe;
+#endif
dev->i2s_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
if (IS_ERR(dev->i2s_base))
}
}
+ if (of_device_is_compatible(np, "snps,designware-i2srx")) { //record
+ ret = dw_i2srx_clk_init(pdev, dev);
+ if (ret < 0)
+ goto err_clk_disable;
+ } else if (of_device_is_compatible(np, "snps,designware-i2stx-4ch0")) { //playback
+ ret = dw_i2stx_4ch0_clk_init(pdev, dev);
+ if (ret < 0)
+ goto err_clk_disable;
+ } else if (of_device_is_compatible(np, "snps,designware-i2stx-4ch1")) { //playback
+ ret = dw_i2stx_4ch1_clk_init(pdev, dev);
+ if (ret < 0)
+ goto err_clk_disable;
+ }
+
dev->i2s_reg_comp1 = I2S_COMP_PARAM_1;
dev->i2s_reg_comp2 = I2S_COMP_PARAM_2;
if (pdata) {