Implement TDM driver for JH7110 SoC
authorWalker Chen <walker.chen@starfivetech.com>
Mon, 20 Jun 2022 12:54:16 +0000 (20:54 +0800)
committerWalker Chen <walker.chen@starfivetech.com>
Mon, 20 Jun 2022 12:54:16 +0000 (20:54 +0800)
Signed-off-by: Walker Chen <walker.chen@starfivetech.com>
13 files changed:
arch/riscv/boot/dts/starfive/codecs/sf_pdm.dtsi [new file with mode: 0644]
arch/riscv/boot/dts/starfive/codecs/sf_tdm.dtsi [new file with mode: 0644]
arch/riscv/boot/dts/starfive/jh7110-common.dtsi
arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/boot/dts/starfive/jh7110_clk.dtsi
arch/riscv/boot/dts/starfive/jh7110_pinctrl.dtsi
arch/riscv/configs/starfive_jh7110_defconfig
drivers/dma/dw-axi-dmac/dw-axi-dmac-platform.c
drivers/dma/dw-axi-dmac/dw-axi-dmac.h
drivers/pinctrl/starfive/pinctrl-starfive.c
sound/soc/codecs/wm8960.c
sound/soc/starfive/starfive_tdm.c [changed mode: 0644->0755]
sound/soc/starfive/starfive_tdm.h [changed mode: 0644->0755]

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 (file)
index 0000000..5037598
--- /dev/null
@@ -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 (file)
index 0000000..02f8d2b
--- /dev/null
@@ -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";
+               };
+       };
+};
index cd24d62..33acdd6 100644 (file)
 &tdm {
        pinctrl-names = "default";
        pinctrl-0 = <&tdm0_pins>;
-       status = "disabled";
+       status = "okay";
 };
 
 &spdif0 {
index ab45c33..61621ba 100644 (file)
                                 <&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";
                                };
                        };
                };
index ae7fc23..1fb3706 100644 (file)
                #clock-cells = <0>;
                clock-frequency = <297000000>;
        };
+
+       wm8960_mclk: wm8960_mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24576000>;
+       };
 };
index af0b352..0d05b3c 100644 (file)
 
        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>;
index 2ce3c67..627ba81 100644 (file)
@@ -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
index d3c2433..29d7934 100755 (executable)
@@ -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,15 +1076,22 @@ 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;
 
-       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);
@@ -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 */
index 2bc9ecf..164a2d6 100755 (executable)
@@ -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 {
index db17302..801fa3f 100644 (file)
@@ -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);
index 09f5bb2..2827428 100755 (executable)
@@ -15,6 +15,7 @@
 #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
@@ -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");
+
old mode 100644 (file)
new mode 100755 (executable)
index 4d37295..b51a6cf
 #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);
 }
 
 
@@ -117,96 +129,118 @@ 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)
+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;
 }
 
@@ -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)
+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);
@@ -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);
old mode 100644 (file)
new mode 100755 (executable)
index a42d296..2f81fcd
 #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,
 };
@@ -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;