diff --git a/arch/riscv/boot/dts/starfive/codecs/sf_pdm.dtsi b/arch/riscv/boot/dts/starfive/codecs/sf_pdm.dtsi new file mode 100644 index 000000000000..5037598c708b --- /dev/null +++ b/arch/riscv/boot/dts/starfive/codecs/sf_pdm.dtsi @@ -0,0 +1,17 @@ +&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>; + }; + }; +}; diff --git a/arch/riscv/boot/dts/starfive/codecs/sf_tdm.dtsi b/arch/riscv/boot/dts/starfive/codecs/sf_tdm.dtsi new file mode 100644 index 000000000000..02f8d2bc4155 --- /dev/null +++ b/arch/riscv/boot/dts/starfive/codecs/sf_tdm.dtsi @@ -0,0 +1,34 @@ +&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"; + }; + }; +}; diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi index cd24d62b17cb..33acdd66f84a 100644 --- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi @@ -438,7 +438,7 @@ &tdm { pinctrl-names = "default"; pinctrl-0 = <&tdm0_pins>; - status = "disabled"; + status = "okay"; }; &spdif0 { diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi index ab45c3376552..61621baa2eff 100644 --- a/arch/riscv/boot/dts/starfive/jh7110.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi @@ -1035,10 +1035,14 @@ <&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>; @@ -1588,33 +1592,34 @@ 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"; }; }; }; diff --git a/arch/riscv/boot/dts/starfive/jh7110_clk.dtsi b/arch/riscv/boot/dts/starfive/jh7110_clk.dtsi index ae7fc2316075..1fb37069aa7f 100644 --- a/arch/riscv/boot/dts/starfive/jh7110_clk.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110_clk.dtsi @@ -117,4 +117,10 @@ #clock-cells = <0>; clock-frequency = <297000000>; }; + + wm8960_mclk: wm8960_mclk { + compatible = "fixed-clock"; + #clock-cells = <0>; + clock-frequency = <24576000>; + }; }; diff --git a/arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi b/arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi index af0b352a2225..0d05b3c95cbc 100644 --- a/arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi +++ b/arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi @@ -198,8 +198,8 @@ i2c0_pins: i2c0-pins { i2c0-pins-scl { - sf,pins = ; - sf,pinmux = ; + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; sf,pin-gpio-dout = ; sf,pin-gpio-doen = ; @@ -207,8 +207,8 @@ }; i2c0-pins-sda { - sf,pins = ; - sf,pinmux = ; + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; sf,pin-gpio-dout = ; sf,pin-gpio-doen = ; @@ -412,6 +412,7 @@ }; pwmdac0_pins: pwmdac0-pins { +/* pwmdac0-pins-left { sf,pins = ; sf,pinmux = ; @@ -419,6 +420,7 @@ sf,pin-gpio-dout = ; sf,pin-gpio-doen = ; }; +*/ pwmdac0-pins-right { sf,pins = ; @@ -449,47 +451,40 @@ tdm0_pins: tdm0-pins { tdm0-pins-tx { - sf,pins = ; - sf,pinmux = ; + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; sf,pin-gpio-dout = ; sf,pin-gpio-doen = ; }; tdm0-pins-rx { - sf,pins = ; - sf,pinmux = ; + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; sf,pin-gpio-doen = ; sf,pin-gpio-din = ; }; tdm0-pins-sync { - sf,pins = ; - sf,pinmux = ; + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; - sf,pin-gpio-dout = ; - sf,pin-gpio-doen = ; + sf,pin-gpio-doen = ; + sf,pin-gpio-din = ; }; - tdm0-pins-mclk { - sf,pins = ; - sf,pinmux = ; + tdm0-pins-pcmclk { + sf,pins = ; + sf,pinmux = ; sf,pin-ioconfig = ; - sf,pin-gpio-dout = ; - sf,pin-gpio-doen = ; - }; - - tdm0-pins-mst { - sf,pins = ; - sf,pinmux = ; - sf,pin-ioconfig = ; - sf,pin-gpio-dout = ; - sf,pin-gpio-doen = ; + sf,pin-gpio-doen = ; + sf,pin-gpio-din = ; }; }; i2s_clk_pins: i2s-clk0 { +/* i2s-clk0_mclk { sf,pins = ; sf,pinmux = ; @@ -497,6 +492,7 @@ sf,pin-gpio-dout = ; sf,pin-gpio-doen = ; }; +*/ }; i2stx_pins: i2stx-pins { @@ -937,11 +933,13 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +/* rgb-2-pins { sf,pins = ; sf,pinmux = ; sf,pin-ioconfig = ; }; +*/ rgb-3-pins { sf,pins = ; sf,pinmux = ; @@ -967,11 +965,13 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +/* rgb-8-pins { sf,pins = ; sf,pinmux = ; sf,pin-ioconfig = ; }; +*/ rgb-9-pins { sf,pins = ; sf,pinmux = ; @@ -1032,6 +1032,7 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +/* rgb-21-pins { sf,pins = ; sf,pinmux = ; @@ -1042,6 +1043,7 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +*/ rgb-23-pins { sf,pins = ; sf,pinmux = ; @@ -1062,11 +1064,13 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +/* rgb-27-pins { sf,pins = ; sf,pinmux = ; sf,pin-ioconfig = ; }; +*/ }; inno_hdmi_pins: inno_hdmi-pins { inno_hdmi-scl { @@ -1114,11 +1118,13 @@ sf,pinmux = ; sf,pin-ioconfig = ; }; +/* mipitx-3-pins { sf,pins = ; sf,pinmux = ; sf,pin-ioconfig = ; }; +*/ mipitx-4-pins { sf,pins = ; sf,pinmux = ; diff --git a/arch/riscv/configs/starfive_jh7110_defconfig b/arch/riscv/configs/starfive_jh7110_defconfig index 2ce3c67c7ebd..627ba81b99be 100644 --- a/arch/riscv/configs/starfive_jh7110_defconfig +++ b/arch/riscv/configs/starfive_jh7110_defconfig @@ -192,10 +192,8 @@ CONFIG_FRAMEBUFFER_CONSOLE=y 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 diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c index d3c2433c065f..29d79347c442 100755 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c @@ -198,11 +198,18 @@ static inline void axi_chan_disable(struct axi_dma_chan *chan) { 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) @@ -337,13 +344,12 @@ dma_chan_tx_status(struct dma_chan *dchan, dma_cookie_t cookie, 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; } @@ -380,6 +386,7 @@ static void dw_axi_dma_set_byte_halfword(struct axi_dma_chan *chan, bool set) 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) @@ -389,12 +396,11 @@ static void axi_chan_block_xfer_start(struct axi_dma_chan *chan, 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; } @@ -522,6 +528,7 @@ static int dma_chan_alloc_chan_resources(struct dma_chan *dchan) /* 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; @@ -549,6 +556,7 @@ static void dma_chan_free_chan_resources(struct dma_chan *dchan) /* 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)); @@ -572,7 +580,7 @@ static void dw_axi_dma_set_hw_channel(struct axi_dma_chan *chan, bool set) 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; } @@ -1068,16 +1076,23 @@ static void axi_chan_list_dump_lli(struct axi_dma_chan *chan, 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; + + 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)); spin_lock_irqsave(&chan->vc.lock, flags); - axi_chan_disable(chan); - /* The bad descriptor currently is in the head of vc list */ vd = vchan_next_desc(&chan->vc); if (!vd) { @@ -1086,18 +1101,18 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) 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); @@ -1109,6 +1124,20 @@ static noinline void axi_chan_handle_err(struct axi_dma_chan *chan, u32 status) 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); @@ -1537,6 +1566,7 @@ static int dw_probe(struct platform_device *pdev) chan->vc.desc_free = vchan_desc_put; vchan_init(&chan->vc, &dw->dma); + tasklet_setup(&chan->dma_tasklet, axi_chan_tasklet); } /* Set capabilities */ diff --git a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h index 2bc9ecff7af8..164a2d6fabbd 100755 --- a/drivers/dma/dw-axi-dmac/dw-axi-dmac.h +++ b/drivers/dma/dw-axi-dmac/dw-axi-dmac.h @@ -77,9 +77,10 @@ struct axi_dma_chan { 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 { diff --git a/drivers/pinctrl/starfive/pinctrl-starfive.c b/drivers/pinctrl/starfive/pinctrl-starfive.c index db17302ecf99..801fa3f940b1 100644 --- a/drivers/pinctrl/starfive/pinctrl-starfive.c +++ b/drivers/pinctrl/starfive/pinctrl-starfive.c @@ -94,7 +94,7 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, return -EINVAL; } - nmaps = size / pin_size; + nmaps = size / pin_size * 2; ngroups = size / pin_size; pgnames = devm_kcalloc(dev, ngroups, sizeof(*pgnames), GFP_KERNEL); @@ -133,6 +133,11 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, } 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) { @@ -155,22 +160,30 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, 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); @@ -187,6 +200,7 @@ static int starfive_dt_node_to_map(struct pinctrl_dev *pctldev, 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); diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c index 09f5bb2e39e7..282742863bc7 100755 --- a/sound/soc/codecs/wm8960.c +++ b/sound/soc/codecs/wm8960.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -22,11 +23,11 @@ #include #include #include -#include #include "wm8960.h" -#define WM8960_MCLK 51200000//4096000 +#define WM8960_MCLK 24000000 + /* R25 - Power 1 */ #define WM8960_VMID_MASK 0x180 #define WM8960_VREF 0x40 @@ -123,7 +124,7 @@ struct wm8960_priv { 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; @@ -153,6 +154,7 @@ static const char *wm8960_adc_data_output_sel[] = { "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[] = { @@ -514,7 +516,7 @@ static int wm8960_add_widgets(struct snd_soc_component *component) if (strcmp(w->name, "OUT3 VMID") == 0) wm8960->out3 = w; } - + return 0; } @@ -697,13 +699,6 @@ int wm8960_configure_pll(struct snd_soc_component *component, int freq_in, 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; @@ -744,6 +739,7 @@ int wm8960_configure_pll(struct snd_soc_component *component, int freq_in, return best_freq_out; } + static int wm8960_configure_clocking(struct snd_soc_component *component) { struct wm8960_priv *wm8960 = snd_soc_component_get_drvdata(component); @@ -864,6 +860,56 @@ static int wm8960_hw_params(struct snd_pcm_substream *substream, /* 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]) @@ -1290,6 +1336,7 @@ static int wm8960_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, { 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) { @@ -1351,11 +1398,15 @@ static struct snd_soc_dai_driver wm8960_dai = { 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; } @@ -1364,9 +1415,11 @@ 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); @@ -1377,21 +1430,23 @@ static int wm8960_probe(struct snd_soc_component *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)); @@ -1497,14 +1552,14 @@ static int wm8960_i2c_probe(struct i2c_client *i2c, 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); @@ -1558,4 +1613,4 @@ module_i2c_driver(wm8960_i2c_driver); MODULE_DESCRIPTION("ASoC WM8960 driver"); MODULE_AUTHOR("Liam Girdwood"); -MODULE_LICENSE("GPL"); + diff --git a/sound/soc/starfive/starfive_tdm.c b/sound/soc/starfive/starfive_tdm.c old mode 100644 new mode 100755 index 4d372957e474..b51a6cfdcded --- a/sound/soc/starfive/starfive_tdm.c +++ b/sound/soc/starfive/starfive_tdm.c @@ -18,93 +18,105 @@ #include #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); - datatx = (tdm->tx.ifl << 11) | (tdm->tx.wl << 8) | (tdm->tx.sscale << 4) | - (tdm->tx.sl << 2) | (tdm->tx.lrj << 1); + datarx = (dev->rx.ifl << 11) | (dev->rx.wl << 8) | (dev->rx.sscale << 4) | + (dev->rx.sl << 2) | (dev->rx.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); } @@ -117,99 +129,121 @@ static const struct snd_soc_component_driver sf_tdm_component = { .resume = sf_tdm_resume, }; -static int sf_tdm_startup(struct snd_pcm_substream *substream, - struct snd_soc_dai *cpu_dai) -{ - struct sf_tdm_dev *dev = snd_soc_dai_get_drvdata(cpu_dai); - struct snd_dmaengine_dai_dma_data *dma_data = NULL; - - 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); - - return 0; -} - -static void sf_tdm_shutdown(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - snd_soc_dai_set_dma_data(dai, substream, NULL); -} - - 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; + struct snd_dmaengine_dai_dma_data *dma_data = NULL; + unsigned int data_width; + unsigned int mclk_rate; + int ret; + + 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; + } + + data_width = params_width(params); + dev->pcmclk = 2 * dev->samplerate * data_width; 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_S8: + chan_wl = TDM_8BIT_WORD_LEN; + chan_sl = TDM_8BIT_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_S16_LE: + chan_wl = TDM_16BIT_WORD_LEN; + chan_sl = TDM_16BIT_SLOT_LEN; + break; - case SNDRV_PCM_FORMAT_S32_LE: - chan_wl = TDM_32BIT_WORD_LEN; - chan_sl = TDM_32BIT_SLOT_LEN; - break; + case SNDRV_PCM_FORMAT_S24_LE: + chan_wl = TDM_24BIT_WORD_LEN; + chan_sl = TDM_32BIT_SLOT_LEN; + break; - default: - dev_err(dev->dev, "tdm: unsupported PCM fmt"); - return -EINVAL; + 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; } 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; } - + + 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); return 0; } -static int sf_tdm_prepare(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - return 0; -} - static int sf_tdm_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *dai) { @@ -244,10 +278,10 @@ static int sf_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) 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: @@ -262,119 +296,193 @@ static int sf_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) } 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) -{ - 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; - - return 0; -} - static int sf_tdm_dai_probe(struct snd_soc_dai *dai) { 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_clock_init(struct platform_device *pdev, struct sf_tdm_dev *dev) +#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) +{ + 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; + } + + 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_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); + ret = reset_control_assert(dev->rst_ahb); + if (ret) { + dev_err(&pdev->dev, "failed to assert rst_ahb\n"); + goto exit; } - 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_apb); + if (ret) { + dev_err(&pdev->dev, "failed to assert rst_apb\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_tdm); + if (ret) { + dev_err(&pdev->dev, "failed to assert rst_tdm\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); - } - - 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); @@ -398,6 +506,20 @@ static int sf_tdm_clock_init(struct platform_device *pdev, struct sf_tdm_dev *de 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; } @@ -406,19 +528,11 @@ static int sf_tdm_probe(struct platform_device *pdev) 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)) @@ -426,72 +540,38 @@ static int sf_tdm_probe(struct platform_device *pdev) 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); diff --git a/sound/soc/starfive/starfive_tdm.h b/sound/soc/starfive/starfive_tdm.h old mode 100644 new mode 100755 index a42d2965402f..2f81fcd832c3 --- a/sound/soc/starfive/starfive_tdm.h +++ b/sound/soc/starfive/starfive_tdm.h @@ -16,25 +16,35 @@ #include #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, }; @@ -42,10 +52,16 @@ enum TDM_MODE { 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, @@ -103,7 +119,10 @@ struct sf_tdm_dev { 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; @@ -112,7 +131,8 @@ struct sf_tdm_dev { 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;