From 30d5a945743cd05ec5c847f2e38c2fbda5e00944 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Thu, 23 May 2019 17:11:57 -0700 Subject: clk: Unexport __clk_of_table This symbol doesn't need to be exported to clk providers anymore. Originally, it was hidden inside clk.c, but then OMAP needed to get access to it in commit 819b4861c18d ("CLK: ti: add init support for clock IP blocks"), but eventually that code also changed in commit c08ee14cc663 ("clk: ti: change clock init to use generic of_clk_init") and we were left with this exported. Move this back into clk.c so that it isn't exposed anymore. Signed-off-by: Stephen Boyd --- drivers/clk/clk.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index aa51756fd4d6..b34e84bb8167 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -4038,6 +4038,7 @@ struct of_clk_provider { void *data; }; +extern struct of_device_id __clk_of_table; static const struct of_device_id __clk_of_table_sentinel __used __section(__clk_of_table_end); -- cgit v1.2.3 From 2256d89333bd17b8b56b42734a7e1046d52f7fc3 Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 12 Jun 2019 20:24:53 +0200 Subject: clk: bcm2835: remove pllb Raspberry Pi's firmware controls this pll, we should use the firmware interface to access it. Signed-off-by: Nicolas Saenz Julienne Acked-by: Eric Anholt Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-bcm2835.c | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c index 770bb01f523e..867ae3c20041 100644 --- a/drivers/clk/bcm/clk-bcm2835.c +++ b/drivers/clk/bcm/clk-bcm2835.c @@ -1651,30 +1651,10 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { .fixed_divider = 1, .flags = CLK_SET_RATE_PARENT), - /* PLLB is used for the ARM's clock. */ - [BCM2835_PLLB] = REGISTER_PLL( - .name = "pllb", - .cm_ctrl_reg = CM_PLLB, - .a2w_ctrl_reg = A2W_PLLB_CTRL, - .frac_reg = A2W_PLLB_FRAC, - .ana_reg_base = A2W_PLLB_ANA0, - .reference_enable_mask = A2W_XOSC_CTRL_PLLB_ENABLE, - .lock_mask = CM_LOCK_FLOCKB, - - .ana = &bcm2835_ana_default, - - .min_rate = 600000000u, - .max_rate = 3000000000u, - .max_fb_rate = BCM2835_MAX_FB_RATE), - [BCM2835_PLLB_ARM] = REGISTER_PLL_DIV( - .name = "pllb_arm", - .source_pll = "pllb", - .cm_reg = CM_PLLB, - .a2w_reg = A2W_PLLB_ARM, - .load_mask = CM_PLLB_LOADARM, - .hold_mask = CM_PLLB_HOLDARM, - .fixed_divider = 1, - .flags = CLK_SET_RATE_PARENT), + /* + * PLLB is used for the ARM's clock. Controlled by firmware, see + * clk-raspberrypi.c. + */ /* * PLLC is the core PLL, used to drive the core VPU clock. -- cgit v1.2.3 From 4e85e535e6cc6e8a96350e8ee684d0f22eb8629e Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 12 Jun 2019 20:24:54 +0200 Subject: clk: bcm283x: add driver interfacing with Raspberry Pi's firmware Raspberry Pi's firmware offers an interface though which update it's clock's frequencies. This is specially useful in order to change the CPU clock (pllb_arm) which is 'owned' by the firmware and we're unable to scale using the register interface provided by clk-bcm2835. Signed-off-by: Nicolas Saenz Julienne Acked-by: Eric Anholt Signed-off-by: Stephen Boyd --- drivers/clk/bcm/Kconfig | 7 + drivers/clk/bcm/Makefile | 1 + drivers/clk/bcm/clk-raspberrypi.c | 300 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 308 insertions(+) create mode 100644 drivers/clk/bcm/clk-raspberrypi.c (limited to 'drivers/clk') diff --git a/drivers/clk/bcm/Kconfig b/drivers/clk/bcm/Kconfig index 0eb281d597fc..e5497e995cfb 100644 --- a/drivers/clk/bcm/Kconfig +++ b/drivers/clk/bcm/Kconfig @@ -72,3 +72,10 @@ config CLK_BCM_SR default ARCH_BCM_IPROC help Enable common clock framework support for the Broadcom Stingray SoC + +config CLK_RASPBERRYPI + tristate "Raspberry Pi firmware based clock support" + depends on RASPBERRYPI_FIRMWARE || (COMPILE_TEST && !RASPBERRYPI_FIRMWARE) + help + Enable common clock framework support for Raspberry Pi's firmware + dependent clocks diff --git a/drivers/clk/bcm/Makefile b/drivers/clk/bcm/Makefile index e924f25bc6c8..004e9526d6f6 100644 --- a/drivers/clk/bcm/Makefile +++ b/drivers/clk/bcm/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835.o obj-$(CONFIG_CLK_BCM2835) += clk-bcm2835-aux.o +obj-$(CONFIG_CLK_RASPBERRYPI) += clk-raspberrypi.o obj-$(CONFIG_ARCH_BCM_53573) += clk-bcm53573-ilp.o obj-$(CONFIG_CLK_BCM_CYGNUS) += clk-cygnus.o obj-$(CONFIG_CLK_BCM_HR2) += clk-hr2.o diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c new file mode 100644 index 000000000000..fef1f7caee4f --- /dev/null +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -0,0 +1,300 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Raspberry Pi driver for firmware controlled clocks + * + * Even though clk-bcm2835 provides an interface to the hardware registers for + * the system clocks we've had to factor out 'pllb' as the firmware 'owns' it. + * We're not allowed to change it directly as we might race with the + * over-temperature and under-voltage protections provided by the firmware. + * + * Copyright (C) 2019 Nicolas Saenz Julienne + */ + +#include +#include +#include +#include +#include + +#include + +#define RPI_FIRMWARE_ARM_CLK_ID 0x00000003 + +#define RPI_FIRMWARE_STATE_ENABLE_BIT BIT(0) +#define RPI_FIRMWARE_STATE_WAIT_BIT BIT(1) + +/* + * Even though the firmware interface alters 'pllb' the frequencies are + * provided as per 'pllb_arm'. We need to scale before passing them trough. + */ +#define RPI_FIRMWARE_PLLB_ARM_DIV_RATE 2 + +#define A2W_PLL_FRAC_BITS 20 + +struct raspberrypi_clk { + struct device *dev; + struct rpi_firmware *firmware; + + unsigned long min_rate; + unsigned long max_rate; + + struct clk_hw pllb; + struct clk_hw *pllb_arm; + struct clk_lookup *pllb_arm_lookup; +}; + +/* + * Structure of the message passed to Raspberry Pi's firmware in order to + * change clock rates. The 'disable_turbo' option is only available to the ARM + * clock (pllb) which we enable by default as turbo mode will alter multiple + * clocks at once. + * + * Even though we're able to access the clock registers directly we're bound to + * use the firmware interface as the firmware ultimately takes care of + * mitigating overheating/undervoltage situations and we would be changing + * frequencies behind his back. + * + * For more information on the firmware interface check: + * https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface + */ +struct raspberrypi_firmware_prop { + __le32 id; + __le32 val; + __le32 disable_turbo; +} __packed; + +static int raspberrypi_clock_property(struct rpi_firmware *firmware, u32 tag, + u32 clk, u32 *val) +{ + struct raspberrypi_firmware_prop msg = { + .id = cpu_to_le32(clk), + .val = cpu_to_le32(*val), + .disable_turbo = cpu_to_le32(1), + }; + int ret; + + ret = rpi_firmware_property(firmware, tag, &msg, sizeof(msg)); + if (ret) + return ret; + + *val = le32_to_cpu(msg.val); + + return 0; +} + +static int raspberrypi_fw_pll_is_on(struct clk_hw *hw) +{ + struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, + pllb); + u32 val = 0; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_CLOCK_STATE, + RPI_FIRMWARE_ARM_CLK_ID, &val); + if (ret) + return 0; + + return !!(val & RPI_FIRMWARE_STATE_ENABLE_BIT); +} + + +static unsigned long raspberrypi_fw_pll_get_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, + pllb); + u32 val = 0; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, + &val); + if (ret) + return ret; + + return val * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; +} + +static int raspberrypi_fw_pll_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, + pllb); + u32 new_rate = rate / RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + int ret; + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_SET_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, + &new_rate); + if (ret) + dev_err_ratelimited(rpi->dev, "Failed to change %s frequency: %d", + clk_hw_get_name(hw), ret); + + return ret; +} + +/* + * Sadly there is no firmware rate rounding interface. We borrowed it from + * clk-bcm2835. + */ +static int raspberrypi_pll_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) +{ + struct raspberrypi_clk *rpi = container_of(hw, struct raspberrypi_clk, + pllb); + u64 div, final_rate; + u32 ndiv, fdiv; + + /* We can't use req->rate directly as it would overflow */ + final_rate = clamp(req->rate, rpi->min_rate, rpi->max_rate); + + div = (u64)final_rate << A2W_PLL_FRAC_BITS; + do_div(div, req->best_parent_rate); + + ndiv = div >> A2W_PLL_FRAC_BITS; + fdiv = div & ((1 << A2W_PLL_FRAC_BITS) - 1); + + final_rate = ((u64)req->best_parent_rate * + ((ndiv << A2W_PLL_FRAC_BITS) + fdiv)); + + req->rate = final_rate >> A2W_PLL_FRAC_BITS; + + return 0; +} + +static const struct clk_ops raspberrypi_firmware_pll_clk_ops = { + .is_prepared = raspberrypi_fw_pll_is_on, + .recalc_rate = raspberrypi_fw_pll_get_rate, + .set_rate = raspberrypi_fw_pll_set_rate, + .determine_rate = raspberrypi_pll_determine_rate, +}; + +static int raspberrypi_register_pllb(struct raspberrypi_clk *rpi) +{ + u32 min_rate = 0, max_rate = 0; + struct clk_init_data init; + int ret; + + memset(&init, 0, sizeof(init)); + + /* All of the PLLs derive from the external oscillator. */ + init.parent_names = (const char *[]){ "osc" }; + init.num_parents = 1; + init.name = "pllb"; + init.ops = &raspberrypi_firmware_pll_clk_ops; + init.flags = CLK_GET_RATE_NOCACHE | CLK_IGNORE_UNUSED; + + /* Get min & max rates set by the firmware */ + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_MIN_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, + &min_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s min freq: %d\n", + init.name, ret); + return ret; + } + + ret = raspberrypi_clock_property(rpi->firmware, + RPI_FIRMWARE_GET_MAX_CLOCK_RATE, + RPI_FIRMWARE_ARM_CLK_ID, + &max_rate); + if (ret) { + dev_err(rpi->dev, "Failed to get %s max freq: %d\n", + init.name, ret); + return ret; + } + + if (!min_rate || !max_rate) { + dev_err(rpi->dev, "Unexpected frequency range: min %u, max %u\n", + min_rate, max_rate); + return -EINVAL; + } + + dev_info(rpi->dev, "CPU frequency range: min %u, max %u\n", + min_rate, max_rate); + + rpi->min_rate = min_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + rpi->max_rate = max_rate * RPI_FIRMWARE_PLLB_ARM_DIV_RATE; + + rpi->pllb.init = &init; + + return devm_clk_hw_register(rpi->dev, &rpi->pllb); +} + +static int raspberrypi_register_pllb_arm(struct raspberrypi_clk *rpi) +{ + rpi->pllb_arm = clk_hw_register_fixed_factor(rpi->dev, + "pllb_arm", "pllb", + CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE, + 1, 2); + if (IS_ERR(rpi->pllb_arm)) { + dev_err(rpi->dev, "Failed to initialize pllb_arm\n"); + return PTR_ERR(rpi->pllb_arm); + } + + rpi->pllb_arm_lookup = clkdev_hw_create(rpi->pllb_arm, NULL, "cpu0"); + if (!rpi->pllb_arm_lookup) { + dev_err(rpi->dev, "Failed to initialize pllb_arm_lookup\n"); + clk_hw_unregister_fixed_factor(rpi->pllb_arm); + return -ENOMEM; + } + + return 0; +} + +static int raspberrypi_clk_probe(struct platform_device *pdev) +{ + struct device_node *firmware_node; + struct device *dev = &pdev->dev; + struct rpi_firmware *firmware; + struct raspberrypi_clk *rpi; + int ret; + + firmware_node = of_find_compatible_node(NULL, NULL, + "raspberrypi,bcm2835-firmware"); + if (!firmware_node) { + dev_err(dev, "Missing firmware node\n"); + return -ENOENT; + } + + firmware = rpi_firmware_get(firmware_node); + of_node_put(firmware_node); + if (!firmware) + return -EPROBE_DEFER; + + rpi = devm_kzalloc(dev, sizeof(*rpi), GFP_KERNEL); + if (!rpi) + return -ENOMEM; + + rpi->dev = dev; + rpi->firmware = firmware; + + ret = raspberrypi_register_pllb(rpi); + if (ret) { + dev_err(dev, "Failed to initialize pllb, %d\n", ret); + return ret; + } + + ret = raspberrypi_register_pllb_arm(rpi); + if (ret) + return ret; + + return 0; +} + +static struct platform_driver raspberrypi_clk_driver = { + .driver = { + .name = "raspberrypi-clk", + }, + .probe = raspberrypi_clk_probe, +}; +module_platform_driver(raspberrypi_clk_driver); + +MODULE_AUTHOR("Nicolas Saenz Julienne "); +MODULE_DESCRIPTION("Raspberry Pi firmware clock driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:raspberrypi-clk"); -- cgit v1.2.3 From e2bb18347c8e5c4187831f3700c380e3c759601a Mon Sep 17 00:00:00 2001 From: Nicolas Saenz Julienne Date: Wed, 12 Jun 2019 20:24:57 +0200 Subject: clk: raspberrypi: register platform device for raspberrypi-cpufreq As 'clk-raspberrypi' depends on RPi's firmware interface, which might be configured as a module, the cpu clock might not be available for the cpufreq driver during it's init process. So we register the 'raspberrypi-cpufreq' platform device after the probe sequence succeeds. Signed-off-by: Nicolas Saenz Julienne Acked-by: Eric Anholt Signed-off-by: Stephen Boyd --- drivers/clk/bcm/clk-raspberrypi.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/bcm/clk-raspberrypi.c b/drivers/clk/bcm/clk-raspberrypi.c index fef1f7caee4f..1654fd0eedc9 100644 --- a/drivers/clk/bcm/clk-raspberrypi.c +++ b/drivers/clk/bcm/clk-raspberrypi.c @@ -34,6 +34,7 @@ struct raspberrypi_clk { struct device *dev; struct rpi_firmware *firmware; + struct platform_device *cpufreq; unsigned long min_rate; unsigned long max_rate; @@ -272,6 +273,7 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) rpi->dev = dev; rpi->firmware = firmware; + platform_set_drvdata(pdev, rpi); ret = raspberrypi_register_pllb(rpi); if (ret) { @@ -283,6 +285,18 @@ static int raspberrypi_clk_probe(struct platform_device *pdev) if (ret) return ret; + rpi->cpufreq = platform_device_register_data(dev, "raspberrypi-cpufreq", + -1, NULL, 0); + + return 0; +} + +static int raspberrypi_clk_remove(struct platform_device *pdev) +{ + struct raspberrypi_clk *rpi = platform_get_drvdata(pdev); + + platform_device_unregister(rpi->cpufreq); + return 0; } @@ -291,6 +305,7 @@ static struct platform_driver raspberrypi_clk_driver = { .name = "raspberrypi-clk", }, .probe = raspberrypi_clk_probe, + .remove = raspberrypi_clk_remove, }; module_platform_driver(raspberrypi_clk_driver); -- cgit v1.2.3 From 0d34dfbf3023cf119b83f6470692c0b10c832495 Mon Sep 17 00:00:00 2001 From: JC Kuo Date: Wed, 12 Jun 2019 11:14:34 +0800 Subject: clk: tegra210: fix PLLU and PLLU_OUT1 Full-speed and low-speed USB devices do not work with Tegra210 platforms because of incorrect PLLU/PLLU_OUT1 clock settings. When full-speed device is connected: [ 14.059886] usb 1-3: new full-speed USB device number 2 using tegra-xusb [ 14.196295] usb 1-3: device descriptor read/64, error -71 [ 14.436311] usb 1-3: device descriptor read/64, error -71 [ 14.675749] usb 1-3: new full-speed USB device number 3 using tegra-xusb [ 14.812335] usb 1-3: device descriptor read/64, error -71 [ 15.052316] usb 1-3: device descriptor read/64, error -71 [ 15.164799] usb usb1-port3: attempt power cycle When low-speed device is connected: [ 37.610949] usb usb1-port3: Cannot enable. Maybe the USB cable is bad? [ 38.557376] usb usb1-port3: Cannot enable. Maybe the USB cable is bad? [ 38.564977] usb usb1-port3: attempt power cycle This commit fixes the issue by: 1. initializing PLLU_OUT1 before initializing XUSB_FS_SRC clock because PLLU_OUT1 is parent of XUSB_FS_SRC. 2. changing PLLU post-divider to /2 (DIVP=1) according to Technical Reference Manual. Fixes: e745f992cf4b ("clk: tegra: Rework pll_u") Signed-off-by: JC Kuo Acked-By: Peter De Schrijver Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra210.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index ed3c7df75d1e..1be4d82d78cf 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -2215,9 +2215,9 @@ static struct div_nmp pllu_nmp = { }; static struct tegra_clk_pll_freq_table pll_u_freq_table[] = { - { 12000000, 480000000, 40, 1, 0, 0 }, - { 13000000, 480000000, 36, 1, 0, 0 }, /* actual: 468.0 MHz */ - { 38400000, 480000000, 25, 2, 0, 0 }, + { 12000000, 480000000, 40, 1, 1, 0 }, + { 13000000, 480000000, 36, 1, 1, 0 }, /* actual: 468.0 MHz */ + { 38400000, 480000000, 25, 2, 1, 0 }, { 0, 0, 0, 0, 0, 0 }, }; @@ -3344,6 +3344,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 }, + { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 }, { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 }, { TEGRA210_CLK_XUSB_FS_SRC, TEGRA210_CLK_PLL_U_48M, 48000000, 0 }, @@ -3368,7 +3369,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_PLL_DP, TEGRA210_CLK_CLK_MAX, 270000000, 0 }, { TEGRA210_CLK_SOC_THERM, TEGRA210_CLK_PLL_P, 51000000, 0 }, { TEGRA210_CLK_CCLK_G, TEGRA210_CLK_CLK_MAX, 0, 1 }, - { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 }, { TEGRA210_CLK_PLL_U_OUT2, TEGRA210_CLK_CLK_MAX, 60000000, 1 }, { TEGRA210_CLK_SPDIF_IN_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 }, { TEGRA210_CLK_I2S0_SYNC, TEGRA210_CLK_CLK_MAX, 24576000, 0 }, -- cgit v1.2.3 From 20675070127b51c6ca26a895c7e0b459f2c397e1 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 13 Jun 2019 18:12:23 +0200 Subject: clk: tegra: Do not warn unnecessarily There is no need to warn if the reference PLL is enabled with the correct defaults. Only warn if the boot values don't match the defaults. Signed-off-by: Thierry Reding Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra210.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 1be4d82d78cf..51a21bf1715e 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -995,8 +995,6 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) pllre->params->defaults_set = true; if (val & PLL_ENABLE) { - pr_warn("PLL_RE already enabled. Postponing set full defaults\n"); - /* * PLL is ON: check if defaults already set, then set those * that can be updated in flight. @@ -1023,6 +1021,9 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); udelay(1); + if (!pllre->params->defaults_set) + pr_warn("PLL_RE already enabled. Postponing set full defaults\n"); + return; } -- cgit v1.2.3 From c1139d20833f8882df608f456ce65b06cd1caa98 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 13 Jun 2019 18:12:24 +0200 Subject: clk: tegra: Warn if an enabled PLL is in IDDQ A PLL in IDDQ doesn't work, whether it's enabled or not. This is not a configuration that makes sense, so warn about it. Signed-off-by: Thierry Reding Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra210.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 51a21bf1715e..18384666b380 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -1014,8 +1014,12 @@ static void tegra210_pllre_set_defaults(struct tegra_clk_pll *pllre) _pll_misc_chk_default(clk_base, pllre->params, 0, val, ~mask & PLLRE_MISC0_WRITE_MASK); - /* Enable lock detect */ + /* The PLL doesn't work if it's in IDDQ. */ val = readl_relaxed(clk_base + pllre->params->ext_misc_reg[0]); + if (val & PLLRE_MISC0_IDDQ) + pr_warn("unexpected IDDQ bit set for enabled clock\n"); + + /* Enable lock detect */ val &= ~mask; val |= PLLRE_MISC0_DEFAULT_VALUE & mask; writel_relaxed(val, clk_base + pllre->params->ext_misc_reg[0]); -- cgit v1.2.3 From e3527dca15c853daaacddc3f95461e8a02190114 Mon Sep 17 00:00:00 2001 From: Thierry Reding Date: Thu, 13 Jun 2019 18:12:25 +0200 Subject: clk: tegra: Do not enable PLL_RE_VCO on Tegra210 It turns out that this PLL is not used on Tegra210, so there's no need to enable it via the init table. Remove the init table entry for this PLL to avoid it getting enabled at boot time. If the bootloader enabled it and forgot to turn it off, the common clock framework will now know to disable it because it is unused. Signed-off-by: Thierry Reding Acked-by: Jon Hunter Signed-off-by: Stephen Boyd --- drivers/clk/tegra/clk-tegra210.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 18384666b380..b474d3d7b1b6 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -3348,7 +3348,6 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA210_CLK_DFLL_SOC, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_DFLL_REF, TEGRA210_CLK_PLL_P, 51000000, 1 }, { TEGRA210_CLK_SBC4, TEGRA210_CLK_PLL_P, 12000000, 1 }, - { TEGRA210_CLK_PLL_RE_VCO, TEGRA210_CLK_CLK_MAX, 672000000, 1 }, { TEGRA210_CLK_PLL_U_OUT1, TEGRA210_CLK_CLK_MAX, 48000000, 1 }, { TEGRA210_CLK_XUSB_GATE, TEGRA210_CLK_CLK_MAX, 0, 1 }, { TEGRA210_CLK_XUSB_SS_SRC, TEGRA210_CLK_PLL_U_480M, 120000000, 0 }, -- cgit v1.2.3 From 69b39d2503af55e3a2ac3130c95855ac185bb70d Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 22 May 2019 09:15:01 +0800 Subject: clk: sprd: Switch from of_iomap() to devm_ioremap_resource() devm_ioremap_resources() automatically requests resources and devm_ wrappers do better error handling and unmapping of the I/O region when needed, that would make drivers more clean and simple. Signed-off-by: Chunyan Zhang Reviewed-by: Baolin Wang Signed-off-by: Stephen Boyd --- drivers/clk/sprd/common.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c index e038b0447206..9ce690999eaa 100644 --- a/drivers/clk/sprd/common.c +++ b/drivers/clk/sprd/common.c @@ -42,6 +42,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev, void __iomem *base; struct device_node *node = pdev->dev.of_node; struct regmap *regmap; + struct resource *res; if (of_find_property(node, "sprd,syscon", NULL)) { regmap = syscon_regmap_lookup_by_phandle(node, "sprd,syscon"); @@ -50,7 +51,11 @@ int sprd_clk_regmap_init(struct platform_device *pdev, return PTR_ERR(regmap); } } else { - base = of_iomap(node, 0); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + regmap = devm_regmap_init_mmio(&pdev->dev, base, &sprdclk_regmap_config); if (IS_ERR_OR_NULL(regmap)) { -- cgit v1.2.3 From 78f529695182b980a5183b850fe2d87091e36874 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 22 May 2019 09:15:02 +0800 Subject: clk: sprd: Check error only for devm_regmap_init_mmio() The function devm_regmap_init_mmio() wouldn't return NULL pointer for now, so only need to ensure the return value is not an error code. Signed-off-by: Chunyan Zhang Reviewed-by: Baolin Wang Signed-off-by: Stephen Boyd --- drivers/clk/sprd/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/sprd/common.c b/drivers/clk/sprd/common.c index 9ce690999eaa..a5bdca1de5d0 100644 --- a/drivers/clk/sprd/common.c +++ b/drivers/clk/sprd/common.c @@ -58,7 +58,7 @@ int sprd_clk_regmap_init(struct platform_device *pdev, regmap = devm_regmap_init_mmio(&pdev->dev, base, &sprdclk_regmap_config); - if (IS_ERR_OR_NULL(regmap)) { + if (IS_ERR(regmap)) { pr_err("failed to init regmap\n"); return PTR_ERR(regmap); } -- cgit v1.2.3 From 5cf6d876a7d05fdd893c74b4c274bbe78fbe9698 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 21 May 2019 10:11:22 +0000 Subject: clk: at91: sckc: sama5d4 has no bypass support The slow clock of SAMA5D4 has no bypass support thus remove it. Signed-off-by: Claudiu Beznea Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index e76b1d64e905..6c55a7a86f79 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -429,7 +429,6 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) struct clk_init_data init; const char *xtal_name; const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; - bool bypass; int ret; if (!regbase) @@ -443,8 +442,6 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) xtal_name = of_clk_get_parent_name(np, 0); - bypass = of_property_read_bool(np, "atmel,osc-bypass"); - osc = kzalloc(sizeof(*osc), GFP_KERNEL); if (!osc) return; @@ -459,9 +456,6 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) osc->sckcr = regbase; osc->startup_usec = 1200000; - if (bypass) - writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase); - hw = &osc->hw; ret = clk_hw_register(NULL, &osc->hw); if (ret) { -- cgit v1.2.3 From abaceffc88ebf510ffb95380985cb3da16d7aa9d Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 21 May 2019 10:11:26 +0000 Subject: clk: at91: sckc: add support to specify registers bit offsets Different IPs uses different bit offsets in registers for the same functionality, thus adapt the driver to support this. Signed-off-by: Claudiu Beznea Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 93 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 32 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 6c55a7a86f79..ab18b1da269f 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -23,14 +23,18 @@ SLOW_CLOCK_FREQ) #define AT91_SCKC_CR 0x00 -#define AT91_SCKC_RCEN (1 << 0) -#define AT91_SCKC_OSC32EN (1 << 1) -#define AT91_SCKC_OSC32BYP (1 << 2) -#define AT91_SCKC_OSCSEL (1 << 3) + +struct clk_slow_bits { + u32 cr_rcen; + u32 cr_osc32en; + u32 cr_osc32byp; + u32 cr_oscsel; +}; struct clk_slow_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_bits *bits; unsigned long startup_usec; }; @@ -39,6 +43,7 @@ struct clk_slow_osc { struct clk_sama5d4_slow_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_bits *bits; unsigned long startup_usec; bool prepared; }; @@ -48,6 +53,7 @@ struct clk_sama5d4_slow_osc { struct clk_slow_rc_osc { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_bits *bits; unsigned long frequency; unsigned long accuracy; unsigned long startup_usec; @@ -58,6 +64,7 @@ struct clk_slow_rc_osc { struct clk_sam9x5_slow { struct clk_hw hw; void __iomem *sckcr; + const struct clk_slow_bits *bits; u8 parent; }; @@ -69,10 +76,10 @@ static int clk_slow_osc_prepare(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN)) + if (tmp & (osc->bits->cr_osc32byp | osc->bits->cr_osc32en)) return 0; - writel(tmp | AT91_SCKC_OSC32EN, sckcr); + writel(tmp | osc->bits->cr_osc32en, sckcr); usleep_range(osc->startup_usec, osc->startup_usec + 1); @@ -85,10 +92,10 @@ static void clk_slow_osc_unprepare(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & AT91_SCKC_OSC32BYP) + if (tmp & osc->bits->cr_osc32byp) return; - writel(tmp & ~AT91_SCKC_OSC32EN, sckcr); + writel(tmp & ~osc->bits->cr_osc32en, sckcr); } static int clk_slow_osc_is_prepared(struct clk_hw *hw) @@ -97,10 +104,10 @@ static int clk_slow_osc_is_prepared(struct clk_hw *hw) void __iomem *sckcr = osc->sckcr; u32 tmp = readl(sckcr); - if (tmp & AT91_SCKC_OSC32BYP) + if (tmp & osc->bits->cr_osc32byp) return 1; - return !!(tmp & AT91_SCKC_OSC32EN); + return !!(tmp & osc->bits->cr_osc32en); } static const struct clk_ops slow_osc_ops = { @@ -114,7 +121,8 @@ at91_clk_register_slow_osc(void __iomem *sckcr, const char *name, const char *parent_name, unsigned long startup, - bool bypass) + bool bypass, + const struct clk_slow_bits *bits) { struct clk_slow_osc *osc; struct clk_hw *hw; @@ -137,10 +145,11 @@ at91_clk_register_slow_osc(void __iomem *sckcr, osc->hw.init = &init; osc->sckcr = sckcr; osc->startup_usec = startup; + osc->bits = bits; if (bypass) - writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP, - sckcr); + writel((readl(sckcr) & ~osc->bits->cr_osc32en) | + osc->bits->cr_osc32byp, sckcr); hw = &osc->hw; ret = clk_hw_register(NULL, &osc->hw); @@ -173,7 +182,7 @@ static int clk_slow_rc_osc_prepare(struct clk_hw *hw) struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); void __iomem *sckcr = osc->sckcr; - writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr); + writel(readl(sckcr) | osc->bits->cr_rcen, sckcr); usleep_range(osc->startup_usec, osc->startup_usec + 1); @@ -185,14 +194,14 @@ static void clk_slow_rc_osc_unprepare(struct clk_hw *hw) struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); void __iomem *sckcr = osc->sckcr; - writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr); + writel(readl(sckcr) & ~osc->bits->cr_rcen, sckcr); } static int clk_slow_rc_osc_is_prepared(struct clk_hw *hw) { struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); - return !!(readl(osc->sckcr) & AT91_SCKC_RCEN); + return !!(readl(osc->sckcr) & osc->bits->cr_rcen); } static const struct clk_ops slow_rc_osc_ops = { @@ -208,7 +217,8 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, const char *name, unsigned long frequency, unsigned long accuracy, - unsigned long startup) + unsigned long startup, + const struct clk_slow_bits *bits) { struct clk_slow_rc_osc *osc; struct clk_hw *hw; @@ -230,6 +240,7 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, osc->hw.init = &init; osc->sckcr = sckcr; + osc->bits = bits; osc->frequency = frequency; osc->accuracy = accuracy; osc->startup_usec = startup; @@ -255,14 +266,14 @@ static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) tmp = readl(sckcr); - if ((!index && !(tmp & AT91_SCKC_OSCSEL)) || - (index && (tmp & AT91_SCKC_OSCSEL))) + if ((!index && !(tmp & slowck->bits->cr_oscsel)) || + (index && (tmp & slowck->bits->cr_oscsel))) return 0; if (index) - tmp |= AT91_SCKC_OSCSEL; + tmp |= slowck->bits->cr_oscsel; else - tmp &= ~AT91_SCKC_OSCSEL; + tmp &= ~slowck->bits->cr_oscsel; writel(tmp, sckcr); @@ -275,7 +286,7 @@ static u8 clk_sam9x5_slow_get_parent(struct clk_hw *hw) { struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); - return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL); + return !!(readl(slowck->sckcr) & slowck->bits->cr_oscsel); } static const struct clk_ops sam9x5_slow_ops = { @@ -287,7 +298,8 @@ static struct clk_hw * __init at91_clk_register_sam9x5_slow(void __iomem *sckcr, const char *name, const char **parent_names, - int num_parents) + int num_parents, + const struct clk_slow_bits *bits) { struct clk_sam9x5_slow *slowck; struct clk_hw *hw; @@ -309,7 +321,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, slowck->hw.init = &init; slowck->sckcr = sckcr; - slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL); + slowck->bits = bits; + slowck->parent = !!(readl(sckcr) & slowck->bits->cr_oscsel); hw = &slowck->hw; ret = clk_hw_register(NULL, &slowck->hw); @@ -322,7 +335,8 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, } static void __init at91sam9x5_sckc_register(struct device_node *np, - unsigned int rc_osc_startup_us) + unsigned int rc_osc_startup_us, + const struct clk_slow_bits *bits) { const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; void __iomem *regbase = of_iomap(np, 0); @@ -335,7 +349,8 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, return; hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768, - 50000000, rc_osc_startup_us); + 50000000, rc_osc_startup_us, + bits); if (IS_ERR(hw)) return; @@ -358,11 +373,12 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, return; hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name, - 1200000, bypass); + 1200000, bypass, bits); if (IS_ERR(hw)) return; - hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2, + bits); if (IS_ERR(hw)) return; @@ -373,16 +389,23 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw); } +static const struct clk_slow_bits at91sam9x5_bits = { + .cr_rcen = BIT(0), + .cr_osc32en = BIT(1), + .cr_osc32byp = BIT(2), + .cr_oscsel = BIT(3), +}; + static void __init of_at91sam9x5_sckc_setup(struct device_node *np) { - at91sam9x5_sckc_register(np, 75); + at91sam9x5_sckc_register(np, 75, &at91sam9x5_bits); } CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc", of_at91sam9x5_sckc_setup); static void __init of_sama5d3_sckc_setup(struct device_node *np) { - at91sam9x5_sckc_register(np, 500); + at91sam9x5_sckc_register(np, 500, &at91sam9x5_bits); } CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc", of_sama5d3_sckc_setup); @@ -398,7 +421,7 @@ static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) * Assume that if it has already been selected (for example by the * bootloader), enough time has aready passed. */ - if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) { + if ((readl(osc->sckcr) & osc->bits->cr_oscsel)) { osc->prepared = true; return 0; } @@ -421,6 +444,10 @@ static const struct clk_ops sama5d4_slow_osc_ops = { .is_prepared = clk_sama5d4_slow_osc_is_prepared, }; +static const struct clk_slow_bits at91sama5d4_bits = { + .cr_oscsel = BIT(3), +}; + static void __init of_sama5d4_sckc_setup(struct device_node *np) { void __iomem *regbase = of_iomap(np, 0); @@ -455,6 +482,7 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) osc->hw.init = &init; osc->sckcr = regbase; osc->startup_usec = 1200000; + osc->bits = &at91sama5d4_bits; hw = &osc->hw; ret = clk_hw_register(NULL, &osc->hw); @@ -463,7 +491,8 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) return; } - hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2); + hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2, + &at91sama5d4_bits); if (IS_ERR(hw)) return; -- cgit v1.2.3 From 04bcc4275e601d5928beaf21e888017d4b7ad3d1 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Tue, 21 May 2019 10:11:33 +0000 Subject: clk: at91: sckc: add support for SAM9X60 Add support for SAM9X60's slow clock. Signed-off-by: Claudiu Beznea Acked-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index ab18b1da269f..1f0f1cd06387 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -410,6 +410,80 @@ static void __init of_sama5d3_sckc_setup(struct device_node *np) CLK_OF_DECLARE(sama5d3_clk_sckc, "atmel,sama5d3-sckc", of_sama5d3_sckc_setup); +static const struct clk_slow_bits at91sam9x60_bits = { + .cr_osc32en = BIT(1), + .cr_osc32byp = BIT(2), + .cr_oscsel = BIT(24), +}; + +static void __init of_sam9x60_sckc_setup(struct device_node *np) +{ + void __iomem *regbase = of_iomap(np, 0); + struct clk_hw_onecell_data *clk_data; + struct clk_hw *slow_rc, *slow_osc; + const char *xtal_name; + const char *parent_names[2] = { "slow_rc_osc", "slow_osc" }; + bool bypass; + int ret; + + if (!regbase) + return; + + slow_rc = clk_hw_register_fixed_rate(NULL, parent_names[0], NULL, 0, + 32768); + if (IS_ERR(slow_rc)) + return; + + xtal_name = of_clk_get_parent_name(np, 0); + if (!xtal_name) + goto unregister_slow_rc; + + bypass = of_property_read_bool(np, "atmel,osc-bypass"); + slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1], + xtal_name, 5000000, bypass, + &at91sam9x60_bits); + if (IS_ERR(slow_osc)) + goto unregister_slow_rc; + + clk_data = kzalloc(sizeof(*clk_data) + (2 * sizeof(struct clk_hw *)), + GFP_KERNEL); + if (!clk_data) + goto unregister_slow_osc; + + /* MD_SLCK and TD_SLCK. */ + clk_data->num = 2; + clk_data->hws[0] = clk_hw_register_fixed_rate(NULL, "md_slck", + parent_names[0], + 0, 32768); + if (IS_ERR(clk_data->hws[0])) + goto clk_data_free; + + clk_data->hws[1] = at91_clk_register_sam9x5_slow(regbase, "td_slck", + parent_names, 2, + &at91sam9x60_bits); + if (IS_ERR(clk_data->hws[1])) + goto unregister_md_slck; + + ret = of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); + if (WARN_ON(ret)) + goto unregister_td_slck; + + return; + +unregister_td_slck: + clk_hw_unregister(clk_data->hws[1]); +unregister_md_slck: + clk_hw_unregister(clk_data->hws[0]); +clk_data_free: + kfree(clk_data); +unregister_slow_osc: + clk_hw_unregister(slow_osc); +unregister_slow_rc: + clk_hw_unregister(slow_rc); +} +CLK_OF_DECLARE(sam9x60_clk_sckc, "microchip,sam9x60-sckc", + of_sam9x60_sckc_setup); + static int clk_sama5d4_slow_osc_prepare(struct clk_hw *hw) { struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(hw); -- cgit v1.2.3 From 7fb791d07954910ced6edbecc60c07b7191a39cf Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:39 +0300 Subject: clk: at91: sckc: add support to free slow oscillator Add support to free slow oscillator resources. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 1f0f1cd06387..3f84d58d06a5 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -161,6 +161,14 @@ at91_clk_register_slow_osc(void __iomem *sckcr, return hw; } +static void at91_clk_unregister_slow_osc(struct clk_hw *hw) +{ + struct clk_slow_osc *osc = to_clk_slow_osc(hw); + + clk_hw_unregister(hw); + kfree(osc); +} + static unsigned long clk_slow_rc_osc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { -- cgit v1.2.3 From 036702468c9112f65abc58cce6770e01e41996a9 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:40 +0300 Subject: clk: at91: sckc: add support to free slow rc oscillator Add support to free slow rc oscillator resources. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 3f84d58d06a5..4b0fcfd29f82 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -263,6 +263,14 @@ at91_clk_register_slow_rc_osc(void __iomem *sckcr, return hw; } +static void at91_clk_unregister_slow_rc_osc(struct clk_hw *hw) +{ + struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(hw); + + clk_hw_unregister(hw); + kfree(osc); +} + static int clk_sam9x5_slow_set_parent(struct clk_hw *hw, u8 index) { struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); -- cgit v1.2.3 From 016d22dd10eac723815adb6befdbf265a76d2383 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:41 +0300 Subject: clk: at91: sckc: add support to free slow clock osclillator Add support to free slow clock oscillator resources. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 4b0fcfd29f82..68a818e69325 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -350,6 +350,14 @@ at91_clk_register_sam9x5_slow(void __iomem *sckcr, return hw; } +static void at91_clk_unregister_sam9x5_slow(struct clk_hw *hw) +{ + struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(hw); + + clk_hw_unregister(hw); + kfree(slowck); +} + static void __init at91sam9x5_sckc_register(struct device_node *np, unsigned int rc_osc_startup_us, const struct clk_slow_bits *bits) -- cgit v1.2.3 From 82e25dc8f6bef3e08d7b58720f8812c12f2e3a89 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:42 +0300 Subject: clk: at91: sckc: improve error path for sam9x5 sck register Improve error path for sam9x5 slow clock registration. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 50 +++++++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 18 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 68a818e69325..0641f9b37333 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -366,16 +366,17 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, void __iomem *regbase = of_iomap(np, 0); struct device_node *child = NULL; const char *xtal_name; - struct clk_hw *hw; + struct clk_hw *slow_rc, *slow_osc, *slowck; bool bypass; + int ret; if (!regbase) return; - hw = at91_clk_register_slow_rc_osc(regbase, parent_names[0], 32768, - 50000000, rc_osc_startup_us, - bits); - if (IS_ERR(hw)) + slow_rc = at91_clk_register_slow_rc_osc(regbase, parent_names[0], + 32768, 50000000, + rc_osc_startup_us, bits); + if (IS_ERR(slow_rc)) return; xtal_name = of_clk_get_parent_name(np, 0); @@ -383,7 +384,7 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, /* DT backward compatibility */ child = of_get_compatible_child(np, "atmel,at91sam9x5-clk-slow-osc"); if (!child) - return; + goto unregister_slow_rc; xtal_name = of_clk_get_parent_name(child, 0); bypass = of_property_read_bool(child, "atmel,osc-bypass"); @@ -394,23 +395,36 @@ static void __init at91sam9x5_sckc_register(struct device_node *np, } if (!xtal_name) - return; - - hw = at91_clk_register_slow_osc(regbase, parent_names[1], xtal_name, - 1200000, bypass, bits); - if (IS_ERR(hw)) - return; + goto unregister_slow_rc; - hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2, - bits); - if (IS_ERR(hw)) - return; + slow_osc = at91_clk_register_slow_osc(regbase, parent_names[1], + xtal_name, 1200000, bypass, bits); + if (IS_ERR(slow_osc)) + goto unregister_slow_rc; - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); + slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, + 2, bits); + if (IS_ERR(slowck)) + goto unregister_slow_osc; /* DT backward compatibility */ if (child) - of_clk_add_hw_provider(child, of_clk_hw_simple_get, hw); + ret = of_clk_add_hw_provider(child, of_clk_hw_simple_get, + slowck); + else + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck); + + if (WARN_ON(ret)) + goto unregister_slowck; + + return; + +unregister_slowck: + at91_clk_unregister_sam9x5_slow(slowck); +unregister_slow_osc: + at91_clk_unregister_slow_osc(slow_osc); +unregister_slow_rc: + at91_clk_unregister_slow_rc_osc(slow_rc); } static const struct clk_slow_bits at91sam9x5_bits = { -- cgit v1.2.3 From 8c938c2d00c14e6af0c3401d31443d2fd626b664 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:43 +0300 Subject: clk: at91: sckc: remove unnecessary line Remove unnecessary line. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index 0641f9b37333..a9c2ad68e155 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -596,7 +596,6 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) osc->startup_usec = 1200000; osc->bits = &at91sama5d4_bits; - hw = &osc->hw; ret = clk_hw_register(NULL, &osc->hw); if (ret) { kfree(osc); -- cgit v1.2.3 From d09e6ca1381fee498f3fd0431800617daffb8fd4 Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:44 +0300 Subject: clk: at91: sckc: improve error path for sama5d4 sck registration Improve error path for sama5d4 sck registration. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 43 ++++++++++++++++++++++++++++--------------- 1 file changed, 28 insertions(+), 15 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index a9c2ad68e155..e216bb613562 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -563,7 +563,7 @@ static const struct clk_slow_bits at91sama5d4_bits = { static void __init of_sama5d4_sckc_setup(struct device_node *np) { void __iomem *regbase = of_iomap(np, 0); - struct clk_hw *hw; + struct clk_hw *slow_rc, *slowck; struct clk_sama5d4_slow_osc *osc; struct clk_init_data init; const char *xtal_name; @@ -573,17 +573,18 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) if (!regbase) return; - hw = clk_hw_register_fixed_rate_with_accuracy(NULL, parent_names[0], - NULL, 0, 32768, - 250000000); - if (IS_ERR(hw)) + slow_rc = clk_hw_register_fixed_rate_with_accuracy(NULL, + parent_names[0], + NULL, 0, 32768, + 250000000); + if (IS_ERR(slow_rc)) return; xtal_name = of_clk_get_parent_name(np, 0); osc = kzalloc(sizeof(*osc), GFP_KERNEL); if (!osc) - return; + goto unregister_slow_rc; init.name = parent_names[1]; init.ops = &sama5d4_slow_osc_ops; @@ -597,17 +598,29 @@ static void __init of_sama5d4_sckc_setup(struct device_node *np) osc->bits = &at91sama5d4_bits; ret = clk_hw_register(NULL, &osc->hw); - if (ret) { - kfree(osc); - return; - } + if (ret) + goto free_slow_osc_data; - hw = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2, - &at91sama5d4_bits); - if (IS_ERR(hw)) - return; + slowck = at91_clk_register_sam9x5_slow(regbase, "slowck", + parent_names, 2, + &at91sama5d4_bits); + if (IS_ERR(slowck)) + goto unregister_slow_osc; - of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw); + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, slowck); + if (WARN_ON(ret)) + goto unregister_slowck; + + return; + +unregister_slowck: + at91_clk_unregister_sam9x5_slow(slowck); +unregister_slow_osc: + clk_hw_unregister(&osc->hw); +free_slow_osc_data: + kfree(osc); +unregister_slow_rc: + clk_hw_unregister(slow_rc); } CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc", of_sama5d4_sckc_setup); -- cgit v1.2.3 From ecbcc2aa655744363647b91dee09096918e41eaf Mon Sep 17 00:00:00 2001 From: Claudiu Beznea Date: Thu, 27 Jun 2019 18:53:45 +0300 Subject: clk: at91: sckc: use dedicated functions to unregister clock Use at91 specific functions to free all resources in case of error. Signed-off-by: Claudiu Beznea Reviewed-by: Alexandre Belloni Signed-off-by: Stephen Boyd --- drivers/clk/at91/sckc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c index e216bb613562..c0451c9cf334 100644 --- a/drivers/clk/at91/sckc.c +++ b/drivers/clk/at91/sckc.c @@ -509,13 +509,13 @@ static void __init of_sam9x60_sckc_setup(struct device_node *np) return; unregister_td_slck: - clk_hw_unregister(clk_data->hws[1]); + at91_clk_unregister_sam9x5_slow(clk_data->hws[1]); unregister_md_slck: clk_hw_unregister(clk_data->hws[0]); clk_data_free: kfree(clk_data); unregister_slow_osc: - clk_hw_unregister(slow_osc); + at91_clk_unregister_slow_osc(slow_osc); unregister_slow_rc: clk_hw_unregister(slow_rc); } -- cgit v1.2.3 From c974c48deeb969c5e4250e4f06af91edd84b1f10 Mon Sep 17 00:00:00 2001 From: Chunyan Zhang Date: Wed, 22 May 2019 09:15:03 +0800 Subject: clk: sprd: Add check for return value of sprd_clk_regmap_init() sprd_clk_regmap_init() doesn't always return success, adding check for its return value should make the code more strong. Signed-off-by: Chunyan Zhang Reviewed-by: Baolin Wang [sboyd@kernel.org: Add a missing int ret] Signed-off-by: Stephen Boyd --- drivers/clk/sprd/sc9860-clk.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'drivers/clk') diff --git a/drivers/clk/sprd/sc9860-clk.c b/drivers/clk/sprd/sc9860-clk.c index 9980ab55271b..f76305b4bc8d 100644 --- a/drivers/clk/sprd/sc9860-clk.c +++ b/drivers/clk/sprd/sc9860-clk.c @@ -2023,6 +2023,7 @@ static int sc9860_clk_probe(struct platform_device *pdev) { const struct of_device_id *match; const struct sprd_clk_desc *desc; + int ret; match = of_match_node(sprd_sc9860_clk_ids, pdev->dev.of_node); if (!match) { @@ -2031,7 +2032,9 @@ static int sc9860_clk_probe(struct platform_device *pdev) } desc = match->data; - sprd_clk_regmap_init(pdev, desc); + ret = sprd_clk_regmap_init(pdev, desc); + if (ret) + return ret; return sprd_clk_probe(&pdev->dev, desc->hw_clks); } -- cgit v1.2.3 From 1df379924304b687263942452836db1d725155df Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Tue, 2 Jul 2019 12:03:50 +1000 Subject: clk: consoldiate the __clk_get_hw() declarations Without this we were getting errors like: In file included from drivers/clk/clkdev.c:22:0: drivers/clk/clk.h:36:23: error: static declaration of '__clk_get_hw' follows non-static declaration include/linux/clk-provider.h:808:16: note: previous declaration of '__clk_get_hw' was here Fixes: 59fcdce425b7 ("clk: Remove ifdef for COMMON_CLK in clk-provider.h") fixes: 73e0e496afda ("clkdev: Always allocate a struct clk and call __clk_get() w/ CCF") Signed-off-by: Stephen Rothwell Signed-off-by: Stephen Boyd --- drivers/clk/clk.h | 4 ---- drivers/clk/imx/clk-imx6q.c | 1 + drivers/clk/imx/clk-imx6sll.c | 1 + drivers/clk/imx/clk-imx6sx.c | 1 + drivers/clk/imx/clk-imx6ul.c | 1 + drivers/clk/imx/clk-imx7d.c | 1 + drivers/clk/imx/clk.c | 1 + 7 files changed, 6 insertions(+), 4 deletions(-) (limited to 'drivers/clk') diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index d8400d623b34..2d801900cad5 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -33,10 +33,6 @@ clk_hw_create_clk(struct device *dev, struct clk_hw *hw, const char *dev_id, { return (struct clk *)hw; } -static struct clk_hw *__clk_get_hw(struct clk *clk) -{ - return (struct clk_hw *)clk; -} static inline void __clk_put(struct clk *clk) { } #endif diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index 708e7c5590dd..fa5ef3cc2240 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx6sll.c b/drivers/clk/imx/clk-imx6sll.c index 7eea448cb9a9..a9548c4b6d78 100644 --- a/drivers/clk/imx/clk-imx6sll.c +++ b/drivers/clk/imx/clk-imx6sll.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx6sx.c b/drivers/clk/imx/clk-imx6sx.c index 91558b09bf9e..77748d6d4ccc 100644 --- a/drivers/clk/imx/clk-imx6sx.c +++ b/drivers/clk/imx/clk-imx6sx.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index fd60d1549f71..e0e4625aacd0 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 5b8a0c729f90..0ff3eb14d3af 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include diff --git a/drivers/clk/imx/clk.c b/drivers/clk/imx/clk.c index 1efed86217f7..588d1f45325d 100644 --- a/drivers/clk/imx/clk.c +++ b/drivers/clk/imx/clk.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include -- cgit v1.2.3