diff options
author | Stephen Boyd <sboyd@codeaurora.org> | 2017-04-19 09:02:00 -0700 |
---|---|---|
committer | Stephen Boyd <sboyd@codeaurora.org> | 2017-04-19 09:02:00 -0700 |
commit | 8062b4aafc67376fb55c0438f26410d0563459ec (patch) | |
tree | bceac42287e7cd3c26bef2e16abfc184d5ac45a2 /drivers/clk | |
parent | e609f9f23e57f6af1c8f0b5759a87f9db3521eb1 (diff) | |
parent | cb545960dea2749771c88b0cb26e5adfd12a0315 (diff) |
Merge tag 'sunxi-clk-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux into clk-next
Pull Allwinner clock patches for 4.12 from Maxime Ripard:
Support for the new H5 SoC and the PRCM block found in a number of SoCs as
well, plus the usual chunk of fixes and minor enhancements.
* tag 'sunxi-clk-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git/sunxi/linux:
clk: sunxi-ng: Display index when clock registration fails
clk: sunxi-ng: a33: Add offset and minimum value for DDR1 PLL N factor
clk: sunxi-ng: a80: Remodel CPU cluster PLLs as N-type multiplier clocks
clk: sunxi-ng: mult: Support PLL lock detection
clk: sunxi-ng: add support for PRCM CCUs
dt-bindings: update device tree binding for Allwinner PRCM CCUs
clk: sunxi-ng: sun5i: Fix mux width for csi clock
clk: sunxi-ng: tighten SoC deps on explicit AllWinner SoCs
clk: sunxi-ng: add Allwinner H5 CCU support for H3 CCU driver
clk: sunxi-ng: gate: Support common pre-dividers
Diffstat (limited to 'drivers/clk')
-rw-r--r-- | drivers/clk/sunxi-ng/Kconfig | 16 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/Makefile | 1 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun5i.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-a33.c | 18 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-h3.c | 327 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-h3.h | 3 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-r.c | 213 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun8i-r.h | 27 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu-sun9i-a80.c | 70 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_common.c | 4 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_gate.c | 47 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mult.c | 2 | ||||
-rw-r--r-- | drivers/clk/sunxi-ng/ccu_mult.h | 2 |
13 files changed, 695 insertions, 37 deletions
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index 1c2357301017..64088e599404 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -64,6 +64,7 @@ config SUN50I_A64_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default ARM64 && ARCH_SUNXI + depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN5I_CCU bool "Support for the Allwinner sun5i family CCM" @@ -75,6 +76,7 @@ config SUN5I_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN5I + depends on MACH_SUN5I || COMPILE_TEST config SUN6I_A31_CCU bool "Support for the Allwinner A31/A31s CCU" @@ -86,6 +88,7 @@ config SUN6I_A31_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN6I + depends on MACH_SUN6I || COMPILE_TEST config SUN8I_A23_CCU bool "Support for the Allwinner A23 CCU" @@ -98,6 +101,7 @@ config SUN8I_A23_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN8I + depends on MACH_SUN8I || COMPILE_TEST config SUN8I_A33_CCU bool "Support for the Allwinner A33 CCU" @@ -110,6 +114,7 @@ config SUN8I_A33_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN8I + depends on MACH_SUN8I || COMPILE_TEST config SUN8I_H3_CCU bool "Support for the Allwinner H3 CCU" @@ -120,7 +125,8 @@ config SUN8I_H3_CCU select SUNXI_CCU_NM select SUNXI_CCU_MP select SUNXI_CCU_PHASE - default MACH_SUN8I + default MACH_SUN8I || (ARM64 && ARCH_SUNXI) + depends on MACH_SUN8I || (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN8I_V3S_CCU bool "Support for the Allwinner V3s CCU" @@ -132,6 +138,7 @@ config SUN8I_V3S_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN8I + depends on MACH_SUN8I || COMPILE_TEST config SUN9I_A80_CCU bool "Support for the Allwinner A80 CCU" @@ -143,5 +150,12 @@ config SUN9I_A80_CCU select SUNXI_CCU_MP select SUNXI_CCU_PHASE default MACH_SUN9I + depends on MACH_SUN9I || COMPILE_TEST + +config SUN8I_R_CCU + bool "Support for Allwinner SoCs' PRCM CCUs" + select SUNXI_CCU_DIV + select SUNXI_CCU_GATE + default MACH_SUN8I || (ARCH_SUNXI && ARM64) endif diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 6feaac0c5600..0ec02fe14c50 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o +obj-$(CONFIG_SUN8I_R_CCU) += ccu-sun8i-r.o obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80.o obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-de.o obj-$(CONFIG_SUN9I_A80_CCU) += ccu-sun9i-a80-usb.o diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index 06edaa523479..5c476f966a72 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -469,7 +469,7 @@ static const char * const csi_parents[] = { "hosc", "pll-video0", "pll-video1", static const u8 csi_table[] = { 0, 1, 2, 5, 6 }; static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_clk, "csi", csi_parents, csi_table, - 0x134, 0, 5, 24, 2, BIT(31), 0); + 0x134, 0, 5, 24, 3, BIT(31), 0); static SUNXI_CCU_GATE(ve_clk, "ve", "pll-ve", 0x13c, BIT(31), CLK_SET_RATE_PARENT); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 2c69b631967a..8d38e6510e29 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -159,13 +159,17 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", BIT(28), /* lock */ CLK_SET_RATE_UNGATE); -/* TODO: Fix N */ -static SUNXI_CCU_N_WITH_GATE_LOCK(pll_ddr1_clk, "pll-ddr1", - "osc24M", 0x04c, - 8, 6, /* N */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static struct ccu_mult pll_ddr1_clk = { + .enable = BIT(31), + .lock = BIT(28), + .mult = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 6, 0, 12, 0), + .common = { + .reg = 0x04c, + .hw.init = CLK_HW_INIT("pll-ddr1", "osc24M", + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; static const char * const cpux_parents[] = { "osc32k", "osc24M", "pll-cpux" , "pll-cpux" }; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index a26c8a19fe93..4cbc1b701b7c 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -300,8 +300,10 @@ static SUNXI_CCU_GATE(bus_uart2_clk, "bus-uart2", "apb2", 0x06c, BIT(18), 0); static SUNXI_CCU_GATE(bus_uart3_clk, "bus-uart3", "apb2", 0x06c, BIT(19), 0); -static SUNXI_CCU_GATE(bus_scr_clk, "bus-scr", "apb2", +static SUNXI_CCU_GATE(bus_scr0_clk, "bus-scr0", "apb2", 0x06c, BIT(20), 0); +static SUNXI_CCU_GATE(bus_scr1_clk, "bus-scr1", "apb2", + 0x06c, BIT(21), 0); static SUNXI_CCU_GATE(bus_ephy_clk, "bus-ephy", "ahb1", 0x070, BIT(0), 0); @@ -546,7 +548,7 @@ static struct ccu_common *sun8i_h3_ccu_clks[] = { &bus_uart1_clk.common, &bus_uart2_clk.common, &bus_uart3_clk.common, - &bus_scr_clk.common, + &bus_scr0_clk.common, &bus_ephy_clk.common, &bus_dbg_clk.common, &ths_clk.common, @@ -597,6 +599,114 @@ static struct ccu_common *sun8i_h3_ccu_clks[] = { &gpu_clk.common, }; +static struct ccu_common *sun50i_h5_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_audio_base_clk.common, + &pll_video_clk.common, + &pll_ve_clk.common, + &pll_ddr_clk.common, + &pll_periph0_clk.common, + &pll_gpu_clk.common, + &pll_periph1_clk.common, + &pll_de_clk.common, + &cpux_clk.common, + &axi_clk.common, + &ahb1_clk.common, + &apb1_clk.common, + &apb2_clk.common, + &ahb2_clk.common, + &bus_ce_clk.common, + &bus_dma_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_nand_clk.common, + &bus_dram_clk.common, + &bus_emac_clk.common, + &bus_ts_clk.common, + &bus_hstimer_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &bus_otg_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_ehci2_clk.common, + &bus_ehci3_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ohci2_clk.common, + &bus_ohci3_clk.common, + &bus_ve_clk.common, + &bus_tcon0_clk.common, + &bus_tcon1_clk.common, + &bus_deinterlace_clk.common, + &bus_csi_clk.common, + &bus_tve_clk.common, + &bus_hdmi_clk.common, + &bus_de_clk.common, + &bus_gpu_clk.common, + &bus_msgbox_clk.common, + &bus_spinlock_clk.common, + &bus_codec_clk.common, + &bus_spdif_clk.common, + &bus_pio_clk.common, + &bus_ths_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_scr0_clk.common, + &bus_scr1_clk.common, + &bus_ephy_clk.common, + &bus_dbg_clk.common, + &ths_clk.common, + &nand_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &ts_clk.common, + &ce_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &spdif_clk.common, + &usb_phy0_clk.common, + &usb_phy1_clk.common, + &usb_phy2_clk.common, + &usb_phy3_clk.common, + &usb_ohci0_clk.common, + &usb_ohci1_clk.common, + &usb_ohci2_clk.common, + &usb_ohci3_clk.common, + &dram_clk.common, + &dram_ve_clk.common, + &dram_csi_clk.common, + &dram_deinterlace_clk.common, + &dram_ts_clk.common, + &de_clk.common, + &tcon_clk.common, + &tve_clk.common, + &deinterlace_clk.common, + &csi_misc_clk.common, + &csi_sclk_clk.common, + &csi_mclk_clk.common, + &ve_clk.common, + &ac_dig_clk.common, + &avs_clk.common, + &hdmi_clk.common, + &hdmi_ddc_clk.common, + &mbus_clk.common, + &gpu_clk.common, +}; + /* We hardcode the divider to 4 for now */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); @@ -677,7 +787,7 @@ static struct clk_hw_onecell_data sun8i_h3_hw_clks = { [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, - [CLK_BUS_SCR] = &bus_scr_clk.common.hw, + [CLK_BUS_SCR0] = &bus_scr0_clk.common.hw, [CLK_BUS_EPHY] = &bus_ephy_clk.common.hw, [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, [CLK_THS] = &ths_clk.common.hw, @@ -727,7 +837,123 @@ static struct clk_hw_onecell_data sun8i_h3_hw_clks = { [CLK_MBUS] = &mbus_clk.common.hw, [CLK_GPU] = &gpu_clk.common.hw, }, - .num = CLK_NUMBER, + .num = CLK_NUMBER_H3, +}; + +static struct clk_hw_onecell_data sun50i_h5_hw_clks = { + .hws = { + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_AUDIO_BASE] = &pll_audio_base_clk.common.hw, + [CLK_PLL_AUDIO] = &pll_audio_clk.hw, + [CLK_PLL_AUDIO_2X] = &pll_audio_2x_clk.hw, + [CLK_PLL_AUDIO_4X] = &pll_audio_4x_clk.hw, + [CLK_PLL_AUDIO_8X] = &pll_audio_8x_clk.hw, + [CLK_PLL_VIDEO] = &pll_video_clk.common.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_DDR] = &pll_ddr_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.hw, + [CLK_PLL_GPU] = &pll_gpu_clk.common.hw, + [CLK_PLL_PERIPH1] = &pll_periph1_clk.common.hw, + [CLK_PLL_DE] = &pll_de_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_AXI] = &axi_clk.common.hw, + [CLK_AHB1] = &ahb1_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_APB2] = &apb2_clk.common.hw, + [CLK_AHB2] = &ahb2_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MMC0] = &bus_mmc0_clk.common.hw, + [CLK_BUS_MMC1] = &bus_mmc1_clk.common.hw, + [CLK_BUS_MMC2] = &bus_mmc2_clk.common.hw, + [CLK_BUS_NAND] = &bus_nand_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_BUS_TS] = &bus_ts_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_EHCI2] = &bus_ehci2_clk.common.hw, + [CLK_BUS_EHCI3] = &bus_ehci3_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_OHCI2] = &bus_ohci2_clk.common.hw, + [CLK_BUS_OHCI3] = &bus_ohci3_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_TCON0] = &bus_tcon0_clk.common.hw, + [CLK_BUS_TCON1] = &bus_tcon1_clk.common.hw, + [CLK_BUS_DEINTERLACE] = &bus_deinterlace_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_BUS_TVE] = &bus_tve_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_BUS_GPU] = &bus_gpu_clk.common.hw, + [CLK_BUS_MSGBOX] = &bus_msgbox_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_CODEC] = &bus_codec_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_BUS_PIO] = &bus_pio_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_BUS_I2S0] = &bus_i2s0_clk.common.hw, + [CLK_BUS_I2S1] = &bus_i2s1_clk.common.hw, + [CLK_BUS_I2S2] = &bus_i2s2_clk.common.hw, + [CLK_BUS_I2C0] = &bus_i2c0_clk.common.hw, + [CLK_BUS_I2C1] = &bus_i2c1_clk.common.hw, + [CLK_BUS_I2C2] = &bus_i2c2_clk.common.hw, + [CLK_BUS_UART0] = &bus_uart0_clk.common.hw, + [CLK_BUS_UART1] = &bus_uart1_clk.common.hw, + [CLK_BUS_UART2] = &bus_uart2_clk.common.hw, + [CLK_BUS_UART3] = &bus_uart3_clk.common.hw, + [CLK_BUS_SCR0] = &bus_scr0_clk.common.hw, + [CLK_BUS_SCR1] = &bus_scr1_clk.common.hw, + [CLK_BUS_EPHY] = &bus_ephy_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_THS] = &ths_clk.common.hw, + [CLK_NAND] = &nand_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_clk.common.hw, + [CLK_TS] = &ts_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_SPDIF] = &spdif_clk.common.hw, + [CLK_USB_PHY0] = &usb_phy0_clk.common.hw, + [CLK_USB_PHY1] = &usb_phy1_clk.common.hw, + [CLK_USB_PHY2] = &usb_phy2_clk.common.hw, + [CLK_USB_PHY3] = &usb_phy3_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_USB_OHCI2] = &usb_ohci2_clk.common.hw, + [CLK_USB_OHCI3] = &usb_ohci3_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_DRAM_VE] = &dram_ve_clk.common.hw, + [CLK_DRAM_CSI] = &dram_csi_clk.common.hw, + [CLK_DRAM_DEINTERLACE] = &dram_deinterlace_clk.common.hw, + [CLK_DRAM_TS] = &dram_ts_clk.common.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_TCON0] = &tcon_clk.common.hw, + [CLK_TVE] = &tve_clk.common.hw, + [CLK_DEINTERLACE] = &deinterlace_clk.common.hw, + [CLK_CSI_MISC] = &csi_misc_clk.common.hw, + [CLK_CSI_SCLK] = &csi_sclk_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_AC_DIG] = &ac_dig_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_HDMI] = &hdmi_clk.common.hw, + [CLK_HDMI_DDC] = &hdmi_ddc_clk.common.hw, + [CLK_MBUS] = &mbus_clk.common.hw, + [CLK_GPU] = &gpu_clk.common.hw, + }, + .num = CLK_NUMBER_H5, }; static struct ccu_reset_map sun8i_h3_ccu_resets[] = { @@ -790,7 +1016,71 @@ static struct ccu_reset_map sun8i_h3_ccu_resets[] = { [RST_BUS_UART1] = { 0x2d8, BIT(17) }, [RST_BUS_UART2] = { 0x2d8, BIT(18) }, [RST_BUS_UART3] = { 0x2d8, BIT(19) }, - [RST_BUS_SCR] = { 0x2d8, BIT(20) }, + [RST_BUS_SCR0] = { 0x2d8, BIT(20) }, +}; + +static struct ccu_reset_map sun50i_h5_ccu_resets[] = { + [RST_USB_PHY0] = { 0x0cc, BIT(0) }, + [RST_USB_PHY1] = { 0x0cc, BIT(1) }, + [RST_USB_PHY2] = { 0x0cc, BIT(2) }, + [RST_USB_PHY3] = { 0x0cc, BIT(3) }, + + [RST_MBUS] = { 0x0fc, BIT(31) }, + + [RST_BUS_CE] = { 0x2c0, BIT(5) }, + [RST_BUS_DMA] = { 0x2c0, BIT(6) }, + [RST_BUS_MMC0] = { 0x2c0, BIT(8) }, + [RST_BUS_MMC1] = { 0x2c0, BIT(9) }, + [RST_BUS_MMC2] = { 0x2c0, BIT(10) }, + [RST_BUS_NAND] = { 0x2c0, BIT(13) }, + [RST_BUS_DRAM] = { 0x2c0, BIT(14) }, + [RST_BUS_EMAC] = { 0x2c0, BIT(17) }, + [RST_BUS_TS] = { 0x2c0, BIT(18) }, + [RST_BUS_HSTIMER] = { 0x2c0, BIT(19) }, + [RST_BUS_SPI0] = { 0x2c0, BIT(20) }, + [RST_BUS_SPI1] = { 0x2c0, BIT(21) }, + [RST_BUS_OTG] = { 0x2c0, BIT(23) }, + [RST_BUS_EHCI0] = { 0x2c0, BIT(24) }, + [RST_BUS_EHCI1] = { 0x2c0, BIT(25) }, + [RST_BUS_EHCI2] = { 0x2c0, BIT(26) }, + [RST_BUS_EHCI3] = { 0x2c0, BIT(27) }, + [RST_BUS_OHCI0] = { 0x2c0, BIT(28) }, + [RST_BUS_OHCI1] = { 0x2c0, BIT(29) }, + [RST_BUS_OHCI2] = { 0x2c0, BIT(30) }, + [RST_BUS_OHCI3] = { 0x2c0, BIT(31) }, + + [RST_BUS_VE] = { 0x2c4, BIT(0) }, + [RST_BUS_TCON0] = { 0x2c4, BIT(3) }, + [RST_BUS_TCON1] = { 0x2c4, BIT(4) }, + [RST_BUS_DEINTERLACE] = { 0x2c4, BIT(5) }, + [RST_BUS_CSI] = { 0x2c4, BIT(8) }, + [RST_BUS_TVE] = { 0x2c4, BIT(9) }, + [RST_BUS_HDMI0] = { 0x2c4, BIT(10) }, + [RST_BUS_HDMI1] = { 0x2c4, BIT(11) }, + [RST_BUS_DE] = { 0x2c4, BIT(12) }, + [RST_BUS_GPU] = { 0x2c4, BIT(20) }, + [RST_BUS_MSGBOX] = { 0x2c4, BIT(21) }, + [RST_BUS_SPINLOCK] = { 0x2c4, BIT(22) }, + [RST_BUS_DBG] = { 0x2c4, BIT(31) }, + + [RST_BUS_EPHY] = { 0x2c8, BIT(2) }, + + [RST_BUS_CODEC] = { 0x2d0, BIT(0) }, + [RST_BUS_SPDIF] = { 0x2d0, BIT(1) }, + [RST_BUS_THS] = { 0x2d0, BIT(8) }, + [RST_BUS_I2S0] = { 0x2d0, BIT(12) }, + [RST_BUS_I2S1] = { 0x2d0, BIT(13) }, + [RST_BUS_I2S2] = { 0x2d0, BIT(14) }, + + [RST_BUS_I2C0] = { 0x2d8, BIT(0) }, + [RST_BUS_I2C1] = { 0x2d8, BIT(1) }, + [RST_BUS_I2C2] = { 0x2d8, BIT(2) }, + [RST_BUS_UART0] = { 0x2d8, BIT(16) }, + [RST_BUS_UART1] = { 0x2d8, BIT(17) }, + [RST_BUS_UART2] = { 0x2d8, BIT(18) }, + [RST_BUS_UART3] = { 0x2d8, BIT(19) }, + [RST_BUS_SCR0] = { 0x2d8, BIT(20) }, + [RST_BUS_SCR1] = { 0x2d8, BIT(20) }, }; static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { @@ -803,6 +1093,16 @@ static const struct sunxi_ccu_desc sun8i_h3_ccu_desc = { .num_resets = ARRAY_SIZE(sun8i_h3_ccu_resets), }; +static const struct sunxi_ccu_desc sun50i_h5_ccu_desc = { + .ccu_clks = sun50i_h5_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_h5_ccu_clks), + + .hw_clks = &sun50i_h5_hw_clks, + + .resets = sun50i_h5_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_h5_ccu_resets), +}; + static struct ccu_mux_nb sun8i_h3_cpu_nb = { .common = &cpux_clk.common, .cm = &cpux_clk.mux, @@ -810,7 +1110,8 @@ static struct ccu_mux_nb sun8i_h3_cpu_nb = { .bypass_index = 1, /* index of 24 MHz oscillator */ }; -static void __init sun8i_h3_ccu_setup(struct device_node *node) +static void __init sunxi_h3_h5_ccu_init(struct device_node *node, + const struct sunxi_ccu_desc *desc) { void __iomem *reg; u32 val; @@ -827,10 +1128,22 @@ static void __init sun8i_h3_ccu_setup(struct device_node *node) val &= ~GENMASK(19, 16); writel(val | (3 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); - sunxi_ccu_probe(node, reg, &sun8i_h3_ccu_desc); + sunxi_ccu_probe(node, reg, desc); ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, &sun8i_h3_cpu_nb); } + +static void __init sun8i_h3_ccu_setup(struct device_node *node) +{ + sunxi_h3_h5_ccu_init(node, &sun8i_h3_ccu_desc); +} CLK_OF_DECLARE(sun8i_h3_ccu, "allwinner,sun8i-h3-ccu", sun8i_h3_ccu_setup); + +static void __init sun50i_h5_ccu_setup(struct device_node *node) +{ + sunxi_h3_h5_ccu_init(node, &sun50i_h5_ccu_desc); +} +CLK_OF_DECLARE(sun50i_h5_ccu, "allwinner,sun50i-h5-ccu", + sun50i_h5_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h index 78be712c7487..85973d1e8165 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.h +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.h @@ -57,6 +57,7 @@ /* And the GPU module clock is exported */ -#define CLK_NUMBER (CLK_GPU + 1) +#define CLK_NUMBER_H3 (CLK_GPU + 1) +#define CLK_NUMBER_H5 (CLK_BUS_SCR1 + 1) #endif /* _CCU_SUN8I_H3_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c new file mode 100644 index 000000000000..0d027d53dbdf --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -0,0 +1,213 @@ +/* + * Copyright (c) 2016 Icenowy Zheng <icenowy@aosc.xyz> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_nm.h" + +#include "ccu-sun8i-r.h" + +static const char * const ar100_parents[] = { "osc32k", "osc24M", + "pll-periph0", "iosc" }; + +static struct ccu_div ar100_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(4, 2, CLK_DIVIDER_POWER_OF_TWO), + + .mux = { + .shift = 16, + .width = 2, + + .variable_prediv = { + .index = 2, + .shift = 8, + .width = 5, + }, + }, + + .common = { + .reg = 0x00, + .features = CCU_FEATURE_VARIABLE_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS("ar100", + ar100_parents, + &ccu_div_ops, + 0), + }, +}; + +static CLK_FIXED_FACTOR(ahb0_clk, "ahb0", "ar100", 1, 1, 0); + +static struct ccu_div apb0_clk = { + .div = _SUNXI_CCU_DIV_FLAGS(0, 2, CLK_DIVIDER_POWER_OF_TWO), + + .common = { + .reg = 0x0c, + .hw.init = CLK_HW_INIT("apb0", + "ahb0", + &ccu_div_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE(apb0_pio_clk, "apb0-pio", "apb0", + 0x28, BIT(0), 0); +static SUNXI_CCU_GATE(apb0_ir_clk, "apb0-ir", "apb0", + 0x28, BIT(1), 0); +static SUNXI_CCU_GATE(apb0_timer_clk, "apb0-timer", "apb0", + 0x28, BIT(2), 0); +static SUNXI_CCU_GATE(apb0_rsb_clk, "apb0-rsb", "apb0", + 0x28, BIT(3), 0); +static SUNXI_CCU_GATE(apb0_uart_clk, "apb0-uart", "apb0", + 0x28, BIT(4), 0); +static SUNXI_CCU_GATE(apb0_i2c_clk, "apb0-i2c", "apb0", + 0x28, BIT(6), 0); +static SUNXI_CCU_GATE(apb0_twd_clk, "apb0-twd", "apb0", + 0x28, BIT(7), 0); + +static const char * const r_mod0_default_parents[] = { "osc32K", "osc24M" }; +static SUNXI_CCU_MP_WITH_MUX_GATE(ir_clk, "ir", + r_mod0_default_parents, 0x54, + 0, 4, /* M */ + 16, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static struct ccu_common *sun8i_h3_r_ccu_clks[] = { + &ar100_clk.common, + &apb0_clk.common, + &apb0_pio_clk.common, + &apb0_ir_clk.common, + &apb0_timer_clk.common, + &apb0_uart_clk.common, + &apb0_i2c_clk.common, + &apb0_twd_clk.common, + &ir_clk.common, +}; + +static struct ccu_common *sun50i_a64_r_ccu_clks[] = { + &ar100_clk.common, + &apb0_clk.common, + &apb0_pio_clk.common, + &apb0_ir_clk.common, + &apb0_timer_clk.common, + &apb0_rsb_clk.common, + &apb0_uart_clk.common, + &apb0_i2c_clk.common, + &apb0_twd_clk.common, + &ir_clk.common, +}; + +static struct clk_hw_onecell_data sun8i_h3_r_hw_clks = { + .hws = { + [CLK_AR100] = &ar100_clk.common.hw, + [CLK_AHB0] = &ahb0_clk.hw, + [CLK_APB0] = &apb0_clk.common.hw, + [CLK_APB0_PIO] = &apb0_pio_clk.common.hw, + [CLK_APB0_IR] = &apb0_ir_clk.common.hw, + [CLK_APB0_TIMER] = &apb0_timer_clk.common.hw, + [CLK_APB0_UART] = &apb0_uart_clk.common.hw, + [CLK_APB0_I2C] = &apb0_i2c_clk.common.hw, + [CLK_APB0_TWD] = &apb0_twd_clk.common.hw, + [CLK_IR] = &ir_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct clk_hw_onecell_data sun50i_a64_r_hw_clks = { + .hws = { + [CLK_AR100] = &ar100_clk.common.hw, + [CLK_AHB0] = &ahb0_clk.hw, + [CLK_APB0] = &apb0_clk.common.hw, + [CLK_APB0_PIO] = &apb0_pio_clk.common.hw, + [CLK_APB0_IR] = &apb0_ir_clk.common.hw, + [CLK_APB0_TIMER] = &apb0_timer_clk.common.hw, + [CLK_APB0_RSB] = &apb0_rsb_clk.common.hw, + [CLK_APB0_UART] = &apb0_uart_clk.common.hw, + [CLK_APB0_I2C] = &apb0_i2c_clk.common.hw, + [CLK_APB0_TWD] = &apb0_twd_clk.common.hw, + [CLK_IR] = &ir_clk.common.hw, + }, + .num = CLK_NUMBER, +}; + +static struct ccu_reset_map sun8i_h3_r_ccu_resets[] = { + [RST_APB0_IR] = { 0xb0, BIT(1) }, + [RST_APB0_TIMER] = { 0xb0, BIT(2) }, + [RST_APB0_UART] = { 0xb0, BIT(4) }, + [RST_APB0_I2C] = { 0xb0, BIT(6) }, +}; + +static struct ccu_reset_map sun50i_a64_r_ccu_resets[] = { + [RST_APB0_IR] = { 0xb0, BIT(1) }, + [RST_APB0_TIMER] = { 0xb0, BIT(2) }, + [RST_APB0_RSB] = { 0xb0, BIT(3) }, + [RST_APB0_UART] = { 0xb0, BIT(4) }, + [RST_APB0_I2C] = { 0xb0, BIT(6) }, +}; + +static const struct sunxi_ccu_desc sun8i_h3_r_ccu_desc = { + .ccu_clks = sun8i_h3_r_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun8i_h3_r_ccu_clks), + + .hw_clks = &sun8i_h3_r_hw_clks, + + .resets = sun8i_h3_r_ccu_resets, + .num_resets = ARRAY_SIZE(sun8i_h3_r_ccu_resets), +}; + +static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = { + .ccu_clks = sun50i_a64_r_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun50i_a64_r_ccu_clks), + + .hw_clks = &sun50i_a64_r_hw_clks, + + .resets = sun50i_a64_r_ccu_resets, + .num_resets = ARRAY_SIZE(sun50i_a64_r_ccu_resets), +}; + +static void __init sunxi_r_ccu_init(struct device_node *node, + const struct sunxi_ccu_desc *desc) +{ + void __iomem *reg; + + reg = of_io_request_and_map(node, 0, of_node_full_name(node)); + if (IS_ERR(reg)) { + pr_err("%s: Could not map the clock registers\n", + of_node_full_name(node)); + return; + } + + sunxi_ccu_probe(node, reg, desc); +} + +static void __init sun8i_h3_r_ccu_setup(struct device_node *node) +{ + sunxi_r_ccu_init(node, &sun8i_h3_r_ccu_desc); +} +CLK_OF_DECLARE(sun8i_h3_r_ccu, "allwinner,sun8i-h3-r-ccu", + sun8i_h3_r_ccu_setup); + +static void __init sun50i_a64_r_ccu_setup(struct device_node *node) +{ + sunxi_r_ccu_init(node, &sun50i_a64_r_ccu_desc); +} +CLK_OF_DECLARE(sun50i_a64_r_ccu, "allwinner,sun50i-a64-r-ccu", + sun50i_a64_r_ccu_setup); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.h b/drivers/clk/sunxi-ng/ccu-sun8i-r.h new file mode 100644 index 000000000000..eaa431fd1d8f --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.h @@ -0,0 +1,27 @@ +/* + * Copyright 2016 Icenowy <icenowy@aosc.xyz> + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CCU_SUN8I_R_H +#define _CCU_SUN8I_R_H_ + +#include <dt-bindings/clock/sun8i-r-ccu.h> +#include <dt-bindings/reset/sun8i-r-ccu.h> + +/* AHB/APB bus clocks are not exported */ +#define CLK_AHB0 1 +#define CLK_APB0 2 + +#define CLK_NUMBER (CLK_APB0_TWD + 1) + +#endif /* _CCU_SUN8I_R_H */ diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index e13e313ce4f5..51f6d495de5b 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -29,41 +29,41 @@ #define CCU_SUN9I_LOCK_REG 0x09c -static struct clk_div_table pll_cpux_p_div_table[] = { - { .val = 0, .div = 1 }, - { .val = 1, .div = 4 }, - { /* Sentinel */ }, -}; - /* - * The CPU PLLs are actually NP clocks, but P is /1 or /4, so here we - * use the NM clocks with a divider table for M. + * The CPU PLLs are actually NP clocks, with P being /1 or /4. However + * P should only be used for output frequencies lower than 228 MHz. + * Neither mainline Linux, U-boot, nor the vendor BSPs use these. + * + * For now we can just model it as a multiplier clock, and force P to /1. */ -static struct ccu_nm pll_c0cpux_clk = { +#define SUN9I_A80_PLL_C0CPUX_REG 0x000 +#define SUN9I_A80_PLL_C1CPUX_REG 0x004 + +static struct ccu_mult pll_c0cpux_clk = { .enable = BIT(31), .lock = BIT(0), - .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), - .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table), + .mult = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .common = { - .reg = 0x000, + .reg = SUN9I_A80_PLL_C0CPUX_REG, .lock_reg = CCU_SUN9I_LOCK_REG, .features = CCU_FEATURE_LOCK_REG, .hw.init = CLK_HW_INIT("pll-c0cpux", "osc24M", - &ccu_nm_ops, CLK_SET_RATE_UNGATE), + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), }, }; -static struct ccu_nm pll_c1cpux_clk = { +static struct ccu_mult pll_c1cpux_clk = { .enable = BIT(31), .lock = BIT(1), - .n = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), - .m = _SUNXI_CCU_DIV_TABLE(16, 1, pll_cpux_p_div_table), + .mult = _SUNXI_CCU_MULT_OFFSET_MIN_MAX(8, 8, 0, 12, 0), .common = { - .reg = 0x004, + .reg = SUN9I_A80_PLL_C1CPUX_REG, .lock_reg = CCU_SUN9I_LOCK_REG, .features = CCU_FEATURE_LOCK_REG, .hw.init = CLK_HW_INIT("pll-c1cpux", "osc24M", - &ccu_nm_ops, CLK_SET_RATE_UNGATE), + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), }, }; @@ -1189,6 +1189,36 @@ static const struct sunxi_ccu_desc sun9i_a80_ccu_desc = { .num_resets = ARRAY_SIZE(sun9i_a80_ccu_resets), }; +#define SUN9I_A80_PLL_P_SHIFT 16 +#define SUN9I_A80_PLL_N_SHIFT 8 +#define SUN9I_A80_PLL_N_WIDTH 8 + +static void sun9i_a80_cpu_pll_fixup(void __iomem *reg) +{ + u32 val = readl(reg); + + /* bail out if P divider is not used */ + if (!(val & BIT(SUN9I_A80_PLL_P_SHIFT))) + return; + + /* + * If P is used, output should be less than 288 MHz. When we + * set P to 1, we should also decrease the multiplier so the + * output doesn't go out of range, but not too much such that + * the multiplier stays above 12, the minimal operation value. + * + * To keep it simple, set the multiplier to 17, the reset value. + */ + val &= ~GENMASK(SUN9I_A80_PLL_N_SHIFT + SUN9I_A80_PLL_N_WIDTH - 1, + SUN9I_A80_PLL_N_SHIFT); + val |= 17 << SUN9I_A80_PLL_N_SHIFT; + + /* And clear P */ + val &= ~BIT(SUN9I_A80_PLL_P_SHIFT); + + writel(val, reg); +} + static int sun9i_a80_ccu_probe(struct platform_device *pdev) { struct resource *res; @@ -1205,6 +1235,10 @@ static int sun9i_a80_ccu_probe(struct platform_device *pdev) val &= (BIT(16) & BIT(18)); writel(val, reg + SUN9I_A80_PLL_AUDIO_REG); + /* Enforce P = 1 for both CPU cluster PLLs */ + sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C0CPUX_REG); + sun9i_a80_cpu_pll_fixup(reg + SUN9I_A80_PLL_C1CPUX_REG); + return sunxi_ccu_probe(pdev->dev.of_node, reg, &sun9i_a80_ccu_desc); } diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 9d8724715a43..40aac316128f 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -112,8 +112,8 @@ int sunxi_ccu_probe(struct device_node *node, void __iomem *reg, ret = clk_hw_register(NULL, hw); if (ret) { - pr_err("Couldn't register clock %s\n", - clk_hw_get_name(hw)); + pr_err("Couldn't register clock %d - %s\n", + i, clk_hw_get_name(hw)); goto err_clk_unreg; } } diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c index 8a81f9d4a89f..cd069d5da215 100644 --- a/drivers/clk/sunxi-ng/ccu_gate.c +++ b/drivers/clk/sunxi-ng/ccu_gate.c @@ -75,8 +75,55 @@ static int ccu_gate_is_enabled(struct clk_hw *hw) return ccu_gate_helper_is_enabled(&cg->common, cg->enable); } +static unsigned long ccu_gate_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ccu_gate *cg = hw_to_ccu_gate(hw); + unsigned long rate = parent_rate; + + if (cg->common.features & CCU_FEATURE_ALL_PREDIV) + rate /= cg->common.prediv; + + return rate; +} + +static long ccu_gate_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct ccu_gate *cg = hw_to_ccu_gate(hw); + int div = 1; + + if (cg->common.features & CCU_FEATURE_ALL_PREDIV) + div = cg->common.prediv; + + if (clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) { + unsigned long best_parent = rate; + + if (cg->common.features & CCU_FEATURE_ALL_PREDIV) + best_parent *= div; + *prate = clk_hw_round_rate(clk_hw_get_parent(hw), best_parent); + } + + return *prate / div; +} + +static int ccu_gate_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + /* + * We must report success but we can do so unconditionally because + * clk_factor_round_rate returns values that ensure this call is a + * nop. + */ + + return 0; +} + const struct clk_ops ccu_gate_ops = { .disable = ccu_gate_disable, .enable = ccu_gate_enable, .is_enabled = ccu_gate_is_enabled, + .round_rate = ccu_gate_round_rate, + .set_rate = ccu_gate_set_rate, + .recalc_rate = ccu_gate_recalc_rate, }; diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c index 8724c01171b1..671141359895 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.c +++ b/drivers/clk/sunxi-ng/ccu_mult.c @@ -137,6 +137,8 @@ static int ccu_mult_set_rate(struct clk_hw *hw, unsigned long rate, spin_unlock_irqrestore(cm->common.lock, flags); + ccu_helper_wait_for_lock(&cm->common, cm->lock); + return 0; } diff --git a/drivers/clk/sunxi-ng/ccu_mult.h b/drivers/clk/sunxi-ng/ccu_mult.h index 524acddfcb2e..f9c37b987d72 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.h +++ b/drivers/clk/sunxi-ng/ccu_mult.h @@ -33,6 +33,7 @@ struct ccu_mult_internal { struct ccu_mult { u32 enable; + u32 lock; struct ccu_frac_internal frac; struct ccu_mult_internal mult; @@ -45,6 +46,7 @@ struct ccu_mult { _flags) \ struct ccu_mult _struct = { \ .enable = _gate, \ + .lock = _lock, \ .mult = _SUNXI_CCU_MULT(_mshift, _mwidth), \ .common = { \ .reg = _reg, \ |