diff options
32 files changed, 897 insertions, 223 deletions
diff --git a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml index aa1df03ef4a6..df256ebcd366 100644 --- a/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml +++ b/Documentation/devicetree/bindings/clock/ingenic,cgu.yaml @@ -22,6 +22,7 @@ select: enum: - ingenic,jz4740-cgu - ingenic,jz4725b-cgu + - ingenic,jz4755-cgu - ingenic,jz4760-cgu - ingenic,jz4760b-cgu - ingenic,jz4770-cgu @@ -51,6 +52,7 @@ properties: - enum: - ingenic,jz4740-cgu - ingenic,jz4725b-cgu + - ingenic,jz4755-cgu - ingenic,jz4760-cgu - ingenic,jz4760b-cgu - ingenic,jz4770-cgu diff --git a/drivers/clk/clk-bulk.c b/drivers/clk/clk-bulk.c index e9e16425c739..826b3ff99433 100644 --- a/drivers/clk/clk-bulk.c +++ b/drivers/clk/clk-bulk.c @@ -96,9 +96,9 @@ static int __clk_bulk_get(struct device *dev, int num_clks, if (ret == -ENOENT && optional) continue; - if (ret != -EPROBE_DEFER) - dev_err(dev, "Failed to get clk '%s': %d\n", - clks[i].id, ret); + dev_err_probe(dev, ret, + "Failed to get clk '%s'\n", + clks[i].id); goto err; } } diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index ef9a2d44e40c..6350682f7e6d 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -603,28 +603,15 @@ of_clk_cdce925_get(struct of_phandle_args *clkspec, void *_data) return &data->clk[idx].hw; } -static void cdce925_regulator_disable(void *regulator) -{ - regulator_disable(regulator); -} - static int cdce925_regulator_enable(struct device *dev, const char *name) { - struct regulator *regulator; int err; - regulator = devm_regulator_get(dev, name); - if (IS_ERR(regulator)) - return PTR_ERR(regulator); - - err = regulator_enable(regulator); - if (err) { - dev_err(dev, "Failed to enable %s: %d\n", name, err); - return err; - } + err = devm_regulator_get_enable(dev, name); + if (err) + dev_err_probe(dev, err, "Failed to enable %s:\n", name); - return devm_add_action_or_reset(dev, cdce925_regulator_disable, - regulator); + return err; } /* The CDCE925 uses a funky way to read/write registers. Bulk mode is diff --git a/drivers/clk/clk-lmk04832.c b/drivers/clk/clk-lmk04832.c index f416f8bc2898..57485356de4c 100644 --- a/drivers/clk/clk-lmk04832.c +++ b/drivers/clk/clk-lmk04832.c @@ -12,12 +12,10 @@ #include <linux/bitfield.h> #include <linux/clk.h> #include <linux/clk-provider.h> -#include <linux/debugfs.h> #include <linux/device.h> #include <linux/gcd.h> #include <linux/gpio/consumer.h> #include <linux/module.h> -#include <linux/uaccess.h> #include <linux/regmap.h> #include <linux/spi/spi.h> @@ -177,14 +175,14 @@ enum lmk04832_device_types { }; /** - * lmk04832_device_info - Holds static device information that is specific to - * the chip revision + * struct lmk04832_device_info - Holds static device information that is + * specific to the chip revision * - * pid: Product Identifier - * maskrev: IC version identifier - * num_channels: Number of available output channels (clkout count) - * vco0_range: {min, max} of the VCO0 operating range (in MHz) - * vco1_range: {min, max} of the VCO1 operating range (in MHz) + * @pid: Product Identifier + * @maskrev: IC version identifier + * @num_channels: Number of available output channels (clkout count) + * @vco0_range: {min, max} of the VCO0 operating range (in MHz) + * @vco1_range: {min, max} of the VCO1 operating range (in MHz) */ struct lmk04832_device_info { u16 pid; @@ -282,7 +280,7 @@ static bool lmk04832_regmap_rd_regs(struct device *dev, unsigned int reg) default: return false; }; -}; +} static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg) { @@ -305,7 +303,7 @@ static bool lmk04832_regmap_wr_regs(struct device *dev, unsigned int reg) default: return false; }; -}; +} static const struct regmap_config regmap_config = { .name = "lmk04832", @@ -371,7 +369,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw, unsigned long prate) { struct lmk04832 *lmk = container_of(hw, struct lmk04832, vco); - unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7}; + const unsigned int pll2_p[] = {8, 2, 2, 3, 4, 5, 6, 7}; unsigned int pll2_n, p, pll2_r; unsigned int pll2_misc; unsigned long vco_rate; @@ -403,7 +401,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw, pll2_misc)) * pll2_n * pll2_p[p] / pll2_r; return vco_rate; -}; +} /** * lmk04832_check_vco_ranges - Check requested VCO frequency against VCO ranges @@ -414,7 +412,7 @@ static unsigned long lmk04832_vco_recalc_rate(struct clk_hw *hw, * The LMK04832 has 2 internal VCO, each with independent operating ranges. * Use the device_info structure to determine which VCO to use based on rate. * - * Returns VCO_MUX value or negative errno. + * Returns: VCO_MUX value or negative errno. */ static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate) { @@ -451,7 +449,7 @@ static int lmk04832_check_vco_ranges(struct lmk04832 *lmk, unsigned long rate) * * VCO = OSCin * 2 * PLL2_N * PLL2_P / PLL2_R * - * Returns vco rate or negative errno. + * Returns: vco rate or negative errno. */ static long lmk04832_calc_pll2_params(unsigned long prate, unsigned long rate, unsigned int *n, unsigned int *p, @@ -509,7 +507,7 @@ static long lmk04832_vco_round_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; return vco_rate; -}; +} static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) @@ -568,7 +566,7 @@ static int lmk04832_vco_set_rate(struct clk_hw *hw, unsigned long rate, return regmap_write(lmk->regmap, LMK04832_REG_PLL2_N_2, FIELD_GET(0x0000ff, n)); -}; +} static const struct clk_ops lmk04832_vco_ops = { .is_enabled = lmk04832_vco_is_enabled, @@ -633,7 +631,7 @@ static int lmk04832_register_vco(struct lmk04832 *lmk) static int lmk04832_clkout_set_ddly(struct lmk04832 *lmk, int id) { - int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0}; + const int dclk_div_adj[] = {0, 0, -2, -2, 0, 3, -1, 0}; unsigned int sclkx_y_ddly = 10; unsigned int dclkx_y_ddly; unsigned int dclkx_y_div; @@ -1063,7 +1061,7 @@ static unsigned long lmk04832_dclk_recalc_rate(struct clk_hw *hw, rate = DIV_ROUND_CLOSEST(prate, dclk_div); return rate; -}; +} static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate, unsigned long *prate) @@ -1085,7 +1083,7 @@ static long lmk04832_dclk_round_rate(struct clk_hw *hw, unsigned long rate, return -EINVAL; return dclk_rate; -}; +} static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) @@ -1147,7 +1145,7 @@ static int lmk04832_dclk_set_rate(struct clk_hw *hw, unsigned long rate, dev_err(lmk->dev, "SYNC sequence failed\n"); return ret; -}; +} static const struct clk_ops lmk04832_dclk_ops = { .is_enabled = lmk04832_dclk_is_enabled, @@ -1551,6 +1549,7 @@ static void lmk04832_remove(struct spi_device *spi) clk_disable_unprepare(lmk->oscin); of_clk_del_provider(spi->dev.of_node); } + static const struct spi_device_id lmk04832_id[] = { { "lmk04832", LMK04832 }, {} diff --git a/drivers/clk/clk-nomadik.c b/drivers/clk/clk-nomadik.c index 71fbe687fa7b..06245681dac7 100644 --- a/drivers/clk/clk-nomadik.c +++ b/drivers/clk/clk-nomadik.c @@ -138,7 +138,7 @@ out_put: } /** - * struct clk_pll1 - Nomadik PLL1 clock + * struct clk_pll - Nomadik PLL clock * @hw: corresponding clock hardware entry * @id: PLL instance: 1 or 2 */ diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c index 7ad2e6203bae..01e5a466897f 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -155,7 +155,7 @@ static const char * const eth_src[] = { "pll4_p", "pll3_q" }; -const struct clk_parent_data ethrx_src[] = { +static const struct clk_parent_data ethrx_src[] = { { .name = "ethck_k", .fw_name = "ETH_RX_CLK/ETH_REF_CLK" }, }; diff --git a/drivers/clk/clk-versaclock5.c b/drivers/clk/clk-versaclock5.c index 88689415aff9..e9737969170e 100644 --- a/drivers/clk/clk-versaclock5.c +++ b/drivers/clk/clk-versaclock5.c @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_platform.h> -#include <linux/rational.h> #include <linux/regmap.h> #include <linux/slab.h> diff --git a/drivers/clk/ingenic/Kconfig b/drivers/clk/ingenic/Kconfig index 898f1bc478c9..f80ac4f2992b 100644 --- a/drivers/clk/ingenic/Kconfig +++ b/drivers/clk/ingenic/Kconfig @@ -15,6 +15,16 @@ config INGENIC_CGU_JZ4740 If building for a JZ4740 SoC, you want to say Y here. +config INGENIC_CGU_JZ4755 + bool "Ingenic JZ4755 CGU driver" + default MACH_JZ4755 + select INGENIC_CGU_COMMON + help + Support the clocks provided by the CGU hardware on Ingenic JZ4755 + and compatible SoCs. + + If building for a JZ4755 SoC, you want to say Y here. + config INGENIC_CGU_JZ4725B bool "Ingenic JZ4725B CGU driver" default MACH_JZ4725B diff --git a/drivers/clk/ingenic/Makefile b/drivers/clk/ingenic/Makefile index 9edfaf4610b9..81d8e23c2636 100644 --- a/drivers/clk/ingenic/Makefile +++ b/drivers/clk/ingenic/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-$(CONFIG_INGENIC_CGU_COMMON) += cgu.o pm.o obj-$(CONFIG_INGENIC_CGU_JZ4740) += jz4740-cgu.o +obj-$(CONFIG_INGENIC_CGU_JZ4755) += jz4755-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4725B) += jz4725b-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4760) += jz4760-cgu.o obj-$(CONFIG_INGENIC_CGU_JZ4770) += jz4770-cgu.o diff --git a/drivers/clk/ingenic/cgu.c b/drivers/clk/ingenic/cgu.c index 861c50d6cb24..1f7ba30f5a1b 100644 --- a/drivers/clk/ingenic/cgu.c +++ b/drivers/clk/ingenic/cgu.c @@ -83,7 +83,7 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) const struct ingenic_cgu_clk_info *clk_info = to_clk_info(ingenic_clk); struct ingenic_cgu *cgu = ingenic_clk->cgu; const struct ingenic_cgu_pll_info *pll_info; - unsigned m, n, od_enc, od; + unsigned m, n, od, od_enc = 0; bool bypass; u32 ctl; @@ -96,8 +96,11 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) m += pll_info->m_offset; n = (ctl >> pll_info->n_shift) & GENMASK(pll_info->n_bits - 1, 0); n += pll_info->n_offset; - od_enc = ctl >> pll_info->od_shift; - od_enc &= GENMASK(pll_info->od_bits - 1, 0); + + if (pll_info->od_bits > 0) { + od_enc = ctl >> pll_info->od_shift; + od_enc &= GENMASK(pll_info->od_bits - 1, 0); + } if (pll_info->bypass_bit >= 0) { ctl = readl(cgu->base + pll_info->bypass_reg); @@ -108,11 +111,15 @@ ingenic_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) return parent_rate; } - for (od = 0; od < pll_info->od_max; od++) { + for (od = 0; od < pll_info->od_max; od++) if (pll_info->od_encoding[od] == od_enc) break; - } - BUG_ON(od == pll_info->od_max); + + /* if od_max = 0, od_bits should be 0 and od is fixed to 1. */ + if (pll_info->od_max == 0) + BUG_ON(pll_info->od_bits != 0); + else + BUG_ON(od == pll_info->od_max); od++; return div_u64((u64)parent_rate * m * pll_info->rate_multiplier, @@ -182,6 +189,9 @@ static inline int ingenic_pll_check_stable(struct ingenic_cgu *cgu, { u32 ctl; + if (pll_info->stable_bit < 0) + return 0; + return readl_poll_timeout(cgu->base + pll_info->reg, ctl, ctl & BIT(pll_info->stable_bit), 0, 100 * USEC_PER_MSEC); @@ -215,13 +225,18 @@ ingenic_pll_set_rate(struct clk_hw *hw, unsigned long req_rate, ctl &= ~(GENMASK(pll_info->n_bits - 1, 0) << pll_info->n_shift); ctl |= (n - pll_info->n_offset) << pll_info->n_shift; - ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift); - ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; + if (pll_info->od_bits > 0) { + ctl &= ~(GENMASK(pll_info->od_bits - 1, 0) << pll_info->od_shift); + ctl |= pll_info->od_encoding[od - 1] << pll_info->od_shift; + } writel(ctl, cgu->base + pll_info->reg); + if (pll_info->set_rate_hook) + pll_info->set_rate_hook(pll_info, rate, parent_rate); + /* If the PLL is enabled, verify that it's stable */ - if (ctl & BIT(pll_info->enable_bit)) + if (pll_info->enable_bit >= 0 && (ctl & BIT(pll_info->enable_bit))) ret = ingenic_pll_check_stable(cgu, pll_info); spin_unlock_irqrestore(&cgu->lock, flags); @@ -239,6 +254,9 @@ static int ingenic_pll_enable(struct clk_hw *hw) int ret; u32 ctl; + if (pll_info->enable_bit < 0) + return 0; + spin_lock_irqsave(&cgu->lock, flags); if (pll_info->bypass_bit >= 0) { ctl = readl(cgu->base + pll_info->bypass_reg); @@ -269,6 +287,9 @@ static void ingenic_pll_disable(struct clk_hw *hw) unsigned long flags; u32 ctl; + if (pll_info->enable_bit < 0) + return; + spin_lock_irqsave(&cgu->lock, flags); ctl = readl(cgu->base + pll_info->reg); @@ -286,6 +307,9 @@ static int ingenic_pll_is_enabled(struct clk_hw *hw) const struct ingenic_cgu_pll_info *pll_info = &clk_info->pll; u32 ctl; + if (pll_info->enable_bit < 0) + return true; + ctl = readl(cgu->base + pll_info->reg); return !!(ctl & BIT(pll_info->enable_bit)); diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index 147b7df0d657..99da9bd86e63 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -33,7 +33,8 @@ * @od_shift: the number of bits to shift the post-VCO divider value by (ie. * the index of the lowest bit of the post-VCO divider value in * the PLL's control register) - * @od_bits: the size of the post-VCO divider field in bits + * @od_bits: the size of the post-VCO divider field in bits, or 0 if no + * OD field exists (then the OD is fixed to 1) * @od_max: the maximum post-VCO divider value * @od_encoding: a pointer to an array mapping post-VCO divider values to * their encoded values in the PLL control register, or -1 for @@ -41,8 +42,12 @@ * @bypass_reg: the offset of the bypass control register within the CGU * @bypass_bit: the index of the bypass bit in the PLL control register, or * -1 if there is no bypass bit - * @enable_bit: the index of the enable bit in the PLL control register - * @stable_bit: the index of the stable bit in the PLL control register + * @enable_bit: the index of the enable bit in the PLL control register, or + * -1 if there is no enable bit (ie, the PLL is always on) + * @stable_bit: the index of the stable bit in the PLL control register, or + * -1 if there is no stable bit + * @set_rate_hook: hook called immediately after updating the CGU register, + * before releasing the spinlock */ struct ingenic_cgu_pll_info { unsigned reg; @@ -53,11 +58,13 @@ struct ingenic_cgu_pll_info { u8 od_shift, od_bits, od_max; unsigned bypass_reg; s8 bypass_bit; - u8 enable_bit; - u8 stable_bit; + s8 enable_bit; + s8 stable_bit; void (*calc_m_n_od)(const struct ingenic_cgu_pll_info *pll_info, unsigned long rate, unsigned long parent_rate, unsigned int *m, unsigned int *n, unsigned int *od); + void (*set_rate_hook)(const struct ingenic_cgu_pll_info *pll_info, + unsigned long rate, unsigned long parent_rate); }; /** diff --git a/drivers/clk/ingenic/jz4755-cgu.c b/drivers/clk/ingenic/jz4755-cgu.c new file mode 100644 index 000000000000..f2c2d848dab7 --- /dev/null +++ b/drivers/clk/ingenic/jz4755-cgu.c @@ -0,0 +1,346 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Ingenic JZ4755 SoC CGU driver + * Heavily based on JZ4725b CGU driver + * + * Copyright (C) 2022 Siarhei Volkau + * Author: Siarhei Volkau <[email protected]> + */ + +#include <linux/clk-provider.h> +#include <linux/delay.h> +#include <linux/of.h> + +#include <dt-bindings/clock/ingenic,jz4755-cgu.h> + +#include "cgu.h" +#include "pm.h" + +/* CGU register offsets */ +#define CGU_REG_CPCCR 0x00 +#define CGU_REG_CPPCR 0x10 +#define CGU_REG_CLKGR 0x20 +#define CGU_REG_OPCR 0x24 +#define CGU_REG_I2SCDR 0x60 +#define CGU_REG_LPCDR 0x64 +#define CGU_REG_MSCCDR 0x68 +#define CGU_REG_SSICDR 0x74 +#define CGU_REG_CIMCDR 0x7C + +static struct ingenic_cgu *cgu; + +static const s8 pll_od_encoding[4] = { + 0x0, 0x1, -1, 0x3, +}; + +static const u8 jz4755_cgu_cpccr_div_table[] = { + 1, 2, 3, 4, 6, 8, +}; + +static const u8 jz4755_cgu_pll_half_div_table[] = { + 2, 1, +}; + +static const struct ingenic_cgu_clk_info jz4755_cgu_clocks[] = { + + /* External clocks */ + + [JZ4755_CLK_EXT] = { "ext", CGU_CLK_EXT }, + [JZ4755_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT }, + + [JZ4755_CLK_PLL] = { + "pll", CGU_CLK_PLL, + .parents = { JZ4755_CLK_EXT, }, + .pll = { + .reg = CGU_REG_CPPCR, + .rate_multiplier = 1, + .m_shift = 23, + .m_bits = 9, + .m_offset = 2, + .n_shift = 18, + .n_bits = 5, + .n_offset = 2, + .od_shift = 16, + .od_bits = 2, + .od_max = 4, + .od_encoding = pll_od_encoding, + .stable_bit = 10, + .bypass_reg = CGU_REG_CPPCR, + .bypass_bit = 9, + .enable_bit = 8, + }, + }, + + /* Muxes & dividers */ + + [JZ4755_CLK_PLL_HALF] = { + "pll half", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 21, 1, 1, -1, -1, -1, 0, + jz4755_cgu_pll_half_div_table, + }, + }, + + [JZ4755_CLK_EXT_HALF] = { + "ext half", CGU_CLK_DIV, + .parents = { JZ4755_CLK_EXT, }, + .div = { + CGU_REG_CPCCR, 30, 1, 1, -1, -1, -1, 0, + NULL, + }, + }, + + [JZ4755_CLK_CCLK] = { + "cclk", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0, + jz4755_cgu_cpccr_div_table, + }, + }, + + [JZ4755_CLK_H0CLK] = { + "hclk", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0, + jz4755_cgu_cpccr_div_table, + }, + }, + + [JZ4755_CLK_PCLK] = { + "pclk", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0, + jz4755_cgu_cpccr_div_table, + }, + }, + + [JZ4755_CLK_MCLK] = { + "mclk", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0, + jz4755_cgu_cpccr_div_table, + }, + }, + + [JZ4755_CLK_H1CLK] = { + "h1clk", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL, }, + .div = { + CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0, + jz4755_cgu_cpccr_div_table, + }, + }, + + [JZ4755_CLK_UDC] = { + "udc", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, }, + .mux = { CGU_REG_CPCCR, 29, 1 }, + .div = { CGU_REG_CPCCR, 23, 1, 6, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 10 }, + }, + + [JZ4755_CLK_LCD] = { + "lcd", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4755_CLK_PLL_HALF, }, + .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 9 }, + }, + + [JZ4755_CLK_MMC] = { + "mmc", CGU_CLK_DIV, + .parents = { JZ4755_CLK_PLL_HALF, }, + .div = { CGU_REG_MSCCDR, 0, 1, 5, -1, -1, -1 }, + }, + + [JZ4755_CLK_I2S] = { + "i2s", CGU_CLK_MUX | CGU_CLK_DIV, + .parents = { JZ4755_CLK_EXT_HALF, JZ4755_CLK_PLL_HALF, }, + .mux = { CGU_REG_CPCCR, 31, 1 }, + .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 }, + }, + + [JZ4755_CLK_SPI] = { + "spi", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4755_CLK_PLL_HALF, }, + .div = { CGU_REG_SSICDR, 0, 1, 4, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 4 }, + }, + + [JZ4755_CLK_TVE] = { + "tve", CGU_CLK_MUX | CGU_CLK_GATE, + .parents = { JZ4755_CLK_LCD, JZ4755_CLK_EXT, }, + .mux = { CGU_REG_LPCDR, 31, 1 }, + .gate = { CGU_REG_CLKGR, 18 }, + }, + + [JZ4755_CLK_RTC] = { + "rtc", CGU_CLK_MUX | CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT512, JZ4755_CLK_OSC32K, }, + .mux = { CGU_REG_OPCR, 2, 1}, + .gate = { CGU_REG_CLKGR, 2 }, + }, + + [JZ4755_CLK_CIM] = { + "cim", CGU_CLK_DIV | CGU_CLK_GATE, + .parents = { JZ4755_CLK_PLL_HALF, }, + .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 }, + .gate = { CGU_REG_CLKGR, 8 }, + }, + + /* Gate-only clocks */ + + [JZ4755_CLK_UART0] = { + "uart0", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 0 }, + }, + + [JZ4755_CLK_UART1] = { + "uart1", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 14 }, + }, + + [JZ4755_CLK_UART2] = { + "uart2", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 15 }, + }, + + [JZ4755_CLK_ADC] = { + "adc", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 7 }, + }, + + [JZ4755_CLK_AIC] = { + "aic", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 5 }, + }, + + [JZ4755_CLK_I2C] = { + "i2c", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_CLKGR, 3 }, + }, + + [JZ4755_CLK_BCH] = { + "bch", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 11 }, + }, + + [JZ4755_CLK_TCU] = { + "tcu", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT, }, + .gate = { CGU_REG_CLKGR, 1 }, + }, + + [JZ4755_CLK_DMA] = { + "dma", CGU_CLK_GATE, + .parents = { JZ4755_CLK_PCLK, }, + .gate = { CGU_REG_CLKGR, 12 }, + }, + + [JZ4755_CLK_MMC0] = { + "mmc0", CGU_CLK_GATE, + .parents = { JZ4755_CLK_MMC, }, + .gate = { CGU_REG_CLKGR, 6 }, + }, + + [JZ4755_CLK_MMC1] = { + "mmc1", CGU_CLK_GATE, + .parents = { JZ4755_CLK_MMC, }, + .gate = { CGU_REG_CLKGR, 16 }, + }, + + [JZ4755_CLK_AUX_CPU] = { + "aux_cpu", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 24 }, + }, + + [JZ4755_CLK_AHB1] = { + "ahb1", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 23 }, + }, + + [JZ4755_CLK_IDCT] = { + "idct", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 22 }, + }, + + [JZ4755_CLK_DB] = { + "db", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 21 }, + }, + + [JZ4755_CLK_ME] = { + "me", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 20 }, + }, + + [JZ4755_CLK_MC] = { + "mc", CGU_CLK_GATE, + .parents = { JZ4755_CLK_H1CLK, }, + .gate = { CGU_REG_CLKGR, 19 }, + }, + + [JZ4755_CLK_TSSI] = { + "tssi", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF/* not sure */, }, + .gate = { CGU_REG_CLKGR, 17 }, + }, + + [JZ4755_CLK_IPU] = { + "ipu", CGU_CLK_GATE, + .parents = { JZ4755_CLK_PLL_HALF/* not sure */, }, + .gate = { CGU_REG_CLKGR, 13 }, + }, + + [JZ4755_CLK_EXT512] = { + "ext/512", CGU_CLK_FIXDIV, + .parents = { JZ4755_CLK_EXT, }, + + .fixdiv = { 512 }, + }, + + [JZ4755_CLK_UDC_PHY] = { + "udc_phy", CGU_CLK_GATE, + .parents = { JZ4755_CLK_EXT_HALF, }, + .gate = { CGU_REG_OPCR, 6, true }, + }, +}; + +static void __init jz4755_cgu_init(struct device_node *np) +{ + int retval; + + cgu = ingenic_cgu_new(jz4755_cgu_clocks, + ARRAY_SIZE(jz4755_cgu_clocks), np); + if (!cgu) { + pr_err("%s: failed to initialise CGU\n", __func__); + return; + } + + retval = ingenic_cgu_register_clocks(cgu); + if (retval) + pr_err("%s: failed to register CGU Clocks\n", __func__); + + ingenic_cgu_register_syscore_ops(cgu); +} +/* + * CGU has some children devices, this is useful for probing children devices + * in the case where the device node is compatible with "simple-mfd". + */ +CLK_OF_DECLARE_DRIVER(jz4755_cgu, "ingenic,jz4755-cgu", jz4755_cgu_init); diff --git a/drivers/clk/ingenic/x1000-cgu.c b/drivers/clk/ingenic/x1000-cgu.c index b2ce3fb83f54..feb03eed4fe8 100644 --- a/drivers/clk/ingenic/x1000-cgu.c +++ b/drivers/clk/ingenic/x1000-cgu.c @@ -8,6 +8,7 @@ #include <linux/delay.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/rational.h> #include <dt-bindings/clock/ingenic,x1000-cgu.h> @@ -168,6 +169,38 @@ static const struct clk_ops x1000_otg_phy_ops = { .is_enabled = x1000_usb_phy_is_enabled, }; +static void +x1000_i2spll_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info, + unsigned long rate, unsigned long parent_rate, + unsigned int *pm, unsigned int *pn, unsigned int *pod) +{ + const unsigned long m_max = GENMASK(pll_info->m_bits - 1, 0); + const unsigned long n_max = GENMASK(pll_info->n_bits - 1, 0); + unsigned long m, n; + + rational_best_approximation(rate, parent_rate, m_max, n_max, &m, &n); + + /* n should not be less than 2*m */ + if (n < 2 * m) + n = 2 * m; + + *pm = m; + *pn = n; + *pod = 1; +} + +static void +x1000_i2spll_set_rate_hook(const struct ingenic_cgu_pll_info *pll_info, + unsigned long rate, unsigned long parent_rate) +{ + /* + * Writing 0 causes I2SCDR1.I2SDIV_D to be automatically recalculated + * based on the current value of I2SCDR.I2SDIV_N, which is needed for + * the divider to function correctly. + */ + writel(0, cgu->base + CGU_REG_I2SCDR1); +} + static const s8 pll_od_encoding[8] = { 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3, }; @@ -183,7 +216,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_APLL] = { "apll", CGU_CLK_PLL, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .pll = { .reg = CGU_REG_APLL, .rate_multiplier = 1, @@ -206,7 +239,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_MPLL] = { "mpll", CGU_CLK_PLL, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .pll = { .reg = CGU_REG_MPLL, .rate_multiplier = 1, @@ -256,7 +289,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { * system; mark it critical. */ .flags = CLK_IS_CRITICAL, - .parents = { X1000_CLK_CPUMUX, -1, -1, -1 }, + .parents = { X1000_CLK_CPUMUX }, .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 }, .gate = { CGU_REG_CLKGR, 30 }, }, @@ -268,7 +301,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { * disabling it or any parent clocks will hang the system. */ .flags = CLK_IS_CRITICAL, - .parents = { X1000_CLK_CPUMUX, -1, -1, -1 }, + .parents = { X1000_CLK_CPUMUX }, .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 }, }, @@ -287,13 +320,13 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_AHB2] = { "ahb2", CGU_CLK_DIV, - .parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 }, + .parents = { X1000_CLK_AHB2PMUX }, .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 }, }, [X1000_CLK_PCLK] = { "pclk", CGU_CLK_DIV | CGU_CLK_GATE, - .parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 }, + .parents = { X1000_CLK_AHB2PMUX }, .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 }, .gate = { CGU_REG_CLKGR, 28 }, }, @@ -319,6 +352,37 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { .gate = { CGU_REG_CLKGR, 25 }, }, + [X1000_CLK_I2SPLLMUX] = { + "i2s_pll_mux", CGU_CLK_MUX, + .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, + .mux = { CGU_REG_I2SCDR, 31, 1 }, + }, + + [X1000_CLK_I2SPLL] = { + "i2s_pll", CGU_CLK_PLL, + .parents = { X1000_CLK_I2SPLLMUX }, + .pll = { + .reg = CGU_REG_I2SCDR, + .rate_multiplier = 1, + .m_shift = 13, + .m_bits = 9, + .n_shift = 0, + .n_bits = 13, + .calc_m_n_od = x1000_i2spll_calc_m_n_od, + .set_rate_hook = x1000_i2spll_set_rate_hook, + }, + }, + + [X1000_CLK_I2S] = { + "i2s", CGU_CLK_MUX, + .parents = { X1000_CLK_EXCLK, -1, -1, X1000_CLK_I2SPLL }, + /* + * NOTE: the mux is at bit 30; bit 29 enables the M/N divider. + * Therefore, the divider is disabled when EXCLK is selected. + */ + .mux = { CGU_REG_I2SCDR, 29, 2 }, + }, + [X1000_CLK_LCD] = { "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE, .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, @@ -329,13 +393,13 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_MSCMUX] = { "msc_mux", CGU_CLK_MUX, - .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL}, + .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, .mux = { CGU_REG_MSC0CDR, 31, 1 }, }, [X1000_CLK_MSC0] = { "msc0", CGU_CLK_DIV | CGU_CLK_GATE, - .parents = { X1000_CLK_MSCMUX, -1, -1, -1 }, + .parents = { X1000_CLK_MSCMUX }, .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR, 4 }, }, @@ -349,8 +413,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_OTG] = { "otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX, - .parents = { X1000_CLK_EXCLK, -1, - X1000_CLK_APLL, X1000_CLK_MPLL }, + .parents = { X1000_CLK_EXCLK, -1, X1000_CLK_APLL, X1000_CLK_MPLL }, .mux = { CGU_REG_USBCDR, 30, 2 }, .div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 }, .gate = { CGU_REG_CLKGR, 3 }, @@ -358,7 +421,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_SSIPLL] = { "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV, - .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL, -1, -1 }, + .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL }, .mux = { CGU_REG_SSICDR, 31, 1 }, .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 }, }, @@ -371,7 +434,7 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_SSIMUX] = { "ssi_mux", CGU_CLK_MUX, - .parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2, -1, -1 }, + .parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2 }, .mux = { CGU_REG_SSICDR, 30, 1 }, }, @@ -392,79 +455,85 @@ static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = { [X1000_CLK_EMC] = { "emc", CGU_CLK_GATE, - .parents = { X1000_CLK_AHB2, -1, -1, -1 }, + .parents = { X1000_CLK_AHB2 }, .gate = { CGU_REG_CLKGR, 0 }, }, [X1000_CLK_EFUSE] = { "efuse", CGU_CLK_GATE, - .parents = { X1000_CLK_AHB2, -1, -1, -1 }, + .parents = { X1000_CLK_AHB2 }, .gate = { CGU_REG_CLKGR, 1 }, }, [X1000_CLK_SFC] = { "sfc", CGU_CLK_GATE, - .parents = { X1000_CLK_SSIPLL, -1, -1, -1 }, + .parents = { X1000_CLK_SSIPLL }, .gate = { CGU_REG_CLKGR, 2 }, }, [X1000_CLK_I2C0] = { "i2c0", CGU_CLK_GATE, - .parents = { X1000_CLK_PCLK, -1, -1, -1 }, + .parents = { X1000_CLK_PCLK }, .gate = { CGU_REG_CLKGR, 7 }, }, [X1000_CLK_I2C1] = { "i2c1", CGU_CLK_GATE, - .parents = { X1000_CLK_PCLK, -1, -1, -1 }, + .parents = { X1000_CLK_PCLK }, .gate = { CGU_REG_CLKGR, 8 }, }, [X1000_CLK_I2C2] = { "i2c2", CGU_CLK_GATE, - .parents = { X1000_CLK_PCLK, -1, -1, -1 }, + .parents = { X1000_CLK_PCLK }, .gate = { CGU_REG_CLKGR, 9 }, }, + [X1000_CLK_AIC] = { + "aic", CGU_CLK_GATE, + .parents = { X1000_CLK_EXCLK }, + .gate = { CGU_REG_CLKGR, 11 }, + }, + [X1000_CLK_UART0] = { "uart0", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .gate = { CGU_REG_CLKGR, 14 }, }, [X1000_CLK_UART1] = { "uart1", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK}, .gate = { CGU_REG_CLKGR, 15 }, }, [X1000_CLK_UART2] = { "uart2", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .gate = { CGU_REG_CLKGR, 16 }, }, [X1000_CLK_TCU] = { "tcu", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .gate = { CGU_REG_CLKGR, 18 }, }, [X1000_CLK_SSI] = { "ssi", CGU_CLK_GATE, - .parents = { X1000_CLK_SSIMUX, -1, -1, -1 }, + .parents = { X1000_CLK_SSIMUX }, .gate = { CGU_REG_CLKGR, 19 }, }, [X1000_CLK_OST] = { "ost", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .gate = { CGU_REG_CLKGR, 20 }, }, [X1000_CLK_PDMA] = { "pdma", CGU_CLK_GATE, - .parents = { X1000_CLK_EXCLK, -1, -1, -1 }, + .parents = { X1000_CLK_EXCLK }, .gate = { CGU_REG_CLKGR, 21 }, }, }; diff --git a/drivers/clk/keystone/syscon-clk.c b/drivers/clk/keystone/syscon-clk.c index 19198325b909..5d7cc83682da 100644 --- a/drivers/clk/keystone/syscon-clk.c +++ b/drivers/clk/keystone/syscon-clk.c @@ -102,12 +102,9 @@ static int ti_syscon_gate_clk_probe(struct platform_device *pdev) return -EINVAL; regmap = syscon_node_to_regmap(dev->of_node); - if (IS_ERR(regmap)) { - if (PTR_ERR(regmap) == -EPROBE_DEFER) - return -EPROBE_DEFER; - dev_err(dev, "failed to find parent regmap\n"); - return PTR_ERR(regmap); - } + if (IS_ERR(regmap)) + return dev_err_probe(dev, PTR_ERR(regmap), + "failed to find parent regmap\n"); num_clks = 0; for (p = data; p->name; p++) diff --git a/drivers/clk/meson/clk-pll.c b/drivers/clk/meson/clk-pll.c index 9e55617bc3b4..4b96e1590224 100644 --- a/drivers/clk/meson/clk-pll.c +++ b/drivers/clk/meson/clk-pll.c @@ -32,7 +32,6 @@ #include <linux/io.h> #include <linux/math64.h> #include <linux/module.h> -#include <linux/rational.h> #include "clk-regmap.h" #include "clk-pll.h" diff --git a/drivers/clk/mstar/Kconfig b/drivers/clk/mstar/Kconfig index de37e1bce2d2..b9bcb5e02814 100644 --- a/drivers/clk/mstar/Kconfig +++ b/drivers/clk/mstar/Kconfig @@ -1,4 +1,11 @@ # SPDX-License-Identifier: GPL-2.0-only +config MSTAR_MSC313_CPUPLL + bool "MStar CPUPLL driver" + depends on ARCH_MSTARV7 || COMPILE_TEST + default ARCH_MSTARV7 + help + Support for the CPU PLL present on MStar/Sigmastar SoCs. + config MSTAR_MSC313_MPLL bool "MStar MPLL driver" depends on ARCH_MSTARV7 || COMPILE_TEST diff --git a/drivers/clk/mstar/Makefile b/drivers/clk/mstar/Makefile index f8dcd25ede1d..17d97eedcd36 100644 --- a/drivers/clk/mstar/Makefile +++ b/drivers/clk/mstar/Makefile @@ -3,4 +3,5 @@ # Makefile for mstar specific clk # +obj-$(CONFIG_MSTAR_MSC313_CPUPLL) += clk-msc313-cpupll.o obj-$(CONFIG_MSTAR_MSC313_MPLL) += clk-msc313-mpll.o diff --git a/drivers/clk/mstar/clk-msc313-cpupll.c b/drivers/clk/mstar/clk-msc313-cpupll.c new file mode 100644 index 000000000000..a93e2dba09d3 --- /dev/null +++ b/drivers/clk/mstar/clk-msc313-cpupll.c @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2019 Daniel Palmer <[email protected]> + */ + +#include <linux/clk-provider.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/of_address.h> +#include <linux/platform_device.h> + +/* + * This IP is not documented outside of the messy vendor driver. + * Below is what we think the registers look like based on looking at + * the vendor code and poking at the hardware: + * + * 0x140 -- LPF low. Seems to store one half of the clock transition + * 0x144 / + * 0x148 -- LPF high. Seems to store one half of the clock transition + * 0x14c / + * 0x150 -- vendor code says "toggle lpf enable" + * 0x154 -- mu? + * 0x15c -- lpf_update_count? + * 0x160 -- vendor code says "switch to LPF". Clock source config? Register bank? + * 0x164 -- vendor code says "from low to high" which seems to mean transition from LPF low to + * LPF high. + * 0x174 -- Seems to be the PLL lock status bit + * 0x180 -- Seems to be the current frequency, this might need to be populated by software? + * 0x184 / The vendor driver uses these to set the initial value of LPF low + * + * Frequency seems to be calculated like this: + * (parent clock (432mhz) / register_magic_value) * 16 * 524288 + * Only the lower 24 bits of the resulting value will be used. In addition, the + * PLL doesn't seem to be able to lock on frequencies lower than 220 MHz, as + * divisor 0xfb586f (220 MHz) works but 0xfb7fff locks up. + * + * Vendor values: + * frequency - register value + * + * 400000000 - 0x0067AE14 + * 600000000 - 0x00451EB8, + * 800000000 - 0x0033D70A, + * 1000000000 - 0x002978d4, + */ + +#define REG_LPF_LOW_L 0x140 +#define REG_LPF_LOW_H 0x144 +#define REG_LPF_HIGH_BOTTOM 0x148 +#define REG_LPF_HIGH_TOP 0x14c +#define REG_LPF_TOGGLE 0x150 +#define REG_LPF_MYSTERYTWO 0x154 +#define REG_LPF_UPDATE_COUNT 0x15c +#define REG_LPF_MYSTERYONE 0x160 +#define REG_LPF_TRANSITIONCTRL 0x164 +#define REG_LPF_LOCK 0x174 +#define REG_CURRENT 0x180 + +#define LPF_LOCK_TIMEOUT 100000000 + +#define MULTIPLIER_1 16 +#define MULTIPLIER_2 524288 +#define MULTIPLIER (MULTIPLIER_1 * MULTIPLIER_2) + +struct msc313_cpupll { + void __iomem *base; + struct clk_hw clk_hw; +}; + +#define to_cpupll(_hw) container_of(_hw, struct msc313_cpupll, clk_hw) + +static u32 msc313_cpupll_reg_read32(struct msc313_cpupll *cpupll, unsigned int reg) +{ + u32 value; + + value = ioread16(cpupll->base + reg + 4) << 16; + value |= ioread16(cpupll->base + reg); + + return value; +} + +static void msc313_cpupll_reg_write32(struct msc313_cpupll *cpupll, unsigned int reg, u32 value) +{ + u16 l = value & 0xffff, h = (value >> 16) & 0xffff; + + iowrite16(l, cpupll->base + reg); + iowrite16(h, cpupll->base + reg + 4); +} + +static void msc313_cpupll_setfreq(struct msc313_cpupll *cpupll, u32 regvalue) +{ + ktime_t timeout; + + msc313_cpupll_reg_write32(cpupll, REG_LPF_HIGH_BOTTOM, regvalue); + + iowrite16(0x1, cpupll->base + REG_LPF_MYSTERYONE); + iowrite16(0x6, cpupll->base + REG_LPF_MYSTERYTWO); + iowrite16(0x8, cpupll->base + REG_LPF_UPDATE_COUNT); + iowrite16(BIT(12), cpupll->base + REG_LPF_TRANSITIONCTRL); + + iowrite16(0, cpupll->base + REG_LPF_TOGGLE); + iowrite16(1, cpupll->base + REG_LPF_TOGGLE); + + timeout = ktime_add_ns(ktime_get(), LPF_LOCK_TIMEOUT); + while (!(ioread16(cpupll->base + REG_LPF_LOCK))) { + if (ktime_after(ktime_get(), timeout)) { + pr_err("timeout waiting for LPF_LOCK\n"); + return; + } + cpu_relax(); + } + + iowrite16(0, cpupll->base + REG_LPF_TOGGLE); + + msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, regvalue); +} + +static unsigned long msc313_cpupll_frequencyforreg(u32 reg, unsigned long parent_rate) +{ + unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER; + + if (prescaled == 0 || reg == 0) + return 0; + return DIV_ROUND_DOWN_ULL(prescaled, reg); +} + +static u32 msc313_cpupll_regforfrequecy(unsigned long rate, unsigned long parent_rate) +{ + unsigned long long prescaled = ((unsigned long long)parent_rate) * MULTIPLIER; + + if (prescaled == 0 || rate == 0) + return 0; + return DIV_ROUND_UP_ULL(prescaled, rate); +} + +static unsigned long msc313_cpupll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) +{ + struct msc313_cpupll *cpupll = to_cpupll(hw); + + return msc313_cpupll_frequencyforreg(msc313_cpupll_reg_read32(cpupll, REG_LPF_LOW_L), + parent_rate); +} + +static long msc313_cpupll_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + u32 reg = msc313_cpupll_regforfrequecy(rate, *parent_rate); + long rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + + /* + * This is my poor attempt at making sure the resulting + * rate doesn't overshoot the requested rate. + */ + for (; rounded >= rate && reg > 0; reg--) + rounded = msc313_cpupll_frequencyforreg(reg, *parent_rate); + + return rounded; +} + +static int msc313_cpupll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) +{ + struct msc313_cpupll *cpupll = to_cpupll(hw); + u32 reg = msc313_cpupll_regforfrequecy(rate, parent_rate); + + msc313_cpupll_setfreq(cpupll, reg); + + return 0; +} + +static const struct clk_ops msc313_cpupll_ops = { + .recalc_rate = msc313_cpupll_recalc_rate, + .round_rate = msc313_cpupll_round_rate, + .set_rate = msc313_cpupll_set_rate, +}; + +static const struct of_device_id msc313_cpupll_of_match[] = { + { .compatible = "mstar,msc313-cpupll" }, + {} +}; + +static int msc313_cpupll_probe(struct platform_device *pdev) +{ + struct clk_init_data clk_init = {}; + struct clk_parent_data cpupll_parent = { .index = 0 }; + struct device *dev = &pdev->dev; + struct msc313_cpupll *cpupll; + int ret; + + cpupll = devm_kzalloc(&pdev->dev, sizeof(*cpupll), GFP_KERNEL); + if (!cpupll) + return -ENOMEM; + + cpupll->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(cpupll->base)) + return PTR_ERR(cpupll->base); + + /* LPF might not contain the current frequency so fix that up */ + msc313_cpupll_reg_write32(cpupll, REG_LPF_LOW_L, + msc313_cpupll_reg_read32(cpupll, REG_CURRENT)); + + clk_init.name = dev_name(dev); + clk_init.ops = &msc313_cpupll_ops; + clk_init.parent_data = &cpupll_parent; + clk_init.num_parents = 1; + cpupll->clk_hw.init = &clk_init; + + ret = devm_clk_hw_register(dev, &cpupll->clk_hw); + if (ret) + return ret; + + return devm_of_clk_add_hw_provider(&pdev->dev, of_clk_hw_simple_get, &cpupll->clk_hw); +} + +static struct platform_driver msc313_cpupll_driver = { + .driver = { + .name = "mstar-msc313-cpupll", + .of_match_table = msc313_cpupll_of_match, + }, + .probe = msc313_cpupll_probe, +}; +builtin_platform_driver(msc313_cpupll_driver); diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c index e63d4f20b479..398c427b8e81 100644 --- a/drivers/clk/rockchip/clk.c +++ b/drivers/clk/rockchip/clk.c @@ -21,7 +21,6 @@ #include <linux/mfd/syscon.h> #include <linux/regmap.h> #include <linux/reboot.h> -#include <linux/rational.h> #include "../clk-fractional-divider.h" #include "clk.h" diff --git a/drivers/clk/samsung/clk-exynos5-subcmu.c b/drivers/clk/samsung/clk-exynos5-subcmu.c index 65c82d922b05..96d74bc250e5 100644 --- a/drivers/clk/samsung/clk-exynos5-subcmu.c +++ b/drivers/clk/samsung/clk-exynos5-subcmu.c @@ -47,10 +47,10 @@ static void exynos5_subcmu_defer_gate(struct samsung_clk_provider *ctx, /* * Pass the needed clock provider context and register sub-CMU clocks * - * NOTE: This function has to be called from the main, OF_CLK_DECLARE- + * NOTE: This function has to be called from the main, CLK_OF_DECLARE- * initialized clock provider driver. This happens very early during boot * process. Then this driver, during core_initcall registers two platform - * drivers: one which binds to the same device-tree node as OF_CLK_DECLARE + * drivers: one which binds to the same device-tree node as CLK_OF_DECLARE * driver and second, for handling its per-domain child-devices. Those * platform drivers are bound to their devices a bit later in arch_initcall, * when OF-core populates all device-tree nodes. diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index fe383471c5f0..0ff28938943f 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1583,6 +1583,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, if (ret) { pr_err("%s: failed to register pll clock %s : %d\n", __func__, pll_clk->name, ret); + kfree(pll->rate_table); kfree(pll); return; } diff --git a/drivers/clk/socfpga/clk-gate.c b/drivers/clk/socfpga/clk-gate.c index 53d6e3ec4309..c94b59b80dd4 100644 --- a/drivers/clk/socfpga/clk-gate.c +++ b/drivers/clk/socfpga/clk-gate.c @@ -188,8 +188,10 @@ void __init socfpga_gate_init(struct device_node *node) return; ops = kmemdup(&gateclk_ops, sizeof(gateclk_ops), GFP_KERNEL); - if (WARN_ON(!ops)) + if (WARN_ON(!ops)) { + kfree(socfpga_clk); return; + } rc = of_property_read_u32_array(node, "clk-gate", clk_gate, 2); if (rc) @@ -243,6 +245,7 @@ void __init socfpga_gate_init(struct device_node *node) err = clk_hw_register(NULL, hw_clk); if (err) { + kfree(ops); kfree(socfpga_clk); return; } diff --git a/drivers/clk/st/clkgen-fsyn.c b/drivers/clk/st/clkgen-fsyn.c index d820292a381d..40df1db102a7 100644 --- a/drivers/clk/st/clkgen-fsyn.c +++ b/drivers/clk/st/clkgen-fsyn.c @@ -1020,9 +1020,10 @@ static void __init st_of_quadfs_setup(struct device_node *np, clk = st_clk_register_quadfs_pll(pll_name, clk_parent_name, datac->data, reg, lock); - if (IS_ERR(clk)) + if (IS_ERR(clk)) { + kfree(lock); goto err_exit; - else + } else pr_debug("%s: parent %s rate %u\n", __clk_get_name(clk), __clk_get_name(clk_get_parent(clk)), diff --git a/drivers/clk/visconti/pll.c b/drivers/clk/visconti/pll.c index a484cb945d67..1f3234f22667 100644 --- a/drivers/clk/visconti/pll.c +++ b/drivers/clk/visconti/pll.c @@ -277,6 +277,7 @@ static struct clk_hw *visconti_register_pll(struct visconti_pll_provider *ctx, ret = clk_hw_register(NULL, &pll->hw); if (ret) { pr_err("failed to register pll clock %s : %d\n", name, ret); + kfree(pll->rate_table); kfree(pll); pll_hw_clk = ERR_PTR(ret); } diff --git a/drivers/clk/x86/Kconfig b/drivers/clk/x86/Kconfig index 69642e15fcc1..ced99e082e3d 100644 --- a/drivers/clk/x86/Kconfig +++ b/drivers/clk/x86/Kconfig @@ -1,8 +1,9 @@ # SPDX-License-Identifier: GPL-2.0-only config CLK_LGM_CGU depends on OF && HAS_IOMEM && (X86 || COMPILE_TEST) + select MFD_SYSCON select OF_EARLY_FLATTREE bool "Clock driver for Lightning Mountain(LGM) platform" help - Clock Generation Unit(CGU) driver for Intel Lightning Mountain(LGM) - network processor SoC. + Clock Generation Unit(CGU) driver for MaxLinear's x86 based + Lightning Mountain(LGM) network processor SoC. diff --git a/drivers/clk/x86/clk-cgu-pll.c b/drivers/clk/x86/clk-cgu-pll.c index 3179557b5f78..409dbf55f4ca 100644 --- a/drivers/clk/x86/clk-cgu-pll.c +++ b/drivers/clk/x86/clk-cgu-pll.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2020-2022 MaxLinear, Inc. * Copyright (C) 2020 Intel Corporation. - * Zhu YiXin <[email protected]> - * Rahul Tanwar <[email protected]> + * Zhu Yixin <[email protected]> + * Rahul Tanwar <[email protected]> */ #include <linux/clk-provider.h> @@ -40,13 +41,10 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate) { struct lgm_clk_pll *pll = to_lgm_clk_pll(hw); unsigned int div, mult, frac; - unsigned long flags; - spin_lock_irqsave(&pll->lock, flags); mult = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 0, 12); div = lgm_get_clk_val(pll->membase, PLL_REF_DIV(pll->reg), 18, 6); frac = lgm_get_clk_val(pll->membase, pll->reg, 2, 24); - spin_unlock_irqrestore(&pll->lock, flags); if (pll->type == TYPE_LJPLL) div *= 4; @@ -57,12 +55,9 @@ static unsigned long lgm_pll_recalc_rate(struct clk_hw *hw, unsigned long prate) static int lgm_pll_is_enabled(struct clk_hw *hw) { struct lgm_clk_pll *pll = to_lgm_clk_pll(hw); - unsigned long flags; unsigned int ret; - spin_lock_irqsave(&pll->lock, flags); ret = lgm_get_clk_val(pll->membase, pll->reg, 0, 1); - spin_unlock_irqrestore(&pll->lock, flags); return ret; } @@ -70,15 +65,13 @@ static int lgm_pll_is_enabled(struct clk_hw *hw) static int lgm_pll_enable(struct clk_hw *hw) { struct lgm_clk_pll *pll = to_lgm_clk_pll(hw); - unsigned long flags; u32 val; int ret; - spin_lock_irqsave(&pll->lock, flags); lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 1); - ret = readl_poll_timeout_atomic(pll->membase + pll->reg, - val, (val & 0x1), 1, 100); - spin_unlock_irqrestore(&pll->lock, flags); + ret = regmap_read_poll_timeout_atomic(pll->membase, pll->reg, + val, (val & 0x1), 1, 100); + return ret; } @@ -86,11 +79,8 @@ static int lgm_pll_enable(struct clk_hw *hw) static void lgm_pll_disable(struct clk_hw *hw) { struct lgm_clk_pll *pll = to_lgm_clk_pll(hw); - unsigned long flags; - spin_lock_irqsave(&pll->lock, flags); lgm_set_clk_val(pll->membase, pll->reg, 0, 1, 0); - spin_unlock_irqrestore(&pll->lock, flags); } static const struct clk_ops lgm_pll_ops = { @@ -121,7 +111,6 @@ lgm_clk_register_pll(struct lgm_clk_provider *ctx, return ERR_PTR(-ENOMEM); pll->membase = ctx->membase; - pll->lock = ctx->lock; pll->reg = list->reg; pll->flags = list->flags; pll->type = list->type; diff --git a/drivers/clk/x86/clk-cgu.c b/drivers/clk/x86/clk-cgu.c index 33de600e0c38..89b53f280aee 100644 --- a/drivers/clk/x86/clk-cgu.c +++ b/drivers/clk/x86/clk-cgu.c @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2020-2022 MaxLinear, Inc. * Copyright (C) 2020 Intel Corporation. - * Zhu YiXin <[email protected]> - * Rahul Tanwar <[email protected]> + * Zhu Yixin <[email protected]> + * Rahul Tanwar <[email protected]> */ #include <linux/clk-provider.h> #include <linux/device.h> @@ -24,14 +25,10 @@ static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list) { - unsigned long flags; - if (list->div_flags & CLOCK_FLAG_VAL_INIT) { - spin_lock_irqsave(&ctx->lock, flags); + if (list->div_flags & CLOCK_FLAG_VAL_INIT) lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift, list->div_width, list->div_val); - spin_unlock_irqrestore(&ctx->lock, flags); - } return clk_hw_register_fixed_rate(NULL, list->name, list->parent_data[0].name, @@ -41,33 +38,27 @@ static struct clk_hw *lgm_clk_register_fixed(struct lgm_clk_provider *ctx, static u8 lgm_clk_mux_get_parent(struct clk_hw *hw) { struct lgm_clk_mux *mux = to_lgm_clk_mux(hw); - unsigned long flags; u32 val; - spin_lock_irqsave(&mux->lock, flags); if (mux->flags & MUX_CLK_SW) val = mux->reg; else val = lgm_get_clk_val(mux->membase, mux->reg, mux->shift, mux->width); - spin_unlock_irqrestore(&mux->lock, flags); return clk_mux_val_to_index(hw, NULL, mux->flags, val); } static int lgm_clk_mux_set_parent(struct clk_hw *hw, u8 index) { struct lgm_clk_mux *mux = to_lgm_clk_mux(hw); - unsigned long flags; u32 val; val = clk_mux_index_to_val(NULL, mux->flags, index); - spin_lock_irqsave(&mux->lock, flags); if (mux->flags & MUX_CLK_SW) mux->reg = val; else lgm_set_clk_val(mux->membase, mux->reg, mux->shift, mux->width, val); - spin_unlock_irqrestore(&mux->lock, flags); return 0; } @@ -90,7 +81,7 @@ static struct clk_hw * lgm_clk_register_mux(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list) { - unsigned long flags, cflags = list->mux_flags; + unsigned long cflags = list->mux_flags; struct device *dev = ctx->dev; u8 shift = list->mux_shift; u8 width = list->mux_width; @@ -111,7 +102,6 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx, init.num_parents = list->num_parents; mux->membase = ctx->membase; - mux->lock = ctx->lock; mux->reg = reg; mux->shift = shift; mux->width = width; @@ -123,11 +113,8 @@ lgm_clk_register_mux(struct lgm_clk_provider *ctx, if (ret) return ERR_PTR(ret); - if (cflags & CLOCK_FLAG_VAL_INIT) { - spin_lock_irqsave(&mux->lock, flags); + if (cflags & CLOCK_FLAG_VAL_INIT) lgm_set_clk_val(mux->membase, reg, shift, width, list->mux_val); - spin_unlock_irqrestore(&mux->lock, flags); - } return hw; } @@ -136,13 +123,10 @@ static unsigned long lgm_clk_divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct lgm_clk_divider *divider = to_lgm_clk_divider(hw); - unsigned long flags; unsigned int val; - spin_lock_irqsave(÷r->lock, flags); val = lgm_get_clk_val(divider->membase, divider->reg, divider->shift, divider->width); - spin_unlock_irqrestore(÷r->lock, flags); return divider_recalc_rate(hw, parent_rate, val, divider->table, divider->flags, divider->width); @@ -163,7 +147,6 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) { struct lgm_clk_divider *divider = to_lgm_clk_divider(hw); - unsigned long flags; int value; value = divider_get_val(rate, prate, divider->table, @@ -171,10 +154,8 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, if (value < 0) return value; - spin_lock_irqsave(÷r->lock, flags); lgm_set_clk_val(divider->membase, divider->reg, divider->shift, divider->width, value); - spin_unlock_irqrestore(÷r->lock, flags); return 0; } @@ -182,12 +163,10 @@ lgm_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, static int lgm_clk_divider_enable_disable(struct clk_hw *hw, int enable) { struct lgm_clk_divider *div = to_lgm_clk_divider(hw); - unsigned long flags; - spin_lock_irqsave(&div->lock, flags); - lgm_set_clk_val(div->membase, div->reg, div->shift_gate, - div->width_gate, enable); - spin_unlock_irqrestore(&div->lock, flags); + if (div->flags != DIV_CLK_NO_MASK) + lgm_set_clk_val(div->membase, div->reg, div->shift_gate, + div->width_gate, enable); return 0; } @@ -213,7 +192,7 @@ static struct clk_hw * lgm_clk_register_divider(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list) { - unsigned long flags, cflags = list->div_flags; + unsigned long cflags = list->div_flags; struct device *dev = ctx->dev; struct lgm_clk_divider *div; struct clk_init_data init = {}; @@ -236,7 +215,6 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx, init.num_parents = 1; div->membase = ctx->membase; - div->lock = ctx->lock; div->reg = reg; div->shift = shift; div->width = width; @@ -251,11 +229,8 @@ lgm_clk_register_divider(struct lgm_clk_provider *ctx, if (ret) return ERR_PTR(ret); - if (cflags & CLOCK_FLAG_VAL_INIT) { - spin_lock_irqsave(&div->lock, flags); + if (cflags & CLOCK_FLAG_VAL_INIT) lgm_set_clk_val(div->membase, reg, shift, width, list->div_val); - spin_unlock_irqrestore(&div->lock, flags); - } return hw; } @@ -264,7 +239,6 @@ static struct clk_hw * lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list) { - unsigned long flags; struct clk_hw *hw; hw = clk_hw_register_fixed_factor(ctx->dev, list->name, @@ -273,12 +247,9 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx, if (IS_ERR(hw)) return ERR_CAST(hw); - if (list->div_flags & CLOCK_FLAG_VAL_INIT) { - spin_lock_irqsave(&ctx->lock, flags); + if (list->div_flags & CLOCK_FLAG_VAL_INIT) lgm_set_clk_val(ctx->membase, list->div_off, list->div_shift, list->div_width, list->div_val); - spin_unlock_irqrestore(&ctx->lock, flags); - } return hw; } @@ -286,13 +257,10 @@ lgm_clk_register_fixed_factor(struct lgm_clk_provider *ctx, static int lgm_clk_gate_enable(struct clk_hw *hw) { struct lgm_clk_gate *gate = to_lgm_clk_gate(hw); - unsigned long flags; unsigned int reg; - spin_lock_irqsave(&gate->lock, flags); reg = GATE_HW_REG_EN(gate->reg); lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1); - spin_unlock_irqrestore(&gate->lock, flags); return 0; } @@ -300,25 +268,19 @@ static int lgm_clk_gate_enable(struct clk_hw *hw) static void lgm_clk_gate_disable(struct clk_hw *hw) { struct lgm_clk_gate *gate = to_lgm_clk_gate(hw); - unsigned long flags; unsigned int reg; - spin_lock_irqsave(&gate->lock, flags); reg = GATE_HW_REG_DIS(gate->reg); lgm_set_clk_val(gate->membase, reg, gate->shift, 1, 1); - spin_unlock_irqrestore(&gate->lock, flags); } static int lgm_clk_gate_is_enabled(struct clk_hw *hw) { struct lgm_clk_gate *gate = to_lgm_clk_gate(hw); unsigned int reg, ret; - unsigned long flags; - spin_lock_irqsave(&gate->lock, flags); reg = GATE_HW_REG_STAT(gate->reg); ret = lgm_get_clk_val(gate->membase, reg, gate->shift, 1); - spin_unlock_irqrestore(&gate->lock, flags); return ret; } @@ -333,7 +295,7 @@ static struct clk_hw * lgm_clk_register_gate(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list) { - unsigned long flags, cflags = list->gate_flags; + unsigned long cflags = list->gate_flags; const char *pname = list->parent_data[0].name; struct device *dev = ctx->dev; u8 shift = list->gate_shift; @@ -354,7 +316,6 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx, init.num_parents = pname ? 1 : 0; gate->membase = ctx->membase; - gate->lock = ctx->lock; gate->reg = reg; gate->shift = shift; gate->flags = cflags; @@ -366,9 +327,7 @@ lgm_clk_register_gate(struct lgm_clk_provider *ctx, return ERR_PTR(ret); if (cflags & CLOCK_FLAG_VAL_INIT) { - spin_lock_irqsave(&gate->lock, flags); lgm_set_clk_val(gate->membase, reg, shift, 1, list->gate_val); - spin_unlock_irqrestore(&gate->lock, flags); } return hw; @@ -396,8 +355,22 @@ int lgm_clk_register_branches(struct lgm_clk_provider *ctx, hw = lgm_clk_register_fixed_factor(ctx, list); break; case CLK_TYPE_GATE: - hw = lgm_clk_register_gate(ctx, list); + if (list->gate_flags & GATE_CLK_HW) { + hw = lgm_clk_register_gate(ctx, list); + } else { + /* + * GATE_CLKs can be controlled either from + * CGU clk driver i.e. this driver or directly + * from power management driver/daemon. It is + * dependent on the power policy/profile requirements + * of the end product. To override control of gate + * clks from this driver, provide NULL for this index + * of gate clk provider. + */ + hw = NULL; + } break; + default: dev_err(ctx->dev, "invalid clk type\n"); return -EINVAL; @@ -443,24 +416,18 @@ lgm_clk_ddiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) static int lgm_clk_ddiv_enable(struct clk_hw *hw) { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); - unsigned long flags; - spin_lock_irqsave(&ddiv->lock, flags); lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate, ddiv->width_gate, 1); - spin_unlock_irqrestore(&ddiv->lock, flags); return 0; } static void lgm_clk_ddiv_disable(struct clk_hw *hw) { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); - unsigned long flags; - spin_lock_irqsave(&ddiv->lock, flags); lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift_gate, ddiv->width_gate, 0); - spin_unlock_irqrestore(&ddiv->lock, flags); } static int @@ -497,32 +464,25 @@ lgm_clk_ddiv_set_rate(struct clk_hw *hw, unsigned long rate, { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); u32 div, ddiv1, ddiv2; - unsigned long flags; div = DIV_ROUND_CLOSEST_ULL((u64)prate, rate); - spin_lock_irqsave(&ddiv->lock, flags); if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) { div = DIV_ROUND_CLOSEST_ULL((u64)div, 5); div = div * 2; } - if (div <= 0) { - spin_unlock_irqrestore(&ddiv->lock, flags); + if (div <= 0) return -EINVAL; - } - if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2)) { - spin_unlock_irqrestore(&ddiv->lock, flags); + if (lgm_clk_get_ddiv_val(div, &ddiv1, &ddiv2)) return -EINVAL; - } lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift0, ddiv->width0, ddiv1 - 1); lgm_set_clk_val(ddiv->membase, ddiv->reg, ddiv->shift1, ddiv->width1, ddiv2 - 1); - spin_unlock_irqrestore(&ddiv->lock, flags); return 0; } @@ -533,18 +493,15 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, { struct lgm_clk_ddiv *ddiv = to_lgm_clk_ddiv(hw); u32 div, ddiv1, ddiv2; - unsigned long flags; u64 rate64; div = DIV_ROUND_CLOSEST_ULL((u64)*prate, rate); /* if predivide bit is enabled, modify div by factor of 2.5 */ - spin_lock_irqsave(&ddiv->lock, flags); if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) { div = div * 2; div = DIV_ROUND_CLOSEST_ULL((u64)div, 5); } - spin_unlock_irqrestore(&ddiv->lock, flags); if (div <= 0) return *prate; @@ -558,12 +515,10 @@ lgm_clk_ddiv_round_rate(struct clk_hw *hw, unsigned long rate, do_div(rate64, ddiv2); /* if predivide bit is enabled, modify rounded rate by factor of 2.5 */ - spin_lock_irqsave(&ddiv->lock, flags); if (lgm_get_clk_val(ddiv->membase, ddiv->reg, ddiv->shift2, 1)) { rate64 = rate64 * 2; rate64 = DIV_ROUND_CLOSEST_ULL(rate64, 5); } - spin_unlock_irqrestore(&ddiv->lock, flags); return rate64; } @@ -600,7 +555,6 @@ int lgm_clk_register_ddiv(struct lgm_clk_provider *ctx, init.num_parents = 1; ddiv->membase = ctx->membase; - ddiv->lock = ctx->lock; ddiv->reg = list->reg; ddiv->shift0 = list->shift0; ddiv->width0 = list->width0; diff --git a/drivers/clk/x86/clk-cgu.h b/drivers/clk/x86/clk-cgu.h index 4e22bfb22312..bcaf8aec94e5 100644 --- a/drivers/clk/x86/clk-cgu.h +++ b/drivers/clk/x86/clk-cgu.h @@ -1,28 +1,28 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * Copyright(c) 2020 Intel Corporation. - * Zhu YiXin <[email protected]> - * Rahul Tanwar <[email protected]> + * Copyright (C) 2020-2022 MaxLinear, Inc. + * Copyright (C) 2020 Intel Corporation. + * Zhu Yixin <[email protected]> + * Rahul Tanwar <[email protected]> */ #ifndef __CLK_CGU_H #define __CLK_CGU_H -#include <linux/io.h> +#include <linux/regmap.h> struct lgm_clk_mux { struct clk_hw hw; - void __iomem *membase; + struct regmap *membase; unsigned int reg; u8 shift; u8 width; unsigned long flags; - spinlock_t lock; }; struct lgm_clk_divider { struct clk_hw hw; - void __iomem *membase; + struct regmap *membase; unsigned int reg; u8 shift; u8 width; @@ -30,12 +30,11 @@ struct lgm_clk_divider { u8 width_gate; unsigned long flags; const struct clk_div_table *table; - spinlock_t lock; }; struct lgm_clk_ddiv { struct clk_hw hw; - void __iomem *membase; + struct regmap *membase; unsigned int reg; u8 shift0; u8 width0; @@ -48,16 +47,14 @@ struct lgm_clk_ddiv { unsigned int mult; unsigned int div; unsigned long flags; - spinlock_t lock; }; struct lgm_clk_gate { struct clk_hw hw; - void __iomem *membase; + struct regmap *membase; unsigned int reg; u8 shift; unsigned long flags; - spinlock_t lock; }; enum lgm_clk_type { @@ -77,11 +74,10 @@ enum lgm_clk_type { * @clk_data: array of hw clocks and clk number. */ struct lgm_clk_provider { - void __iomem *membase; + struct regmap *membase; struct device_node *np; struct device *dev; struct clk_hw_onecell_data clk_data; - spinlock_t lock; }; enum pll_type { @@ -92,11 +88,10 @@ enum pll_type { struct lgm_clk_pll { struct clk_hw hw; - void __iomem *membase; + struct regmap *membase; unsigned int reg; unsigned long flags; enum pll_type type; - spinlock_t lock; }; /** @@ -202,6 +197,8 @@ struct lgm_clk_branch { /* clock flags definition */ #define CLOCK_FLAG_VAL_INIT BIT(16) #define MUX_CLK_SW BIT(17) +#define GATE_CLK_HW BIT(18) +#define DIV_CLK_NO_MASK BIT(19) #define LGM_MUX(_id, _name, _pdata, _f, _reg, \ _shift, _width, _cf, _v) \ @@ -300,29 +297,32 @@ struct lgm_clk_branch { .div = _d, \ } -static inline void lgm_set_clk_val(void __iomem *membase, u32 reg, +static inline void lgm_set_clk_val(struct regmap *membase, u32 reg, u8 shift, u8 width, u32 set_val) { u32 mask = (GENMASK(width - 1, 0) << shift); - u32 regval; - regval = readl(membase + reg); - regval = (regval & ~mask) | ((set_val << shift) & mask); - writel(regval, membase + reg); + regmap_update_bits(membase, reg, mask, set_val << shift); } -static inline u32 lgm_get_clk_val(void __iomem *membase, u32 reg, +static inline u32 lgm_get_clk_val(struct regmap *membase, u32 reg, u8 shift, u8 width) { u32 mask = (GENMASK(width - 1, 0) << shift); u32 val; - val = readl(membase + reg); + if (regmap_read(membase, reg, &val)) { + WARN_ONCE(1, "Failed to read clk reg: 0x%x\n", reg); + return 0; + } + val = (val & mask) >> shift; return val; } + + int lgm_clk_register_branches(struct lgm_clk_provider *ctx, const struct lgm_clk_branch *list, unsigned int nr_clk); diff --git a/drivers/clk/x86/clk-lgm.c b/drivers/clk/x86/clk-lgm.c index 020f4e83a5cc..f69455dd1c98 100644 --- a/drivers/clk/x86/clk-lgm.c +++ b/drivers/clk/x86/clk-lgm.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2020-2022 MaxLinear, Inc. * Copyright (C) 2020 Intel Corporation. - * Zhu YiXin <[email protected]> - * Rahul Tanwar <[email protected]> + * Zhu Yixin <[email protected]> + * Rahul Tanwar <[email protected]> */ #include <linux/clk-provider.h> +#include <linux/mfd/syscon.h> #include <linux/of.h> #include <linux/platform_device.h> #include <dt-bindings/clock/intel,lgm-clk.h> @@ -253,8 +255,8 @@ static const struct lgm_clk_branch lgm_branch_clks[] = { LGM_FIXED(LGM_CLK_SLIC, "slic", NULL, 0, CGU_IF_CLK1, 8, 2, CLOCK_FLAG_VAL_INIT, 8192000, 2), LGM_FIXED(LGM_CLK_DOCSIS, "v_docsis", NULL, 0, 0, 0, 0, 0, 16000000, 0), - LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", 0, CGU_PCMCR, - 25, 3, 0, 0, 0, 0, dcl_div), + LGM_DIV(LGM_CLK_DCL, "dcl", "v_ifclk", CLK_SET_RATE_PARENT, CGU_PCMCR, + 25, 3, 0, 0, DIV_CLK_NO_MASK, 0, dcl_div), LGM_MUX(LGM_CLK_PCM, "pcm", pcm_p, 0, CGU_C55_PCMCR, 0, 1, CLK_MUX_ROUND_CLOSEST, 0), LGM_FIXED_FACTOR(LGM_CLK_DDR_PHY, "ddr_phy", "ddr", @@ -433,13 +435,15 @@ static int lgm_cgu_probe(struct platform_device *pdev) ctx->clk_data.num = CLK_NR_CLKS; - ctx->membase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(ctx->membase)) + ctx->membase = syscon_node_to_regmap(np); + if (IS_ERR(ctx->membase)) { + dev_err(dev, "Failed to get clk CGU iomem\n"); return PTR_ERR(ctx->membase); + } + ctx->np = np; ctx->dev = dev; - spin_lock_init(&ctx->lock); ret = lgm_clk_register_plls(ctx, lgm_pll_clks, ARRAY_SIZE(lgm_pll_clks)); diff --git a/drivers/clk/xilinx/Kconfig b/drivers/clk/xilinx/Kconfig index f205522c40ff..051756953558 100644 --- a/drivers/clk/xilinx/Kconfig +++ b/drivers/clk/xilinx/Kconfig @@ -2,7 +2,7 @@ config XILINX_VCU tristate "Xilinx VCU logicoreIP Init" - depends on HAS_IOMEM && COMMON_CLK + depends on HAS_IOMEM select REGMAP_MMIO help Provides the driver to enable and disable the isolation between the @@ -19,7 +19,7 @@ config XILINX_VCU config COMMON_CLK_XLNX_CLKWZRD tristate "Xilinx Clocking Wizard" - depends on COMMON_CLK && OF + depends on OF depends on HAS_IOMEM help Support for the Xilinx Clocking Wizard IP core clock generator. diff --git a/include/dt-bindings/clock/ingenic,jz4755-cgu.h b/include/dt-bindings/clock/ingenic,jz4755-cgu.h new file mode 100644 index 000000000000..10098494e7df --- /dev/null +++ b/include/dt-bindings/clock/ingenic,jz4755-cgu.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */ +/* + * This header provides clock numbers for the ingenic,jz4755-cgu DT binding. + */ + +#ifndef __DT_BINDINGS_CLOCK_JZ4755_CGU_H__ +#define __DT_BINDINGS_CLOCK_JZ4755_CGU_H__ + +#define JZ4755_CLK_EXT 0 +#define JZ4755_CLK_OSC32K 1 +#define JZ4755_CLK_PLL 2 +#define JZ4755_CLK_PLL_HALF 3 +#define JZ4755_CLK_EXT_HALF 4 +#define JZ4755_CLK_CCLK 5 +#define JZ4755_CLK_H0CLK 6 +#define JZ4755_CLK_PCLK 7 +#define JZ4755_CLK_MCLK 8 +#define JZ4755_CLK_H1CLK 9 +#define JZ4755_CLK_UDC 10 +#define JZ4755_CLK_LCD 11 +#define JZ4755_CLK_UART0 12 +#define JZ4755_CLK_UART1 13 +#define JZ4755_CLK_UART2 14 +#define JZ4755_CLK_DMA 15 +#define JZ4755_CLK_MMC 16 +#define JZ4755_CLK_MMC0 17 +#define JZ4755_CLK_MMC1 18 +#define JZ4755_CLK_EXT512 19 +#define JZ4755_CLK_RTC 20 +#define JZ4755_CLK_UDC_PHY 21 +#define JZ4755_CLK_I2S 22 +#define JZ4755_CLK_SPI 23 +#define JZ4755_CLK_AIC 24 +#define JZ4755_CLK_ADC 25 +#define JZ4755_CLK_TCU 26 +#define JZ4755_CLK_BCH 27 +#define JZ4755_CLK_I2C 28 +#define JZ4755_CLK_TVE 29 +#define JZ4755_CLK_CIM 30 +#define JZ4755_CLK_AUX_CPU 31 +#define JZ4755_CLK_AHB1 32 +#define JZ4755_CLK_IDCT 33 +#define JZ4755_CLK_DB 34 +#define JZ4755_CLK_ME 35 +#define JZ4755_CLK_MC 36 +#define JZ4755_CLK_TSSI 37 +#define JZ4755_CLK_IPU 38 + +#endif /* __DT_BINDINGS_CLOCK_JZ4755_CGU_H__ */ diff --git a/include/dt-bindings/clock/ingenic,x1000-cgu.h b/include/dt-bindings/clock/ingenic,x1000-cgu.h index f187e0719fd3..78daf44b3514 100644 --- a/include/dt-bindings/clock/ingenic,x1000-cgu.h +++ b/include/dt-bindings/clock/ingenic,x1000-cgu.h @@ -50,5 +50,9 @@ #define X1000_CLK_PDMA 35 #define X1000_CLK_EXCLK_DIV512 36 #define X1000_CLK_RTC 37 +#define X1000_CLK_AIC 38 +#define X1000_CLK_I2SPLLMUX 39 +#define X1000_CLK_I2SPLL 40 +#define X1000_CLK_I2S 41 #endif /* __DT_BINDINGS_CLOCK_X1000_CGU_H__ */ |