diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-13 02:02:27 +0100 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-01-13 02:02:27 +0100 |
commit | 455e73a07f6e288b0061dfcf4fcf54fa9fe06458 (patch) | |
tree | 6700ff5802e4c32d5baa39a6704e4e4e13598817 /drivers/clk/sunxi-ng | |
parent | Merge tag 'leds-5.17-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/pa... (diff) | |
parent | Merge branches 'clk-ingenic' and 'clk-mediatek' into clk-next (diff) | |
download | linux-455e73a07f6e288b0061dfcf4fcf54fa9fe06458.tar.xz linux-455e73a07f6e288b0061dfcf4fcf54fa9fe06458.zip |
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd:
"We have a couple patches in the framework core this time around but
they're mostly minor cleanups and some debugfs stuff. The real work
that's in here is the typical pile of clk driver updates and new SoC
support.
Per usual (or maybe just recent trends), Qualcomm gains a handful of
SoC drivers additions and has the largest diffstat. After that there
are quite a few updates to the Allwinner (sunxi) drivers to support
modular drivers and Renesas is heavily updated to add more support for
various clks.
Overall it looks pretty normal.
New Drivers:
- Add MDMA and BDMA clks to Ingenic JZ4760 and JZ4770
- MediaTek mt7986 SoC basic support
- Clock and reset driver for Toshiba Visconti SoCs
- Initial clock driver for the Exynos7885 SoC (Samsung Galaxy A8)
- Allwinner D1 clks
- Lan966x Generic Clock Controller driver and associated DT bindings
- Qualcomm SDX65, SM8450, and MSM8976 GCC clks
- Qualcomm SDX65 and SM8450 RPMh clks
Updates:
- Set suppress_bind_attrs to true for i.MX8ULP driver
- Switch from do_div to div64_ul for throughout all i.MX drivers
- Fix imx8mn_clko1_sels for i.MX8MN
- Remove unused IPG_AUDIO_ROOT from i.MX8MP
- Switch parent for audio_root_clk to audio ahb in i.MX8MP driver
- Removal of all remaining uses of __clk_lookup() in
drivers/clk/samsung
- Refactoring of the CPU clocks registration to use common interface
- An update of the Exynos850 driver (support for more clock domains)
required by the E850-96 development board
- Prep for runtime PM and generic power domains on Tegra
- Support modular Allwinner clk drivers via platform bus
- Lan966x clock driver extended to support clock gating
- Add serial (SCI1), watchdog (WDT), timer (OSTM), SPI (RSPI), and
thermal (TSU) clocks and resets on Renesas RZ/G2L
- Rework SDHI clock handling in the Renesas R-Car Gen3 and RZ/G2
clock drivers, and in the Renesas SDHI driver
- Make the Cortex-A55 (I) clock on Renesas RZ/G2L programmable
- Document support for the new Renesas R-Car S4-8 (R8A779F0) SoC
- Add support for the new Renesas R-Car S4-8 (R8A779F0) SoC
- Add GPU clock and resets on Renesas RZ/G2L
- Add clk-provider.h to various Qualcomm clk drivers
- devm version of clk_hw_register_gate()
- kerneldoc fixes in a couple drivers"
* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (131 commits)
clk: visconti: Remove pointless NULL check in visconti_pll_add_lookup()
clk: mediatek: add mt7986 clock support
clk: mediatek: add mt7986 clock IDs
dt-bindings: clock: mediatek: document clk bindings for mediatek mt7986 SoC
clk: mediatek: clk-gate: Use regmap_{set/clear}_bits helpers
clk: mediatek: clk-gate: Shrink by adding clockgating bit check helper
clk: x86: Fix clk_gate_flags for RV_CLK_GATE
clk: x86: Use dynamic con_id string during clk registration
ACPI: APD: Add a fmw property clk-name
drivers: acpi: acpi_apd: Remove unused device property "is-rv"
x86: clk: clk-fch: Add support for newer family of AMD's SOC
clk: ingenic: Add MDMA and BDMA clocks
dt-bindings: clk/ingenic: Add MDMA and BDMA clocks
clk: bm1880: remove kfrees on static allocations
clk: Drop unused COMMON_CLK_STM32MP157_SCMI config
clk: st: clkgen-mux: search reg within node or parent
clk: st: clkgen-fsyn: search reg within node or parent
clk: Enable/Disable runtime PM for clk_summary
MAINTAINERS: Add entries for Toshiba Visconti PLL and clock controller
clk: visconti: Add support common clock driver and reset driver
...
Diffstat (limited to 'drivers/clk/sunxi-ng')
44 files changed, 2256 insertions, 237 deletions
diff --git a/drivers/clk/sunxi-ng/Kconfig b/drivers/clk/sunxi-ng/Kconfig index e76e1676f0f0..68a94e5af8ed 100644 --- a/drivers/clk/sunxi-ng/Kconfig +++ b/drivers/clk/sunxi-ng/Kconfig @@ -1,6 +1,6 @@ # SPDX-License-Identifier: GPL-2.0-only config SUNXI_CCU - bool "Clock support for Allwinner SoCs" + tristate "Clock support for Allwinner SoCs" depends on ARCH_SUNXI || COMPILE_TEST select RESET_CONTROLLER default ARCH_SUNXI @@ -8,42 +8,52 @@ config SUNXI_CCU if SUNXI_CCU config SUNIV_F1C100S_CCU - bool "Support for the Allwinner newer F1C100s CCU" + tristate "Support for the Allwinner newer F1C100s CCU" default MACH_SUNIV depends on MACH_SUNIV || COMPILE_TEST +config SUN20I_D1_CCU + tristate "Support for the Allwinner D1 CCU" + default RISCV && ARCH_SUNXI + depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST + +config SUN20I_D1_R_CCU + tristate "Support for the Allwinner D1 PRCM CCU" + default RISCV && ARCH_SUNXI + depends on (RISCV && ARCH_SUNXI) || COMPILE_TEST + config SUN50I_A64_CCU - bool "Support for the Allwinner A64 CCU" + tristate "Support for the Allwinner A64 CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN50I_A100_CCU - bool "Support for the Allwinner A100 CCU" + tristate "Support for the Allwinner A100 CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN50I_A100_R_CCU - bool "Support for the Allwinner A100 PRCM CCU" + tristate "Support for the Allwinner A100 PRCM CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN50I_H6_CCU - bool "Support for the Allwinner H6 CCU" + tristate "Support for the Allwinner H6 CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN50I_H616_CCU - bool "Support for the Allwinner H616 CCU" + tristate "Support for the Allwinner H616 CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN50I_H6_R_CCU - bool "Support for the Allwinner H6 and H616 PRCM CCU" + tristate "Support for the Allwinner H6 and H616 PRCM CCU" default ARM64 && ARCH_SUNXI depends on (ARM64 && ARCH_SUNXI) || COMPILE_TEST config SUN4I_A10_CCU - bool "Support for the Allwinner A10/A20 CCU" + tristate "Support for the Allwinner A10/A20 CCU" default MACH_SUN4I default MACH_SUN7I depends on MACH_SUN4I || MACH_SUN7I || COMPILE_TEST @@ -52,53 +62,54 @@ config SUN5I_CCU bool "Support for the Allwinner sun5i family CCM" default MACH_SUN5I depends on MACH_SUN5I || COMPILE_TEST + depends on SUNXI_CCU=y config SUN6I_A31_CCU - bool "Support for the Allwinner A31/A31s CCU" + tristate "Support for the Allwinner A31/A31s CCU" default MACH_SUN6I depends on MACH_SUN6I || COMPILE_TEST config SUN8I_A23_CCU - bool "Support for the Allwinner A23 CCU" + tristate "Support for the Allwinner A23 CCU" default MACH_SUN8I depends on MACH_SUN8I || COMPILE_TEST config SUN8I_A33_CCU - bool "Support for the Allwinner A33 CCU" + tristate "Support for the Allwinner A33 CCU" default MACH_SUN8I depends on MACH_SUN8I || COMPILE_TEST config SUN8I_A83T_CCU - bool "Support for the Allwinner A83T CCU" + tristate "Support for the Allwinner A83T CCU" default MACH_SUN8I depends on MACH_SUN8I || COMPILE_TEST config SUN8I_H3_CCU - bool "Support for the Allwinner H3 CCU" + tristate "Support for the Allwinner H3 CCU" 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" + tristate "Support for the Allwinner V3s CCU" default MACH_SUN8I depends on MACH_SUN8I || COMPILE_TEST config SUN8I_DE2_CCU - bool "Support for the Allwinner SoCs DE2 CCU" + tristate "Support for the Allwinner SoCs DE2 CCU" default MACH_SUN8I || (ARM64 && ARCH_SUNXI) config SUN8I_R40_CCU - bool "Support for the Allwinner R40 CCU" + tristate "Support for the Allwinner R40 CCU" default MACH_SUN8I depends on MACH_SUN8I || COMPILE_TEST config SUN9I_A80_CCU - bool "Support for the Allwinner A80 CCU" + tristate "Support for the Allwinner A80 CCU" default MACH_SUN9I depends on MACH_SUN9I || COMPILE_TEST config SUN8I_R_CCU - bool "Support for Allwinner SoCs' PRCM CCUs" + tristate "Support for Allwinner SoCs' PRCM CCUs" default MACH_SUN8I || (ARCH_SUNXI && ARM64) endif diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index 96c324306d97..ec931cb7aa14 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -1,44 +1,73 @@ # SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_SUNXI_CCU) += sunxi-ccu.o + # Common objects -obj-y += ccu_common.o -obj-y += ccu_mmc_timing.o -obj-y += ccu_reset.o +sunxi-ccu-y += ccu_common.o +sunxi-ccu-y += ccu_mmc_timing.o +sunxi-ccu-y += ccu_reset.o # Base clock types -obj-y += ccu_div.o -obj-y += ccu_frac.o -obj-y += ccu_gate.o -obj-y += ccu_mux.o -obj-y += ccu_mult.o -obj-y += ccu_phase.o -obj-y += ccu_sdm.o +sunxi-ccu-y += ccu_div.o +sunxi-ccu-y += ccu_frac.o +sunxi-ccu-y += ccu_gate.o +sunxi-ccu-y += ccu_mux.o +sunxi-ccu-y += ccu_mult.o +sunxi-ccu-y += ccu_phase.o +sunxi-ccu-y += ccu_sdm.o # Multi-factor clocks -obj-y += ccu_nk.o -obj-y += ccu_nkm.o -obj-y += ccu_nkmp.o -obj-y += ccu_nm.o -obj-y += ccu_mp.o +sunxi-ccu-y += ccu_nk.o +sunxi-ccu-y += ccu_nkm.o +sunxi-ccu-y += ccu_nkmp.o +sunxi-ccu-y += ccu_nm.o +sunxi-ccu-y += ccu_mp.o # SoC support -obj-$(CONFIG_SUNIV_F1C100S_CCU) += ccu-suniv-f1c100s.o -obj-$(CONFIG_SUN50I_A64_CCU) += ccu-sun50i-a64.o -obj-$(CONFIG_SUN50I_A100_CCU) += ccu-sun50i-a100.o -obj-$(CONFIG_SUN50I_A100_R_CCU) += ccu-sun50i-a100-r.o -obj-$(CONFIG_SUN50I_H6_CCU) += ccu-sun50i-h6.o -obj-$(CONFIG_SUN50I_H616_CCU) += ccu-sun50i-h616.o -obj-$(CONFIG_SUN50I_H6_R_CCU) += ccu-sun50i-h6-r.o -obj-$(CONFIG_SUN4I_A10_CCU) += ccu-sun4i-a10.o -obj-$(CONFIG_SUN5I_CCU) += ccu-sun5i.o -obj-$(CONFIG_SUN6I_A31_CCU) += ccu-sun6i-a31.o -obj-$(CONFIG_SUN8I_A23_CCU) += ccu-sun8i-a23.o -obj-$(CONFIG_SUN8I_A33_CCU) += ccu-sun8i-a33.o -obj-$(CONFIG_SUN8I_A83T_CCU) += ccu-sun8i-a83t.o -obj-$(CONFIG_SUN8I_H3_CCU) += ccu-sun8i-h3.o -obj-$(CONFIG_SUN8I_V3S_CCU) += ccu-sun8i-v3s.o -obj-$(CONFIG_SUN8I_DE2_CCU) += ccu-sun8i-de2.o -obj-$(CONFIG_SUN8I_R_CCU) += ccu-sun8i-r.o -obj-$(CONFIG_SUN8I_R40_CCU) += ccu-sun8i-r40.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 +obj-$(CONFIG_SUNIV_F1C100S_CCU) += suniv-f1c100s-ccu.o +obj-$(CONFIG_SUN20I_D1_CCU) += sun20i-d1-ccu.o +obj-$(CONFIG_SUN20I_D1_R_CCU) += sun20i-d1-r-ccu.o +obj-$(CONFIG_SUN50I_A64_CCU) += sun50i-a64-ccu.o +obj-$(CONFIG_SUN50I_A100_CCU) += sun50i-a100-ccu.o +obj-$(CONFIG_SUN50I_A100_R_CCU) += sun50i-a100-r-ccu.o +obj-$(CONFIG_SUN50I_H6_CCU) += sun50i-h6-ccu.o +obj-$(CONFIG_SUN50I_H6_R_CCU) += sun50i-h6-r-ccu.o +obj-$(CONFIG_SUN50I_H616_CCU) += sun50i-h616-ccu.o +obj-$(CONFIG_SUN4I_A10_CCU) += sun4i-a10-ccu.o +obj-$(CONFIG_SUN5I_CCU) += sun5i-ccu.o +obj-$(CONFIG_SUN6I_A31_CCU) += sun6i-a31-ccu.o +obj-$(CONFIG_SUN8I_A23_CCU) += sun8i-a23-ccu.o +obj-$(CONFIG_SUN8I_A33_CCU) += sun8i-a33-ccu.o +obj-$(CONFIG_SUN8I_A83T_CCU) += sun8i-a83t-ccu.o +obj-$(CONFIG_SUN8I_H3_CCU) += sun8i-h3-ccu.o +obj-$(CONFIG_SUN8I_R40_CCU) += sun8i-r40-ccu.o +obj-$(CONFIG_SUN8I_V3S_CCU) += sun8i-v3s-ccu.o +obj-$(CONFIG_SUN8I_DE2_CCU) += sun8i-de2-ccu.o +obj-$(CONFIG_SUN8I_R_CCU) += sun8i-r-ccu.o +obj-$(CONFIG_SUN9I_A80_CCU) += sun9i-a80-ccu.o +obj-$(CONFIG_SUN9I_A80_CCU) += sun9i-a80-de-ccu.o +obj-$(CONFIG_SUN9I_A80_CCU) += sun9i-a80-usb-ccu.o + +suniv-f1c100s-ccu-y += ccu-suniv-f1c100s.o +sun20i-d1-ccu-y += ccu-sun20i-d1.o +sun20i-d1-r-ccu-y += ccu-sun20i-d1-r.o +sun50i-a64-ccu-y += ccu-sun50i-a64.o +sun50i-a100-ccu-y += ccu-sun50i-a100.o +sun50i-a100-r-ccu-y += ccu-sun50i-a100-r.o +sun50i-h6-ccu-y += ccu-sun50i-h6.o +sun50i-h6-r-ccu-y += ccu-sun50i-h6-r.o +sun50i-h616-ccu-y += ccu-sun50i-h616.o +sun4i-a10-ccu-y += ccu-sun4i-a10.o +sun5i-ccu-y += ccu-sun5i.o +sun6i-a31-ccu-y += ccu-sun6i-a31.o +sun8i-a23-ccu-y += ccu-sun8i-a23.o +sun8i-a33-ccu-y += ccu-sun8i-a33.o +sun8i-a83t-ccu-y += ccu-sun8i-a83t.o +sun8i-h3-ccu-y += ccu-sun8i-h3.o +sun8i-r40-ccu-y += ccu-sun8i-r40.o +sun8i-v3s-ccu-y += ccu-sun8i-v3s.o +sun8i-de2-ccu-y += ccu-sun8i-de2.o +sun8i-r-ccu-y += ccu-sun8i-r.o +sun9i-a80-ccu-y += ccu-sun9i-a80.o +sun9i-a80-de-ccu-y += ccu-sun9i-a80-de.o +sun9i-a80-usb-ccu-y += ccu-sun9i-a80-usb.o diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c new file mode 100644 index 000000000000..9d3ffd3fb2c1 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.c @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 huangzhenwei@allwinnertech.com + * Copyright (C) 2021 Samuel Holland <samuel@sholland.org> + */ + +#include <linux/clk-provider.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_gate.h" +#include "ccu_mp.h" + +#include "ccu-sun20i-d1-r.h" + +static const struct clk_parent_data r_ahb_apb0_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .fw_name = "pll-periph" }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX(r_ahb_clk, "r-ahb", + r_ahb_apb0_parents, 0x000, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); +static const struct clk_hw *r_ahb_hw = &r_ahb_clk.common.hw; + +static SUNXI_CCU_MP_DATA_WITH_MUX(r_apb0_clk, "r-apb0", + r_ahb_apb0_parents, 0x00c, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + 0); +static const struct clk_hw *r_apb0_hw = &r_apb0_clk.common.hw; + +static SUNXI_CCU_GATE_HWS(bus_r_timer_clk, "bus-r-timer", &r_apb0_hw, + 0x11c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_r_twd_clk, "bus-r-twd", &r_apb0_hw, + 0x12c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_r_ppu_clk, "bus-r-ppu", &r_apb0_hw, + 0x1ac, BIT(0), 0); + +static const struct clk_parent_data r_ir_rx_parents[] = { + { .fw_name = "losc" }, + { .fw_name = "hosc" }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(r_ir_rx_clk, "r-ir-rx", + r_ir_rx_parents, 0x1c0, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_r_ir_rx_clk, "bus-r-ir-rx", &r_apb0_hw, + 0x1cc, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_r_rtc_clk, "bus-r-rtc", &r_ahb_hw, + 0x20c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_r_cpucfg_clk, "bus-r-cpucfg", &r_apb0_hw, + 0x22c, BIT(0), 0); + +static struct ccu_common *sun20i_d1_r_ccu_clks[] = { + &r_ahb_clk.common, + &r_apb0_clk.common, + &bus_r_timer_clk.common, + &bus_r_twd_clk.common, + &bus_r_ppu_clk.common, + &r_ir_rx_clk.common, + &bus_r_ir_rx_clk.common, + &bus_r_rtc_clk.common, + &bus_r_cpucfg_clk.common, +}; + +static struct clk_hw_onecell_data sun20i_d1_r_hw_clks = { + .num = CLK_NUMBER, + .hws = { + [CLK_R_AHB] = &r_ahb_clk.common.hw, + [CLK_R_APB0] = &r_apb0_clk.common.hw, + [CLK_BUS_R_TIMER] = &bus_r_timer_clk.common.hw, + [CLK_BUS_R_TWD] = &bus_r_twd_clk.common.hw, + [CLK_BUS_R_PPU] = &bus_r_ppu_clk.common.hw, + [CLK_R_IR_RX] = &r_ir_rx_clk.common.hw, + [CLK_BUS_R_IR_RX] = &bus_r_ir_rx_clk.common.hw, + [CLK_BUS_R_RTC] = &bus_r_rtc_clk.common.hw, + [CLK_BUS_R_CPUCFG] = &bus_r_cpucfg_clk.common.hw, + }, +}; + +static struct ccu_reset_map sun20i_d1_r_ccu_resets[] = { + [RST_BUS_R_TIMER] = { 0x11c, BIT(16) }, + [RST_BUS_R_TWD] = { 0x12c, BIT(16) }, + [RST_BUS_R_PPU] = { 0x1ac, BIT(16) }, + [RST_BUS_R_IR_RX] = { 0x1cc, BIT(16) }, + [RST_BUS_R_RTC] = { 0x20c, BIT(16) }, + [RST_BUS_R_CPUCFG] = { 0x22c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun20i_d1_r_ccu_desc = { + .ccu_clks = sun20i_d1_r_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun20i_d1_r_ccu_clks), + + .hw_clks = &sun20i_d1_r_hw_clks, + + .resets = sun20i_d1_r_ccu_resets, + .num_resets = ARRAY_SIZE(sun20i_d1_r_ccu_resets), +}; + +static int sun20i_d1_r_ccu_probe(struct platform_device *pdev) +{ + void __iomem *reg; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_r_ccu_desc); +} + +static const struct of_device_id sun20i_d1_r_ccu_ids[] = { + { .compatible = "allwinner,sun20i-d1-r-ccu" }, + { } +}; + +static struct platform_driver sun20i_d1_r_ccu_driver = { + .probe = sun20i_d1_r_ccu_probe, + .driver = { + .name = "sun20i-d1-r-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun20i_d1_r_ccu_ids, + }, +}; +module_platform_driver(sun20i_d1_r_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h new file mode 100644 index 000000000000..afd4342209ee --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1-r.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 frank@allwinnertech.com + * Copyright (C) 2021 Samuel Holland <samuel@sholland.org> + */ + +#ifndef _CCU_SUN20I_D1_R_H +#define _CCU_SUN20I_D1_R_H + +#include <dt-bindings/clock/sun20i-d1-r-ccu.h> +#include <dt-bindings/reset/sun20i-d1-r-ccu.h> + +#define CLK_R_APB0 1 + +#define CLK_NUMBER (CLK_BUS_R_CPUCFG + 1) + +#endif /* _CCU_SUN20I_D1_R_H */ diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.c b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c new file mode 100644 index 000000000000..51058ba4db4d --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.c @@ -0,0 +1,1390 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2020 huangzhenwei@allwinnertech.com + * Copyright (C) 2021 Samuel Holland <samuel@sholland.org> + */ + +#include <linux/clk-provider.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#include "../clk.h" + +#include "ccu_common.h" +#include "ccu_reset.h" + +#include "ccu_div.h" +#include "ccu_gate.h" +#include "ccu_mp.h" +#include "ccu_mult.h" +#include "ccu_nk.h" +#include "ccu_nkm.h" +#include "ccu_nkmp.h" +#include "ccu_nm.h" + +#include "ccu-sun20i-d1.h" + +static const struct clk_parent_data osc24M[] = { + { .fw_name = "hosc" } +}; + +/* + * For the CPU PLL, the output divider is described as "only for testing" + * in the user manual. So it's not modelled and forced to 0. + */ +#define SUN20I_D1_PLL_CPUX_REG 0x000 +static struct ccu_mult pll_cpux_clk = { + .enable = BIT(27), + .lock = BIT(28), + .mult = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .common = { + .reg = 0x000, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-cpux", osc24M, + &ccu_mult_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* Some PLLs are input * N / div1 / P. Model them as NKMP with no K */ +#define SUN20I_D1_PLL_DDR0_REG 0x010 +static struct ccu_nkmp pll_ddr0_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x010, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-ddr0", osc24M, + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +#define SUN20I_D1_PLL_PERIPH0_REG 0x020 +static struct ccu_nm pll_periph0_4x_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .common = { + .reg = 0x020, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-periph0-4x", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const struct clk_hw *pll_periph0_4x_hws[] = { + &pll_periph0_4x_clk.common.hw +}; +static SUNXI_CCU_M_HWS(pll_periph0_2x_clk, "pll-periph0-2x", + pll_periph0_4x_hws, 0x020, 16, 3, 0); +static SUNXI_CCU_M_HWS(pll_periph0_800M_clk, "pll-periph0-800M", + pll_periph0_4x_hws, 0x020, 20, 3, 0); + +static const struct clk_hw *pll_periph0_2x_hws[] = { + &pll_periph0_2x_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_periph0_clk, "pll-periph0", + pll_periph0_2x_hws, 2, 1, 0); + +static const struct clk_hw *pll_periph0_hws[] = { &pll_periph0_clk.hw }; +static CLK_FIXED_FACTOR_HWS(pll_periph0_div3_clk, "pll-periph0-div3", + pll_periph0_2x_hws, 6, 1, 0); + +/* + * For Video PLLs, the output divider is described as "only for testing" + * in the user manual. So it's not modelled and forced to 0. + */ +#define SUN20I_D1_PLL_VIDEO0_REG 0x040 +static struct ccu_nm pll_video0_4x_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .common = { + .reg = 0x040, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-video0-4x", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const struct clk_hw *pll_video0_4x_hws[] = { + &pll_video0_4x_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video0_2x_clk, "pll-video0-2x", + pll_video0_4x_hws, 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video0_clk, "pll-video0", + pll_video0_4x_hws, 4, 1, CLK_SET_RATE_PARENT); + +#define SUN20I_D1_PLL_VIDEO1_REG 0x048 +static struct ccu_nm pll_video1_4x_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .common = { + .reg = 0x048, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-video1-4x", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const struct clk_hw *pll_video1_4x_hws[] = { + &pll_video1_4x_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_video1_2x_clk, "pll-video1-2x", + pll_video1_4x_hws, 2, 1, CLK_SET_RATE_PARENT); +static CLK_FIXED_FACTOR_HWS(pll_video1_clk, "pll-video1", + pll_video1_4x_hws, 4, 1, CLK_SET_RATE_PARENT); + +#define SUN20I_D1_PLL_VE_REG 0x058 +static struct ccu_nkmp pll_ve_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), /* input divider */ + .p = _SUNXI_CCU_DIV(0, 1), /* output divider */ + .common = { + .reg = 0x058, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-ve", osc24M, + &ccu_nkmp_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +/* + * PLL_AUDIO0 has m0, m1 dividers in addition to the usual N, M factors. + * Since we only need one frequency from this PLL (22.5792 x 4 == 90.3168 MHz), + * ignore them for now. Enforce the default for them, which is m1 = 0, m0 = 0. + * The M factor must be an even number to produce a 50% duty cycle output. + */ +#define SUN20I_D1_PLL_AUDIO0_REG 0x078 +static struct ccu_sdm_setting pll_audio0_sdm_table[] = { + { .rate = 90316800, .pattern = 0xc001288d, .m = 6, .n = 22 }, +}; + +static struct ccu_nm pll_audio0_4x_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(16, 6), + .sdm = _SUNXI_CCU_SDM(pll_audio0_sdm_table, BIT(24), + 0x178, BIT(31)), + .common = { + .reg = 0x078, + .features = CCU_FEATURE_SIGMA_DELTA_MOD, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-audio0-4x", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const struct clk_hw *pll_audio0_4x_hws[] = { + &pll_audio0_4x_clk.common.hw +}; +static CLK_FIXED_FACTOR_HWS(pll_audio0_2x_clk, "pll-audio0-2x", + pll_audio0_4x_hws, 2, 1, 0); +static CLK_FIXED_FACTOR_HWS(pll_audio0_clk, "pll-audio0", + pll_audio0_4x_hws, 4, 1, 0); + +/* + * PLL_AUDIO1 doesn't need Fractional-N. The output is usually 614.4 MHz for + * audio. The ADC or DAC should divide the PLL output further to 24.576 MHz. + */ +#define SUN20I_D1_PLL_AUDIO1_REG 0x080 +static struct ccu_nm pll_audio1_clk = { + .enable = BIT(27), + .lock = BIT(28), + .n = _SUNXI_CCU_MULT_MIN(8, 8, 12), + .m = _SUNXI_CCU_DIV(1, 1), + .common = { + .reg = 0x080, + .hw.init = CLK_HW_INIT_PARENTS_DATA("pll-audio1", osc24M, + &ccu_nm_ops, + CLK_SET_RATE_UNGATE), + }, +}; + +static const struct clk_hw *pll_audio1_hws[] = { + &pll_audio1_clk.common.hw +}; +static SUNXI_CCU_M_HWS(pll_audio1_div2_clk, "pll-audio1-div2", + pll_audio1_hws, 0x080, 16, 3, 0); +static SUNXI_CCU_M_HWS(pll_audio1_div5_clk, "pll-audio1-div5", + pll_audio1_hws, 0x080, 20, 3, 0); + +/* + * The CPUX gate is not modelled - it is in a separate register (0x504) + * and has a special key field. The clock does not need to be ungated anyway. + */ +static const struct clk_parent_data cpux_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_cpux_clk.common.hw }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_periph0_800M_clk.common.hw }, +}; +static SUNXI_CCU_MUX_DATA(cpux_clk, "cpux", cpux_parents, + 0x500, 24, 3, CLK_SET_RATE_PARENT); + +static const struct clk_hw *cpux_hws[] = { &cpux_clk.common.hw }; +static SUNXI_CCU_M_HWS(cpux_axi_clk, "cpux-axi", + cpux_hws, 0x500, 0, 2, 0); +static SUNXI_CCU_M_HWS(cpux_apb_clk, "cpux-apb", + cpux_hws, 0x500, 8, 2, 0); + +static const struct clk_parent_data psi_ahb_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_periph0_clk.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX(psi_ahb_clk, "psi-ahb", psi_ahb_parents, 0x510, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const struct clk_parent_data apb0_apb1_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .hw = &psi_ahb_clk.common.hw }, + { .hw = &pll_periph0_clk.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX(apb0_clk, "apb0", apb0_apb1_parents, 0x520, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static SUNXI_CCU_MP_DATA_WITH_MUX(apb1_clk, "apb1", apb0_apb1_parents, 0x524, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + 0); + +static const struct clk_hw *psi_ahb_hws[] = { &psi_ahb_clk.common.hw }; +static const struct clk_hw *apb0_hws[] = { &apb0_clk.common.hw }; +static const struct clk_hw *apb1_hws[] = { &apb1_clk.common.hw }; + +static const struct clk_hw *de_di_g2d_parents[] = { + &pll_periph0_2x_clk.common.hw, + &pll_video0_4x_clk.common.hw, + &pll_video1_4x_clk.common.hw, + &pll_audio1_div2_clk.common.hw, +}; +static SUNXI_CCU_M_HW_WITH_MUX_GATE(de_clk, "de", de_di_g2d_parents, 0x600, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_de_clk, "bus-de", psi_ahb_hws, + 0x60c, BIT(0), 0); + +static SUNXI_CCU_M_HW_WITH_MUX_GATE(di_clk, "di", de_di_g2d_parents, 0x620, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_di_clk, "bus-di", psi_ahb_hws, + 0x62c, BIT(0), 0); + +static SUNXI_CCU_M_HW_WITH_MUX_GATE(g2d_clk, "g2d", de_di_g2d_parents, 0x630, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_g2d_clk, "bus-g2d", psi_ahb_hws, + 0x63c, BIT(0), 0); + +static const struct clk_parent_data ce_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_periph0_clk.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ce_clk, "ce", ce_parents, 0x680, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_ce_clk, "bus-ce", psi_ahb_hws, + 0x68c, BIT(0), 0); + +static const struct clk_hw *ve_parents[] = { + &pll_ve_clk.common.hw, + &pll_periph0_2x_clk.common.hw, +}; +static SUNXI_CCU_M_HW_WITH_MUX_GATE(ve_clk, "ve", ve_parents, 0x690, + 0, 5, /* M */ + 24, 1, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_ve_clk, "bus-ve", psi_ahb_hws, + 0x69c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_dma_clk, "bus-dma", psi_ahb_hws, + 0x70c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_msgbox0_clk, "bus-msgbox0", psi_ahb_hws, + 0x71c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_msgbox1_clk, "bus-msgbox1", psi_ahb_hws, + 0x71c, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_msgbox2_clk, "bus-msgbox2", psi_ahb_hws, + 0x71c, BIT(2), 0); + +static SUNXI_CCU_GATE_HWS(bus_spinlock_clk, "bus-spinlock", psi_ahb_hws, + 0x72c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_hstimer_clk, "bus-hstimer", psi_ahb_hws, + 0x73c, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(avs_clk, "avs", osc24M, + 0x740, BIT(31), 0); + +static SUNXI_CCU_GATE_HWS(bus_dbg_clk, "bus-dbg", psi_ahb_hws, + 0x78c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_pwm_clk, "bus-pwm", apb0_hws, + 0x7ac, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_iommu_clk, "bus-iommu", apb0_hws, + 0x7bc, BIT(0), 0); + +static const struct clk_hw *dram_parents[] = { + &pll_ddr0_clk.common.hw, + &pll_audio1_div2_clk.common.hw, + &pll_periph0_2x_clk.common.hw, + &pll_periph0_800M_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dram_clk, "dram", dram_parents, 0x800, + 0, 2, /* M */ + 8, 2, /* P */ + 24, 2, /* mux */ + BIT(31), CLK_IS_CRITICAL); + +static CLK_FIXED_FACTOR_HW(mbus_clk, "mbus", + &dram_clk.common.hw, 4, 1, 0); + +static const struct clk_hw *mbus_hws[] = { &mbus_clk.hw }; + +static SUNXI_CCU_GATE_HWS(mbus_dma_clk, "mbus-dma", mbus_hws, + 0x804, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(mbus_ve_clk, "mbus-ve", mbus_hws, + 0x804, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(mbus_ce_clk, "mbus-ce", mbus_hws, + 0x804, BIT(2), 0); +static SUNXI_CCU_GATE_HWS(mbus_tvin_clk, "mbus-tvin", mbus_hws, + 0x804, BIT(7), 0); +static SUNXI_CCU_GATE_HWS(mbus_csi_clk, "mbus-csi", mbus_hws, + 0x804, BIT(8), 0); +static SUNXI_CCU_GATE_HWS(mbus_g2d_clk, "mbus-g2d", mbus_hws, + 0x804, BIT(10), 0); +static SUNXI_CCU_GATE_HWS(mbus_riscv_clk, "mbus-riscv", mbus_hws, + 0x804, BIT(11), 0); + +static SUNXI_CCU_GATE_HWS(bus_dram_clk, "bus-dram", psi_ahb_hws, + 0x80c, BIT(0), CLK_IS_CRITICAL); + +static const struct clk_parent_data mmc0_mmc1_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc0_clk, "mmc0", mmc0_mmc1_parents, 0x830, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc1_clk, "mmc1", mmc0_mmc1_parents, 0x834, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const struct clk_parent_data mmc2_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_periph0_800M_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(mmc2_clk, "mmc2", mmc2_parents, 0x838, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_mmc0_clk, "bus-mmc0", psi_ahb_hws, + 0x84c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_mmc1_clk, "bus-mmc1", psi_ahb_hws, + 0x84c, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_mmc2_clk, "bus-mmc2", psi_ahb_hws, + 0x84c, BIT(2), 0); + +static SUNXI_CCU_GATE_HWS(bus_uart0_clk, "bus-uart0", apb1_hws, + 0x90c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_uart1_clk, "bus-uart1", apb1_hws, + 0x90c, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_uart2_clk, "bus-uart2", apb1_hws, + 0x90c, BIT(2), 0); +static SUNXI_CCU_GATE_HWS(bus_uart3_clk, "bus-uart3", apb1_hws, + 0x90c, BIT(3), 0); +static SUNXI_CCU_GATE_HWS(bus_uart4_clk, "bus-uart4", apb1_hws, + 0x90c, BIT(4), 0); +static SUNXI_CCU_GATE_HWS(bus_uart5_clk, "bus-uart5", apb1_hws, + 0x90c, BIT(5), 0); + +static SUNXI_CCU_GATE_HWS(bus_i2c0_clk, "bus-i2c0", apb1_hws, + 0x91c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_i2c1_clk, "bus-i2c1", apb1_hws, + 0x91c, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_i2c2_clk, "bus-i2c2", apb1_hws, + 0x91c, BIT(2), 0); +static SUNXI_CCU_GATE_HWS(bus_i2c3_clk, "bus-i2c3", apb1_hws, + 0x91c, BIT(3), 0); + +static const struct clk_parent_data spi_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + { .hw = &pll_audio1_div5_clk.common.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi0_clk, "spi0", spi_parents, 0x940, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(spi1_clk, "spi1", spi_parents, 0x944, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_spi0_clk, "bus-spi0", psi_ahb_hws, + 0x96c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_spi1_clk, "bus-spi1", psi_ahb_hws, + 0x96c, BIT(1), 0); + +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(emac_25M_clk, "emac-25M", pll_periph0_hws, + 0x970, BIT(31) | BIT(30), 24, 0); + +static SUNXI_CCU_GATE_HWS(bus_emac_clk, "bus-emac", psi_ahb_hws, + 0x97c, BIT(0), 0); + +static const struct clk_parent_data ir_tx_ledc_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, +}; +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ir_tx_clk, "ir-tx", ir_tx_ledc_parents, 0x9c0, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_ir_tx_clk, "bus-ir-tx", apb0_hws, + 0x9cc, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_gpadc_clk, "bus-gpadc", apb0_hws, + 0x9ec, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_ths_clk, "bus-ths", apb0_hws, + 0x9fc, BIT(0), 0); + +static const struct clk_hw *i2s_spdif_tx_parents[] = { + &pll_audio0_clk.hw, + &pll_audio0_4x_clk.common.hw, + &pll_audio1_div2_clk.common.hw, + &pll_audio1_div5_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s0_clk, "i2s0", i2s_spdif_tx_parents, 0xa10, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s1_clk, "i2s1", i2s_spdif_tx_parents, 0xa14, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_clk, "i2s2", i2s_spdif_tx_parents, 0xa18, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const struct clk_hw *i2s2_asrc_parents[] = { + &pll_audio0_4x_clk.common.hw, + &pll_periph0_clk.hw, + &pll_audio1_div2_clk.common.hw, + &pll_audio1_div5_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(i2s2_asrc_clk, "i2s2-asrc", i2s2_asrc_parents, 0xa1c, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_i2s0_clk, "bus-i2s0", apb0_hws, + 0xa20, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_i2s1_clk, "bus-i2s1", apb0_hws, + 0xa20, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_i2s2_clk, "bus-i2s2", apb0_hws, + 0xa20, BIT(2), 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_tx_clk, "spdif-tx", i2s_spdif_tx_parents, 0xa24, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const struct clk_hw *spdif_rx_parents[] = { + &pll_periph0_clk.hw, + &pll_audio1_div2_clk.common.hw, + &pll_audio1_div5_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(spdif_rx_clk, "spdif-rx", spdif_rx_parents, 0xa28, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_spdif_clk, "bus-spdif", apb0_hws, + 0xa2c, BIT(0), 0); + +static const struct clk_hw *dmic_codec_parents[] = { + &pll_audio0_clk.hw, + &pll_audio1_div2_clk.common.hw, + &pll_audio1_div5_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(dmic_clk, "dmic", dmic_codec_parents, 0xa40, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_dmic_clk, "bus-dmic", apb0_hws, + 0xa4c, BIT(0), 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_dac_clk, "audio-dac", dmic_codec_parents, 0xa50, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(audio_adc_clk, "audio-adc", dmic_codec_parents, 0xa54, + 0, 5, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_audio_clk, "bus-audio", apb0_hws, + 0xa5c, BIT(0), 0); + + +/* + * The first parent is a 48 MHz input clock divided by 4. That 48 MHz clock is + * a 2x multiplier from osc24M synchronized by pll-periph0, and is also used by + * the OHCI module. + */ +static const struct clk_parent_data usb_ohci_parents[] = { + { .hw = &pll_periph0_clk.hw }, + { .fw_name = "hosc" }, + { .fw_name = "losc" }, +}; +static const struct ccu_mux_fixed_prediv usb_ohci_predivs[] = { + { .index = 0, .div = 50 }, + { .index = 1, .div = 2 }, +}; + +static struct ccu_mux usb_ohci0_clk = { + .enable = BIT(31), + .mux = { + .shift = 24, + .width = 2, + .fixed_predivs = usb_ohci_predivs, + .n_predivs = ARRAY_SIZE(usb_ohci_predivs), + }, + .common = { + .reg = 0xa70, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("usb-ohci0", + usb_ohci_parents, + &ccu_mux_ops, + 0), + }, +}; + +static struct ccu_mux usb_ohci1_clk = { + .enable = BIT(31), + .mux = { + .shift = 24, + .width = 2, + .fixed_predivs = usb_ohci_predivs, + .n_predivs = ARRAY_SIZE(usb_ohci_predivs), + }, + .common = { + .reg = 0xa74, + .features = CCU_FEATURE_FIXED_PREDIV, + .hw.init = CLK_HW_INIT_PARENTS_DATA("usb-ohci1", + usb_ohci_parents, + &ccu_mux_ops, + 0), + }, +}; + +static SUNXI_CCU_GATE_HWS(bus_ohci0_clk, "bus-ohci0", psi_ahb_hws, + 0xa8c, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_ohci1_clk, "bus-ohci1", psi_ahb_hws, + 0xa8c, BIT(1), 0); +static SUNXI_CCU_GATE_HWS(bus_ehci0_clk, "bus-ehci0", psi_ahb_hws, + 0xa8c, BIT(4), 0); +static SUNXI_CCU_GATE_HWS(bus_ehci1_clk, "bus-ehci1", psi_ahb_hws, + 0xa8c, BIT(5), 0); +static SUNXI_CCU_GATE_HWS(bus_otg_clk, "bus-otg", psi_ahb_hws, + 0xa8c, BIT(8), 0); + +static SUNXI_CCU_GATE_HWS(bus_lradc_clk, "bus-lradc", apb0_hws, + 0xa9c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_dpss_top_clk, "bus-dpss-top", psi_ahb_hws, + 0xabc, BIT(0), 0); + +static SUNXI_CCU_GATE_DATA(hdmi_24M_clk, "hdmi-24M", osc24M, + 0xb04, BIT(31), 0); + +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(hdmi_cec_32k_clk, "hdmi-cec-32k", + pll_periph0_2x_hws, + 0xb10, BIT(30), 36621, 0); + +static const struct clk_parent_data hdmi_cec_parents[] = { + { .fw_name = "losc" }, + { .hw = &hdmi_cec_32k_clk.common.hw }, +}; +static SUNXI_CCU_MUX_DATA_WITH_GATE(hdmi_cec_clk, "hdmi-cec", hdmi_cec_parents, 0xb10, + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_hdmi_clk, "bus-hdmi", psi_ahb_hws, + 0xb1c, BIT(0), 0); + +static const struct clk_parent_data mipi_dsi_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_video0_2x_clk.hw }, + { .hw = &pll_video1_2x_clk.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(mipi_dsi_clk, "mipi-dsi", mipi_dsi_parents, 0xb24, + 0, 4, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_mipi_dsi_clk, "bus-mipi-dsi", psi_ahb_hws, + 0xb4c, BIT(0), 0); + +static const struct clk_hw *tcon_tve_parents[] = { + &pll_video0_clk.hw, + &pll_video0_4x_clk.common.hw, + &pll_video1_clk.hw, + &pll_video1_4x_clk.common.hw, + &pll_periph0_2x_clk.common.hw, + &pll_audio1_div2_clk.common.hw, +}; +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_lcd0_clk, "tcon-lcd0", tcon_tve_parents, 0xb60, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_tcon_lcd0_clk, "bus-tcon-lcd0", psi_ahb_hws, + 0xb7c, BIT(0), 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tcon_tv_clk, "tcon-tv", tcon_tve_parents, 0xb80, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + CLK_SET_RATE_PARENT); + +static SUNXI_CCU_GATE_HWS(bus_tcon_tv_clk, "bus-tcon-tv", psi_ahb_hws, + 0xb9c, BIT(0), 0); + +static SUNXI_CCU_MP_HW_WITH_MUX_GATE(tve_clk, "tve", tcon_tve_parents, 0xbb0, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_tve_top_clk, "bus-tve-top", psi_ahb_hws, + 0xbbc, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_tve_clk, "bus-tve", psi_ahb_hws, + 0xbbc, BIT(1), 0); + +static const struct clk_parent_data tvd_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_video0_clk.hw }, + { .hw = &pll_video1_clk.hw }, + { .hw = &pll_periph0_clk.hw }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(tvd_clk, "tvd", tvd_parents, 0xbc0, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_tvd_top_clk, "bus-tvd-top", psi_ahb_hws, + 0xbdc, BIT(0), 0); +static SUNXI_CCU_GATE_HWS(bus_tvd_clk, "bus-tvd", psi_ahb_hws, + 0xbdc, BIT(1), 0); + +static SUNXI_CCU_MP_DATA_WITH_MUX_GATE(ledc_clk, "ledc", ir_tx_ledc_parents, 0xbf0, + 0, 4, /* M */ + 8, 2, /* P */ + 24, 1, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_ledc_clk, "bus-ledc", psi_ahb_hws, + 0xbfc, BIT(0), 0); + +static const struct clk_hw *csi_top_parents[] = { + &pll_periph0_2x_clk.common.hw, + &pll_video0_2x_clk.hw, + &pll_video1_2x_clk.hw, +}; +static SUNXI_CCU_M_HW_WITH_MUX_GATE(csi_top_clk, "csi-top", csi_top_parents, 0xc04, + 0, 4, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static const struct clk_parent_data csi_mclk_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_video0_clk.hw }, + { .hw = &pll_video1_clk.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, + { .hw = &pll_audio1_div5_clk.common.hw }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, 0xc08, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_csi_clk, "bus-csi", psi_ahb_hws, + 0xc1c, BIT(0), 0); + +static const struct clk_parent_data tpadc_parents[] = { + { .fw_name = "hosc" }, + { .hw = &pll_audio0_clk.hw }, +}; +static SUNXI_CCU_MUX_DATA_WITH_GATE(tpadc_clk, "tpadc", tpadc_parents, 0xc50, + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_tpadc_clk, "bus-tpadc", apb0_hws, + 0xc5c, BIT(0), 0); + +static SUNXI_CCU_GATE_HWS(bus_tzma_clk, "bus-tzma", apb0_hws, + 0xc6c, BIT(0), 0); + +static const struct clk_parent_data dsp_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_periph0_2x_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX_GATE(dsp_clk, "dsp", dsp_parents, 0xc70, + 0, 5, /* M */ + 24, 3, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_GATE_HWS(bus_dsp_cfg_clk, "bus-dsp-cfg", psi_ahb_hws, + 0xc7c, BIT(1), 0); + +/* + * The RISC-V gate is not modelled - it is in a separate register (0xd04) + * and has a special key field. The clock is critical anyway. + */ +static const struct clk_parent_data riscv_parents[] = { + { .fw_name = "hosc" }, + { .fw_name = "losc" }, + { .fw_name = "iosc" }, + { .hw = &pll_periph0_800M_clk.common.hw }, + { .hw = &pll_periph0_clk.hw }, + { .hw = &pll_cpux_clk.common.hw }, + { .hw = &pll_audio1_div2_clk.common.hw }, +}; +static SUNXI_CCU_M_DATA_WITH_MUX(riscv_clk, "riscv", riscv_parents, 0xd00, + 0, 5, /* M */ + 24, 3, /* mux */ + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL); + +/* The riscv-axi clk must be divided by at least 2. */ +static struct clk_div_table riscv_axi_table[] = { + { .val = 1, .div = 2 }, + { .val = 2, .div = 3 }, + { .val = 3, .div = 4 }, + { /* Sentinel */ } +}; +static SUNXI_CCU_DIV_TABLE_HW(riscv_axi_clk, "riscv-axi", &riscv_clk.common.hw, + 0xd00, 8, 2, riscv_axi_table, 0); + +static SUNXI_CCU_GATE_HWS(bus_riscv_cfg_clk, "bus-riscv-cfg", psi_ahb_hws, + 0xd0c, BIT(0), CLK_IS_CRITICAL); + +static SUNXI_CCU_GATE_DATA(fanout_24M_clk, "fanout-24M", osc24M, + 0xf30, BIT(0), 0); +static SUNXI_CCU_GATE_DATA_WITH_PREDIV(fanout_12M_clk, "fanout-12M", osc24M, + 0xf30, BIT(1), 2, 0); +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_16M_clk, "fanout-16M", pll_periph0_2x_hws, + 0xf30, BIT(2), 75, 0); +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_25M_clk, "fanout-25M", pll_periph0_hws, + 0xf30, BIT(3), 24, 0); +static SUNXI_CCU_GATE_HWS_WITH_PREDIV(fanout_32k_clk, "fanout-32k", pll_periph0_2x_hws, + 0xf30, BIT(4), 36621, 0); + +/* This clock has a second divider that is not modelled and forced to 0. */ +#define SUN20I_D1_FANOUT_27M_REG 0xf34 +static const struct clk_hw *fanout_27M_parents[] = { + &pll_video0_clk.hw, + &pll_video1_clk.hw, +}; +static SUNXI_CCU_M_HW_WITH_MUX_GATE(fanout_27M_clk, "fanout-27M", fanout_27M_parents, 0xf34, + 0, 5, /* M */ + 24, 2, /* mux */ + BIT(31), /* gate */ + 0); + +static SUNXI_CCU_M_HWS_WITH_GATE(fanout_pclk_clk, "fanout-pclk", apb0_hws, 0xf38, + 0, 5, /* M */ + BIT(31), /* gate */ + 0); + +static const struct clk_hw *fanout_parents[] = { + &fanout_32k_clk.common.hw, + &fanout_12M_clk.common.hw, + &fanout_16M_clk.common.hw, + &fanout_24M_clk.common.hw, + &fanout_25M_clk.common.hw, + &fanout_27M_clk.common.hw, + &fanout_pclk_clk.common.hw, +}; +static SUNXI_CCU_MUX_HW_WITH_GATE(fanout0_clk, "fanout0", fanout_parents, 0xf3c, + 0, 3, /* mux */ + BIT(21), /* gate */ + 0); +static SUNXI_CCU_MUX_HW_WITH_GATE(fanout1_clk, "fanout1", fanout_parents, 0xf3c, + 3, 3, /* mux */ + BIT(22), /* gate */ + 0); +static SUNXI_CCU_MUX_HW_WITH_GATE(fanout2_clk, "fanout2", fanout_parents, 0xf3c, + 6, 3, /* mux */ + BIT(23), /* gate */ + 0); + +static struct ccu_common *sun20i_d1_ccu_clks[] = { + &pll_cpux_clk.common, + &pll_ddr0_clk.common, + &pll_periph0_4x_clk.common, + &pll_periph0_2x_clk.common, + &pll_periph0_800M_clk.common, + &pll_video0_4x_clk.common, + &pll_video1_4x_clk.common, + &pll_ve_clk.common, + &pll_audio0_4x_clk.common, + &pll_audio1_clk.common, + &pll_audio1_div2_clk.common, + &pll_audio1_div5_clk.common, + &cpux_clk.common, + &cpux_axi_clk.common, + &cpux_apb_clk.common, + &psi_ahb_clk.common, + &apb0_clk.common, + &apb1_clk.common, + &de_clk.common, + &bus_de_clk.common, + &di_clk.common, + &bus_di_clk.common, + &g2d_clk.common, + &bus_g2d_clk.common, + &ce_clk.common, + &bus_ce_clk.common, + &ve_clk.common, + &bus_ve_clk.common, + &bus_dma_clk.common, + &bus_msgbox0_clk.common, + &bus_msgbox1_clk.common, + &bus_msgbox2_clk.common, + &bus_spinlock_clk.common, + &bus_hstimer_clk.common, + &avs_clk.common, + &bus_dbg_clk.common, + &bus_pwm_clk.common, + &bus_iommu_clk.common, + &dram_clk.common, + &mbus_dma_clk.common, + &mbus_ve_clk.common, + &mbus_ce_clk.common, + &mbus_tvin_clk.common, + &mbus_csi_clk.common, + &mbus_g2d_clk.common, + &mbus_riscv_clk.common, + &bus_dram_clk.common, + &mmc0_clk.common, + &mmc1_clk.common, + &mmc2_clk.common, + &bus_mmc0_clk.common, + &bus_mmc1_clk.common, + &bus_mmc2_clk.common, + &bus_uart0_clk.common, + &bus_uart1_clk.common, + &bus_uart2_clk.common, + &bus_uart3_clk.common, + &bus_uart4_clk.common, + &bus_uart5_clk.common, + &bus_i2c0_clk.common, + &bus_i2c1_clk.common, + &bus_i2c2_clk.common, + &bus_i2c3_clk.common, + &spi0_clk.common, + &spi1_clk.common, + &bus_spi0_clk.common, + &bus_spi1_clk.common, + &emac_25M_clk.common, + &bus_emac_clk.common, + &ir_tx_clk.common, + &bus_ir_tx_clk.common, + &bus_gpadc_clk.common, + &bus_ths_clk.common, + &i2s0_clk.common, + &i2s1_clk.common, + &i2s2_clk.common, + &i2s2_asrc_clk.common, + &bus_i2s0_clk.common, + &bus_i2s1_clk.common, + &bus_i2s2_clk.common, + &spdif_tx_clk.common, + &spdif_rx_clk.common, + &bus_spdif_clk.common, + &dmic_clk.common, + &bus_dmic_clk.common, + &audio_dac_clk.common, + &audio_adc_clk.common, + &bus_audio_clk.common, + &usb_ohci0_clk.common, + &usb_ohci1_clk.common, + &bus_ohci0_clk.common, + &bus_ohci1_clk.common, + &bus_ehci0_clk.common, + &bus_ehci1_clk.common, + &bus_otg_clk.common, + &bus_lradc_clk.common, + &bus_dpss_top_clk.common, + &hdmi_24M_clk.common, + &hdmi_cec_32k_clk.common, + &hdmi_cec_clk.common, + &bus_hdmi_clk.common, + &mipi_dsi_clk.common, + &bus_mipi_dsi_clk.common, + &tcon_lcd0_clk.common, + &bus_tcon_lcd0_clk.common, + &tcon_tv_clk.common, + &bus_tcon_tv_clk.common, + &tve_clk.common, + &bus_tve_top_clk.common, + &bus_tve_clk.common, + &tvd_clk.common, + &bus_tvd_top_clk.common, + &bus_tvd_clk.common, + &ledc_clk.common, + &bus_ledc_clk.common, + &csi_top_clk.common, + &csi_mclk_clk.common, + &bus_csi_clk.common, + &tpadc_clk.common, + &bus_tpadc_clk.common, + &bus_tzma_clk.common, + &dsp_clk.common, + &bus_dsp_cfg_clk.common, + &riscv_clk.common, + &riscv_axi_clk.common, + &bus_riscv_cfg_clk.common, + &fanout_24M_clk.common, + &fanout_12M_clk.common, + &fanout_16M_clk.common, + &fanout_25M_clk.common, + &fanout_32k_clk.common, + &fanout_27M_clk.common, + &fanout_pclk_clk.common, + &fanout0_clk.common, + &fanout1_clk.common, + &fanout2_clk.common, +}; + +static struct clk_hw_onecell_data sun20i_d1_hw_clks = { + .num = CLK_NUMBER, + .hws = { + [CLK_PLL_CPUX] = &pll_cpux_clk.common.hw, + [CLK_PLL_DDR0] = &pll_ddr0_clk.common.hw, + [CLK_PLL_PERIPH0_4X] = &pll_periph0_4x_clk.common.hw, + [CLK_PLL_PERIPH0_2X] = &pll_periph0_2x_clk.common.hw, + [CLK_PLL_PERIPH0_800M] = &pll_periph0_800M_clk.common.hw, + [CLK_PLL_PERIPH0] = &pll_periph0_clk.hw, + [CLK_PLL_PERIPH0_DIV3] = &pll_periph0_div3_clk.hw, + [CLK_PLL_VIDEO0_4X] = &pll_video0_4x_clk.common.hw, + [CLK_PLL_VIDEO0_2X] = &pll_video0_2x_clk.hw, + [CLK_PLL_VIDEO0] = &pll_video0_clk.hw, + [CLK_PLL_VIDEO1_4X] = &pll_video1_4x_clk.common.hw, + [CLK_PLL_VIDEO1_2X] = &pll_video1_2x_clk.hw, + [CLK_PLL_VIDEO1] = &pll_video1_clk.hw, + [CLK_PLL_VE] = &pll_ve_clk.common.hw, + [CLK_PLL_AUDIO0_4X] = &pll_audio0_4x_clk.common.hw, + [CLK_PLL_AUDIO0_2X] = &pll_audio0_2x_clk.hw, + [CLK_PLL_AUDIO0] = &pll_audio0_clk.hw, + [CLK_PLL_AUDIO1] = &pll_audio1_clk.common.hw, + [CLK_PLL_AUDIO1_DIV2] = &pll_audio1_div2_clk.common.hw, + [CLK_PLL_AUDIO1_DIV5] = &pll_audio1_div5_clk.common.hw, + [CLK_CPUX] = &cpux_clk.common.hw, + [CLK_CPUX_AXI] = &cpux_axi_clk.common.hw, + [CLK_CPUX_APB] = &cpux_apb_clk.common.hw, + [CLK_PSI_AHB] = &psi_ahb_clk.common.hw, + [CLK_APB0] = &apb0_clk.common.hw, + [CLK_APB1] = &apb1_clk.common.hw, + [CLK_MBUS] = &mbus_clk.hw, + [CLK_DE] = &de_clk.common.hw, + [CLK_BUS_DE] = &bus_de_clk.common.hw, + [CLK_DI] = &di_clk.common.hw, + [CLK_BUS_DI] = &bus_di_clk.common.hw, + [CLK_G2D] = &g2d_clk.common.hw, + [CLK_BUS_G2D] = &bus_g2d_clk.common.hw, + [CLK_CE] = &ce_clk.common.hw, + [CLK_BUS_CE] = &bus_ce_clk.common.hw, + [CLK_VE] = &ve_clk.common.hw, + [CLK_BUS_VE] = &bus_ve_clk.common.hw, + [CLK_BUS_DMA] = &bus_dma_clk.common.hw, + [CLK_BUS_MSGBOX0] = &bus_msgbox0_clk.common.hw, + [CLK_BUS_MSGBOX1] = &bus_msgbox1_clk.common.hw, + [CLK_BUS_MSGBOX2] = &bus_msgbox2_clk.common.hw, + [CLK_BUS_SPINLOCK] = &bus_spinlock_clk.common.hw, + [CLK_BUS_HSTIMER] = &bus_hstimer_clk.common.hw, + [CLK_AVS] = &avs_clk.common.hw, + [CLK_BUS_DBG] = &bus_dbg_clk.common.hw, + [CLK_BUS_PWM] = &bus_pwm_clk.common.hw, + [CLK_BUS_IOMMU] = &bus_iommu_clk.common.hw, + [CLK_DRAM] = &dram_clk.common.hw, + [CLK_MBUS_DMA] = &mbus_dma_clk.common.hw, + [CLK_MBUS_VE] = &mbus_ve_clk.common.hw, + [CLK_MBUS_CE] = &mbus_ce_clk.common.hw, + [CLK_MBUS_TVIN] = &mbus_tvin_clk.common.hw, + [CLK_MBUS_CSI] = &mbus_csi_clk.common.hw, + [CLK_MBUS_G2D] = &mbus_g2d_clk.common.hw, + [CLK_MBUS_RISCV] = &mbus_riscv_clk.common.hw, + [CLK_BUS_DRAM] = &bus_dram_clk.common.hw, + [CLK_MMC0] = &mmc0_clk.common.hw, + [CLK_MMC1] = &mmc1_clk.common.hw, + [CLK_MMC2] = &mmc2_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_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_UART4] = &bus_uart4_clk.common.hw, + [CLK_BUS_UART5] = &bus_uart5_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_I2C3] = &bus_i2c3_clk.common.hw, + [CLK_SPI0] = &spi0_clk.common.hw, + [CLK_SPI1] = &spi1_clk.common.hw, + [CLK_BUS_SPI0] = &bus_spi0_clk.common.hw, + [CLK_BUS_SPI1] = &bus_spi1_clk.common.hw, + [CLK_EMAC_25M] = &emac_25M_clk.common.hw, + [CLK_BUS_EMAC] = &bus_emac_clk.common.hw, + [CLK_IR_TX] = &ir_tx_clk.common.hw, + [CLK_BUS_IR_TX] = &bus_ir_tx_clk.common.hw, + [CLK_BUS_GPADC] = &bus_gpadc_clk.common.hw, + [CLK_BUS_THS] = &bus_ths_clk.common.hw, + [CLK_I2S0] = &i2s0_clk.common.hw, + [CLK_I2S1] = &i2s1_clk.common.hw, + [CLK_I2S2] = &i2s2_clk.common.hw, + [CLK_I2S2_ASRC] = &i2s2_asrc_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_SPDIF_TX] = &spdif_tx_clk.common.hw, + [CLK_SPDIF_RX] = &spdif_rx_clk.common.hw, + [CLK_BUS_SPDIF] = &bus_spdif_clk.common.hw, + [CLK_DMIC] = &dmic_clk.common.hw, + [CLK_BUS_DMIC] = &bus_dmic_clk.common.hw, + [CLK_AUDIO_DAC] = &audio_dac_clk.common.hw, + [CLK_AUDIO_ADC] = &audio_adc_clk.common.hw, + [CLK_BUS_AUDIO] = &bus_audio_clk.common.hw, + [CLK_USB_OHCI0] = &usb_ohci0_clk.common.hw, + [CLK_USB_OHCI1] = &usb_ohci1_clk.common.hw, + [CLK_BUS_OHCI0] = &bus_ohci0_clk.common.hw, + [CLK_BUS_OHCI1] = &bus_ohci1_clk.common.hw, + [CLK_BUS_EHCI0] = &bus_ehci0_clk.common.hw, + [CLK_BUS_EHCI1] = &bus_ehci1_clk.common.hw, + [CLK_BUS_OTG] = &bus_otg_clk.common.hw, + [CLK_BUS_LRADC] = &bus_lradc_clk.common.hw, + [CLK_BUS_DPSS_TOP] = &bus_dpss_top_clk.common.hw, + [CLK_HDMI_24M] = &hdmi_24M_clk.common.hw, + [CLK_HDMI_CEC_32K] = &hdmi_cec_32k_clk.common.hw, + [CLK_HDMI_CEC] = &hdmi_cec_clk.common.hw, + [CLK_BUS_HDMI] = &bus_hdmi_clk.common.hw, + [CLK_MIPI_DSI] = &mipi_dsi_clk.common.hw, + [CLK_BUS_MIPI_DSI] = &bus_mipi_dsi_clk.common.hw, + [CLK_TCON_LCD0] = &tcon_lcd0_clk.common.hw, + [CLK_BUS_TCON_LCD0] = &bus_tcon_lcd0_clk.common.hw, + [CLK_TCON_TV] = &tcon_tv_clk.common.hw, + [CLK_BUS_TCON_TV] = &bus_tcon_tv_clk.common.hw, + [CLK_TVE] = &tve_clk.common.hw, + [CLK_BUS_TVE_TOP] = &bus_tve_top_clk.common.hw, + [CLK_BUS_TVE] = &bus_tve_clk.common.hw, + [CLK_TVD] = &tvd_clk.common.hw, + [CLK_BUS_TVD_TOP] = &bus_tvd_top_clk.common.hw, + [CLK_BUS_TVD] = &bus_tvd_clk.common.hw, + [CLK_LEDC] = &ledc_clk.common.hw, + [CLK_BUS_LEDC] = &bus_ledc_clk.common.hw, + [CLK_CSI_TOP] = &csi_top_clk.common.hw, + [CLK_CSI_MCLK] = &csi_mclk_clk.common.hw, + [CLK_BUS_CSI] = &bus_csi_clk.common.hw, + [CLK_TPADC] = &tpadc_clk.common.hw, + [CLK_BUS_TPADC] = &bus_tpadc_clk.common.hw, + [CLK_BUS_TZMA] = &bus_tzma_clk.common.hw, + [CLK_DSP] = &dsp_clk.common.hw, + [CLK_BUS_DSP_CFG] = &bus_dsp_cfg_clk.common.hw, + [CLK_RISCV] = &riscv_clk.common.hw, + [CLK_RISCV_AXI] = &riscv_axi_clk.common.hw, + [CLK_BUS_RISCV_CFG] = &bus_riscv_cfg_clk.common.hw, + [CLK_FANOUT_24M] = &fanout_24M_clk.common.hw, + [CLK_FANOUT_12M] = &fanout_12M_clk.common.hw, + [CLK_FANOUT_16M] = &fanout_16M_clk.common.hw, + [CLK_FANOUT_25M] = &fanout_25M_clk.common.hw, + [CLK_FANOUT_32K] = &fanout_32k_clk.common.hw, + [CLK_FANOUT_27M] = &fanout_27M_clk.common.hw, + [CLK_FANOUT_PCLK] = &fanout_pclk_clk.common.hw, + [CLK_FANOUT0] = &fanout0_clk.common.hw, + [CLK_FANOUT1] = &fanout1_clk.common.hw, + [CLK_FANOUT2] = &fanout2_clk.common.hw, + }, +}; + +static struct ccu_reset_map sun20i_d1_ccu_resets[] = { + [RST_MBUS] = { 0x540, BIT(30) }, + [RST_BUS_DE] = { 0x60c, BIT(16) }, + [RST_BUS_DI] = { 0x62c, BIT(16) }, + [RST_BUS_G2D] = { 0x63c, BIT(16) }, + [RST_BUS_CE] = { 0x68c, BIT(16) }, + [RST_BUS_VE] = { 0x69c, BIT(16) }, + [RST_BUS_DMA] = { 0x70c, BIT(16) }, + [RST_BUS_MSGBOX0] = { 0x71c, BIT(16) }, + [RST_BUS_MSGBOX1] = { 0x71c, BIT(17) }, + [RST_BUS_MSGBOX2] = { 0x71c, BIT(18) }, + [RST_BUS_SPINLOCK] = { 0x72c, BIT(16) }, + [RST_BUS_HSTIMER] = { 0x73c, BIT(16) }, + [RST_BUS_DBG] = { 0x78c, BIT(16) }, + [RST_BUS_PWM] = { 0x7ac, BIT(16) }, + [RST_BUS_DRAM] = { 0x80c, BIT(16) }, + [RST_BUS_MMC0] = { 0x84c, BIT(16) }, + [RST_BUS_MMC1] = { 0x84c, BIT(17) }, + [RST_BUS_MMC2] = { 0x84c, BIT(18) }, + [RST_BUS_UART0] = { 0x90c, BIT(16) }, + [RST_BUS_UART1] = { 0x90c, BIT(17) }, + [RST_BUS_UART2] = { 0x90c, BIT(18) }, + [RST_BUS_UART3] = { 0x90c, BIT(19) }, + [RST_BUS_UART4] = { 0x90c, BIT(20) }, + [RST_BUS_UART5] = { 0x90c, BIT(21) }, + [RST_BUS_I2C0] = { 0x91c, BIT(16) }, + [RST_BUS_I2C1] = { 0x91c, BIT(17) }, + [RST_BUS_I2C2] = { 0x91c, BIT(18) }, + [RST_BUS_I2C3] = { 0x91c, BIT(19) }, + [RST_BUS_SPI0] = { 0x96c, BIT(16) }, + [RST_BUS_SPI1] = { 0x96c, BIT(17) }, + [RST_BUS_EMAC] = { 0x97c, BIT(16) }, + [RST_BUS_IR_TX] = { 0x9cc, BIT(16) }, + [RST_BUS_GPADC] = { 0x9ec, BIT(16) }, + [RST_BUS_THS] = { 0x9fc, BIT(16) }, + [RST_BUS_I2S0] = { 0xa20, BIT(16) }, + [RST_BUS_I2S1] = { 0xa20, BIT(17) }, + [RST_BUS_I2S2] = { 0xa20, BIT(18) }, + [RST_BUS_SPDIF] = { 0xa2c, BIT(16) }, + [RST_BUS_DMIC] = { 0xa4c, BIT(16) }, + [RST_BUS_AUDIO] = { 0xa5c, BIT(16) }, + [RST_USB_PHY0] = { 0xa70, BIT(30) }, + [RST_USB_PHY1] = { 0xa74, BIT(30) }, + [RST_BUS_OHCI0] = { 0xa8c, BIT(16) }, + [RST_BUS_OHCI1] = { 0xa8c, BIT(17) }, + [RST_BUS_EHCI0] = { 0xa8c, BIT(20) }, + [RST_BUS_EHCI1] = { 0xa8c, BIT(21) }, + [RST_BUS_OTG] = { 0xa8c, BIT(24) }, + [RST_BUS_LRADC] = { 0xa9c, BIT(16) }, + [RST_BUS_DPSS_TOP] = { 0xabc, BIT(16) }, + [RST_BUS_HDMI_MAIN] = { 0xb1c, BIT(16) }, + [RST_BUS_HDMI_SUB] = { 0xb1c, BIT(17) }, + [RST_BUS_MIPI_DSI] = { 0xb4c, BIT(16) }, + [RST_BUS_TCON_LCD0] = { 0xb7c, BIT(16) }, + [RST_BUS_TCON_TV] = { 0xb9c, BIT(16) }, + [RST_BUS_LVDS0] = { 0xbac, BIT(16) }, + [RST_BUS_TVE_TOP] = { 0xbbc, BIT(16) }, + [RST_BUS_TVE] = { 0xbbc, BIT(17) }, + [RST_BUS_TVD_TOP] = { 0xbdc, BIT(16) }, + [RST_BUS_TVD] = { 0xbdc, BIT(17) }, + [RST_BUS_LEDC] = { 0xbfc, BIT(16) }, + [RST_BUS_CSI] = { 0xc1c, BIT(16) }, + [RST_BUS_TPADC] = { 0xc5c, BIT(16) }, + [RST_DSP] = { 0xc7c, BIT(16) }, + [RST_BUS_DSP_CFG] = { 0xc7c, BIT(17) }, + [RST_BUS_DSP_DBG] = { 0xc7c, BIT(18) }, + [RST_BUS_RISCV_CFG] = { 0xd0c, BIT(16) }, +}; + +static const struct sunxi_ccu_desc sun20i_d1_ccu_desc = { + .ccu_clks = sun20i_d1_ccu_clks, + .num_ccu_clks = ARRAY_SIZE(sun20i_d1_ccu_clks), + + .hw_clks = &sun20i_d1_hw_clks, + + .resets = sun20i_d1_ccu_resets, + .num_resets = ARRAY_SIZE(sun20i_d1_ccu_resets), +}; + +static const u32 pll_regs[] = { + SUN20I_D1_PLL_CPUX_REG, + SUN20I_D1_PLL_DDR0_REG, + SUN20I_D1_PLL_PERIPH0_REG, + SUN20I_D1_PLL_VIDEO0_REG, + SUN20I_D1_PLL_VIDEO1_REG, + SUN20I_D1_PLL_VE_REG, + SUN20I_D1_PLL_AUDIO0_REG, + SUN20I_D1_PLL_AUDIO1_REG, +}; + +static const u32 pll_video_regs[] = { + SUN20I_D1_PLL_VIDEO0_REG, + SUN20I_D1_PLL_VIDEO1_REG, +}; + +static struct ccu_mux_nb sun20i_d1_riscv_nb = { + .common = &riscv_clk.common, + .cm = &riscv_clk.mux, + .delay_us = 1, + .bypass_index = 4, /* index of pll-periph0 */ +}; + +static int sun20i_d1_ccu_probe(struct platform_device *pdev) +{ + void __iomem *reg; + u32 val; + int i, ret; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); + + /* Enable the enable, LDO, and lock bits on all PLLs. */ + for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { + val = readl(reg + pll_regs[i]); + val |= BIT(31) | BIT(30) | BIT(29); + writel(val, reg + pll_regs[i]); + } + + /* Force PLL_CPUX factor M to 0. */ + val = readl(reg + SUN20I_D1_PLL_CPUX_REG); + val &= ~GENMASK(1, 0); + writel(val, reg + SUN20I_D1_PLL_CPUX_REG); + + /* + * Force the output divider of video PLLs to 0. + * + * See the comment before pll-video0 definition for the reason. + */ + for (i = 0; i < ARRAY_SIZE(pll_video_regs); i++) { + val = readl(reg + pll_video_regs[i]); + val &= ~BIT(0); + writel(val, reg + pll_video_regs[i]); + } + + /* Enforce m1 = 0, m0 = 0 for PLL_AUDIO0 */ + val = readl(reg + SUN20I_D1_PLL_AUDIO0_REG); + val &= ~BIT(1) | BIT(0); + writel(val, reg + SUN20I_D1_PLL_AUDIO0_REG); + + /* Force fanout-27M factor N to 0. */ + val = readl(reg + SUN20I_D1_FANOUT_27M_REG); + val &= ~GENMASK(9, 8); + writel(val, reg + SUN20I_D1_FANOUT_27M_REG); + + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun20i_d1_ccu_desc); + if (ret) + return ret; + + /* Reparent CPU during PLL CPUX rate changes */ + ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, + &sun20i_d1_riscv_nb); + + return 0; +} + +static const struct of_device_id sun20i_d1_ccu_ids[] = { + { .compatible = "allwinner,sun20i-d1-ccu" }, + { } +}; + +static struct platform_driver sun20i_d1_ccu_driver = { + .probe = sun20i_d1_ccu_probe, + .driver = { + .name = "sun20i-d1-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun20i_d1_ccu_ids, + }, +}; +module_platform_driver(sun20i_d1_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun20i-d1.h b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h new file mode 100644 index 000000000000..e303176f0d4e --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu-sun20i-d1.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2020 frank@allwinnertech.com + * Copyright (C) 2021 Samuel Holland <samuel@sholland.org> + */ + +#ifndef _CCU_SUN20I_D1_H_ +#define _CCU_SUN20I_D1_H_ + +#include <dt-bindings/clock/sun20i-d1-ccu.h> +#include <dt-bindings/reset/sun20i-d1-ccu.h> + +#define CLK_NUMBER (CLK_FANOUT2 + 1) + +#endif /* _CCU_SUN20I_D1_H_ */ diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index bd9a8782fec3..c19828f1aa0f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -7,7 +7,9 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -1425,18 +1427,19 @@ static const struct sunxi_ccu_desc sun7i_a20_ccu_desc = { .num_resets = ARRAY_SIZE(sunxi_a10_a20_ccu_resets), }; -static void __init sun4i_ccu_init(struct device_node *node, - const struct sunxi_ccu_desc *desc) +static int sun4i_a10_ccu_probe(struct platform_device *pdev) { + const struct sunxi_ccu_desc *desc; void __iomem *reg; u32 val; - 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; - } + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); val = readl(reg + SUN4I_PLL_AUDIO_REG); @@ -1464,19 +1467,30 @@ static void __init sun4i_ccu_init(struct device_node *node, val &= ~GENMASK(7, 6); writel(val | (2 << 6), reg + SUN4I_AHB_REG); - of_sunxi_ccu_probe(node, reg, desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, desc); } -static void __init sun4i_a10_ccu_setup(struct device_node *node) -{ - sun4i_ccu_init(node, &sun4i_a10_ccu_desc); -} -CLK_OF_DECLARE(sun4i_a10_ccu, "allwinner,sun4i-a10-ccu", - sun4i_a10_ccu_setup); +static const struct of_device_id sun4i_a10_ccu_ids[] = { + { + .compatible = "allwinner,sun4i-a10-ccu", + .data = &sun4i_a10_ccu_desc, + }, + { + .compatible = "allwinner,sun7i-a20-ccu", + .data = &sun7i_a20_ccu_desc, + }, + { } +}; -static void __init sun7i_a20_ccu_setup(struct device_node *node) -{ - sun4i_ccu_init(node, &sun7i_a20_ccu_desc); -} -CLK_OF_DECLARE(sun7i_a20_ccu, "allwinner,sun7i-a20-ccu", - sun7i_a20_ccu_setup); +static struct platform_driver sun4i_a10_ccu_driver = { + .probe = sun4i_a10_ccu_probe, + .driver = { + .name = "sun4i-a10-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun4i_a10_ccu_ids, + }, +}; +module_platform_driver(sun4i_a10_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c index 804729e0a208..fddd6c877cec 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100-r.c @@ -5,7 +5,6 @@ #include <linux/clk-provider.h> #include <linux/module.h> -#include <linux/of_address.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -213,3 +212,6 @@ static struct platform_driver sun50i_a100_r_ccu_driver = { }, }; module_platform_driver(sun50i_a100_r_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c index 1d475d5a3d91..5f93b5526e13 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a100.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a100.c @@ -6,7 +6,6 @@ #include <linux/clk-provider.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_address.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -1275,3 +1274,6 @@ static struct platform_driver sun50i_a100_ccu_driver = { }, }; module_platform_driver(sun50i_a100_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c index a8c5a92b7d0c..41519185600a 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-a64.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-a64.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -980,4 +980,7 @@ static struct platform_driver sun50i_a64_ccu_driver = { .of_match_table = sun50i_a64_ccu_ids, }, }; -builtin_platform_driver(sun50i_a64_ccu_driver); +module_platform_driver(sun50i_a64_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c index f30d7eb5424d..712e103382d8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6-r.c @@ -4,7 +4,8 @@ */ #include <linux/clk-provider.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -221,30 +222,43 @@ static const struct sunxi_ccu_desc sun50i_h616_r_ccu_desc = { .num_resets = ARRAY_SIZE(sun50i_h616_r_ccu_resets), }; -static void __init sunxi_r_ccu_init(struct device_node *node, - const struct sunxi_ccu_desc *desc) +static int sun50i_h6_r_ccu_probe(struct platform_device *pdev) { + 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("%pOF: Could not map the clock registers\n", node); - return; - } + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; - of_sunxi_ccu_probe(node, reg, desc); -} + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); -static void __init sun50i_h6_r_ccu_setup(struct device_node *node) -{ - sunxi_r_ccu_init(node, &sun50i_h6_r_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, desc); } -CLK_OF_DECLARE(sun50i_h6_r_ccu, "allwinner,sun50i-h6-r-ccu", - sun50i_h6_r_ccu_setup); -static void __init sun50i_h616_r_ccu_setup(struct device_node *node) -{ - sunxi_r_ccu_init(node, &sun50i_h616_r_ccu_desc); -} -CLK_OF_DECLARE(sun50i_h616_r_ccu, "allwinner,sun50i-h616-r-ccu", - sun50i_h616_r_ccu_setup); +static const struct of_device_id sun50i_h6_r_ccu_ids[] = { + { + .compatible = "allwinner,sun50i-h6-r-ccu", + .data = &sun50i_h6_r_ccu_desc, + }, + { + .compatible = "allwinner,sun50i-h616-r-ccu", + .data = &sun50i_h616_r_ccu_desc, + }, + { } +}; + +static struct platform_driver sun50i_h6_r_ccu_driver = { + .probe = sun50i_h6_r_ccu_probe, + .driver = { + .name = "sun50i-h6-r-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun50i_h6_r_ccu_ids, + }, +}; +module_platform_driver(sun50i_h6_r_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c index e5672c10d065..1a5e418923f6 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h6.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h6.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -1254,4 +1254,7 @@ static struct platform_driver sun50i_h6_ccu_driver = { .of_match_table = sun50i_h6_ccu_ids, }, }; -builtin_platform_driver(sun50i_h6_ccu_driver); +module_platform_driver(sun50i_h6_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c index 22eb18079a15..49a2474cf314 100644 --- a/drivers/clk/sunxi-ng/ccu-sun50i-h616.c +++ b/drivers/clk/sunxi-ng/ccu-sun50i-h616.c @@ -7,7 +7,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -1082,17 +1082,15 @@ static const u32 usb2_clk_regs[] = { SUN50I_H616_USB3_CLK_REG, }; -static void __init sun50i_h616_ccu_setup(struct device_node *node) +static int sun50i_h616_ccu_probe(struct platform_device *pdev) { void __iomem *reg; u32 val; int i; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map clock registers\n", node); - return; - } + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Enable the lock bits and the output enable bits on all PLLs */ for (i = 0; i < ARRAY_SIZE(pll_regs); i++) { @@ -1141,8 +1139,23 @@ static void __init sun50i_h616_ccu_setup(struct device_node *node) val |= BIT(24); writel(val, reg + SUN50I_H616_HDMI_CEC_CLK_REG); - of_sunxi_ccu_probe(node, reg, &sun50i_h616_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun50i_h616_ccu_desc); } -CLK_OF_DECLARE(sun50i_h616_ccu, "allwinner,sun50i-h616-ccu", - sun50i_h616_ccu_setup); +static const struct of_device_id sun50i_h616_ccu_ids[] = { + { .compatible = "allwinner,sun50i-h616-ccu" }, + { } +}; + +static struct platform_driver sun50i_h616_ccu_driver = { + .probe = sun50i_h616_ccu_probe, + .driver = { + .name = "sun50i-h616-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun50i_h616_ccu_ids, + }, +}; +module_platform_driver(sun50i_h616_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 3df5c0b41580..0762deffb33c 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -9,7 +9,8 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -1226,16 +1227,15 @@ static struct ccu_mux_nb sun6i_a31_cpu_nb = { .bypass_index = 1, /* index of 24 MHz oscillator */ }; -static void __init sun6i_a31_ccu_setup(struct device_node *node) +static int sun6i_a31_ccu_probe(struct platform_device *pdev) { void __iomem *reg; + int ret; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN6I_A31_PLL_AUDIO_REG); @@ -1257,10 +1257,30 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node) val |= 0x3 << 12; writel(val, reg + SUN6I_A31_AHB1_REG); - of_sunxi_ccu_probe(node, reg, &sun6i_a31_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun6i_a31_ccu_desc); + if (ret) + return ret; ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk, &sun6i_a31_cpu_nb); + + return 0; } -CLK_OF_DECLARE(sun6i_a31_ccu, "allwinner,sun6i-a31-ccu", - sun6i_a31_ccu_setup); + +static const struct of_device_id sun6i_a31_ccu_ids[] = { + { .compatible = "allwinner,sun6i-a31-ccu" }, + { } +}; + +static struct platform_driver sun6i_a31_ccu_driver = { + .probe = sun6i_a31_ccu_probe, + .driver = { + .name = "sun6i-a31-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun6i_a31_ccu_ids, + }, +}; +module_platform_driver(sun6i_a31_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index 577bb235d658..e80cc3864e44 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -5,7 +5,8 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -724,16 +725,14 @@ static const struct sunxi_ccu_desc sun8i_a23_ccu_desc = { .num_resets = ARRAY_SIZE(sun8i_a23_ccu_resets), }; -static void __init sun8i_a23_ccu_setup(struct device_node *node) +static int sun8i_a23_ccu_probe(struct platform_device *pdev) { void __iomem *reg; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_A23_PLL_AUDIO_REG); @@ -745,7 +744,23 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node) val &= ~BIT(16); writel(val, reg + SUN8I_A23_PLL_MIPI_REG); - of_sunxi_ccu_probe(node, reg, &sun8i_a23_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a23_ccu_desc); } -CLK_OF_DECLARE(sun8i_a23_ccu, "allwinner,sun8i-a23-ccu", - sun8i_a23_ccu_setup); + +static const struct of_device_id sun8i_a23_ccu_ids[] = { + { .compatible = "allwinner,sun8i-a23-ccu" }, + { } +}; + +static struct platform_driver sun8i_a23_ccu_driver = { + .probe = sun8i_a23_ccu_probe, + .driver = { + .name = "sun8i-a23-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun8i_a23_ccu_ids, + }, +}; +module_platform_driver(sun8i_a23_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c index 8f65cd03f5ac..d12878a1ba9e 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a33.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a33.c @@ -5,7 +5,8 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -784,16 +785,15 @@ static struct ccu_mux_nb sun8i_a33_cpu_nb = { .bypass_index = 1, /* index of 24 MHz oscillator */ }; -static void __init sun8i_a33_ccu_setup(struct device_node *node) +static int sun8i_a33_ccu_probe(struct platform_device *pdev) { void __iomem *reg; + int ret; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_A33_PLL_AUDIO_REG); @@ -805,7 +805,9 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node) val &= ~BIT(16); writel(val, reg + SUN8I_A33_PLL_MIPI_REG); - of_sunxi_ccu_probe(node, reg, &sun8i_a33_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &sun8i_a33_ccu_desc); + if (ret) + return ret; /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&sun8i_a33_pll_cpu_nb); @@ -813,6 +815,24 @@ static void __init sun8i_a33_ccu_setup(struct device_node *node) /* Reparent CPU during PLL CPU rate changes */ ccu_mux_notifier_register(pll_cpux_clk.common.hw.clk, &sun8i_a33_cpu_nb); + + return 0; } -CLK_OF_DECLARE(sun8i_a33_ccu, "allwinner,sun8i-a33-ccu", - sun8i_a33_ccu_setup); + +static const struct of_device_id sun8i_a33_ccu_ids[] = { + { .compatible = "allwinner,sun8i-a33-ccu" }, + { } +}; + +static struct platform_driver sun8i_a33_ccu_driver = { + .probe = sun8i_a33_ccu_probe, + .driver = { + .name = "sun8i-a33-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun8i_a33_ccu_ids, + }, +}; +module_platform_driver(sun8i_a33_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index 3c310aea8cfa..76cbd9e9e89f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -920,4 +920,7 @@ static struct platform_driver sun8i_a83t_ccu_driver = { .of_match_table = sun8i_a83t_ccu_ids, }, }; -builtin_platform_driver(sun8i_a83t_ccu_driver); +module_platform_driver(sun8i_a83t_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 573b5051d305..e7e3ddf4a227 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -5,8 +5,8 @@ #include <linux/clk.h> #include <linux/clk-provider.h> -#include <linux/of_address.h> -#include <linux/of_platform.h> +#include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/reset.h> @@ -394,4 +394,7 @@ static struct platform_driver sunxi_de2_clk_driver = { .of_match_table = sunxi_de2_clk_ids, }, }; -builtin_platform_driver(sunxi_de2_clk_driver); +module_platform_driver(sunxi_de2_clk_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index d2fc2903787d..e058cf691aea 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -5,7 +5,9 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -1137,24 +1139,29 @@ static struct ccu_mux_nb sun8i_h3_cpu_nb = { .bypass_index = 1, /* index of 24 MHz oscillator */ }; -static void __init sunxi_h3_h5_ccu_init(struct device_node *node, - const struct sunxi_ccu_desc *desc) +static int sun8i_h3_ccu_probe(struct platform_device *pdev) { + const struct sunxi_ccu_desc *desc; void __iomem *reg; + int ret; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_H3_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); - of_sunxi_ccu_probe(node, reg, desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, desc); + if (ret) + return ret; /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&sun8i_h3_pll_cpu_nb); @@ -1162,18 +1169,31 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node, /* Reparent CPU during PLL CPU rate changes */ 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); + return 0; } -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); +static const struct of_device_id sun8i_h3_ccu_ids[] = { + { + .compatible = "allwinner,sun8i-h3-ccu", + .data = &sun8i_h3_ccu_desc, + }, + { + .compatible = "allwinner,sun50i-h5-ccu", + .data = &sun50i_h5_ccu_desc, + }, + { } +}; + +static struct platform_driver sun8i_h3_ccu_driver = { + .probe = sun8i_h3_ccu_probe, + .driver = { + .name = "sun8i-h3-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun8i_h3_ccu_ids, + }, +}; +module_platform_driver(sun8i_h3_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r.c b/drivers/clk/sunxi-ng/ccu-sun8i-r.c index 9e754d1f754a..5b7fab832a52 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r.c @@ -4,7 +4,8 @@ */ #include <linux/clk-provider.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/of_device.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -254,37 +255,47 @@ static const struct sunxi_ccu_desc sun50i_a64_r_ccu_desc = { .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) +static int sun8i_r_ccu_probe(struct platform_device *pdev) { + 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("%pOF: Could not map the clock registers\n", node); - return; - } + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; - of_sunxi_ccu_probe(node, reg, desc); -} + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); -static void __init sun8i_a83t_r_ccu_setup(struct device_node *node) -{ - sunxi_r_ccu_init(node, &sun8i_a83t_r_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, desc); } -CLK_OF_DECLARE(sun8i_a83t_r_ccu, "allwinner,sun8i-a83t-r-ccu", - sun8i_a83t_r_ccu_setup); -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 const struct of_device_id sun8i_r_ccu_ids[] = { + { + .compatible = "allwinner,sun8i-a83t-r-ccu", + .data = &sun8i_a83t_r_ccu_desc, + }, + { + .compatible = "allwinner,sun8i-h3-r-ccu", + .data = &sun8i_h3_r_ccu_desc, + }, + { + .compatible = "allwinner,sun50i-a64-r-ccu", + .data = &sun50i_a64_r_ccu_desc, + }, + { } +}; -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); +static struct platform_driver sun8i_r_ccu_driver = { + .probe = sun8i_r_ccu_probe, + .driver = { + .name = "sun8i-r-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun8i_r_ccu_ids, + }, +}; +module_platform_driver(sun8i_r_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c index 8bb18d9add05..31eca0d3bc1e 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-r40.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-r40.c @@ -5,6 +5,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -1371,4 +1372,7 @@ static struct platform_driver sun8i_r40_ccu_driver = { .of_match_table = sun8i_r40_ccu_ids, }, }; -builtin_platform_driver(sun8i_r40_ccu_driver); +module_platform_driver(sun8i_r40_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c index ce150f83ab54..87f87d6ea3ad 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-v3s.c @@ -8,7 +8,9 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -805,38 +807,49 @@ static const struct sunxi_ccu_desc sun8i_v3_ccu_desc = { .num_resets = ARRAY_SIZE(sun8i_v3_ccu_resets), }; -static void __init sun8i_v3_v3s_ccu_init(struct device_node *node, - const struct sunxi_ccu_desc *ccu_desc) +static int sun8i_v3s_ccu_probe(struct platform_device *pdev) { + const struct sunxi_ccu_desc *desc; void __iomem *reg; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + desc = of_device_get_match_data(&pdev->dev); + if (!desc) + return -EINVAL; + + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_V3S_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); writel(val, reg + SUN8I_V3S_PLL_AUDIO_REG); - of_sunxi_ccu_probe(node, reg, ccu_desc); -} - -static void __init sun8i_v3s_ccu_setup(struct device_node *node) -{ - sun8i_v3_v3s_ccu_init(node, &sun8i_v3s_ccu_desc); + return devm_sunxi_ccu_probe(&pdev->dev, reg, desc); } -static void __init sun8i_v3_ccu_setup(struct device_node *node) -{ - sun8i_v3_v3s_ccu_init(node, &sun8i_v3_ccu_desc); -} +static const struct of_device_id sun8i_v3s_ccu_ids[] = { + { + .compatible = "allwinner,sun8i-v3-ccu", + .data = &sun8i_v3_ccu_desc, + }, + { + .compatible = "allwinner,sun8i-v3s-ccu", + .data = &sun8i_v3s_ccu_desc, + }, + { } +}; -CLK_OF_DECLARE(sun8i_v3s_ccu, "allwinner,sun8i-v3s-ccu", - sun8i_v3s_ccu_setup); +static struct platform_driver sun8i_v3s_ccu_driver = { + .probe = sun8i_v3s_ccu_probe, + .driver = { + .name = "sun8i-v3s-ccu", + .suppress_bind_attrs = true, + .of_match_table = sun8i_v3s_ccu_ids, + }, +}; +module_platform_driver(sun8i_v3s_ccu_driver); -CLK_OF_DECLARE(sun8i_v3_ccu, "allwinner,sun8i-v3-ccu", - sun8i_v3_ccu_setup); +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c index 3cde2610f467..f2fe0e1cc3c0 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-de.c @@ -5,7 +5,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include <linux/reset.h> @@ -270,4 +270,7 @@ static struct platform_driver sun9i_a80_de_clk_driver = { .of_match_table = sun9i_a80_de_clk_ids, }, }; -builtin_platform_driver(sun9i_a80_de_clk_driver); +module_platform_driver(sun9i_a80_de_clk_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c index 0740e8978ae8..575ae4ccc65f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80-usb.c @@ -5,7 +5,7 @@ #include <linux/clk.h> #include <linux/clk-provider.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -138,4 +138,7 @@ static struct platform_driver sun9i_a80_usb_clk_driver = { .of_match_table = sun9i_a80_usb_clk_ids, }, }; -builtin_platform_driver(sun9i_a80_usb_clk_driver); +module_platform_driver(sun9i_a80_usb_clk_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c index d416af29e0d3..730fd8e28014 100644 --- a/drivers/clk/sunxi-ng/ccu-sun9i-a80.c +++ b/drivers/clk/sunxi-ng/ccu-sun9i-a80.c @@ -5,7 +5,7 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> #include <linux/platform_device.h> #include "ccu_common.h" @@ -1245,4 +1245,7 @@ static struct platform_driver sun9i_a80_ccu_driver = { .of_match_table = sun9i_a80_ccu_ids, }, }; -builtin_platform_driver(sun9i_a80_ccu_driver); +module_platform_driver(sun9i_a80_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c index 61ad7ee91c11..ed097c4f780f 100644 --- a/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c +++ b/drivers/clk/sunxi-ng/ccu-suniv-f1c100s.c @@ -6,7 +6,8 @@ #include <linux/clk-provider.h> #include <linux/io.h> -#include <linux/of_address.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include "ccu_common.h" #include "ccu_reset.h" @@ -522,23 +523,24 @@ static struct ccu_mux_nb suniv_cpu_nb = { .bypass_index = 1, /* index of 24 MHz oscillator */ }; -static void __init suniv_f1c100s_ccu_setup(struct device_node *node) +static int suniv_f1c100s_ccu_probe(struct platform_device *pdev) { void __iomem *reg; + int ret; u32 val; - reg = of_io_request_and_map(node, 0, of_node_full_name(node)); - if (IS_ERR(reg)) { - pr_err("%pOF: Could not map the clock registers\n", node); - return; - } + reg = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(reg)) + return PTR_ERR(reg); /* Force the PLL-Audio-1x divider to 4 */ val = readl(reg + SUNIV_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); writel(val | (3 << 16), reg + SUNIV_PLL_AUDIO_REG); - of_sunxi_ccu_probe(node, reg, &suniv_ccu_desc); + ret = devm_sunxi_ccu_probe(&pdev->dev, reg, &suniv_ccu_desc); + if (ret) + return ret; /* Gate then ungate PLL CPU after any rate changes */ ccu_pll_notifier_register(&suniv_pll_cpu_nb); @@ -546,6 +548,24 @@ static void __init suniv_f1c100s_ccu_setup(struct device_node *node) /* Reparent CPU during PLL CPU rate changes */ ccu_mux_notifier_register(pll_cpu_clk.common.hw.clk, &suniv_cpu_nb); + + return 0; } -CLK_OF_DECLARE(suniv_f1c100s_ccu, "allwinner,suniv-f1c100s-ccu", - suniv_f1c100s_ccu_setup); + +static const struct of_device_id suniv_f1c100s_ccu_ids[] = { + { .compatible = "allwinner,suniv-f1c100s-ccu" }, + { } +}; + +static struct platform_driver suniv_f1c100s_ccu_driver = { + .probe = suniv_f1c100s_ccu_probe, + .driver = { + .name = "suniv-f1c100s-ccu", + .suppress_bind_attrs = true, + .of_match_table = suniv_f1c100s_ccu_ids, + }, +}; +module_platform_driver(suniv_f1c100s_ccu_driver); + +MODULE_IMPORT_NS(SUNXI_CCU); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu_common.c b/drivers/clk/sunxi-ng/ccu_common.c index 31af8b6b5286..8d28a7a079d0 100644 --- a/drivers/clk/sunxi-ng/ccu_common.c +++ b/drivers/clk/sunxi-ng/ccu_common.c @@ -9,6 +9,7 @@ #include <linux/clk-provider.h> #include <linux/device.h> #include <linux/iopoll.h> +#include <linux/module.h> #include <linux/slab.h> #include "ccu_common.h" @@ -36,6 +37,7 @@ void ccu_helper_wait_for_lock(struct ccu_common *common, u32 lock) WARN_ON(readl_relaxed_poll_timeout(addr, reg, reg & lock, 100, 70000)); } +EXPORT_SYMBOL_NS_GPL(ccu_helper_wait_for_lock, SUNXI_CCU); /* * This clock notifier is called when the frequency of a PLL clock is @@ -83,6 +85,7 @@ int ccu_pll_notifier_register(struct ccu_pll_nb *pll_nb) return clk_notifier_register(pll_nb->common->hw.clk, &pll_nb->clk_nb); } +EXPORT_SYMBOL_NS_GPL(ccu_pll_notifier_register, SUNXI_CCU); static int sunxi_ccu_probe(struct sunxi_ccu *ccu, struct device *dev, struct device_node *node, void __iomem *reg, @@ -194,6 +197,7 @@ int devm_sunxi_ccu_probe(struct device *dev, void __iomem *reg, return 0; } +EXPORT_SYMBOL_NS_GPL(devm_sunxi_ccu_probe, SUNXI_CCU); void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, const struct sunxi_ccu_desc *desc) @@ -211,3 +215,5 @@ void of_sunxi_ccu_probe(struct device_node *node, void __iomem *reg, kfree(ccu); } } + +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/sunxi-ng/ccu_div.c b/drivers/clk/sunxi-ng/ccu_div.c index 4c297089483c..cb10a3ea23f9 100644 --- a/drivers/clk/sunxi-ng/ccu_div.c +++ b/drivers/clk/sunxi-ng/ccu_div.c @@ -141,3 +141,4 @@ const struct clk_ops ccu_div_ops = { .recalc_rate = ccu_div_recalc_rate, .set_rate = ccu_div_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_div_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_div.h b/drivers/clk/sunxi-ng/ccu_div.h index 6682fde6043c..948e2b0c0c3b 100644 --- a/drivers/clk/sunxi-ng/ccu_div.h +++ b/drivers/clk/sunxi-ng/ccu_div.h @@ -108,6 +108,22 @@ struct ccu_div { _shift, _width, _table, 0, \ _flags) +#define SUNXI_CCU_DIV_TABLE_HW(_struct, _name, _parent, _reg, \ + _shift, _width, \ + _table, _flags) \ + struct ccu_div _struct = { \ + .div = _SUNXI_CCU_DIV_TABLE(_shift, _width, \ + _table), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_HW(_name, \ + _parent, \ + &ccu_div_ops, \ + _flags), \ + } \ + } + + #define SUNXI_CCU_M_WITH_MUX_TABLE_GATE(_struct, _name, \ _parents, _table, \ _reg, \ @@ -166,6 +182,68 @@ struct ccu_div { SUNXI_CCU_M_WITH_GATE(_struct, _name, _parent, _reg, \ _mshift, _mwidth, 0, _flags) +#define SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_div _struct = { \ + .enable = _gate, \ + .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ + _parents, \ + &ccu_div_ops, \ + _flags), \ + }, \ + } + +#define SUNXI_CCU_M_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + _flags) \ + SUNXI_CCU_M_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _muxshift, _muxwidth, \ + 0, _flags) + +#define SUNXI_CCU_M_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_div _struct = { \ + .enable = _gate, \ + .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ + _parents, \ + &ccu_div_ops, \ + _flags), \ + }, \ + } + +#define SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ + _mshift, _mwidth, _gate, \ + _flags) \ + struct ccu_div _struct = { \ + .enable = _gate, \ + .div = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_HWS(_name, \ + _parent, \ + &ccu_div_ops, \ + _flags), \ + }, \ + } + +#define SUNXI_CCU_M_HWS(_struct, _name, _parent, _reg, _mshift, \ + _mwidth, _flags) \ + SUNXI_CCU_M_HWS_WITH_GATE(_struct, _name, _parent, _reg, \ + _mshift, _mwidth, 0, _flags) + static inline struct ccu_div *hw_to_ccu_div(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); diff --git a/drivers/clk/sunxi-ng/ccu_frac.c b/drivers/clk/sunxi-ng/ccu_frac.c index 44fcded8b354..b31f3ad946d6 100644 --- a/drivers/clk/sunxi-ng/ccu_frac.c +++ b/drivers/clk/sunxi-ng/ccu_frac.c @@ -18,6 +18,7 @@ bool ccu_frac_helper_is_enabled(struct ccu_common *common, return !(readl(common->base + common->reg) & cf->enable); } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_is_enabled, SUNXI_CCU); void ccu_frac_helper_enable(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -33,6 +34,7 @@ void ccu_frac_helper_enable(struct ccu_common *common, writel(reg & ~cf->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_enable, SUNXI_CCU); void ccu_frac_helper_disable(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -48,6 +50,7 @@ void ccu_frac_helper_disable(struct ccu_common *common, writel(reg | cf->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_disable, SUNXI_CCU); bool ccu_frac_helper_has_rate(struct ccu_common *common, struct ccu_frac_internal *cf, @@ -58,6 +61,7 @@ bool ccu_frac_helper_has_rate(struct ccu_common *common, return (cf->rates[0] == rate) || (cf->rates[1] == rate); } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_has_rate, SUNXI_CCU); unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, struct ccu_frac_internal *cf) @@ -79,6 +83,7 @@ unsigned long ccu_frac_helper_read_rate(struct ccu_common *common, return (reg & cf->select) ? cf->rates[1] : cf->rates[0]; } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_read_rate, SUNXI_CCU); int ccu_frac_helper_set_rate(struct ccu_common *common, struct ccu_frac_internal *cf, @@ -107,3 +112,4 @@ int ccu_frac_helper_set_rate(struct ccu_common *common, return 0; } +EXPORT_SYMBOL_NS_GPL(ccu_frac_helper_set_rate, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_gate.c b/drivers/clk/sunxi-ng/ccu_gate.c index 3d5ca092b08f..a2115a21807d 100644 --- a/drivers/clk/sunxi-ng/ccu_gate.c +++ b/drivers/clk/sunxi-ng/ccu_gate.c @@ -24,6 +24,7 @@ void ccu_gate_helper_disable(struct ccu_common *common, u32 gate) spin_unlock_irqrestore(common->lock, flags); } +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_disable, SUNXI_CCU); static void ccu_gate_disable(struct clk_hw *hw) { @@ -49,6 +50,7 @@ int ccu_gate_helper_enable(struct ccu_common *common, u32 gate) return 0; } +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_enable, SUNXI_CCU); static int ccu_gate_enable(struct clk_hw *hw) { @@ -64,6 +66,7 @@ int ccu_gate_helper_is_enabled(struct ccu_common *common, u32 gate) return readl(common->base + common->reg) & gate; } +EXPORT_SYMBOL_NS_GPL(ccu_gate_helper_is_enabled, SUNXI_CCU); static int ccu_gate_is_enabled(struct clk_hw *hw) { @@ -124,3 +127,4 @@ const struct clk_ops ccu_gate_ops = { .set_rate = ccu_gate_set_rate, .recalc_rate = ccu_gate_recalc_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_gate_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_gate.h b/drivers/clk/sunxi-ng/ccu_gate.h index c386689a952b..dc05ce06737a 100644 --- a/drivers/clk/sunxi-ng/ccu_gate.h +++ b/drivers/clk/sunxi-ng/ccu_gate.h @@ -53,7 +53,7 @@ struct ccu_gate { } /* - * The following two macros allow the re-use of the data structure + * The following macros allow the re-use of the data structure * holding the parent info. */ #define SUNXI_CCU_GATE_HWS(_struct, _name, _parent, _reg, _gate, _flags) \ @@ -68,6 +68,21 @@ struct ccu_gate { } \ } +#define SUNXI_CCU_GATE_HWS_WITH_PREDIV(_struct, _name, _parent, _reg, \ + _gate, _prediv, _flags) \ + struct ccu_gate _struct = { \ + .enable = _gate, \ + .common = { \ + .reg = _reg, \ + .prediv = _prediv, \ + .features = CCU_FEATURE_ALL_PREDIV, \ + .hw.init = CLK_HW_INIT_HWS(_name, \ + _parent, \ + &ccu_gate_ops, \ + _flags), \ + } \ + } + #define SUNXI_CCU_GATE_DATA(_struct, _name, _data, _reg, _gate, _flags) \ struct ccu_gate _struct = { \ .enable = _gate, \ @@ -81,6 +96,21 @@ struct ccu_gate { } \ } +#define SUNXI_CCU_GATE_DATA_WITH_PREDIV(_struct, _name, _parent, _reg, \ + _gate, _prediv, _flags) \ + struct ccu_gate _struct = { \ + .enable = _gate, \ + .common = { \ + .reg = _reg, \ + .prediv = _prediv, \ + .features = CCU_FEATURE_ALL_PREDIV, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ + _parent, \ + &ccu_gate_ops, \ + _flags), \ + } \ + } + static inline struct ccu_gate *hw_to_ccu_gate(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); diff --git a/drivers/clk/sunxi-ng/ccu_mp.c b/drivers/clk/sunxi-ng/ccu_mp.c index 9d3a76604d94..57cf2d615148 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.c +++ b/drivers/clk/sunxi-ng/ccu_mp.c @@ -245,6 +245,7 @@ const struct clk_ops ccu_mp_ops = { .recalc_rate = ccu_mp_recalc_rate, .set_rate = ccu_mp_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_mp_ops, SUNXI_CCU); /* * Support for MMC timing mode switching @@ -325,3 +326,4 @@ const struct clk_ops ccu_mp_mmc_ops = { .recalc_rate = ccu_mp_mmc_recalc_rate, .set_rate = ccu_mp_mmc_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_mp_mmc_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_mp.h b/drivers/clk/sunxi-ng/ccu_mp.h index b392e0d575b5..6e50f3728fb5 100644 --- a/drivers/clk/sunxi-ng/ccu_mp.h +++ b/drivers/clk/sunxi-ng/ccu_mp.h @@ -82,6 +82,55 @@ struct ccu_mp { _muxshift, _muxwidth, \ 0, _flags) +#define SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \ + .enable = _gate, \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + } + +#define SUNXI_CCU_MP_DATA_WITH_MUX(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _flags) \ + SUNXI_CCU_MP_DATA_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + 0, _flags) + +#define SUNXI_CCU_MP_HW_WITH_MUX_GATE(_struct, _name, _parents, _reg, \ + _mshift, _mwidth, \ + _pshift, _pwidth, \ + _muxshift, _muxwidth, \ + _gate, _flags) \ + struct ccu_mp _struct = { \ + .enable = _gate, \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .p = _SUNXI_CCU_DIV(_pshift, _pwidth), \ + .mux = _SUNXI_CCU_MUX(_muxshift, _muxwidth), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ + _parents, \ + &ccu_mp_ops, \ + _flags), \ + } \ + } + static inline struct ccu_mp *hw_to_ccu_mp(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); diff --git a/drivers/clk/sunxi-ng/ccu_mult.c b/drivers/clk/sunxi-ng/ccu_mult.c index 7c8cf2e04e94..7bee217ef111 100644 --- a/drivers/clk/sunxi-ng/ccu_mult.c +++ b/drivers/clk/sunxi-ng/ccu_mult.c @@ -170,3 +170,4 @@ const struct clk_ops ccu_mult_ops = { .recalc_rate = ccu_mult_recalc_rate, .set_rate = ccu_mult_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_mult_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_mux.c b/drivers/clk/sunxi-ng/ccu_mux.c index 7d75da9a1f2e..2306a1cd83e4 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.c +++ b/drivers/clk/sunxi-ng/ccu_mux.c @@ -64,6 +64,7 @@ unsigned long ccu_mux_helper_apply_prediv(struct ccu_common *common, { return parent_rate / ccu_mux_get_prediv(common, cm, parent_index); } +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_apply_prediv, SUNXI_CCU); static unsigned long ccu_mux_helper_unapply_prediv(struct ccu_common *common, struct ccu_mux_internal *cm, @@ -152,6 +153,7 @@ out: req->rate = best_rate; return 0; } +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_determine_rate, SUNXI_CCU); u8 ccu_mux_helper_get_parent(struct ccu_common *common, struct ccu_mux_internal *cm) @@ -174,6 +176,7 @@ u8 ccu_mux_helper_get_parent(struct ccu_common *common, return parent; } +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_get_parent, SUNXI_CCU); int ccu_mux_helper_set_parent(struct ccu_common *common, struct ccu_mux_internal *cm, @@ -195,6 +198,7 @@ int ccu_mux_helper_set_parent(struct ccu_common *common, return 0; } +EXPORT_SYMBOL_NS_GPL(ccu_mux_helper_set_parent, SUNXI_CCU); static void ccu_mux_disable(struct clk_hw *hw) { @@ -251,6 +255,7 @@ const struct clk_ops ccu_mux_ops = { .determine_rate = __clk_mux_determine_rate, .recalc_rate = ccu_mux_recalc_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_mux_ops, SUNXI_CCU); /* * This clock notifier is called when the frequency of the of the parent @@ -285,3 +290,4 @@ int ccu_mux_notifier_register(struct clk *clk, struct ccu_mux_nb *mux_nb) return clk_notifier_register(clk, &mux_nb->clk_nb); } +EXPORT_SYMBOL_NS_GPL(ccu_mux_notifier_register, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_mux.h b/drivers/clk/sunxi-ng/ccu_mux.h index e31efc509b3d..2c1811a445b0 100644 --- a/drivers/clk/sunxi-ng/ccu_mux.h +++ b/drivers/clk/sunxi-ng/ccu_mux.h @@ -72,6 +72,39 @@ struct ccu_mux { SUNXI_CCU_MUX_TABLE_WITH_GATE(_struct, _name, _parents, NULL, \ _reg, _shift, _width, 0, _flags) +#define SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \ + _shift, _width, _gate, _flags) \ + struct ccu_mux _struct = { \ + .enable = _gate, \ + .mux = _SUNXI_CCU_MUX(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_DATA(_name, \ + _parents, \ + &ccu_mux_ops, \ + _flags), \ + } \ + } + +#define SUNXI_CCU_MUX_DATA(_struct, _name, _parents, _reg, \ + _shift, _width, _flags) \ + SUNXI_CCU_MUX_DATA_WITH_GATE(_struct, _name, _parents, _reg, \ + _shift, _width, 0, _flags) + +#define SUNXI_CCU_MUX_HW_WITH_GATE(_struct, _name, _parents, _reg, \ + _shift, _width, _gate, _flags) \ + struct ccu_mux _struct = { \ + .enable = _gate, \ + .mux = _SUNXI_CCU_MUX(_shift, _width), \ + .common = { \ + .reg = _reg, \ + .hw.init = CLK_HW_INIT_PARENTS_HW(_name, \ + _parents, \ + &ccu_mux_ops, \ + _flags), \ + } \ + } + static inline struct ccu_mux *hw_to_ccu_mux(struct clk_hw *hw) { struct ccu_common *common = hw_to_ccu_common(hw); diff --git a/drivers/clk/sunxi-ng/ccu_nk.c b/drivers/clk/sunxi-ng/ccu_nk.c index aee68b00f3b2..c4fb82af97e8 100644 --- a/drivers/clk/sunxi-ng/ccu_nk.c +++ b/drivers/clk/sunxi-ng/ccu_nk.c @@ -157,3 +157,4 @@ const struct clk_ops ccu_nk_ops = { .round_rate = ccu_nk_round_rate, .set_rate = ccu_nk_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_nk_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_nkm.c b/drivers/clk/sunxi-ng/ccu_nkm.c index b9cfee0276ea..67da2c189b53 100644 --- a/drivers/clk/sunxi-ng/ccu_nkm.c +++ b/drivers/clk/sunxi-ng/ccu_nkm.c @@ -206,3 +206,4 @@ const struct clk_ops ccu_nkm_ops = { .recalc_rate = ccu_nkm_recalc_rate, .set_rate = ccu_nkm_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_nkm_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c index bda87b38c45c..39413cb0985c 100644 --- a/drivers/clk/sunxi-ng/ccu_nkmp.c +++ b/drivers/clk/sunxi-ng/ccu_nkmp.c @@ -230,3 +230,4 @@ const struct clk_ops ccu_nkmp_ops = { .round_rate = ccu_nkmp_round_rate, .set_rate = ccu_nkmp_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_nkmp_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index e6bcc0a7170c..9ca9257f4426 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -238,3 +238,4 @@ const struct clk_ops ccu_nm_ops = { .round_rate = ccu_nm_round_rate, .set_rate = ccu_nm_set_rate, }; +EXPORT_SYMBOL_NS_GPL(ccu_nm_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_phase.c b/drivers/clk/sunxi-ng/ccu_phase.c index 92ab8bd66427..e4cae2afe9db 100644 --- a/drivers/clk/sunxi-ng/ccu_phase.c +++ b/drivers/clk/sunxi-ng/ccu_phase.c @@ -121,3 +121,4 @@ const struct clk_ops ccu_phase_ops = { .get_phase = ccu_phase_get_phase, .set_phase = ccu_phase_set_phase, }; +EXPORT_SYMBOL_NS_GPL(ccu_phase_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_reset.c b/drivers/clk/sunxi-ng/ccu_reset.c index 483100e45df3..6577aa18cb01 100644 --- a/drivers/clk/sunxi-ng/ccu_reset.c +++ b/drivers/clk/sunxi-ng/ccu_reset.c @@ -75,3 +75,4 @@ const struct reset_control_ops ccu_reset_ops = { .reset = ccu_reset_reset, .status = ccu_reset_status, }; +EXPORT_SYMBOL_NS_GPL(ccu_reset_ops, SUNXI_CCU); diff --git a/drivers/clk/sunxi-ng/ccu_sdm.c b/drivers/clk/sunxi-ng/ccu_sdm.c index 79581a1c649a..41937ed0766d 100644 --- a/drivers/clk/sunxi-ng/ccu_sdm.c +++ b/drivers/clk/sunxi-ng/ccu_sdm.c @@ -20,6 +20,7 @@ bool ccu_sdm_helper_is_enabled(struct ccu_common *common, return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable); } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, SUNXI_CCU); void ccu_sdm_helper_enable(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -49,6 +50,7 @@ void ccu_sdm_helper_enable(struct ccu_common *common, writel(reg | sdm->enable, common->base + common->reg); spin_unlock_irqrestore(common->lock, flags); } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, SUNXI_CCU); void ccu_sdm_helper_disable(struct ccu_common *common, struct ccu_sdm_internal *sdm) @@ -69,6 +71,7 @@ void ccu_sdm_helper_disable(struct ccu_common *common, writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg); spin_unlock_irqrestore(common->lock, flags); } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, SUNXI_CCU); /* * Sigma delta modulation provides a way to do fractional-N frequency @@ -102,6 +105,7 @@ bool ccu_sdm_helper_has_rate(struct ccu_common *common, return false; } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, SUNXI_CCU); unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -132,6 +136,7 @@ unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, /* We can't calculate the effective clock rate, so just fail. */ return 0; } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, SUNXI_CCU); int ccu_sdm_helper_get_factors(struct ccu_common *common, struct ccu_sdm_internal *sdm, @@ -153,3 +158,4 @@ int ccu_sdm_helper_get_factors(struct ccu_common *common, /* nothing found */ return -EINVAL; } +EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, SUNXI_CCU); |