Merge branch 'CR_1754_usb_device_mass_storage_minda' into 'jh7110-5.15.y-devel'
authorJason Zhou <jason.zhou@starfivetech.com>
Fri, 5 Aug 2022 03:00:23 +0000 (03:00 +0000)
committerJason Zhou <jason.zhou@starfivetech.com>
Fri, 5 Aug 2022 03:00:23 +0000 (03:00 +0000)
CR_1754 usb: gadget: add usb device mass storage support

See merge request sdk/linux!341

20 files changed:
arch/riscv/boot/dts/starfive/Makefile
arch/riscv/boot/dts/starfive/codecs/sf_ac108.dtsi [new file with mode: 0644]
arch/riscv/boot/dts/starfive/jh7110-clk.dtsi
arch/riscv/boot/dts/starfive/jh7110-common.dtsi
arch/riscv/boot/dts/starfive/jh7110-evb-i2s-ac108.dts [new file with mode: 0644]
arch/riscv/boot/dts/starfive/jh7110-evb-pcie-i2s-sd.dts
arch/riscv/boot/dts/starfive/jh7110.dtsi
arch/riscv/configs/starfive_jh7110_defconfig
drivers/gpu/drm/verisilicon/inno_hdmi.c
drivers/gpu/drm/verisilicon/vs_simple_enc.c
drivers/net/phy/motorcomm.c
drivers/rtc/Kconfig
sound/soc/codecs/ac101.c [changed mode: 0644->0755]
sound/soc/codecs/ac108.c [changed mode: 0644->0755]
sound/soc/dwc/dwc-i2s.c
sound/soc/dwc/local.h
sound/soc/starfive/starfive_spdif.c
sound/soc/starfive/starfive_spdif.h
sound/soc/starfive/starfive_spdif_pcm.c
sound/soc/starfive/starfive_tdm.c

index c026fab..ed9df6b 100644 (file)
@@ -6,6 +6,7 @@ dtb-$(CONFIG_SOC_STARFIVE_JH7110) += jh7110-visionfive-v2.dtb   \
                                jh7110-evb-can-pdm-pwmdac.dtb   \
                                jh7110-evb-dvp-rgb2hdmi.dtb     \
                                jh7110-evb-pcie-i2s-sd.dtb      \
+                               jh7110-evb-i2s-ac108.dtb        \
                                jh7110-evb-spi-uart2.dtb        \
                                jh7110-evb-uart1-rgb2hdmi.dtb   \
                                jh7110-evb-uart4-emmc-spdif.dtb \
diff --git a/arch/riscv/boot/dts/starfive/codecs/sf_ac108.dtsi b/arch/riscv/boot/dts/starfive/codecs/sf_ac108.dtsi
new file mode 100644 (file)
index 0000000..42c8698
--- /dev/null
@@ -0,0 +1,34 @@
+&sound {
+       /* i2s + ac108 */
+       simple-audio-card,dai-link@0 {
+               reg = <0>;
+               format = "i2s";
+               bitclock-master = <&sndcodec1>;
+               frame-master = <&sndcodec1>;
+
+               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 = <&i2srx_3ch>;
+               };
+               sndcodec1: codec {
+                       sound-dai = <&ac108_a>;
+                       clocks = <&ac108_mclk>;
+                       clock-names = "mclk";
+               };
+       };
+};
index 1fb3706..9c9aade 100644 (file)
                #clock-cells = <0>;
                clock-frequency = <24576000>;
        };
+
+       ac108_mclk: ac108_mclk {
+               compatible = "fixed-clock";
+               #clock-cells = <0>;
+               clock-frequency = <24000000>;
+       };
 };
index 8cbe905..97be5fe 100644 (file)
 
 &gmac0 {
        status = "okay";
+       #address-cells = <1>;
+       #size-cells = <0>;
+       phy0: ethernet-phy@0 {
+               rxc_dly_en = <0>;
+               tx_delay_sel_fe = <5>;
+               tx_delay_sel = <11>;
+       };
 };
 
 &gmac1 {
        #address-cells = <1>;
        #size-cells = <0>;
        status = "okay";
-       phy0: ethernet-phy@0 {
+       phy1: ethernet-phy@1 {
                rxc-skew-ps = <1060>;
                txc-skew-ps = <1800>;
                reg = <0>;
 
 &i2srx_3ch {
        pinctrl-names = "default";
-       pinctrl-0 = <&i2srx_pins>;
+       pinctrl-0 = <&i2s_clk_pins &i2srx_pins>;
        status = "disabled";
 };
 
 
 &i2stx_4ch1 {
        pinctrl-names = "default";
-       pinctrl-0 = <&i2s_clk_pins &i2stx_pins>;
+       pinctrl-0 = <&i2stx_pins>;
        status = "disabled";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110-evb-i2s-ac108.dts b/arch/riscv/boot/dts/starfive/jh7110-evb-i2s-ac108.dts
new file mode 100644 (file)
index 0000000..3516040
--- /dev/null
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ * Copyright (C) 2022 Hal Feng <hal.feng@starfivetech.com>
+ */
+
+/dts-v1/;
+#include "jh7110-evb.dtsi"
+#include "codecs/sf_ac108.dtsi"
+
+/ {
+       model = "StarFive JH7110 EVB";
+       compatible = "starfive,jh7110-evb", "starfive,jh7110";
+};
+
+
+&i2c0 {
+       status = "okay";
+};
+
+&i2srx_3ch {
+       status = "okay";
+};
index 0ac88af..152ef0a 100644 (file)
 &i2stx_4ch1 {
        status = "okay";
 };
+
+&usbdrd30 {
+       clocks = <&clkgen JH7110_USB_125M>,
+                <&clkgen JH7110_USB0_CLK_APP_125>,
+                <&clkgen JH7110_USB0_CLK_LPM>,
+                <&clkgen JH7110_USB0_CLK_STB>,
+                <&clkgen JH7110_USB0_CLK_USB_APB>,
+                <&clkgen JH7110_USB0_CLK_AXI>,
+                <&clkgen JH7110_USB0_CLK_UTMI_APB>;
+       clock-names = "125m","app","lpm","stb","apb","axi","utmi";
+       resets = <&rstgen RSTN_U0_CDN_USB_PWRUP>,
+                <&rstgen RSTN_U0_CDN_USB_APB>,
+                <&rstgen RSTN_U0_CDN_USB_AXI>,
+                <&rstgen RSTN_U0_CDN_USB_UTMI_APB>;
+       reset-names = "pwrup","apb","axi","utmi";
+       dr_mode = "host"; /*host or peripheral*/
+       starfive,usb2-only;
+       pinctrl-names = "default";
+       pinctrl-0 = <&usb_pins>;
+       status = "okay";
+};
index 556768d..e74f1d3 100755 (executable)
                        reg = <0x0 0x100a0000 0x0 0x1000>;
                        clocks = <&clkgen JH7110_SPDIF_CLK_APB>,
                                 <&clkgen JH7110_SPDIF_CLK_CORE>,
-                                <&clkgen JH7110_APB0>,
                                 <&clkgen JH7110_AUDIO_ROOT>,
                                 <&clkgen JH7110_MCLK_INNER>;
-                       clock-names = "spdif-apb", "spdif-core", "apb0",
+                       clock-names = "spdif-apb", "spdif-core",
                                      "audroot", "mclk_inner";
                        resets = <&rstgen RSTN_U0_CDNS_SPDIF_APB>;
                        reset-names = "rst_apb";
                                 <&clkgen JH7110_I2SRX_3CH_BCLK_MST>,
                                 <&clkgen JH7110_I2SRX_3CH_LRCK_MST>,
                                 <&clkgen JH7110_I2SRX0_3CH_BCLK>,
-                                <&clkgen JH7110_I2SRX0_3CH_LRCK>;
+                                <&clkgen JH7110_I2SRX0_3CH_LRCK>,
+                                <&clkgen JH7110_MCLK>,
+                                <&i2srx_bclk_ext>,
+                                <&i2srx_lrck_ext>;
                        clock-names = "apb0", "3ch-apb",
                                        "audioroot", "mclk-inner",
                                        "bclk_mst", "3ch-lrck",
-                                       "rx-bclk", "rx-lrck";
+                                       "rx-bclk", "rx-lrck",
+                                       "mclk", "bclk-ext",
+                                       "lrck-ext";
                        resets = <&rstgen RSTN_U0_I2SRX_3CH_APB>,
                                 <&rstgen RSTN_U0_I2SRX_3CH_BCLK>;
                        dmas = <&dma 24 1>;
index b83b7c5..e6c5b74 100644 (file)
@@ -209,6 +209,7 @@ CONFIG_SND_STARFIVE_SPDIF_PCM=y
 CONFIG_SND_STARFIVE_PWMDAC=y
 CONFIG_SND_STARFIVE_PDM=y
 CONFIG_SND_STARFIVE_TDM=y
+CONFIG_SND_SOC_AC108=y
 CONFIG_SND_SOC_SPDIF=y
 CONFIG_SND_SOC_WM8960=y
 CONFIG_SND_SIMPLE_CARD=y
index 8e46de4..a42bab4 100755 (executable)
@@ -15,8 +15,8 @@
 #include <linux/mutex.h>
 #include <linux/of_device.h>
 #include <linux/component.h>
-#include<linux/reset.h>
-
+#include <linux/reset.h>
+#include <drm/drm_scdc_helper.h>
 #include <drm/bridge/dw_hdmi.h>
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_edid.h>
@@ -105,7 +105,7 @@ static const struct pre_pll_config pre_pll_cfg_table[] = {
        {148352000, 185440000, 4, 494, 0, 2, 2,  1, 3, 2, 2, 0, 0x816817},
        {148500000, 185625000, 4, 495, 0, 2, 2,  1, 3, 2, 2, 0, 0},
        {296703000, 296703000, 1,  98, 0, 1, 1,  1, 0, 2, 2, 0, 0xE6AE6B},
-       {297000000, 297000000, 1,  99, 0, 1, 1,  1, 0, 2, 2, 0, 0},
+       {297000000, 297000000, 1,  99, 1, 0, 0,  1, 2, 1, 1, 0, 0},
        {296703000, 370878750, 4, 494, 1, 2, 0,  1, 3, 1, 1, 0, 0x816817},
        {297000000, 371250000, 4, 495, 1, 2, 0,  1, 3, 1, 1, 0, 0},
        {593407000, 296703500, 1,  98, 0, 1, 1,  1, 0, 2, 1, 0, 0xE6AE6B},
@@ -118,97 +118,17 @@ static const struct pre_pll_config pre_pll_cfg_table[] = {
 };
 
 static const struct post_pll_config post_pll_cfg_table[] = {
-       {25200000,      1, 80, 7, 0,1},
-       {27000000,      1, 40, 3, 0,1},
-       {33750000,      1, 40, 8, 3,1},
+       {25200000,      1, 80, 7, 3, 1},
+       {27000000,      1, 40, 11, 3, 1},
+       {33750000,      1, 40, 8, 3, 1},
        //{33750000,    1, 80, 8, 2},
-       {74250000,      1, 20, 1, 3,1},
+       {74250000,      1, 20, 1, 3, 1},
        //{74250000, 18, 80, 8, 2},
-       {148500000, 1, 20, 1, 3,3},
-       {297000000, 2, 20, 0, 3,3},
-       {594000000, 4, 20, 0, 0,0},//postpll_postdiv_en = 0
+       {148500000, 1, 20, 1, 3, 3},
+       {297000000, 4, 20, 0, 0, 3},
+       {594000000, 4, 20, 0, 0, 0},//postpll_postdiv_en = 0
        { /* sentinel */ }
 };
-/*
-static const struct post_pll_config post_pll_cfg_table[] = {
-       {33750000,  1, 40, 8, 1},
-       {33750000,  1, 80, 8, 2},
-       {74250000,  1, 40, 8, 1},
-       {74250000, 18, 80, 8, 2},
-       {148500000, 2, 40, 4, 3},
-       {297000000, 4, 40, 2, 3},
-       {594000000, 8, 40, 1, 3},
-};
-*/
-static const char coeff_csc[][24] = {
-       /*
-        * YUV2RGB:601 SD mode(Y[16:235], UV[16:240], RGB[0:255]):
-        *   R = 1.164*Y + 1.596*V - 204
-        *   G = 1.164*Y - 0.391*U - 0.813*V + 154
-        *   B = 1.164*Y + 2.018*U - 258
-        */
-       {
-               0x04, 0xa7, 0x00, 0x00, 0x06, 0x62, 0x02, 0xcc,
-               0x04, 0xa7, 0x11, 0x90, 0x13, 0x40, 0x00, 0x9a,
-               0x04, 0xa7, 0x08, 0x12, 0x00, 0x00, 0x03, 0x02
-       },
-       /*
-        * YUV2RGB:601 SD mode(YUV[0:255],RGB[0:255]):
-        *   R = Y + 1.402*V - 248
-        *   G = Y - 0.344*U - 0.714*V + 135
-        *   B = Y + 1.772*U - 227
-        */
-       {
-               0x04, 0x00, 0x00, 0x00, 0x05, 0x9b, 0x02, 0xf8,
-               0x04, 0x00, 0x11, 0x60, 0x12, 0xdb, 0x00, 0x87,
-               0x04, 0x00, 0x07, 0x16, 0x00, 0x00, 0x02, 0xe3
-       },
-       /*
-        * YUV2RGB:709 HD mode(Y[16:235],UV[16:240],RGB[0:255]):
-        *   R = 1.164*Y + 1.793*V - 248
-        *   G = 1.164*Y - 0.213*U - 0.534*V + 77
-        *   B = 1.164*Y + 2.115*U - 289
-        */
-       {
-               0x04, 0xa7, 0x00, 0x00, 0x07, 0x2c, 0x02, 0xf8,
-               0x04, 0xa7, 0x10, 0xda, 0x12, 0x22, 0x00, 0x4d,
-               0x04, 0xa7, 0x08, 0x74, 0x00, 0x00, 0x03, 0x21
-       },
-
-       /*
-        * RGB2YUV:601 SD mode:
-        *   Cb = -0.291G - 0.148R + 0.439B + 128
-        *   Y  = 0.504G  + 0.257R + 0.098B + 16
-        *   Cr = -0.368G + 0.439R - 0.071B + 128
-        */
-       {
-               0x11, 0x5f, 0x01, 0x82, 0x10, 0x23, 0x00, 0x80,
-               0x02, 0x1c, 0x00, 0xa1, 0x00, 0x36, 0x00, 0x1e,
-               0x11, 0x29, 0x10, 0x59, 0x01, 0x82, 0x00, 0x80
-       },
-       /*
-        * RGB2YUV:709 HD mode:
-        *   Cb = - 0.338G - 0.101R + 0.439B + 128
-        *   Y  = 0.614G   + 0.183R + 0.062B + 16
-        *   Cr = - 0.399G + 0.439R - 0.040B + 128
-        */
-       {
-               0x11, 0x98, 0x01, 0xc1, 0x10, 0x28, 0x00, 0x80,
-               0x02, 0x74, 0x00, 0xbb, 0x00, 0x3f, 0x00, 0x10,
-               0x11, 0x5a, 0x10, 0x67, 0x01, 0xc1, 0x00, 0x80
-       },
-       /*
-        * RGB[0:255]2RGB[16:235]:
-        *   R' = R x (235-16)/255 + 16;
-        *   G' = G x (235-16)/255 + 16;
-        *   B' = B x (235-16)/255 + 16;
-        */
-       {
-               0x00, 0x00, 0x03, 0x6F, 0x00, 0x00, 0x00, 0x10,
-               0x03, 0x6F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
-               0x00, 0x00, 0x00, 0x00, 0x03, 0x6F, 0x00, 0x10
-       },
-};
 
 static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
 {
@@ -217,6 +137,7 @@ static inline u8 hdmi_readb(struct inno_hdmi *hdmi, u16 offset)
 
 static inline void hdmi_writeb(struct inno_hdmi *hdmi, u16 offset, u32 val)
 {
+       printk("write: addr 0x%02x, val 0x%02x\n",offset,val);
        writel_relaxed(val, hdmi->regs + (offset) * 0x04);
 }
 
@@ -259,15 +180,20 @@ static void inno_hdmi_power_up(struct inno_hdmi *hdmi)
 }
 
 static void inno_hdmi_tx_phy_power_down(struct inno_hdmi *hdmi)
-{
-       //hdmi_write(0x63, word_align(0x00));
-       writel_relaxed(0x63, hdmi->regs + (0x00) * 0x04);
+{      
+       hdmi_writeb(hdmi, 0x00, 0x63);
 }
 
 static void inno_hdmi_config_pll(struct inno_hdmi *hdmi)
 {
        u8 reg_1ad_value = hdmi->post_cfg->post_div_en ?
-                hdmi->post_cfg->postdiv : 0x0d;
+                hdmi->post_cfg->postdiv : 0x00;
+       u8 reg_1aa_value = hdmi->post_cfg->post_div_en ?
+                0x0e : 0x02;
+       if(1 == hdmi->hdmi_data.vic){
+               reg_1ad_value = 0x0d;
+       }
+
        const reg_value_t cfg_pll_data[] = {
                {0x1a0, 0x01},
                {0x1aa, 0x0f},
@@ -280,24 +206,16 @@ static void inno_hdmi_config_pll(struct inno_hdmi *hdmi)
                {0x1ab, hdmi->post_cfg->prediv},
                {0x1ac, hdmi->post_cfg->fbdiv & 0xff},
                {0x1ad, reg_1ad_value},
-               {0x1aa, 0x0e},
+               {0x1aa, reg_1aa_value},
                {0x1a0, 0x00},
        };
 
        int i;
        for (i = 0; i < sizeof(cfg_pll_data) / sizeof(reg_value_t); i++)
        {
-               /*
-               if(0x1ad == cfg_pll_data[i].reg)
-               {
-                       if(0 == hdmi->post_cfg->post_div_en)
-                       {
-                               writel_relaxed(0x0d, hdmi->regs + (cfg_pll_data[i].reg) * 0x04);
-                               continue;
-                       }
-               }*/
-               dev_info(hdmi->dev, "%s %d reg[%02x],val[%02x]\n",__func__, __LINE__,cfg_pll_data[i].reg,cfg_pll_data[i].value);
-               writel_relaxed(cfg_pll_data[i].value, hdmi->regs + (cfg_pll_data[i].reg) * 0x04);
+               //dev_info(hdmi->dev, "%s %d reg[%02x],val[%02x]\n",__func__, __LINE__,cfg_pll_data[i].reg,cfg_pll_data[i].value);
+               //writel_relaxed(cfg_pll_data[i].value, hdmi->regs + (cfg_pll_data[i].reg) * 0x04);
+               hdmi_writeb(hdmi, cfg_pll_data[i].reg, cfg_pll_data[i].value);
        }
        return;
 }
@@ -331,23 +249,14 @@ static void inno_hdmi_config_1920x1080p60(struct inno_hdmi *hdmi)
 
 static void inno_hdmi_tx_ctrl(struct inno_hdmi *hdmi)
 {
-       writel_relaxed(0x06, hdmi->regs + (0x9f) * 0x04);
-       writel_relaxed(0x82, hdmi->regs + (0xa0) * 0x04);
-       writel_relaxed(0xd, hdmi->regs + (0xa2) * 0x04);
-       writel_relaxed(0x0, hdmi->regs + (0xa3) * 0x04);
-       writel_relaxed(0x0, hdmi->regs + (0xa4) * 0x04);
-       writel_relaxed(0x8, hdmi->regs + (0xa5) * 0x04);
-       writel_relaxed(0x70, hdmi->regs + (0xa6) * 0x04);
-       writel_relaxed(0x10, hdmi->regs + (0xa7) * 0x04);
-       writel_relaxed(0x10, hdmi->regs + (0xc9) * 0x04);
+       hdmi_writeb(hdmi, 0x9f, 0x06);
+       hdmi_writeb(hdmi, 0xa7, hdmi->hdmi_data.vic);
 }
 
 static void inno_hdmi_tx_phy_param_config(struct inno_hdmi *hdmi)
 {
        inno_hdmi_config_1920x1080p60(hdmi);
        inno_hdmi_tx_ctrl(hdmi);
-
-    return;
 }
 
 static void inno_hdmi_tx_phy_power_on(struct inno_hdmi *hdmi)
@@ -357,14 +266,16 @@ static void inno_hdmi_tx_phy_power_on(struct inno_hdmi *hdmi)
        };
        int i;
        for (i = 0; i < sizeof(pwon_data)/sizeof(reg_value_t); i++) {
-               writel_relaxed(pwon_data[i].value, hdmi->regs + (pwon_data[i].reg) * 0x04);
+               //writel_relaxed(pwon_data[i].value, hdmi->regs + (pwon_data[i].reg) * 0x04);
+               hdmi_writeb(hdmi, pwon_data[i].reg, pwon_data[i].value);
        }
        return;
 }
 
 void inno_hdmi_tmds_driver_on(struct inno_hdmi *hdmi)
 {
-       writel_relaxed(0x8f, hdmi->regs + (0x1b2) * 0x04);
+       //writel_relaxed(0x8f, hdmi->regs + (0x1b2) * 0x04);
+       hdmi_writeb(hdmi, 0x1b2, 0x8f);
 }
 
 
@@ -408,13 +319,9 @@ static void inno_hdmi_set_pwr_mode(struct inno_hdmi *hdmi, int mode)
 
 static void inno_hdmi_init(struct inno_hdmi *hdmi)
 {
-       writel_relaxed(0x3, hdmi->regs + (0x100) * 0x04);
-       writel_relaxed(0xc, hdmi->regs + (0x8) * 0x04);
-
        inno_hdmi_power_up(hdmi);
        inno_hdmi_tx_phy_power_down(hdmi);
        inno_hdmi_tx_phy_param_config(hdmi);
-       //inno_hdmi_wait_pll_clk_locked();
 
        inno_hdmi_tx_phy_power_on(hdmi);
        inno_hdmi_tmds_driver_on(hdmi);
@@ -429,225 +336,35 @@ static void inno_hdmi_reset(struct inno_hdmi *hdmi)
        u32 val;
        u32 msk;
 
+       msk = m_INT_POL;
+       val = v_INT_POL_HIGH;
+       hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
+
        hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_DIGITAL, v_NOT_RST_DIGITAL);
        udelay(100);
 
        hdmi_modb(hdmi, HDMI_SYS_CTRL, m_RST_ANALOG, v_NOT_RST_ANALOG);
        udelay(100);
 
-       msk = m_REG_CLK_INV | m_REG_CLK_SOURCE | m_POWER | m_INT_POL;
-       val = v_REG_CLK_INV | v_REG_CLK_SOURCE_SYS | v_PWR_ON | v_INT_POL_HIGH;
-       hdmi_modb(hdmi, HDMI_SYS_CTRL, msk, val);
-
        inno_hdmi_set_pwr_mode(hdmi, NORMAL);
 }
 
-static int inno_hdmi_upload_frame(struct inno_hdmi *hdmi, int setup_rc,
-                                 union hdmi_infoframe *frame, u32 frame_index,
-                                 u32 mask, u32 disable, u32 enable)
-{
-
-       if (mask)
-               hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, disable);
-
-       hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_BUF_INDEX, frame_index);
-
-       if (setup_rc >= 0) {
-               u8 packed_frame[HDMI_MAXIMUM_INFO_FRAME_SIZE];
-               ssize_t rc, i;
-
-               rc = hdmi_infoframe_pack(frame, packed_frame,
-                                        sizeof(packed_frame));
-               if (rc < 0)
-                       return rc;
-
-               for (i = 0; i < rc; i++)
-                       hdmi_writeb(hdmi, HDMI_CONTROL_PACKET_ADDR + i,
-                                   packed_frame[i]);
-
-               if (mask)
-                       hdmi_modb(hdmi, HDMI_PACKET_SEND_AUTO, mask, enable);
-       }
-
-       return setup_rc;
-}
-
-static int inno_hdmi_config_video_vsi(struct inno_hdmi *hdmi,
-                                     struct drm_display_mode *mode)
-{
-       union hdmi_infoframe frame;
-       int rc;
-
-       rc = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
-                                                        &hdmi->connector,
-                                                        mode);
-
-       return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_VSI,
-               m_PACKET_VSI_EN, v_PACKET_VSI_EN(0), v_PACKET_VSI_EN(1));
-}
-
-static int inno_hdmi_config_video_avi(struct inno_hdmi *hdmi,
-                                     struct drm_display_mode *mode)
-{
-       union hdmi_infoframe frame;
-       int rc;
-
-       rc = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi,
-                                                     &hdmi->connector,
-                                                     mode);
-
-       if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV444)
-               frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
-       else if (hdmi->hdmi_data.enc_out_format == HDMI_COLORSPACE_YUV422)
-               frame.avi.colorspace = HDMI_COLORSPACE_YUV422;
-       else
-               frame.avi.colorspace = HDMI_COLORSPACE_RGB;
-
-       return inno_hdmi_upload_frame(hdmi, rc, &frame, INFOFRAME_AVI, 0, 0, 0);
-}
-
-static int inno_hdmi_config_video_csc(struct inno_hdmi *hdmi)
-{
-       struct hdmi_data_info *data = &hdmi->hdmi_data;
-       int c0_c2_change = 0;
-       int csc_enable = 0;
-       int csc_mode = 0;
-       int auto_csc = 0;
-       int value;
-       int i;
-
-       /* Input video mode is SDR RGB24bit, data enable signal from external */
-       hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL1, v_DE_EXTERNAL |
-                   v_VIDEO_INPUT_FORMAT(VIDEO_INPUT_SDR_RGB444));
-
-       /* Input color hardcode to RGB, and output color hardcode to RGB888 */
-       value = v_VIDEO_INPUT_BITS(VIDEO_INPUT_8BITS) |
-               v_VIDEO_OUTPUT_COLOR(0) |
-               v_VIDEO_INPUT_CSP(0);
-       hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL2, value);
-
-       if (data->enc_in_format == data->enc_out_format) {
-               if ((data->enc_in_format == HDMI_COLORSPACE_RGB) ||
-                   (data->enc_in_format >= HDMI_COLORSPACE_YUV444)) {
-                       value = v_SOF_DISABLE | v_COLOR_DEPTH_NOT_INDICATED(1);
-                       hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
-
-                       hdmi_modb(hdmi, HDMI_VIDEO_CONTRL,
-                                 m_VIDEO_AUTO_CSC | m_VIDEO_C0_C2_SWAP,
-                                 v_VIDEO_AUTO_CSC(AUTO_CSC_DISABLE) |
-                                 v_VIDEO_C0_C2_SWAP(C0_C2_CHANGE_DISABLE));
-                       return 0;
-               }
-       }
-
-       if (data->colorimetry == HDMI_COLORIMETRY_ITU_601) {
-               if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
-                   (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
-                       csc_mode = CSC_RGB_0_255_TO_ITU601_16_235_8BIT;
-                       auto_csc = AUTO_CSC_DISABLE;
-                       c0_c2_change = C0_C2_CHANGE_DISABLE;
-                       csc_enable = v_CSC_ENABLE;
-               } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
-                          (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
-                       csc_mode = CSC_ITU601_16_235_TO_RGB_0_255_8BIT;
-                       auto_csc = AUTO_CSC_ENABLE;
-                       c0_c2_change = C0_C2_CHANGE_DISABLE;
-                       csc_enable = v_CSC_DISABLE;
-               }
-       } else {
-               if ((data->enc_in_format == HDMI_COLORSPACE_RGB) &&
-                   (data->enc_out_format == HDMI_COLORSPACE_YUV444)) {
-                       csc_mode = CSC_RGB_0_255_TO_ITU709_16_235_8BIT;
-                       auto_csc = AUTO_CSC_DISABLE;
-                       c0_c2_change = C0_C2_CHANGE_DISABLE;
-                       csc_enable = v_CSC_ENABLE;
-               } else if ((data->enc_in_format == HDMI_COLORSPACE_YUV444) &&
-                          (data->enc_out_format == HDMI_COLORSPACE_RGB)) {
-                       csc_mode = CSC_ITU709_16_235_TO_RGB_0_255_8BIT;
-                       auto_csc = AUTO_CSC_ENABLE;
-                       c0_c2_change = C0_C2_CHANGE_DISABLE;
-                       csc_enable = v_CSC_DISABLE;
-               }
-       }
-
-       for (i = 0; i < 24; i++)
-               hdmi_writeb(hdmi, HDMI_VIDEO_CSC_COEF + i,
-                           coeff_csc[csc_mode][i]);
-
-       value = v_SOF_DISABLE | csc_enable | v_COLOR_DEPTH_NOT_INDICATED(1);
-       hdmi_writeb(hdmi, HDMI_VIDEO_CONTRL3, value);
-       hdmi_modb(hdmi, HDMI_VIDEO_CONTRL, m_VIDEO_AUTO_CSC |
-                 m_VIDEO_C0_C2_SWAP, v_VIDEO_AUTO_CSC(auto_csc) |
-                 v_VIDEO_C0_C2_SWAP(c0_c2_change));
-
-       return 0;
-}
-
-static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
-                                        struct drm_display_mode *mode)
-{
-       int value;
-
-       /* Set detail external video timing polarity and interlace mode */
-       value = v_EXTERANL_VIDEO(1);
-       value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
-                v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
-       value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
-                v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
-       value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
-                v_INETLACE(1) : v_INETLACE(0);
-       hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
-
-       /* Set detail external video timing */
-       value = mode->htotal;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_L, value & 0xFF);
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HTOTAL_H, (value >> 8) & 0xFF);
-
-       value = mode->htotal - mode->hdisplay;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_L, value & 0xFF);
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HBLANK_H, (value >> 8) & 0xFF);
-
-       value = mode->hsync_start - mode->hdisplay;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_L, value & 0xFF);
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDELAY_H, (value >> 8) & 0xFF);
-
-       value = mode->hsync_end - mode->hsync_start;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_L, value & 0xFF);
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_HDURATION_H, (value >> 8) & 0xFF);
-
-       value = mode->vtotal;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_L, value & 0xFF);
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VTOTAL_H, (value >> 8) & 0xFF);
-
-       value = mode->vtotal - mode->vdisplay;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VBLANK, value & 0xFF);
-
-       value = mode->vsync_start - mode->vdisplay;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDELAY, value & 0xFF);
-
-       value = mode->vsync_end - mode->vsync_start;
-       hdmi_writeb(hdmi, HDMI_VIDEO_EXT_VDURATION, value & 0xFF);
-
-       return 0;
-}
-
  static const
  struct pre_pll_config *inno_hdmi_phy_get_pre_pll_cfg(struct inno_hdmi *hdmi,
                                                          unsigned long rate)
- {
-        const struct pre_pll_config *cfg = pre_pll_cfg_table;
-        //unsigned long tmdsclock = 148500000;
+{
+       const struct pre_pll_config *cfg = pre_pll_cfg_table;
        rate = (rate / 1000) * 1000;
 
-        for (; cfg->pixclock != 0; cfg++)
-                if (cfg->pixclock == rate)
-                        break;
+       for (; cfg->pixclock != 0; cfg++)
+               if (cfg->tmdsclock == rate)
+                       break;
 
-        if (cfg->pixclock == 0)
-                return ERR_PTR(-EINVAL);
+       if (cfg->pixclock == 0)
+               return ERR_PTR(-EINVAL);
 
-        return cfg;
- }
+       return cfg;
+}
 
 #define PRE_PLL_POWER_DOWN                     BIT(0)
 
@@ -683,7 +400,7 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
        return PTR_ERR(hdmi->pre_cfg);
 
        for (; hdmi->post_cfg->tmdsclock != 0; hdmi->post_cfg++)
-               if (tmdsclock <= hdmi->post_cfg->tmdsclock && hdmi->post_cfg->version)
+               if (tmdsclock <= hdmi->post_cfg->tmdsclock)
                        break;
 
        dev_info(hdmi->dev, "%s hdmi->pre_cfg->pixclock = %lu\n",__func__, hdmi->pre_cfg->pixclock);
@@ -711,7 +428,6 @@ static int inno_hdmi_config_video_timing(struct inno_hdmi *hdmi,
        dev_info(hdmi->dev, "%s hdmi->post_cfg->version = %d\n",__func__, hdmi->post_cfg->version);
 
        inno_hdmi_config_pll(hdmi);
-       //1920x1080p60
        //inno_hdmi_tx_ctrl(hdmi);
 
 #if 0 //pre pll + post pll configire
@@ -814,22 +530,14 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
                           struct drm_display_mode *mode)
 {
        u8 val;
-       int value;
-       hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
 
        val = readl_relaxed(hdmi->regs + (0x1b0) * 0x04);
        val |= 0x4;
-       writel_relaxed(val, hdmi->regs + (0x1b0) * 0x04);
-       writel_relaxed(0xf, hdmi->regs + (0x1cc) * 0x04);
-
-       /*turn on pre-PLL*/
-       val = readl_relaxed(hdmi->regs + (0x1a0) * 0x04);
-       val &= ~(0x1);
-       writel_relaxed(val, hdmi->regs + (0x1a0) * 0x04);
-       /*turn on post-PLL*/
-       val = readl_relaxed(hdmi->regs + (0x1aa) * 0x04);
-       val &= ~(0x1);
-       writel_relaxed(val, hdmi->regs + (0x1aa) * 0x04);
+       //writel_relaxed(val, hdmi->regs + (0x1b0) * 0x04);
+       //writel_relaxed(0xf, hdmi->regs + (0x1cc) * 0x04);
+       hdmi_writeb(hdmi, 0x1b0, val);
+       hdmi_writeb(hdmi, 0x1cc, 0xf);
+       hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
 
        hdmi->tmds_rate = mode->clock * 1000;
        inno_hdmi_phy_clk_set_rate(hdmi,hdmi->tmds_rate);
@@ -839,60 +547,30 @@ static int inno_hdmi_setup(struct inno_hdmi *hdmi,
        while (!(readl_relaxed(hdmi->regs + (0x1af) * 0x04) & 0x1))
        ;
 
-       /*turn on LDO*/
-       writel_relaxed(0x7, hdmi->regs + (0x1b4) * 0x04);
-       /*turn on serializer*/
-       writel_relaxed(0x70, hdmi->regs + (0x1be) * 0x04);
+       /*turn on LDO*/ 
+       hdmi_writeb(hdmi, 0x1b4, 0x7);
+       /*turn on serializer*/  
+       hdmi_writeb(hdmi, 0x1be, 0x70);
        inno_hdmi_tx_phy_power_down(hdmi);
-       /* Set HDMI Mode */
-       hdmi_writeb(hdmi, 0x100,0x3);
-       //hdmi_writeb(hdmi, 0x8,0x00);
-
-       /* Set detail external video timing polarity and interlace mode */
-       value = v_EXTERANL_VIDEO(0);
-       value |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
-                v_HSYNC_POLARITY(1) : v_HSYNC_POLARITY(0);
-       value |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
-                v_VSYNC_POLARITY(1) : v_VSYNC_POLARITY(0);
-       value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
-                v_INETLACE(1) : v_INETLACE(0);
-       hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
-
-       hdmi->hdmi_data.vic = drm_match_cea_mode(mode);
 
-       hdmi->hdmi_data.enc_in_format = HDMI_COLORSPACE_RGB;
-       hdmi->hdmi_data.enc_out_format = HDMI_COLORSPACE_RGB;
+       hdmi_writeb(hdmi, 0xC9, 0x40);
+       inno_hdmi_tx_ctrl(hdmi);
 
-       if ((hdmi->hdmi_data.vic == 6) || (hdmi->hdmi_data.vic == 7) ||
-           (hdmi->hdmi_data.vic == 21) || (hdmi->hdmi_data.vic == 22) ||
-           (hdmi->hdmi_data.vic == 2) || (hdmi->hdmi_data.vic == 3) ||
-           (hdmi->hdmi_data.vic == 17) || (hdmi->hdmi_data.vic == 18))
-               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
-       else
-               hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
+       //hdmi_writeb(hdmi, 0x100, 0x02);
 
-       /* Mute audio output */
-       hdmi_modb(hdmi, HDMI_AV_MUTE, m_AUDIO_MUTE ,
-                 v_AUDIO_MUTE(1));
+       //drm_scdc_set_high_tmds_clock_ratio(hdmi->ddc, true);
+       //drm_scdc_set_scrambling(hdmi->ddc, true);
 
-
-    if(0 == hdmi->hdmi_data.vic)
-       {
-               inno_hdmi_config_video_timing(hdmi, mode);
-
-               inno_hdmi_config_video_csc(hdmi);
-    }
-
-       if (hdmi->hdmi_data.sink_is_hdmi) {
-               inno_hdmi_config_video_avi(hdmi, mode);
-               inno_hdmi_config_video_vsi(hdmi, mode);
-       }
+       hdmi_writeb(hdmi, 0x35, 0x01);
+       hdmi_writeb(hdmi, 0x38, 0x04);
+       hdmi_writeb(hdmi, 0x40, 0x18);
+       hdmi_writeb(hdmi, 0x41, 0x80);
 
        inno_hdmi_tx_phy_power_on(hdmi);
        inno_hdmi_tmds_driver_on(hdmi);
 
-       writel_relaxed(0x0, hdmi->regs + (0xce) * 0x04);
-       writel_relaxed(0x1, hdmi->regs + (0xce) * 0x04);
+       hdmi_writeb(hdmi, 0xce, 0x0);
+       hdmi_writeb(hdmi, 0xce, 0x1);
 
        return 0;
 }
@@ -912,7 +590,6 @@ static void inno_hdmi_encoder_mode_set(struct drm_encoder *encoder,
 static void inno_hdmi_encoder_enable(struct drm_encoder *encoder)
 {
        struct inno_hdmi *hdmi = to_inno_hdmi(encoder);
-       //inno_hdmi_init(hdmi);
 
        inno_hdmi_set_pwr_mode(hdmi, NORMAL);
 }
@@ -1096,6 +773,10 @@ inno_hdmi_connector_mode_valid(struct drm_connector *connector,
        return (valid) ? MODE_OK : MODE_BAD;
 #endif
        u32 vic = drm_match_cea_mode(mode);
+       struct drm_display_info *display = &connector->display_info;
+       printk("vic ======== %d-------display->hdmi.scdc.supported = %d",vic,display->hdmi.scdc.supported);
+       
+       printk("display->hdmi.scdc.scrambling.supported = %d",display->hdmi.scdc.scrambling.supported);
 
        if (vic >= 1)
                return MODE_OK;
@@ -1109,7 +790,7 @@ static int
 inno_hdmi_probe_single_connector_modes(struct drm_connector *connector,
                                       uint32_t maxX, uint32_t maxY)
 {
-       return drm_helper_probe_single_connector_modes(connector, 1920, 1080);
+       return drm_helper_probe_single_connector_modes(connector, 3840, 2160);//3840x2160
 }
 
 static void inno_hdmi_connector_destroy(struct drm_connector *connector)
@@ -1338,61 +1019,6 @@ static struct i2c_adapter *inno_hdmi_i2c_adapter(struct inno_hdmi *hdmi)
        return adap;
 }
 
-
-
-
-#if 0
-static void inno_hdmi_get_edid(struct inno_hdmi *hdmi, unsigned int tmds_clk, unsigned char *data)
-{
-       unsigned int i, ddc_div_msb, ddc_div_lsb;
-       unsigned int ddc_scl = 100000; //scl:100k
-
-       //hdmi_write(0xff, 0x0c2);
-       //hdmi_write(0xff, 0x0c4);
-
-       ddc_div_lsb = (tmds_clk/(4*ddc_scl))>>2;
-       ddc_div_msb = (tmds_clk/(4*ddc_scl)) & 0x00ff;
-       hdmi_writeb(hdmi, 0x04b,ddc_div_lsb);
-       hdmi_writeb(hdmi, 0x04c,ddc_div_msb);
-       /*enable EDID ready interrupt*/
-       hdmi_writeb(hdmi,0x0c0,0x04 );
-
-       /*read e-edid segment 0x00 256 bytes steps*/
-       /*set EDID FIFO initial address*/
-       hdmi_writeb(hdmi,0x04f, 0x00);
-       /*set EDID first word address, read first 128 byte*/
-       hdmi_writeb(hdmi,0x04e, 0x00);
-       /*set EDID segment 0x00 address*/
-       hdmi_writeb(hdmi, 0x04d,0x00);
-
-       while(!(hdmi_readb(hdmi,0x0c1) & 0x4));
-       hdmi_writeb(hdmi,0x0c1, 0x04); // clear ready interrupt: write 1 to bit2
-
-       /*read first 128 bytes*/
-       for(i = 0; i < 128; i++)
-       {
-               data[i] = hdmi_readb(hdmi,0x050);
-       }
-
-       /*set EDID FIFO initial address again*/
-       hdmi_writeb(hdmi,0x04f, 0x00);
-       /*set EDID first word address, read last 128 byte*/
-       hdmi_writeb(hdmi,0x04e, 0x80);
-       /*set EDID segment 0x00 address*/
-       hdmi_writeb(hdmi,0x04d, 0x00);
-
-       while(!(hdmi_readb(hdmi,0x0c1) & 0x4));
-       hdmi_writeb(hdmi,0x0c1, 0x04); // clear ready interrupt: write 1 to bit2
-
-       /*read last 128 bytes*/
-       for(i = 128; i < 256; i++)
-       {
-               data[i] = hdmi_readb(hdmi,0x050);
-       }
-
-}
-#endif
-
 static int inno_hdmi_get_clk_rst(struct device *dev, struct inno_hdmi *hdmi)
 {
        hdmi->sys_clk = devm_clk_get(dev, "sysclk");
@@ -1503,6 +1129,7 @@ static int inno_hdmi_bind(struct device *dev, struct device *master,
                goto err_disable_clk;
        }
 #ifdef CONFIG_DRM_I2C_NXP_TDA998X
+       hdmi->hdmi_data.vic = 0x10;
        inno_hdmi_init(hdmi);
 #endif
        inno_hdmi_reset(hdmi);
index 5ebda7c..e1f1fda 100755 (executable)
@@ -214,7 +214,7 @@ static int encoder_bind(struct device *dev, struct device *master, void *data)
 
        encoder->possible_crtcs =
                        drm_of_find_possible_crtcs(drm_dev, dev->of_node);
-       encoder->possible_crtcs = 3;
+       encoder->possible_crtcs = 2;
 
        /* output port is port1*/
 
index 78a2323..6149e79 100644 (file)
 /*
  * Driver for Motorcomm PHYs
  *
- * Author: Peter Geis <pgwipeout@gmail.com>
+ * Author: yinghong.zhang<yinghong.zhang@motor-comm.com>
+ *
+ * Copyright (c) 2019 Motorcomm, Inc.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ * Support : Motorcomm Phys:
+ *        Giga phys: yt8511, yt8521, yt8531, yt8614, yt8618
+ *        100/10 Phys : yt8512, yt8512b, yt8510
+ *        Automotive 100Mb Phys : yt8010
+ *        Automotive 100/10 hyper range Phys: yt8510
  */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/phy.h>
+#include <linux/of.h>
+#include <linux/clk.h>
 
-#define PHY_ID_YT8511          0x0000010a
-#define PHY_ID_YT8521          0x0000011a
-#define MOTORCOMM_PHY_ID_MASK  0x00000fff
-
-#define YT8511_PAGE_SELECT     0x1e
-#define YT8511_PAGE            0x1f
-#define YT8511_EXT_CLK_GATE    0x0c
-#define YT8511_EXT_DELAY_DRIVE 0x0d
-#define YT8511_EXT_SLEEP_CTRL  0x27
+/* for wol feature, 20210604 */
+#include <linux/netdevice.h>
 
-/* 2b00 25m from pll
- * 2b01 25m from xtl *default*
- * 2b10 62.m from pll
- * 2b11 125m from pll
- */
-#define YT8511_CLK_125M                (BIT(2) | BIT(1))
-#define YT8511_PLLON_SLP       BIT(14)
+#define YT_LINUX_MAJOR         2
+#define YT_LINUX_MINOR         2
+#define YT_LINUX_SUBVERSION    6255
+#define YT_LINUX_VERSIONID     "2.2.6255"
 
-/* RX Delay enabled = 1.8ns 1000T, 8ns 10/100T */
-#define YT8511_DELAY_RX                BIT(0)
+/********************************************
+ **** configuration section begin ***********/
 
-/* TX Gig-E Delay is bits 7:4, default 0x5
- * TX Fast-E Delay is bits 15:12, default 0xf
- * Delay = 150ps * N - 250ps
- * On = 2000ps, off = 50ps
+/* if system depends on ethernet packet to restore from sleep,
+ * please define this macro to 1 otherwise, define it to 0.
  */
-#define YT8511_DELAY_GE_TX_EN  (0xf << 4)
-#define YT8511_DELAY_GE_TX_DIS (0x2 << 4)
-#define YT8511_DELAY_FE_TX_EN  (0xf << 12)
-#define YT8511_DELAY_FE_TX_DIS (0x2 << 12)
-
-#define YT8521_SLEEP_SW_EN     BIT(15)
-#define YT8521_LINK_STATUS     BIT(10)
-#define YT8521_DUPLEX          0x2000
-#define YT8521_SPEED_MODE      0xc000
-#define YTPHY_REG_SPACE_UTP    0
-#define YTPHY_REG_SPACE_FIBER  2
-#define REG_PHY_SPEC_STATUS    0x11
-/* based on yt8521 wol config register */
-#define YTPHY_UTP_INTR_REG     0x12
-
-#define SYS_WAKEUP_BASED_ON_ETH_PKT    0
-
-/* to enable system WOL of phy, please define this macro to 1
+#define SYS_WAKEUP_BASED_ON_ETH_PKT     1
+
+/* to enable system WOL feature of phy, please define this macro to 1
  * otherwise, define it to 0.
  */
-#define YTPHY_ENABLE_WOL       0
+#define YTPHY_WOL_FEATURE_ENABLE        0
 
-#if (YTPHY_ENABLE_WOL)
-       #undef SYS_WAKEUP_BASED_ON_ETH_PKT
-       #define SYS_WAKEUP_BASED_ON_ETH_PKT     1
-#endif
+/* some GMAC need clock input from PHY, for eg., 125M,
+ * please enable this macro
+ * by degault, it is set to 0
+ * NOTE: this macro will need macro SYS_WAKEUP_BASED_ON_ETH_PKT to set to 1
+ */
+#define GMAC_CLOCK_INPUT_NEEDED         0
 
-#if (YTPHY_ENABLE_WOL)
-enum ytphy_wol_type_e {
-       YTPHY_WOL_TYPE_LEVEL,
-       YTPHY_WOL_TYPE_PULSE,
-       YTPHY_WOL_TYPE_MAX
+/* the max number of yt8521 chip on pcb board
+ * the most case is only 1 chip per board, but
+ * by default, we support up to 8.
+ */
+#define YTPHY_BOARD_MAX_NUM_OF_CHIP_8521    8
+#define YTPHY_BOARD_MAX_NUM_OF_CHIP_8614    4
+
+/* for YT8531 package A xtal init config */
+#define YTPHY8531A_XTAL_INIT                (0)
+
+/**** configuration section end ***********
+ ******************************************/
+
+/* no need to change below */
+#define MOTORCOMM_PHY_ID_MASK           0x00000fff
+#define MOTORCOMM_PHY_ID_8531_MASK      0xffffffff
+#define MOTORCOMM_MPHY_ID_MASK          0x0000ffff
+#define MOTORCOMM_MPHY_ID_MASK_8614     0xffffffff
+#define MOTORCOMM_PHY_ID_MASK_8821      0xffffffff
+
+#define PHY_ID_YT8010                   0x00000309
+#define PHY_ID_YT8010AS                 0x4f51eb19
+#define PHY_ID_YT8510                   0x00000109
+#define PHY_ID_YT8511                   0x0000010a
+#define PHY_ID_YT8512                   0x00000118
+#define PHY_ID_YT8512B                  0x00000128
+#define PHY_ID_YT8521                   0x0000011a
+#define PHY_ID_YT8531S                  0x4f51e91a
+#define PHY_ID_YT8531                   0x4f51e91b
+#define PHY_ID_YT8614                   0x4F51E899
+#define PHY_ID_YT8618                   0x0000e889
+#define PHY_ID_YT8821                   0x4f51ea10
+
+#define REG_PHY_SPEC_STATUS             0x11
+#define REG_DEBUG_ADDR_OFFSET           0x1e
+#define REG_DEBUG_DATA                  0x1f
+
+#define YT8512_EXTREG_LED0              0x40c0
+#define YT8512_EXTREG_LED1              0x40c3
+
+#define YT8512_EXTREG_SLEEP_CONTROL1    0x2027
+
+#define YT_SOFTWARE_RESET               0x8000
+
+#define YT8512_LED0_ACT_BLK_IND         0x1000
+#define YT8512_LED0_DIS_LED_AN_TRY      0x0001
+#define YT8512_LED0_BT_BLK_EN           0x0002
+#define YT8512_LED0_HT_BLK_EN           0x0004
+#define YT8512_LED0_COL_BLK_EN          0x0008
+#define YT8512_LED0_BT_ON_EN            0x0010
+#define YT8512_LED1_BT_ON_EN            0x0010
+#define YT8512_LED1_TXACT_BLK_EN        0x0100
+#define YT8512_LED1_RXACT_BLK_EN        0x0200
+#define YT8512_SPEED_MODE               0xc000
+#define YT8512_DUPLEX                   0x2000
+
+#define YT8512_SPEED_MODE_BIT           14
+#define YT8512_DUPLEX_BIT               13
+#define YT8512_EN_SLEEP_SW_BIT          15
+
+#define YT8521_EXTREG_SLEEP_CONTROL1    0x27
+#define YT8521_EN_SLEEP_SW_BIT          15
+
+#define YT8521_SPEED_MODE               0xc000
+#define YT8521_DUPLEX                   0x2000
+#define YT8521_SPEED_MODE_BIT           14
+#define YT8521_DUPLEX_BIT               13
+#define YT8521_LINK_STATUS_BIT          10
+
+/* based on yt8521 wol feature config register */
+#define YTPHY_UTP_INTR_REG              0x12
+/* WOL Feature Event Interrupt Enable */
+#define YTPHY_WOL_FEATURE_INTR          BIT(6)
+
+/* Magic Packet MAC address registers */
+#define YTPHY_WOL_FEATURE_MACADDR2_4_MAGIC_PACKET    0xa007
+#define YTPHY_WOL_FEATURE_MACADDR1_4_MAGIC_PACKET    0xa008
+#define YTPHY_WOL_FEATURE_MACADDR0_4_MAGIC_PACKET    0xa009
+
+#define YTPHY_WOL_FEATURE_REG_CFG               0xa00a
+#define YTPHY_WOL_FEATURE_TYPE_CFG              BIT(0)    /* WOL TYPE Config */
+#define YTPHY_WOL_FEATURE_ENABLE_CFG            BIT(3)    /* WOL Enable Config */
+#define YTPHY_WOL_FEATURE_INTR_SEL_CFG          BIT(6)    /* WOL Event Interrupt Enable Config */
+#define YTPHY_WOL_FEATURE_WIDTH1_CFG            BIT(1)    /* WOL Pulse Width Config */
+#define YTPHY_WOL_FEATURE_WIDTH2_CFG            BIT(2)    /* WOL Pulse Width Config */
+
+#define YTPHY_REG_SPACE_UTP             0
+#define YTPHY_REG_SPACE_FIBER           2
+
+#define YTPHY_EXTREG_CHIP_CONFIG       0xa001
+#define YTPHY_EXTREG_RGMII_CONFIG1     0xa003
+
+enum ytphy_wol_feature_trigger_type_e {
+       YTPHY_WOL_FEATURE_PULSE_TRIGGER,
+       YTPHY_WOL_FEATURE_LEVEL_TRIGGER,
+       YTPHY_WOL_FEATURE_TRIGGER_TYPE_MAX
 };
-typedef enum ytphy_wol_type_e ytphy_wol_type_t;
-
-enum ytphy_wol_width_e {
-       YTPHY_WOL_WIDTH_84MS,
-       YTPHY_WOL_WIDTH_168MS,
-       YTPHY_WOL_WIDTH_336MS,
-       YTPHY_WOL_WIDTH_672MS,
-       YTPHY_WOL_WIDTH_MAX
+
+enum ytphy_wol_feature_pulse_width_e {
+       YTPHY_WOL_FEATURE_672MS_PULSE_WIDTH,
+       YTPHY_WOL_FEATURE_336MS_PULSE_WIDTH,
+       YTPHY_WOL_FEATURE_168MS_PULSE_WIDTH,
+       YTPHY_WOL_FEATURE_84MS_PULSE_WIDTH,
+       YTPHY_WOL_FEATURE_PULSE_WIDTH_MAX
 };
-typedef enum ytphy_wol_width_e ytphy_wol_width_t;
 
-struct ytphy_wol_cfg_s {
-       int enable;
+struct ytphy_wol_feature_cfg {
+       bool enable;
        int type;
        int width;
 };
-typedef struct ytphy_wol_cfg_s ytphy_wol_cfg_t;
-#endif /*(YTPHY_ENABLE_WOL)*/
 
-static int yt8511_read_page(struct phy_device *phydev)
-{
-       return __phy_read(phydev, YT8511_PAGE_SELECT);
-};
+#if (YTPHY_WOL_FEATURE_ENABLE)
+#undef SYS_WAKEUP_BASED_ON_ETH_PKT
+#define SYS_WAKEUP_BASED_ON_ETH_PKT     1
+#endif
 
-static int yt8511_write_page(struct phy_device *phydev, int page)
-{
-       return __phy_write(phydev, YT8511_PAGE_SELECT, page);
+/* YT8521 polling mode */
+#define YT8521_PHY_MODE_FIBER           1 //fiber mode only
+#define YT8521_PHY_MODE_UTP             2 //utp mode only
+#define YT8521_PHY_MODE_POLL            3 //fiber and utp, poll mode
+
+/* below are for bitmap */
+#define YT_PHY_MODE_FIBER               1 //fiber/sgmii mode only
+#define YT_PHY_MODE_UTP                 2 //utp mode only
+#define YT_PHY_MODE_QSGMII              4 //qsgmii mode only
+
+//qsgmii, fiber/sgmii and utp, poll mode
+#define YT_PHY_MODE_POLL                (YT_PHY_MODE_FIBER |\
+                                       YT_PHY_MODE_UTP |\
+                                       YT_PHY_MODE_QSGMII)
+/* support automatically check polling mode for yt8521
+ * for Fiber only system, please define YT8521_PHY_MODE_CURR 1
+ * for UTP only system, please define YT8521_PHY_MODE_CURR 2
+ * for combo system, please define YT8521_PHY_MODE_CURR 3
+ */
+#define YTPHY_861X_ABC_VER              0
+#if (YTPHY_861X_ABC_VER)
+static int yt8614_get_port_from_phydev(struct phy_device *phydev);
+#endif
+static int yt8521_hw_strap_polling(struct phy_device *phydev);
+static int yt8614_hw_strap_polling(struct phy_device *phydev);
+#define YT8521_PHY_MODE_CURR    yt8521_hw_strap_polling(phydev)
+#define YT8614_PHY_MODE_CURR    yt8614_hw_strap_polling(phydev)
+
+struct ytphy_reg_field {
+       const char      *name;
+       const u8        size;   /* Size of the bitfield, in bits */
+       const u8        off;    /* Offset from bit 0 */
+       const u8        dflt;   /* Default value */
 };
 
-static int yt8511_config_init(struct phy_device *phydev)
-{
-       int oldpage, ret = 0;
-       unsigned int ge, fe;
-
-       oldpage = phy_select_page(phydev, YT8511_EXT_CLK_GATE);
-       if (oldpage < 0)
-               goto err_restore_page;
-
-       /* set rgmii delay mode */
-       switch (phydev->interface) {
-       case PHY_INTERFACE_MODE_RGMII:
-               ge = YT8511_DELAY_GE_TX_DIS;
-               fe = YT8511_DELAY_FE_TX_DIS;
-               break;
-       case PHY_INTERFACE_MODE_RGMII_RXID:
-               ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_DIS;
-               fe = YT8511_DELAY_FE_TX_DIS;
-               break;
-       case PHY_INTERFACE_MODE_RGMII_TXID:
-               ge = YT8511_DELAY_GE_TX_EN;
-               fe = YT8511_DELAY_FE_TX_EN;
-               break;
-       case PHY_INTERFACE_MODE_RGMII_ID:
-               ge = YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN;
-               fe = YT8511_DELAY_FE_TX_EN;
-               break;
-       default: /* do not support other modes */
-               ret = -EOPNOTSUPP;
-               goto err_restore_page;
-       }
-
-       ret = __phy_modify(phydev, YT8511_PAGE, (YT8511_DELAY_RX | YT8511_DELAY_GE_TX_EN), ge);
-       if (ret < 0)
-               goto err_restore_page;
-
-       /* set clock mode to 125mhz */
-       ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_CLK_125M);
-       if (ret < 0)
-               goto err_restore_page;
-
-       /* fast ethernet delay is in a separate page */
-       ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_DELAY_DRIVE);
-       if (ret < 0)
-               goto err_restore_page;
+static const struct ytphy_reg_field ytphy_rxtxd_grp[] = {
+       { "rx_delay_sel", 4, 10, 0x0 },
+       { "tx_delay_sel_fe", 4, 4, 0xf },
+       { "tx_delay_sel", 4, 0, 0x1 }
+};
 
-       ret = __phy_modify(phydev, YT8511_PAGE, YT8511_DELAY_FE_TX_EN, fe);
-       if (ret < 0)
-               goto err_restore_page;
+static const struct ytphy_reg_field ytphy_rxden_grp[] = {
+       { "rxc_dly_en", 1, 8, 0x1 }
+};
 
-       /* leave pll enabled in sleep */
-       ret = __phy_write(phydev, YT8511_PAGE_SELECT, YT8511_EXT_SLEEP_CTRL);
-       if (ret < 0)
-               goto err_restore_page;
+static uint bitfield_mask(uint shift, uint width)
+{
+       return ((1 << width) - 1) << shift;
+}
 
-       ret = __phy_modify(phydev, YT8511_PAGE, 0, YT8511_PLLON_SLP);
-       if (ret < 0)
-               goto err_restore_page;
+static uint bitfield_replace(uint reg_val, uint shift, uint width,
+                                   uint bitfield_val)
+{
+       uint mask = bitfield_mask(shift, width);
 
-err_restore_page:
-       return phy_restore_page(phydev, oldpage, ret);
+       return (reg_val & ~mask) | ((bitfield_val << shift) & mask);
 }
 
-int genphy_config_init(struct phy_device *phydev)
+static int ytphy_config_init(struct phy_device *phydev)
 {
-       return genphy_read_abilities(phydev);
+       int val;
+
+       val = phy_read(phydev, 3);
+
+       return 0;
 }
 
 static int ytphy_read_ext(struct phy_device *phydev, u32 regnum)
@@ -170,11 +241,11 @@ static int ytphy_read_ext(struct phy_device *phydev, u32 regnum)
        int ret;
        int val;
 
-       ret = phy_write(phydev, YT8511_PAGE_SELECT, regnum);
+       ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
        if (ret < 0)
                return ret;
 
-       val = phy_read(phydev, YT8511_PAGE);
+       val = phy_read(phydev, REG_DEBUG_DATA);
 
        return val;
 }
@@ -183,263 +254,212 @@ static int ytphy_write_ext(struct phy_device *phydev, u32 regnum, u16 val)
 {
        int ret;
 
-       ret = phy_write(phydev, YT8511_PAGE_SELECT, regnum);
+       ret = phy_write(phydev, REG_DEBUG_ADDR_OFFSET, regnum);
        if (ret < 0)
                return ret;
 
-       ret = phy_write(phydev, YT8511_PAGE, val);
+       ret = phy_write(phydev, REG_DEBUG_DATA, val);
 
        return ret;
 }
 
-int yt8521_soft_reset(struct phy_device *phydev)
+static int ytphy_soft_reset(struct phy_device *phydev)
 {
-       int ret, val;
+       int ret = 0, val = 0;
 
-       val = ytphy_read_ext(phydev, 0xa001);
-       ytphy_write_ext(phydev, 0xa001, (val & ~0x8000));
+       val = phy_read(phydev, MII_BMCR);
+       if (val < 0)
+               return val;
 
-       ret = genphy_soft_reset(phydev);
+       ret = phy_write(phydev, MII_BMCR, val | BMCR_RESET);
        if (ret < 0)
                return ret;
 
-       return 0;
+       return ret;
 }
 
-#if (YTPHY_ENABLE_WOL)
-static int ytphy_switch_reg_space(struct phy_device *phydev, int space)
+#if (YTPHY8531A_XTAL_INIT)
+static int yt8531a_xtal_init(struct phy_device *phydev)
 {
-       int ret;
+       int ret = 0;
+       int val = 0;
+       bool state = false;
 
-       if (space == YTPHY_REG_SPACE_UTP)
-               ret = ytphy_write_ext(phydev, 0xa000, 0);
-       else
-               ret = ytphy_write_ext(phydev, 0xa000, 2);
+       msleep(50);
+
+       do {
+               ret = ytphy_write_ext(phydev, 0xa012, 0x88);
+               if (ret < 0)
+                       return ret;
+
+               msleep(100);
+
+               val = ytphy_read_ext(phydev, 0xa012);
+               if (val < 0)
+                       return val;
+
+               usleep_range(10000, 20000);
+       } while (val != 0x88);
+
+       ret = ytphy_write_ext(phydev, 0xa012, 0xc8);
+       if (ret < 0)
+               return ret;
 
        return ret;
 }
+#endif
 
-static int ytphy_wol_en_cfg(struct phy_device *phydev, ytphy_wol_cfg_t wol_cfg)
+int yt8010_soft_reset(struct phy_device *phydev)
 {
-       int ret=0;
-       int val=0;
+       ytphy_soft_reset(phydev);
 
-       val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG);
-       if (val < 0)
-               return val;
+       return 0;
+}
 
-       if(wol_cfg.enable) {
-               val |= YTPHY_WOL_CFG_EN;
-
-               if(wol_cfg.type == YTPHY_WOL_TYPE_LEVEL) {
-                       val &= ~YTPHY_WOL_CFG_TYPE;
-                       val &= ~YTPHY_WOL_CFG_INTR_SEL;
-               } else if(wol_cfg.type == YTPHY_WOL_TYPE_PULSE) {
-                       val |= YTPHY_WOL_CFG_TYPE;
-                       val |= YTPHY_WOL_CFG_INTR_SEL;
-
-                       if(wol_cfg.width == YTPHY_WOL_WIDTH_84MS) {
-                               val &= ~YTPHY_WOL_CFG_WIDTH1;
-                               val &= ~YTPHY_WOL_CFG_WIDTH2;
-                       } else if(wol_cfg.width == YTPHY_WOL_WIDTH_168MS) {
-                               val |= YTPHY_WOL_CFG_WIDTH1;
-                               val &= ~YTPHY_WOL_CFG_WIDTH2;
-                       } else if(wol_cfg.width == YTPHY_WOL_WIDTH_336MS) {
-                               val &= ~YTPHY_WOL_CFG_WIDTH1;
-                               val |= YTPHY_WOL_CFG_WIDTH2;
-                       } else if(wol_cfg.width == YTPHY_WOL_WIDTH_672MS) {
-                               val |= YTPHY_WOL_CFG_WIDTH1;
-                               val |= YTPHY_WOL_CFG_WIDTH2;
-                       }
-               }
-       } else {
-               val &= ~YTPHY_WOL_CFG_EN;
-               val &= ~YTPHY_WOL_CFG_INTR_SEL;
+int yt8010AS_soft_reset(struct phy_device *phydev)
+{
+       int ret = 0;
+
+       /* sgmii */
+       ytphy_write_ext(phydev, 0xe, 1);
+       ret = ytphy_soft_reset(phydev);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xe, 0);
+               return ret;
        }
 
-       ret = ytphy_write_ext(phydev, YTPHY_WOL_CFG_REG, val);
+       /* utp */
+       ytphy_write_ext(phydev, 0xe, 0);
+       ret = ytphy_soft_reset(phydev);
        if (ret < 0)
                return ret;
 
        return 0;
 }
 
-static void ytphy_get_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+int yt8010_aneg_done(struct phy_device *phydev)
 {
        int val = 0;
 
-       wol->supported = WAKE_MAGIC;
-       wol->wolopts = 0;
-
-       val = ytphy_read_ext(phydev, YTPHY_WOL_CFG_REG);
-       if (val < 0)
-               return;
-
-       if (val & YTPHY_WOL_CFG_EN)
-               wol->wolopts |= WAKE_MAGIC;
+       val = phy_read(phydev, 0x1);
+       val = phy_read(phydev, 0x1);
 
-       return;
+       return (val < 0) ? val : (val & BMSR_LSTATUS);
 }
 
-static int ytphy_set_wol(struct phy_device *phydev, struct ethtool_wolinfo *wol)
+static int yt8010_config_aneg(struct phy_device *phydev)
 {
-       int ret, pre_page, val;
-       ytphy_wol_cfg_t wol_cfg;
-       struct net_device *p_attached_dev = phydev->attached_dev;
+       phydev->speed = SPEED_100;
+       return 0;
+}
 
-       memset(&wol_cfg,0,sizeof(ytphy_wol_cfg_t));
-       pre_page = ytphy_read_ext(phydev, 0xa000);
-       if (pre_page < 0)
-               return pre_page;
+static int yt8010_read_status(struct phy_device *phydev)
+{
+       int ret = 0;
 
-       /* Switch to phy UTP page */
-       ret = ytphy_switch_reg_space(phydev, YTPHY_REG_SPACE_UTP);
-       if (ret < 0)
+       ret = genphy_update_link(phydev);
+       if (ret)
                return ret;
 
-       if (wol->wolopts & WAKE_MAGIC) {
-               /* Enable the WOL interrupt */
-               val = phy_read(phydev, YTPHY_UTP_INTR_REG);
-               val |= YTPHY_WOL_INTR;
-               ret = phy_write(phydev, YTPHY_UTP_INTR_REG, val);
-               if (ret < 0)
-                       return ret;
-
-               /* Set the WOL config */
-               wol_cfg.enable = 1; //enable
-               wol_cfg.type= YTPHY_WOL_TYPE_PULSE;
-               wol_cfg.width= YTPHY_WOL_WIDTH_672MS;
-               ret = ytphy_wol_en_cfg(phydev, wol_cfg);
-               if (ret < 0)
-                       return ret;
+       /* for 8010, no definition mii reg 0x04, 0x11, here force 100/full */
+       phydev->speed = SPEED_100;
+       phydev->duplex = DUPLEX_FULL;
 
-               /* Store the device address for the magic packet */
-               ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR2,
-                               ((p_attached_dev->dev_addr[0] << 8) |
-                                p_attached_dev->dev_addr[1]));
-               if (ret < 0)
-                       return ret;
-               ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR1,
-                               ((p_attached_dev->dev_addr[2] << 8) |
-                                p_attached_dev->dev_addr[3]));
-               if (ret < 0)
-                       return ret;
-               ret = ytphy_write_ext(phydev, YTPHY_MAGIC_PACKET_MAC_ADDR0,
-                               ((p_attached_dev->dev_addr[4] << 8) |
-                                p_attached_dev->dev_addr[5]));
-               if (ret < 0)
-                       return ret;
-       } else {
-               wol_cfg.enable = 0; //disable
-               wol_cfg.type= YTPHY_WOL_TYPE_MAX;
-               wol_cfg.width= YTPHY_WOL_WIDTH_MAX;
-               ret = ytphy_wol_en_cfg(phydev, wol_cfg);
-               if (ret < 0)
-                       return ret;
-       }
+       return 0;
+}
 
-       /* Recover to previous register space page */
-       ret = ytphy_switch_reg_space(phydev, pre_page);
-       if (ret < 0)
-               return ret;
+static int yt8010AS_config_init(struct phy_device *phydev)
+{
+       phydev->autoneg = AUTONEG_DISABLE;
 
        return 0;
 }
-#endif /*(YTPHY_ENABLE_WOL)*/
 
-static int yt8521_config_init(struct phy_device *phydev)
+static int yt8512_led_init(struct phy_device *phydev)
 {
        int ret;
        int val;
+       int mask;
 
-       phydev->irq = PHY_POLL;
+       val = ytphy_read_ext(phydev, YT8512_EXTREG_LED0);
+       if (val < 0)
+               return val;
 
-       ytphy_write_ext(phydev, 0xa000, 0);
+       val |= YT8512_LED0_ACT_BLK_IND;
 
-       ret = genphy_config_init(phydev);
+       mask = YT8512_LED0_DIS_LED_AN_TRY | YT8512_LED0_BT_BLK_EN |
+       YT8512_LED0_HT_BLK_EN | YT8512_LED0_COL_BLK_EN |
+       YT8512_LED0_BT_ON_EN;
+       val &= ~mask;
+
+       ret = ytphy_write_ext(phydev, YT8512_EXTREG_LED0, val);
        if (ret < 0)
                return ret;
 
-       /* disable auto sleep */
-       val = ytphy_read_ext(phydev, YT8511_EXT_SLEEP_CTRL);
+       val = ytphy_read_ext(phydev, YT8512_EXTREG_LED1);
        if (val < 0)
                return val;
 
-       val &= ~YT8521_SLEEP_SW_EN;
+       val |= YT8512_LED1_BT_ON_EN;
 
-       ret = ytphy_write_ext(phydev, YT8511_EXT_SLEEP_CTRL, val);
-       if (ret < 0)
-               return ret;
+       mask = YT8512_LED1_TXACT_BLK_EN | YT8512_LED1_RXACT_BLK_EN;
+       val &= ~mask;
 
-       /*  enable tx delay 450ps per step */
-       val = ytphy_read_ext(phydev, 0xa003);
-       if (val < 0) {
-               printk(KERN_INFO "yt8521_config: read 0xa003 error!\n");
-               return val;
-       }
+       ret = ytphy_write_ext(phydev, YT8512_LED1_BT_ON_EN, val);
 
-       val &= ~0x3CFF;
-       val |= 0x5b;
-       ret = ytphy_write_ext(phydev, 0xa003, val);
-       if (ret < 0) {
-               printk(KERN_INFO "yt8521_config: set 0xa003 error!\n");
-               return ret;
-       }
+       return ret;
+}
 
-       /* disable rx delay */
-       val = ytphy_read_ext(phydev, 0xa001);
-       if (val < 0) {
-               printk(KERN_INFO "yt8521_config: read 0xa001 error!\n");
-               return val;
-       }
-       val &= ~(1<<8);
-       val |= BIT(8);
-       ret = ytphy_write_ext(phydev, 0xa001, val);
-       if (ret < 0) {
-               printk(KERN_INFO "yt8521_config: failed to disable rx_delay!\n");
-               return ret;
-       }
+static int yt8512_config_init(struct phy_device *phydev)
+{
+       int ret;
+       int val;
 
-       /* enable RXC clock when no wire plug */
-       ret = ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_config_init(phydev);
        if (ret < 0)
                return ret;
 
-       val = ytphy_read_ext(phydev, YT8511_EXT_CLK_GATE);
+       ret = yt8512_led_init(phydev);
+
+       /* disable auto sleep */
+       val = ytphy_read_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1);
        if (val < 0)
                return val;
-       val &= ~(1 << 12);
-       ret = ytphy_write_ext(phydev, YT8511_EXT_CLK_GATE, val);
+
+       val &= (~BIT(YT8512_EN_SLEEP_SW_BIT));
+
+       ret = ytphy_write_ext(phydev, YT8512_EXTREG_SLEEP_CONTROL1, val);
        if (ret < 0)
                return ret;
 
        return ret;
 }
 
-/*
- * for fiber mode, there is no 10M speed mode and
- * this function is for this purpose.
- */
-static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp)
+static int yt8512_read_status(struct phy_device *phydev)
 {
-       int speed_mode, duplex;
-       int speed = SPEED_UNKNOWN;
+       int ret;
+       int val;
+       int speed, speed_mode, duplex;
+
+       ret = genphy_update_link(phydev);
+       if (ret)
+               return ret;
+
+       val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+       if (val < 0)
+               return val;
 
-       duplex = (val & YT8521_DUPLEX) >> 13;
-       speed_mode = (val & YT8521_SPEED_MODE) >> 14;
+       duplex = (val & YT8512_DUPLEX) >> YT8512_DUPLEX_BIT;
+       speed_mode = (val & YT8512_SPEED_MODE) >> YT8512_SPEED_MODE_BIT;
        switch (speed_mode) {
        case 0:
-               if (is_utp)
-                       speed = SPEED_10;
+               speed = SPEED_10;
                break;
        case 1:
                speed = SPEED_100;
                break;
        case 2:
-               speed = SPEED_1000;
-               break;
        case 3:
-               break;
        default:
                speed = SPEED_UNKNOWN;
                break;
@@ -447,142 +467,1711 @@ static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp)
 
        phydev->speed = speed;
        phydev->duplex = duplex;
+
        return 0;
 }
 
-static int yt8521_read_status(struct phy_device *phydev)
+int yt8521_soft_reset(struct phy_device *phydev)
 {
-       int ret;
-       volatile int val;
-       volatile int link;
-       int link_utp = 0;
+       int ret, val;
 
-       /* reading UTP */
-       ret = ytphy_write_ext(phydev, 0xa000, 0);
-       if (ret < 0)
-               return ret;
+       if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_UTP) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               ytphy_soft_reset(phydev);
+       }
 
-       val = phy_read(phydev, REG_PHY_SPEC_STATUS);
-       if (val < 0)
-               return val;
+       if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_FIBER) {
+               ytphy_write_ext(phydev, 0xa000, 2);
+               ytphy_soft_reset(phydev);
 
-       link = val & YT8521_LINK_STATUS;
-       if (link) {
-               link_utp = 1;
-               yt8521_adjust_status(phydev, val, 1);
-       } else {
-               link_utp = 0;
+               ytphy_write_ext(phydev, 0xa000, 0);
        }
 
-       if (link_utp) {
-               phydev->link = 1;
+       if (YT8521_PHY_MODE_CURR == YT8521_PHY_MODE_POLL) {
+               val = ytphy_read_ext(phydev, 0xa001);
+               ytphy_write_ext(phydev, 0xa001, (val & ~0x8000));
+
                ytphy_write_ext(phydev, 0xa000, 0);
-       } else {
-               phydev->link = 0;
+               ret = ytphy_soft_reset(phydev);
        }
 
        return 0;
 }
 
-int yt8521_suspend(struct phy_device *phydev)
+#if GMAC_CLOCK_INPUT_NEEDED
+static int ytphy_mii_rd_ext(struct mii_bus *bus, int phy_id, u32 regnum)
 {
-#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
-       int value;
-
-       ytphy_write_ext(phydev, 0xa000, 0);
-       value = phy_read(phydev, MII_BMCR);
-       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+       int ret;
+       int val;
 
-       ytphy_write_ext(phydev, 0xa000, 2);
-       value = phy_read(phydev, MII_BMCR);
-       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+       ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum);
+       if (ret < 0)
+               return ret;
 
-       ytphy_write_ext(phydev, 0xa000, 0);
-#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+       val = bus->read(bus, phy_id, REG_DEBUG_DATA);
 
-       return 0;
+       return val;
 }
 
-int yt8521_resume(struct phy_device *phydev)
+static int ytphy_mii_wr_ext(struct mii_bus *bus
+                               int phy_id,
+                               u32 regnum,
+                               u16 val)
 {
-#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
-       int value;
        int ret;
 
-       ytphy_write_ext(phydev, 0xa000, 0);
-       value = phy_read(phydev, MII_BMCR);
-       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+       ret = bus->write(bus, phy_id, REG_DEBUG_ADDR_OFFSET, regnum);
+       if (ret < 0)
+               return ret;
+
+       ret = bus->write(bus, phy_id, REG_DEBUG_DATA, val);
+
+       return ret;
+}
+
+int yt8511_config_dis_txdelay(struct mii_bus *bus, int phy_id)
+{
+       int ret;
+       int val;
 
        /* disable auto sleep */
-       value = ytphy_read_ext(phydev, YT8511_EXT_SLEEP_CTRL);
-       if (value < 0)
-               return value;
+       val = ytphy_mii_rd_ext(bus, phy_id, 0x27);
+       if (val < 0)
+               return val;
 
-       value &= ~YT8521_SLEEP_SW_EN;
-       ret = ytphy_write_ext(phydev, YT8511_EXT_SLEEP_CTRL, value);
+       val &= (~BIT(15));
+
+       ret = ytphy_mii_wr_ext(bus, phy_id, 0x27, val);
        if (ret < 0)
                return ret;
 
        /* enable RXC clock when no wire plug */
-       value = ytphy_read_ext(phydev, YT8511_EXT_CLK_GATE);
-       if (value < 0)
-               return value;
-       value &= ~(1 << 12);
-       ret = ytphy_write_ext(phydev, YT8511_EXT_CLK_GATE, value);
-       if (ret < 0)
-               return ret;
+       val = ytphy_mii_rd_ext(bus, phy_id, 0xc);
+       if (val < 0)
+               return val;
 
-       ytphy_write_ext(phydev, 0xa000, 2);
-       value = phy_read(phydev, MII_BMCR);
-       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+       /* ext reg 0xc b[7:4]
+        * Tx Delay time = 150ps * N - 250ps
+        */
+       val &= ~(0xf << 4);
+       ret = ytphy_mii_wr_ext(bus, phy_id, 0xc, val);
 
-       ytphy_write_ext(phydev, 0xa000, 0);
+       return ret;
+}
 
-#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+int yt8511_config_out_125m(struct mii_bus *bus, int phy_id)
+{
+       int ret;
+       int val;
 
-       return 0;
-}
+       /* disable auto sleep */
+       val = ytphy_mii_rd_ext(bus, phy_id, 0x27);
+       if (val < 0)
+               return val;
 
-static struct phy_driver motorcomm_phy_drvs[] = {
-       {
-               PHY_ID_MATCH_EXACT(PHY_ID_YT8511),
-               .name           = "YT8511 Gigabit Ethernet",
-               .config_init    = yt8511_config_init,
-               .suspend        = genphy_suspend,
-               .resume         = genphy_resume,
-               .read_page      = yt8511_read_page,
-               .write_page     = yt8511_write_page,
-       },
+       val &= (~BIT(15));
+
+       ret = ytphy_mii_wr_ext(bus, phy_id, 0x27, val);
+       if (ret < 0)
+               return ret;
+
+       /* enable RXC clock when no wire plug */
+       val = ytphy_mii_rd_ext(bus, phy_id, 0xc);
+       if (val < 0)
+               return val;
+
+       /* ext reg 0xc.b[2:1]
+        * 00-----25M from pll;
+        * 01---- 25M from xtl;(default)
+        * 10-----62.5M from pll;
+        * 11----125M from pll(here set to this value)
+        */
+       val |= (3 << 1);
+       ret = ytphy_mii_wr_ext(bus, phy_id, 0xc, val);
+
+#ifdef YT_8511_INIT_TO_MASTER
+       /* for customer, please enable it based on demand.
+        * configure to master
+        */
+
+       /* master/slave config reg*/
+       val = bus->read(bus, phy_id, 0x9);
+       /* to be manual config and force to be master */
+       val |= (0x3 << 11);
+       /* take effect until phy soft reset */
+       ret = bus->write(bus, phy_id, 0x9, val);
+       if (ret < 0)
+               return ret;
+#endif
+
+       return ret;
+}
+
+static int yt8511_config_init(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = ytphy_config_init(phydev);
+
+       netdev_info(phydev->attached_dev, "%s done, phy addr: %d\n",
+                   __func__, phydev->mdio.addr);
+
+       return ret;
+}
+#endif /* GMAC_CLOCK_INPUT_NEEDED */
+
+#if (YTPHY_WOL_FEATURE_ENABLE)
+static int ytphy_switch_reg_space(struct phy_device *phydev, int space)
+{
+       int ret;
+
+       if (space == YTPHY_REG_SPACE_UTP)
+               ret = ytphy_write_ext(phydev, 0xa000, 0);
+       else
+               ret = ytphy_write_ext(phydev, 0xa000, 2);
+
+       return ret;
+}
+
+static int ytphy_wol_feature_enable_cfg(struct phy_device *phydev,
+                                       struct ytphy_wol_feature_cfg wol_cfg)
+{
+       int ret = 0;
+       int val = 0;
+
+       val = ytphy_read_ext(phydev, YTPHY_WOL_FEATURE_REG_CFG);
+       if (val < 0)
+               return val;
+
+       if (wol_cfg.enable) {
+               val |= YTPHY_WOL_FEATURE_ENABLE_CFG;
+
+       if (wol_cfg.type == YTPHY_WOL_FEATURE_LEVEL_TRIGGER) {
+               val &= ~YTPHY_WOL_FEATURE_TYPE_CFG;
+               val &= ~YTPHY_WOL_FEATURE_INTR_SEL_CFG;
+       } else if (wol_cfg.type == YTPHY_WOL_FEATURE_PULSE_TRIGGER) {
+               val |= YTPHY_WOL_FEATURE_TYPE_CFG;
+               val |= YTPHY_WOL_FEATURE_INTR_SEL_CFG;
+
+               if (wol_cfg.width == YTPHY_WOL_FEATURE_84MS_PULSE_WIDTH) {
+                       val &= ~YTPHY_WOL_FEATURE_WIDTH1_CFG;
+                       val &= ~YTPHY_WOL_FEATURE_WIDTH2_CFG;
+               } else if (wol_cfg.width == YTPHY_WOL_FEATURE_168MS_PULSE_WIDTH) {
+                       val |= YTPHY_WOL_FEATURE_WIDTH1_CFG;
+                       val &= ~YTPHY_WOL_FEATURE_WIDTH2_CFG;
+               } else if (wol_cfg.width == YTPHY_WOL_FEATURE_336MS_PULSE_WIDTH) {
+                       val &= ~YTPHY_WOL_FEATURE_WIDTH1_CFG;
+                       val |= YTPHY_WOL_FEATURE_WIDTH2_CFG;
+               } else if (wol_cfg.width == YTPHY_WOL_FEATURE_672MS_PULSE_WIDTH) {
+                       val |= YTPHY_WOL_FEATURE_WIDTH1_CFG;
+                       val |= YTPHY_WOL_FEATURE_WIDTH2_CFG;
+               }
+       }
+       } else {
+               val &= ~YTPHY_WOL_FEATURE_ENABLE_CFG;
+               val &= ~YTPHY_WOL_FEATURE_INTR_SEL_CFG;
+       }
+
+       ret = ytphy_write_ext(phydev, YTPHY_WOL_FEATURE_REG_CFG, val);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void ytphy_wol_feature_get(struct phy_device *phydev,
+                                 struct ethtool_wolinfo *wol)
+{
+       int val = 0;
+
+       wol->supported = WAKE_MAGIC;
+       wol->wolopts = 0;
+
+       val = ytphy_read_ext(phydev, YTPHY_WOL_FEATURE_REG_CFG);
+       if (val < 0)
+               return;
+
+       if (val & YTPHY_WOL_FEATURE_ENABLE_CFG)
+               wol->wolopts |= WAKE_MAGIC;
+
+       //return;
+}
+
+static int ytphy_wol_feature_set(struct phy_device *phydev,
+                                struct ethtool_wolinfo *wol)
+{
+       int ret, curr_reg_space, val;
+       struct ytphy_wol_feature_cfg wol_cfg;
+       struct net_device *p_attached_dev = phydev->attached_dev;
+
+       memset(&wol_cfg, 0, sizeof(struct ytphy_wol_feature_cfg));
+       curr_reg_space = ytphy_read_ext(phydev, 0xa000);
+       if (curr_reg_space < 0)
+               return curr_reg_space;
+
+       /* Switch to phy UTP page */
+       ret = ytphy_switch_reg_space(phydev, YTPHY_REG_SPACE_UTP);
+       if (ret < 0)
+               return ret;
+
+       if (wol->wolopts & WAKE_MAGIC) {
+               /* Enable the WOL feature interrupt */
+               val = phy_read(phydev, YTPHY_UTP_INTR_REG);
+               val |= YTPHY_WOL_FEATURE_INTR;
+               ret = phy_write(phydev, YTPHY_UTP_INTR_REG, val);
+               if (ret < 0)
+                       return ret;
+
+               /* Set the WOL feature config */
+               wol_cfg.enable = true;
+               wol_cfg.type = YTPHY_WOL_FEATURE_PULSE_TRIGGER;
+               wol_cfg.width = YTPHY_WOL_FEATURE_672MS_PULSE_WIDTH;
+               ret = ytphy_wol_feature_enable_cfg(phydev, wol_cfg);
+               if (ret < 0)
+                       return ret;
+
+               /* Store the device address for the magic packet */
+               ret = ytphy_write_ext(phydev, YTPHY_WOL_FEATURE_MACADDR2_4_MAGIC_PACKET,
+                                     ((p_attached_dev->dev_addr[0] << 8) |
+                                     p_attached_dev->dev_addr[1]));
+               if (ret < 0)
+                       return ret;
+               ret = ytphy_write_ext(phydev, YTPHY_WOL_FEATURE_MACADDR1_4_MAGIC_PACKET,
+                                     ((p_attached_dev->dev_addr[2] << 8) |
+                                      p_attached_dev->dev_addr[3]));
+               if (ret < 0)
+                       return ret;
+               ret = ytphy_write_ext(phydev, YTPHY_WOL_FEATURE_MACADDR0_4_MAGIC_PACKET,
+                                     ((p_attached_dev->dev_addr[4] << 8) |
+                                      p_attached_dev->dev_addr[5]));
+               if (ret < 0)
+                       return ret;
+       } else {
+               wol_cfg.enable = false;
+               wol_cfg.type = YTPHY_WOL_FEATURE_TRIGGER_TYPE_MAX;
+               wol_cfg.width = YTPHY_WOL_FEATURE_PULSE_WIDTH_MAX;
+               ret = ytphy_wol_feature_enable_cfg(phydev, wol_cfg);
+               if (ret < 0)
+                       return ret;
+       }
+
+       /* Recover to previous register space page */
+       ret = ytphy_switch_reg_space(phydev, curr_reg_space);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+#endif /*(YTPHY_WOL_FEATURE_ENABLE)*/
+
+static int yt8521_hw_strap_polling(struct phy_device *phydev)
+{
+       int val = 0;
+
+       val = ytphy_read_ext(phydev, 0xa001) & 0x7;
+       switch (val) {
+       case 1:
+       case 4:
+       case 5:
+               return YT8521_PHY_MODE_FIBER;
+       case 2:
+       case 6:
+       case 7:
+               return YT8521_PHY_MODE_POLL;
+       case 3:
+       case 0:
+       default:
+               return YT8521_PHY_MODE_UTP;
+       }
+}
+
+static int ytphy_of_config(struct phy_device *phydev)
+{
+       const struct device_node *of_node;
+       const struct device *dev;
+       u32 val;
+       u32 cfg;
+       int ret;
+       int i = 0;
+
+       dev = &phydev->mdio.dev;
+       do {
+               of_node = dev->of_node;
+               dev = dev->parent;
+               if (i++ > 5) {
+                       phydev_err(phydev, "Get of node timeout\n");
+                       return -EINVAL;
+               }
+       } while (!of_node && dev);
+
+       of_node = of_node->child;
+       if (of_node) {
+               ret = of_property_read_u32(of_node, ytphy_rxden_grp[0].name, &cfg);
+               if (!ret) {
+                       val = ytphy_read_ext(phydev, YTPHY_EXTREG_CHIP_CONFIG);
+
+                       /*check the cfg overflow or not*/
+                       cfg = (cfg > ((1 << ytphy_rxden_grp[0].size) - 1)) ?
+                               ((1 << ytphy_rxden_grp[0].size) - 1) : cfg;
+                       val = bitfield_replace(val, ytphy_rxden_grp[0].off,
+                               ytphy_rxden_grp[0].size, cfg);
+                       ytphy_write_ext(phydev, YTPHY_EXTREG_CHIP_CONFIG, val);
+               }
+
+               val = ytphy_read_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1);
+               for (i = 0; i < ARRAY_SIZE(ytphy_rxtxd_grp); i++) {
+                       ret = of_property_read_u32(of_node, ytphy_rxtxd_grp[i].name, &cfg);
+                       if (!ret) {
+                               cfg = (cfg != -1) ? cfg : ytphy_rxtxd_grp[i].dflt;
+
+                               /*check the cfg overflow or not*/
+                               cfg = (cfg > ((1 << ytphy_rxtxd_grp[i].size) - 1)) ?
+                                       ((1 << ytphy_rxtxd_grp[i].size) - 1) : cfg;
+
+                               val = bitfield_replace(val, ytphy_rxtxd_grp[i].off,
+                                               ytphy_rxtxd_grp[i].size, cfg);
+                       }
+               }
+               return ytphy_write_ext(phydev, YTPHY_EXTREG_RGMII_CONFIG1, val);
+       }
+
+       phydev_err(phydev, "Get of node fail\n");
+       return -EINVAL;
+}
+
+static int yt8521_config_init(struct phy_device *phydev)
+{
+       int ret;
+       int val, hw_strap_mode;
+
+#if (YTPHY_WOL_FEATURE_ENABLE)
+       struct ethtool_wolinfo wol;
+
+       /* set phy wol enable */
+       memset(&wol, 0x0, sizeof(struct ethtool_wolinfo));
+       wol.wolopts |= WAKE_MAGIC;
+       ytphy_wol_feature_set(phydev, &wol);
+#endif
+
+       phydev->irq = PHY_POLL;
+       /* NOTE: this function should not be
+        * called more than one for each chip.
+        */
+       hw_strap_mode = ytphy_read_ext(phydev, 0xa001) & 0x7;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_config_init(phydev);
+
+       if (ret < 0)
+               return ret;
+
+       /* disable auto sleep */
+       val = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1);
+       if (val < 0)
+               return val;
+
+       val &= (~BIT(YT8521_EN_SLEEP_SW_BIT));
+
+       ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, val);
+       if (ret < 0)
+               return ret;
+
+       /*set delay config*/
+       ret = ytphy_of_config(phydev);
+       if (ret < 0)
+               return ret;
+
+       /* enable RXC clock when no wire plug */
+       val = ytphy_read_ext(phydev, 0xc);
+       if (val < 0)
+               return val;
+       val &= ~(1 << 12);
+       ret = ytphy_write_ext(phydev, 0xc, val);
+       if (ret < 0)
+               return ret;
+
+       netdev_info(phydev->attached_dev,
+                   "%s done, phy addr: %d, strap mode = %d, polling mode = %d\n",
+                   __func__, phydev->mdio.addr, hw_strap_mode,
+               yt8521_hw_strap_polling(phydev));
+
+       return ret;
+}
+
+/* for fiber mode, there is no 10M speed mode and
+ * this function is for this purpose.
+ */
+static int yt8521_adjust_status(struct phy_device *phydev, int val, int is_utp)
+{
+       int speed_mode, duplex;
+       int speed = SPEED_UNKNOWN;
+
+       if (is_utp)
+               duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT;
+       else
+               duplex = 1;
+       speed_mode = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT;
+       switch (speed_mode) {
+       case 0:
+               if (is_utp)
+                       speed = SPEED_10;
+               break;
+       case 1:
+               speed = SPEED_100;
+               break;
+       case 2:
+               speed = SPEED_1000;
+               break;
+       case 3:
+               break;
+       default:
+               speed = SPEED_UNKNOWN;
+               break;
+       }
+
+       phydev->speed = speed;
+       phydev->duplex = duplex;
+
+       return 0;
+}
+
+/* for fiber mode, when speed is 100M, there is no definition for
+ * autonegotiation, and this function handles this case and return
+ * 1 per linux kernel's polling.
+ */
+int yt8521_aneg_done(struct phy_device *phydev)
+{
+       int link_fiber = 0, link_utp = 0;
+
+       /* reading Fiber */
+       ytphy_write_ext(phydev, 0xa000, 2);
+       link_fiber = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) &
+                       (BIT(YT8521_LINK_STATUS_BIT)));
+
+       /* reading UTP */
+       ytphy_write_ext(phydev, 0xa000, 0);
+       if (!link_fiber)
+               link_utp = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) &
+                               (BIT(YT8521_LINK_STATUS_BIT)));
+
+       netdev_info(phydev->attached_dev,
+                   "%s, phy addr: %d, link_fiber: %d, link_utp: %d\n",
+                   __func__, phydev->mdio.addr, link_fiber, link_utp);
+
+       return !!(link_fiber | link_utp);
+}
+
+static int yt8521_read_status(struct phy_device *phydev)
+{
+       int ret;
+       int val;
+       int yt8521_fiber_latch_val;
+       int yt8521_fiber_curr_val;
+       int link;
+       int link_utp = 0, link_fiber = 0;
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
+               /* reading UTP */
+               ret = ytphy_write_ext(phydev, 0xa000, 0);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link) {
+                       link_utp = 1;
+                       yt8521_adjust_status(phydev, val, 1);
+               } else {
+                       link_utp = 0;
+               }
+       } //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER)
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) {
+               /* reading Fiber */
+               ret = ytphy_write_ext(phydev, 0xa000, 2);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               //note: below debug information is used to check multiple PHy ports.
+
+               /* for fiber, from 1000m to 100m, there is not link down from 0x11,
+                * and check reg 1 to identify such case this is important for Linux
+                * kernel for that, missing linkdown event will cause problem.
+                */
+               yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR);
+               yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR);
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link && yt8521_fiber_latch_val != yt8521_fiber_curr_val) {
+                       link = 0;
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, fiber link down detect,"
+                                   "latch = %04x, curr = %04x\n",
+                                   __func__, phydev->mdio.addr,
+                                   yt8521_fiber_latch_val,
+                                   yt8521_fiber_curr_val);
+               }
+
+               if (link) {
+                       link_fiber = 1;
+                       yt8521_adjust_status(phydev, val, 0);
+               } else {
+                       link_fiber = 0;
+               }
+       } //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP)
+
+       if (link_utp || link_fiber) {
+               if (phydev->link == 0)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link up, media: %s,"
+                                   "mii reg 0x11 = 0x%x\n",
+                                   __func__, phydev->mdio.addr,
+                                   (link_utp && link_fiber) ?
+                                   "UNKONWN MEDIA" :
+                                   (link_utp ? "UTP" : "Fiber"),
+                                   (unsigned int)val);
+               phydev->link = 1;
+       } else {
+               if (phydev->link == 1)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link down\n",
+                                   __func__, phydev->mdio.addr);
+               phydev->link = 0;
+       }
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {    //utp or combo
+               if (link_fiber)
+                       ytphy_write_ext(phydev, 0xa000, 2);
+               if (link_utp)
+                       ytphy_write_ext(phydev, 0xa000, 0);
+       }
+       return 0;
+}
+
+int yt8521_suspend(struct phy_device *phydev)
+{
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+       int value;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 2);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+
+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+
+       return 0;
+}
+
+int yt8521_resume(struct phy_device *phydev)
+{
+       int value, ret;
+
+       /* disable auto sleep */
+       value = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1);
+       if (value < 0)
+               return value;
+
+       value &= (~BIT(YT8521_EN_SLEEP_SW_BIT));
+
+       ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, value);
+       if (ret < 0)
+               return ret;
+
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               value = phy_read(phydev, MII_BMCR);
+               phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+       }
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) {
+               ytphy_write_ext(phydev, 0xa000, 2);
+               value = phy_read(phydev, MII_BMCR);
+               phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+               ytphy_write_ext(phydev, 0xa000, 0);
+       }
+
+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+
+       return 0;
+}
+
+static int yt8531S_config_init(struct phy_device *phydev)
+{
+       int ret = 0;
+
+#if (YTPHY8531A_XTAL_INIT)
+       ret = yt8531a_xtal_init(phydev);
+       if (ret < 0)
+               return ret;
+#endif
+
+       ret = yt8521_config_init(phydev);
+
+       return ret;
+}
+
+static int yt8531_config_init(struct phy_device *phydev)
+{
+       int ret;
+
+       ret = 0;
+
+       /*set delay config*/
+       ret = ytphy_of_config(phydev);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+int yt8618_soft_reset(struct phy_device *phydev)
+{
+       int ret;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_soft_reset(phydev);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+int yt8614_soft_reset(struct phy_device *phydev)
+{
+       int ret;
+
+       /* qsgmii */
+       ytphy_write_ext(phydev, 0xa000, 2);
+       ret = ytphy_soft_reset(phydev);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+
+       /* sgmii */
+       ytphy_write_ext(phydev, 0xa000, 3);
+       ret = ytphy_soft_reset(phydev);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+
+       /* utp */
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_soft_reset(phydev);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int yt8618_config_init(struct phy_device *phydev)
+{
+       int ret;
+       int val;
+       unsigned int retries = 12;
+#if (YTPHY_861X_ABC_VER)
+       int port = 0;
+#endif
+
+       phydev->irq = PHY_POLL;
+
+#if (YTPHY_861X_ABC_VER)
+       port = yt8614_get_port_from_phydev(phydev);
+#endif
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_config_init(phydev);
+       if (ret < 0)
+               return ret;
+
+       /* for utp to optimize signal */
+       ret = ytphy_write_ext(phydev, 0x41, 0x33);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x42, 0x66);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x43, 0xaa);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x44, 0xd0d);
+       if (ret < 0)
+               return ret;
+
+#if (YTPHY_861X_ABC_VER)
+       if (port == 2 || port == 5) {
+               ret = ytphy_write_ext(phydev, 0x57, 0x2929);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
+       val = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, val | BMCR_RESET);
+       do {
+               msleep(50);
+               ret = phy_read(phydev, MII_BMCR);
+               if (ret < 0)
+                       return ret;
+       } while ((ret & BMCR_RESET) && --retries);
+       if (ret & BMCR_RESET)
+               return -ETIMEDOUT;
+
+       /* for QSGMII optimization */
+       ytphy_write_ext(phydev, 0xa000, 0x02);
+
+       ret = ytphy_write_ext(phydev, 0x3, 0x4F80);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+       ret = ytphy_write_ext(phydev, 0xe, 0x4F80);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+
+       netdev_info(phydev->attached_dev, "%s done, phy addr: %d\n",
+                   __func__, phydev->mdio.addr);
+       return ret;
+}
+
+static int yt8614_hw_strap_polling(struct phy_device *phydev)
+{
+       int val = 0;
+
+       /* b3:0 are work mode, but b3 is always 1 */
+       val = ytphy_read_ext(phydev, 0xa007) & 0xf;
+       switch (val) {
+       case 8:
+       case 12:
+       case 13:
+       case 15:
+               return (YT_PHY_MODE_FIBER | YT_PHY_MODE_UTP);
+       case 14:
+       case 11:
+               return YT_PHY_MODE_FIBER;
+       case 9:
+       case 10:
+       default:
+               return YT_PHY_MODE_UTP;
+       }
+}
+
+#if (YTPHY_861X_ABC_VER)
+static int yt8614_get_port_from_phydev(struct phy_device *phydev)
+{
+       int tmp = ytphy_read_ext(phydev, 0xa0ff);
+       int phy_addr = 0;
+
+       phy_addr = (unsigned int)phydev->mdio.addr;
+
+       if ((phy_addr - tmp) < 0) {
+               ytphy_write_ext(phydev, 0xa0ff, phy_addr);
+               tmp = phy_addr;
+       }
+
+       return (phy_addr - tmp);
+}
+#endif
+
+static int yt8614_config_init(struct phy_device *phydev)
+{
+       int ret = 0;
+       int val, hw_strap_mode;
+       unsigned int retries = 12;
+#if (YTPHY_861X_ABC_VER)
+       int port = 0;
+#endif
+       phydev->irq = PHY_POLL;
+
+       /* NOTE: this function should not be called more than one for each chip. */
+       hw_strap_mode = ytphy_read_ext(phydev, 0xa007) & 0xf;
+
+#if (YTPHY_861X_ABC_VER)
+       port = yt8614_get_port_from_phydev(phydev);
+#endif
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_config_init(phydev);
+       if (ret < 0)
+               return ret;
+
+       /* for utp to optimize signal */
+       ret = ytphy_write_ext(phydev, 0x41, 0x33);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x42, 0x66);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x43, 0xaa);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x44, 0xd0d);
+       if (ret < 0)
+               return ret;
+
+#if (YTPHY_861X_ABC_VER)
+       if (port == 2) {
+               ret = ytphy_write_ext(phydev, 0x57, 0x2929);
+               if (ret < 0)
+                       return ret;
+       }
+#endif
+
+       /* soft reset to take config effect */
+       val = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, val | BMCR_RESET);
+       do {
+               msleep(50);
+               ret = phy_read(phydev, MII_BMCR);
+               if (ret < 0)
+                       return ret;
+       } while ((ret & BMCR_RESET) && --retries);
+       if (ret & BMCR_RESET)
+               return -ETIMEDOUT;
+
+       /* for QSGMII optimization */
+       ytphy_write_ext(phydev, 0xa000, 0x02);
+       ret = ytphy_write_ext(phydev, 0x3, 0x4F80);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+       ret = ytphy_write_ext(phydev, 0xe, 0x4F80);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+
+       /* for SGMII optimization */
+       ytphy_write_ext(phydev, 0xa000, 0x03);
+       ret = ytphy_write_ext(phydev, 0x3, 0x2420);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+       ret = ytphy_write_ext(phydev, 0xe, 0x24a0);
+       if (ret < 0) {
+               ytphy_write_ext(phydev, 0xa000, 0);
+               return ret;
+       }
+
+       /* back up to utp*/
+       ytphy_write_ext(phydev, 0xa000, 0);
+       netdev_info(phydev->attached_dev,
+                   "%s done, phy addr: %d, chip mode: %d\n",
+                   __func__, phydev->mdio.addr, hw_strap_mode);
+
+       return ret;
+}
+
+int yt8618_aneg_done(struct phy_device *phydev)
+{
+       return genphy_aneg_done(phydev);
+}
+
+int yt8614_aneg_done(struct phy_device *phydev)
+{
+       int link_fiber = 0, link_utp = 0;
+
+       /* reading Fiber */
+       ytphy_write_ext(phydev, 0xa000, 3);
+       link_fiber = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) &
+                       (BIT(YT8521_LINK_STATUS_BIT)));
+
+       /* reading UTP */
+       ytphy_write_ext(phydev, 0xa000, 0);
+       if (!link_fiber)
+               link_utp = !!(phy_read(phydev, REG_PHY_SPEC_STATUS) &
+                               (BIT(YT8521_LINK_STATUS_BIT)));
+       return !!(link_fiber | link_utp);
+}
+
+static int yt8614_read_status(struct phy_device *phydev)
+{
+       int ret;
+       int val, yt8614_fiber_latch_val, yt8614_fiber_curr_val;
+       int link;
+       int link_utp = 0, link_fiber = 0;
+
+       if (YT8614_PHY_MODE_CURR & YT_PHY_MODE_UTP) {
+               /* switch to utp and reading regs  */
+               ret = ytphy_write_ext(phydev, 0xa000, 0);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link) {
+                       if (phydev->link == 0)
+                               netdev_info(phydev->attached_dev,
+                                           "%s, phy addr: %d, link up,"
+                                           "UTP, reg 0x11 = 0x%x\n",
+                                           __func__, phydev->mdio.addr,
+                                           (unsigned int)val);
+                       link_utp = 1;
+                       // here is same as 8521 and re-use the function;
+                       yt8521_adjust_status(phydev, val, 1);
+               } else {
+                       link_utp = 0;
+               }
+       }
+
+       if (YT8614_PHY_MODE_CURR & YT_PHY_MODE_FIBER) {
+               /* reading Fiber/sgmii */
+               ret = ytphy_write_ext(phydev, 0xa000, 3);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               /* for fiber, from 1000m to 100m, there is not link down from 0x11,
+                * and check reg 1 to identify such case
+                */
+               yt8614_fiber_latch_val = phy_read(phydev, MII_BMSR);
+               yt8614_fiber_curr_val = phy_read(phydev, MII_BMSR);
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link && yt8614_fiber_latch_val != yt8614_fiber_curr_val) {
+                       link = 0;
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, fiber link down detect,"
+                                   "latch = %04x, curr = %04x\n",
+                                   __func__, phydev->mdio.addr,
+                                   yt8614_fiber_latch_val,
+                                   yt8614_fiber_curr_val);
+               }
+
+               if (link) {
+                       if (phydev->link == 0)
+                               netdev_info(phydev->attached_dev,
+                                           "%s, phy addr: %d, link up, Fiber,"
+                                           "reg 0x11 = 0x%x\n",
+                                           __func__, phydev->mdio.addr,
+                                           (unsigned int)val);
+                       link_fiber = 1;
+                       yt8521_adjust_status(phydev, val, 0);
+               } else {
+                       link_fiber = 0;
+               }
+       }
+
+       if (link_utp || link_fiber) {
+               if (phydev->link == 0)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link up, media %s\n",
+                                   __func__, phydev->mdio.addr,
+                                   (link_utp && link_fiber) ?
+                                   "both UTP and Fiber" :
+                                   (link_utp ? "UTP" : "Fiber"));
+               phydev->link = 1;
+       } else {
+               if (phydev->link == 1)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link down\n",
+                                   __func__, phydev->mdio.addr);
+               phydev->link = 0;
+       }
+
+       if (YT8614_PHY_MODE_CURR & YT_PHY_MODE_UTP) {
+               if (link_utp)
+                       ytphy_write_ext(phydev, 0xa000, 0);
+       }
+       return 0;
+}
+
+static int yt8618_read_status(struct phy_device *phydev)
+{
+       int ret;
+       /* maybe for 8614 yt8521_fiber_latch_val, yt8521_fiber_curr_val; */
+       int val;
+       int link;
+       int link_utp = 0, link_fiber = 0;
+
+       /* switch to utp and reading regs  */
+       ret = ytphy_write_ext(phydev, 0xa000, 0);
+       if (ret < 0)
+               return ret;
+
+       val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+       if (val < 0)
+               return val;
+
+       link = val & (BIT(YT8521_LINK_STATUS_BIT));
+       if (link) {
+               link_utp = 1;
+               yt8521_adjust_status(phydev, val, 1);
+       } else {
+               link_utp = 0;
+       }
+
+       if (link_utp || link_fiber)
+               phydev->link = 1;
+       else
+               phydev->link = 0;
+
+       return 0;
+}
+
+int yt8618_suspend(struct phy_device *phydev)
+{
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+       int value;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+
+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+
+       return 0;
+}
+
+int yt8618_resume(struct phy_device *phydev)
+{
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+       int value;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+
+       return 0;
+}
+
+int yt8614_suspend(struct phy_device *phydev)
+{
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+       int value;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 3);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value | BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+
+#endif /*!(SYS_WAKEUP_BASED_ON_ETH_PKT)*/
+
+       return 0;
+}
+
+int yt8614_resume(struct phy_device *phydev)
+{
+#if !(SYS_WAKEUP_BASED_ON_ETH_PKT)
+       int value;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 3);
+       value = phy_read(phydev, MII_BMCR);
+       phy_write(phydev, MII_BMCR, value & ~BMCR_PDOWN);
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+
+#endif /* !(SYS_WAKEUP_BASED_ON_ETH_PKT) */
+
+       return 0;
+}
+
+int yt8821_soft_reset(struct phy_device *phydev)
+{
+       int ret, val;
+
+       val = ytphy_read_ext(phydev, 0xa001);
+       ytphy_write_ext(phydev, 0xa001, (val & ~0x8000));
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_soft_reset(phydev);
+
+       return ret;
+}
+
+static int yt8821_init(struct phy_device *phydev)
+{
+       int ret = 0;
+       int val = 0;
+
+       /* sds pll cfg */
+       ret = ytphy_write_ext(phydev, 0xa050, 0x1000);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0xa000, 0x2);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x23, 0x47a1);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0xbd, 0x3547);
+       if (ret < 0)
+               return ret;
+
+       /* wait 1s */
+       msleep(1000);
+
+       /* calibration dcc */
+       ret = ytphy_write_ext(phydev, 0xbd, 0xa547);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x29, 0x3003);
+       if (ret < 0)
+               return ret;
+
+       /* sds driver swing */
+       ret = ytphy_write_ext(phydev, 0x25, 0x788);
+       if (ret < 0)
+               return ret;
+
+       /* phy cfg */
+       ret = ytphy_write_ext(phydev, 0xa000, 0x0);
+       if (ret < 0)
+               return ret;
+
+       /* phy template cfg */
+       ret = ytphy_write_ext(phydev, 0x471, 0x4545);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x476, 0x4848);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x477, 0x4848);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x478, 0x4848);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x479, 0x4848);
+       if (ret < 0)
+               return ret;
+
+       /* calibrate phy lc pll */
+       ret = ytphy_write_ext(phydev, 0x600, 0x2300);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x8, 0x8041);
+       if (ret < 0)
+               return ret;
+
+       /* prm_small_lng/med */
+       ret = ytphy_write_ext(phydev, 0x388, 0x90);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x387, 0x90);
+       if (ret < 0)
+               return ret;
+
+       /* echo_delay_cfg */
+       ret = ytphy_write_ext(phydev, 0x3, 0xa026);
+       if (ret < 0)
+               return ret;
+
+       /* pbo setting */
+       ret = ytphy_write_ext(phydev, 0x47e, 0x3535);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x47f, 0x3535);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x480, 0x3535);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x481, 0x3535);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x483, 0x2a2a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x484, 0x2a2a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x485, 0x2a2a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x486, 0x2a2a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x488, 0x2121);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x489, 0x2121);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x48a, 0x2121);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x48b, 0x2121);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x48d, 0x1a1a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x48e, 0x1a1a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x48f, 0x1a1a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x490, 0x1a1a);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x492, 0x1515);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x493, 0x1515);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x494, 0x1515);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x495, 0x1515);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x497, 0x1111);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x498, 0x1111);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x499, 0x1111);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x49a, 0x1111);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x49c, 0x0d0d);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x49d, 0x0d0d);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x49e, 0x0d0d);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0x49f, 0x0d0d);
+       if (ret < 0)
+               return ret;
+       ret = ytphy_write_ext(phydev, 0xa052, 0x7);
+       if (ret < 0)
+               return ret;
+
+       /* fast link down cfg */
+       ret = ytphy_write_ext(phydev, 0x355, 0x7d07);
+       if (ret < 0)
+               return ret;
+
+       /* soft reset */
+       val = phy_read(phydev, MII_BMCR);
+       if (val < 0)
+               return val;
+       ret = phy_write(phydev, MII_BMCR, val | BMCR_RESET);
+
+       return ret;
+}
+
+static int yt8821_config_init(struct phy_device *phydev)
+{
+       int ret;
+       int val, hw_strap_mode;
+
+       phydev->irq = PHY_POLL;
+
+       /* NOTE: this function should not be called more than one for each chip. */
+       hw_strap_mode = ytphy_read_ext(phydev, 0xa001) & 0x7;
+
+       ytphy_write_ext(phydev, 0xa000, 0);
+       ret = ytphy_config_init(phydev);
+       if (ret < 0)
+               return ret;
+
+       ret = yt8821_init(phydev);
+       if (ret < 0)
+               return ret;
+
+       /* disable auto sleep */
+       val = ytphy_read_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1);
+       if (val < 0)
+               return val;
+
+       val &= (~BIT(YT8521_EN_SLEEP_SW_BIT));
+
+       ret = ytphy_write_ext(phydev, YT8521_EXTREG_SLEEP_CONTROL1, val);
+       if (ret < 0)
+               return ret;
+
+       netdev_info(phydev->attached_dev,
+                   "%s done, phy addr: %d, strap mode = %d\n",
+                   __func__, phydev->mdio.addr, hw_strap_mode);
+
+       return ret;
+}
+
+/* for fiber mode, there is no 10M speed mode and
+ * this function is for this purpose.
+ */
+static int yt8821_adjust_status(struct phy_device *phydev, int val, int is_utp)
+{
+       int speed_mode, duplex;
+       int speed_mode_bit15_14, speed_mode_bit9;
+       int speed = SPEED_UNKNOWN;
+
+       if (is_utp)
+               duplex = (val & YT8512_DUPLEX) >> YT8521_DUPLEX_BIT;
+       else
+               duplex = 1;
+
+       /* Bit9-Bit15-Bit14 speed mode 100---2.5G; 010---1000M; 001---100M; 000---10M */
+       speed_mode_bit15_14 = (val & YT8521_SPEED_MODE) >> YT8521_SPEED_MODE_BIT;
+       speed_mode_bit9 = (val & BIT(9)) >> 9;
+       speed_mode = (speed_mode_bit9 << 2) | speed_mode_bit15_14;
+       switch (speed_mode) {
+       case 0:
+               if (is_utp)
+                       speed = SPEED_10;
+               break;
+       case 1:
+               speed = SPEED_100;
+               break;
+       case 2:
+               speed = SPEED_1000;
+               break;
+       case 4:
+               speed = SPEED_2500;
+               break;
+       default:
+               speed = SPEED_UNKNOWN;
+               break;
+       }
+
+       phydev->speed = speed;
+       phydev->duplex = duplex;
+
+       return 0;
+}
+
+static int yt8821_read_status(struct phy_device *phydev)
+{
+       int ret;
+       int val;
+       int yt8521_fiber_latch_val;
+       int yt8521_fiber_curr_val;
+       int link;
+       int link_utp = 0, link_fiber = 0;
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
+               /* reading UTP */
+               ret = ytphy_write_ext(phydev, 0xa000, 0);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link) {
+                       if (link_utp == 0)
+                               netdev_info(phydev->attached_dev,
+                                           "%s, phy addr: %d, link up, UTP,"
+                                           "reg 0x11 = 0x%x\n",
+                                           __func__, phydev->mdio.addr,
+                                           (unsigned int)val);
+                       link_utp = 1;
+                       /* speed(2500), duplex */
+                       yt8821_adjust_status(phydev, val, 1);
+               } else {
+                       link_utp = 0;
+               }
+       } //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER)
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP) {
+               /* reading Fiber */
+               ret = ytphy_write_ext(phydev, 0xa000, 2);
+               if (ret < 0)
+                       return ret;
+
+               val = phy_read(phydev, REG_PHY_SPEC_STATUS);
+               if (val < 0)
+                       return val;
+
+               //note: below debug information is used to check multiple PHy ports.
+
+               /* for fiber, from 1000m to 100m, there is not link down from 0x11,
+                * and check reg 1 to identify such case this is important for Linux
+                * kernel for that, missing linkdown event will cause problem.
+                */
+               yt8521_fiber_latch_val = phy_read(phydev, MII_BMSR);
+               yt8521_fiber_curr_val = phy_read(phydev, MII_BMSR);
+               link = val & (BIT(YT8521_LINK_STATUS_BIT));
+               if (link && yt8521_fiber_latch_val != yt8521_fiber_curr_val) {
+                       link = 0;
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, fiber link down detect,"
+                                   "latch = %04x, curr = %04x\n",
+                                   __func__, phydev->mdio.addr,
+                                   yt8521_fiber_latch_val,
+                                   yt8521_fiber_curr_val);
+               }
+
+               if (link) {
+                       if (link_fiber == 0)
+                               netdev_info(phydev->attached_dev,
+                                           "%s, phy addr: %d, link up, Fiber,"
+                                           "reg 0x11 = 0x%x\n",
+                                           __func__, phydev->mdio.addr,
+                                           (unsigned int)val);
+                       link_fiber = 1;
+                       yt8821_adjust_status(phydev, val, 0);
+               } else {
+                       link_fiber = 0;
+               }
+       } //(YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_UTP)
+
+       if (link_utp || link_fiber) {
+               if (phydev->link == 0)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link up, media %s,"
+                                   "reg 0x11 = 0x%x\n",
+                                   __func__, phydev->mdio.addr,
+                                   (link_utp && link_fiber) ?
+                                   "both UTP and Fiber" :
+                                   (link_utp ? "UTP" : "Fiber"),
+                                   (unsigned int)val);
+               phydev->link = 1;
+       } else {
+               if (phydev->link == 1)
+                       netdev_info(phydev->attached_dev,
+                                   "%s, phy addr: %d, link down\n",
+                                   __func__, phydev->mdio.addr);
+               phydev->link = 0;
+       }
+
+       if (YT8521_PHY_MODE_CURR != YT8521_PHY_MODE_FIBER) {
+               if (link_utp)
+                       ytphy_write_ext(phydev, 0xa000, 0);
+       }
+       return 0;
+}
+
+static int yt8821_get_features(struct phy_device *phydev)
+{
+       linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT, phydev->supported, 1);
+       return genphy_read_abilities(phydev);
+}
+
+static struct phy_driver ytphy_drvs[] = {
        {
-               PHY_ID_MATCH_EXACT(PHY_ID_YT8521),
-               .name           = "YT8521 Gigabit Ethernet",
-               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
-               .flags          = PHY_POLL,
-               .soft_reset     = yt8521_soft_reset,
-               .config_aneg    = genphy_config_aneg,
-               .aneg_done      = genphy_aneg_done,
-               .config_init    = yt8521_config_init,
-               .read_status    = yt8521_read_status,
-               .suspend        = yt8521_suspend,
-               .resume         = yt8521_resume,
-#if (YTPHY_ENABLE_WOL)
-               .get_wol        = &ytphy_get_wol,
-               .set_wol        = &ytphy_set_wol,
+               .phy_id         = PHY_ID_YT8010,
+               .name           = "YT8010 Automotive Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_BASIC_FEATURES,
+               .flags          = PHY_POLL,
+               .soft_reset     = yt8010_soft_reset,
+               .config_aneg    = yt8010_config_aneg,
+               .aneg_done      = yt8010_aneg_done,
+               .config_init    = ytphy_config_init,
+               .read_status    = yt8010_read_status,
+       }, {
+               .phy_id         = PHY_ID_YT8010AS,
+               .name           = "YT8010AS Automotive Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_BASIC_FEATURES,
+               .flags          = PHY_POLL,
+               .soft_reset     = yt8010AS_soft_reset,
+               .aneg_done      = yt8010_aneg_done,
+               .config_init    = yt8010AS_config_init,
+               .read_status    = yt8010_read_status,
+       }, {
+               .phy_id         = PHY_ID_YT8510,
+               .name           = "YT8510 100/10Mb Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_BASIC_FEATURES,
+               .flags          = PHY_POLL,
+               .config_aneg    = genphy_config_aneg,
+               .config_init    = ytphy_config_init,
+               .read_status    = genphy_read_status,
+       }, {
+               .phy_id         = PHY_ID_YT8511,
+               .name           = "YT8511 Gigabit Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_POLL,
+               .config_aneg    = genphy_config_aneg,
+#if GMAC_CLOCK_INPUT_NEEDED
+               .config_init    = yt8511_config_init,
+#else
+               .config_init    = ytphy_config_init,
 #endif
+               .read_status    = genphy_read_status,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+       }, {
+               .phy_id         = PHY_ID_YT8512,
+               .name           = "YT8512 Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_BASIC_FEATURES,
+               .flags          = PHY_POLL,
+               .config_aneg    = genphy_config_aneg,
+               .config_init    = yt8512_config_init,
+               .read_status    = yt8512_read_status,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+       }, {
+               .phy_id         = PHY_ID_YT8512B,
+               .name           = "YT8512B Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_BASIC_FEATURES,
+               .flags          = PHY_POLL,
+               .config_aneg    = genphy_config_aneg,
+               .config_init    = yt8512_config_init,
+               .read_status    = yt8512_read_status,
+               .suspend        = genphy_suspend,
+               .resume         = genphy_resume,
+       }, {
+               .phy_id         = PHY_ID_YT8521,
+               .name           = "YT8521 Ethernet",
+               .phy_id_mask    = MOTORCOMM_PHY_ID_MASK,
+               .features       = PHY_GBIT_FEATURES,
+               .flags          = PHY_POLL,
+               .soft_reset     = yt8521_soft_reset,
+               .config_aneg    = genphy_config_aneg,
+               .aneg_done      = yt8521_aneg_done,
+               .config_init    = yt8521_config_init,
+               .read_status    = yt8521_read_status,
+               .suspend        = yt8521_suspend,
+               .resume         = yt8521_resume,
+#if (YTPHY_WOL_FEATURE_ENABLE)
+               .get_wol        = &ytphy_wol_feature_get,
+               .set_wol        = &ytphy_wol_feature_set,
+#endif
+       }, {
+               /* same as 8521 */
+               .phy_id        = PHY_ID_YT8531S,
+               .name          = "YT8531S Ethernet",
+               .phy_id_mask   = MOTORCOMM_PHY_ID_MASK,
+               .features      = PHY_GBIT_FEATURES,
+               .flags         = PHY_POLL,
+               .soft_reset    = yt8521_soft_reset,
+               .config_aneg   = genphy_config_aneg,
+               .aneg_done     = yt8521_aneg_done,
+               .config_init   = yt8531S_config_init,
+               .read_status   = yt8521_read_status,
+               .suspend       = yt8521_suspend,
+               .resume        = yt8521_resume,
+#if (YTPHY_WOL_FEATURE_ENABLE)
+               .get_wol       = &ytphy_wol_feature_get,
+               .set_wol       = &ytphy_wol_feature_set,
+#endif
+       }, {
+               /* same as 8511 */
+               .phy_id        = PHY_ID_YT8531,
+               .name          = "YT8531 Gigabit Ethernet",
+               .phy_id_mask   = MOTORCOMM_PHY_ID_MASK,
+               .features      = PHY_GBIT_FEATURES,
+               .flags         = PHY_POLL,
+               .config_aneg   = genphy_config_aneg,
+
+               .config_init   = yt8531_config_init,
+               .read_status   = genphy_read_status,
+               .suspend       = genphy_suspend,
+               .resume        = genphy_resume,
+#if (YTPHY_WOL_FEATURE_ENABLE)
+               .get_wol       = &ytphy_wol_feature_get,
+               .set_wol       = &ytphy_wol_feature_set,
+#endif
+       }, {
+               .phy_id        = PHY_ID_YT8618,
+               .name          = "YT8618 Ethernet",
+               .phy_id_mask   = MOTORCOMM_MPHY_ID_MASK,
+               .features      = PHY_GBIT_FEATURES,
+               .flags         = PHY_POLL,
+               .soft_reset    = yt8618_soft_reset,
+               .config_aneg   = genphy_config_aneg,
+               .aneg_done     = yt8618_aneg_done,
+               .config_init   = yt8618_config_init,
+               .read_status   = yt8618_read_status,
+               .suspend       = yt8618_suspend,
+               .resume        = yt8618_resume,
+       },
+       {
+               .phy_id        = PHY_ID_YT8614,
+               .name          = "YT8614 Ethernet",
+               .phy_id_mask   = MOTORCOMM_MPHY_ID_MASK_8614,
+               .features      = PHY_GBIT_FEATURES,
+               .flags         = PHY_POLL,
+               .soft_reset    = yt8614_soft_reset,
+               .config_aneg   = genphy_config_aneg,
+               .aneg_done     = yt8614_aneg_done,
+               .config_init   = yt8614_config_init,
+               .read_status   = yt8614_read_status,
+               .suspend       = yt8614_suspend,
+               .resume        = yt8614_resume,
+       },
+       {
+               .phy_id        = PHY_ID_YT8821,
+               .name          = "YT8821 2.5Gb Ethernet",
+               .phy_id_mask   = MOTORCOMM_PHY_ID_MASK_8821,
+               .flags         = PHY_POLL,
+               .soft_reset    = yt8821_soft_reset,
+               .config_aneg   = genphy_config_aneg,
+               .aneg_done     = yt8521_aneg_done,
+               .get_features  = yt8821_get_features,
+               .config_init   = yt8821_config_init,
+               .read_status   = yt8821_read_status,
+               .suspend       = yt8521_suspend,
+               .resume        = yt8521_resume,
        },
 };
 
-module_phy_driver(motorcomm_phy_drvs);
+/* for linux 4.x */
+module_phy_driver(ytphy_drvs);
 
 MODULE_DESCRIPTION("Motorcomm PHY driver");
-MODULE_AUTHOR("Peter Geis");
-MODULE_AUTHOR("Walker Chen <walker.chen@starfivetech.com>");
+MODULE_AUTHOR("Leilei Zhao");
 MODULE_LICENSE("GPL");
 
-static const struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
-       { PHY_ID_MATCH_EXACT(PHY_ID_YT8511) },
-       { PHY_ID_MATCH_EXACT(PHY_ID_YT8521) },
-       { /* sentinal */ }
+static struct mdio_device_id __maybe_unused motorcomm_tbl[] = {
+       { PHY_ID_YT8010, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8510, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8511, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8512, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8512B, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8521, MOTORCOMM_PHY_ID_MASK },
+       { PHY_ID_YT8531S, MOTORCOMM_PHY_ID_8531_MASK },
+       { PHY_ID_YT8531, MOTORCOMM_PHY_ID_8531_MASK },
+       { PHY_ID_YT8618, MOTORCOMM_MPHY_ID_MASK },
+       { PHY_ID_YT8614, MOTORCOMM_MPHY_ID_MASK_8614 },
+       { PHY_ID_YT8821, MOTORCOMM_PHY_ID_MASK_8821 },
+       { }
 };
 
 MODULE_DEVICE_TABLE(mdio, motorcomm_tbl);
+
index 497c48b..5eb62f8 100644 (file)
@@ -1314,6 +1314,14 @@ config RTC_DRV_NTXEC
          embedded controller found in certain e-book readers designed by the
          original design manufacturer Netronix.
 
+config RTC_DRV_STARFIVE
+       tristate "StarFive 32.768k-RTC"
+       depends on SOC_STARFIVE
+       depends on OF
+       help
+         If you say Y here you will get support for the RTC found on
+         StarFive SOCS.
+
 comment "on-CPU RTC drivers"
 
 config RTC_DRV_ASM9260
@@ -1587,14 +1595,6 @@ config RTC_DRV_STARFIRE
          If you say Y here you will get support for the RTC found on
          Starfire systems.
 
-config RTC_DRV_STARFIVE
-       tristate "StarFive 32.768k-RTC"
-       depends on RISCV
-       depends on OF
-       help
-         If you say Y here you will get support for the RTC found on
-         StarFive SOCS.
-
 config RTC_DRV_MV
        tristate "Marvell SoC RTC"
        depends on ARCH_DOVE || ARCH_MVEBU || COMPILE_TEST
old mode 100644 (file)
new mode 100755 (executable)
index 0a32950..f0064b1
@@ -1583,7 +1583,7 @@ int ac10x_fill_regcache(struct device* dev, struct regmap* map) {
                regcache_cache_bypass(map, true);
                r = regmap_read(map, i, &v);
                if (r) {
-                       dev_err(dev, "failed to read register %d\n", i);
+                       dev_dbg(dev, "failed to read register %d\n", i);
                        continue;
                }
                regcache_cache_bypass(map, false);
old mode 100644 (file)
new mode 100755 (executable)
index 316a835..a4afb1f
 #define _MASTER_INDEX  0
 
 /**
- * TODO: 
- * 1, add PM API:  ac108_suspend,ac108_resume 
- * 2,0x65-0x6a 
- * 3,0x76-0x79 high 4bit 
+ * TODO:
+ * 1, add PM API:  ac108_suspend,ac108_resume
+ * 2,0x65-0x6a
+ * 3,0x76-0x79 high 4bit
  */
 struct pll_div {
        unsigned int freq_in;
@@ -82,7 +82,7 @@ static const struct real_val_to_reg_val ac108_samp_res[] = {
        { 32, 7 },
 };
 
-static const unsigned ac108_bclkdivs[] = {
+static const unsigned int ac108_bclkdivs[] = {
         0,   1,   2,   4,
         6,   8,  12,  16,
        24,  32,  48,  64,
@@ -92,10 +92,10 @@ static const unsigned ac108_bclkdivs[] = {
 /* FOUT =(FIN * N) / [(M1+1) * (M2+1)*(K1+1)*(K2+1)] ; M1[0,31],  M2[0,1],  N[0,1023],  K1[0,31],  K2[0,1] */
 static const struct pll_div ac108_pll_div_list[] = {
        { 400000,   _FREQ_24_576K, 0,  0, 614, 4, 1 },
-       { 512000,   _FREQ_24_576K, 0,  0, 960, 9, 1 }, //_FREQ_24_576K/48
-       { 768000,   _FREQ_24_576K, 0,  0, 640, 9, 1 }, //_FREQ_24_576K/32
+       { 512000,   _FREQ_24_576K, 0,  0, 960, 9, 1 }, /* _FREQ_24_576K/48 */
+       { 768000,   _FREQ_24_576K, 0,  0, 640, 9, 1 }, /* _FREQ_24_576K/32 */
        { 800000,   _FREQ_24_576K, 0,  0, 614, 9, 1 },
-       { 1024000,  _FREQ_24_576K, 0,  0, 480, 9, 1 }, //_FREQ_24_576K/24
+       { 1024000,  _FREQ_24_576K, 0,  0, 480, 9, 1 }, /* _FREQ_24_576K/24 */
        { 1600000,  _FREQ_24_576K, 0,  0, 307, 9, 1 },
        { 2048000,  _FREQ_24_576K, 0,  0, 240, 9, 1 }, /* accurate,  8000 * 256 */
        { 3072000,  _FREQ_24_576K, 0,  0, 160, 9, 1 }, /* accurate, 12000 * 256 */
@@ -107,7 +107,7 @@ static const struct pll_div ac108_pll_div_list[] = {
        { 16000000, _FREQ_24_576K, 12, 0, 400, 9, 1 },
        { 19200000, _FREQ_24_576K, 15, 0, 410, 9, 1 },
        { 19680000, _FREQ_24_576K, 15, 0, 400, 9, 1 },
-       { 24000000, _FREQ_24_576K, 4,  0, 128,24, 0 }, // accurate, 24M -> 24.576M */
+       { 24000000, _FREQ_24_576K, 9,  0, 256,24, 0 }, /* accurate, 24M -> 24.576M */
 
        { 400000,   _FREQ_22_579K, 0,  0, 566, 4, 1 },
        { 512000,   _FREQ_22_579K, 0,  0, 880, 9, 1 },
@@ -125,35 +125,35 @@ static const struct pll_div ac108_pll_div_list[] = {
        { 16000000, _FREQ_22_579K, 11, 0, 340, 9, 1 },
        { 19200000, _FREQ_22_579K, 13, 0, 330, 9, 1 },
        { 19680000, _FREQ_22_579K, 14, 0, 345, 9, 1 },
-       { 24000000, _FREQ_22_579K, 24, 0, 588,24, 0 }, // accurate, 24M -> 22.5792M */
-
-
-       { _FREQ_24_576K / 1,   _FREQ_24_576K, 9,  0, 200, 9, 1 }, //_FREQ_24_576K
-       { _FREQ_24_576K / 2,   _FREQ_24_576K, 9,  0, 400, 9, 1 }, /*12288000,accurate, 48000 * 256 */
-       { _FREQ_24_576K / 4,   _FREQ_24_576K, 4,  0, 400, 9, 1 }, /*6144000, accurate, 24000 * 256 */
-       { _FREQ_24_576K / 16,  _FREQ_24_576K, 0,  0, 320, 9, 1 }, //1536000
-       { _FREQ_24_576K / 64,  _FREQ_24_576K, 0,  0, 640, 4, 1 }, //384000
-       { _FREQ_24_576K / 96,  _FREQ_24_576K, 0,  0, 960, 4, 1 }, //256000
-       { _FREQ_24_576K / 128, _FREQ_24_576K, 0,  0, 512, 1, 1 }, //192000
-       { _FREQ_24_576K / 176, _FREQ_24_576K, 0,  0, 880, 4, 0 }, //140000
-       { _FREQ_24_576K / 192, _FREQ_24_576K, 0,  0, 960, 4, 0 }, //128000
-
-       { _FREQ_22_579K / 1,   _FREQ_22_579K, 9,  0, 200, 9, 1 }, //_FREQ_22_579K
-       { _FREQ_22_579K / 2,   _FREQ_22_579K, 9,  0, 400, 9, 1 }, /*11289600,accurate, 44100 * 256 */
-       { _FREQ_22_579K / 4,   _FREQ_22_579K, 4,  0, 400, 9, 1 }, /*5644800, accurate, 22050 * 256 */
-       { _FREQ_22_579K / 16,  _FREQ_22_579K, 0,  0, 320, 9, 1 }, //1411200
-       { _FREQ_22_579K / 64,  _FREQ_22_579K, 0,  0, 640, 4, 1 }, //352800
-       { _FREQ_22_579K / 96,  _FREQ_22_579K, 0,  0, 960, 4, 1 }, //235200
-       { _FREQ_22_579K / 128, _FREQ_22_579K, 0,  0, 512, 1, 1 }, //176400
-       { _FREQ_22_579K / 176, _FREQ_22_579K, 0,  0, 880, 4, 0 }, //128290
-       { _FREQ_22_579K / 192, _FREQ_22_579K, 0,  0, 960, 4, 0 }, //117600
-
-       { _FREQ_22_579K / 6,   _FREQ_22_579K, 2,  0, 360, 9, 1 }, //3763200
-       { _FREQ_22_579K / 8,   _FREQ_22_579K, 0,  0, 160, 9, 1 }, /*2822400, accurate, 11025 * 256 */
-       { _FREQ_22_579K / 12,  _FREQ_22_579K, 0,  0, 240, 9, 1 }, //1881600
-       { _FREQ_22_579K / 24,  _FREQ_22_579K, 0,  0, 480, 9, 1 }, //940800
-       { _FREQ_22_579K / 32,  _FREQ_22_579K, 0,  0, 640, 9, 1 }, //705600
-       { _FREQ_22_579K / 48,  _FREQ_22_579K, 0,  0, 960, 9, 1 }, //470400
+       { 24000000, _FREQ_22_579K, 24, 0, 588,24, 0 }, /* accurate, 24M -> 22.5792M */
+
+
+       { _FREQ_24_576K / 1,   _FREQ_24_576K, 9,  0, 200, 9, 1 }, /* _FREQ_24_576K */
+       { _FREQ_24_576K / 2,   _FREQ_24_576K, 9,  0, 400, 9, 1 }, /* 12288000,accurate, 48000 * 256 */
+       { _FREQ_24_576K / 4,   _FREQ_24_576K, 4,  0, 400, 9, 1 }, /* 6144000, accurate, 24000 * 256 */
+       { _FREQ_24_576K / 16,  _FREQ_24_576K, 0,  0, 320, 9, 1 }, /* 1536000 */
+       { _FREQ_24_576K / 64,  _FREQ_24_576K, 0,  0, 640, 4, 1 }, /* 384000 */
+       { _FREQ_24_576K / 96,  _FREQ_24_576K, 0,  0, 960, 4, 1 }, /* 256000 */
+       { _FREQ_24_576K / 128, _FREQ_24_576K, 0,  0, 512, 1, 1 }, /* 192000 */
+       { _FREQ_24_576K / 176, _FREQ_24_576K, 0,  0, 880, 4, 0 }, /* 140000 */
+       { _FREQ_24_576K / 192, _FREQ_24_576K, 0,  0, 960, 4, 0 }, /* 128000 */
+
+       { _FREQ_22_579K / 1,   _FREQ_22_579K, 9,  0, 200, 9, 1 }, /* _FREQ_22_579K */
+       { _FREQ_22_579K / 2,   _FREQ_22_579K, 9,  0, 400, 9, 1 }, /* 11289600,accurate, 44100 * 256 */
+       { _FREQ_22_579K / 4,   _FREQ_22_579K, 4,  0, 400, 9, 1 }, /* 5644800, accurate, 22050 * 256 */
+       { _FREQ_22_579K / 16,  _FREQ_22_579K, 0,  0, 320, 9, 1 }, /* 1411200 */
+       { _FREQ_22_579K / 64,  _FREQ_22_579K, 0,  0, 640, 4, 1 }, /* 352800 */
+       { _FREQ_22_579K / 96,  _FREQ_22_579K, 0,  0, 960, 4, 1 }, /* 235200 */
+       { _FREQ_22_579K / 128, _FREQ_22_579K, 0,  0, 512, 1, 1 }, /* 176400 */
+       { _FREQ_22_579K / 176, _FREQ_22_579K, 0,  0, 880, 4, 0 }, /* 128290 */
+       { _FREQ_22_579K / 192, _FREQ_22_579K, 0,  0, 960, 4, 0 }, /* 117600 */
+
+       { _FREQ_22_579K / 6,   _FREQ_22_579K, 2,  0, 360, 9, 1 }, /* 3763200 */
+       { _FREQ_22_579K / 8,   _FREQ_22_579K, 0,  0, 160, 9, 1 }, /* 2822400, accurate, 11025 * 256 */
+       { _FREQ_22_579K / 12,  _FREQ_22_579K, 0,  0, 240, 9, 1 }, /* 1881600 */
+       { _FREQ_22_579K / 24,  _FREQ_22_579K, 0,  0, 480, 9, 1 }, /* 940800 */
+       { _FREQ_22_579K / 32,  _FREQ_22_579K, 0,  0, 640, 9, 1 }, /* 705600 */
+       { _FREQ_22_579K / 48,  _FREQ_22_579K, 0,  0, 960, 9, 1 }, /* 470400 */
 };
 
 
@@ -168,34 +168,34 @@ static const struct pll_div ac108_pll_div_list[] = {
                                        SNDRV_PCM_FMTBIT_S32_LE)
 
 static const DECLARE_TLV_DB_SCALE(tlv_adc_pga_gain, 0, 100, 0);
-static const DECLARE_TLV_DB_SCALE(tlv_ch_digital_vol, -11925,75,0);
+static const DECLARE_TLV_DB_SCALE(tlv_ch_digital_vol, -11925, 75, 0);
 
-int ac10x_read(u8 reg, u8* rt_val, struct regmap* i2cm) {
+int ac10x_read(u8 reg, u8* rt_val, struct regmap* i2cm)
+{
        int r, v = 0;
 
-       if ((r = regmap_read(i2cm, reg, &v)) < 0) {
-               pr_err("ac10x_read error->[REG-0x%02x]\n", reg);
-       } else {
+       if ((r = regmap_read(i2cm, reg, &v)) < 0)
+               pr_info("ac10x_read info->[REG-0x%02x]\n", reg);
+       else
                *rt_val = v;
-       }
        return r;
 }
 
-int ac10x_write(u8 reg, u8 val, struct regmap* i2cm) {
+int ac10x_write(u8 reg, u8 val, struct regmap* i2cm)
+{
        int r;
 
-       if ((r = regmap_write(i2cm, reg, val)) < 0) {
-               pr_err("ac10x_write error->[REG-0x%02x,val-0x%02x]\n", reg, val);
-       }
+       if ((r = regmap_write(i2cm, reg, val)) < 0)
+               pr_info("ac10x_write info->[REG-0x%02x,val-0x%02x]\n", reg, val);
        return r;
 }
 
-int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct regmap* i2cm) {
+int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct regmap* i2cm)
+{
        int r;
 
-       if ((r = regmap_update_bits(i2cm, reg, mask, val)) < 0) {
-               pr_err("%s() error->[REG-0x%02x,val-0x%02x]\n", __func__, reg, val);
-       }
+       if ((r = regmap_update_bits(i2cm, reg, mask, val)) < 0)
+               pr_info("%s() info->[REG-0x%02x,val-0x%02x]\n", __func__, reg, val);
        return r;
 }
 
@@ -210,8 +210,8 @@ int ac10x_update_bits(u8 reg, u8 mask, u8 val, struct regmap* i2cm) {
  * Returns 0 for success.
  */
 static int snd_ac108_get_volsw(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol
-){
+       struct snd_ctl_elem_value *ucontrol)
+{
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int mask = (1 << fls(mc->max)) - 1;
@@ -241,8 +241,8 @@ static int snd_ac108_get_volsw(struct snd_kcontrol *kcontrol,
  * Returns 0 for success.
  */
 static int snd_ac108_put_volsw(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol
-){
+       struct snd_ctl_elem_value *ucontrol)
+{
        struct soc_mixer_control *mc =
                (struct soc_mixer_control *)kcontrol->private_value;
        unsigned int sign_bit = mc->sign_bit;
@@ -338,7 +338,7 @@ static const struct snd_kcontrol_new ac108tdm_snd_controls[] = {
 
 
 static const struct snd_soc_dapm_widget ac108_dapm_widgets[] = {
-       //input widgets
+       /* input widgets */
        SND_SOC_DAPM_INPUT("MIC1P"),
        SND_SOC_DAPM_INPUT("MIC1N"),
 
@@ -444,25 +444,25 @@ static const struct snd_soc_dapm_route ac108_dapm_routes[] = {
 
 };
 
-static int ac108_multi_write(u8 reg, u8 val, struct ac10x_priv *ac10x) {
+static int ac108_multi_write(u8 reg, u8 val, struct ac10x_priv *ac10x)
+{
        u8 i;
-       for (i = 0; i < ac10x->codec_cnt; i++) {
+       for (i = 0; i < ac10x->codec_cnt; i++)
                ac10x_write(reg, val, ac10x->i2cmap[i]);
-       }
        return 0;
 }
 
-static int ac108_multi_update_bits(u8 reg, u8 mask, u8 val, struct ac10x_priv *ac10x) {
+static int ac108_multi_update_bits(u8 reg, u8 mask, u8 val, struct ac10x_priv *ac10x)
+{
        int r = 0;
        u8 i;
-
-       for (i = 0; i < ac10x->codec_cnt; i++) {
+       for (i = 0; i < ac10x->codec_cnt; i++)
                r |= ac10x_update_bits(reg, mask, val, ac10x->i2cmap[i]);
-       }
        return r;
 }
 
-static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int reg) {
+static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int reg)
+{
        unsigned char val_r;
        struct ac10x_priv *ac10x = dev_get_drvdata(codec->dev);
        /*read one chip is fine*/
@@ -470,7 +470,8 @@ static unsigned int ac108_codec_read(struct snd_soc_codec *codec, unsigned int r
        return val_r;
 }
 
-static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val) {
+static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsigned int val)
+{
        struct ac10x_priv *ac10x = dev_get_drvdata(codec->dev);
        ac108_multi_write(reg, val, ac10x);
        return 0;
@@ -480,28 +481,29 @@ static int ac108_codec_write(struct snd_soc_codec *codec, unsigned int reg, unsi
  * The Power management related registers are Reg01h~Reg09h
  * 0x01-0x05,0x08,use the default value
  * @author baozhu (17-6-21)
- * 
- * @param ac10x 
+ *
+ * @param ac10x
  */
-static void ac108_configure_power(struct ac10x_priv *ac10x) {
+static void ac108_configure_power(struct ac10x_priv *ac10x)
+{
        /**
         * 0x06:Enable Analog LDO
         */
        ac108_multi_update_bits(PWR_CTRL6, 0x01 << LDO33ANA_ENABLE, 0x01 << LDO33ANA_ENABLE, ac10x);
        /**
         * 0x07: 
-        * Control VREF output and micbias voltage ? 
-        * REF faststart disable, enable Enable VREF (needed for Analog 
-        * LDO and MICBIAS) 
+        * Control VREF output and micbias voltage ?
+        * REF faststart disable, enable Enable VREF (needed for Analog
+        * LDO and MICBIAS)
         */
        ac108_multi_update_bits(PWR_CTRL7, 0x1f << VREF_SEL | 0x01 << VREF_FASTSTART_ENABLE | 0x01 << VREF_ENABLE,
                                           0x13 << VREF_SEL | 0x00 << VREF_FASTSTART_ENABLE | 0x01 << VREF_ENABLE, ac10x);
        /**
-        * 0x09: 
-        * Disable fast-start circuit on VREFP 
-        * VREFP_RESCTRL=00=1 MOhm 
-        * IGEN_TRIM=100=+25% 
-        * Enable VREFP (needed by all audio input channels) 
+        * 0x09:
+        * Disable fast-start circuit on VREFP
+        * VREFP_RESCTRL=00=1 MOhm
+        * IGEN_TRIM=100=+25%
+        * Enable VREFP (needed by all audio input channels)
         */
        ac108_multi_update_bits(PWR_CTRL9, 0x01 << VREFP_FASTSTART_ENABLE | 0x03 << VREFP_RESCTRL | 0x07 << IGEN_TRIM | 0x01 << VREFP_ENABLE,
                                           0x00 << VREFP_FASTSTART_ENABLE | 0x00 << VREFP_RESCTRL | 0x04 << IGEN_TRIM | 0x01 << VREFP_ENABLE,
@@ -512,13 +514,14 @@ static void ac108_configure_power(struct ac10x_priv *ac10x) {
  * The clock management related registers are Reg20h~Reg25h
  * The PLL management related registers are Reg10h~Reg18h.
  * @author baozhu (17-6-20)
- * 
- * @param ac10x 
+ *
+ * @param ac10x
  * @param rate : sample rate
- * 
+ *
  * @return int : fail or success
  */
-static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lrck_ratio) {
+static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lrck_ratio)
+{
        unsigned int i = 0;
        struct pll_div ac108_pll_div = { 0 };
 
@@ -539,7 +542,7 @@ static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lr
                for (i = 0; i < ARRAY_SIZE(ac108_pll_div_list); i++) {
                        if (ac108_pll_div_list[i].freq_in == pll_freq_in && ac108_pll_div_list[i].freq_out % rate == 0) {
                                ac108_pll_div = ac108_pll_div_list[i];
-                               dev_dbg(&ac10x->i2c[_MASTER_INDEX]->dev, "AC108 PLL freq_in match:%u, freq_out:%u\n\n",
+                               dev_info(&ac10x->i2c[_MASTER_INDEX]->dev, "AC108 PLL freq_in match:%u, freq_out:%u\n\n",
                                                                ac108_pll_div.freq_in, ac108_pll_div.freq_out);
                                break;
                        }
@@ -559,7 +562,7 @@ static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lr
                 * 0x20: enable pll, pll source from mclk/bclk, sysclk source from pll, enable sysclk
                 */
                ac108_multi_update_bits(SYSCLK_CTRL, 0x01 << PLLCLK_EN | 0x03  << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN,
-                                                    0x01 << PLLCLK_EN |pll_src<< PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac10x);
+                                                    0x01 << PLLCLK_EN | pll_src << PLLCLK_SRC | 0x01 << SYSCLK_SRC | 0x01 << SYSCLK_EN, ac10x);
                ac10x->mclk = ac108_pll_div.freq_out;
        }
        if (ac10x->clk_id == SYSCLK_SRC_MCLK) {
@@ -577,7 +580,8 @@ static int ac108_config_pll(struct ac10x_priv *ac10x, unsigned rate, unsigned lr
 /*
  * support no more than 16 slots.
  */
-static int ac108_multi_chips_slots(struct ac10x_priv *ac, int slots) {
+static int ac108_multi_chips_slots(struct ac10x_priv *ac, int slots)
+{
        int i;
 
        /*
@@ -643,7 +647,9 @@ static int ac108_multi_chips_slots(struct ac10x_priv *ac, int slots) {
        return 0;
 }
 
-static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) {
+static int ac108_hw_params(struct snd_pcm_substream *substream,
+       struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
+{
        unsigned int i, channels, samp_res, rate;
        struct snd_soc_codec *codec = dai->codec;
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
@@ -695,7 +701,7 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
                samp_res = 6;
                break;
        default:
-               pr_err("AC108 don't supported the sample resolution: %u\n", params_format(params));
+               dev_err(dai->dev, "AC108 don't supported the sample resolution: %u\n", params_format(params));
                return -EINVAL;
        }
 
@@ -816,15 +822,14 @@ static int ac108_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_h
        return 0;
 }
 
-static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) {
+static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir)
+{
 
        struct ac10x_priv *ac10x = snd_soc_dai_get_drvdata(dai);
 
        freq = 24000000;
        clk_id = SYSCLK_SRC_PLL;
 
-       pr_info("%s  :%d\n", __FUNCTION__, freq);
-
        switch (clk_id) {
        case SYSCLK_SRC_MCLK:
                ac108_multi_update_bits(SYSCLK_CTRL, 0x1 << SYSCLK_SRC, SYSCLK_SRC_MCLK << SYSCLK_SRC, ac10x);
@@ -853,30 +858,27 @@ static int ac108_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int fr
  * 
  * @return int 
  */
-static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
+static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
        unsigned char tx_offset, lrck_polarity, brck_polarity;
        struct ac10x_priv *ac10x = dev_get_drvdata(dai->dev);
 
-       dev_dbg(dai->dev, "%s\n", __FUNCTION__);
-
        switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
-       case SND_SOC_DAIFMT_CBM_CFM:    /*AC108 Master*/
+       case SND_SOC_DAIFMT_CBM_CFM:    /* AC108 Master */
                if (! ac10x->i2c101 || _MASTER_MULTI_CODEC == _MASTER_AC108) {
-                       dev_dbg(dai->dev, "AC108 set to work as Master\n");
                        /**
                         * 0x30:chip is master mode ,BCLK & LRCK output
                         */
                        ac108_multi_update_bits(I2S_CTRL, 0x03 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN,
-                                                         0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac10x);
+                                                         0x03 << LRCK_IOEN | 0x01 << SDO1_EN | 0x1 << TXEN | 0x1 << GEN, ac10x);
                        /* multi_chips: only one chip set as Master, and the others also need to set as Slave */
                        ac10x_update_bits(I2S_CTRL, 0x3 << LRCK_IOEN, 0x01 << BCLK_IOEN, ac10x->i2cmap[_MASTER_INDEX]);
-                       break;
                } else {
                        /* TODO: Both cpu_dai and codec_dai(AC108) be set as slave in DTS */
-                       dev_dbg(dai->dev, "used as slave when AC101 is master\n");
+                       dev_err(dai->dev, "used as slave when AC101 is master\n");
                }
-       case SND_SOC_DAIFMT_CBS_CFS:    /*AC108 Slave*/
-               dev_dbg(dai->dev, "AC108 set to work as Slave\n");
+               break;
+       case SND_SOC_DAIFMT_CBS_CFS:    /* AC108 Slave */
                /**
                 * 0x30:chip is slave mode, BCLK & LRCK input,enable SDO1_EN and 
                 *  SDO2_EN, Transmitter Block Enable, Globe Enable
@@ -885,66 +887,57 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
                                                  0x00 << LRCK_IOEN | 0x03 << SDO1_EN | 0x0 << TXEN | 0x0 << GEN, ac10x);
                break;
        default:
-               pr_err("AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12);
+               dev_err(dai->dev, "AC108 Master/Slave mode config error:%u\n\n", (fmt & SND_SOC_DAIFMT_MASTER_MASK) >> 12);
                return -EINVAL;
        }
 
        /*AC108 config I2S/LJ/RJ/PCM format*/
        switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
        case SND_SOC_DAIFMT_I2S:
-               dev_dbg(dai->dev, "AC108 config I2S format\n");
                ac10x->i2s_mode = LEFT_JUSTIFIED_FORMAT;
                tx_offset = 1;
                break;
        case SND_SOC_DAIFMT_RIGHT_J:
-               dev_dbg(dai->dev, "AC108 config RIGHT-JUSTIFIED format\n");
                ac10x->i2s_mode = RIGHT_JUSTIFIED_FORMAT;
                tx_offset = 0;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
-               dev_dbg(dai->dev, "AC108 config LEFT-JUSTIFIED format\n");
                ac10x->i2s_mode = LEFT_JUSTIFIED_FORMAT;
                tx_offset = 0;
                break;
        case SND_SOC_DAIFMT_DSP_A:
-               dev_dbg(dai->dev, "AC108 config PCM-A format\n");
                ac10x->i2s_mode = PCM_FORMAT;
                tx_offset = 1;
                break;
        case SND_SOC_DAIFMT_DSP_B:
-               dev_dbg(dai->dev, "AC108 config PCM-B format\n");
                ac10x->i2s_mode = PCM_FORMAT;
                tx_offset = 0;
                break;
        default:
-               pr_err("AC108 I2S format config error:%u\n\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK);
+               dev_err(dai->dev, "AC108 I2S format config error:%u\n\n", fmt & SND_SOC_DAIFMT_FORMAT_MASK);
                return -EINVAL;
        }
 
        /*AC108 config BCLK&LRCK polarity*/
        switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
        case SND_SOC_DAIFMT_NB_NF:
-               dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_normal,LRCK_normal\n");
                brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P;
                lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW;
                break;
        case SND_SOC_DAIFMT_NB_IF:
-               dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_normal,LRCK_invert\n");
                brck_polarity = BCLK_NORMAL_DRIVE_N_SAMPLE_P;
                lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH;
                break;
        case SND_SOC_DAIFMT_IB_NF:
-               dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_invert,LRCK_normal\n");
                brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N;
                lrck_polarity = LRCK_LEFT_HIGH_RIGHT_LOW;
                break;
        case SND_SOC_DAIFMT_IB_IF:
-               dev_dbg(dai->dev, "AC108 config BCLK&LRCK polarity: BCLK_invert,LRCK_invert\n");
                brck_polarity = BCLK_INVERT_DRIVE_P_SAMPLE_N;
                lrck_polarity = LRCK_LEFT_LOW_RIGHT_HIGH;
                break;
        default:
-               pr_err("AC108 config BCLK/LRCLK polarity error:%u\n\n", (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8);
+               dev_err(dai->dev, "AC108 config BCLK/LRCLK polarity error:%u\n\n", (fmt & SND_SOC_DAIFMT_INV_MASK) >> 8);
                return -EINVAL;
        }
 
@@ -997,7 +990,8 @@ static int ac108_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) {
 /*
  * due to miss channels order in cpu_dai, we meed defer the clock starting.
  */
-static int ac108_set_clock(int y_start_n_stop) {
+static int ac108_set_clock(int y_start_n_stop)
+{
        u8 reg;
        int ret = 0;
 
@@ -1068,63 +1062,9 @@ static int ac108_prepare(struct snd_pcm_substream *substream,
        return 0;
 }
 
-static int ac108_trigger(struct snd_pcm_substream *substream, int cmd,
-                            struct snd_soc_dai *dai)
-{
-       struct snd_soc_codec *codec = dai->codec;
-       struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
-       unsigned long flags;
-       int ret = 0;
-       u8 r;
-
-       dev_dbg(dai->dev, "%s() stream=%s  cmd=%d\n",
-               __FUNCTION__,
-               snd_pcm_stream_str(substream),
-               cmd);
-
-       spin_lock_irqsave(&ac10x->lock, flags);
-
-       if (ac10x->i2c101 && _MASTER_MULTI_CODEC == _MASTER_AC101) {
-               ac101_trigger(substream, cmd, dai);
-               if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
-                      goto __ret;
-               }
-       }
-
-       switch (cmd) {
-       case SNDRV_PCM_TRIGGER_START:
-       case SNDRV_PCM_TRIGGER_RESUME:
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               /* disable global clock if lrck disabled */
-               ac10x_read(I2S_CTRL, &r, ac10x->i2cmap[_MASTER_INDEX]);
-               if ((r & (0x01 << BCLK_IOEN)) && (r & (0x01 << LRCK_IOEN)) == 0) {
-                       /* disable global clock */
-                       ac108_multi_update_bits(I2S_CTRL, 0x1 << TXEN | 0x1 << GEN, 0x0 << TXEN | 0x0 << GEN, ac10x);
-               }
-
-               /* delayed clock starting, move to machine trigger() */
-               //msleep(10);
-               ac108_set_clock(1);
-               break;
-       case SNDRV_PCM_TRIGGER_STOP:
-       case SNDRV_PCM_TRIGGER_SUSPEND:
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               //msleep(10);
-               ac108_set_clock(0);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-__ret:
-       spin_unlock_irqrestore(&ac10x->lock, flags);
-
-       return ret;
-}
-
 int ac108_audio_startup(struct snd_pcm_substream *substream,
-       struct snd_soc_dai *dai
-{
+       struct snd_soc_dai *dai)
+{
        struct snd_soc_codec *codec = dai->codec;
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
 
@@ -1135,8 +1075,8 @@ int ac108_audio_startup(struct snd_pcm_substream *substream,
 }
 
 void ac108_aif_shutdown(struct snd_pcm_substream *substream,
-       struct snd_soc_dai *dai
-{
+       struct snd_soc_dai *dai)
+{
        struct snd_soc_codec *codec = dai->codec;
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
 
@@ -1154,7 +1094,8 @@ void ac108_aif_shutdown(struct snd_pcm_substream *substream,
        }
 }
 
-int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int stream) {
+int ac108_aif_mute(struct snd_soc_dai *dai, int mute, int stream)
+{
        struct snd_soc_codec *codec = dai->codec;
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
 
@@ -1174,13 +1115,10 @@ static const struct snd_soc_dai_ops ac108_dai_ops = {
        /*ALSA PCM audio operations*/
        .hw_params      = ac108_hw_params,
        .prepare        = ac108_prepare,
-       /*.trigger      = ac108_trigger, */
        .mute_stream    = ac108_aif_mute,
 
        /*DAI format configuration*/
        .set_fmt        = ac108_set_fmt,
-
-       // .hw_free = ac108_hw_free,
 };
 
 static  struct snd_soc_dai_driver ac108_dai0 = {
@@ -1230,7 +1168,8 @@ static  struct snd_soc_dai_driver *ac108_dai[] = {
        &ac108_dai1,
 };
 
-static int ac108_add_widgets(struct snd_soc_codec *codec) {
+static int ac108_add_widgets(struct snd_soc_codec *codec)
+{
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
        const struct snd_kcontrol_new* snd_kcntl = ac108_snd_controls;
@@ -1249,7 +1188,8 @@ static int ac108_add_widgets(struct snd_soc_codec *codec) {
        return 0;
 }
 
-static int ac108_codec_probe(struct snd_soc_codec *codec) {
+static int ac108_codec_probe(struct snd_soc_codec *codec)
+{
        spin_lock_init(&ac10x->lock);
 
        ac10x->codec = codec;
@@ -1263,7 +1203,8 @@ static int ac108_codec_probe(struct snd_soc_codec *codec) {
        return 0;
 }
 
-static int ac108_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) {
+static int ac108_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level)
+{
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
 
        dev_dbg(codec->dev, "AC108 level:%d\n", level);
@@ -1312,7 +1253,8 @@ void ac108_codec_remove_void(struct snd_soc_codec *codec) {
 #define ac108_codec_remove ac108_codec_remove_void
 #endif
 
-int ac108_codec_suspend(struct snd_soc_codec *codec) {
+int ac108_codec_suspend(struct snd_soc_codec *codec)
+{
        struct ac10x_priv *ac10x = snd_soc_codec_get_drvdata(codec);
        int i;
 
@@ -1356,7 +1298,8 @@ static struct snd_soc_codec_driver ac10x_soc_codec_driver = {
        .write          = ac108_codec_write,
 };
 
-static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) {
+static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+{
        int val = 0, flag = 0;
        u8 i = 0, reg, num, value_w, value_r[4];
 
@@ -1367,54 +1310,46 @@ static ssize_t ac108_store(struct device *dev, struct device_attribute *attr, co
                reg = (val >> 8) & 0xFF;
                value_w = val & 0xFF;
                ac108_multi_write(reg, value_w, ac10x);
-               printk("Write 0x%02x to REG:0x%02x\n", value_w, reg);
+               dev_info(dev, "Write 0x%02x to REG:0x%02x\n", value_w, reg);
        } else {
                int k;
 
                reg = (val >> 8) & 0xFF;
                num = val & 0xff;
-               printk("\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);
+               dev_info(dev, "\nRead: start REG:0x%02x,count:0x%02x\n", reg, num);
 
-               for (k = 0; k < ac10x->codec_cnt; k++) {
+               for (k = 0; k < ac10x->codec_cnt; k++)
                        regcache_cache_bypass(ac10x->i2cmap[k], true);
-               }
-               do {
 
+               do {
                        memset(value_r, 0, sizeof value_r);
 
-                       for (k = 0; k < ac10x->codec_cnt; k++) {
+                       for (k = 0; k < ac10x->codec_cnt; k++)
                                ac10x_read(reg, &value_r[k], ac10x->i2cmap[k]);
-                       }
-                       if (ac10x->codec_cnt >= 2) {
-                               printk("REG[0x%02x]: 0x%02x 0x%02x", reg, value_r[0], value_r[1]);
-                       } else {
-                               printk("REG[0x%02x]: 0x%02x", reg, value_r[0]);
-                       }
+
+                       if (ac10x->codec_cnt >= 2)
+                               dev_info(dev, "REG[0x%02x]: 0x%02x 0x%02x", reg, value_r[0], value_r[1]);
+                       else
+                               dev_info(dev, "REG[0x%02x]: 0x%02x", reg, value_r[0]);
                        reg++;
 
-                       if ((++i == num) || (i % 4 == 0)) {
-                               printk("\n");
-                       }
+                       if ((++i == num) || (i % 4 == 0))
+                               dev_info(dev, "\n");
                } while (i < num);
-               for (k = 0; k < ac10x->codec_cnt; k++) {
+
+               for (k = 0; k < ac10x->codec_cnt; k++)
                        regcache_cache_bypass(ac10x->i2cmap[k], false);
-               }
        }
 
        return count;
 }
 
-static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf) {
-#if 1
-       printk("echo flag|reg|val > ac108\n");
-       printk("eg read star addres=0x06,count 0x10:echo 0610 >ac108\n");
-       printk("eg write value:0xfe to address:0x06 :echo 106fe > ac108\n");
+static ssize_t ac108_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       dev_info(dev, "echo flag|reg|val > ac108\n");
+       dev_info(dev, "eg read star addres=0x06,count 0x10:echo 0610 >ac108\n");
+       dev_info(dev, "eg write value:0xfe to address:0x06 :echo 106fe > ac108\n");
        return 0;
-#else
-       return snprintf(buf, PAGE_SIZE,"echo flag|reg|val > ac108\n"
-                                       "eg read star addres=0x06,count 0x10:echo 0610 >ac108\n"
-                                       "eg write value:0xfe to address:0x06 :echo 106fe > ac108\n");
-#endif
 }
 
 static DEVICE_ATTR(ac108, 0644, ac108_show, ac108_store);
@@ -1434,7 +1369,8 @@ static const struct regmap_config ac108_regmap = {
        .max_register = 0xDF,
        .cache_type = REGCACHE_FLAT,
 };
-static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id) {
+static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i2c_id)
+{
        struct device_node *np = i2c->dev.of_node;
        unsigned int val = 0;
        int ret = 0, index;
@@ -1461,7 +1397,7 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
 
        ret = of_property_read_u32(np, "data-protocol", &val);
        if (ret) {
-               pr_err("Please set data-protocol.\n");
+               dev_err(&i2c->dev, "Please set data-protocol.\n");
                return -EINVAL;
        }
        ac10x->data_protocol = val;
@@ -1469,8 +1405,8 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
        if (of_property_read_u32(np, "tdm-chips-count", &val)) val = 1;
        ac10x->tdm_chips_cnt = val;
 
-       pr_err(" ac10x i2c_id number: %d\n", index);
-       pr_err(" ac10x data protocol: %d\n", ac10x->data_protocol);
+       dev_info(&i2c->dev, " ac10x i2c_id number: %d\n", index);
+       dev_info(&i2c->dev, " ac10x data protocol: %d\n", ac10x->data_protocol);
 
        ac10x->i2c[index] = i2c;
        ac10x->i2cmap[index] = devm_regmap_init_i2c(i2c, &ac108_regmap);
@@ -1481,7 +1417,7 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
        }
 
        /*
-        * Writing this register with 0x12 
+        * Writing this register with 0x12
         * will resets all register to their default state.
         */
        regcache_cache_only(ac10x->i2cmap[index], false);
@@ -1493,18 +1429,17 @@ static int ac108_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *i
        ac10x_fill_regcache(&i2c->dev, ac10x->i2cmap[index]);
 
        ac10x->codec_cnt++;
-       pr_err(" ac10x codec count  : %d\n", ac10x->codec_cnt);
+       dev_info(&i2c->dev, " ac10x codec count  : %d\n", ac10x->codec_cnt);
 
        ret = sysfs_create_group(&i2c->dev.kobj, &ac108_debug_attr_group);
        if (ret) {
-               pr_err("failed to create attr group\n");
+               dev_err(&i2c->dev, "failed to create attr group\n");
        }
 
 __ret:
        /* It's time to bind codec to i2c[_MASTER_INDEX] when all i2c are ready */
        if ((ac10x->codec_cnt != 0 && ac10x->tdm_chips_cnt < 2)
        || (ac10x->i2c[0] && ac10x->i2c[1] && ac10x->i2c101)) {
-               //seeed_voice_card_register_set_clock(SNDRV_PCM_STREAM_CAPTURE, ac108_set_clock);
                /* no playback stream */
                if (! ac10x->i2c101) {
                        memset(&ac108_dai[_MASTER_INDEX]->playback, '\0', sizeof ac108_dai[_MASTER_INDEX]->playback);
@@ -1518,7 +1453,8 @@ __ret:
        return ret;
 }
 
-static int ac108_i2c_remove(struct i2c_client *i2c) {
+static int ac108_i2c_remove(struct i2c_client *i2c)
+{
        if (ac10x->codec != NULL) {
                snd_soc_unregister_codec(&ac10x->i2c[_MASTER_INDEX]->dev);
                ac10x->codec = NULL;
index 468ba7e..2703307 100755 (executable)
 
 #define CLOCK_BASE     0x13020000UL
 
-static void saif_set_reg(void __iomem *addr, u32 data, u32 shift, u32 mask)
-{
-       u32 tmp;
-       tmp = readl(addr);
-       tmp &= ~mask;
-       tmp |= (data << shift) & mask;
-       writel(tmp, addr);
-}
-
 static inline void i2s_write_reg(void __iomem *io_base, int reg, u32 val)
 {
        writel(val, io_base + reg);
@@ -295,27 +286,54 @@ static int dw_i2s_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       if (txrx == SNDRV_PCM_STREAM_PLAYBACK)
-       {
-               //_SWITCH_CLOCK_CLK_MCLK_SOURCE_CLK_MCLK_EXT_;
-               saif_set_reg(dev->clk_base + 0x48, 1, 24, 0x1000000);
+       if (txrx == SNDRV_PCM_STREAM_PLAYBACK) {
+               ret = clk_prepare_enable(dev->clks_dac_bclk);
+               if (ret) {
+                       dev_err(dev->dev, "%s: failed to enable clks_dac_bclk\n", __func__);
+                       return ret;
+               }
 
-               //_SWITCH_CLOCK_CLK_U1_I2STX_4CH_BCLK_SOURCE_CLK_I2STX_BCLK_EXT_;
-               saif_set_reg(dev->clk_base + 0x2B0, 1, 24, 0x1000000);
+               ret = clk_set_parent(dev->clks_bclk, dev->clks_dac_bclk);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set clock source for clks_bclk: %d\n", ret);
+                       return ret;
+               }
 
-               //_SWITCH_CLOCK_CLK_U1_I2STX_4CH_LRCK_SOURCE_CLK_I2STX_LRCK_EXT_;
-               saif_set_reg(dev->clk_base + 0x2B8, 1, 24, 0x1000000);
-       }
-       else if (txrx == SNDRV_PCM_STREAM_CAPTURE)
-       {
-               //_SWITCH_CLOCK_CLK_MCLK_SOURCE_CLK_MCLK_EXT_;
-               saif_set_reg(dev->clk_base + 0x48, 1, 24, 0x1000000);
+               ret = clk_prepare_enable(dev->clks_dac_lrck);
+               if (ret) {
+                       dev_err(dev->dev, "%s: failed to enable clks_dac_lrck\n", __func__);
+                       return ret;
+               }
+
+               ret = clk_set_parent(dev->clks_lrclk, dev->clks_dac_lrck);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set clock source for clks_lrclk: %d\n", ret);
+                       return ret;
+               }
+       }else if (txrx == SNDRV_PCM_STREAM_CAPTURE) {
+               ret = clk_prepare_enable(dev->clks[CLK_ADC_BCLK_EXT]);
+               if (ret) {
+                       dev_err(dev->dev, "%s: failed to enable CLK_ADC_BCLK_EXT\n", __func__);
+                       return ret;
+               }
 
-               //_SWITCH_CLOCK_CLK_U1_I2STX_4CH_BCLK_SOURCE_CLK_I2STX_BCLK_EXT_;
-               saif_set_reg(dev->clk_base + 0x2CC, 1, 24, 0x1000000);
+               ret = clk_set_parent(dev->clks[CLK_ADC_RX_BCLK], dev->clks[CLK_ADC_BCLK_EXT]);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set clock source for CLK_ADC_RX_BCLK: %d\n", ret);
+                       return ret;
+               }
 
-               //_SWITCH_CLOCK_CLK_U1_I2STX_4CH_LRCK_SOURCE_CLK_I2STX_LRCK_EXT_;
-               saif_set_reg(dev->clk_base + 0x2D4, 1, 24, 0x1000000);
+               ret = clk_prepare_enable(dev->clks[CLK_ADC_LRCK_EXT]);
+               if (ret) {
+                       dev_err(dev->dev, "%s: failed to enable CLK_ADC_LRCK_EXT\n", __func__);
+                       return ret;
+               }
+
+               ret = clk_set_parent(dev->clks[CLK_ADC_RX_LRCK], dev->clks[CLK_ADC_LRCK_EXT]);
+               if (ret) {
+                       dev_err(dev->dev, "Can't set clock source for CLK_ADC_RX_LRCK: %d\n", ret);
+                       return ret;
+               }
        }
 
        dw_i2s_config(dev, substream->stream);
@@ -503,6 +521,9 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
                { .id = "3ch-lrck" },
                { .id = "rx-bclk" },
                { .id = "rx-lrck" },
+               { .id = "mclk" },
+               { .id = "bclk-ext" },
+               { .id = "lrck-ext" },
        };
 
        ret = devm_clk_bulk_get(&pdev->dev, ARRAY_SIZE(clks), clks);
@@ -518,6 +539,9 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
        dev->clks[CLK_ADC_LRCLK] = clks[5].clk;
        dev->clks[CLK_ADC_RX_BCLK] = clks[6].clk;
        dev->clks[CLK_ADC_RX_LRCK] = clks[7].clk;
+       dev->clks[CLK_ADC_MCLK] = clks[8].clk;
+       dev->clks[CLK_ADC_BCLK_EXT] = clks[9].clk;
+       dev->clks[CLK_ADC_LRCK_EXT] = clks[10].clk;
 
        ret = clk_prepare_enable(dev->clks[CLK_ADC_APB0]);
        if (ret) {
@@ -536,6 +560,7 @@ static int dw_i2srx_clk_init(struct platform_device *pdev, struct dw_i2s_dev *de
                dev_err(&pdev->dev, "%s: failed to enable CLK_ADC_AUDROOT\n", __func__);
                goto disable_audroot_clk;
        }
+
        ret = clk_set_rate(dev->clks[CLK_ADC_AUDROOT], 204800000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for CLK_ADC_MCLK \n");
@@ -768,6 +793,14 @@ static int dw_i2stx_4ch1_clk_init(struct platform_device *pdev, struct dw_i2s_de
        if (IS_ERR(dev->clks_4ch_apb))
                return PTR_ERR(dev->clks_4ch_apb);
 
+       dev->clks_dac_bclk = devm_clk_get(&pdev->dev, "bclk_ext");
+       if (IS_ERR(dev->clks_dac_bclk))
+               return PTR_ERR(dev->clks_dac_bclk);
+
+       dev->clks_dac_lrck = devm_clk_get(&pdev->dev, "lrck_ext");
+       if (IS_ERR(dev->clks_dac_lrck))
+               return PTR_ERR(dev->clks_dac_lrck);
+
        ret = clk_prepare_enable(dev->clks_audroot);
        if (ret) {
                dev_err(&pdev->dev, "%s: failed to enable clks_audroot\n", __func__);
index eba6c08..d588b04 100755 (executable)
@@ -100,6 +100,9 @@ enum {
        CLK_ADC_LRCLK,
        CLK_ADC_RX_BCLK,
        CLK_ADC_RX_LRCK,
+       CLK_ADC_MCLK,
+       CLK_ADC_BCLK_EXT,
+       CLK_ADC_LRCK_EXT,
        CLK_AUDIO_NUM,
 };
 
@@ -146,6 +149,8 @@ struct dw_i2s_dev {
        struct clk *clks_mclk_out;
        struct clk *clks_apb0;
        struct clk *clks_4ch_apb;
+       struct clk *clks_dac_bclk;
+       struct clk *clks_dac_lrck;
        struct reset_control *rstc_rx;
        struct reset_control *rstc_ch0;
        struct reset_control *rstc_ch1;
index 177c361..cbc5c42 100755 (executable)
@@ -1,4 +1,4 @@
-//SPDX-License-Identifier: GPL-2.0
+// SPDX-License-Identifier: GPL-2.0
 /*
  * SPDIF driver for the StarFive JH7110 SoC
  *
@@ -138,6 +138,7 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
        unsigned int format;
        unsigned int tsamplerate;
        unsigned int mclk;
+       unsigned int audio_root;
        int ret;
 
        channels = params_channels(params);
@@ -145,7 +146,17 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
        format = params_format(params);
 
        switch (channels) {
+       case 1:
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_CHANNEL_MODE, SPDIF_CHANNEL_MODE);
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_DUPLICATE, SPDIF_DUPLICATE);
+               spdif->channels = false;
+               break;
        case 2:
+               regmap_update_bits(spdif->regmap, SPDIF_CTRL,
+                       SPDIF_CHANNEL_MODE, 0);
+               spdif->channels = true;
                break;
        default:
                dev_err(dai->dev, "invalid channels number\n");
@@ -155,6 +166,7 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
        switch (format) {
        case SNDRV_PCM_FORMAT_S16_LE:
        case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
        case SNDRV_PCM_FORMAT_S32_LE:
                break;
        default:
@@ -162,6 +174,7 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       audio_root = 204800000;
        switch (rate) {
        case 8000:
                mclk = 4096000;
@@ -173,6 +186,7 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
                mclk = 8192000;
                break;
        case 22050:
+               audio_root = 153600000;
                mclk = 11289600;
                break;
        default:
@@ -180,15 +194,24 @@ static int sf_spdif_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
+       ret = clk_set_rate(spdif->audio_root, audio_root);
+       if (ret) {
+               dev_err(dai->dev, "failed to set audio_root rate :%d\n", ret);
+               return ret;
+       }
+       dev_dbg(dai->dev, "audio_root get rate:%ld\n",
+                       clk_get_rate(spdif->audio_root));
+
        ret = clk_set_rate(spdif->mclk_inner, mclk);
        if (ret) {
-               dev_err(dai->dev, "failed to set rate for spdif mclk_inner ret=%d\n", ret);
+               dev_err(dai->dev, "failed to set mclk_inner rate :%d\n", ret);
                return ret;
        }
 
+       mclk = clk_get_rate(spdif->mclk_inner);
+       dev_dbg(dai->dev, "mclk_inner get rate:%d\n", mclk);
        /* (FCLK)4096000/128=32000 */
-       tsamplerate = (32000 + rate/2)/rate - 1;
-
+       tsamplerate = (mclk / 128 + rate / 2) / rate - 1;
        if (tsamplerate < 3)
                tsamplerate = 3;
 
@@ -204,7 +227,6 @@ static int sf_spdif_clks_get(struct platform_device *pdev,
        static struct clk_bulk_data clks[] = {
                { .id = "spdif-apb" },          /* clock-names in dts file */
                { .id = "spdif-core" },
-               { .id = "apb0" },
                { .id = "audroot" },
                { .id = "mclk_inner"},
        };
@@ -212,9 +234,8 @@ static int sf_spdif_clks_get(struct platform_device *pdev,
 
        spdif->spdif_apb = clks[0].clk;
        spdif->spdif_core = clks[1].clk;
-       spdif->apb0_clk = clks[2].clk;
-       spdif->audio_root = clks[3].clk;
-       spdif->mclk_inner = clks[4].clk;
+       spdif->audio_root = clks[2].clk;
+       spdif->mclk_inner = clks[3].clk;
        return ret;
 }
 
@@ -225,6 +246,7 @@ static int sf_spdif_resets_get(struct platform_device *pdev,
                        { .id = "rst_apb" },
        };
        int ret = devm_reset_control_bulk_get_exclusive(&pdev->dev, ARRAY_SIZE(resets), resets);
+
        if (ret)
                return ret;
 
@@ -250,54 +272,29 @@ static int sf_spdif_clk_init(struct platform_device *pdev,
                goto disable_core_clk;
        }
 
-       ret = clk_prepare_enable(spdif->apb0_clk);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable apb0_clk\n");
-               goto disable_apb0_clk;
-       }
-
-       ret = clk_prepare_enable(spdif->audio_root);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable spdif->audio_root\n");
-               goto disable_audroot_clk;
-       }
-
        ret = clk_set_rate(spdif->audio_root, 204800000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for spdif audroot ret=%d\n", ret);
-               goto disable_audroot_clk;
-       }
-
-       ret = clk_prepare_enable(spdif->mclk_inner);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to prepare enable spdif->mclk_inner\n");
-               goto disable_mclk_clk;
+               goto disable_core_clk;
        }
 
        ret = clk_set_rate(spdif->mclk_inner, 8192000);
        if (ret) {
                dev_err(&pdev->dev, "failed to set rate for spdif mclk_inner ret=%d\n", ret);
-               goto disable_mclk_clk;
+               goto disable_core_clk;
        }
 
        dev_dbg(&pdev->dev, "spdif->spdif_apb = %lu\n", clk_get_rate(spdif->spdif_apb));
        dev_dbg(&pdev->dev, "spdif->spdif_core = %lu\n", clk_get_rate(spdif->spdif_core));
-       dev_dbg(&pdev->dev, "spdif->apb0_clk = %lu\n", clk_get_rate(spdif->apb0_clk));
 
        ret = reset_control_deassert(spdif->rst_apb);
        if (ret) {
                dev_err(&pdev->dev, "failed to deassert apb\n");
-               goto disable_mclk_clk;
+               goto disable_core_clk;
        }
 
        return 0;
 
-disable_mclk_clk:
-       clk_disable_unprepare(spdif->mclk_inner);
-disable_audroot_clk:
-       clk_disable_unprepare(spdif->audio_root);
-disable_apb0_clk:
-       clk_disable_unprepare(spdif->apb0_clk);
 disable_core_clk:
        clk_disable_unprepare(spdif->spdif_core);
 disable_apb_clk:
@@ -377,20 +374,12 @@ static struct snd_soc_dai_driver sf_spdif_dai = {
        .probe = sf_spdif_dai_probe,
        .playback = {
                .stream_name = "Playback",
-               .channels_min = 2,
-               .channels_max = 2,
-               .rates = SF_PCM_RATE_8000_22050,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | \
-                          SNDRV_PCM_FMTBIT_S24_LE | \
-                          SNDRV_PCM_FMTBIT_S32_LE,
-       },
-       .capture =  {
-               .stream_name = "Capture",
-               .channels_min = 2,
+               .channels_min = 1,
                .channels_max = 2,
                .rates = SF_PCM_RATE_8000_22050,
-               .formats = SNDRV_PCM_FMTBIT_S16_LE | \
-                          SNDRV_PCM_FMTBIT_S24_LE | \
+               .formats = SNDRV_PCM_FMTBIT_S16_LE |
+                          SNDRV_PCM_FMTBIT_S24_LE |
+                          SNDRV_PCM_FMTBIT_S24_3LE |
                           SNDRV_PCM_FMTBIT_S32_LE,
        },
        .ops = &sf_spdif_dai_ops,
index 805e93e..9120a17 100755 (executable)
@@ -1,4 +1,4 @@
-//SPDX-License-Identifier: GPL-2.0
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * SPDIF driver for the StarFive JH7110 SoC
  *
@@ -79,7 +79,7 @@
                                 SPDIF_FIOF_AEMPTY | SPDIF_FIFO_FULL | \
                                 SPDIF_FIFO_AFULL | SPDIF_SYNCERR | \
                                 SPDIF_LOCK | SPDIF_BLOCK_BEGIN)
-                                                
+
 #define SPDIF_ERROR_INT_STATUS (SPDIF_PARITYO | \
                                 SPDIF_TDATA_UNDERR | SPDIF_RDATA_OVRERR)
 #define SPDIF_FIFO_INT_STATUS  (SPDIF_FIFO_EMPTY | SPDIF_FIOF_AEMPTY | \
 #define SPDIF_BEGIN_FLAG       (1<<30) /* 1:start a new block */
 #define SPDIF_RIGHT_LEFT       (1<<31) /* 1:left channel received and tx into FIFO; 0:right channel received and tx into FIFO */
 
-#define BIT8TO20MASK   0x1FFF
+#define BIT8TO20MASK   0x1FFF
 #define ALLBITMASK             0xFFFFFFFF
 
 #define SPDIF_STAT             (SPDIF_PARITY_FLAG | SPDIF_UNDERR_FLAG | \
@@ -146,13 +146,13 @@ struct sf_spdif_dev {
                        bool *period_elapsed, snd_pcm_format_t format);
 
        snd_pcm_format_t format;
+       bool channels;
        unsigned int tx_ptr;
        unsigned int rx_ptr;
-       struct clk* spdif_apb;
-       struct clk* spdif_core;
-       struct clk* apb0_clk;
-       struct clk* audio_root;
-       struct clk* mclk_inner;
+       struct clk *spdif_apb;
+       struct clk *spdif_core;
+       struct clk *audio_root;
+       struct clk *mclk_inner;
        struct reset_control *rst_apb;
 
        struct snd_dmaengine_dai_dma_data dma_data;
index ba5cd04..5823837 100755 (executable)
@@ -1,22 +1,23 @@
-/**
-  ******************************************************************************
-  * @file  sf_spdif_pcm.c
-  * @author  StarFive Technology
-  * @version  V1.0
-  * @date  05/27/2021
-  * @brief
-  ******************************************************************************
-  * @copy
-  *
-  * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
-  * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
-  * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
-  * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
-  * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
-  * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
-  *
-  * <h2><center>&copy; COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd. </center></h2>
-  */
+// SPDX-License-Identifier: GPL-2.0
+/*
+ ******************************************************************************
+ * @file  sf_spdif_pcm.c
+ * @author  StarFive Technology
+ * @version  V1.0
+ * @date  05/27/2021
+ * @brief
+ ******************************************************************************
+ * @copy
+ *
+ * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
+ * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
+ * TIME. AS A RESULT, STARFIVE SHALL NOT BE HELD LIABLE FOR ANY
+ * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
+ * FROM THE CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
+ * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
+ *
+ * <h2><center>&copy; COPYRIGHT 20120 Shanghai StarFive Technology Co., Ltd. </center></h2>
+ */
 
 #include <linux/io.h>
 #include <linux/rcupdate.h>
 #define PERIOD_BYTES_MIN       4096
 #define PERIODS_MIN            2
 
-static unsigned int sf_spdif_pcm_tx(struct sf_spdif_dev *dev, 
-               struct snd_pcm_runtime *runtime, unsigned int tx_ptr, 
-               bool *period_elapsed, snd_pcm_format_t format) 
-{ 
-       const u16 (*p16)[2] = (void *)runtime->dma_area; 
-       const u32 (*p32)[2] = (void *)runtime->dma_area; 
+static unsigned int sf_spdif_pcm_tx(struct sf_spdif_dev *dev,
+               struct snd_pcm_runtime *runtime, unsigned int tx_ptr,
+               bool *period_elapsed, snd_pcm_format_t format)
+{
        u32 data[2];
-       unsigned int period_pos = tx_ptr % runtime->period_size; 
-       int i;  
-
-       for (i = 0; i < dev->fifo_th; i++) { 
-               if (SNDRV_PCM_FORMAT_S16_LE == format) {
-                       data[0] = p16[tx_ptr][0];
-                       data[1] = p16[tx_ptr][1];
-                       data[0] = data[0]<<8;
-                       data[1] = data[1]<<8;
-               } else if (SNDRV_PCM_FORMAT_S24_LE == format) {
-                       data[0] = p32[tx_ptr][0];
-                       data[1] = p32[tx_ptr][1];
-               } else if (SNDRV_PCM_FORMAT_S32_LE == format) {
-                       data[0] = p32[tx_ptr][0];
-                       data[1] = p32[tx_ptr][1];
-                       data[0] = data[0]>>8;
-                       data[1] = data[1]>>8;
+       unsigned int period_pos = tx_ptr % runtime->period_size;
+       int i;
+
+       /* two- channel and signal-channel mode */
+       if (dev->channels) {
+               const u16 (*p16)[2] = (void *)runtime->dma_area;
+               const u32 (*p32)[2] = (void *)runtime->dma_area;
+
+               for (i = 0; i < dev->fifo_th; i++) {
+                       if (format == SNDRV_PCM_FORMAT_S16_LE) {
+                               data[0] = p16[tx_ptr][0];
+                               data[0] = data[0]<<8;
+                               data[0] &= 0x00ffff00;
+                               data[1] = p16[tx_ptr][1];
+                               data[1] = data[1]<<8;
+                               data[1] &= 0x00ffff00;
+                       } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
+                               data[0] = p32[tx_ptr][0];
+                               data[1] = p32[tx_ptr][1];
+
+                               /*
+                                * To adapt S24_3LE and ALSA pass parameter of S24_LE.
+                                * operation of S24_LE should be same to S24_3LE.
+                                * So it would wrong when playback S24_LE file.
+                                * when want to playback S24_LE file, should add in there:
+                                * data[0] = data[0]>>8;
+                                * data[1] = data[1]>>8;
+                                */
+
+                               data[0] &= 0x00ffffff;
+                               data[1] &= 0x00ffffff;
+                       } else if (format == SNDRV_PCM_FORMAT_S24_3LE) {
+                               data[0] = p32[tx_ptr][0];
+                               data[1] = p32[tx_ptr][1];
+                               data[0] &= 0x00ffffff;
+                               data[1] &= 0x00ffffff;
+                       } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
+                               data[0] = p32[tx_ptr][0];
+                               data[0] = data[0]>>8;
+                               data[1] = p32[tx_ptr][1];
+                               data[1] = data[1]>>8;
+                       }
+
+                       iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       period_pos++;
+                       if (++tx_ptr >= runtime->buffer_size)
+                               tx_ptr = 0;
                }
-               
-               iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR); 
-               iowrite32(data[1], dev->spdif_base + SPDIF_FIFO_ADDR); 
-               period_pos++; 
-               if (++tx_ptr >= runtime->buffer_size) {
-                       tx_ptr = 0; 
+       } else {
+               const u16 (*p16) = (void *)runtime->dma_area;
+               const u32 (*p32) = (void *)runtime->dma_area;
+
+               for (i = 0; i < dev->fifo_th; i++) {
+                       if (format == SNDRV_PCM_FORMAT_S16_LE) {
+                               data[0] = p16[tx_ptr];
+                               data[0] = data[0]<<8;
+                               data[0] &= 0x00ffff00;
+                       } else if (format == SNDRV_PCM_FORMAT_S24_LE ||
+                               format == SNDRV_PCM_FORMAT_S24_3LE) {
+                               data[0] = p32[tx_ptr];
+                               data[0] &= 0x00ffffff;
+                       } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
+                               data[0] = p32[tx_ptr];
+                               data[0] = data[0]>>8;
+                       }
+
+                       iowrite32(data[0], dev->spdif_base + SPDIF_FIFO_ADDR);
+                       period_pos++;
+                       if (++tx_ptr >= runtime->buffer_size)
+                               tx_ptr = 0;
                }
-       } 
+       }
 
-       *period_elapsed = period_pos >= runtime->period_size; 
-       return tx_ptr; 
+       *period_elapsed = period_pos >= runtime->period_size;
+       return tx_ptr;
 }
 
-static unsigned int sf_spdif_pcm_rx(struct sf_spdif_dev *dev, 
-               struct snd_pcm_runtime *runtime, unsigned int rx_ptr, 
-               bool *period_elapsed, snd_pcm_format_t format) 
-{ 
-       u16 (*p16)[2] = (void *)runtime->dma_area; 
-       u32 (*p32)[2] = (void *)runtime->dma_area; 
+static unsigned int sf_spdif_pcm_rx(struct sf_spdif_dev *dev,
+               struct snd_pcm_runtime *runtime, unsigned int rx_ptr,
+               bool *period_elapsed, snd_pcm_format_t format)
+{
+       u16 (*p16)[2] = (void *)runtime->dma_area;
+       u32 (*p32)[2] = (void *)runtime->dma_area;
        u32 data[2];
-       unsigned int period_pos = rx_ptr % runtime->period_size; 
-       int i; 
+       unsigned int period_pos = rx_ptr % runtime->period_size;
+       int i;
 
-       for (i = 0; i < dev->fifo_th; i++) { 
+       for (i = 0; i < dev->fifo_th; i++) {
                data[0] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
                data[1] = ioread32(dev->spdif_base + SPDIF_FIFO_ADDR);
-               if (SNDRV_PCM_FORMAT_S16_LE == format) {
+               if (format == SNDRV_PCM_FORMAT_S16_LE) {
                        p16[rx_ptr][0] = data[0]>>8;
                        p16[rx_ptr][1] = data[1]>>8;
-               } else if (SNDRV_PCM_FORMAT_S24_LE == format) {
+               } else if (format == SNDRV_PCM_FORMAT_S24_LE) {
                        p32[rx_ptr][0] = data[0];
                        p32[rx_ptr][1] = data[1];
-               } else if (SNDRV_PCM_FORMAT_S32_LE == format) {
+               } else if (format == SNDRV_PCM_FORMAT_S32_LE) {
                        p32[rx_ptr][0] = data[0]<<8;
                        p32[rx_ptr][1] = data[1]<<8;
-               } 
-               
-               period_pos++; 
-               if (++rx_ptr >= runtime->buffer_size) 
-                       rx_ptr = 0; 
-       } 
-       
-       *period_elapsed = period_pos >= runtime->period_size; 
-       return rx_ptr; 
+               }
+
+               period_pos++;
+               if (++rx_ptr >= runtime->buffer_size)
+                       rx_ptr = 0;
+       }
+
+       *period_elapsed = period_pos >= runtime->period_size;
+       return rx_ptr;
 }
 
 static const struct snd_pcm_hardware sf_pcm_hardware = {
@@ -115,8 +161,9 @@ static const struct snd_pcm_hardware sf_pcm_hardware = {
        .rate_max = 48000,
        .formats = SNDRV_PCM_FMTBIT_S16_LE |
                SNDRV_PCM_FMTBIT_S24_LE |
+               SNDRV_PCM_FMTBIT_S24_3LE |
                SNDRV_PCM_FMTBIT_S32_LE,
-       .channels_min = 2,
+       .channels_min = 1,
        .channels_max = 2,
        .buffer_bytes_max = BUFFER_BYTES_MAX,
        .period_bytes_min = PERIOD_BYTES_MIN,
@@ -198,6 +245,7 @@ static int sf_pcm_hw_params(struct snd_soc_component *component,
        struct sf_spdif_dev *dev = runtime->private_data;
 
        switch (params_channels(hw_params)) {
+       case 1:
        case 2:
                break;
        default:
@@ -209,6 +257,7 @@ static int sf_pcm_hw_params(struct snd_soc_component *component,
        switch (dev->format) {
        case SNDRV_PCM_FORMAT_S16_LE:
        case SNDRV_PCM_FORMAT_S24_LE:
+       case SNDRV_PCM_FORMAT_S24_3LE:
        case SNDRV_PCM_FORMAT_S32_LE:
                break;
        default:
@@ -264,12 +313,10 @@ static snd_pcm_uframes_t sf_pcm_pointer(struct snd_soc_component *component,
        struct sf_spdif_dev *dev = runtime->private_data;
        snd_pcm_uframes_t pos;
 
-       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+       if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
                pos = READ_ONCE(dev->tx_ptr);
-       }
-       else {
+       else
                pos = READ_ONCE(dev->rx_ptr);
-       }
 
        return pos < runtime->buffer_size ? pos : 0;
 }
@@ -285,7 +332,7 @@ static int sf_pcm_new(struct snd_soc_component *component,
 
        return 0;
 }
-                         
+
 static const struct snd_soc_component_driver sf_pcm_component = {
        .open           = sf_pcm_open,
        .close          = sf_pcm_close,
index 0d94350..4542d2b 100644 (file)
@@ -2,7 +2,7 @@
 /*
  * TDM driver for the StarFive JH7110 SoC
  *
- * Copyright (C) 2021 StarFive Technology Co., Ltd.
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
  */
 #include <linux/clk.h>
 #include <linux/device.h>
@@ -101,7 +101,6 @@ static void sf_tdm_config(struct sf_tdm_dev *dev, struct snd_pcm_substream *subs
 {
        u32 datarx, datatx;
 
-       sf_tdm_stop(dev, substream);
        sf_tdm_contrl(dev);
        sf_tdm_syncdiv(dev);
 
@@ -139,15 +138,20 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
        int channels;
        int ret;
 
+       channels = params_channels(params);
+       data_width = params_width(params);
+
        dev->samplerate = params_rate(params);
        switch (dev->samplerate) {
-       /*  There is a issue with 8k sample rate  */
-/*
+       /*  There are some limitation when using 8k sample rate  */
        case 8000:
-               mclk_rate = 11289600; //sysclk
-               dev->pcmclk = 352800; //bit clock
+               mclk_rate = 12288000;
+               dev->pcmclk = 512000;
+               if ((data_width == 16) || (channels == 1)) {
+                       pr_err("TDM: not support 16bit or 1-channel when using 8k sample rate\n");
+                       return -EINVAL;
+               }
                break;
-*/
        case 11025:
                mclk_rate = 11289600; //sysclk
                dev->pcmclk = 352800; //bit clock, for 16-bit
@@ -177,8 +181,6 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
                return -EINVAL;
        }
 
-       data_width = params_width(params);
-       channels = params_channels(params);
        dev->pcmclk = channels * dev->samplerate * data_width;
 
        switch (params_format(params)) {
@@ -188,20 +190,11 @@ static int sf_tdm_hw_params(struct snd_pcm_substream *substream,
                dma_bus_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
                break;
 
-       /*  There are some issue with 24-bit and 32-bit */
-/*
-       case SNDRV_PCM_FORMAT_S24_LE:
-               chan_wl = TDM_24BIT_WORD_LEN;
-               chan_sl = TDM_32BIT_SLOT_LEN;
-               dma_bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-               break;
-
        case SNDRV_PCM_FORMAT_S32_LE:
                chan_wl = TDM_32BIT_WORD_LEN;
                chan_sl = TDM_32BIT_SLOT_LEN;
                dma_bus_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
                break;
-*/
 
        default:
                dev_err(dev->dev, "tdm: unsupported PCM fmt");
@@ -338,9 +331,7 @@ static int sf_tdm_dai_probe(struct snd_soc_dai *dai)
        return 0;
 }
 
-#define SF_TDM_RATES   (SNDRV_PCM_RATE_11025 | SNDRV_PCM_RATE_16000 | \
-                       SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 | \
-                       SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000)
+#define SF_TDM_RATES SNDRV_PCM_RATE_8000_48000
 
 #define SF_TDM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
                        SNDRV_PCM_FMTBIT_S32_LE)
@@ -353,14 +344,14 @@ static struct snd_soc_dai_driver sf_tdm_dai = {
                .channels_min   = 1,
                .channels_max   = 8,
                .rates          = SF_TDM_RATES,
-               .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats        = SF_TDM_FORMATS,
        },
        .capture = {
                .stream_name    = "Capture",
                .channels_min   = 1,
                .channels_max   = 8,
                .rates          = SF_TDM_RATES,
-               .formats        = SNDRV_PCM_FMTBIT_S16_LE,
+               .formats        = SF_TDM_FORMATS,
        },
        .ops = &sf_tdm_dai_ops,
        .probe = sf_tdm_dai_probe,
@@ -386,8 +377,6 @@ static void tdm_init_params(struct sf_tdm_dev *dev)
        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;