--- /dev/null
+&sound{
+ simple-audio-card,dai-link@0 {
+ reg = <0>;
+ status = "okay";
+ format = "i2s";
+ bitclock-master = <&dailink_master>;
+ frame-master = <&dailink_master>;
+
+ dailink_master:cpu {
+ sound-dai = <&i2srx_3ch>;
+ };
+
+ dailink_slave:codec {
+ sound-dai = <&pdm>;
+ };
+ };
+};
--- /dev/null
+&sound{
+ simple-audio-card,dai-link@0 {
+ reg = <0>;
+ status = "okay";
+ format = "dsp_a";
+ bitclock-master = <&dailink_master>;
+ frame-master = <&dailink_master>;
+
+ widgets =
+ "Microphone", "Mic Jack",
+ "Line", "Line In",
+ "Line", "Line Out",
+ "Speaker", "Speaker",
+ "Headphone", "Headphone Jack";
+ routing =
+ "Headphone Jack", "HP_L",
+ "Headphone Jack", "HP_R",
+ "Speaker", "SPK_LP",
+ "Speaker", "SPK_LN",
+ "LINPUT1", "Mic Jack",
+ "LINPUT3", "Mic Jack",
+ "RINPUT1", "Mic Jack",
+ "RINPUT2", "Mic Jack";
+ cpu {
+ sound-dai = <&tdm>;
+ };
+
+ dailink_master:codec {
+ sound-dai = <&wm8960>;
+ clocks = <&wm8960_mclk>;
+ clock-names = "mclk";
+ };
+ };
+};
&tdm {
pinctrl-names = "default";
pinctrl-0 = <&tdm0_pins>;
- status = "disabled";
+ status = "okay";
};
&spdif0 {
<&clkgen JH7110_TDM_CLK_AHB>,
<&clkgen JH7110_APB0>,
<&clkgen JH7110_TDM_CLK_APB>,
- <&clkgen JH7110_TDM_INTERNAL>;
+ <&clkgen JH7110_TDM_INTERNAL>,
+ <&tdm_ext>,
+ <&clkgen JH7110_TDM_CLK_TDM>,
+ <&clkgen JH7110_MCLK_INNER>;
clock-names = "clk_ahb0", "clk_tdm_ahb",
"clk_apb0", "clk_tdm_apb",
- "clk_tdm_intl";
+ "clk_tdm_internal", "clk_tdm_ext",
+ "clk_tdm", "mclk_inner";
resets = <&rstgen RSTN_U0_TDM16SLOT_AHB>,
<&rstgen RSTN_U0_TDM16SLOT_APB>,
<&rstgen RSTN_U0_TDM16SLOT_TDM>;
simple-audio-card,dai-link@0 {
reg = <0>;
- format = "left_j";
- bitclock-master = <&sndcpu0>;
- frame-master = <&sndcpu0>;
status = "okay";
-
- sndcpu0: cpu {
- sound-dai = <&pwmdac>;
- };
-
- codec {
- sound-dai = <&pwmdac_codec>;
- };
- };
-
- simple-audio-card,dai-link@1 {
- reg = <0>;
- status = "okay";
- format = "i2s";
+ format = "dsp_a";
bitclock-master = <&dailink_master>;
frame-master = <&dailink_master>;
-
- dailink_master:cpu {
- sound-dai = <&i2srx_3ch>;
+
+ widgets =
+ "Microphone", "Mic Jack",
+ "Line", "Line In",
+ "Line", "Line Out",
+ "Speaker", "Speaker",
+ "Headphone", "Headphone Jack";
+ routing =
+ "Headphone Jack", "HP_L",
+ "Headphone Jack", "HP_R",
+ "Speaker", "SPK_LP",
+ "Speaker", "SPK_LN",
+ "LINPUT1", "Mic Jack",
+ "LINPUT3", "Mic Jack",
+ "RINPUT1", "Mic Jack",
+ "RINPUT2", "Mic Jack";
+ cpu {
+ sound-dai = <&tdm>;
};
-
- dailink_slave:codec {
- sound-dai = <&pdm>;
+
+ dailink_master:codec {
+ sound-dai = <&wm8960>;
+ clocks = <&wm8960_mclk>;
+ clock-names = "mclk";
};
};
};
#clock-cells = <0>;
clock-frequency = <297000000>;
};
+
+ wm8960_mclk: wm8960_mclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
};
i2c0_pins: i2c0-pins {
i2c0-pins-scl {
- sf,pins = <PAD_GPIO36>;
- sf,pinmux = <PAD_GPIO36_FUNC_SEL 0>;
+ sf,pins = <PAD_GPIO57>;
+ sf,pinmux = <PAD_GPIO57_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1)|(GPIO_PU(1)))>;
sf,pin-gpio-dout = <GPO_LOW>;
sf,pin-gpio-doen = <OEN_I2C0_IC_CLK_OE>;
};
i2c0-pins-sda {
- sf,pins = <PAD_GPIO37>;
- sf,pinmux = <PAD_GPIO37_FUNC_SEL 0>;
+ sf,pins = <PAD_GPIO58>;
+ sf,pinmux = <PAD_GPIO58_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1)|(GPIO_PU(1)))>;
sf,pin-gpio-dout = <GPO_LOW>;
sf,pin-gpio-doen = <OEN_I2C0_IC_DATA_OE>;
};
pwmdac0_pins: pwmdac0-pins {
+/*
pwmdac0-pins-left {
sf,pins = <PAD_GPIO57>;
sf,pinmux = <PAD_GPIO57_FUNC_SEL 0>;
sf,pin-gpio-dout = <GPO_PWMDAC0_LEFT_OUTPUT>;
sf,pin-gpio-doen = <OEN_LOW>;
};
+*/
pwmdac0-pins-right {
sf,pins = <PAD_GPIO42>;
tdm0_pins: tdm0-pins {
tdm0-pins-tx {
- sf,pins = <PAD_GPIO21>;
- sf,pinmux = <PAD_GPIO21_FUNC_SEL 0>;
+ sf,pins = <PAD_GPIO44>;
+ sf,pinmux = <PAD_GPIO44_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1))>;
sf,pin-gpio-dout = <GPO_TDM0_PCM_TXD>;
sf,pin-gpio-doen = <OEN_LOW>;
};
tdm0-pins-rx {
- sf,pins = <PAD_GPIO15>;
- sf,pinmux = <PAD_GPIO15_FUNC_SEL 0>;
+ sf,pins = <PAD_GPIO61>;
+ sf,pinmux = <PAD_GPIO61_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1))>;
sf,pin-gpio-doen = <OEN_HIGH>;
sf,pin-gpio-din = <GPI_TDM0_PCM_RXD>;
};
tdm0-pins-sync {
- sf,pins = <PAD_GPIO22>;
- sf,pinmux = <PAD_GPIO22_FUNC_SEL 0>;
- sf,pin-ioconfig = <IO(GPIO_IE(1))>;
- sf,pin-gpio-dout = <GPO_TDM0_PCM_SYNCOUT>;
- sf,pin-gpio-doen = <OEN_LOW>;
- };
-
- tdm0-pins-mclk {
- sf,pins = <PAD_GPIO30>;
- sf,pinmux = <PAD_GPIO30_FUNC_SEL 0>;
+ sf,pins = <PAD_GPIO63>;
+ sf,pinmux = <PAD_GPIO63_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1))>;
- sf,pin-gpio-dout = <GPO_CRG0_MCLK_OUT>;
- sf,pin-gpio-doen = <OEN_LOW>;
+ sf,pin-gpio-doen = <OEN_HIGH>;
+ sf,pin-gpio-din = <GPI_TDM0_PCM_SYNCIN>;
};
- tdm0-pins-mst {
- sf,pins = <PAD_GPIO39>;
- sf,pinmux = <PAD_GPIO39_FUNC_SEL 0>;
+ tdm0-pins-pcmclk {
+ sf,pins = <PAD_GPIO38>;
+ sf,pinmux = <PAD_GPIO38_FUNC_SEL 0>;
sf,pin-ioconfig = <IO(GPIO_IE(1))>;
- sf,pin-gpio-dout = <GPO_TDM0_CLK_MST>;
- sf,pin-gpio-doen = <OEN_LOW>;
+ sf,pin-gpio-doen = <OEN_HIGH>;
+ sf,pin-gpio-din = <GPI_TDM0_CLK_SLV>;
};
};
i2s_clk_pins: i2s-clk0 {
+/*
i2s-clk0_mclk {
sf,pins = <PAD_GPIO58>;
sf,pinmux = <PAD_GPIO58_FUNC_SEL 0>;
sf,pin-gpio-dout = <GPO_CRG0_MCLK_OUT>;
sf,pin-gpio-doen = <OEN_LOW>;
};
+*/
};
i2stx_pins: i2stx-pins {
sf,pinmux = <PAD_GPIO37_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+/*
rgb-2-pins {
sf,pins = <PAD_GPIO38>;
sf,pinmux = <PAD_GPIO38_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+*/
rgb-3-pins {
sf,pins = <PAD_GPIO39>;
sf,pinmux = <PAD_GPIO39_FUNC_SEL 1>;
sf,pinmux = <PAD_GPIO43_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+/*
rgb-8-pins {
sf,pins = <PAD_GPIO44>;
sf,pinmux = <PAD_GPIO44_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+*/
rgb-9-pins {
sf,pins = <PAD_GPIO45>;
sf,pinmux = <PAD_GPIO45_FUNC_SEL 1>;
sf,pinmux = <PAD_GPIO56_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+/*
rgb-21-pins {
sf,pins = <PAD_GPIO57>;
sf,pinmux = <PAD_GPIO57_FUNC_SEL 1>;
sf,pinmux = <PAD_GPIO58_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+*/
rgb-23-pins {
sf,pins = <PAD_GPIO59>;
sf,pinmux = <PAD_GPIO59_FUNC_SEL 1>;
sf,pinmux = <PAD_GPIO62_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+/*
rgb-27-pins {
sf,pins = <PAD_GPIO63>;
sf,pinmux = <PAD_GPIO63_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+*/
};
inno_hdmi_pins: inno_hdmi-pins {
inno_hdmi-scl {
sf,pinmux = <PAD_GPIO37_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+/*
mipitx-3-pins {
sf,pins = <PAD_GPIO38>;
sf,pinmux = <PAD_GPIO38_FUNC_SEL 1>;
sf,pin-ioconfig = <IO(GPIO_IE(0))>;
};
+*/
mipitx-4-pins {
sf,pins = <PAD_GPIO39>;
sf,pinmux = <PAD_GPIO39_FUNC_SEL 1>;
CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
-CONFIG_SND_DESIGNWARE_I2S=y
-CONFIG_SND_DESIGNWARE_I2S_STARFIVE_JH7110=y
-CONFIG_SND_STARFIVE_PWMDAC=y
-CONFIG_SND_STARFIVE_PDM=y
+CONFIG_SND_STARFIVE_TDM=y
+CONFIG_SND_SOC_WM8960=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
{
struct dma_multi *multi = &chan->chip->multi;
u32 val;
+ int ret;
+ u32 chan_active = BIT(chan->id) << DMAC_CHAN_EN_SHIFT;
val = axi_dma_ioread32(chan->chip, multi->en.ch_en);
val &= ~(BIT(chan->id) << multi->en.ch_en_shift);
val |= BIT(chan->id) << multi->en.ch_en_we_shift;
axi_dma_iowrite32(chan->chip, multi->en.ch_en, val);
+
+ ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val,
+ !(val & chan_active), 10, 100000); //10 ms
+ if (ret == -ETIMEDOUT)
+ pr_info("dma: failed to stop\n");
}
static inline void axi_chan_enable(struct axi_dma_chan *chan)
len = vd_to_axi_desc(vdesc)->hw_desc[0].len;
completed_length = completed_blocks * len;
bytes = length - completed_length;
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+ dma_set_residue(txstate, bytes);
} else {
- bytes = vd_to_axi_desc(vdesc)->length;
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
}
- spin_unlock_irqrestore(&chan->vc.lock, flags);
- dma_set_residue(txstate, bytes);
-
return status;
}
iowrite32(val, chan->chip->apb_regs + offset);
}
+
/* Called in chan locked context */
static void axi_chan_block_xfer_start(struct axi_dma_chan *chan,
struct axi_dma_desc *first)
u32 reg_lo, reg_hi, irq_mask;
u8 lms = 0; /* Select AXI0 master for LLI fetching */
- chan->is_err = false;
if (unlikely(axi_chan_is_hw_enable(chan))) {
+ //printk(KERN_INFO ">>>>>>>>>>axi_chan_block_xfer_start\n");
dev_err(chan2dev(chan), "%s is non-idle!\n",
axi_chan_name(chan));
axi_chan_disable(chan);
- chan->is_err = true;
//return;
}
/* ASSERT: channel is idle */
if (axi_chan_is_hw_enable(chan)) {
+ printk(KERN_INFO ">>>>>>>>>>dma_chan_alloc_chan_resources\n");
dev_err(chan2dev(chan), "%s is non-idle!\n",
axi_chan_name(chan));
return -EBUSY;
/* ASSERT: channel is idle */
if (axi_chan_is_hw_enable(chan))
+ printk(KERN_INFO ">>>>>>>>>>dma_chan_free_chan_resources\n");
dev_err(dchan2dev(dchan), "%s is non-idle!\n",
axi_chan_name(chan));
unsigned long reg_value, val;
if (!chip->apb_regs) {
- dev_err(chip->dev, "apb_regs not initialized\n");
+ dev_dbg(chip->dev, "apb_regs not initialized\n");
return;
}
axi_chan_dump_lli(chan, &desc_head->hw_desc[i]);
}
-static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
+static void axi_chan_tasklet(struct tasklet_struct *t)
{
+ struct axi_dma_chan *chan = from_tasklet(chan, t, dma_tasklet);
struct virt_dma_desc *vd;
+ u32 chan_active = BIT(chan->id) << DMAC_CHAN_EN_SHIFT;
unsigned long flags;
- struct axi_dma_desc *desc;
+ u32 val;
+ int ret;
- spin_lock_irqsave(&chan->vc.lock, flags);
+ ret = readl_poll_timeout_atomic(chan->chip->regs + DMAC_CHEN, val,
+ !(val & chan_active), 10, 1000);
+ if (ret == -ETIMEDOUT)
+ dev_warn(chan2dev(chan),
+ "irq %s failed to stop\n", axi_chan_name(chan));
- axi_chan_disable(chan);
+ spin_lock_irqsave(&chan->vc.lock, flags);
/* The bad descriptor currently is in the head of vc list */
vd = vchan_next_desc(&chan->vc);
spin_unlock_irqrestore(&chan->vc.lock, flags);
return;
}
- if (chan->is_err) {
- desc = vd_to_axi_desc(vd);
- axi_chan_block_xfer_start(chan, desc);
- chan->is_err = false;
+
+ if (chan->cyclic) {
+ vchan_cyclic_callback(vd);
+ axi_chan_enable(chan);
} else {
/* Remove the completed descriptor from issued list */
list_del(&vd->node);
/* WARN about bad descriptor */
dev_err(chan2dev(chan),
- "Bad descriptor submitted for %s, cookie: %d, irq: 0x%08x\n",
- axi_chan_name(chan), vd->tx.cookie, status);
+ "Bad descriptor submitted for %s, cookie: %d\n",
+ axi_chan_name(chan), vd->tx.cookie);
axi_chan_list_dump_lli(chan, vd_to_axi_desc(vd));
vchan_cookie_complete(vd);
spin_unlock_irqrestore(&chan->vc.lock, flags);
}
+static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->vc.lock, flags);
+
+ if (unlikely(axi_chan_is_hw_enable(chan))) {
+ axi_chan_disable(chan);
+ }
+
+ tasklet_schedule(&chan->dma_tasklet);
+ spin_unlock_irqrestore(&chan->vc.lock, flags);
+}
+
static void axi_chan_block_xfer_complete(struct axi_dma_chan *chan)
{
int count = atomic_read(&chan->descs_allocated);
chan->vc.desc_free = vchan_desc_put;
vchan_init(&chan->vc, &dw->dma);
+ tasklet_setup(&chan->dma_tasklet, axi_chan_tasklet);
}
/* Set capabilities */
enum dma_transfer_direction direction;
bool fixed_burst_trans_len;
bool cyclic;
- bool is_err;
+ //bool is_err;
/* these other elements are all protected by vc.lock */
bool is_paused;
+ struct tasklet_struct dma_tasklet;
};
struct dw_axi_dma {
return -EINVAL;
}
- nmaps = size / pin_size;
+ nmaps = size / pin_size * 2;
ngroups = size / pin_size;
pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL);
}
pgnames[ngroups++] = grpname;
+ map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
+ map[nmaps].data.mux.function = np->name;
+ map[nmaps].data.mux.group = grpname;
+ nmaps += 1;
+
list = of_get_property(child, "sf,pins", &psize);
if (!list) {
info->starfive_pinctrl_parse_pin(sfp,
pins_id, pin_data, list, child);
+ map[nmaps].type = PIN_MAP_TYPE_CONFIGS_PIN;
+ map[nmaps].data.configs.group_or_pin =
+ pin_get_name(pctldev, pin_data->pin);
+ map[nmaps].data.configs.configs =
+ &pin_data->pin_config.io_config;
+ map[nmaps].data.configs.num_configs = 1;
+ nmaps += 1;
+
list++;
}
offset += i;
-
+/*
map[nmaps].type = PIN_MAP_TYPE_MUX_GROUP;
map[nmaps].data.mux.function = np->name;
map[nmaps].data.mux.group = grpname;
nmaps += 1;
-
+*/
ret = pinctrl_generic_add_group(pctldev,
grpname, pins_id, child_num_pins, pin_data);
if (ret < 0) {
dev_err(dev, "error adding group %s: %d\n", grpname, ret);
goto put_child;
}
-
+#if 0
ret = pinconf_generic_parse_dt_config(child, pctldev,
&map[nmaps].data.configs.configs,
&map[nmaps].data.configs.num_configs);
map[nmaps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
map[nmaps].data.configs.group_or_pin = grpname;
nmaps += 1;
+#endif
}
ret = pinmux_generic_add_function(pctldev, np->name, pgnames, ngroups, NULL);
#include <linux/clk.h>
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/debugfs.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include <sound/tlv.h>
#include <sound/wm8960.h>
-#include <linux/debugfs.h>
#include "wm8960.h"
-#define WM8960_MCLK 51200000//4096000
+#define WM8960_MCLK 24000000
+
/* R25 - Power 1 */
#define WM8960_VMID_MASK 0x180
#define WM8960_VREF 0x40
struct clk *mclk;
struct regmap *regmap;
int (*set_bias_level)(struct snd_soc_component *,
- enum snd_soc_bias_level level);
+ enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1;
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
"Left Data = Right ADC; Right Data = Right ADC",
"Left Data = Right ADC; Right Data = Left ADC",
};
+
static const char *wm8960_dmonomix[] = {"Stereo", "Mono"};
static const struct soc_enum wm8960_enum[] = {
if (strcmp(w->name, "OUT3 VMID") == 0)
wm8960->out3 = w;
}
-
+
return 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;
return best_freq_out;
}
+
static int wm8960_configure_clocking(struct snd_soc_component *component)
{
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
/* set iface */
snd_soc_component_write(component, WM8960_IFACE1, iface);
+ /* Temp add by walker */
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_POWER2, 0x1f8);
+ snd_soc_component_write(component, WM8960_POWER2, 0x1f9);
+ snd_soc_component_write(component, WM8960_PLL1, 0x28);
+ snd_soc_component_write(component, WM8960_PLL1, 0x38);
+ snd_soc_component_write(component, WM8960_CLOCK1, 0xdd);
+ snd_soc_component_write(component, WM8960_CLOCK2, 0x1cc);
+ snd_soc_component_write(component, WM8960_POWER3, 0x3c);
+
+ if (tx) {
+ snd_soc_component_write(component, WM8960_LOUTMIX, 0x100);
+ snd_soc_component_write(component, WM8960_ROUTMIX, 0x100);
+ snd_soc_component_write(component, WM8960_POWER3, 0xc);
+ snd_soc_component_write(component, WM8960_POWER2, 0x1f9);
+ snd_soc_component_write(component, WM8960_POWER2, 0x1f9);
+ snd_soc_component_write(component, WM8960_IFACE1, 0x3);
+ snd_soc_component_write(component, WM8960_IFACE1, 0x43);
+ snd_soc_component_write(component, WM8960_POWER1, 0xd6);
+ snd_soc_component_write(component, WM8960_POWER1, 0xc6);
+ } else {
+ snd_soc_component_write(component, WM8960_POWER3, 0x30);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_POWER3, 0x30);
+ snd_soc_component_write(component, WM8960_POWER3, 0x30);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_ADDCTL2, 0x0);
+ snd_soc_component_write(component, WM8960_IFACE1, 0x3);
+ snd_soc_component_write(component, WM8960_IFACE1, 0x43);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_LINPATH, 0x108);
+ snd_soc_component_write(component, WM8960_POWER1, 0xfe);
+ snd_soc_component_write(component, WM8960_RINPATH, 0x108);
+ }
+
+ snd_soc_component_write(component, WM8960_ADDCTL1, 0xc0);
+ snd_soc_component_write(component, WM8960_ADDCTL4, 0x0);
+ snd_soc_component_write(component, WM8960_BYPASS1, 0x0);
+ snd_soc_component_write(component, WM8960_BYPASS2, 0x0);
+ snd_soc_component_write(component, WM8960_CLASSD1, 0xf7);
+ snd_soc_component_write(component, WM8960_DACCTL1, 0x0);
+ snd_soc_component_write(component, WM8960_NOISEG, 0xf9);
+ snd_soc_component_write(component, WM8960_ALC1, 0x1bb);
+ snd_soc_component_write(component, WM8960_ALC2, 0x30);
+ /* bclk inverted */
+ snd_soc_component_update_bits(component, WM8960_IFACE1, 0x80, 0x80);
+ snd_soc_component_write(component, WM8960_POWER2, 0x1f9);
+
wm8960->is_stream_in_use[tx] = true;
if (!wm8960->is_stream_in_use[!tx])
{
struct snd_soc_component *component = dai->component;
struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component);
+
clk_id = WM8960_SYSCLK_PLL;
switch (clk_id) {
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++)
- {
+ int i, reg;
+
+ for (i = 0; i < WM8960_REG_MAX; i++) {
+ if ((i == 0xc) || (i == 0xd) || (i == 0xe) || (i == 0xf) ||
+ (i == 0x1e) || (i == 0x1f) || (i == 0x23) ||
+ (i == 0x24) || (i == 0x32))
+ continue;
reg = snd_soc_component_read(component, i);
- printk("wm8960 reg:0x%x: 0x%x\n", i, reg);
+ pr_info("reg:0x%x value:0x%x\n", i, reg);
}
return 0;
}
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);
else
wm8960->set_bias_level = wm8960_set_bias_level_out3;
- #if 1
snd_soc_component_update_bits(component, WM8960_LDAC, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_RDAC, 0x100, 0x100);
- snd_soc_component_update_bits(component, WM8960_LOUT1, 0x100, 0x100);
- snd_soc_component_update_bits(component, WM8960_ROUT1, 0x100, 0x100);
+ snd_soc_component_update_bits(component, WM8960_LOUT1, 0x100, 0x100);
+ snd_soc_component_update_bits(component, WM8960_ROUT1, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_LOUT2, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_ROUT2, 0x100, 0x100);
snd_soc_component_update_bits(component, WM8960_POWER2, 0x1fB, 0x198);
snd_soc_component_update_bits(component, WM8960_LOUTMIX, 0x1F0, 0x100);
snd_soc_component_update_bits(component, WM8960_ROUTMIX, 0x1F0, 0x100);
- snd_soc_component_update_bits(component, WM8960_LOUT1, 0x7f, 0x6f);
- snd_soc_component_update_bits(component, WM8960_ROUT1, 0x7f, 0x6f);
- snd_soc_component_update_bits(component, WM8960_LOUT2, 0x7f, 0x7f);
- snd_soc_component_update_bits(component, WM8960_ROUT2, 0x7f, 0x7f);
- #endif
+ snd_soc_component_update_bits(component, WM8960_LOUT1, 0x1ff, 0x170);
+ snd_soc_component_update_bits(component, WM8960_ROUT1, 0x1ff, 0x170);
+ snd_soc_component_update_bits(component, WM8960_LOUT2, 0x1ff, 0x170);
+ snd_soc_component_update_bits(component, WM8960_ROUT2, 0x1ff, 0x170);
+ snd_soc_component_write(component, WM8960_LDAC, 0x1e0);
+ snd_soc_component_write(component, WM8960_RDAC, 0x1e0);
+ snd_soc_component_write(component, WM8960_LADC, 0x1e0);
+ snd_soc_component_write(component, WM8960_RADC, 0x1e0);
snd_soc_add_component_controls(component, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
-
+
regmap_update_bits(wm8960->regmap, WM8960_LINPATH, 0x138, 0x138);
regmap_update_bits(wm8960->regmap, WM8960_RINPATH, 0x138, 0x138);
regmap_update_bits(wm8960->regmap, WM8960_POWER1, 0x7E, 0x7E);
regmap_update_bits(wm8960->regmap, WM8960_POWER3, 0x30, 0x30);
- regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x19F, 0x197);
- regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x19F, 0x197);
-
+ regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x1ff, 0x128);
+ regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x1ff, 0x128);
+
/* ADCLRC pin configured as GPIO. */
regmap_update_bits(wm8960->regmap, WM8960_IFACE2, 1 << 6,
wm8960->pdata.gpio_cfg[0] << 6);
MODULE_DESCRIPTION("ASoC WM8960 driver");
MODULE_AUTHOR("Liam Girdwood");
-MODULE_LICENSE("GPL");
+
#include <sound/tlv.h>
#include "starfive_tdm.h"
-#define AUDIOC_CLK (12288000)
+#define CLOCK_BASE 0x13020000UL
-static inline u32 sf_tdm_readl(struct sf_tdm_dev *tdm, u16 reg)
+static inline u32 sf_tdm_readl(struct sf_tdm_dev *dev, u16 reg)
{
- return readl_relaxed(tdm->tdm_base + reg);
+ return readl_relaxed(dev->tdm_base + reg);
}
-static inline void sf_tdm_writel(struct sf_tdm_dev *tdm, u16 reg, u32 val)
+static inline void sf_tdm_writel(struct sf_tdm_dev *dev, u16 reg, u32 val)
{
- writel_relaxed(val, tdm->tdm_base + reg);
+ writel_relaxed(val, dev->tdm_base + reg);
}
-static void sf_tdm_start(struct sf_tdm_dev *tdm, struct snd_pcm_substream *substream)
+static void sf_tdm_start(struct sf_tdm_dev *dev, struct snd_pcm_substream *substream)
{
u32 data;
-
- data = sf_tdm_readl(tdm, TDM_PCMGBCR);
- sf_tdm_writel(tdm, TDM_PCMGBCR, data | 0x1 | (0x1<<4));
+ unsigned int val;
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- sf_tdm_writel(tdm, TDM_PCMTXCR, sf_tdm_readl(tdm, TDM_PCMTXCR) | 0x1);
- else
- sf_tdm_writel(tdm, TDM_PCMRXCR, sf_tdm_readl(tdm, TDM_PCMRXCR) | 0x1);
+ data = sf_tdm_readl(dev, TDM_PCMGBCR);
+ sf_tdm_writel(dev, TDM_PCMGBCR, data | PCMGBCR_ENABLE);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val = sf_tdm_readl(dev, TDM_PCMTXCR);
+ sf_tdm_writel(dev, TDM_PCMTXCR, val | PCMTXCR_TXEN);
+ } else {
+ val = sf_tdm_readl(dev, TDM_PCMRXCR);
+ sf_tdm_writel(dev, TDM_PCMRXCR, val | PCMRXCR_RXEN);
+ }
}
-static void sf_tdm_stop(struct sf_tdm_dev*tdm, struct snd_pcm_substream *substream)
+static void sf_tdm_stop(struct sf_tdm_dev *dev, struct snd_pcm_substream *substream)
{
- if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- sf_tdm_writel(tdm, TDM_PCMTXCR, sf_tdm_readl(tdm, TDM_PCMTXCR) & 0xffe);
- else
- sf_tdm_writel(tdm, TDM_PCMRXCR, sf_tdm_readl(tdm, TDM_PCMRXCR) & 0xffe);
+ unsigned int val;
+ unsigned int bcr;
- sf_tdm_writel(tdm, TDM_PCMGBCR, sf_tdm_readl(tdm, TDM_PCMGBCR) & 0x1e);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ val = sf_tdm_readl(dev, TDM_PCMTXCR);
+ val &= ~PCMTXCR_TXEN;
+ sf_tdm_writel(dev, TDM_PCMTXCR, val);
+ } else {
+ val = sf_tdm_readl(dev, TDM_PCMRXCR);
+ val &= ~PCMRXCR_RXEN;
+ sf_tdm_writel(dev, TDM_PCMRXCR, val);
+ }
+
+ bcr = sf_tdm_readl(dev, TDM_PCMGBCR);
+ sf_tdm_writel(dev, TDM_PCMGBCR, bcr & PCMGBCR_MASK);
}
-static int sf_tdm_syncdiv(struct sf_tdm_dev *tdm)
+static int sf_tdm_syncdiv(struct sf_tdm_dev *dev)
{
u32 sl, sscale, syncdiv;
- sl = (tdm->rx.sl >= tdm->tx.sl) ? tdm->rx.sl:tdm->tx.sl;
- sscale = (tdm->rx.sscale >= tdm->tx.sscale) ? tdm->rx.sscale:tdm->tx.sscale;
- syncdiv = tdm->pcmclk / tdm->samplerate - 1;
+ sl = (dev->rx.sl >= dev->tx.sl) ? dev->rx.sl:dev->tx.sl;
+ sscale = (dev->rx.sscale >= dev->tx.sscale) ? dev->rx.sscale:dev->tx.sscale;
+ syncdiv = dev->pcmclk / dev->samplerate - 1;
if ((syncdiv + 1) < (sl * sscale)) {
pr_info("set syncdiv failed !\n");
return -1;
}
- if ((tdm->syncm == TDM_SYNCM_LONG) && ((tdm->rx.sscale <= 1) || (tdm->tx.sscale <= 1))) {
+ if ((dev->syncm == TDM_SYNCM_LONG) &&
+ ((dev->rx.sscale <= 1) || (dev->tx.sscale <= 1))) {
if ((syncdiv + 1) <= sl) {
- pr_info("set syncdiv failed ! it must be (syncdiv+1) > max[txsl, rxsl]\n");
+ pr_info("set syncdiv failed! it must be (syncdiv+1) > max[tx.sl, rx.sl]\n");
return -1;
}
}
- sf_tdm_writel(tdm, TDM_PCMDIV, syncdiv);
+ sf_tdm_writel(dev, TDM_PCMDIV, syncdiv);
return 0;
}
-static void sf_tdm_contrl(struct sf_tdm_dev *tdm)
+static void sf_tdm_contrl(struct sf_tdm_dev *dev)
{
u32 data;
- data = (tdm->clkpolity << 5) | (tdm->elm << 3) | (tdm->syncm << 2) | (tdm->mode << 1);
- sf_tdm_writel(tdm, TDM_PCMGBCR, data);
+ data = (dev->clkpolity << 5) | (dev->elm << 3) | (dev->syncm << 2) | (dev->ms_mode << 1);
+ sf_tdm_writel(dev, TDM_PCMGBCR, data);
}
-static void sf_tdm_config(struct sf_tdm_dev *tdm, struct snd_pcm_substream *substream)
+static void sf_tdm_config(struct sf_tdm_dev *dev, struct snd_pcm_substream *substream)
{
u32 datarx, datatx;
-
- sf_tdm_stop(tdm, substream);
- sf_tdm_contrl(tdm);
- sf_tdm_syncdiv(tdm);
- datarx = (tdm->rx.ifl << 11) | (tdm->rx.wl << 8) | (tdm->rx.sscale << 4) |
- (tdm->rx.sl << 2) | (tdm->rx.lrj << 1);
+ sf_tdm_stop(dev, substream);
+ sf_tdm_contrl(dev);
+ sf_tdm_syncdiv(dev);
+
+ datarx = (dev->rx.ifl << 11) | (dev->rx.wl << 8) | (dev->rx.sscale << 4) |
+ (dev->rx.sl << 2) | (dev->rx.lrj << 1);
- datatx = (tdm->tx.ifl << 11) | (tdm->tx.wl << 8) | (tdm->tx.sscale << 4) |
- (tdm->tx.sl << 2) | (tdm->tx.lrj << 1);
+ datatx = (dev->tx.ifl << 11) | (dev->tx.wl << 8) | (dev->tx.sscale << 4) |
+ (dev->tx.sl << 2) | (dev->tx.lrj << 1);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
- sf_tdm_writel(tdm, TDM_PCMTXCR, datatx);
+ sf_tdm_writel(dev, TDM_PCMTXCR, datatx);
else
- sf_tdm_writel(tdm, TDM_PCMRXCR, datarx);
-
- sf_tdm_start(tdm, substream);
+ sf_tdm_writel(dev, TDM_PCMRXCR, datarx);
}
.resume = sf_tdm_resume,
};
-static int sf_tdm_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *cpu_dai)
+static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
- struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(cpu_dai);
+ struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(dai);
+ int chan_wl, chan_sl, chan_nr;
struct snd_dmaengine_dai_dma_data *dma_data = NULL;
+ unsigned int data_width;
+ unsigned int mclk_rate;
+ int ret;
- 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;
+ dev->samplerate = params_rate(params);
+ switch (dev->samplerate) {
+ case 8000:
+ mclk_rate = 12288000;
+ dev->pcmclk = 256000;
+ break;
+ case 16000:
+ mclk_rate = 12288000;
+ dev->pcmclk = 512000;
+ break;
+ default:
+ pr_err("TDM: not support sample rate:%d\n", dev->samplerate);
+ return -EINVAL;
+ }
- snd_soc_dai_set_dma_data(cpu_dai, substream, (void *)dma_data);
+ data_width = params_width(params);
+ dev->pcmclk = 2 * dev->samplerate * data_width;
- return 0;
-}
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S8:
+ chan_wl = TDM_8BIT_WORD_LEN;
+ chan_sl = TDM_8BIT_SLOT_LEN;
+ break;
-static void sf_tdm_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- snd_soc_dai_set_dma_data(dai, substream, NULL);
-}
+ case SNDRV_PCM_FORMAT_S16_LE:
+ chan_wl = TDM_16BIT_WORD_LEN;
+ chan_sl = TDM_16BIT_SLOT_LEN;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ chan_wl = TDM_24BIT_WORD_LEN;
+ chan_sl = TDM_32BIT_SLOT_LEN;
+ break;
-static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
-{
- struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(dai);
- int chan_wl, chan_sl, chan_nr;
+ case SNDRV_PCM_FORMAT_S32_LE:
+ chan_wl = TDM_32BIT_WORD_LEN;
+ chan_sl = TDM_32BIT_SLOT_LEN;
+ break;
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S8:
- chan_wl = TDM_8BIT_WORD_LEN;
- chan_sl = TDM_8BIT_SLOT_LEN;
- break;
-
- case SNDRV_PCM_FORMAT_S16_LE:
- chan_wl = TDM_16BIT_WORD_LEN;
- chan_sl = TDM_16BIT_SLOT_LEN;
- break;
-
- case SNDRV_PCM_FORMAT_S24_LE:
- chan_wl = TDM_24BIT_WORD_LEN;
- chan_sl = TDM_32BIT_SLOT_LEN;
- break;
-
- case SNDRV_PCM_FORMAT_S32_LE:
- chan_wl = TDM_32BIT_WORD_LEN;
- chan_sl = TDM_32BIT_SLOT_LEN;
- break;
-
- default:
- dev_err(dev->dev, "tdm: unsupported PCM fmt");
- return -EINVAL;
+ default:
+ dev_err(dev->dev, "tdm: unsupported PCM fmt");
+ return -EINVAL;
}
chan_nr = params_channels(params);
switch (chan_nr) {
- case TWO_CHANNEL_SUPPORT:
- case FOUR_CHANNEL_SUPPORT:
- case SIX_CHANNEL_SUPPORT:
- case EIGHT_CHANNEL_SUPPORT:
- break;
- default:
- dev_err(dev->dev, "channel not supported\n");
- return -EINVAL;
- }
-
+ case TWO_CHANNEL_SUPPORT:
+ case FOUR_CHANNEL_SUPPORT:
+ case SIX_CHANNEL_SUPPORT:
+ case EIGHT_CHANNEL_SUPPORT:
+ break;
+ default:
+ dev_err(dev->dev, "channel not supported\n");
+ return -EINVAL;
+ }
+
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
dev->tx.wl = chan_wl;
dev->tx.sl = chan_sl;
dev->tx.sscale = chan_nr;
+ dma_data = &dev->play_dma_data;
} else {
dev->rx.wl = chan_wl;
dev->rx.sl = chan_sl;
dev->rx.sscale = chan_nr;
+ dma_data = &dev->capture_dma_data;
}
- dev->samplerate = params_rate(params);
- if (!dev->mode) {
- sf_tdm_syncdiv(dev);
+ snd_soc_dai_set_dma_data(dai, substream, dma_data);
+
+ ret = clk_set_rate(dev->clk_mclk_inner, mclk_rate);
+ if (ret) {
+ dev_info(dev->dev, "Can't set clk_mclk: %d\n", ret);
+ return ret;
}
-
- sf_tdm_config(dev, substream);
- return 0;
-}
+ ret = clk_set_rate(dev->clk_tdm_internal, dev->pcmclk);
+ if (ret) {
+ dev_info(dev->dev, "Can't set clk_tdm_internal: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_set_parent(dev->clk_tdm, dev->clk_tdm_ext);
+ if (ret) {
+ dev_info(dev->dev, "Can't set clock source for clk_tdm: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dev->clk_tdm_ahb);
+ if (ret) {
+ dev_err(dev->dev, "Failed to prepare enable clk_tdm_ahb\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(dev->clk_tdm_apb);
+ if (ret) {
+ dev_err(dev->dev, "Failed to prepare enable clk_tdm_apb\n");
+ return ret;
+ }
+
+ sf_tdm_config(dev, substream);
-static int sf_tdm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
return 0;
}
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- dev->mode = TDM_AS_SLAVE;
+ dev->ms_mode = TDM_AS_SLAVE;
break;
case SND_SOC_DAIFMT_CBS_CFS:
- dev->mode = TDM_AS_MASTER;
+ dev->ms_mode = TDM_AS_MASTER;
break;
case SND_SOC_DAIFMT_CBM_CFS:
case SND_SOC_DAIFMT_CBS_CFM:
}
static const struct snd_soc_dai_ops sf_tdm_dai_ops = {
- .startup = sf_tdm_startup,
- .shutdown = sf_tdm_shutdown,
.hw_params = sf_tdm_hw_params,
- .prepare = sf_tdm_prepare,
.trigger = sf_tdm_trigger,
.set_fmt = sf_tdm_set_fmt,
};
-static int tdm_configure_dai(struct sf_tdm_dev *dev,
- struct snd_soc_dai_driver *sf_tdm_dai,
- unsigned int rates)
+static int sf_tdm_dai_probe(struct snd_soc_dai *dai)
{
- sf_tdm_dai->playback.channels_min = TDM_MIN_CHANNEL_NUM;
- sf_tdm_dai->playback.channels_max = TDM_MAX_CHANNEL_NUM;
- sf_tdm_dai->playback.formats = SNDRV_PCM_FMTBIT_S8|SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE;
- sf_tdm_dai->playback.rates = rates;
-
- sf_tdm_dai->capture.channels_min = TDM_MIN_CHANNEL_NUM;
- sf_tdm_dai->capture.channels_max = TDM_MAX_CHANNEL_NUM;
- sf_tdm_dai->capture.formats = SNDRV_PCM_FMTBIT_S8|SNDRV_PCM_FMTBIT_S16_LE|SNDRV_PCM_FMTBIT_S24_LE|SNDRV_PCM_FMTBIT_S32_LE;
- sf_tdm_dai->capture.rates = rates;
+ struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(dai);
+ snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
+ snd_soc_dai_set_drvdata(dai, dev);
return 0;
}
-static int sf_tdm_dai_probe(struct snd_soc_dai *dai)
+#define SF_TDM_RATE (SNDRV_PCM_RATE_8000 | \
+ SNDRV_PCM_RATE_16000 | \
+ SNDRV_PCM_RATE_32000)
+
+#define SF_TDM_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
+ SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE | \
+ SNDRV_PCM_FMTBIT_S32_LE)
+
+static struct snd_soc_dai_driver sf_tdm_dai = {
+ .name = "sf_tdm",
+ .id = 0,
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SF_TDM_RATE,
+ .formats = SF_TDM_FORMATS,
+ },
+ .capture = {
+ .stream_name = "Capture",
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = SF_TDM_RATE,
+ .formats = SF_TDM_FORMATS,
+ },
+ .ops = &sf_tdm_dai_ops,
+ .probe = sf_tdm_dai_probe,
+ .symmetric_rate = 1,
+};
+
+static void tdm_init_params(struct sf_tdm_dev *dev)
{
- struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(dai);
+ dev->clkpolity = TDM_TX_RASING_RX_FALLING;
+ if (dev->frame_mode == SHORT_LATER) {
+ dev->elm = TDM_ELM_LATE;
+ dev->syncm = TDM_SYNCM_SHORT;
+ } else if (dev->frame_mode == SHORT_EARLY) {
+ dev->elm = TDM_ELM_EARLY;
+ dev->syncm = TDM_SYNCM_SHORT;
+ } else {
+ dev->elm = TDM_ELM_EARLY;
+ dev->syncm = TDM_SYNCM_LONG;
+ }
- snd_soc_dai_init_dma_data(dai, &dev->play_dma_data, &dev->capture_dma_data);
- return 0;
+ dev->ms_mode = TDM_AS_SLAVE;
+ dev->rx.ifl = dev->tx.ifl = TDM_FIFO_HALF;
+ dev->rx.wl = dev->tx.wl = TDM_16BIT_WORD_LEN;
+ dev->rx.sscale = dev->tx.sscale = 2;
+ dev->rx.lrj = dev->tx.lrj = TDM_LEFT_JUSTIFT;
+ dev->samplerate = 16000;
+ dev->pcmclk = 512000;
+
+ dev->play_dma_data.addr = TDM_FIFO;
+ dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ dev->play_dma_data.fifo_size = TDM_FIFO_DEPTH/2;
+ dev->play_dma_data.maxburst = 16;
+
+ dev->capture_dma_data.addr = TDM_FIFO;
+ dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ dev->capture_dma_data.fifo_size = TDM_FIFO_DEPTH/2;
+ dev->capture_dma_data.maxburst = 8;
}
-static int sf_tdm_clock_init(struct platform_device *pdev, struct sf_tdm_dev *dev)
+static int sf_tdm_clk_reset_init(struct platform_device *pdev, struct sf_tdm_dev *dev)
{
int ret;
+ static struct clk_bulk_data clks[] = {
+ { .id = "clk_ahb0" },
+ { .id = "clk_tdm_ahb" },
+ { .id = "clk_apb0" },
+ { .id = "clk_tdm_apb" },
+ { .id = "clk_tdm_internal" },
+ { .id = "clk_tdm_ext" },
+ { .id = "clk_tdm" },
+ { .id = "mclk_inner" },
+ };
+
+ ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get tdm clocks\n");
+ goto exit;
+ }
+
+ dev->clk_ahb0 = clks[0].clk;
+ dev->clk_tdm_ahb = clks[1].clk;
+ dev->clk_apb0 = clks[2].clk;
+ dev->clk_tdm_apb = clks[3].clk;
+ dev->clk_tdm_internal = clks[4].clk;
+ dev->clk_tdm_ext = clks[5].clk;
+ dev->clk_tdm = clks[6].clk;
+ dev->clk_mclk_inner = clks[7].clk;
+
dev->rst_ahb = devm_reset_control_get_exclusive(&pdev->dev, "tdm_ahb");
if (IS_ERR(dev->rst_ahb)) {
dev_err(&pdev->dev, "Failed to get tdm_ahb reset control\n");
- return PTR_ERR(dev->rst_ahb);
+ ret = PTR_ERR(dev->rst_ahb);
+ goto exit;
}
dev->rst_apb = devm_reset_control_get_exclusive(&pdev->dev, "tdm_apb");
if (IS_ERR(dev->rst_apb)) {
dev_err(&pdev->dev, "Failed to get tdm_apb reset control\n");
- return PTR_ERR(dev->rst_apb);
+ ret = PTR_ERR(dev->rst_apb);
+ goto exit;
}
dev->rst_tdm = devm_reset_control_get_exclusive(&pdev->dev, "tdm_rst");
if (IS_ERR(dev->rst_tdm)) {
dev_err(&pdev->dev, "Failed to get tdm_rst reset control\n");
- return PTR_ERR(dev->rst_tdm);
+ ret = PTR_ERR(dev->rst_tdm);
+ goto exit;
}
- dev->clk_ahb0 = devm_clk_get(&pdev->dev, "clk_ahb0");
- if (IS_ERR(dev->clk_ahb0)) {
- dev_err(&pdev->dev, "Failed to get clk_ahb0");
- return PTR_ERR(dev->clk_ahb0);
- }
-
- dev->clk_tdm_ahb = devm_clk_get(&pdev->dev, "clk_tdm_ahb");
- if (IS_ERR(dev->clk_tdm_ahb)) {
- dev_err(&pdev->dev, "Failed to get clk_tdm_ahb");
- return PTR_ERR(dev->clk_tdm_ahb);
+ ret = reset_control_assert(dev->rst_ahb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to assert rst_ahb\n");
+ goto exit;
}
- dev->clk_apb0 = devm_clk_get(&pdev->dev, "clk_apb0");
- if (IS_ERR(dev->clk_apb0)) {
- dev_err(&pdev->dev, "Failed to get clk_apb0");
- return PTR_ERR(dev->clk_apb0);
+ ret = reset_control_assert(dev->rst_apb);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to assert rst_apb\n");
+ goto exit;
}
- dev->clk_tdm_apb = devm_clk_get(&pdev->dev, "clk_tdm_apb");
- if (IS_ERR(dev->clk_tdm_apb)) {
- dev_err(&pdev->dev, "Failed to get clk_tdm_apb");
- return PTR_ERR(dev->clk_tdm_ahb);
+ ret = reset_control_assert(dev->rst_tdm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to assert rst_tdm\n");
+ goto exit;
}
- dev->clk_tdm_intl = devm_clk_get(&pdev->dev, "clk_tdm_intl");
- if (IS_ERR(dev->clk_tdm_intl)) {
- dev_err(&pdev->dev, "Failed to get clk_tdm_intl");
- return PTR_ERR(dev->clk_tdm_intl);
+ ret = clk_prepare_enable(dev->clk_mclk_inner);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare enable clk_mclk_inner\n");
+ goto exit;
}
ret = clk_prepare_enable(dev->clk_ahb0);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare enable clk_ahb0\n");
- goto err_clk_disable;
+ goto err_dis_ahb0;
}
ret = clk_prepare_enable(dev->clk_tdm_ahb);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_ahb\n");
- goto err_clk_disable;
+ goto err_dis_tdm_ahb;
}
ret = clk_prepare_enable(dev->clk_apb0);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare enable clk_apb0\n");
- goto err_clk_disable;
+ goto err_dis_apb0;
}
ret = clk_prepare_enable(dev->clk_tdm_apb);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_apb\n");
- goto err_clk_disable;
+ goto err_dis_tdm_apb;
}
- ret = clk_prepare_enable(dev->clk_tdm_intl);
+ ret = clk_prepare_enable(dev->clk_tdm_internal);
if (ret) {
dev_err(&pdev->dev, "Failed to prepare enable clk_tdm_intl\n");
- goto err_clk_disable;
+ goto err_dis_tdm_internal;
+ }
+
+ ret = clk_prepare_enable(dev->clk_tdm_ext);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to prepare enable clk_tdm_ext\n");
+ goto err_dis_tdm_ext;
}
ret = reset_control_deassert(dev->rst_ahb);
return 0;
err_clk_disable:
+ clk_disable_unprepare(dev->clk_tdm_ext);
+err_dis_tdm_ext:
+ clk_disable_unprepare(dev->clk_tdm_internal);
+err_dis_tdm_internal:
+ clk_disable_unprepare(dev->clk_tdm_apb);
+err_dis_tdm_apb:
+ clk_disable_unprepare(dev->clk_apb0);
+err_dis_apb0:
+ clk_disable_unprepare(dev->clk_tdm_ahb);
+err_dis_tdm_ahb:
+ clk_disable_unprepare(dev->clk_ahb0);
+err_dis_ahb0:
+ clk_disable_unprepare(dev->clk_mclk_inner);
+exit:
return ret;
}
struct sf_tdm_dev *dev;
struct resource *res;
int ret;
- struct snd_soc_dai_driver *sf_tdm_dai;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
- sf_tdm_dai = devm_kzalloc(&pdev->dev, sizeof(*sf_tdm_dai), GFP_KERNEL);
- if (!sf_tdm_dai)
- return -ENOMEM;
-
- sf_tdm_dai->ops = &sf_tdm_dai_ops;
- sf_tdm_dai->probe = sf_tdm_dai_probe;
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dev->tdm_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(dev->tdm_base))
dev->dev = &pdev->dev;
- ret = tdm_configure_dai(dev, sf_tdm_dai, SNDRV_PCM_RATE_8000_192000);
- if (ret < 0)
- return ret;
-
- dev->clkpolity = TDM_TX_RASING_RX_FALLING;
- dev->tritxen = 1;
- dev->elm = TDM_ELM_LATE;
- dev->syncm = TDM_SYNCM_SHORT;
- dev->mode = TDM_AS_MASTER;
- dev->rx.ifl = TDM_FIFO_HALF;
- dev->tx.ifl = TDM_FIFO_HALF;
- dev->rx.sscale = 1;
- dev->tx.sscale = 1;
- dev->rx.lrj = TDM_LEFT_JUSTIFT;
- dev->tx.lrj = TDM_LEFT_JUSTIFT;
-
- dev->samplerate = 16000;
- dev->pcmclk = 4096000;
-
- dev->play_dma_data.addr = res->start + TDM_TXDMA;
- dev->play_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev->play_dma_data.fifo_size = TDM_FIFO_DEPTH/2;
- dev->play_dma_data.maxburst = 16;
-
- dev->capture_dma_data.addr = res->start + TDM_RXDMA;
- dev->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- dev->capture_dma_data.fifo_size = TDM_FIFO_DEPTH/2;
- dev->capture_dma_data.maxburst = 16;
-
- ret = sf_tdm_clock_init(pdev, dev);
+ ret = sf_tdm_clk_reset_init(pdev, dev);
if (ret) {
dev_err(&pdev->dev, "failed to enable audio-tdm clock\n");
return ret;
}
- ret = sf_tdm_clock_init(pdev, dev);
- if (ret) {
- dev_err(&pdev->dev, "failed to enable audio-tdm clock\n");
- return ret;
- }
+ dev->frame_mode = SHORT_LATER;
+ tdm_init_params(dev);
dev_set_drvdata(&pdev->dev, dev);
ret = devm_snd_soc_register_component(&pdev->dev, &sf_tdm_component,
- sf_tdm_dai, 1);
+ &sf_tdm_dai, 1);
if (ret != 0) {
- dev_err(&pdev->dev, "not able to register dai\n");
+ dev_err(&pdev->dev, "failed to register dai\n");
return ret;
}
-
+
ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
if (ret) {
- dev_err(&pdev->dev, "could not register pcm: %d\n",
- ret);
+ dev_err(&pdev->dev, "could not register pcm: %d\n", ret);
return ret;
}
-
+
return 0;
}
-
static int sf_tdm_dev_remove(struct platform_device *pdev)
{
return 0;
}
static const struct of_device_id sf_tdm_of_match[] = {
- {.compatible = "starfive,sf-tdm",},
+ {.compatible = "starfive,sf-tdm",},
{}
};
MODULE_DEVICE_TABLE(of, sf_tdm_of_match);
#include <linux/types.h>
#define TDM_PCMGBCR 0x00
+ #define PCMGBCR_MASK 0x1e
+ #define PCMGBCR_ENABLE BIT(0)
+ #define PCMGBCR_TRITXEN BIT(4)
+ #define CLKPOL_BIT 5
+ #define TRITXEN_BIT 4
+ #define ELM_BIT 3
+ #define SYNCM_BIT 2
+ #define MS_BIT 1
#define TDM_PCMTXCR 0x04
+ #define PCMTXCR_TXEN BIT(0)
#define TDM_PCMRXCR 0x08
+ #define PCMRXCR_RXEN BIT(0)
+ #define PCMRXCR_RXSL_MASK 0xc
+ #define PCMRXCR_RXSL_16BIT 0x4
+ #define PCMRXCR_RXSL_32BIT 0x8
+ #define PCMRXCR_SCALE_MASK 0xf0
+ #define PCMRXCR_SCALE_1CH 0x10
#define TDM_PCMDIV 0x0c
/* DMA registers */
-#define TDM_RXDMA 0xc0
-#define TDM_TXDMA 0xd0
-
+#define TDM_FIFO 0x170c0000
#define TDM_FIFO_DEPTH 16
-#define TDM_MAX_CHANNEL_NUM 8
-#define TDM_MIN_CHANNEL_NUM 2
-
#define TWO_CHANNEL_SUPPORT 2
#define FOUR_CHANNEL_SUPPORT 4
#define SIX_CHANNEL_SUPPORT 6
#define EIGHT_CHANNEL_SUPPORT 8
-enum TDM_MODE {
+enum TDM_MASTER_SLAVE_MODE {
TDM_AS_MASTER = 0,
TDM_AS_SLAVE,
};
enum TDM_CLKPOL {
/* tx raising and rx falling */
TDM_TX_RASING_RX_FALLING = 0,
- /* tx raising and rx falling */
+ /* tx falling and rx raising */
TDM_TX_FALLING_RX_RASING,
};
+enum TDM_FRAME_MODE {
+ SHORT_EARLY = 0,
+ SHORT_LATER,
+ LONG,
+};
+
enum TDM_ELM {
/* only work while SYNCM=0 */
TDM_ELM_LATE = 0,
struct clk *clk_tdm_ahb;
struct clk *clk_apb0;
struct clk *clk_tdm_apb;
- struct clk *clk_tdm_intl;
+ struct clk *clk_tdm_internal;
+ struct clk *clk_tdm_ext;
+ struct clk *clk_tdm;
+ struct clk *clk_mclk_inner;
struct reset_control *rst_ahb;
struct reset_control *rst_apb;
struct reset_control *rst_tdm;
enum TDM_CLKPOL clkpolity;
enum TDM_ELM elm;
enum TDM_SYNCM syncm;
- enum TDM_MODE mode;
+ enum TDM_MASTER_SLAVE_MODE ms_mode;
+ enum TDM_FRAME_MODE frame_mode;
unsigned char tritxen;
tdm_chan_cfg_t tx;