rockchip: rk3288: Add i2s pinctrl and clock support
authorSimon Glass <sjg@chromium.org>
Fri, 28 Dec 2018 03:15:20 +0000 (20:15 -0700)
committerPhilipp Tomsich <philipp.tomsich@theobroma-systems.com>
Fri, 1 Feb 2019 15:59:10 +0000 (16:59 +0100)
Add support for setting pinctrl and clock for I2S on rk3288. This allows
the sound driver to operate. These settings were created by rkmux.py

Signed-off-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
arch/arm/include/asm/arch-rockchip/cru_rk3288.h
arch/arm/include/asm/arch-rockchip/grf_rk3288.h
arch/arm/include/asm/arch-rockchip/periph.h
drivers/clk/rockchip/clk_rk3288.c
drivers/pinctrl/rockchip/pinctrl_rk3288.c

index 0475598b77b9c953cffee2d72a6733ed180ba4cd..e891f20b373974f705ac169bae1a0dfbe1d3a146 100644 (file)
@@ -75,6 +75,14 @@ enum {
        MMC0_DIV_MASK           = 0x3f << MMC0_DIV_SHIFT,
 };
 
+/* CRU_CLKSEL8_CON */
+enum {
+       I2S0_FRAC_DENOM_SHIFT   = 0,
+       I2S0_FRAC_DENOM_MASK    = 0xffff << I2S0_FRAC_DENOM_SHIFT,
+       I2S0_FRAC_NUMER_SHIFT   = 16,
+       I2S0_FRAC_NUMER_MASK    = 0xffffu << I2S0_FRAC_NUMER_SHIFT,
+};
+
 /* CRU_CLKSEL12_CON */
 enum {
        EMMC_PLL_SHIFT          = 0xe,
index c235607cee52494c4504c42f1d93d4372af79d8d..77295446c636cf006b827c2218e676ebaec1827f 100644 (file)
@@ -561,6 +561,49 @@ enum {
        GPIO5C0_TS0_SYNC,
 };
 
+/* GRF_GPIO6A_IOMUX */
+enum {
+       GPIO6A7_SHIFT           = 0xe,
+       GPIO6A7_MASK            = 1,
+       GPIO6A7_GPIO            = 0,
+       GPIO6A7_I2S_SDO3,
+
+       GPIO6A6_SHIFT           = 0xc,
+       GPIO6A6_MASK            = 1,
+       GPIO6A6_GPIO            = 0,
+       GPIO6A6_I2S_SDO2,
+
+       GPIO6A5_SHIFT           = 0xa,
+       GPIO6A5_MASK            = 1,
+       GPIO6A5_GPIO            = 0,
+       GPIO6A5_I2S_SDO1,
+
+       GPIO6A4_SHIFT           = 8,
+       GPIO6A4_MASK            = 1,
+       GPIO6A4_GPIO            = 0,
+       GPIO6A4_I2S_SDO0,
+
+       GPIO6A3_SHIFT           = 6,
+       GPIO6A3_MASK            = 1,
+       GPIO6A3_GPIO            = 0,
+       GPIO6A3_I2S_SDI,
+
+       GPIO6A2_SHIFT           = 4,
+       GPIO6A2_MASK            = 1,
+       GPIO6A2_GPIO            = 0,
+       GPIO6A2_I2S_LRCKTX,
+
+       GPIO6A1_SHIFT           = 2,
+       GPIO6A1_MASK            = 1,
+       GPIO6A1_GPIO            = 0,
+       GPIO6A1_I2S_LRCKRX,
+
+       GPIO6A0_SHIFT           = 0,
+       GPIO6A0_MASK            = 1,
+       GPIO6A0_GPIO            = 0,
+       GPIO6A0_I2S_SCLK,
+};
+
 /* GRF_GPIO6B_IOMUX */
 enum {
        GPIO6B3_SHIFT           = 6,
@@ -1042,6 +1085,59 @@ enum GRF_SOC_CON8 {
        RK3288_DPHY_TX0_TURNREQUEST_DIS = 0,
 };
 
+/* GRF_IO_VSEL */
+enum {
+       GPIO1830_V18SEL_SHIFT           = 9,
+       GPIO1830_V18SEL_MASK            = 1,
+       GPIO1830_V18SEL_3_3V            = 0,
+       GPIO1830_V18SEL_1_8V,
+
+       GPIO30_V18SEL_SHIFT     = 8,
+       GPIO30_V18SEL_MASK      = 1,
+       GPIO30_V18SEL_3_3V      = 0,
+       GPIO30_V18SEL_1_8V,
+
+       SDCARD_V18SEL_SHIFT     = 7,
+       SDCARD_V18SEL_MASK      = 1,
+       SDCARD_V18SEL_3_3V      = 0,
+       SDCARD_V18SEL_1_8V,
+
+       AUDIO_V18SEL_SHIFT      = 6,
+       AUDIO_V18SEL_MASK       = 1,
+       AUDIO_V18SEL_3_3V       = 0,
+       AUDIO_V18SEL_1_8V,
+
+       BB_V18SEL_SHIFT         = 5,
+       BB_V18SEL_MASK          = 1,
+       BB_V18SEL_3_3V          = 0,
+       BB_V18SEL_1_8V,
+
+       WIFI_V18SEL_SHIFT       = 4,
+       WIFI_V18SEL_MASK        = 1,
+       WIFI_V18SEL_3_3V        = 0,
+       WIFI_V18SEL_1_8V,
+
+       FLASH1_V18SEL_SHIFT     = 3,
+       FLASH1_V18SEL_MASK      = 1,
+       FLASH1_V18SEL_3_3V      = 0,
+       FLASH1_V18SEL_1_8V,
+
+       FLASH0_V18SEL_SHIFT     = 2,
+       FLASH0_V18SEL_MASK      = 1,
+       FLASH0_V18SEL_3_3V      = 0,
+       FLASH0_V18SEL_1_8V,
+
+       DVP_V18SEL_SHIFT        = 1,
+       DVP_V18SEL_MASK         = 1,
+       DVP_V18SEL_3_3V         = 0,
+       DVP_V18SEL_1_8V,
+
+       LCDC_V18SEL_SHIFT       = 0,
+       LCDC_V18SEL_MASK        = 1,
+       LCDC_V18SEL_3_3V        = 0,
+       LCDC_V18SEL_1_8V,
+};
+
 /* GPIO Bias settings */
 enum GPIO_BIAS {
        GPIO_BIAS_2MA = 0,
index 514baf6a53515e8412b9c6d6f975e1a4574742cb..2191b7d43a896885a0007f32e82039b25dcd0ae4 100644 (file)
@@ -45,6 +45,7 @@ enum periph_id {
        PERIPH_ID_HDMI,
        PERIPH_ID_GMAC,
        PERIPH_ID_SFC,
+       PERIPH_ID_I2S,
 
        PERIPH_ID_COUNT,
 
index 4a6e5c7113db0f79a7134b7e05219b36182d8c97..930c99f4d9f1e57d6bfcb3a7b42bbee5ebadaf7d 100644 (file)
@@ -6,6 +6,7 @@
 #include <common.h>
 #include <bitfield.h>
 #include <clk-uclass.h>
+#include <div64.h>
 #include <dm.h>
 #include <dt-structs.h>
 #include <errno.h>
@@ -371,6 +372,50 @@ static int rockchip_vop_set_clk(struct rk3288_cru *cru, struct rk3288_grf *grf,
 
        return 0;
 }
+
+static u32 rockchip_clk_gcd(u32 a, u32 b)
+{
+       while (b != 0) {
+               int r = b;
+
+               b = a % b;
+               a = r;
+       }
+       return a;
+}
+
+static ulong rockchip_i2s_get_clk(struct rk3288_cru *cru, uint gclk_rate)
+{
+       unsigned long long rate;
+       uint val;
+       int n, d;
+
+       val = readl(&cru->cru_clksel_con[8]);
+       n = (val & I2S0_FRAC_NUMER_MASK) >> I2S0_FRAC_NUMER_SHIFT;
+       d = (val & I2S0_FRAC_DENOM_MASK) >> I2S0_FRAC_DENOM_SHIFT;
+
+       rate = (unsigned long long)gclk_rate * n;
+       do_div(rate, d);
+
+       return (ulong)rate;
+}
+
+static ulong rockchip_i2s_set_clk(struct rk3288_cru *cru, uint gclk_rate,
+                                 uint freq)
+{
+       int n, d;
+       int v;
+
+       /* set frac divider */
+       v = rockchip_clk_gcd(gclk_rate, freq);
+       n = gclk_rate / v;
+       d = freq / v;
+       assert(freq == gclk_rate / n * d);
+       writel(d << I2S0_FRAC_NUMER_SHIFT | n << I2S0_FRAC_DENOM_SHIFT,
+              &cru->cru_clksel_con[8]);
+
+       return rockchip_i2s_get_clk(cru, gclk_rate);
+}
 #endif /* CONFIG_SPL_BUILD */
 
 static void rkclk_init(struct rk3288_cru *cru, struct rk3288_grf *grf)
@@ -769,6 +814,9 @@ static ulong rk3288_clk_set_rate(struct clk *clk, ulong rate)
                new_rate = rockchip_spi_set_clk(cru, gclk_rate, clk->id, rate);
                break;
 #ifndef CONFIG_SPL_BUILD
+       case SCLK_I2S0:
+               new_rate = rockchip_i2s_set_clk(cru, gclk_rate, rate);
+               break;
        case SCLK_MAC:
                new_rate = rockchip_mac_set_clk(priv->cru, rate);
                break;
index 3e01cfd98f4053205f16e81218bc57a5c147bc87..fd19cfb51cc824322e1f3506b650bd9876e9ed09 100644 (file)
@@ -531,6 +531,17 @@ static void pinctrl_rk3288_hdmi_config(struct rk3288_grf *grf, int hdmi_id)
                break;
        }
 }
+
+static void pinctrl_rk3288_i2s_config(struct rk3288_grf *grf)
+{
+       rk_setreg(&grf->gpio6a_iomux, GPIO6A4_I2S_SDO0 << GPIO6A4_SHIFT |
+                 GPIO6A3_I2S_SDI << GPIO6A3_SHIFT |
+                 GPIO6A2_I2S_LRCKTX << GPIO6A2_SHIFT |
+                 GPIO6A1_I2S_LRCKRX << GPIO6A1_SHIFT |
+                 GPIO6A0_I2S_SCLK << GPIO6A0_SHIFT);
+       rk_setreg(&grf->gpio6b_iomux, GPIO6B0_I2S_CLK << GPIO6B0_SHIFT);
+       rk_setreg(&grf->io_vsel, AUDIO_V18SEL_1_8V << AUDIO_V18SEL_SHIFT);
+}
 #endif
 
 static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags)
@@ -567,6 +578,9 @@ static int rk3288_pinctrl_request(struct udevice *dev, int func, int flags)
                pinctrl_rk3288_uart_config(priv->grf, func);
                break;
 #ifndef CONFIG_SPL_BUILD
+       case PERIPH_ID_I2S:
+               pinctrl_rk3288_i2s_config(priv->grf);
+               break;
        case PERIPH_ID_LCDC0:
        case PERIPH_ID_LCDC1:
                pinctrl_rk3288_lcdc_config(priv->grf, func);