diff options
Diffstat (limited to 'drivers/clk')
50 files changed, 2602 insertions, 259 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 1b992a554ff8..73243ce10107 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -169,6 +169,14 @@ config COMMON_CLK_CDCE706 help This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. +config COMMON_CLK_TPS68470 + tristate "Clock Driver for TI TPS68470 PMIC" + depends on I2C + depends on INTEL_SKL_INT3472 || COMPILE_TEST + select REGMAP_I2C + help + This driver supports the clocks provided by the TPS68470 PMIC. + config COMMON_CLK_CDCE925 tristate "Clock driver for TI CDCE913/925/937/949 devices" depends on I2C diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index d8565ef01b34..154bf3c6f1ae 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -64,6 +64,7 @@ obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_STM32F) += clk-stm32f4.o obj-$(CONFIG_COMMON_CLK_STM32H7) += clk-stm32h7.o obj-$(CONFIG_COMMON_CLK_STM32MP157) += clk-stm32mp1.o +obj-$(CONFIG_COMMON_CLK_TPS68470) += clk-tps68470.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_VC5) += clk-versaclock5.o @@ -111,7 +112,7 @@ obj-$(CONFIG_PLAT_SPEAR) += spear/ obj-y += sprd/ obj-$(CONFIG_ARCH_STI) += st/ obj-$(CONFIG_ARCH_SUNXI) += sunxi/ -obj-$(CONFIG_SUNXI_CCU) += sunxi-ng/ +obj-y += sunxi-ng/ obj-$(CONFIG_ARCH_TEGRA) += tegra/ obj-y += ti/ obj-$(CONFIG_CLK_UNIPHIER) += uniphier/ diff --git a/drivers/clk/clk-stm32f4.c b/drivers/clk/clk-stm32f4.c index af46176ad053..473dfe632cc5 100644 --- a/drivers/clk/clk-stm32f4.c +++ b/drivers/clk/clk-stm32f4.c @@ -129,7 +129,6 @@ static const struct stm32f4_gate_data stm32f429_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" }, { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, - { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { @@ -211,7 +210,6 @@ static const struct stm32f4_gate_data stm32f469_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 20, "spi5", "apb2_div" }, { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, - { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { @@ -286,7 +284,6 @@ static const struct stm32f4_gate_data stm32f746_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 23, "sai2", "apb2_div" }, - { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, }; static const struct stm32f4_gate_data stm32f769_gates[] __initconst = { @@ -364,7 +361,6 @@ static const struct stm32f4_gate_data stm32f769_gates[] __initconst = { { STM32F4_RCC_APB2ENR, 21, "spi6", "apb2_div" }, { STM32F4_RCC_APB2ENR, 22, "sai1", "apb2_div" }, { STM32F4_RCC_APB2ENR, 23, "sai2", "apb2_div" }, - { STM32F4_RCC_APB2ENR, 26, "ltdc", "apb2_div" }, { STM32F4_RCC_APB2ENR, 30, "mdio", "apb2_div" }, }; diff --git a/drivers/clk/clk-tps68470.c b/drivers/clk/clk-tps68470.c new file mode 100644 index 000000000000..e5fbefd6ac2d --- /dev/null +++ b/drivers/clk/clk-tps68470.c @@ -0,0 +1,261 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Clock driver for TPS68470 PMIC + * + * Copyright (c) 2021 Red Hat Inc. + * Copyright (C) 2018 Intel Corporation + * + * Authors: + * Hans de Goede <hdegoede@redhat.com> + * Zaikuo Wang <zaikuo.wang@intel.com> + * Tianshu Qiu <tian.shu.qiu@intel.com> + * Jian Xu Zheng <jian.xu.zheng@intel.com> + * Yuning Pu <yuning.pu@intel.com> + * Antti Laakso <antti.laakso@intel.com> + */ + +#include <linux/clk-provider.h> +#include <linux/clkdev.h> +#include <linux/kernel.h> +#include <linux/mfd/tps68470.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/platform_data/tps68470.h> +#include <linux/regmap.h> + +#define TPS68470_CLK_NAME "tps68470-clk" + +#define to_tps68470_clkdata(clkd) \ + container_of(clkd, struct tps68470_clkdata, clkout_hw) + +static struct tps68470_clkout_freqs { + unsigned long freq; + unsigned int xtaldiv; + unsigned int plldiv; + unsigned int postdiv; + unsigned int buckdiv; + unsigned int boostdiv; +} clk_freqs[] = { +/* + * The PLL is used to multiply the crystal oscillator + * frequency range of 3 MHz to 27 MHz by a programmable + * factor of F = (M/N)*(1/P) such that the output + * available at the HCLK_A or HCLK_B pins are in the range + * of 4 MHz to 64 MHz in increments of 0.1 MHz. + * + * hclk_# = osc_in * (((plldiv*2)+320) / (xtaldiv+30)) * (1 / 2^postdiv) + * + * PLL_REF_CLK should be as close as possible to 100kHz + * PLL_REF_CLK = input clk / XTALDIV[7:0] + 30) + * + * PLL_VCO_CLK = (PLL_REF_CLK * (plldiv*2 + 320)) + * + * BOOST should be as close as possible to 2Mhz + * BOOST = PLL_VCO_CLK / (BOOSTDIV[4:0] + 16) * + * + * BUCK should be as close as possible to 5.2Mhz + * BUCK = PLL_VCO_CLK / (BUCKDIV[3:0] + 5) + * + * osc_in xtaldiv plldiv postdiv hclk_# + * 20Mhz 170 32 1 19.2Mhz + * 20Mhz 170 40 1 20Mhz + * 20Mhz 170 80 1 24Mhz + */ + { 19200000, 170, 32, 1, 2, 3 }, + { 20000000, 170, 40, 1, 3, 4 }, + { 24000000, 170, 80, 1, 4, 8 }, +}; + +struct tps68470_clkdata { + struct clk_hw clkout_hw; + struct regmap *regmap; + unsigned long rate; +}; + +static int tps68470_clk_is_prepared(struct clk_hw *hw) +{ + struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw); + int val; + + if (regmap_read(clkdata->regmap, TPS68470_REG_PLLCTL, &val)) + return 0; + + return val & TPS68470_PLL_EN_MASK; +} + +static int tps68470_clk_prepare(struct clk_hw *hw) +{ + struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw); + + regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1, + (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_A_SHIFT) | + (TPS68470_PLL_OUTPUT_ENABLE << TPS68470_OUTPUT_B_SHIFT)); + + regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL, + TPS68470_PLL_EN_MASK, TPS68470_PLL_EN_MASK); + + /* + * The PLLCTL reg lock bit is set by the PMIC after approx. 4ms and + * does not indicate a true lock, so just wait 4 ms. + */ + usleep_range(4000, 5000); + + return 0; +} + +static void tps68470_clk_unprepare(struct clk_hw *hw) +{ + struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw); + + /* Disable clock first ... */ + regmap_update_bits(clkdata->regmap, TPS68470_REG_PLLCTL, TPS68470_PLL_EN_MASK, 0); + + /* ... and then tri-state the clock outputs. */ + regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG1, 0); +} + +static unsigned long tps68470_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw); + + return clkdata->rate; +} + +/* + * This returns the index of the clk_freqs[] cfg with the closest rate for + * use in tps68470_clk_round_rate(). tps68470_clk_set_rate() checks that + * the rate of the returned cfg is an exact match. + */ +static unsigned int tps68470_clk_cfg_lookup(unsigned long rate) +{ + long diff, best_diff = LONG_MAX; + unsigned int i, best_idx = 0; + + for (i = 0; i < ARRAY_SIZE(clk_freqs); i++) { + diff = clk_freqs[i].freq - rate; + if (diff == 0) + return i; + + diff = abs(diff); + if (diff < best_diff) { + best_diff = diff; + best_idx = i; + } + } + + return best_idx; +} + +static long tps68470_clk_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + unsigned int idx = tps68470_clk_cfg_lookup(rate); + + return clk_freqs[idx].freq; +} + +static int tps68470_clk_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct tps68470_clkdata *clkdata = to_tps68470_clkdata(hw); + unsigned int idx = tps68470_clk_cfg_lookup(rate); + + if (rate != clk_freqs[idx].freq) + return -EINVAL; + + regmap_write(clkdata->regmap, TPS68470_REG_BOOSTDIV, clk_freqs[idx].boostdiv); + regmap_write(clkdata->regmap, TPS68470_REG_BUCKDIV, clk_freqs[idx].buckdiv); + regmap_write(clkdata->regmap, TPS68470_REG_PLLSWR, TPS68470_PLLSWR_DEFAULT); + regmap_write(clkdata->regmap, TPS68470_REG_XTALDIV, clk_freqs[idx].xtaldiv); + regmap_write(clkdata->regmap, TPS68470_REG_PLLDIV, clk_freqs[idx].plldiv); + regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV, clk_freqs[idx].postdiv); + regmap_write(clkdata->regmap, TPS68470_REG_POSTDIV2, clk_freqs[idx].postdiv); + regmap_write(clkdata->regmap, TPS68470_REG_CLKCFG2, TPS68470_CLKCFG2_DRV_STR_2MA); + + regmap_write(clkdata->regmap, TPS68470_REG_PLLCTL, + TPS68470_OSC_EXT_CAP_DEFAULT << TPS68470_OSC_EXT_CAP_SHIFT | + TPS68470_CLK_SRC_XTAL << TPS68470_CLK_SRC_SHIFT); + + clkdata->rate = rate; + + return 0; +} + +static const struct clk_ops tps68470_clk_ops = { + .is_prepared = tps68470_clk_is_prepared, + .prepare = tps68470_clk_prepare, + .unprepare = tps68470_clk_unprepare, + .recalc_rate = tps68470_clk_recalc_rate, + .round_rate = tps68470_clk_round_rate, + .set_rate = tps68470_clk_set_rate, +}; + +static int tps68470_clk_probe(struct platform_device *pdev) +{ + struct tps68470_clk_platform_data *pdata = pdev->dev.platform_data; + struct clk_init_data tps68470_clk_initdata = { + .name = TPS68470_CLK_NAME, + .ops = &tps68470_clk_ops, + /* Changing the dividers when the PLL is on is not allowed */ + .flags = CLK_SET_RATE_GATE, + }; + struct tps68470_clkdata *tps68470_clkdata; + int ret; + + tps68470_clkdata = devm_kzalloc(&pdev->dev, sizeof(*tps68470_clkdata), + GFP_KERNEL); + if (!tps68470_clkdata) + return -ENOMEM; + + tps68470_clkdata->regmap = dev_get_drvdata(pdev->dev.parent); + tps68470_clkdata->clkout_hw.init = &tps68470_clk_initdata; + + /* Set initial rate */ + tps68470_clk_set_rate(&tps68470_clkdata->clkout_hw, clk_freqs[0].freq, 0); + + ret = devm_clk_hw_register(&pdev->dev, &tps68470_clkdata->clkout_hw); + if (ret) + return ret; + + ret = devm_clk_hw_register_clkdev(&pdev->dev, &tps68470_clkdata->clkout_hw, + TPS68470_CLK_NAME, NULL); + if (ret) + return ret; + + if (pdata) { + ret = devm_clk_hw_register_clkdev(&pdev->dev, + &tps68470_clkdata->clkout_hw, + pdata->consumer_con_id, + pdata->consumer_dev_name); + } + + return ret; +} + +static struct platform_driver tps68470_clk_driver = { + .driver = { + .name = TPS68470_CLK_NAME, + }, + .probe = tps68470_clk_probe, +}; + +/* + * The ACPI tps68470 probe-ordering depends on the clk/gpio/regulator drivers + * registering before the drivers for the camera-sensors which use them bind. + * subsys_initcall() ensures this when the drivers are builtin. + */ +static int __init tps68470_clk_init(void) +{ + return platform_driver_register(&tps68470_clk_driver); +} +subsys_initcall(tps68470_clk_init); + +static void __exit tps68470_clk_exit(void) +{ + platform_driver_unregister(&tps68470_clk_driver); +} +module_exit(tps68470_clk_exit); + +MODULE_ALIAS("platform:tps68470-clk"); +MODULE_DESCRIPTION("clock driver for TPS68470 pmic"); +MODULE_LICENSE("GPL"); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index d6eed760327d..608e0e8ca49a 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -720,6 +720,35 @@ static struct clk_regmap gxbb_mpll0_div = { .width = 14, }, .sdm_en = { + .reg_off = HHI_MPLL_CNTL, + .shift = 25, + .width = 1, + }, + .n2 = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 16, + .width = 9, + }, + .lock = &meson_clk_lock, + }, + .hw.init = &(struct clk_init_data){ + .name = "mpll0_div", + .ops = &meson_clk_mpll_ops, + .parent_hws = (const struct clk_hw *[]) { + &gxbb_mpll_prediv.hw + }, + .num_parents = 1, + }, +}; + +static struct clk_regmap gxl_mpll0_div = { + .data = &(struct meson_clk_mpll_data){ + .sdm = { + .reg_off = HHI_MPLL_CNTL7, + .shift = 0, + .width = 14, + }, + .sdm_en = { .reg_off = HHI_MPLL_CNTL7, .shift = 15, .width = 1, @@ -749,7 +778,16 @@ static struct clk_regmap gxbb_mpll0 = { .hw.init = &(struct clk_init_data){ .name = "mpll0", .ops = &clk_regmap_gate_ops, - .parent_hws = (const struct clk_hw *[]) { &gxbb_mpll0_div.hw }, + .parent_data = &(const struct clk_parent_data) { + /* + * Note: + * GXL and GXBB have different SDM_EN registers. We + * fallback to the global naming string mechanism so + * mpll0_div picks up the appropriate one. + */ + .name = "mpll0_div", + .index = -1, + }, .num_parents = 1, .flags = CLK_SET_RATE_PARENT, }, @@ -3044,7 +3082,7 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_VAPB_1] = &gxbb_vapb_1.hw, [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, [CLKID_VAPB] = &gxbb_vapb.hw, - [CLKID_MPLL0_DIV] = &gxbb_mpll0_div.hw, + [CLKID_MPLL0_DIV] = &gxl_mpll0_div.hw, [CLKID_MPLL1_DIV] = &gxbb_mpll1_div.hw, [CLKID_MPLL2_DIV] = &gxbb_mpll2_div.hw, [CLKID_MPLL_PREDIV] = &gxbb_mpll_prediv.hw, @@ -3439,7 +3477,7 @@ static struct clk_regmap *const gxl_clk_regmaps[] = { &gxbb_mpll0, &gxbb_mpll1, &gxbb_mpll2, - &gxbb_mpll0_div, + &gxl_mpll0_div, &gxbb_mpll1_div, &gxbb_mpll2_div, &gxbb_cts_amclk_div, 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); diff --git a/drivers/clk/x86/clk-fch.c b/drivers/clk/x86/clk-fch.c index 8f7c5142b0f0..fdc060e75839 100644 --- a/drivers/clk/x86/clk-fch.c +++ b/drivers/clk/x86/clk-fch.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT /* - * clock framework for AMD Stoney based clocks + * clock framework for AMD FCH controller block * * Copyright 2018 Advanced Micro Devices, Inc. */ @@ -8,6 +8,7 @@ #include <linux/clk.h> #include <linux/clkdev.h> #include <linux/clk-provider.h> +#include <linux/pci.h> #include <linux/platform_data/clk-fch.h> #include <linux/platform_device.h> @@ -26,22 +27,37 @@ #define ST_CLK_GATE 3 #define ST_MAX_CLKS 4 -#define RV_CLK_48M 0 -#define RV_CLK_GATE 1 -#define RV_MAX_CLKS 2 +#define CLK_48M_FIXED 0 +#define CLK_GATE_FIXED 1 +#define CLK_MAX_FIXED 2 + +/* List of supported CPU ids for clk mux with 25Mhz clk support */ +#define AMD_CPU_ID_ST 0x1576 static const char * const clk_oscout1_parents[] = { "clk48MHz", "clk25MHz" }; static struct clk_hw *hws[ST_MAX_CLKS]; +static const struct pci_device_id fch_pci_ids[] = { + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_ST) }, + { } +}; + static int fch_clk_probe(struct platform_device *pdev) { struct fch_clk_data *fch_data; + struct pci_dev *rdev; fch_data = dev_get_platdata(&pdev->dev); if (!fch_data || !fch_data->base) return -EINVAL; - if (!fch_data->is_rv) { + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (!rdev) { + dev_err(&pdev->dev, "FCH device not found\n"); + return -ENODEV; + } + + if (pci_match_id(fch_pci_ids, rdev)) { hws[ST_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz", NULL, 0, 48000000); hws[ST_CLK_25M] = clk_hw_register_fixed_rate(NULL, "clk25MHz", @@ -59,34 +75,38 @@ static int fch_clk_probe(struct platform_device *pdev) OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL); devm_clk_hw_register_clkdev(&pdev->dev, hws[ST_CLK_GATE], - "oscout1", NULL); + fch_data->name, NULL); } else { - hws[RV_CLK_48M] = clk_hw_register_fixed_rate(NULL, "clk48MHz", + hws[CLK_48M_FIXED] = clk_hw_register_fixed_rate(NULL, "clk48MHz", NULL, 0, 48000000); - hws[RV_CLK_GATE] = clk_hw_register_gate(NULL, "oscout1", + hws[CLK_GATE_FIXED] = clk_hw_register_gate(NULL, "oscout1", "clk48MHz", 0, fch_data->base + MISCCLKCNTL1, - OSCCLKENB, CLK_GATE_SET_TO_DISABLE, NULL); + OSCCLKENB, 0, NULL); - devm_clk_hw_register_clkdev(&pdev->dev, hws[RV_CLK_GATE], - "oscout1", NULL); + devm_clk_hw_register_clkdev(&pdev->dev, hws[CLK_GATE_FIXED], + fch_data->name, NULL); } + pci_dev_put(rdev); return 0; } static int fch_clk_remove(struct platform_device *pdev) { int i, clks; - struct fch_clk_data *fch_data; + struct pci_dev *rdev; - fch_data = dev_get_platdata(&pdev->dev); + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (!rdev) + return -ENODEV; - clks = fch_data->is_rv ? RV_MAX_CLKS : ST_MAX_CLKS; + clks = pci_match_id(fch_pci_ids, rdev) ? CLK_MAX_FIXED : ST_MAX_CLKS; for (i = 0; i < clks; i++) clk_hw_unregister(hws[i]); + pci_dev_put(rdev); return 0; } |