diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 20:04:24 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-17 20:04:24 -0800 |
commit | fc35c1966e1372a21a88f6655279361e2f92713f (patch) | |
tree | 374588b79aaca55517fb309d7abc87bff4f3382c /drivers | |
parent | 2ce079f04d5914dae14fdc8618f804cc0d2a1b8f (diff) | |
parent | 36331641eb4296f0c62f4bf1e320d8c30bc6a863 (diff) |
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clk updates from Stephen Boyd:
"We have two changes to the core framework this time around.
The first being a large change that introduces runtime PM support to
the clk framework. Now we properly call runtime PM operations on the
device providing a clk when the clk is in use. This helps on SoCs
where the clks provided by a device need something to be powered on
before using the clks, like power domains or regulators. It also helps
power those things down when clks aren't in use.
The other core change is a devm API addition for clk providers so we
can get rid of a bunch of clk driver remove functions that are just
doing of_clk_del_provider().
Outside of the core, we have the usual addition of clk drivers and
smattering of non-critical fixes to existing drivers. The biggest diff
is support for Mediatek MT2712 and MT7622 SoCs, but those patches
really just add a bunch of data.
By the way, we're trying something new here where we build the tree up
with topic branches. We plan to work this into our workflow so that we
don't step on each other's toes, and so the fixes branch can be merged
on an as-needed basis.
Summary:
Core:
- runtime PM support for clk providers
- devm API for of_clk_add_hw_provider()
New Drivers:
- Mediatek MT2712 and MT7622
- Renesas R-Car V3M SoC
Updates:
- runtime PM support for Samsung exynos5433/exynos4412 providers
- removal of clkdev aliases on Samsung SoCs
- convert clk-gpio to use gpio descriptors
- various driver cleanups to match kernel coding style
- Amlogic Video Processing Unit VPU and VAPB clks
- sigma-delta modulation for Allwinner audio PLLs
- Allwinner A83t Display clks
- support for the second display unit clock on Renesas RZ/G1E
- suspend/resume support for Renesas R-Car Gen3 CPG/MSSR
- new clock ids for Rockchip rk3188 and rk3368 SoCs
- various 'const' markings on clk_ops structures
- RPM clk support on Qualcomm MSM8996/MSM8660 SoCs"
* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (137 commits)
clk: stm32h7: fix test of clock config
clk: pxa: fix building on older compilers
clk: sunxi-ng: a83t: Fix i2c buses bits
clk: ti: dra7-atl-clock: fix child-node lookups
clk: qcom: common: fix legacy board-clock registration
clk: uniphier: fix DAPLL2 clock rate of Pro5
clk: uniphier: fix parent of miodmac clock data
clk: hi3798cv200: correct parent mux clock for 'clk_sdio0_ciu'
clk: hisilicon: Delete an error message for a failed memory allocation in hisi_register_clkgate_sep()
clk: hi3660: fix incorrect uart3 clock freqency
clk: kona-setup: Delete error messages for failed memory allocations
ARC: clk: fix spelling mistake: "configurarion" -> "configuration"
clk: cdce925: remove redundant check for non-null parent_name
clk: versatile: Improve sizeof() usage
clk: versatile: Delete error messages for failed memory allocations
clk: ux500: Improve sizeof() usage
clk: ux500: Delete error messages for failed memory allocations
clk: spear: Delete error messages for failed memory allocations
clk: ti: Delete error messages for failed memory allocations
clk: mmp: Adjust checks for NULL pointers
...
Diffstat (limited to 'drivers')
146 files changed, 6114 insertions, 965 deletions
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c index aadabd9d1e2b..cd8d689138ff 100644 --- a/drivers/clk/at91/clk-utmi.c +++ b/drivers/clk/at91/clk-utmi.c @@ -14,14 +14,20 @@ #include <linux/of.h> #include <linux/mfd/syscon.h> #include <linux/regmap.h> +#include <soc/at91/atmel-sfr.h> #include "pmc.h" -#define UTMI_FIXED_MUL 40 +/* + * The purpose of this clock is to generate a 480 MHz signal. A different + * rate can't be configured. + */ +#define UTMI_RATE 480000000 struct clk_utmi { struct clk_hw hw; - struct regmap *regmap; + struct regmap *regmap_pmc; + struct regmap *regmap_sfr; }; #define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw) @@ -37,13 +43,54 @@ static inline bool clk_utmi_ready(struct regmap *regmap) static int clk_utmi_prepare(struct clk_hw *hw) { + struct clk_hw *hw_parent; struct clk_utmi *utmi = to_clk_utmi(hw); unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT | AT91_PMC_BIASEN; + unsigned int utmi_ref_clk_freq; + unsigned long parent_rate; + + /* + * If mainck rate is different from 12 MHz, we have to configure the + * FREQ field of the SFR_UTMICKTRIM register to generate properly + * the utmi clock. + */ + hw_parent = clk_hw_get_parent(hw); + parent_rate = clk_hw_get_rate(hw_parent); + + switch (parent_rate) { + case 12000000: + utmi_ref_clk_freq = 0; + break; + case 16000000: + utmi_ref_clk_freq = 1; + break; + case 24000000: + utmi_ref_clk_freq = 2; + break; + /* + * Not supported on SAMA5D2 but it's not an issue since MAINCK + * maximum value is 24 MHz. + */ + case 48000000: + utmi_ref_clk_freq = 3; + break; + default: + pr_err("UTMICK: unsupported mainck rate\n"); + return -EINVAL; + } - regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr); + if (utmi->regmap_sfr) { + regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM, + AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq); + } else if (utmi_ref_clk_freq) { + pr_err("UTMICK: sfr node required\n"); + return -EINVAL; + } - while (!clk_utmi_ready(utmi->regmap)) + regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr); + + while (!clk_utmi_ready(utmi->regmap_pmc)) cpu_relax(); return 0; @@ -53,21 +100,22 @@ static int clk_utmi_is_prepared(struct clk_hw *hw) { struct clk_utmi *utmi = to_clk_utmi(hw); - return clk_utmi_ready(utmi->regmap); + return clk_utmi_ready(utmi->regmap_pmc); } static void clk_utmi_unprepare(struct clk_hw *hw) { struct clk_utmi *utmi = to_clk_utmi(hw); - regmap_update_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0); + regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, + AT91_PMC_UPLLEN, 0); } static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { - /* UTMI clk is a fixed clk multiplier */ - return parent_rate * UTMI_FIXED_MUL; + /* UTMI clk rate is fixed. */ + return UTMI_RATE; } static const struct clk_ops utmi_ops = { @@ -78,7 +126,7 @@ static const struct clk_ops utmi_ops = { }; static struct clk_hw * __init -at91_clk_register_utmi(struct regmap *regmap, +at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr, const char *name, const char *parent_name) { struct clk_utmi *utmi; @@ -97,7 +145,8 @@ at91_clk_register_utmi(struct regmap *regmap, init.flags = CLK_SET_RATE_GATE; utmi->hw.init = &init; - utmi->regmap = regmap; + utmi->regmap_pmc = regmap_pmc; + utmi->regmap_sfr = regmap_sfr; hw = &utmi->hw; ret = clk_hw_register(NULL, &utmi->hw); @@ -114,17 +163,35 @@ static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np) struct clk_hw *hw; const char *parent_name; const char *name = np->name; - struct regmap *regmap; + struct regmap *regmap_pmc, *regmap_sfr; parent_name = of_clk_get_parent_name(np, 0); of_property_read_string(np, "clock-output-names", &name); - regmap = syscon_node_to_regmap(of_get_parent(np)); - if (IS_ERR(regmap)) + regmap_pmc = syscon_node_to_regmap(of_get_parent(np)); + if (IS_ERR(regmap_pmc)) return; - hw = at91_clk_register_utmi(regmap, name, parent_name); + /* + * If the device supports different mainck rates, this value has to be + * set in the UTMI Clock Trimming register. + * - 9x5: mainck supports several rates but it is indicated that a + * 12 MHz is needed in case of USB. + * - sama5d3 and sama5d2: mainck supports several rates. Configuring + * the FREQ field of the UTMI Clock Trimming register is mandatory. + * - sama5d4: mainck is at 12 MHz. + * + * We only need to retrieve sama5d3 or sama5d2 sfr regmap. + */ + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d3-sfr"); + if (IS_ERR(regmap_sfr)) { + regmap_sfr = syscon_regmap_lookup_by_compatible("atmel,sama5d2-sfr"); + if (IS_ERR(regmap_sfr)) + regmap_sfr = NULL; + } + + hw = at91_clk_register_utmi(regmap_pmc, regmap_sfr, name, parent_name); if (IS_ERR(hw)) return; diff --git a/drivers/clk/bcm/clk-kona-setup.c b/drivers/clk/bcm/clk-kona-setup.c index c37a7f0e83aa..281f4322355c 100644 --- a/drivers/clk/bcm/clk-kona-setup.c +++ b/drivers/clk/bcm/clk-kona-setup.c @@ -579,18 +579,13 @@ static u32 *parent_process(const char *clocks[], */ parent_names = kmalloc_array(parent_count, sizeof(*parent_names), GFP_KERNEL); - if (!parent_names) { - pr_err("%s: error allocating %u parent names\n", __func__, - parent_count); + if (!parent_names) return ERR_PTR(-ENOMEM); - } /* There is at least one parent, so allocate a selector array */ parent_sel = kmalloc_array(parent_count, sizeof(*parent_sel), GFP_KERNEL); if (!parent_sel) { - pr_err("%s: error allocating %u parent selectors\n", __func__, - parent_count); kfree(parent_names); return ERR_PTR(-ENOMEM); diff --git a/drivers/clk/clk-cdce925.c b/drivers/clk/clk-cdce925.c index c933be01c7db..0a7e7d5a7506 100644 --- a/drivers/clk/clk-cdce925.c +++ b/drivers/clk/clk-cdce925.c @@ -665,7 +665,7 @@ static int cdce925_probe(struct i2c_client *client, init.ops = &cdce925_pll_ops; init.flags = 0; init.parent_names = &parent_name; - init.num_parents = parent_name ? 1 : 0; + init.num_parents = 1; /* Register PLL clocks */ for (i = 0; i < data->chip_info->num_plls; ++i) { diff --git a/drivers/clk/clk-gpio.c b/drivers/clk/clk-gpio.c index 86b245746a6b..151513c655c3 100644 --- a/drivers/clk/clk-gpio.c +++ b/drivers/clk/clk-gpio.c @@ -15,9 +15,7 @@ #include <linux/clk-provider.h> #include <linux/export.h> #include <linux/slab.h> -#include <linux/gpio.h> #include <linux/gpio/consumer.h> -#include <linux/of_gpio.h> #include <linux/err.h> #include <linux/device.h> #include <linux/platform_device.h> @@ -95,14 +93,12 @@ const struct clk_ops clk_gpio_mux_ops = { EXPORT_SYMBOL_GPL(clk_gpio_mux_ops); static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags, - const struct clk_ops *clk_gpio_ops) + const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod, + unsigned long flags, const struct clk_ops *clk_gpio_ops) { struct clk_gpio *clk_gpio; struct clk_hw *hw; struct clk_init_data init = {}; - unsigned long gpio_flags; int err; if (dev) @@ -113,32 +109,13 @@ static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, if (!clk_gpio) return ERR_PTR(-ENOMEM); - if (active_low) - gpio_flags = GPIOF_ACTIVE_LOW | GPIOF_OUT_INIT_HIGH; - else - gpio_flags = GPIOF_OUT_INIT_LOW; - - if (dev) - err = devm_gpio_request_one(dev, gpio, gpio_flags, name); - else - err = gpio_request_one(gpio, gpio_flags, name); - if (err) { - if (err != -EPROBE_DEFER) - pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, gpio); - if (!dev) - kfree(clk_gpio); - - return ERR_PTR(err); - } - init.name = name; init.ops = clk_gpio_ops; init.flags = flags | CLK_IS_BASIC; init.parent_names = parent_names; init.num_parents = num_parents; - clk_gpio->gpiod = gpio_to_desc(gpio); + clk_gpio->gpiod = gpiod; clk_gpio->hw.init = &init; hw = &clk_gpio->hw; @@ -151,7 +128,6 @@ static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, return hw; if (!dev) { - gpiod_put(clk_gpio->gpiod); kfree(clk_gpio); } @@ -164,29 +140,27 @@ static struct clk_hw *clk_register_gpio(struct device *dev, const char *name, * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of this clock's parent - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock + * @gpiod: gpio descriptor to gate this clock * @flags: clock flags */ struct clk_hw *clk_hw_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, + const char *parent_name, struct gpio_desc *gpiod, unsigned long flags) { return clk_register_gpio(dev, name, (parent_name ? &parent_name : NULL), - (parent_name ? 1 : 0), gpio, active_low, flags, + (parent_name ? 1 : 0), gpiod, flags, &clk_gpio_gate_ops); } EXPORT_SYMBOL_GPL(clk_hw_register_gpio_gate); struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, unsigned gpio, bool active_low, + const char *parent_name, struct gpio_desc *gpiod, unsigned long flags) { struct clk_hw *hw; - hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpio, active_low, - flags); + hw = clk_hw_register_gpio_gate(dev, name, parent_name, gpiod, flags); if (IS_ERR(hw)) return ERR_CAST(hw); return hw->clk; @@ -199,13 +173,12 @@ EXPORT_SYMBOL_GPL(clk_register_gpio_gate); * @name: name of this clock * @parent_names: names of this clock's parents * @num_parents: number of parents listed in @parent_names - * @gpio: gpio number to gate this clock - * @active_low: true if gpio should be set to 0 to enable clock + * @gpiod: gpio descriptor to gate this clock * @flags: clock flags */ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags) + const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod, + unsigned long flags) { if (num_parents != 2) { pr_err("mux-clock %s must have 2 parents\n", name); @@ -213,18 +186,18 @@ struct clk_hw *clk_hw_register_gpio_mux(struct device *dev, const char *name, } return clk_register_gpio(dev, name, parent_names, num_parents, - gpio, active_low, flags, &clk_gpio_mux_ops); + gpiod, flags, &clk_gpio_mux_ops); } EXPORT_SYMBOL_GPL(clk_hw_register_gpio_mux); struct clk *clk_register_gpio_mux(struct device *dev, const char *name, - const char * const *parent_names, u8 num_parents, unsigned gpio, - bool active_low, unsigned long flags) + const char * const *parent_names, u8 num_parents, struct gpio_desc *gpiod, + unsigned long flags) { struct clk_hw *hw; hw = clk_hw_register_gpio_mux(dev, name, parent_names, num_parents, - gpio, active_low, flags); + gpiod, flags); if (IS_ERR(hw)) return ERR_CAST(hw); return hw->clk; @@ -236,10 +209,10 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) struct device_node *node = pdev->dev.of_node; const char **parent_names, *gpio_name; unsigned int num_parents; - int gpio; - enum of_gpio_flags of_flags; + struct gpio_desc *gpiod; struct clk *clk; - bool active_low, is_mux; + bool is_mux; + int ret; num_parents = of_clk_get_parent_count(node); if (num_parents) { @@ -255,28 +228,27 @@ static int gpio_clk_driver_probe(struct platform_device *pdev) is_mux = of_device_is_compatible(node, "gpio-mux-clock"); - gpio_name = is_mux ? "select-gpios" : "enable-gpios"; - gpio = of_get_named_gpio_flags(node, gpio_name, 0, &of_flags); - if (gpio < 0) { - if (gpio == -EPROBE_DEFER) + gpio_name = is_mux ? "select" : "enable"; + gpiod = devm_gpiod_get(&pdev->dev, gpio_name, GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + ret = PTR_ERR(gpiod); + if (ret == -EPROBE_DEFER) pr_debug("%s: %s: GPIOs not yet available, retry later\n", node->name, __func__); else - pr_err("%s: %s: Can't get '%s' DT property\n", + pr_err("%s: %s: Can't get '%s' named GPIO property\n", node->name, __func__, gpio_name); - return gpio; + return ret; } - active_low = of_flags & OF_GPIO_ACTIVE_LOW; - if (is_mux) clk = clk_register_gpio_mux(&pdev->dev, node->name, - parent_names, num_parents, gpio, active_low, 0); + parent_names, num_parents, gpiod, 0); else clk = clk_register_gpio_gate(&pdev->dev, node->name, - parent_names ? parent_names[0] : NULL, gpio, - active_low, 0); + parent_names ? parent_names[0] : NULL, gpiod, + 0); if (IS_ERR(clk)) return PTR_ERR(clk); diff --git a/drivers/clk/clk-hsdk-pll.c b/drivers/clk/clk-hsdk-pll.c index bbf237173b37..c4ee280f454d 100644 --- a/drivers/clk/clk-hsdk-pll.c +++ b/drivers/clk/clk-hsdk-pll.c @@ -139,7 +139,7 @@ static inline void hsdk_pll_set_cfg(struct hsdk_pll_clk *clk, val |= cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT; val |= cfg->band << CGU_PLL_CTRL_BAND_SHIFT; - dev_dbg(clk->dev, "write configurarion: %#x\n", val); + dev_dbg(clk->dev, "write configuration: %#x\n", val); hsdk_pll_write(clk, CGU_PLL_CTRL, val); } @@ -169,7 +169,7 @@ static unsigned long hsdk_pll_recalc_rate(struct clk_hw *hw, val = hsdk_pll_read(clk, CGU_PLL_CTRL); - dev_dbg(clk->dev, "current configurarion: %#x\n", val); + dev_dbg(clk->dev, "current configuration: %#x\n", val); /* Check if PLL is disabled */ if (val & CGU_PLL_CTRL_PD) diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c index 16a3d5717f4e..39cabe157163 100644 --- a/drivers/clk/clk-mux.c +++ b/drivers/clk/clk-mux.c @@ -134,11 +134,9 @@ struct clk_hw *clk_hw_register_mux_table(struct device *dev, const char *name, } /* allocate the mux */ - mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL); - if (!mux) { - pr_err("%s: could not allocate mux clk\n", __func__); + mux = kzalloc(sizeof(*mux), GFP_KERNEL); + if (!mux) return ERR_PTR(-ENOMEM); - } init.name = name; if (clk_mux_flags & CLK_MUX_READ_ONLY) diff --git a/drivers/clk/clk-stm32h7.c b/drivers/clk/clk-stm32h7.c index a94c3f56c590..61c3e40507d3 100644 --- a/drivers/clk/clk-stm32h7.c +++ b/drivers/clk/clk-stm32h7.c @@ -384,7 +384,7 @@ static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg, mux_ops = div_ops = gate_ops = NULL; mux_hw = div_hw = gate_hw = NULL; - if (gcfg->mux && gcfg->mux) { + if (gcfg->mux && cfg->mux) { mux = _get_cmux(base + cfg->mux->offset, cfg->mux->shift, cfg->mux->width, @@ -410,7 +410,7 @@ static void get_cfg_composite_div(const struct composite_clk_gcfg *gcfg, } } - if (gcfg->gate && gcfg->gate) { + if (gcfg->gate && cfg->gate) { gate = _get_cgate(base + cfg->gate->offset, cfg->gate->bit_idx, gcfg->gate->flags, lock); diff --git a/drivers/clk/clk-twl6040.c b/drivers/clk/clk-twl6040.c index 7b222a5db931..25dfe050ae9f 100644 --- a/drivers/clk/clk-twl6040.c +++ b/drivers/clk/clk-twl6040.c @@ -82,7 +82,7 @@ static const struct clk_ops twl6040_pdmclk_ops = { .recalc_rate = twl6040_pdmclk_recalc_rate, }; -static struct clk_init_data twl6040_pdmclk_init = { +static const struct clk_init_data twl6040_pdmclk_init = { .name = "pdmclk", .ops = &twl6040_pdmclk_ops, .flags = CLK_GET_RATE_NOCACHE, diff --git a/drivers/clk/clk-u300.c b/drivers/clk/clk-u300.c index ec8aafda6e24..7b3e1921771f 100644 --- a/drivers/clk/clk-u300.c +++ b/drivers/clk/clk-u300.c @@ -229,15 +229,15 @@ #define U300_SYSCON_S0CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S0CCR_CLOCK_SELECT_MASK (0x001E) #define U300_SYSCON_S0CCR_CLOCK_ENABLE (0x0001) -#define U300_SYSCON_S0CCR_SEL_MCLK (0x8<<1) -#define U300_SYSCON_S0CCR_SEL_ACC_FSM_CLK (0xA<<1) -#define U300_SYSCON_S0CCR_SEL_PLL60_48_CLK (0xC<<1) -#define U300_SYSCON_S0CCR_SEL_PLL60_60_CLK (0xD<<1) -#define U300_SYSCON_S0CCR_SEL_ACC_PLL208_CLK (0xE<<1) -#define U300_SYSCON_S0CCR_SEL_APP_PLL13_CLK (0x0<<1) -#define U300_SYSCON_S0CCR_SEL_APP_FSM_CLK (0x2<<1) -#define U300_SYSCON_S0CCR_SEL_RTC_CLK (0x4<<1) -#define U300_SYSCON_S0CCR_SEL_APP_PLL208_CLK (0x6<<1) +#define U300_SYSCON_S0CCR_SEL_MCLK (0x8 << 1) +#define U300_SYSCON_S0CCR_SEL_ACC_FSM_CLK (0xA << 1) +#define U300_SYSCON_S0CCR_SEL_PLL60_48_CLK (0xC << 1) +#define U300_SYSCON_S0CCR_SEL_PLL60_60_CLK (0xD << 1) +#define U300_SYSCON_S0CCR_SEL_ACC_PLL208_CLK (0xE << 1) +#define U300_SYSCON_S0CCR_SEL_APP_PLL13_CLK (0x0 << 1) +#define U300_SYSCON_S0CCR_SEL_APP_FSM_CLK (0x2 << 1) +#define U300_SYSCON_S0CCR_SEL_RTC_CLK (0x4 << 1) +#define U300_SYSCON_S0CCR_SEL_APP_PLL208_CLK (0x6 << 1) /* SYS_1_CLK_CONTROL second clock control 16 bit (R/W) */ #define U300_SYSCON_S1CCR (0x124) #define U300_SYSCON_S1CCR_FIELD_MASK (0x43FF) @@ -247,16 +247,16 @@ #define U300_SYSCON_S1CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S1CCR_CLOCK_SELECT_MASK (0x001E) #define U300_SYSCON_S1CCR_CLOCK_ENABLE (0x0001) -#define U300_SYSCON_S1CCR_SEL_MCLK (0x8<<1) -#define U300_SYSCON_S1CCR_SEL_ACC_FSM_CLK (0xA<<1) -#define U300_SYSCON_S1CCR_SEL_PLL60_48_CLK (0xC<<1) -#define U300_SYSCON_S1CCR_SEL_PLL60_60_CLK (0xD<<1) -#define U300_SYSCON_S1CCR_SEL_ACC_PLL208_CLK (0xE<<1) -#define U300_SYSCON_S1CCR_SEL_ACC_PLL13_CLK (0x0<<1) -#define U300_SYSCON_S1CCR_SEL_APP_FSM_CLK (0x2<<1) -#define U300_SYSCON_S1CCR_SEL_RTC_CLK (0x4<<1) -#define U300_SYSCON_S1CCR_SEL_APP_PLL208_CLK (0x6<<1) -/* SYS_2_CLK_CONTROL third clock contol 16 bit (R/W) */ +#define U300_SYSCON_S1CCR_SEL_MCLK (0x8 << 1) +#define U300_SYSCON_S1CCR_SEL_ACC_FSM_CLK (0xA << 1) +#define U300_SYSCON_S1CCR_SEL_PLL60_48_CLK (0xC << 1) +#define U300_SYSCON_S1CCR_SEL_PLL60_60_CLK (0xD << 1) +#define U300_SYSCON_S1CCR_SEL_ACC_PLL208_CLK (0xE << 1) +#define U300_SYSCON_S1CCR_SEL_ACC_PLL13_CLK (0x0 << 1) +#define U300_SYSCON_S1CCR_SEL_APP_FSM_CLK (0x2 << 1) +#define U300_SYSCON_S1CCR_SEL_RTC_CLK (0x4 << 1) +#define U300_SYSCON_S1CCR_SEL_APP_PLL208_CLK (0x6 << 1) +/* SYS_2_CLK_CONTROL third clock control 16 bit (R/W) */ #define U300_SYSCON_S2CCR (0x128) #define U300_SYSCON_S2CCR_FIELD_MASK (0xC3FF) #define U300_SYSCON_S2CCR_CLK_STEAL (0x8000) @@ -266,15 +266,15 @@ #define U300_SYSCON_S2CCR_CLOCK_FREQ_MASK (0x01E0) #define U300_SYSCON_S2CCR_CLOCK_SELECT_MASK (0x001E) #define U300_SYSCON_S2CCR_CLOCK_ENABLE (0x0001) -#define U300_SYSCON_S2CCR_SEL_MCLK (0x8<<1) -#define U300_SYSCON_S2CCR_SEL_ACC_FSM_CLK (0xA<<1) -#define U300_SYSCON_S2CCR_SEL_PLL60_48_CLK (0xC<<1) -#define U300_SYSCON_S2CCR_SEL_PLL60_60_CLK (0xD<<1) -#define U300_SYSCON_S2CCR_SEL_ACC_PLL208_CLK (0xE<<1) -#define U300_SYSCON_S2CCR_SEL_ACC_PLL13_CLK (0x0<<1) -#define U300_SYSCON_S2CCR_SEL_APP_FSM_CLK (0x2<<1) -#define U300_SYSCON_S2CCR_SEL_RTC_CLK (0x4<<1) -#define U300_SYSCON_S2CCR_SEL_APP_PLL208_CLK (0x6<<1) +#define U300_SYSCON_S2CCR_SEL_MCLK (0x8 << 1) +#define U300_SYSCON_S2CCR_SEL_ACC_FSM_CLK (0xA << 1) +#define U300_SYSCON_S2CCR_SEL_PLL60_48_CLK (0xC << 1) +#define U300_SYSCON_S2CCR_SEL_PLL60_60_CLK (0xD << 1) +#define U300_SYSCON_S2CCR_SEL_ACC_PLL208_CLK (0xE << 1) +#define U300_SYSCON_S2CCR_SEL_ACC_PLL13_CLK (0x0 << 1) +#define U300_SYSCON_S2CCR_SEL_APP_FSM_CLK (0x2 << 1) +#define U300_SYSCON_S2CCR_SEL_RTC_CLK (0x4 << 1) +#define U300_SYSCON_S2CCR_SEL_APP_PLL208_CLK (0x6 << 1) /* SC_PLL_IRQ_CONTROL 16bit (R/W) */ #define U300_SYSCON_PICR (0x0130) #define U300_SYSCON_PICR_MASK (0x00FF) @@ -378,7 +378,7 @@ * +- ISP Image Signal Processor (U335 only) * +- CDS (U335 only) * +- DMA Direct Memory Access Controller - * +- AAIF APP/ACC Inteface (Mobile Scalable Link, MSL) + * +- AAIF APP/ACC Interface (Mobile Scalable Link, MSL) * +- APEX * +- VIDEO_ENC AVE2/3 Video Encoder * +- XGAM Graphics Accelerator Controller @@ -568,14 +568,14 @@ syscon_clk_recalc_rate(struct clk_hw *hw, struct clk_syscon *sclk = to_syscon(hw); u16 perf = syscon_get_perf(); - switch(sclk->clk_val) { + switch (sclk->clk_val) { case U300_SYSCON_SBCER_FAST_BRIDGE_CLK_EN: case U300_SYSCON_SBCER_I2C0_CLK_EN: case U300_SYSCON_SBCER_I2C1_CLK_EN: case U300_SYSCON_SBCER_MMC_CLK_EN: case U300_SYSCON_SBCER_SPI_CLK_EN: /* The FAST clocks have one progression */ - switch(perf) { + switch (perf) { case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER: case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW: return 13000000; @@ -586,7 +586,7 @@ syscon_clk_recalc_rate(struct clk_hw *hw, case U300_SYSCON_SBCER_NANDIF_CLK_EN: case U300_SYSCON_SBCER_XGAM_CLK_EN: /* AMBA interconnect peripherals */ - switch(perf) { + switch (perf) { case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER: case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW: return 6500000; @@ -598,7 +598,7 @@ syscon_clk_recalc_rate(struct clk_hw *hw, case U300_SYSCON_SBCER_SEMI_CLK_EN: case U300_SYSCON_SBCER_EMIF_CLK_EN: /* EMIF speeds */ - switch(perf) { + switch (perf) { case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER: case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW: return 13000000; @@ -609,7 +609,7 @@ syscon_clk_recalc_rate(struct clk_hw *hw, } case U300_SYSCON_SBCER_CPU_CLK_EN: /* And the fast CPU clock */ - switch(perf) { + switch (perf) { case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW_POWER: case U300_SYSCON_CCR_CLKING_PERFORMANCE_LOW: return 13000000; @@ -702,12 +702,10 @@ syscon_clk_register(struct device *dev, const char *name, struct clk_init_data init; int ret; - sclk = kzalloc(sizeof(struct clk_syscon), GFP_KERNEL); - if (!sclk) { - pr_err("could not allocate syscon clock %s\n", - name); + sclk = kzalloc(sizeof(*sclk), GFP_KERNEL); + if (!sclk) return ERR_PTR(-ENOMEM); - } + init.name = name; init.ops = &syscon_clk_ops; init.flags = flags; @@ -1123,12 +1121,10 @@ mclk_clk_register(struct device *dev, const char *name, struct clk_init_data init; int ret; - mclk = kzalloc(sizeof(struct clk_mclk), GFP_KERNEL); - if (!mclk) { - pr_err("could not allocate MMC/SD clock %s\n", - name); + mclk = kzalloc(sizeof(*mclk), GFP_KERNEL); + if (!mclk) return ERR_PTR(-ENOMEM); - } + init.name = "mclk"; init.ops = &mclk_ops; init.flags = 0; diff --git a/drivers/clk/clk-wm831x.c b/drivers/clk/clk-wm831x.c index a47960aacfa5..146769532325 100644 --- a/drivers/clk/clk-wm831x.c +++ b/drivers/clk/clk-wm831x.c @@ -52,7 +52,7 @@ static const struct clk_ops wm831x_xtal_ops = { .recalc_rate = wm831x_xtal_recalc_rate, }; -static struct clk_init_data wm831x_xtal_init = { +static const struct clk_init_data wm831x_xtal_init = { .name = "xtal", .ops = &wm831x_xtal_ops, }; @@ -225,7 +225,7 @@ static const struct clk_ops wm831x_fll_ops = { .get_parent = wm831x_fll_get_parent, }; -static struct clk_init_data wm831x_fll_init = { +static const struct clk_init_data wm831x_fll_init = { .name = "fll", .ops = &wm831x_fll_ops, .parent_names = wm831x_fll_parents, @@ -338,7 +338,7 @@ static const struct clk_ops wm831x_clkout_ops = { .set_parent = wm831x_clkout_set_parent, }; -static struct clk_init_data wm831x_clkout_init = { +static const struct clk_init_data wm831x_clkout_init = { .name = "clkout", .ops = &wm831x_clkout_ops, .parent_names = wm831x_clkout_parents, diff --git a/drivers/clk/clk-xgene.c b/drivers/clk/clk-xgene.c index 4c75821a3933..531b030d4d4e 100644 --- a/drivers/clk/clk-xgene.c +++ b/drivers/clk/clk-xgene.c @@ -146,10 +146,8 @@ static struct clk *xgene_register_clk_pll(struct device *dev, /* allocate the APM clock structure */ apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); - if (!apmclk) { - pr_err("%s: could not allocate APM clk\n", __func__); + if (!apmclk) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &xgene_clk_pll_ops; @@ -191,7 +189,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty int version = xgene_pllclk_version(np); reg = of_iomap(np, 0); - if (reg == NULL) { + if (!reg) { pr_err("Unable to map CSR register for %pOF\n", np); return; } @@ -467,7 +465,7 @@ static int xgene_clk_enable(struct clk_hw *hw) if (pclk->lock) spin_lock_irqsave(pclk->lock, flags); - if (pclk->param.csr_reg != NULL) { + if (pclk->param.csr_reg) { pr_debug("%s clock enabled\n", clk_hw_get_name(hw)); /* First enable the clock */ data = xgene_clk_read(pclk->param.csr_reg + @@ -507,7 +505,7 @@ static void xgene_clk_disable(struct clk_hw *hw) if (pclk->lock) spin_lock_irqsave(pclk->lock, flags); - if (pclk->param.csr_reg != NULL) { + if (pclk->param.csr_reg) { pr_debug("%s clock disabled\n", clk_hw_get_name(hw)); /* First put the CSR in reset */ data = xgene_clk_read(pclk->param.csr_reg + @@ -533,7 +531,7 @@ static int xgene_clk_is_enabled(struct clk_hw *hw) struct xgene_clk *pclk = to_xgene_clk(hw); u32 data = 0; - if (pclk->param.csr_reg != NULL) { + if (pclk->param.csr_reg) { pr_debug("%s clock checking\n", clk_hw_get_name(hw)); data = xgene_clk_read(pclk->param.csr_reg + pclk->param.reg_clk_offset); @@ -542,7 +540,7 @@ static int xgene_clk_is_enabled(struct clk_hw *hw) "disabled"); } - if (pclk->param.csr_reg == NULL) + if (!pclk->param.csr_reg) return 1; return data & pclk->param.reg_clk_mask ? 1 : 0; } @@ -650,10 +648,8 @@ static struct clk *xgene_register_clk(struct device *dev, /* allocate the APM clock structure */ apmclk = kzalloc(sizeof(*apmclk), GFP_KERNEL); - if (!apmclk) { - pr_err("%s: could not allocate APM clk\n", __func__); + if (!apmclk) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &xgene_clk_ops; @@ -709,7 +705,7 @@ static void __init xgene_devclk_init(struct device_node *np) break; } map_res = of_iomap(np, i); - if (map_res == NULL) { + if (!map_res) { pr_err("Unable to map resource %d for %pOF\n", i, np); goto err; } diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index c8d83acda006..647d056df88c 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -21,6 +21,7 @@ #include <linux/of.h> #include <linux/device.h> #include <linux/init.h> +#include <linux/pm_runtime.h> #include <linux/sched.h> #include <linux/clkdev.h> @@ -46,6 +47,7 @@ struct clk_core { const struct clk_ops *ops; struct clk_hw *hw; struct module *owner; + struct device *dev; struct clk_core *parent; const char **parent_names; struct clk_core **parents; @@ -87,6 +89,26 @@ struct clk { struct hlist_node clks_node; }; +/*** runtime pm ***/ +static int clk_pm_runtime_get(struct clk_core *core) +{ + int ret = 0; + + if (!core->dev) + return 0; + + ret = pm_runtime_get_sync(core->dev); + return ret < 0 ? ret : 0; +} + +static void clk_pm_runtime_put(struct clk_core *core) +{ + if (!core->dev) + return; + + pm_runtime_put_sync(core->dev); +} + /*** locking ***/ static void clk_prepare_lock(void) { @@ -150,6 +172,8 @@ static void clk_enable_unlock(unsigned long flags) static bool clk_core_is_prepared(struct clk_core *core) { + bool ret = false; + /* * .is_prepared is optional for clocks that can prepare * fall back to software usage counter if it is missing @@ -157,11 +181,18 @@ static bool clk_core_is_prepared(struct clk_core *core) if (!core->ops->is_prepared) return core->prepare_count; - return core->ops->is_prepared(core->hw); + if (!clk_pm_runtime_get(core)) { + ret = core->ops->is_prepared(core->hw); + clk_pm_runtime_put(core); + } + + return ret; } static bool clk_core_is_enabled(struct clk_core *core) { + bool ret = false; + /* * .is_enabled is only mandatory for clocks that gate * fall back to software usage counter if .is_enabled is missing @@ -169,7 +200,29 @@ static bool clk_core_is_enabled(struct clk_core *core) if (!core->ops->is_enabled) return core->enable_count; - return core->ops->is_enabled(core->hw); + /* + * Check if clock controller's device is runtime active before + * calling .is_enabled callback. If not, assume that clock is + * disabled, because we might be called from atomic context, from + * which pm_runtime_get() is not allowed. + * This function is called mainly from clk_disable_unused_subtree, + * which ensures proper runtime pm activation of controller before + * taking enable spinlock, but the below check is needed if one tries + * to call it from other places. + */ + if (core->dev) { + pm_runtime_get_noresume(core->dev); + if (!pm_runtime_active(core->dev)) { + ret = false; + goto done; + } + } + + ret = core->ops->is_enabled(core->hw); +done: + clk_pm_runtime_put(core); + + return ret; } /*** helper functions ***/ @@ -489,6 +542,8 @@ static void clk_core_unprepare(struct clk_core *core) if (core->ops->unprepare) core->ops->unprepare(core->hw); + clk_pm_runtime_put(core); + trace_clk_unprepare_complete(core); clk_core_unprepare(core->parent); } @@ -530,10 +585,14 @@ static int clk_core_prepare(struct clk_core *core) return 0; if (core->prepare_count == 0) { - ret = clk_core_prepare(core->parent); + ret = clk_pm_runtime_get(core); if (ret) return ret; + ret = clk_core_prepare(core->parent); + if (ret) + goto runtime_put; + trace_clk_prepare(core); if (core->ops->prepare) @@ -541,15 +600,18 @@ static int clk_core_prepare(struct clk_core *core) trace_clk_prepare_complete(core); - if (ret) { - clk_core_unprepare(core->parent); - return ret; - } + if (ret) + goto unprepare; } core->prepare_count++; return 0; +unprepare: + clk_core_unprepare(core->parent); +runtime_put: + clk_pm_runtime_put(core); + return ret; } static int clk_core_prepare_lock(struct clk_core *core) @@ -745,6 +807,9 @@ static void clk_unprepare_unused_subtree(struct clk_core *core) if (core->flags & CLK_IGNORE_UNUSED) return; + if (clk_pm_runtime_get(core)) + return; + if (clk_core_is_prepared(core)) { trace_clk_unprepare(core); if (core->ops->unprepare_unused) @@ -753,6 +818,8 @@ static void clk_unprepare_unused_subtree(struct clk_core *core) core->ops->unprepare(core->hw); trace_clk_unprepare_complete(core); } + + clk_pm_runtime_put(core); } static void clk_disable_unused_subtree(struct clk_core *core) @@ -768,6 +835,9 @@ static void clk_disable_unused_subtree(struct clk_core *core) if (core->flags & CLK_OPS_PARENT_ENABLE) clk_core_prepare_enable(core->parent); + if (clk_pm_runtime_get(core)) + goto unprepare_out; + flags = clk_enable_lock(); if (core->enable_count) @@ -792,6 +862,8 @@ static void clk_disable_unused_subtree(struct clk_core *core) unlock_out: clk_enable_unlock(flags); + clk_pm_runtime_put(core); +unprepare_out: if (core->flags & CLK_OPS_PARENT_ENABLE) clk_core_disable_unprepare(core->parent); } @@ -1038,9 +1110,13 @@ EXPORT_SYMBOL_GPL(clk_get_accuracy); static unsigned long clk_recalc(struct clk_core *core, unsigned long parent_rate) { - if (core->ops->recalc_rate) - return core->ops->recalc_rate(core->hw, parent_rate); - return parent_rate; + unsigned long rate = parent_rate; + + if (core->ops->recalc_rate && !clk_pm_runtime_get(core)) { + rate = core->ops->recalc_rate(core->hw, parent_rate); + clk_pm_runtime_put(core); + } + return rate; } /** @@ -1565,6 +1641,7 @@ static int clk_core_set_rate_nolock(struct clk_core *core, { struct clk_core *top, *fail_clk; unsigned long rate = req_rate; + int ret = 0; if (!core) return 0; @@ -1581,21 +1658,28 @@ static int clk_core_set_rate_nolock(struct clk_core *core, if (!top) return -EINVAL; + ret = clk_pm_runtime_get(core); + if (ret) + return ret; + /* notify that we are about to change rates */ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE); if (fail_clk) { pr_debug("%s: failed to set %s rate\n", __func__, fail_clk->name); clk_propagate_rate_change(top, ABORT_RATE_CHANGE); - return -EBUSY; + ret = -EBUSY; + goto err; } /* change the rates */ clk_change_rate(top); core->req_rate = req_rate; +err: + clk_pm_runtime_put(core); - return 0; + return ret; } /** @@ -1826,12 +1910,16 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) p_rate = parent->rate; } + ret = clk_pm_runtime_get(core); + if (ret) + goto out; + /* propagate PRE_RATE_CHANGE notifications */ ret = __clk_speculate_rates(core, p_rate); /* abort if a driver objects */ if (ret & NOTIFY_STOP_MASK) - goto out; + goto runtime_put; /* do the re-parent */ ret = __clk_set_parent(core, parent, p_index); @@ -1844,6 +1932,8 @@ static int clk_core_set_parent(struct clk_core *core, struct clk_core *parent) __clk_recalc_accuracies(core); } +runtime_put: + clk_pm_runtime_put(core); out: clk_prepare_unlock(); @@ -2350,7 +2440,7 @@ static inline void clk_debug_unregister(struct clk_core *core) */ static int __clk_core_init(struct clk_core *core) { - int i, ret = 0; + int i, ret; struct clk_core *orphan; struct hlist_node *tmp2; unsigned long rate; @@ -2360,6 +2450,10 @@ static int __clk_core_init(struct clk_core *core) clk_prepare_lock(); + ret = clk_pm_runtime_get(core); + if (ret) + goto unlock; + /* check to see if a clock with this name is already registered */ if (clk_core_lookup(core->name)) { pr_debug("%s: clk %s already initialized\n", @@ -2512,6 +2606,8 @@ static int __clk_core_init(struct clk_core *core) kref_init(&core->ref); out: + clk_pm_runtime_put(core); +unlock: clk_prepare_unlock(); if (!ret) @@ -2583,6 +2679,8 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) goto fail_name; } core->ops = hw->init->ops; + if (dev && pm_runtime_enabled(dev)) + core->dev = dev; if (dev && dev->driver) core->owner = dev->driver->owner; core->hw = hw; @@ -3177,6 +3275,37 @@ int of_clk_add_hw_provider(struct device_node *np, } EXPORT_SYMBOL_GPL(of_clk_add_hw_provider); +static void devm_of_clk_release_provider(struct device *dev, void *res) +{ + of_clk_del_provider(*(struct device_node **)res); +} + +int devm_of_clk_add_hw_provider(struct device *dev, + struct clk_hw *(*get)(struct of_phandle_args *clkspec, + void *data), + void *data) +{ + struct device_node **ptr, *np; + int ret; + + ptr = devres_alloc(devm_of_clk_release_provider, sizeof(*ptr), + GFP_KERNEL); + if (!ptr) + return -ENOMEM; + + np = dev->of_node; + ret = of_clk_add_hw_provider(np, get, data); + if (!ret) { + *ptr = np; + devres_add(dev, ptr); + } else { + devres_free(ptr); + } + + return ret; +} +EXPORT_SYMBOL_GPL(devm_of_clk_add_hw_provider); + /** * of_clk_del_provider() - Remove a previously registered clock provider * @np: Device node pointer associated with clock provider @@ -3198,6 +3327,27 @@ void of_clk_del_provider(struct device_node *np) } EXPORT_SYMBOL_GPL(of_clk_del_provider); +static int devm_clk_provider_match(struct device *dev, void *res, void *data) +{ + struct device_node **np = res; + + if (WARN_ON(!np || !*np)) + return 0; + + return *np == data; +} + +void devm_of_clk_del_provider(struct device *dev) +{ + int ret; + + ret = devres_release(dev, devm_of_clk_release_provider, + devm_clk_provider_match, dev->of_node); + + WARN_ON(ret); +} +EXPORT_SYMBOL(devm_of_clk_del_provider); + static struct clk_hw * __of_clk_get_hw_from_provider(struct of_clk_provider *provider, struct of_phandle_args *clkspec) diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c index fa0fba653898..77072c7778b9 100644 --- a/drivers/clk/hisilicon/clk-hi3620.c +++ b/drivers/clk/hisilicon/clk-hi3620.c @@ -415,7 +415,7 @@ static int mmc_clk_set_rate(struct clk_hw *hw, unsigned long rate, return mmc_clk_set_timing(hw, rate); } -static struct clk_ops clk_mmc_ops = { +static const struct clk_ops clk_mmc_ops = { .prepare = mmc_clk_prepare, .determine_rate = mmc_clk_determine_rate, .set_rate = mmc_clk_set_rate, diff --git a/drivers/clk/hisilicon/clk-hi3660.c b/drivers/clk/hisilicon/clk-hi3660.c index a18258eb89cb..f40419959656 100644 --- a/drivers/clk/hisilicon/clk-hi3660.c +++ b/drivers/clk/hisilicon/clk-hi3660.c @@ -34,7 +34,7 @@ static const struct hisi_fixed_rate_clock hi3660_fixed_rate_clks[] = { /* crgctrl */ static const struct hisi_fixed_factor_clock hi3660_crg_fixed_factor_clks[] = { - { HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 8, 0, }, + { HI3660_FACTOR_UART3, "clk_factor_uart3", "iomcu_peri0", 1, 16, 0, }, { HI3660_CLK_FACTOR_MMC, "clk_factor_mmc", "clkin_sys", 1, 6, 0, }, { HI3660_CLK_GATE_I2C0, "clk_gate_i2c0", "clk_i2c0_iomcu", 1, 4, 0, }, { HI3660_CLK_GATE_I2C1, "clk_gate_i2c1", "clk_i2c1_iomcu", 1, 4, 0, }, diff --git a/drivers/clk/hisilicon/clk-hi6220.c b/drivers/clk/hisilicon/clk-hi6220.c index e786d717f75d..a87809d4bd52 100644 --- a/drivers/clk/hisilicon/clk-hi6220.c +++ b/drivers/clk/hisilicon/clk-hi6220.c @@ -145,7 +145,7 @@ static struct hisi_gate_clock hi6220_separated_gate_clks_sys[] __initdata = { { HI6220_BBPPLL_SEL, "bbppll_sel", "pll0_bbp_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 9, 0, }, { HI6220_MEDIA_PLL_SRC, "media_pll_src", "pll_media_gate", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 10, 0, }, { HI6220_MMC2_SEL, "mmc2_sel", "mmc2_mux1", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 11, 0, }, - { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IGNORE_UNUSED, 0x270, 12, 0, }, + { HI6220_CS_ATB_SYSPLL, "cs_atb_syspll", "syspll", CLK_SET_RATE_PARENT|CLK_IS_CRITICAL, 0x270, 12, 0, }, }; static struct hisi_mux_clock hi6220_mux_clks_sys[] __initdata = { diff --git a/drivers/clk/hisilicon/clk-hix5hd2.c b/drivers/clk/hisilicon/clk-hix5hd2.c index 14b05efa3c2a..9584f0c32dda 100644 --- a/drivers/clk/hisilicon/clk-hix5hd2.c +++ b/drivers/clk/hisilicon/clk-hix5hd2.c @@ -208,7 +208,7 @@ static void clk_ether_unprepare(struct clk_hw *hw) writel_relaxed(val, clk->ctrl_reg); } -static struct clk_ops clk_ether_ops = { +static const struct clk_ops clk_ether_ops = { .prepare = clk_ether_prepare, .unprepare = clk_ether_unprepare, }; @@ -247,7 +247,7 @@ static void clk_complex_disable(struct clk_hw *hw) writel_relaxed(val, clk->phy_reg); } -static struct clk_ops clk_complex_ops = { +static const struct clk_ops clk_complex_ops = { .enable = clk_complex_enable, .disable = clk_complex_disable, }; diff --git a/drivers/clk/hisilicon/clkgate-separated.c b/drivers/clk/hisilicon/clkgate-separated.c index 7908bc3c9ec7..f36bdef91831 100644 --- a/drivers/clk/hisilicon/clkgate-separated.c +++ b/drivers/clk/hisilicon/clkgate-separated.c @@ -88,7 +88,7 @@ static int clkgate_separated_is_enabled(struct clk_hw *hw) return reg ? 1 : 0; } -static struct clk_ops clkgate_separated_ops = { +static const struct clk_ops clkgate_separated_ops = { .enable = clkgate_separated_enable, .disable = clkgate_separated_disable, .is_enabled = clkgate_separated_is_enabled, @@ -105,10 +105,8 @@ struct clk *hisi_register_clkgate_sep(struct device *dev, const char *name, struct clk_init_data init; sclk = kzalloc(sizeof(*sclk), GFP_KERNEL); - if (!sclk) { - pr_err("%s: fail to allocate separated gated clk\n", __func__); + if (!sclk) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &clkgate_separated_ops; diff --git a/drivers/clk/hisilicon/crg-hi3798cv200.c b/drivers/clk/hisilicon/crg-hi3798cv200.c index ed8bb5f7507f..8478948e858e 100644 --- a/drivers/clk/hisilicon/crg-hi3798cv200.c +++ b/drivers/clk/hisilicon/crg-hi3798cv200.c @@ -47,6 +47,8 @@ #define HI3798CV200_FIXED_12M 81 #define HI3798CV200_FIXED_48M 82 #define HI3798CV200_FIXED_60M 83 +#define HI3798CV200_FIXED_166P5M 84 +#define HI3798CV200_SDIO0_MUX 85 #define HI3798CV200_CRG_NR_CLKS 128 @@ -63,6 +65,7 @@ static const struct hisi_fixed_rate_clock hi3798cv200_fixed_rate_clks[] = { { HI3798CV200_FIXED_75M, "75m", NULL, 0, 75000000, }, { HI3798CV200_FIXED_100M, "100m", NULL, 0, 100000000, }, { HI3798CV200_FIXED_150M, "150m", NULL, 0, 150000000, }, + { HI3798CV200_FIXED_166P5M, "166p5m", NULL, 0, 165000000, }, { HI3798CV200_FIXED_200M, "200m", NULL, 0, 200000000, }, { HI3798CV200_FIXED_250M, "250m", NULL, 0, 250000000, }, }; @@ -75,12 +78,19 @@ static const char *const comphy1_mux_p[] = { "100m", "25m"}; static u32 comphy1_mux_table[] = {2, 3}; +static const char *const sdio_mux_p[] = { + "100m", "50m", "150m", "166p5m" }; +static u32 sdio_mux_table[] = {0, 1, 2, 3}; + static struct hisi_mux_clock hi3798cv200_mux_clks[] = { { HI3798CV200_MMC_MUX, "mmc_mux", mmc_mux_p, ARRAY_SIZE(mmc_mux_p), CLK_SET_RATE_PARENT, 0xa0, 8, 3, 0, mmc_mux_table, }, { HI3798CV200_COMBPHY1_MUX, "combphy1_mux", comphy1_mux_p, ARRAY_SIZE(comphy1_mux_p), CLK_SET_RATE_PARENT, 0x188, 10, 2, 0, comphy1_mux_table, }, + { HI3798CV200_SDIO0_MUX, "sdio0_mux", sdio_mux_p, + ARRAY_SIZE(sdio_mux_p), CLK_SET_RATE_PARENT, + 0x9c, 8, 2, 0, sdio_mux_table, }, }; static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { @@ -104,7 +114,7 @@ static const struct hisi_gate_clock hi3798cv200_gate_clks[] = { /* SDIO */ { HISTB_SDIO0_BIU_CLK, "clk_sdio0_biu", "200m", CLK_SET_RATE_PARENT, 0x9c, 0, 0, }, - { HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "mmc_mux", + { HISTB_SDIO0_CIU_CLK, "clk_sdio0_ciu", "sdio0_mux", CLK_SET_RATE_PARENT, 0x9c, 1, 0, }, /* EMMC */ { HISTB_MMC_BIU_CLK, "clk_mmc_biu", "200m", diff --git a/drivers/clk/imx/clk-busy.c b/drivers/clk/imx/clk-busy.c index 5cc99590f9a3..6df3389687bc 100644 --- a/drivers/clk/imx/clk-busy.c +++ b/drivers/clk/imx/clk-busy.c @@ -72,7 +72,7 @@ static int clk_busy_divider_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static struct clk_ops clk_busy_divider_ops = { +static const struct clk_ops clk_busy_divider_ops = { .recalc_rate = clk_busy_divider_recalc_rate, .round_rate = clk_busy_divider_round_rate, .set_rate = clk_busy_divider_set_rate, @@ -147,7 +147,7 @@ static int clk_busy_mux_set_parent(struct clk_hw *hw, u8 index) return ret; } -static struct clk_ops clk_busy_mux_ops = { +static const struct clk_ops clk_busy_mux_ops = { .get_parent = clk_busy_mux_get_parent, .set_parent = clk_busy_mux_set_parent, }; diff --git a/drivers/clk/imx/clk-gate2.c b/drivers/clk/imx/clk-gate2.c index db44a198a0d9..60fc9d7a9723 100644 --- a/drivers/clk/imx/clk-gate2.c +++ b/drivers/clk/imx/clk-gate2.c @@ -118,7 +118,7 @@ static void clk_gate2_disable_unused(struct clk_hw *hw) spin_unlock_irqrestore(gate->lock, flags); } -static struct clk_ops clk_gate2_ops = { +static const struct clk_ops clk_gate2_ops = { .enable = clk_gate2_enable, .disable = clk_gate2_disable, .disable_unused = clk_gate2_disable_unused, diff --git a/drivers/clk/imx/clk-imx6q.c b/drivers/clk/imx/clk-imx6q.c index c07df719b8a3..8d518ad5dc13 100644 --- a/drivers/clk/imx/clk-imx6q.c +++ b/drivers/clk/imx/clk-imx6q.c @@ -761,7 +761,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node) clk[IMX6QDL_CLK_GPU2D_CORE] = imx_clk_gate2("gpu2d_core", "gpu2d_core_podf", base + 0x6c, 24); clk[IMX6QDL_CLK_GPU3D_CORE] = imx_clk_gate2("gpu3d_core", "gpu3d_core_podf", base + 0x6c, 26); clk[IMX6QDL_CLK_HDMI_IAHB] = imx_clk_gate2("hdmi_iahb", "ahb", base + 0x70, 0); - clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "video_27m", base + 0x70, 4); + clk[IMX6QDL_CLK_HDMI_ISFR] = imx_clk_gate2("hdmi_isfr", "mipi_core_cfg", base + 0x70, 4); clk[IMX6QDL_CLK_I2C1] = imx_clk_gate2("i2c1", "ipg_per", base + 0x70, 6); clk[IMX6QDL_CLK_I2C2] = imx_clk_gate2("i2c2", "ipg_per", base + 0x70, 8); clk[IMX6QDL_CLK_I2C3] = imx_clk_gate2("i2c3", "ipg_per", base + 0x70, 10); diff --git a/drivers/clk/imx/clk-imx6ul.c b/drivers/clk/imx/clk-imx6ul.c index 5e8c18afce9a..85c118164469 100644 --- a/drivers/clk/imx/clk-imx6ul.c +++ b/drivers/clk/imx/clk-imx6ul.c @@ -267,7 +267,7 @@ static void __init imx6ul_clocks_init(struct device_node *ccm_node) clks[IMX6ULL_CLK_EPDC_SEL] = imx_clk_mux("epdc_sel", base + 0x34, 9, 3, epdc_sels, ARRAY_SIZE(epdc_sels)); } clks[IMX6UL_CLK_ECSPI_SEL] = imx_clk_mux("ecspi_sel", base + 0x38, 18, 1, ecspi_sels, ARRAY_SIZE(ecspi_sels)); - clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels)); + clks[IMX6UL_CLK_LCDIF_PRE_SEL] = imx_clk_mux_flags("lcdif_pre_sel", base + 0x38, 15, 3, lcdif_pre_sels, ARRAY_SIZE(lcdif_pre_sels), CLK_SET_RATE_PARENT); clks[IMX6UL_CLK_LCDIF_SEL] = imx_clk_mux("lcdif_sel", base + 0x38, 9, 3, lcdif_sels, ARRAY_SIZE(lcdif_sels)); clks[IMX6UL_CLK_LDB_DI0_DIV_SEL] = imx_clk_mux("ldb_di0", base + 0x20, 10, 1, ldb_di0_div_sels, ARRAY_SIZE(ldb_di0_div_sels)); diff --git a/drivers/clk/imx/clk-imx7d.c b/drivers/clk/imx/clk-imx7d.c index 2305699db467..80dc211eb74b 100644 --- a/drivers/clk/imx/clk-imx7d.c +++ b/drivers/clk/imx/clk-imx7d.c @@ -54,11 +54,6 @@ static const char *arm_m4_sel[] = { "osc", "pll_sys_main_240m_clk", "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_usb_main_clk", }; -static const char *arm_m0_sel[] = { "osc", "pll_sys_main_120m_clk", - "pll_enet_125m_clk", "pll_sys_pfd2_135m_clk", - "pll_dram_533m_clk", "pll_audio_post_div", "pll_video_main_clk", - "pll_usb_main_clk", }; - static const char *axi_sel[] = { "osc", "pll_sys_pfd1_332m_clk", "pll_dram_533m_clk", "pll_enet_250m_clk", "pll_sys_pfd5_clk", "pll_audio_post_div", "pll_video_main_clk", "pll_sys_pfd7_clk", }; @@ -510,7 +505,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_ARM_A7_ROOT_SRC] = imx_clk_mux2("arm_a7_src", base + 0x8000, 24, 3, arm_a7_sel, ARRAY_SIZE(arm_a7_sel)); clks[IMX7D_ARM_M4_ROOT_SRC] = imx_clk_mux2("arm_m4_src", base + 0x8080, 24, 3, arm_m4_sel, ARRAY_SIZE(arm_m4_sel)); - clks[IMX7D_ARM_M0_ROOT_SRC] = imx_clk_mux2("arm_m0_src", base + 0x8100, 24, 3, arm_m0_sel, ARRAY_SIZE(arm_m0_sel)); clks[IMX7D_MAIN_AXI_ROOT_SRC] = imx_clk_mux2("axi_src", base + 0x8800, 24, 3, axi_sel, ARRAY_SIZE(axi_sel)); clks[IMX7D_DISP_AXI_ROOT_SRC] = imx_clk_mux2("disp_axi_src", base + 0x8880, 24, 3, disp_axi_sel, ARRAY_SIZE(disp_axi_sel)); clks[IMX7D_ENET_AXI_ROOT_SRC] = imx_clk_mux2("enet_axi_src", base + 0x8900, 24, 3, enet_axi_sel, ARRAY_SIZE(enet_axi_sel)); @@ -582,7 +576,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_ARM_A7_ROOT_CG] = imx_clk_gate3("arm_a7_cg", "arm_a7_src", base + 0x8000, 28); clks[IMX7D_ARM_M4_ROOT_CG] = imx_clk_gate3("arm_m4_cg", "arm_m4_src", base + 0x8080, 28); - clks[IMX7D_ARM_M0_ROOT_CG] = imx_clk_gate3("arm_m0_cg", "arm_m0_src", base + 0x8100, 28); clks[IMX7D_MAIN_AXI_ROOT_CG] = imx_clk_gate3("axi_cg", "axi_src", base + 0x8800, 28); clks[IMX7D_DISP_AXI_ROOT_CG] = imx_clk_gate3("disp_axi_cg", "disp_axi_src", base + 0x8880, 28); clks[IMX7D_ENET_AXI_ROOT_CG] = imx_clk_gate3("enet_axi_cg", "enet_axi_src", base + 0x8900, 28); @@ -721,7 +714,6 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_ARM_A7_ROOT_DIV] = imx_clk_divider2("arm_a7_div", "arm_a7_cg", base + 0x8000, 0, 3); clks[IMX7D_ARM_M4_ROOT_DIV] = imx_clk_divider2("arm_m4_div", "arm_m4_cg", base + 0x8080, 0, 3); - clks[IMX7D_ARM_M0_ROOT_DIV] = imx_clk_divider2("arm_m0_div", "arm_m0_cg", base + 0x8100, 0, 3); clks[IMX7D_MAIN_AXI_ROOT_DIV] = imx_clk_divider2("axi_post_div", "axi_pre_div", base + 0x8800, 0, 6); clks[IMX7D_DISP_AXI_ROOT_DIV] = imx_clk_divider2("disp_axi_post_div", "disp_axi_pre_div", base + 0x8880, 0, 6); clks[IMX7D_ENET_AXI_ROOT_DIV] = imx_clk_divider2("enet_axi_post_div", "enet_axi_pre_div", base + 0x8900, 0, 6); @@ -793,11 +785,10 @@ static void __init imx7d_clocks_init(struct device_node *ccm_node) clks[IMX7D_ARM_A7_ROOT_CLK] = imx_clk_gate4("arm_a7_root_clk", "arm_a7_div", base + 0x4000, 0); clks[IMX7D_ARM_M4_ROOT_CLK] = imx_clk_gate4("arm_m4_root_clk", "arm_m4_div", base + 0x4010, 0); - clks[IMX7D_ARM_M0_ROOT_CLK] = imx_clk_gate4("arm_m0_root_clk", "arm_m0_div", base + 0x4020, 0); clks[IMX7D_MAIN_AXI_ROOT_CLK] = imx_clk_gate4("main_axi_root_clk", "axi_post_div", base + 0x4040, 0); clks[IMX7D_DISP_AXI_ROOT_CLK] = imx_clk_gate4("disp_axi_root_clk", "disp_axi_post_div", base + 0x4050, 0); clks[IMX7D_ENET_AXI_ROOT_CLK] = imx_clk_gate4("enet_axi_root_clk", "enet_axi_post_div", base + 0x4060, 0); - clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "axi_post_div", base + 0x4110, 0); + clks[IMX7D_OCRAM_CLK] = imx_clk_gate4("ocram_clk", "main_axi_root_clk", base + 0x4110, 0); clks[IMX7D_OCRAM_S_CLK] = imx_clk_gate4("ocram_s_clk", "ahb_root_clk", base + 0x4120, 0); clks[IMX7D_DRAM_ROOT_CLK] = imx_clk_gate4("dram_root_clk", "dram_post_div", base + 0x4130, 0); clks[IMX7D_DRAM_PHYM_ROOT_CLK] = imx_clk_gate4("dram_phym_root_clk", "dram_phym_cg", base + 0x4130, 0); diff --git a/drivers/clk/imx/clk-pllv1.c b/drivers/clk/imx/clk-pllv1.c index e47a1c2fe8bd..4ba9973d4c18 100644 --- a/drivers/clk/imx/clk-pllv1.c +++ b/drivers/clk/imx/clk-pllv1.c @@ -107,7 +107,7 @@ static unsigned long clk_pllv1_recalc_rate(struct clk_hw *hw, return ull; } -static struct clk_ops clk_pllv1_ops = { +static const struct clk_ops clk_pllv1_ops = { .recalc_rate = clk_pllv1_recalc_rate, }; diff --git a/drivers/clk/imx/clk-pllv2.c b/drivers/clk/imx/clk-pllv2.c index 9842d657e974..85b5cbe9744c 100644 --- a/drivers/clk/imx/clk-pllv2.c +++ b/drivers/clk/imx/clk-pllv2.c @@ -227,7 +227,7 @@ static void clk_pllv2_unprepare(struct clk_hw *hw) __raw_writel(reg, pllbase + MXC_PLL_DP_CTL); } -static struct clk_ops clk_pllv2_ops = { +static const struct clk_ops clk_pllv2_ops = { .prepare = clk_pllv2_prepare, .unprepare = clk_pllv2_unprepare, .recalc_rate = clk_pllv2_recalc_rate, diff --git a/drivers/clk/mediatek/Kconfig b/drivers/clk/mediatek/Kconfig index 28739a9a6e37..59dc0aad553c 100644 --- a/drivers/clk/mediatek/Kconfig +++ b/drivers/clk/mediatek/Kconfig @@ -50,6 +50,56 @@ config COMMON_CLK_MT2701_BDPSYS ---help--- This driver supports Mediatek MT2701 bdpsys clocks. +config COMMON_CLK_MT2712 + bool "Clock driver for Mediatek MT2712" + depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK && ARM64 + ---help--- + This driver supports Mediatek MT2712 basic clocks. + +config COMMON_CLK_MT2712_BDPSYS + bool "Clock driver for Mediatek MT2712 bdpsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 bdpsys clocks. + +config COMMON_CLK_MT2712_IMGSYS + bool "Clock driver for Mediatek MT2712 imgsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 imgsys clocks. + +config COMMON_CLK_MT2712_JPGDECSYS + bool "Clock driver for Mediatek MT2712 jpgdecsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 jpgdecsys clocks. + +config COMMON_CLK_MT2712_MFGCFG + bool "Clock driver for Mediatek MT2712 mfgcfg" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 mfgcfg clocks. + +config COMMON_CLK_MT2712_MMSYS + bool "Clock driver for Mediatek MT2712 mmsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 mmsys clocks. + +config COMMON_CLK_MT2712_VDECSYS + bool "Clock driver for Mediatek MT2712 vdecsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 vdecsys clocks. + +config COMMON_CLK_MT2712_VENCSYS + bool "Clock driver for Mediatek MT2712 vencsys" + depends on COMMON_CLK_MT2712 + ---help--- + This driver supports Mediatek MT2712 vencsys clocks. + config COMMON_CLK_MT6797 bool "Clock driver for Mediatek MT6797" depends on (ARCH_MEDIATEK && ARM64) || COMPILE_TEST @@ -82,6 +132,36 @@ config COMMON_CLK_MT6797_VENCSYS ---help--- This driver supports Mediatek MT6797 vencsys clocks. +config COMMON_CLK_MT7622 + bool "Clock driver for MediaTek MT7622" + depends on ARCH_MEDIATEK || COMPILE_TEST + select COMMON_CLK_MEDIATEK + default ARCH_MEDIATEK + ---help--- + This driver supports MediaTek MT7622 basic clocks and clocks + required for various periperals found on MediaTek. + +config COMMON_CLK_MT7622_ETHSYS + bool "Clock driver for MediaTek MT7622 ETHSYS" + depends on COMMON_CLK_MT7622 + ---help--- + This driver add support for clocks for Ethernet and SGMII + required on MediaTek MT7622 SoC. + +config COMMON_CLK_MT7622_HIFSYS + bool "Clock driver for MediaTek MT7622 HIFSYS" + depends on COMMON_CLK_MT7622 + ---help--- + This driver supports MediaTek MT7622 HIFSYS clocks providing + to PCI-E and USB. + +config COMMON_CLK_MT7622_AUDSYS + bool "Clock driver for MediaTek MT7622 AUDSYS" + depends on COMMON_CLK_MT7622 + ---help--- + This driver supports MediaTek MT7622 AUDSYS clocks providing + to audio consumers such as I2S and TDM. + config COMMON_CLK_MT8135 bool "Clock driver for Mediatek MT8135" depends on (ARCH_MEDIATEK && ARM) || COMPILE_TEST diff --git a/drivers/clk/mediatek/Makefile b/drivers/clk/mediatek/Makefile index ba2a070765f0..c421ffcd49ff 100644 --- a/drivers/clk/mediatek/Makefile +++ b/drivers/clk/mediatek/Makefile @@ -13,5 +13,17 @@ obj-$(CONFIG_COMMON_CLK_MT2701_HIFSYS) += clk-mt2701-hif.o obj-$(CONFIG_COMMON_CLK_MT2701_IMGSYS) += clk-mt2701-img.o obj-$(CONFIG_COMMON_CLK_MT2701_MMSYS) += clk-mt2701-mm.o obj-$(CONFIG_COMMON_CLK_MT2701_VDECSYS) += clk-mt2701-vdec.o +obj-$(CONFIG_COMMON_CLK_MT2712) += clk-mt2712.o +obj-$(CONFIG_COMMON_CLK_MT2712_BDPSYS) += clk-mt2712-bdp.o +obj-$(CONFIG_COMMON_CLK_MT2712_IMGSYS) += clk-mt2712-img.o +obj-$(CONFIG_COMMON_CLK_MT2712_JPGDECSYS) += clk-mt2712-jpgdec.o +obj-$(CONFIG_COMMON_CLK_MT2712_MFGCFG) += clk-mt2712-mfg.o +obj-$(CONFIG_COMMON_CLK_MT2712_MMSYS) += clk-mt2712-mm.o +obj-$(CONFIG_COMMON_CLK_MT2712_VDECSYS) += clk-mt2712-vdec.o +obj-$(CONFIG_COMMON_CLK_MT2712_VENCSYS) += clk-mt2712-venc.o +obj-$(CONFIG_COMMON_CLK_MT7622) += clk-mt7622.o +obj-$(CONFIG_COMMON_CLK_MT7622_ETHSYS) += clk-mt7622-eth.o +obj-$(CONFIG_COMMON_CLK_MT7622_HIFSYS) += clk-mt7622-hif.o +obj-$(CONFIG_COMMON_CLK_MT7622_AUDSYS) += clk-mt7622-aud.o obj-$(CONFIG_COMMON_CLK_MT8135) += clk-mt8135.o obj-$(CONFIG_COMMON_CLK_MT8173) += clk-mt8173.o diff --git a/drivers/clk/mediatek/clk-mt2701.c b/drivers/clk/mediatek/clk-mt2701.c index 9598889f972b..8e7f16fd87c9 100644 --- a/drivers/clk/mediatek/clk-mt2701.c +++ b/drivers/clk/mediatek/clk-mt2701.c @@ -750,7 +750,7 @@ static const struct mtk_fixed_factor infra_fixed_divs[] = { static struct clk_onecell_data *infra_clk_data; -static void mtk_infrasys_init_early(struct device_node *node) +static void __init mtk_infrasys_init_early(struct device_node *node) { int r, i; diff --git a/drivers/clk/mediatek/clk-mt2712-bdp.c b/drivers/clk/mediatek/clk-mt2712-bdp.c new file mode 100644 index 000000000000..5fe4728c076e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-bdp.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs bdp_cg_regs = { + .set_ofs = 0x100, + .clr_ofs = 0x100, + .sta_ofs = 0x100, +}; + +#define GATE_BDP(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &bdp_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate bdp_clks[] = { + GATE_BDP(CLK_BDP_BRIDGE_B, "bdp_bridge_b", "mm_sel", 0), + GATE_BDP(CLK_BDP_BRIDGE_DRAM, "bdp_bridge_d", "mm_sel", 1), + GATE_BDP(CLK_BDP_LARB_DRAM, "bdp_larb_d", "mm_sel", 2), + GATE_BDP(CLK_BDP_WR_CHANNEL_VDI_PXL, "bdp_vdi_pxl", "tvd_sel", 3), + GATE_BDP(CLK_BDP_WR_CHANNEL_VDI_DRAM, "bdp_vdi_d", "mm_sel", 4), + GATE_BDP(CLK_BDP_WR_CHANNEL_VDI_B, "bdp_vdi_b", "mm_sel", 5), + GATE_BDP(CLK_BDP_MT_B, "bdp_fmt_b", "mm_sel", 9), + GATE_BDP(CLK_BDP_DISPFMT_27M, "bdp_27m", "di_sel", 10), + GATE_BDP(CLK_BDP_DISPFMT_27M_VDOUT, "bdp_27m_vdout", "di_sel", 11), + GATE_BDP(CLK_BDP_DISPFMT_27_74_74, "bdp_27_74_74", "di_sel", 12), + GATE_BDP(CLK_BDP_DISPFMT_2FS, "bdp_2fs", "di_sel", 13), + GATE_BDP(CLK_BDP_DISPFMT_2FS_2FS74_148, "bdp_2fs74_148", "di_sel", 14), + GATE_BDP(CLK_BDP_DISPFMT_B, "bdp_b", "mm_sel", 15), + GATE_BDP(CLK_BDP_VDO_DRAM, "bdp_vdo_d", "mm_sel", 16), + GATE_BDP(CLK_BDP_VDO_2FS, "bdp_vdo_2fs", "di_sel", 17), + GATE_BDP(CLK_BDP_VDO_B, "bdp_vdo_b", "mm_sel", 18), + GATE_BDP(CLK_BDP_WR_CHANNEL_DI_PXL, "bdp_di_pxl", "di_sel", 19), + GATE_BDP(CLK_BDP_WR_CHANNEL_DI_DRAM, "bdp_di_d", "mm_sel", 20), + GATE_BDP(CLK_BDP_WR_CHANNEL_DI_B, "bdp_di_b", "mm_sel", 21), + GATE_BDP(CLK_BDP_NR_AGENT, "bdp_nr_agent", "nr_sel", 22), + GATE_BDP(CLK_BDP_NR_DRAM, "bdp_nr_d", "mm_sel", 23), + GATE_BDP(CLK_BDP_NR_B, "bdp_nr_b", "mm_sel", 24), + GATE_BDP(CLK_BDP_BRIDGE_RT_B, "bdp_bridge_rt_b", "mm_sel", 25), + GATE_BDP(CLK_BDP_BRIDGE_RT_DRAM, "bdp_bridge_rt_d", "mm_sel", 26), + GATE_BDP(CLK_BDP_LARB_RT_DRAM, "bdp_larb_rt_d", "mm_sel", 27), + GATE_BDP(CLK_BDP_TVD_TDC, "bdp_tvd_tdc", "mm_sel", 28), + GATE_BDP(CLK_BDP_TVD_54, "bdp_tvd_clk_54", "tvd_sel", 29), + GATE_BDP(CLK_BDP_TVD_CBUS, "bdp_tvd_cbus", "mm_sel", 30), +}; + +static int clk_mt2712_bdp_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_BDP_NR_CLK); + + mtk_clk_register_gates(node, bdp_clks, ARRAY_SIZE(bdp_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_bdp[] = { + { .compatible = "mediatek,mt2712-bdpsys", }, + {} +}; + +static struct platform_driver clk_mt2712_bdp_drv = { + .probe = clk_mt2712_bdp_probe, + .driver = { + .name = "clk-mt2712-bdp", + .of_match_table = of_match_clk_mt2712_bdp, + }, +}; + +builtin_platform_driver(clk_mt2712_bdp_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-img.c b/drivers/clk/mediatek/clk-mt2712-img.c new file mode 100644 index 000000000000..139ff55d495e --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-img.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs img_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x0, + .sta_ofs = 0x0, +}; + +#define GATE_IMG(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &img_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate img_clks[] = { + GATE_IMG(CLK_IMG_SMI_LARB2, "img_smi_larb2", "mm_sel", 0), + GATE_IMG(CLK_IMG_SENINF_SCAM_EN, "img_scam_en", "csi0", 3), + GATE_IMG(CLK_IMG_SENINF_CAM_EN, "img_cam_en", "mm_sel", 8), + GATE_IMG(CLK_IMG_CAM_SV_EN, "img_cam_sv_en", "mm_sel", 9), + GATE_IMG(CLK_IMG_CAM_SV1_EN, "img_cam_sv1_en", "mm_sel", 10), + GATE_IMG(CLK_IMG_CAM_SV2_EN, "img_cam_sv2_en", "mm_sel", 11), +}; + +static int clk_mt2712_img_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_IMG_NR_CLK); + + mtk_clk_register_gates(node, img_clks, ARRAY_SIZE(img_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_img[] = { + { .compatible = "mediatek,mt2712-imgsys", }, + {} +}; + +static struct platform_driver clk_mt2712_img_drv = { + .probe = clk_mt2712_img_probe, + .driver = { + .name = "clk-mt2712-img", + .of_match_table = of_match_clk_mt2712_img, + }, +}; + +builtin_platform_driver(clk_mt2712_img_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-jpgdec.c b/drivers/clk/mediatek/clk-mt2712-jpgdec.c new file mode 100644 index 000000000000..c7d4aada4892 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-jpgdec.c @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs jpgdec_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_JPGDEC(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &jpgdec_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +static const struct mtk_gate jpgdec_clks[] = { + GATE_JPGDEC(CLK_JPGDEC_JPGDEC1, "jpgdec_jpgdec1", "jpgdec_sel", 0), + GATE_JPGDEC(CLK_JPGDEC_JPGDEC, "jpgdec_jpgdec", "jpgdec_sel", 4), +}; + +static int clk_mt2712_jpgdec_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_JPGDEC_NR_CLK); + + mtk_clk_register_gates(node, jpgdec_clks, ARRAY_SIZE(jpgdec_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_jpgdec[] = { + { .compatible = "mediatek,mt2712-jpgdecsys", }, + {} +}; + +static struct platform_driver clk_mt2712_jpgdec_drv = { + .probe = clk_mt2712_jpgdec_probe, + .driver = { + .name = "clk-mt2712-jpgdec", + .of_match_table = of_match_clk_mt2712_jpgdec, + }, +}; + +builtin_platform_driver(clk_mt2712_jpgdec_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-mfg.c b/drivers/clk/mediatek/clk-mt2712-mfg.c new file mode 100644 index 000000000000..570f72d48d4d --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-mfg.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs mfg_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_MFG(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mfg_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate mfg_clks[] = { + GATE_MFG(CLK_MFG_BG3D, "mfg_bg3d", "mfg_sel", 0), +}; + +static int clk_mt2712_mfg_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_MFG_NR_CLK); + + mtk_clk_register_gates(node, mfg_clks, ARRAY_SIZE(mfg_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_mfg[] = { + { .compatible = "mediatek,mt2712-mfgcfg", }, + {} +}; + +static struct platform_driver clk_mt2712_mfg_drv = { + .probe = clk_mt2712_mfg_probe, + .driver = { + .name = "clk-mt2712-mfg", + .of_match_table = of_match_clk_mt2712_mfg, + }, +}; + +builtin_platform_driver(clk_mt2712_mfg_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-mm.c b/drivers/clk/mediatek/clk-mt2712-mm.c new file mode 100644 index 000000000000..a8b4b6d42488 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-mm.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs mm0_cg_regs = { + .set_ofs = 0x104, + .clr_ofs = 0x108, + .sta_ofs = 0x100, +}; + +static const struct mtk_gate_regs mm1_cg_regs = { + .set_ofs = 0x114, + .clr_ofs = 0x118, + .sta_ofs = 0x110, +}; + +static const struct mtk_gate_regs mm2_cg_regs = { + .set_ofs = 0x224, + .clr_ofs = 0x228, + .sta_ofs = 0x220, +}; + +#define GATE_MM0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_MM1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_MM2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &mm2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate mm_clks[] = { + /* MM0 */ + GATE_MM0(CLK_MM_SMI_COMMON, "mm_smi_common", "mm_sel", 0), + GATE_MM0(CLK_MM_SMI_LARB0, "mm_smi_larb0", "mm_sel", 1), + GATE_MM0(CLK_MM_CAM_MDP, "mm_cam_mdp", "mm_sel", 2), + GATE_MM0(CLK_MM_MDP_RDMA0, "mm_mdp_rdma0", "mm_sel", 3), + GATE_MM0(CLK_MM_MDP_RDMA1, "mm_mdp_rdma1", "mm_sel", 4), + GATE_MM0(CLK_MM_MDP_RSZ0, "mm_mdp_rsz0", "mm_sel", 5), + GATE_MM0(CLK_MM_MDP_RSZ1, "mm_mdp_rsz1", "mm_sel", 6), + GATE_MM0(CLK_MM_MDP_RSZ2, "mm_mdp_rsz2", "mm_sel", 7), + GATE_MM0(CLK_MM_MDP_TDSHP0, "mm_mdp_tdshp0", "mm_sel", 8), + GATE_MM0(CLK_MM_MDP_TDSHP1, "mm_mdp_tdshp1", "mm_sel", 9), + GATE_MM0(CLK_MM_MDP_CROP, "mm_mdp_crop", "mm_sel", 10), + GATE_MM0(CLK_MM_MDP_WDMA, "mm_mdp_wdma", "mm_sel", 11), + GATE_MM0(CLK_MM_MDP_WROT0, "mm_mdp_wrot0", "mm_sel", 12), + GATE_MM0(CLK_MM_MDP_WROT1, "mm_mdp_wrot1", "mm_sel", 13), + GATE_MM0(CLK_MM_FAKE_ENG, "mm_fake_eng", "mm_sel", 14), + GATE_MM0(CLK_MM_MUTEX_32K, "mm_mutex_32k", "clk32k", 15), + GATE_MM0(CLK_MM_DISP_OVL0, "mm_disp_ovl0", "mm_sel", 16), + GATE_MM0(CLK_MM_DISP_OVL1, "mm_disp_ovl1", "mm_sel", 17), + GATE_MM0(CLK_MM_DISP_RDMA0, "mm_disp_rdma0", "mm_sel", 18), + GATE_MM0(CLK_MM_DISP_RDMA1, "mm_disp_rdma1", "mm_sel", 19), + GATE_MM0(CLK_MM_DISP_RDMA2, "mm_disp_rdma2", "mm_sel", 20), + GATE_MM0(CLK_MM_DISP_WDMA0, "mm_disp_wdma0", "mm_sel", 21), + GATE_MM0(CLK_MM_DISP_WDMA1, "mm_disp_wdma1", "mm_sel", 22), + GATE_MM0(CLK_MM_DISP_COLOR0, "mm_disp_color0", "mm_sel", 23), + GATE_MM0(CLK_MM_DISP_COLOR1, "mm_disp_color1", "mm_sel", 24), + GATE_MM0(CLK_MM_DISP_AAL, "mm_disp_aal", "mm_sel", 25), + GATE_MM0(CLK_MM_DISP_GAMMA, "mm_disp_gamma", "mm_sel", 26), + GATE_MM0(CLK_MM_DISP_UFOE, "mm_disp_ufoe", "mm_sel", 27), + GATE_MM0(CLK_MM_DISP_SPLIT0, "mm_disp_split0", "mm_sel", 28), + GATE_MM0(CLK_MM_DISP_OD, "mm_disp_od", "mm_sel", 31), + /* MM1 */ + GATE_MM1(CLK_MM_DISP_PWM0_MM, "mm_pwm0_mm", "mm_sel", 0), + GATE_MM1(CLK_MM_DISP_PWM0_26M, "mm_pwm0_26m", "pwm_sel", 1), + GATE_MM1(CLK_MM_DISP_PWM1_MM, "mm_pwm1_mm", "mm_sel", 2), + GATE_MM1(CLK_MM_DISP_PWM1_26M, "mm_pwm1_26m", "pwm_sel", 3), + GATE_MM1(CLK_MM_DSI0_ENGINE, "mm_dsi0_engine", "mm_sel", 4), + GATE_MM1(CLK_MM_DSI0_DIGITAL, "mm_dsi0_digital", "dsi0_lntc", 5), + GATE_MM1(CLK_MM_DSI1_ENGINE, "mm_dsi1_engine", "mm_sel", 6), + GATE_MM1(CLK_MM_DSI1_DIGITAL, "mm_dsi1_digital", "dsi1_lntc", 7), + GATE_MM1(CLK_MM_DPI_PIXEL, "mm_dpi_pixel", "vpll_dpix", 8), + GATE_MM1(CLK_MM_DPI_ENGINE, "mm_dpi_engine", "mm_sel", 9), + GATE_MM1(CLK_MM_DPI1_PIXEL, "mm_dpi1_pixel", "vpll3_dpix", 10), + GATE_MM1(CLK_MM_DPI1_ENGINE, "mm_dpi1_engine", "mm_sel", 11), + GATE_MM1(CLK_MM_LVDS_PIXEL, "mm_lvds_pixel", "vpll_dpix", 16), + GATE_MM1(CLK_MM_LVDS_CTS, "mm_lvds_cts", "lvdstx", 17), + GATE_MM1(CLK_MM_SMI_LARB4, "mm_smi_larb4", "mm_sel", 18), + GATE_MM1(CLK_MM_SMI_COMMON1, "mm_smi_common1", "mm_sel", 21), + GATE_MM1(CLK_MM_SMI_LARB5, "mm_smi_larb5", "mm_sel", 22), + GATE_MM1(CLK_MM_MDP_RDMA2, "mm_mdp_rdma2", "mm_sel", 23), + GATE_MM1(CLK_MM_MDP_TDSHP2, "mm_mdp_tdshp2", "mm_sel", 24), + GATE_MM1(CLK_MM_DISP_OVL2, "mm_disp_ovl2", "mm_sel", 25), + GATE_MM1(CLK_MM_DISP_WDMA2, "mm_disp_wdma2", "mm_sel", 26), + GATE_MM1(CLK_MM_DISP_COLOR2, "mm_disp_color2", "mm_sel", 27), + GATE_MM1(CLK_MM_DISP_AAL1, "mm_disp_aal1", "mm_sel", 28), + GATE_MM1(CLK_MM_DISP_OD1, "mm_disp_od1", "mm_sel", 29), + GATE_MM1(CLK_MM_LVDS1_PIXEL, "mm_lvds1_pixel", "vpll3_dpix", 30), + GATE_MM1(CLK_MM_LVDS1_CTS, "mm_lvds1_cts", "lvdstx3", 31), + /* MM2 */ + GATE_MM2(CLK_MM_SMI_LARB7, "mm_smi_larb7", "mm_sel", 0), + GATE_MM2(CLK_MM_MDP_RDMA3, "mm_mdp_rdma3", "mm_sel", 1), + GATE_MM2(CLK_MM_MDP_WROT2, "mm_mdp_wrot2", "mm_sel", 2), + GATE_MM2(CLK_MM_DSI2, "mm_dsi2", "mm_sel", 3), + GATE_MM2(CLK_MM_DSI2_DIGITAL, "mm_dsi2_digital", "dsi0_lntc", 4), + GATE_MM2(CLK_MM_DSI3, "mm_dsi3", "mm_sel", 5), + GATE_MM2(CLK_MM_DSI3_DIGITAL, "mm_dsi3_digital", "dsi1_lntc", 6), +}; + +static int clk_mt2712_mm_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_MM_NR_CLK); + + mtk_clk_register_gates(node, mm_clks, ARRAY_SIZE(mm_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_mm[] = { + { .compatible = "mediatek,mt2712-mmsys", }, + {} +}; + +static struct platform_driver clk_mt2712_mm_drv = { + .probe = clk_mt2712_mm_probe, + .driver = { + .name = "clk-mt2712-mm", + .of_match_table = of_match_clk_mt2712_mm, + }, +}; + +builtin_platform_driver(clk_mt2712_mm_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-vdec.c b/drivers/clk/mediatek/clk-mt2712-vdec.c new file mode 100644 index 000000000000..55c64ee8cc91 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-vdec.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs vdec0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x4, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs vdec1_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0xc, + .sta_ofs = 0x8, +}; + +#define GATE_VDEC0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vdec0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +#define GATE_VDEC1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &vdec1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +static const struct mtk_gate vdec_clks[] = { + /* VDEC0 */ + GATE_VDEC0(CLK_VDEC_CKEN, "vdec_cken", "vdec_sel", 0), + /* VDEC1 */ + GATE_VDEC1(CLK_VDEC_LARB1_CKEN, "vdec_larb1_cken", "vdec_sel", 0), + GATE_VDEC1(CLK_VDEC_IMGRZ_CKEN, "vdec_imgrz_cken", "vdec_sel", 1), +}; + +static int clk_mt2712_vdec_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_VDEC_NR_CLK); + + mtk_clk_register_gates(node, vdec_clks, ARRAY_SIZE(vdec_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_vdec[] = { + { .compatible = "mediatek,mt2712-vdecsys", }, + {} +}; + +static struct platform_driver clk_mt2712_vdec_drv = { + .probe = clk_mt2712_vdec_probe, + .driver = { + .name = "clk-mt2712-vdec", + .of_match_table = of_match_clk_mt2712_vdec, + }, +}; + +builtin_platform_driver(clk_mt2712_vdec_drv); diff --git a/drivers/clk/mediatek/clk-mt2712-venc.c b/drivers/clk/mediatek/clk-mt2712-venc.c new file mode 100644 index 000000000000..ccbfe98777c8 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712-venc.c @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static const struct mtk_gate_regs venc_cg_regs = { + .set_ofs = 0x4, + .clr_ofs = 0x8, + .sta_ofs = 0x0, +}; + +#define GATE_VENC(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &venc_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr_inv, \ + } + +static const struct mtk_gate venc_clks[] = { + GATE_VENC(CLK_VENC_SMI_COMMON_CON, "venc_smi", "mm_sel", 0), + GATE_VENC(CLK_VENC_VENC, "venc_venc", "venc_sel", 4), + GATE_VENC(CLK_VENC_SMI_LARB6, "venc_smi_larb6", "jpgdec_sel", 12), +}; + +static int clk_mt2712_venc_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_VENC_NR_CLK); + + mtk_clk_register_gates(node, venc_clks, ARRAY_SIZE(venc_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712_venc[] = { + { .compatible = "mediatek,mt2712-vencsys", }, + {} +}; + +static struct platform_driver clk_mt2712_venc_drv = { + .probe = clk_mt2712_venc_probe, + .driver = { + .name = "clk-mt2712-venc", + .of_match_table = of_match_clk_mt2712_venc, + }, +}; + +builtin_platform_driver(clk_mt2712_venc_drv); diff --git a/drivers/clk/mediatek/clk-mt2712.c b/drivers/clk/mediatek/clk-mt2712.c new file mode 100644 index 000000000000..498d13799388 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt2712.c @@ -0,0 +1,1435 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Weiyi Lu <weiyi.lu@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/mfd/syscon.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt2712-clk.h> + +static DEFINE_SPINLOCK(mt2712_clk_lock); + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_VPLL3_DPIX, "vpll3_dpix", NULL, 200000000), + FIXED_CLK(CLK_TOP_VPLL_DPIX, "vpll_dpix", NULL, 200000000), + FIXED_CLK(CLK_TOP_LTEPLL_FS26M, "ltepll_fs26m", NULL, 26000000), + FIXED_CLK(CLK_TOP_DMPLL, "dmpll_ck", NULL, 350000000), + FIXED_CLK(CLK_TOP_DSI0_LNTC, "dsi0_lntc", NULL, 143000000), + FIXED_CLK(CLK_TOP_DSI1_LNTC, "dsi1_lntc", NULL, 143000000), + FIXED_CLK(CLK_TOP_LVDSTX3_CLKDIG_CTS, "lvdstx3", NULL, 140000000), + FIXED_CLK(CLK_TOP_LVDSTX_CLKDIG_CTS, "lvdstx", NULL, 140000000), + FIXED_CLK(CLK_TOP_CLKRTC_EXT, "clkrtc_ext", NULL, 32768), + FIXED_CLK(CLK_TOP_CLKRTC_INT, "clkrtc_int", NULL, 32747), + FIXED_CLK(CLK_TOP_CSI0, "csi0", NULL, 26000000), + FIXED_CLK(CLK_TOP_CVBSPLL, "cvbspll", NULL, 108000000), +}; + +static const struct mtk_fixed_factor top_early_divs[] = { + FACTOR(CLK_TOP_SYS_26M, "sys_26m", "clk26m", 1, + 1), + FACTOR(CLK_TOP_CLK26M_D2, "clk26m_d2", "sys_26m", 1, + 2), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_ARMCA35PLL, "armca35pll_ck", "armca35pll", 1, + 1), + FACTOR(CLK_TOP_ARMCA35PLL_600M, "armca35pll_600m", "armca35pll_ck", 1, + 2), + FACTOR(CLK_TOP_ARMCA35PLL_400M, "armca35pll_400m", "armca35pll_ck", 1, + 3), + FACTOR(CLK_TOP_ARMCA72PLL, "armca72pll_ck", "armca72pll", 1, + 1), + FACTOR(CLK_TOP_SYSPLL, "syspll_ck", "mainpll", 1, + 1), + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "syspll_ck", 1, + 2), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "syspll_d2", 1, + 2), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "syspll_d2", 1, + 4), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "syspll_d2", 1, + 8), + FACTOR(CLK_TOP_SYSPLL1_D16, "syspll1_d16", "syspll_d2", 1, + 16), + FACTOR(CLK_TOP_SYSPLL_D3, "syspll_d3", "syspll_ck", 1, + 3), + FACTOR(CLK_TOP_SYSPLL2_D2, "syspll2_d2", "syspll_d3", 1, + 2), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "syspll_d3", 1, + 4), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "syspll_ck", 1, + 5), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "syspll_d5", 1, + 2), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "syspll_d5", 1, + 4), + FACTOR(CLK_TOP_SYSPLL_D7, "syspll_d7", "syspll_ck", 1, + 7), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "syspll_d7", 1, + 2), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "syspll_d7", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL, "univpll_ck", "univpll", 1, + 1), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll_ck", 1, + 7), + FACTOR(CLK_TOP_UNIVPLL_D26, "univpll_d26", "univpll_ck", 1, + 26), + FACTOR(CLK_TOP_UNIVPLL_D52, "univpll_d52", "univpll_ck", 1, + 52), + FACTOR(CLK_TOP_UNIVPLL_D104, "univpll_d104", "univpll_ck", 1, + 104), + FACTOR(CLK_TOP_UNIVPLL_D208, "univpll_d208", "univpll_ck", 1, + 208), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll_ck", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll_d2", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll_d2", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll_d2", 1, + 8), + FACTOR(CLK_TOP_UNIVPLL_D3, "univpll_d3", "univpll_ck", 1, + 3), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll_d3", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll_d3", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll_d3", 1, + 8), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll_ck", 1, + 5), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll_d5", 1, + 2), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll_d5", 1, + 4), + FACTOR(CLK_TOP_UNIVPLL3_D8, "univpll3_d8", "univpll_d5", 1, + 8), + FACTOR(CLK_TOP_F_MP0_PLL1, "f_mp0_pll1_ck", "univpll_d2", 1, + 1), + FACTOR(CLK_TOP_F_MP0_PLL2, "f_mp0_pll2_ck", "univpll1_d2", 1, + 1), + FACTOR(CLK_TOP_F_BIG_PLL1, "f_big_pll1_ck", "univpll_d2", 1, + 1), + FACTOR(CLK_TOP_F_BIG_PLL2, "f_big_pll2_ck", "univpll1_d2", 1, + 1), + FACTOR(CLK_TOP_F_BUS_PLL1, "f_bus_pll1_ck", "univpll_d2", 1, + 1), + FACTOR(CLK_TOP_F_BUS_PLL2, "f_bus_pll2_ck", "univpll1_d2", 1, + 1), + FACTOR(CLK_TOP_APLL1, "apll1_ck", "apll1", 1, + 1), + FACTOR(CLK_TOP_APLL1_D2, "apll1_d2", "apll1_ck", 1, + 2), + FACTOR(CLK_TOP_APLL1_D4, "apll1_d4", "apll1_ck", 1, + 4), + FACTOR(CLK_TOP_APLL1_D8, "apll1_d8", "apll1_ck", 1, + 8), + FACTOR(CLK_TOP_APLL1_D16, "apll1_d16", "apll1_ck", 1, + 16), + FACTOR(CLK_TOP_APLL2, "apll2_ck", "apll2", 1, + 1), + FACTOR(CLK_TOP_APLL2_D2, "apll2_d2", "apll2_ck", 1, + 2), + FACTOR(CLK_TOP_APLL2_D4, "apll2_d4", "apll2_ck", 1, + 4), + FACTOR(CLK_TOP_APLL2_D8, "apll2_d8", "apll2_ck", 1, + 8), + FACTOR(CLK_TOP_APLL2_D16, "apll2_d16", "apll2_ck", 1, + 16), + FACTOR(CLK_TOP_LVDSPLL, "lvdspll_ck", "lvdspll", 1, + 1), + FACTOR(CLK_TOP_LVDSPLL_D2, "lvdspll_d2", "lvdspll_ck", 1, + 2), + FACTOR(CLK_TOP_LVDSPLL_D4, "lvdspll_d4", "lvdspll_ck", 1, + 4), + FACTOR(CLK_TOP_LVDSPLL_D8, "lvdspll_d8", "lvdspll_ck", 1, + 8), + FACTOR(CLK_TOP_LVDSPLL2, "lvdspll2_ck", "lvdspll2", 1, + 1), + FACTOR(CLK_TOP_LVDSPLL2_D2, "lvdspll2_d2", "lvdspll2_ck", 1, + 2), + FACTOR(CLK_TOP_LVDSPLL2_D4, "lvdspll2_d4", "lvdspll2_ck", 1, + 4), + FACTOR(CLK_TOP_LVDSPLL2_D8, "lvdspll2_d8", "lvdspll2_ck", 1, + 8), + FACTOR(CLK_TOP_ETHERPLL_125M, "etherpll_125m", "etherpll", 1, + 1), + FACTOR(CLK_TOP_ETHERPLL_50M, "etherpll_50m", "etherpll", 1, + 1), + FACTOR(CLK_TOP_CVBS, "cvbs", "cvbspll", 1, + 1), + FACTOR(CLK_TOP_CVBS_D2, "cvbs_d2", "cvbs", 1, + 2), + FACTOR(CLK_TOP_MMPLL, "mmpll_ck", "mmpll", 1, + 1), + FACTOR(CLK_TOP_MMPLL_D2, "mmpll_d2", "mmpll_ck", 1, + 2), + FACTOR(CLK_TOP_VENCPLL, "vencpll_ck", "vencpll", 1, + 1), + FACTOR(CLK_TOP_VENCPLL_D2, "vencpll_d2", "vencpll_ck", 1, + 2), + FACTOR(CLK_TOP_VCODECPLL, "vcodecpll_ck", "vcodecpll", 1, + 1), + FACTOR(CLK_TOP_VCODECPLL_D2, "vcodecpll_d2", "vcodecpll_ck", 1, + 2), + FACTOR(CLK_TOP_TVDPLL, "tvdpll_ck", "tvdpll", 1, + 1), + FACTOR(CLK_TOP_TVDPLL_D2, "tvdpll_d2", "tvdpll_ck", 1, + 2), + FACTOR(CLK_TOP_TVDPLL_D4, "tvdpll_d4", "tvdpll_ck", 1, + 4), + FACTOR(CLK_TOP_TVDPLL_D8, "tvdpll_d8", "tvdpll_ck", 1, + 8), + FACTOR(CLK_TOP_TVDPLL_429M, "tvdpll_429m", "tvdpll", 1, + 1), + FACTOR(CLK_TOP_TVDPLL_429M_D2, "tvdpll_429m_d2", "tvdpll_429m", 1, + 2), + FACTOR(CLK_TOP_TVDPLL_429M_D4, "tvdpll_429m_d4", "tvdpll_429m", 1, + 4), + FACTOR(CLK_TOP_MSDCPLL, "msdcpll_ck", "msdcpll", 1, + 1), + FACTOR(CLK_TOP_MSDCPLL_D2, "msdcpll_d2", "msdcpll_ck", 1, + 2), + FACTOR(CLK_TOP_MSDCPLL_D4, "msdcpll_d4", "msdcpll_ck", 1, + 4), + FACTOR(CLK_TOP_MSDCPLL2, "msdcpll2_ck", "msdcpll2", 1, + 1), + FACTOR(CLK_TOP_MSDCPLL2_D2, "msdcpll2_d2", "msdcpll2_ck", 1, + 2), + FACTOR(CLK_TOP_MSDCPLL2_D4, "msdcpll2_d4", "msdcpll2_ck", 1, + 4), + FACTOR(CLK_TOP_D2A_ULCLK_6P5M, "d2a_ulclk_6p5m", "clk26m", 1, + 4), +}; + +static const char * const axi_parents[] = { + "clk26m", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "msdcpll2_ck" +}; + +static const char * const mem_parents[] = { + "clk26m", + "dmpll_ck" +}; + +static const char * const mm_parents[] = { + "clk26m", + "vencpll_ck", + "syspll_d3", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll1_d2", + "univpll2_d2" +}; + +static const char * const pwm_parents[] = { + "clk26m", + "univpll2_d4", + "univpll3_d2", + "univpll1_d4" +}; + +static const char * const vdec_parents[] = { + "clk26m", + "vcodecpll_ck", + "tvdpll_429m", + "univpll_d3", + "vencpll_ck", + "syspll_d3", + "univpll1_d2", + "mmpll_d2", + "syspll3_d2", + "tvdpll_ck" +}; + +static const char * const venc_parents[] = { + "clk26m", + "univpll1_d2", + "mmpll_d2", + "tvdpll_d2", + "syspll1_d2", + "univpll_d5", + "vcodecpll_d2", + "univpll2_d2", + "syspll3_d2" +}; + +static const char * const mfg_parents[] = { + "clk26m", + "mmpll_ck", + "univpll_d3", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "clk26m", + "syspll_d3", + "syspll1_d2", + "syspll_d5", + "univpll_d3", + "univpll1_d2", + "univpll_d5", + "univpll2_d2" +}; + +static const char * const camtg_parents[] = { + "clk26m", + "univpll_d52", + "univpll_d208", + "univpll_d104", + "clk26m_d2", + "univpll_d26", + "univpll2_d8", + "syspll3_d4", + "syspll3_d2", + "univpll1_d4", + "univpll2_d2" +}; + +static const char * const uart_parents[] = { + "clk26m", + "univpll2_d8" +}; + +static const char * const spi_parents[] = { + "clk26m", + "univpll2_d4", + "univpll1_d4", + "univpll2_d2", + "univpll3_d2", + "univpll1_d8" +}; + +static const char * const usb20_parents[] = { + "clk26m", + "univpll1_d8", + "univpll3_d4" +}; + +static const char * const usb30_parents[] = { + "clk26m", + "univpll3_d2", + "univpll3_d4", + "univpll2_d4" +}; + +static const char * const msdc50_0_h_parents[] = { + "clk26m", + "syspll1_d2", + "syspll2_d2", + "syspll4_d2", + "univpll_d5", + "univpll1_d4" +}; + +static const char * const msdc50_0_parents[] = { + "clk26m", + "msdcpll_ck", + "msdcpll_d2", + "univpll1_d4", + "syspll2_d2", + "msdcpll_d4", + "vencpll_d2", + "univpll1_d2", + "msdcpll2_ck", + "msdcpll2_d2", + "msdcpll2_d4" +}; + +static const char * const msdc30_1_parents[] = { + "clk26m", + "univpll2_d2", + "msdcpll_d2", + "univpll1_d4", + "syspll2_d2", + "univpll_d7", + "vencpll_d2" +}; + +static const char * const msdc30_3_parents[] = { + "clk26m", + "msdcpll2_ck", + "msdcpll2_d2", + "univpll2_d2", + "msdcpll2_d4", + "univpll1_d4", + "syspll2_d2", + "syspll_d7", + "univpll_d7", + "vencpll_d2", + "msdcpll_ck", + "msdcpll_d2", + "msdcpll_d4" +}; + +static const char * const audio_parents[] = { + "clk26m", + "syspll3_d4", + "syspll4_d4", + "syspll1_d16" +}; + +static const char * const aud_intbus_parents[] = { + "clk26m", + "syspll1_d4", + "syspll4_d2", + "univpll3_d2", + "univpll2_d8", + "syspll3_d2", + "syspll3_d4" +}; + +static const char * const pmicspi_parents[] = { + "clk26m", + "syspll1_d8", + "syspll3_d4", + "syspll1_d16", + "univpll3_d4", + "univpll_d26", + "syspll3_d4" +}; + +static const char * const dpilvds1_parents[] = { + "clk26m", + "lvdspll2_ck", + "lvdspll2_d2", + "lvdspll2_d4", + "lvdspll2_d8", + "clkfpc" +}; + +static const char * const atb_parents[] = { + "clk26m", + "syspll1_d2", + "univpll_d5", + "syspll_d5" +}; + +static const char * const nr_parents[] = { + "clk26m", + "univpll1_d4", + "syspll2_d2", + "syspll1_d4", + "univpll1_d8", + "univpll3_d2", + "univpll2_d2", + "syspll_d5" +}; + +static const char * const nfi2x_parents[] = { + "clk26m", + "syspll4_d4", + "univpll3_d4", + "univpll1_d8", + "syspll2_d4", + "univpll3_d2", + "syspll_d7", + "syspll2_d2", + "univpll2_d2", + "syspll_d5", + "syspll1_d2" +}; + +static const char * const irda_parents[] = { + "clk26m", + "univpll2_d4", + "syspll2_d4", + "univpll2_d8" +}; + +static const char * const cci400_parents[] = { + "clk26m", + "vencpll_ck", + "armca35pll_600m", + "armca35pll_400m", + "univpll_d2", + "syspll_d2", + "msdcpll_ck", + "univpll_d3" +}; + +static const char * const aud_1_parents[] = { + "clk26m", + "apll1_ck", + "univpll2_d4", + "univpll2_d8" +}; + +static const char * const aud_2_parents[] = { + "clk26m", + "apll2_ck", + "univpll2_d4", + "univpll2_d8" +}; + +static const char * const mem_mfg_parents[] = { + "clk26m", + "mmpll_ck", + "univpll_d3" +}; + +static const char * const axi_mfg_parents[] = { + "clk26m", + "axi_sel", + "univpll_d5" +}; + +static const char * const scam_parents[] = { + "clk26m", + "syspll3_d2", + "univpll2_d4", + "syspll2_d4" +}; + +static const char * const nfiecc_parents[] = { + "clk26m", + "nfi2x_sel", + "syspll_d7", + "syspll2_d2", + "univpll2_d2", + "univpll_d5", + "syspll1_d2" +}; + +static const char * const pe2_mac_p0_parents[] = { + "clk26m", + "syspll1_d8", + "syspll4_d2", + "syspll2_d4", + "univpll2_d4", + "syspll3_d2" +}; + +static const char * const dpilvds_parents[] = { + "clk26m", + "lvdspll_ck", + "lvdspll_d2", + "lvdspll_d4", + "lvdspll_d8", + "clkfpc" +}; + +static const char * const hdcp_parents[] = { + "clk26m", + "syspll4_d2", + "syspll3_d4", + "univpll2_d4" +}; + +static const char * const hdcp_24m_parents[] = { + "clk26m", + "univpll_d26", + "univpll_d52", + "univpll2_d8" +}; + +static const char * const rtc_parents[] = { + "clkrtc_int", + "clkrtc_ext", + "clk26m", + "univpll3_d8" +}; + +static const char * const spinor_parents[] = { + "clk26m", + "clk26m_d2", + "syspll4_d4", + "univpll2_d8", + "univpll3_d4", + "syspll4_d2", + "syspll2_d4", + "univpll2_d4", + "etherpll_125m", + "syspll1_d4" +}; + +static const char * const apll_parents[] = { + "clk26m", + "apll1_ck", + "apll1_d2", + "apll1_d4", + "apll1_d8", + "apll1_d16", + "apll2_ck", + "apll2_d2", + "apll2_d4", + "apll2_d8", + "apll2_d16", + "clk26m", + "clk26m" +}; + +static const char * const a1sys_hp_parents[] = { + "clk26m", + "apll1_ck", + "apll1_d2", + "apll1_d4", + "apll1_d8" +}; + +static const char * const a2sys_hp_parents[] = { + "clk26m", + "apll2_ck", + "apll2_d2", + "apll2_d4", + "apll2_d8" +}; + +static const char * const asm_l_parents[] = { + "clk26m", + "univpll2_d4", + "univpll2_d2", + "syspll_d5" +}; + +static const char * const i2so1_parents[] = { + "clk26m", + "apll1_ck", + "apll2_ck" +}; + +static const char * const ether_125m_parents[] = { + "clk26m", + "etherpll_125m", + "univpll3_d2" +}; + +static const char * const ether_50m_parents[] = { + "clk26m", + "etherpll_50m", + "univpll_d26", + "univpll3_d4" +}; + +static const char * const jpgdec_parents[] = { + "clk26m", + "univpll_d3", + "tvdpll_429m", + "vencpll_ck", + "syspll_d3", + "vcodecpll_ck", + "univpll1_d2", + "armca35pll_400m", + "tvdpll_429m_d2", + "tvdpll_429m_d4" +}; + +static const char * const spislv_parents[] = { + "clk26m", + "univpll2_d4", + "univpll1_d4", + "univpll2_d2", + "univpll3_d2", + "univpll1_d8", + "univpll1_d2", + "univpll_d5" +}; + +static const char * const ether_parents[] = { + "clk26m", + "etherpll_50m", + "univpll_d26" +}; + +static const char * const di_parents[] = { + "clk26m", + "tvdpll_d2", + "tvdpll_d4", + "tvdpll_d8", + "vencpll_ck", + "vencpll_d2", + "cvbs", + "cvbs_d2" +}; + +static const char * const tvd_parents[] = { + "clk26m", + "cvbs_d2", + "univpll2_d8" +}; + +static const char * const i2c_parents[] = { + "clk26m", + "univpll_d26", + "univpll2_d4", + "univpll3_d2", + "univpll1_d4" +}; + +static const char * const msdc0p_aes_parents[] = { + "clk26m", + "msdcpll_ck", + "univpll_d3", + "vcodecpll_ck" +}; + +static const char * const cmsys_parents[] = { + "clk26m", + "univpll_d3", + "syspll_d3", + "syspll1_d2", + "syspll2_d2" +}; + +static const char * const gcpu_parents[] = { + "clk26m", + "syspll_d3", + "syspll1_d2", + "univpll1_d2", + "univpll_d5", + "univpll3_d2", + "univpll_d3" +}; + +static const char * const aud_apll1_parents[] = { + "apll1", + "clkaud_ext_i_1" +}; + +static const char * const aud_apll2_parents[] = { + "apll2", + "clkaud_ext_i_2" +}; + +static const char * const audull_vtx_parents[] = { + "d2a_ulclk_6p5m", + "clkaud_ext_i_0" +}; + +static struct mtk_composite top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE_FLAGS(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, 0x040, 0, 3, + 7, CLK_IS_CRITICAL), + MUX_GATE_FLAGS(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, 0x040, 8, 1, + 15, CLK_IS_CRITICAL), + MUX_GATE(CLK_TOP_MM_SEL, "mm_sel", + mm_parents, 0x040, 24, 3, 31), + /* CLK_CFG_1 */ + MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", + pwm_parents, 0x050, 0, 2, 7), + MUX_GATE(CLK_TOP_VDEC_SEL, "vdec_sel", + vdec_parents, 0x050, 8, 4, 15), + MUX_GATE(CLK_TOP_VENC_SEL, "venc_sel", + venc_parents, 0x050, 16, 4, 23), + MUX_GATE(CLK_TOP_MFG_SEL, "mfg_sel", + mfg_parents, 0x050, 24, 4, 31), + /* CLK_CFG_2 */ + MUX_GATE(CLK_TOP_CAMTG_SEL, "camtg_sel", + camtg_parents, 0x060, 0, 4, 7), + MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", + uart_parents, 0x060, 8, 1, 15), + MUX_GATE(CLK_TOP_SPI_SEL, "spi_sel", + spi_parents, 0x060, 16, 3, 23), + MUX_GATE(CLK_TOP_USB20_SEL, "usb20_sel", + usb20_parents, 0x060, 24, 2, 31), + /* CLK_CFG_3 */ + MUX_GATE(CLK_TOP_USB30_SEL, "usb30_sel", + usb30_parents, 0x070, 0, 2, 7), + MUX_GATE(CLK_TOP_MSDC50_0_HCLK_SEL, "msdc50_0_h_sel", + msdc50_0_h_parents, 0x070, 8, 3, 15), + MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", + msdc50_0_parents, 0x070, 16, 4, 23), + MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", + msdc30_1_parents, 0x070, 24, 3, 31), + /* CLK_CFG_4 */ + MUX_GATE(CLK_TOP_MSDC30_2_SEL, "msdc30_2_sel", + msdc30_1_parents, 0x080, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_3_SEL, "msdc30_3_sel", + msdc30_3_parents, 0x080, 8, 4, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", + audio_parents, 0x080, 16, 2, 23), + MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", + aud_intbus_parents, 0x080, 24, 3, 31), + /* CLK_CFG_5 */ + MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", + pmicspi_parents, 0x090, 0, 3, 7), + MUX_GATE(CLK_TOP_DPILVDS1_SEL, "dpilvds1_sel", + dpilvds1_parents, 0x090, 8, 3, 15), + MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", + atb_parents, 0x090, 16, 2, 23), + MUX_GATE(CLK_TOP_NR_SEL, "nr_sel", + nr_parents, 0x090, 24, 3, 31), + /* CLK_CFG_6 */ + MUX_GATE(CLK_TOP_NFI2X_SEL, "nfi2x_sel", + nfi2x_parents, 0x0a0, 0, 4, 7), + MUX_GATE(CLK_TOP_IRDA_SEL, "irda_sel", + irda_parents, 0x0a0, 8, 2, 15), + MUX_GATE(CLK_TOP_CCI400_SEL, "cci400_sel", + cci400_parents, 0x0a0, 16, 3, 23), + MUX_GATE(CLK_TOP_AUD_1_SEL, "aud_1_sel", + aud_1_parents, 0x0a0, 24, 2, 31), + /* CLK_CFG_7 */ + MUX_GATE(CLK_TOP_AUD_2_SEL, "aud_2_sel", + aud_2_parents, 0x0b0, 0, 2, 7), + MUX_GATE(CLK_TOP_MEM_MFG_IN_AS_SEL, "mem_mfg_sel", + mem_mfg_parents, 0x0b0, 8, 2, 15), + MUX_GATE(CLK_TOP_AXI_MFG_IN_AS_SEL, "axi_mfg_sel", + axi_mfg_parents, 0x0b0, 16, 2, 23), + MUX_GATE(CLK_TOP_SCAM_SEL, "scam_sel", + scam_parents, 0x0b0, 24, 2, 31), + /* CLK_CFG_8 */ + MUX_GATE(CLK_TOP_NFIECC_SEL, "nfiecc_sel", + nfiecc_parents, 0x0c0, 0, 3, 7), + MUX_GATE(CLK_TOP_PE2_MAC_P0_SEL, "pe2_mac_p0_sel", + pe2_mac_p0_parents, 0x0c0, 8, 3, 15), + MUX_GATE(CLK_TOP_PE2_MAC_P1_SEL, "pe2_mac_p1_sel", + pe2_mac_p0_parents, 0x0c0, 16, 3, 23), + MUX_GATE(CLK_TOP_DPILVDS_SEL, "dpilvds_sel", + dpilvds_parents, 0x0c0, 24, 3, 31), + /* CLK_CFG_9 */ + MUX_GATE(CLK_TOP_MSDC50_3_HCLK_SEL, "msdc50_3_h_sel", + msdc50_0_h_parents, 0x0d0, 0, 3, 7), + MUX_GATE(CLK_TOP_HDCP_SEL, "hdcp_sel", + hdcp_parents, 0x0d0, 8, 2, 15), + MUX_GATE(CLK_TOP_HDCP_24M_SEL, "hdcp_24m_sel", + hdcp_24m_parents, 0x0d0, 16, 2, 23), + MUX_GATE_FLAGS(CLK_TOP_RTC_SEL, "rtc_sel", rtc_parents, 0x0d0, 24, 2, + 31, CLK_IS_CRITICAL), + /* CLK_CFG_10 */ + MUX_GATE(CLK_TOP_SPINOR_SEL, "spinor_sel", + spinor_parents, 0x500, 0, 4, 7), + MUX_GATE(CLK_TOP_APLL_SEL, "apll_sel", + apll_parents, 0x500, 8, 4, 15), + MUX_GATE(CLK_TOP_APLL2_SEL, "apll2_sel", + apll_parents, 0x500, 16, 4, 23), + MUX_GATE(CLK_TOP_A1SYS_HP_SEL, "a1sys_hp_sel", + a1sys_hp_parents, 0x500, 24, 3, 31), + /* CLK_CFG_11 */ + MUX_GATE(CLK_TOP_A2SYS_HP_SEL, "a2sys_hp_sel", + a2sys_hp_parents, 0x510, 0, 3, 7), + MUX_GATE(CLK_TOP_ASM_L_SEL, "asm_l_sel", + asm_l_parents, 0x510, 8, 2, 15), + MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", + asm_l_parents, 0x510, 16, 2, 23), + MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", + asm_l_parents, 0x510, 24, 2, 31), + /* CLK_CFG_12 */ + MUX_GATE(CLK_TOP_I2SO1_SEL, "i2so1_sel", + i2so1_parents, 0x520, 0, 2, 7), + MUX_GATE(CLK_TOP_I2SO2_SEL, "i2so2_sel", + i2so1_parents, 0x520, 8, 2, 15), + MUX_GATE(CLK_TOP_I2SO3_SEL, "i2so3_sel", + i2so1_parents, 0x520, 16, 2, 23), + MUX_GATE(CLK_TOP_TDMO0_SEL, "tdmo0_sel", + i2so1_parents, 0x520, 24, 2, 31), + /* CLK_CFG_13 */ + MUX_GATE(CLK_TOP_TDMO1_SEL, "tdmo1_sel", + i2so1_parents, 0x530, 0, 2, 7), + MUX_GATE(CLK_TOP_I2SI1_SEL, "i2si1_sel", + i2so1_parents, 0x530, 8, 2, 15), + MUX_GATE(CLK_TOP_I2SI2_SEL, "i2si2_sel", + i2so1_parents, 0x530, 16, 2, 23), + MUX_GATE(CLK_TOP_I2SI3_SEL, "i2si3_sel", + i2so1_parents, 0x530, 24, 2, 31), + /* CLK_CFG_14 */ + MUX_GATE(CLK_TOP_ETHER_125M_SEL, "ether_125m_sel", + ether_125m_parents, 0x540, 0, 2, 7), + MUX_GATE(CLK_TOP_ETHER_50M_SEL, "ether_50m_sel", + ether_50m_parents, 0x540, 8, 2, 15), + MUX_GATE(CLK_TOP_JPGDEC_SEL, "jpgdec_sel", + jpgdec_parents, 0x540, 16, 4, 23), + MUX_GATE(CLK_TOP_SPISLV_SEL, "spislv_sel", + spislv_parents, 0x540, 24, 3, 31), + /* CLK_CFG_15 */ + MUX_GATE(CLK_TOP_ETHER_50M_RMII_SEL, "ether_sel", + ether_parents, 0x550, 0, 2, 7), + MUX_GATE(CLK_TOP_CAM2TG_SEL, "cam2tg_sel", + camtg_parents, 0x550, 8, 4, 15), + MUX_GATE(CLK_TOP_DI_SEL, "di_sel", + di_parents, 0x550, 16, 3, 23), + MUX_GATE(CLK_TOP_TVD_SEL, "tvd_sel", + tvd_parents, 0x550, 24, 2, 31), + /* CLK_CFG_16 */ + MUX_GATE(CLK_TOP_I2C_SEL, "i2c_sel", + i2c_parents, 0x560, 0, 3, 7), + MUX_GATE(CLK_TOP_PWM_INFRA_SEL, "pwm_infra_sel", + pwm_parents, 0x560, 8, 2, 15), + MUX_GATE(CLK_TOP_MSDC0P_AES_SEL, "msdc0p_aes_sel", + msdc0p_aes_parents, 0x560, 16, 2, 23), + MUX_GATE(CLK_TOP_CMSYS_SEL, "cmsys_sel", + cmsys_parents, 0x560, 24, 3, 31), + /* CLK_CFG_17 */ + MUX_GATE(CLK_TOP_GCPU_SEL, "gcpu_sel", + gcpu_parents, 0x570, 0, 3, 7), + /* CLK_AUDDIV_4 */ + MUX(CLK_TOP_AUD_APLL1_SEL, "aud_apll1_sel", + aud_apll1_parents, 0x134, 0, 1), + MUX(CLK_TOP_AUD_APLL2_SEL, "aud_apll2_sel", + aud_apll2_parents, 0x134, 1, 1), + MUX(CLK_TOP_DA_AUDULL_VTX_6P5M_SEL, "audull_vtx_sel", + audull_vtx_parents, 0x134, 31, 1), +}; + +static const char * const mcu_mp0_parents[] = { + "clk26m", + "armca35pll_ck", + "f_mp0_pll1_ck", + "f_mp0_pll2_ck" +}; + +static const char * const mcu_mp2_parents[] = { + "clk26m", + "armca72pll_ck", + "f_big_pll1_ck", + "f_big_pll2_ck" +}; + +static const char * const mcu_bus_parents[] = { + "clk26m", + "cci400_sel", + "f_bus_pll1_ck", + "f_bus_pll2_ck" +}; + +static struct mtk_composite mcu_muxes[] = { + /* mp0_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_MP0_SEL, "mcu_mp0_sel", mcu_mp0_parents, 0x7A0, + 9, 2, -1, CLK_IS_CRITICAL), + /* mp2_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_MP2_SEL, "mcu_mp2_sel", mcu_mp2_parents, 0x7A8, + 9, 2, -1, CLK_IS_CRITICAL), + /* bus_pll_divider_cfg */ + MUX_GATE_FLAGS(CLK_MCU_BUS_SEL, "mcu_bus_sel", mcu_bus_parents, 0x7C0, + 9, 2, -1, CLK_IS_CRITICAL), +}; + +static const struct mtk_clk_divider top_adj_divs[] = { + DIV_ADJ(CLK_TOP_APLL_DIV0, "apll_div0", "i2so1_sel", 0x124, 0, 8), + DIV_ADJ(CLK_TOP_APLL_DIV1, "apll_div1", "i2so2_sel", 0x124, 8, 8), + DIV_ADJ(CLK_TOP_APLL_DIV2, "apll_div2", "i2so3_sel", 0x124, 16, 8), + DIV_ADJ(CLK_TOP_APLL_DIV3, "apll_div3", "tdmo0_sel", 0x124, 24, 8), + DIV_ADJ(CLK_TOP_APLL_DIV4, "apll_div4", "tdmo1_sel", 0x128, 0, 8), + DIV_ADJ(CLK_TOP_APLL_DIV5, "apll_div5", "i2si1_sel", 0x128, 8, 8), + DIV_ADJ(CLK_TOP_APLL_DIV6, "apll_div6", "i2si2_sel", 0x128, 16, 8), + DIV_ADJ(CLK_TOP_APLL_DIV7, "apll_div7", "i2si3_sel", 0x128, 24, 8), +}; + +static const struct mtk_gate_regs top_cg_regs = { + .set_ofs = 0x120, + .clr_ofs = 0x120, + .sta_ofs = 0x120, +}; + +#define GATE_TOP(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate top_clks[] = { + GATE_TOP(CLK_TOP_APLL_DIV_PDN0, "apll_div_pdn0", "i2so1_sel", 0), + GATE_TOP(CLK_TOP_APLL_DIV_PDN1, "apll_div_pdn1", "i2so2_sel", 1), + GATE_TOP(CLK_TOP_APLL_DIV_PDN2, "apll_div_pdn2", "i2so3_sel", 2), + GATE_TOP(CLK_TOP_APLL_DIV_PDN3, "apll_div_pdn3", "tdmo0_sel", 3), + GATE_TOP(CLK_TOP_APLL_DIV_PDN4, "apll_div_pdn4", "tdmo1_sel", 4), + GATE_TOP(CLK_TOP_APLL_DIV_PDN5, "apll_div_pdn5", "i2si1_sel", 5), + GATE_TOP(CLK_TOP_APLL_DIV_PDN6, "apll_div_pdn6", "i2si2_sel", 6), + GATE_TOP(CLK_TOP_APLL_DIV_PDN7, "apll_div_pdn7", "i2si3_sel", 7), +}; + +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x40, +}; + +#define GATE_INFRA(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static const struct mtk_gate infra_clks[] = { + GATE_INFRA(CLK_INFRA_DBGCLK, "infra_dbgclk", "axi_sel", 0), + GATE_INFRA(CLK_INFRA_GCE, "infra_gce", "axi_sel", 6), + GATE_INFRA(CLK_INFRA_M4U, "infra_m4u", "mem_sel", 8), + GATE_INFRA(CLK_INFRA_KP, "infra_kp", "axi_sel", 16), + GATE_INFRA(CLK_INFRA_AO_SPI0, "infra_ao_spi0", "spi_sel", 24), + GATE_INFRA(CLK_INFRA_AO_SPI1, "infra_ao_spi1", "spislv_sel", 25), + GATE_INFRA(CLK_INFRA_AO_UART5, "infra_ao_uart5", "axi_sel", 26), +}; + +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x10, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0xc, + .clr_ofs = 0x14, + .sta_ofs = 0x1c, +}; + +static const struct mtk_gate_regs peri2_cg_regs = { + .set_ofs = 0x42c, + .clr_ofs = 0x42c, + .sta_ofs = 0x42c, +}; + +#define GATE_PERI0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate peri_clks[] = { + /* PERI0 */ + GATE_PERI0(CLK_PERI_NFI, "per_nfi", + "axi_sel", 0), + GATE_PERI0(CLK_PERI_THERM, "per_therm", + "axi_sel", 1), + GATE_PERI0(CLK_PERI_PWM0, "per_pwm0", + "pwm_sel", 2), + GATE_PERI0(CLK_PERI_PWM1, "per_pwm1", + "pwm_sel", 3), + GATE_PERI0(CLK_PERI_PWM2, "per_pwm2", + "pwm_sel", 4), + GATE_PERI0(CLK_PERI_PWM3, "per_pwm3", + "pwm_sel", 5), + GATE_PERI0(CLK_PERI_PWM4, "per_pwm4", + "pwm_sel", 6), + GATE_PERI0(CLK_PERI_PWM5, "per_pwm5", + "pwm_sel", 7), + GATE_PERI0(CLK_PERI_PWM6, "per_pwm6", + "pwm_sel", 8), + GATE_PERI0(CLK_PERI_PWM7, "per_pwm7", + "pwm_sel", 9), + GATE_PERI0(CLK_PERI_PWM, "per_pwm", + "pwm_sel", 10), + GATE_PERI0(CLK_PERI_AP_DMA, "per_ap_dma", + "axi_sel", 13), + GATE_PERI0(CLK_PERI_MSDC30_0, "per_msdc30_0", + "msdc50_0_sel", 14), + GATE_PERI0(CLK_PERI_MSDC30_1, "per_msdc30_1", + "msdc30_1_sel", 15), + GATE_PERI0(CLK_PERI_MSDC30_2, "per_msdc30_2", + "msdc30_2_sel", 16), + GATE_PERI0(CLK_PERI_MSDC30_3, "per_msdc30_3", + "msdc30_3_sel", 17), + GATE_PERI0(CLK_PERI_UART0, "per_uart0", + "uart_sel", 20), + GATE_PERI0(CLK_PERI_UART1, "per_uart1", + "uart_sel", 21), + GATE_PERI0(CLK_PERI_UART2, "per_uart2", + "uart_sel", 22), + GATE_PERI0(CLK_PERI_UART3, "per_uart3", + "uart_sel", 23), + GATE_PERI0(CLK_PERI_I2C0, "per_i2c0", + "axi_sel", 24), + GATE_PERI0(CLK_PERI_I2C1, "per_i2c1", + "axi_sel", 25), + GATE_PERI0(CLK_PERI_I2C2, "per_i2c2", + "axi_sel", 26), + GATE_PERI0(CLK_PERI_I2C3, "per_i2c3", + "axi_sel", 27), + GATE_PERI0(CLK_PERI_I2C4, "per_i2c4", + "axi_sel", 28), + GATE_PERI0(CLK_PERI_AUXADC, "per_auxadc", + "ltepll_fs26m", 29), + GATE_PERI0(CLK_PERI_SPI0, "per_spi0", + "spi_sel", 30), + /* PERI1 */ + GATE_PERI1(CLK_PERI_SPI, "per_spi", + "spinor_sel", 1), + GATE_PERI1(CLK_PERI_I2C5, "per_i2c5", + "axi_sel", 3), + GATE_PERI1(CLK_PERI_SPI2, "per_spi2", + "spi_sel", 5), + GATE_PERI1(CLK_PERI_SPI3, "per_spi3", + "spi_sel", 6), + GATE_PERI1(CLK_PERI_SPI5, "per_spi5", + "spi_sel", 8), + GATE_PERI1(CLK_PERI_UART4, "per_uart4", + "uart_sel", 9), + GATE_PERI1(CLK_PERI_SFLASH, "per_sflash", + "uart_sel", 11), + GATE_PERI1(CLK_PERI_GMAC, "per_gmac", + "uart_sel", 12), + GATE_PERI1(CLK_PERI_PCIE0, "per_pcie0", + "uart_sel", 14), + GATE_PERI1(CLK_PERI_PCIE1, "per_pcie1", + "uart_sel", 15), + GATE_PERI1(CLK_PERI_GMAC_PCLK, "per_gmac_pclk", + "uart_sel", 16), + /* PERI2 */ + GATE_PERI2(CLK_PERI_MSDC50_0_EN, "per_msdc50_0_en", + "msdc50_0_sel", 0), + GATE_PERI2(CLK_PERI_MSDC30_1_EN, "per_msdc30_1_en", + "msdc30_1_sel", 1), + GATE_PERI2(CLK_PERI_MSDC30_2_EN, "per_msdc30_2_en", + "msdc30_2_sel", 2), + GATE_PERI2(CLK_PERI_MSDC30_3_EN, "per_msdc30_3_en", + "msdc30_3_sel", 3), + GATE_PERI2(CLK_PERI_MSDC50_0_HCLK_EN, "per_msdc50_0_h", + "msdc50_0_h_sel", 4), + GATE_PERI2(CLK_PERI_MSDC50_3_HCLK_EN, "per_msdc50_3_h", + "msdc50_3_h_sel", 5), +}; + +#define MT2712_PLL_FMAX (3000UL * MHZ) + +#define CON0_MT2712_RST_BAR BIT(24) + +#define PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift, \ + _div_table) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT2712_RST_BAR, \ + .fmax = MT2712_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .tuner_en_reg = _tuner_en_reg, \ + .tuner_en_bit = _tuner_en_bit, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _tuner_en_reg, \ + _tuner_en_bit, _pcw_reg, _pcw_shift) \ + PLL_B(_id, _name, _reg, _pwr_reg, _en_mask, _flags, \ + _pcwbits, _pd_reg, _pd_shift, _tuner_reg, \ + _tuner_en_reg, _tuner_en_bit, _pcw_reg, \ + _pcw_shift, NULL) + +static const struct mtk_pll_div_table armca35pll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 1202500000 }, + { .div = 2, .freq = 500500000 }, + { .div = 3, .freq = 315250000 }, + { .div = 4, .freq = 157625000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_div_table armca72pll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 994500000 }, + { .div = 2, .freq = 520000000 }, + { .div = 3, .freq = 315250000 }, + { .div = 4, .freq = 157625000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_div_table mmpll_div_table[] = { + { .div = 0, .freq = MT2712_PLL_FMAX }, + { .div = 1, .freq = 1001000000 }, + { .div = 2, .freq = 601250000 }, + { .div = 3, .freq = 250250000 }, + { .div = 4, .freq = 125125000 }, + { } /* sentinel */ +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0230, 0x023C, 0xf0000101, + HAVE_RST_BAR, 31, 0x0230, 4, 0, 0, 0, 0x0234, 0), + PLL(CLK_APMIXED_UNIVPLL, "univpll", 0x0240, 0x024C, 0xfe000101, + HAVE_RST_BAR, 31, 0x0240, 4, 0, 0, 0, 0x0244, 0), + PLL(CLK_APMIXED_VCODECPLL, "vcodecpll", 0x0320, 0x032C, 0xc0000101, + 0, 31, 0x0320, 4, 0, 0, 0, 0x0324, 0), + PLL(CLK_APMIXED_VENCPLL, "vencpll", 0x0280, 0x028C, 0x00000101, + 0, 31, 0x0280, 4, 0, 0, 0, 0x0284, 0), + PLL(CLK_APMIXED_APLL1, "apll1", 0x0330, 0x0340, 0x00000101, + 0, 31, 0x0330, 4, 0x0338, 0x0014, 0, 0x0334, 0), + PLL(CLK_APMIXED_APLL2, "apll2", 0x0350, 0x0360, 0x00000101, + 0, 31, 0x0350, 4, 0x0358, 0x0014, 1, 0x0354, 0), + PLL(CLK_APMIXED_LVDSPLL, "lvdspll", 0x0370, 0x037c, 0x00000101, + 0, 31, 0x0370, 4, 0, 0, 0, 0x0374, 0), + PLL(CLK_APMIXED_LVDSPLL2, "lvdspll2", 0x0390, 0x039C, 0x00000101, + 0, 31, 0x0390, 4, 0, 0, 0, 0x0394, 0), + PLL(CLK_APMIXED_MSDCPLL, "msdcpll", 0x0270, 0x027C, 0x00000101, + 0, 31, 0x0270, 4, 0, 0, 0, 0x0274, 0), + PLL(CLK_APMIXED_MSDCPLL2, "msdcpll2", 0x0410, 0x041C, 0x00000101, + 0, 31, 0x0410, 4, 0, 0, 0, 0x0414, 0), + PLL(CLK_APMIXED_TVDPLL, "tvdpll", 0x0290, 0x029C, 0xc0000101, + 0, 31, 0x0290, 4, 0, 0, 0, 0x0294, 0), + PLL_B(CLK_APMIXED_MMPLL, "mmpll", 0x0250, 0x0260, 0x00000101, + 0, 31, 0x0250, 4, 0, 0, 0, 0x0254, 0, + mmpll_div_table), + PLL_B(CLK_APMIXED_ARMCA35PLL, "armca35pll", 0x0100, 0x0110, 0xf0000101, + HAVE_RST_BAR, 31, 0x0100, 4, 0, 0, 0, 0x0104, 0, + armca35pll_div_table), + PLL_B(CLK_APMIXED_ARMCA72PLL, "armca72pll", 0x0210, 0x0220, 0x00000101, + 0, 31, 0x0210, 4, 0, 0, 0, 0x0214, 0, + armca72pll_div_table), + PLL(CLK_APMIXED_ETHERPLL, "etherpll", 0x0300, 0x030C, 0xc0000101, + 0, 31, 0x0300, 4, 0, 0, 0, 0x0304, 0), +}; + +static int clk_mt2712_apmixed_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static struct clk_onecell_data *top_clk_data; + +static void clk_mt2712_top_init_early(struct device_node *node) +{ + int r, i; + + if (!top_clk_data) { + top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + + for (i = 0; i < CLK_TOP_NR_CLK; i++) + top_clk_data->clks[i] = ERR_PTR(-EPROBE_DEFER); + } + + mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), + top_clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); + if (r) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); +} + +CLK_OF_DECLARE_DRIVER(mt2712_topckgen, "mediatek,mt2712-topckgen", + clk_mt2712_top_init_early); + +static int clk_mt2712_top_probe(struct platform_device *pdev) +{ + int r, i; + struct device_node *node = pdev->dev.of_node; + void __iomem *base; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + pr_err("%s(): ioremap failed\n", __func__); + return PTR_ERR(base); + } + + if (!top_clk_data) { + top_clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + } else { + for (i = 0; i < CLK_TOP_NR_CLK; i++) { + if (top_clk_data->clks[i] == ERR_PTR(-EPROBE_DEFER)) + top_clk_data->clks[i] = ERR_PTR(-ENOENT); + } + } + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + top_clk_data); + mtk_clk_register_factors(top_early_divs, ARRAY_SIZE(top_early_divs), + top_clk_data); + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), top_clk_data); + mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), base, + &mt2712_clk_lock, top_clk_data); + mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), base, + &mt2712_clk_lock, top_clk_data); + mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), + top_clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, top_clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static int clk_mt2712_infra_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + mtk_register_reset_controller(node, 2, 0x30); + + return r; +} + +static int clk_mt2712_peri_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); + + mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + mtk_register_reset_controller(node, 2, 0); + + return r; +} + +static int clk_mt2712_mcu_probe(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + int r; + struct device_node *node = pdev->dev.of_node; + void __iomem *base; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) { + pr_err("%s(): ioremap failed\n", __func__); + return PTR_ERR(base); + } + + clk_data = mtk_alloc_clk_data(CLK_MCU_NR_CLK); + + mtk_clk_register_composites(mcu_muxes, ARRAY_SIZE(mcu_muxes), base, + &mt2712_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + + if (r != 0) + pr_err("%s(): could not register clock provider: %d\n", + __func__, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt2712[] = { + { + .compatible = "mediatek,mt2712-apmixedsys", + .data = clk_mt2712_apmixed_probe, + }, { + .compatible = "mediatek,mt2712-topckgen", + .data = clk_mt2712_top_probe, + }, { + .compatible = "mediatek,mt2712-infracfg", + .data = clk_mt2712_infra_probe, + }, { + .compatible = "mediatek,mt2712-pericfg", + .data = clk_mt2712_peri_probe, + }, { + .compatible = "mediatek,mt2712-mcucfg", + .data = clk_mt2712_mcu_probe, + }, { + /* sentinel */ + } +}; + +static int clk_mt2712_probe(struct platform_device *pdev) +{ + int (*clk_probe)(struct platform_device *); + int r; + + clk_probe = of_device_get_match_data(&pdev->dev); + if (!clk_probe) + return -EINVAL; + + r = clk_probe(pdev); + if (r != 0) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt2712_drv = { + .probe = clk_mt2712_probe, + .driver = { + .name = "clk-mt2712", + .owner = THIS_MODULE, + .of_match_table = of_match_clk_mt2712, + }, +}; + +static int __init clk_mt2712_init(void) +{ + return platform_driver_register(&clk_mt2712_drv); +} + +arch_initcall(clk_mt2712_init); diff --git a/drivers/clk/mediatek/clk-mt7622-aud.c b/drivers/clk/mediatek/clk-mt7622-aud.c new file mode 100644 index 000000000000..fad7d9fc53ba --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622-aud.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Chen Zhong <chen.zhong@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt7622-clk.h> + +#define GATE_AUDIO0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO2(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio2_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_AUDIO3(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &audio3_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +static const struct mtk_gate_regs audio0_cg_regs = { + .set_ofs = 0x0, + .clr_ofs = 0x0, + .sta_ofs = 0x0, +}; + +static const struct mtk_gate_regs audio1_cg_regs = { + .set_ofs = 0x10, + .clr_ofs = 0x10, + .sta_ofs = 0x10, +}; + +static const struct mtk_gate_regs audio2_cg_regs = { + .set_ofs = 0x14, + .clr_ofs = 0x14, + .sta_ofs = 0x14, +}; + +static const struct mtk_gate_regs audio3_cg_regs = { + .set_ofs = 0x634, + .clr_ofs = 0x634, + .sta_ofs = 0x634, +}; + +static const struct mtk_gate audio_clks[] = { + /* AUDIO0 */ + GATE_AUDIO0(CLK_AUDIO_AFE, "audio_afe", "rtc", 2), + GATE_AUDIO0(CLK_AUDIO_HDMI, "audio_hdmi", "apll1_ck_sel", 20), + GATE_AUDIO0(CLK_AUDIO_SPDF, "audio_spdf", "apll1_ck_sel", 21), + GATE_AUDIO0(CLK_AUDIO_APLL, "audio_apll", "apll1_ck_sel", 23), + /* AUDIO1 */ + GATE_AUDIO1(CLK_AUDIO_I2SIN1, "audio_i2sin1", "a1sys_hp_sel", 0), + GATE_AUDIO1(CLK_AUDIO_I2SIN2, "audio_i2sin2", "a1sys_hp_sel", 1), + GATE_AUDIO1(CLK_AUDIO_I2SIN3, "audio_i2sin3", "a1sys_hp_sel", 2), + GATE_AUDIO1(CLK_AUDIO_I2SIN4, "audio_i2sin4", "a1sys_hp_sel", 3), + GATE_AUDIO1(CLK_AUDIO_I2SO1, "audio_i2so1", "a1sys_hp_sel", 6), + GATE_AUDIO1(CLK_AUDIO_I2SO2, "audio_i2so2", "a1sys_hp_sel", 7), + GATE_AUDIO1(CLK_AUDIO_I2SO3, "audio_i2so3", "a1sys_hp_sel", 8), + GATE_AUDIO1(CLK_AUDIO_I2SO4, "audio_i2so4", "a1sys_hp_sel", 9), + GATE_AUDIO1(CLK_AUDIO_ASRCI1, "audio_asrci1", "asm_h_sel", 12), + GATE_AUDIO1(CLK_AUDIO_ASRCI2, "audio_asrci2", "asm_h_sel", 13), + GATE_AUDIO1(CLK_AUDIO_ASRCO1, "audio_asrco1", "asm_h_sel", 14), + GATE_AUDIO1(CLK_AUDIO_ASRCO2, "audio_asrco2", "asm_h_sel", 15), + GATE_AUDIO1(CLK_AUDIO_INTDIR, "audio_intdir", "intdir_sel", 20), + GATE_AUDIO1(CLK_AUDIO_A1SYS, "audio_a1sys", "a1sys_hp_sel", 21), + GATE_AUDIO1(CLK_AUDIO_A2SYS, "audio_a2sys", "a2sys_hp_sel", 22), + /* AUDIO2 */ + GATE_AUDIO2(CLK_AUDIO_UL1, "audio_ul1", "a1sys_hp_sel", 0), + GATE_AUDIO2(CLK_AUDIO_UL2, "audio_ul2", "a1sys_hp_sel", 1), + GATE_AUDIO2(CLK_AUDIO_UL3, "audio_ul3", "a1sys_hp_sel", 2), + GATE_AUDIO2(CLK_AUDIO_UL4, "audio_ul4", "a1sys_hp_sel", 3), + GATE_AUDIO2(CLK_AUDIO_UL5, "audio_ul5", "a1sys_hp_sel", 4), + GATE_AUDIO2(CLK_AUDIO_UL6, "audio_ul6", "a1sys_hp_sel", 5), + GATE_AUDIO2(CLK_AUDIO_DL1, "audio_dl1", "a1sys_hp_sel", 6), + GATE_AUDIO2(CLK_AUDIO_DL2, "audio_dl2", "a1sys_hp_sel", 7), + GATE_AUDIO2(CLK_AUDIO_DL3, "audio_dl3", "a1sys_hp_sel", 8), + GATE_AUDIO2(CLK_AUDIO_DL4, "audio_dl4", "a1sys_hp_sel", 9), + GATE_AUDIO2(CLK_AUDIO_DL5, "audio_dl5", "a1sys_hp_sel", 10), + GATE_AUDIO2(CLK_AUDIO_DL6, "audio_dl6", "a1sys_hp_sel", 11), + GATE_AUDIO2(CLK_AUDIO_DLMCH, "audio_dlmch", "a1sys_hp_sel", 12), + GATE_AUDIO2(CLK_AUDIO_ARB1, "audio_arb1", "a1sys_hp_sel", 13), + GATE_AUDIO2(CLK_AUDIO_AWB, "audio_awb", "a1sys_hp_sel", 14), + GATE_AUDIO2(CLK_AUDIO_AWB2, "audio_awb2", "a1sys_hp_sel", 15), + GATE_AUDIO2(CLK_AUDIO_DAI, "audio_dai", "a1sys_hp_sel", 16), + GATE_AUDIO2(CLK_AUDIO_MOD, "audio_mod", "a1sys_hp_sel", 17), + /* AUDIO3 */ + GATE_AUDIO3(CLK_AUDIO_ASRCI3, "audio_asrci3", "asm_h_sel", 2), + GATE_AUDIO3(CLK_AUDIO_ASRCI4, "audio_asrci4", "asm_h_sel", 3), + GATE_AUDIO3(CLK_AUDIO_ASRCO3, "audio_asrco3", "asm_h_sel", 6), + GATE_AUDIO3(CLK_AUDIO_ASRCO4, "audio_asrco4", "asm_h_sel", 7), + GATE_AUDIO3(CLK_AUDIO_MEM_ASRC1, "audio_mem_asrc1", "asm_h_sel", 10), + GATE_AUDIO3(CLK_AUDIO_MEM_ASRC2, "audio_mem_asrc2", "asm_h_sel", 11), + GATE_AUDIO3(CLK_AUDIO_MEM_ASRC3, "audio_mem_asrc3", "asm_h_sel", 12), + GATE_AUDIO3(CLK_AUDIO_MEM_ASRC4, "audio_mem_asrc4", "asm_h_sel", 13), + GATE_AUDIO3(CLK_AUDIO_MEM_ASRC5, "audio_mem_asrc5", "asm_h_sel", 14), +}; + +static int clk_mt7622_audiosys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_AUDIO_NR_CLK); + + mtk_clk_register_gates(node, audio_clks, ARRAY_SIZE(audio_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt7622_aud[] = { + { + .compatible = "mediatek,mt7622-audsys", + .data = clk_mt7622_audiosys_init, + }, { + /* sentinel */ + } +}; + +static int clk_mt7622_aud_probe(struct platform_device *pdev) +{ + int (*clk_init)(struct platform_device *); + int r; + + clk_init = of_device_get_match_data(&pdev->dev); + if (!clk_init) + return -EINVAL; + + r = clk_init(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt7622_aud_drv = { + .probe = clk_mt7622_aud_probe, + .driver = { + .name = "clk-mt7622-aud", + .of_match_table = of_match_clk_mt7622_aud, + }, +}; + +builtin_platform_driver(clk_mt7622_aud_drv); diff --git a/drivers/clk/mediatek/clk-mt7622-eth.c b/drivers/clk/mediatek/clk-mt7622-eth.c new file mode 100644 index 000000000000..6328127bbb3c --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622-eth.c @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Chen Zhong <chen.zhong@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt7622-clk.h> + +#define GATE_ETH(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = ð_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate_regs eth_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +static const struct mtk_gate eth_clks[] = { + GATE_ETH(CLK_ETH_HSDMA_EN, "eth_hsdma_en", "eth_sel", 5), + GATE_ETH(CLK_ETH_ESW_EN, "eth_esw_en", "eth_500m", 6), + GATE_ETH(CLK_ETH_GP2_EN, "eth_gp2_en", "txclk_src_pre", 7), + GATE_ETH(CLK_ETH_GP1_EN, "eth_gp1_en", "txclk_src_pre", 8), + GATE_ETH(CLK_ETH_GP0_EN, "eth_gp0_en", "txclk_src_pre", 9), +}; + +static const struct mtk_gate_regs sgmii_cg_regs = { + .set_ofs = 0xE4, + .clr_ofs = 0xE4, + .sta_ofs = 0xE4, +}; + +#define GATE_SGMII(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &sgmii_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate sgmii_clks[] = { + GATE_SGMII(CLK_SGMII_TX250M_EN, "sgmii_tx250m_en", + "ssusb_tx250m", 2), + GATE_SGMII(CLK_SGMII_RX250M_EN, "sgmii_rx250m_en", + "ssusb_eq_rx250m", 3), + GATE_SGMII(CLK_SGMII_CDR_REF, "sgmii_cdr_ref", + "ssusb_cdr_ref", 4), + GATE_SGMII(CLK_SGMII_CDR_FB, "sgmii_cdr_fb", + "ssusb_cdr_fb", 5), +}; + +static int clk_mt7622_ethsys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_ETH_NR_CLK); + + mtk_clk_register_gates(node, eth_clks, ARRAY_SIZE(eth_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + mtk_register_reset_controller(node, 1, 0x34); + + return r; +} + +static int clk_mt7622_sgmiisys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_SGMII_NR_CLK); + + mtk_clk_register_gates(node, sgmii_clks, ARRAY_SIZE(sgmii_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static const struct of_device_id of_match_clk_mt7622_eth[] = { + { + .compatible = "mediatek,mt7622-ethsys", + .data = clk_mt7622_ethsys_init, + }, { + .compatible = "mediatek,mt7622-sgmiisys", + .data = clk_mt7622_sgmiisys_init, + }, { + /* sentinel */ + } +}; + +static int clk_mt7622_eth_probe(struct platform_device *pdev) +{ + int (*clk_init)(struct platform_device *); + int r; + + clk_init = of_device_get_match_data(&pdev->dev); + if (!clk_init) + return -EINVAL; + + r = clk_init(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt7622_eth_drv = { + .probe = clk_mt7622_eth_probe, + .driver = { + .name = "clk-mt7622-eth", + .of_match_table = of_match_clk_mt7622_eth, + }, +}; + +builtin_platform_driver(clk_mt7622_eth_drv); diff --git a/drivers/clk/mediatek/clk-mt7622-hif.c b/drivers/clk/mediatek/clk-mt7622-hif.c new file mode 100644 index 000000000000..a6e8534276c6 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622-hif.c @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Chen Zhong <chen.zhong@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" + +#include <dt-bindings/clock/mt7622-clk.h> + +#define GATE_PCIE(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &pcie_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +#define GATE_SSUSB(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &ssusb_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +static const struct mtk_gate_regs pcie_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +static const struct mtk_gate_regs ssusb_cg_regs = { + .set_ofs = 0x30, + .clr_ofs = 0x30, + .sta_ofs = 0x30, +}; + +static const struct mtk_gate ssusb_clks[] = { + GATE_SSUSB(CLK_SSUSB_U2_PHY_1P_EN, "ssusb_u2_phy_1p", + "to_u2_phy_1p", 0), + GATE_SSUSB(CLK_SSUSB_U2_PHY_EN, "ssusb_u2_phy_en", "to_u2_phy", 1), + GATE_SSUSB(CLK_SSUSB_REF_EN, "ssusb_ref_en", "to_usb3_ref", 5), + GATE_SSUSB(CLK_SSUSB_SYS_EN, "ssusb_sys_en", "to_usb3_sys", 6), + GATE_SSUSB(CLK_SSUSB_MCU_EN, "ssusb_mcu_en", "axi_sel", 7), + GATE_SSUSB(CLK_SSUSB_DMA_EN, "ssusb_dma_en", "hif_sel", 8), +}; + +static const struct mtk_gate pcie_clks[] = { + GATE_PCIE(CLK_PCIE_P1_AUX_EN, "pcie_p1_aux_en", "p1_1mhz", 12), + GATE_PCIE(CLK_PCIE_P1_OBFF_EN, "pcie_p1_obff_en", "free_run_4mhz", 13), + GATE_PCIE(CLK_PCIE_P1_AHB_EN, "pcie_p1_ahb_en", "axi_sel", 14), + GATE_PCIE(CLK_PCIE_P1_AXI_EN, "pcie_p1_axi_en", "hif_sel", 15), + GATE_PCIE(CLK_PCIE_P1_MAC_EN, "pcie_p1_mac_en", "pcie1_mac_en", 16), + GATE_PCIE(CLK_PCIE_P1_PIPE_EN, "pcie_p1_pipe_en", "pcie1_pipe_en", 17), + GATE_PCIE(CLK_PCIE_P0_AUX_EN, "pcie_p0_aux_en", "p0_1mhz", 18), + GATE_PCIE(CLK_PCIE_P0_OBFF_EN, "pcie_p0_obff_en", "free_run_4mhz", 19), + GATE_PCIE(CLK_PCIE_P0_AHB_EN, "pcie_p0_ahb_en", "axi_sel", 20), + GATE_PCIE(CLK_PCIE_P0_AXI_EN, "pcie_p0_axi_en", "hif_sel", 21), + GATE_PCIE(CLK_PCIE_P0_MAC_EN, "pcie_p0_mac_en", "pcie0_mac_en", 22), + GATE_PCIE(CLK_PCIE_P0_PIPE_EN, "pcie_p0_pipe_en", "pcie0_pipe_en", 23), + GATE_PCIE(CLK_SATA_AHB_EN, "sata_ahb_en", "axi_sel", 26), + GATE_PCIE(CLK_SATA_AXI_EN, "sata_axi_en", "hif_sel", 27), + GATE_PCIE(CLK_SATA_ASIC_EN, "sata_asic_en", "sata_asic", 28), + GATE_PCIE(CLK_SATA_RBC_EN, "sata_rbc_en", "sata_rbc", 29), + GATE_PCIE(CLK_SATA_PM_EN, "sata_pm_en", "univpll2_d4", 30), +}; + +static int clk_mt7622_ssusbsys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_SSUSB_NR_CLK); + + mtk_clk_register_gates(node, ssusb_clks, ARRAY_SIZE(ssusb_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + mtk_register_reset_controller(node, 1, 0x34); + + return r; +} + +static int clk_mt7622_pciesys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + int r; + + clk_data = mtk_alloc_clk_data(CLK_PCIE_NR_CLK); + + mtk_clk_register_gates(node, pcie_clks, ARRAY_SIZE(pcie_clks), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + mtk_register_reset_controller(node, 1, 0x34); + + return r; +} + +static const struct of_device_id of_match_clk_mt7622_hif[] = { + { + .compatible = "mediatek,mt7622-pciesys", + .data = clk_mt7622_pciesys_init, + }, { + .compatible = "mediatek,mt7622-ssusbsys", + .data = clk_mt7622_ssusbsys_init, + }, { + /* sentinel */ + } +}; + +static int clk_mt7622_hif_probe(struct platform_device *pdev) +{ + int (*clk_init)(struct platform_device *); + int r; + + clk_init = of_device_get_match_data(&pdev->dev); + if (!clk_init) + return -EINVAL; + + r = clk_init(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt7622_hif_drv = { + .probe = clk_mt7622_hif_probe, + .driver = { + .name = "clk-mt7622-hif", + .of_match_table = of_match_clk_mt7622_hif, + }, +}; + +builtin_platform_driver(clk_mt7622_hif_drv); diff --git a/drivers/clk/mediatek/clk-mt7622.c b/drivers/clk/mediatek/clk-mt7622.c new file mode 100644 index 000000000000..92f7e32770c6 --- /dev/null +++ b/drivers/clk/mediatek/clk-mt7622.c @@ -0,0 +1,780 @@ +/* + * Copyright (c) 2017 MediaTek Inc. + * Author: Chen Zhong <chen.zhong@mediatek.com> + * Sean Wang <sean.wang@mediatek.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> + +#include "clk-mtk.h" +#include "clk-gate.h" +#include "clk-cpumux.h" + +#include <dt-bindings/clock/mt7622-clk.h> +#include <linux/clk.h> /* for consumer */ + +#define MT7622_PLL_FMAX (2500UL * MHZ) +#define CON0_MT7622_RST_BAR BIT(27) + +#define PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift, _div_table, _parent_name) { \ + .id = _id, \ + .name = _name, \ + .reg = _reg, \ + .pwr_reg = _pwr_reg, \ + .en_mask = _en_mask, \ + .flags = _flags, \ + .rst_bar_mask = CON0_MT7622_RST_BAR, \ + .fmax = MT7622_PLL_FMAX, \ + .pcwbits = _pcwbits, \ + .pd_reg = _pd_reg, \ + .pd_shift = _pd_shift, \ + .tuner_reg = _tuner_reg, \ + .pcw_reg = _pcw_reg, \ + .pcw_shift = _pcw_shift, \ + .div_table = _div_table, \ + .parent_name = _parent_name, \ + } + +#define PLL(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits, \ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, \ + _pcw_shift) \ + PLL_xtal(_id, _name, _reg, _pwr_reg, _en_mask, _flags, _pcwbits,\ + _pd_reg, _pd_shift, _tuner_reg, _pcw_reg, _pcw_shift, \ + NULL, "clkxtal") + +#define GATE_APMIXED(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &apmixed_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr_inv, \ + } + +#define GATE_INFRA(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &infra_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_TOP0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_TOP1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &top1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_no_setclr, \ + } + +#define GATE_PERI0(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri0_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +#define GATE_PERI1(_id, _name, _parent, _shift) { \ + .id = _id, \ + .name = _name, \ + .parent_name = _parent, \ + .regs = &peri1_cg_regs, \ + .shift = _shift, \ + .ops = &mtk_clk_gate_ops_setclr, \ + } + +static DEFINE_SPINLOCK(mt7622_clk_lock); + +static const char * const infra_mux1_parents[] = { + "clkxtal", + "armpll", + "main_core_en", + "armpll" +}; + +static const char * const axi_parents[] = { + "clkxtal", + "syspll1_d2", + "syspll_d5", + "syspll1_d4", + "univpll_d5", + "univpll2_d2", + "univpll_d7" +}; + +static const char * const mem_parents[] = { + "clkxtal", + "dmpll_ck" +}; + +static const char * const ddrphycfg_parents[] = { + "clkxtal", + "syspll1_d8" +}; + +static const char * const eth_parents[] = { + "clkxtal", + "syspll1_d2", + "univpll1_d2", + "syspll1_d4", + "univpll_d5", + "clk_null", + "univpll_d7" +}; + +static const char * const pwm_parents[] = { + "clkxtal", + "univpll2_d4" +}; + +static const char * const f10m_ref_parents[] = { + "clkxtal", + "syspll4_d16" +}; + +static const char * const nfi_infra_parents[] = { + "clkxtal", + "clkxtal", + "clkxtal", + "clkxtal", + "clkxtal", + "clkxtal", + "clkxtal", + "clkxtal", + "univpll2_d8", + "syspll1_d8", + "univpll1_d8", + "syspll4_d2", + "univpll2_d4", + "univpll3_d2", + "syspll1_d4" +}; + +static const char * const flash_parents[] = { + "clkxtal", + "univpll_d80_d4", + "syspll2_d8", + "syspll3_d4", + "univpll3_d4", + "univpll1_d8", + "syspll2_d4", + "univpll2_d4" +}; + +static const char * const uart_parents[] = { + "clkxtal", + "univpll2_d8" +}; + +static const char * const spi0_parents[] = { + "clkxtal", + "syspll3_d2", + "clkxtal", + "syspll2_d4", + "syspll4_d2", + "univpll2_d4", + "univpll1_d8", + "clkxtal" +}; + +static const char * const spi1_parents[] = { + "clkxtal", + "syspll3_d2", + "clkxtal", + "syspll4_d4", + "syspll4_d2", + "univpll2_d4", + "univpll1_d8", + "clkxtal" +}; + +static const char * const msdc30_0_parents[] = { + "clkxtal", + "univpll2_d16", + "univ48m" +}; + +static const char * const a1sys_hp_parents[] = { + "clkxtal", + "aud1pll_ck", + "aud2pll_ck", + "clkxtal" +}; + +static const char * const intdir_parents[] = { + "clkxtal", + "syspll_d2", + "univpll_d2", + "sgmiipll_ck" +}; + +static const char * const aud_intbus_parents[] = { + "clkxtal", + "syspll1_d4", + "syspll4_d2", + "syspll3_d2" +}; + +static const char * const pmicspi_parents[] = { + "clkxtal", + "clk_null", + "clk_null", + "clk_null", + "clk_null", + "univpll2_d16" +}; + +static const char * const atb_parents[] = { + "clkxtal", + "syspll1_d2", + "syspll_d5" +}; + +static const char * const audio_parents[] = { + "clkxtal", + "syspll3_d4", + "syspll4_d4", + "univpll1_d16" +}; + +static const char * const usb20_parents[] = { + "clkxtal", + "univpll3_d4", + "syspll1_d8", + "clkxtal" +}; + +static const char * const aud1_parents[] = { + "clkxtal", + "aud1pll_ck" +}; + +static const char * const aud2_parents[] = { + "clkxtal", + "aud2pll_ck" +}; + +static const char * const asm_l_parents[] = { + "clkxtal", + "syspll_d5", + "univpll2_d2", + "univpll2_d4" +}; + +static const char * const apll1_ck_parents[] = { + "aud1_sel", + "aud2_sel" +}; + +static const char * const peribus_ck_parents[] = { + "syspll1_d8", + "syspll1_d4" +}; + +static const struct mtk_gate_regs apmixed_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x8, + .sta_ofs = 0x8, +}; + +static const struct mtk_gate_regs infra_cg_regs = { + .set_ofs = 0x40, + .clr_ofs = 0x44, + .sta_ofs = 0x48, +}; + +static const struct mtk_gate_regs top0_cg_regs = { + .set_ofs = 0x120, + .clr_ofs = 0x120, + .sta_ofs = 0x120, +}; + +static const struct mtk_gate_regs top1_cg_regs = { + .set_ofs = 0x128, + .clr_ofs = 0x128, + .sta_ofs = 0x128, +}; + +static const struct mtk_gate_regs peri0_cg_regs = { + .set_ofs = 0x8, + .clr_ofs = 0x10, + .sta_ofs = 0x18, +}; + +static const struct mtk_gate_regs peri1_cg_regs = { + .set_ofs = 0xC, + .clr_ofs = 0x14, + .sta_ofs = 0x1C, +}; + +static const struct mtk_pll_data plls[] = { + PLL(CLK_APMIXED_ARMPLL, "armpll", 0x0200, 0x020C, 0x00000001, + PLL_AO, 21, 0x0204, 24, 0, 0x0204, 0), + PLL(CLK_APMIXED_MAINPLL, "mainpll", 0x0210, 0x021C, 0x00000001, + HAVE_RST_BAR, 21, 0x0214, 24, 0, 0x0214, 0), + PLL(CLK_APMIXED_UNIV2PLL, "univ2pll", 0x0220, 0x022C, 0x00000001, + HAVE_RST_BAR, 7, 0x0224, 24, 0, 0x0224, 14), + PLL(CLK_APMIXED_ETH1PLL, "eth1pll", 0x0300, 0x0310, 0x00000001, + 0, 21, 0x0300, 1, 0, 0x0304, 0), + PLL(CLK_APMIXED_ETH2PLL, "eth2pll", 0x0314, 0x0320, 0x00000001, + 0, 21, 0x0314, 1, 0, 0x0318, 0), + PLL(CLK_APMIXED_AUD1PLL, "aud1pll", 0x0324, 0x0330, 0x00000001, + 0, 31, 0x0324, 1, 0, 0x0328, 0), + PLL(CLK_APMIXED_AUD2PLL, "aud2pll", 0x0334, 0x0340, 0x00000001, + 0, 31, 0x0334, 1, 0, 0x0338, 0), + PLL(CLK_APMIXED_TRGPLL, "trgpll", 0x0344, 0x0354, 0x00000001, + 0, 21, 0x0344, 1, 0, 0x0348, 0), + PLL(CLK_APMIXED_SGMIPLL, "sgmipll", 0x0358, 0x0368, 0x00000001, + 0, 21, 0x0358, 1, 0, 0x035C, 0), +}; + +static const struct mtk_gate apmixed_clks[] = { + GATE_APMIXED(CLK_APMIXED_MAIN_CORE_EN, "main_core_en", "mainpll", 5), +}; + +static const struct mtk_gate infra_clks[] = { + GATE_INFRA(CLK_INFRA_DBGCLK_PD, "infra_dbgclk_pd", "axi_sel", 0), + GATE_INFRA(CLK_INFRA_TRNG, "trng_ck", "axi_sel", 2), + GATE_INFRA(CLK_INFRA_AUDIO_PD, "infra_audio_pd", "aud_intbus_sel", 5), + GATE_INFRA(CLK_INFRA_IRRX_PD, "infra_irrx_pd", "irrx_sel", 16), + GATE_INFRA(CLK_INFRA_APXGPT_PD, "infra_apxgpt_pd", "f10m_ref_sel", 18), + GATE_INFRA(CLK_INFRA_PMIC_PD, "infra_pmic_pd", "pmicspi_sel", 22), +}; + +static const struct mtk_fixed_clk top_fixed_clks[] = { + FIXED_CLK(CLK_TOP_TO_U2_PHY, "to_u2_phy", "clkxtal", + 31250000), + FIXED_CLK(CLK_TOP_TO_U2_PHY_1P, "to_u2_phy_1p", "clkxtal", + 31250000), + FIXED_CLK(CLK_TOP_PCIE0_PIPE_EN, "pcie0_pipe_en", "clkxtal", + 125000000), + FIXED_CLK(CLK_TOP_PCIE1_PIPE_EN, "pcie1_pipe_en", "clkxtal", + 125000000), + FIXED_CLK(CLK_TOP_SSUSB_TX250M, "ssusb_tx250m", "clkxtal", + 250000000), + FIXED_CLK(CLK_TOP_SSUSB_EQ_RX250M, "ssusb_eq_rx250m", "clkxtal", + 250000000), + FIXED_CLK(CLK_TOP_SSUSB_CDR_REF, "ssusb_cdr_ref", "clkxtal", + 33333333), + FIXED_CLK(CLK_TOP_SSUSB_CDR_FB, "ssusb_cdr_fb", "clkxtal", + 50000000), + FIXED_CLK(CLK_TOP_SATA_ASIC, "sata_asic", "clkxtal", + 50000000), + FIXED_CLK(CLK_TOP_SATA_RBC, "sata_rbc", "clkxtal", + 50000000), +}; + +static const struct mtk_fixed_factor top_divs[] = { + FACTOR(CLK_TOP_TO_USB3_SYS, "to_usb3_sys", "eth1pll", 1, 4), + FACTOR(CLK_TOP_P1_1MHZ, "p1_1mhz", "eth1pll", 1, 500), + FACTOR(CLK_TOP_4MHZ, "free_run_4mhz", "eth1pll", 1, 125), + FACTOR(CLK_TOP_P0_1MHZ, "p0_1mhz", "eth1pll", 1, 500), + FACTOR(CLK_TOP_TXCLK_SRC_PRE, "txclk_src_pre", "sgmiipll_d2", 1, 1), + FACTOR(CLK_TOP_RTC, "rtc", "clkxtal", 1, 1024), + FACTOR(CLK_TOP_MEMPLL, "mempll", "clkxtal", 32, 1), + FACTOR(CLK_TOP_DMPLL, "dmpll_ck", "mempll", 1, 1), + FACTOR(CLK_TOP_SYSPLL_D2, "syspll_d2", "mainpll", 1, 2), + FACTOR(CLK_TOP_SYSPLL1_D2, "syspll1_d2", "mainpll", 1, 4), + FACTOR(CLK_TOP_SYSPLL1_D4, "syspll1_d4", "mainpll", 1, 8), + FACTOR(CLK_TOP_SYSPLL1_D8, "syspll1_d8", "mainpll", 1, 16), + FACTOR(CLK_TOP_SYSPLL2_D4, "syspll2_d4", "mainpll", 1, 12), + FACTOR(CLK_TOP_SYSPLL2_D8, "syspll2_d8", "mainpll", 1, 24), + FACTOR(CLK_TOP_SYSPLL_D5, "syspll_d5", "mainpll", 1, 5), + FACTOR(CLK_TOP_SYSPLL3_D2, "syspll3_d2", "mainpll", 1, 10), + FACTOR(CLK_TOP_SYSPLL3_D4, "syspll3_d4", "mainpll", 1, 20), + FACTOR(CLK_TOP_SYSPLL4_D2, "syspll4_d2", "mainpll", 1, 14), + FACTOR(CLK_TOP_SYSPLL4_D4, "syspll4_d4", "mainpll", 1, 28), + FACTOR(CLK_TOP_SYSPLL4_D16, "syspll4_d16", "mainpll", 1, 112), + FACTOR(CLK_TOP_UNIVPLL, "univpll", "univ2pll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL_D2, "univpll_d2", "univpll", 1, 2), + FACTOR(CLK_TOP_UNIVPLL1_D2, "univpll1_d2", "univpll", 1, 4), + FACTOR(CLK_TOP_UNIVPLL1_D4, "univpll1_d4", "univpll", 1, 8), + FACTOR(CLK_TOP_UNIVPLL1_D8, "univpll1_d8", "univpll", 1, 16), + FACTOR(CLK_TOP_UNIVPLL1_D16, "univpll1_d16", "univpll", 1, 32), + FACTOR(CLK_TOP_UNIVPLL2_D2, "univpll2_d2", "univpll", 1, 6), + FACTOR(CLK_TOP_UNIVPLL2_D4, "univpll2_d4", "univpll", 1, 12), + FACTOR(CLK_TOP_UNIVPLL2_D8, "univpll2_d8", "univpll", 1, 24), + FACTOR(CLK_TOP_UNIVPLL2_D16, "univpll2_d16", "univpll", 1, 48), + FACTOR(CLK_TOP_UNIVPLL_D5, "univpll_d5", "univpll", 1, 5), + FACTOR(CLK_TOP_UNIVPLL3_D2, "univpll3_d2", "univpll", 1, 10), + FACTOR(CLK_TOP_UNIVPLL3_D4, "univpll3_d4", "univpll", 1, 20), + FACTOR(CLK_TOP_UNIVPLL3_D16, "univpll3_d16", "univpll", 1, 80), + FACTOR(CLK_TOP_UNIVPLL_D7, "univpll_d7", "univpll", 1, 7), + FACTOR(CLK_TOP_UNIVPLL_D80_D4, "univpll_d80_d4", "univpll", 1, 320), + FACTOR(CLK_TOP_UNIV48M, "univ48m", "univpll", 1, 25), + FACTOR(CLK_TOP_SGMIIPLL, "sgmiipll_ck", "sgmipll", 1, 1), + FACTOR(CLK_TOP_SGMIIPLL_D2, "sgmiipll_d2", "sgmipll", 1, 2), + FACTOR(CLK_TOP_AUD1PLL, "aud1pll_ck", "aud1pll", 1, 1), + FACTOR(CLK_TOP_AUD2PLL, "aud2pll_ck", "aud2pll", 1, 1), + FACTOR(CLK_TOP_AUD_I2S2_MCK, "aud_i2s2_mck", "i2s2_mck_sel", 1, 2), + FACTOR(CLK_TOP_TO_USB3_REF, "to_usb3_ref", "univpll2_d4", 1, 4), + FACTOR(CLK_TOP_PCIE1_MAC_EN, "pcie1_mac_en", "univpll1_d4", 1, 1), + FACTOR(CLK_TOP_PCIE0_MAC_EN, "pcie0_mac_en", "univpll1_d4", 1, 1), + FACTOR(CLK_TOP_ETH_500M, "eth_500m", "eth1pll", 1, 1), +}; + +static const struct mtk_gate top_clks[] = { + /* TOP0 */ + GATE_TOP0(CLK_TOP_APLL1_DIV_PD, "apll1_ck_div_pd", "apll1_ck_div", 0), + GATE_TOP0(CLK_TOP_APLL2_DIV_PD, "apll2_ck_div_pd", "apll2_ck_div", 1), + GATE_TOP0(CLK_TOP_I2S0_MCK_DIV_PD, "i2s0_mck_div_pd", "i2s0_mck_div", + 2), + GATE_TOP0(CLK_TOP_I2S1_MCK_DIV_PD, "i2s1_mck_div_pd", "i2s1_mck_div", + 3), + GATE_TOP0(CLK_TOP_I2S2_MCK_DIV_PD, "i2s2_mck_div_pd", "i2s2_mck_div", + 4), + GATE_TOP0(CLK_TOP_I2S3_MCK_DIV_PD, "i2s3_mck_div_pd", "i2s3_mck_div", + 5), + + /* TOP1 */ + GATE_TOP1(CLK_TOP_A1SYS_HP_DIV_PD, "a1sys_div_pd", "a1sys_div", 0), + GATE_TOP1(CLK_TOP_A2SYS_HP_DIV_PD, "a2sys_div_pd", "a2sys_div", 16), +}; + +static const struct mtk_clk_divider top_adj_divs[] = { + DIV_ADJ(CLK_TOP_APLL1_DIV, "apll1_ck_div", "apll1_ck_sel", + 0x120, 24, 3), + DIV_ADJ(CLK_TOP_APLL2_DIV, "apll2_ck_div", "apll2_ck_sel", + 0x120, 28, 3), + DIV_ADJ(CLK_TOP_I2S0_MCK_DIV, "i2s0_mck_div", "i2s0_mck_sel", + 0x124, 0, 7), + DIV_ADJ(CLK_TOP_I2S1_MCK_DIV, "i2s1_mck_div", "i2s1_mck_sel", + 0x124, 8, 7), + DIV_ADJ(CLK_TOP_I2S2_MCK_DIV, "i2s2_mck_div", "aud_i2s2_mck", + 0x124, 16, 7), + DIV_ADJ(CLK_TOP_I2S3_MCK_DIV, "i2s3_mck_div", "i2s3_mck_sel", + 0x124, 24, 7), + DIV_ADJ(CLK_TOP_A1SYS_HP_DIV, "a1sys_div", "a1sys_hp_sel", + 0x128, 8, 7), + DIV_ADJ(CLK_TOP_A2SYS_HP_DIV, "a2sys_div", "a2sys_hp_sel", + 0x128, 24, 7), +}; + +static const struct mtk_gate peri_clks[] = { + /* PERI0 */ + GATE_PERI0(CLK_PERI_THERM_PD, "peri_therm_pd", "axi_sel", 1), + GATE_PERI0(CLK_PERI_PWM1_PD, "peri_pwm1_pd", "clkxtal", 2), + GATE_PERI0(CLK_PERI_PWM2_PD, "peri_pwm2_pd", "clkxtal", 3), + GATE_PERI0(CLK_PERI_PWM3_PD, "peri_pwm3_pd", "clkxtal", 4), + GATE_PERI0(CLK_PERI_PWM4_PD, "peri_pwm4_pd", "clkxtal", 5), + GATE_PERI0(CLK_PERI_PWM5_PD, "peri_pwm5_pd", "clkxtal", 6), + GATE_PERI0(CLK_PERI_PWM6_PD, "peri_pwm6_pd", "clkxtal", 7), + GATE_PERI0(CLK_PERI_PWM7_PD, "peri_pwm7_pd", "clkxtal", 8), + GATE_PERI0(CLK_PERI_PWM_PD, "peri_pwm_pd", "clkxtal", 9), + GATE_PERI0(CLK_PERI_AP_DMA_PD, "peri_ap_dma_pd", "axi_sel", 12), + GATE_PERI0(CLK_PERI_MSDC30_0_PD, "peri_msdc30_0", "msdc30_0_sel", 13), + GATE_PERI0(CLK_PERI_MSDC30_1_PD, "peri_msdc30_1", "msdc30_1_sel", 14), + GATE_PERI0(CLK_PERI_UART0_PD, "peri_uart0_pd", "axi_sel", 17), + GATE_PERI0(CLK_PERI_UART1_PD, "peri_uart1_pd", "axi_sel", 18), + GATE_PERI0(CLK_PERI_UART2_PD, "peri_uart2_pd", "axi_sel", 19), + GATE_PERI0(CLK_PERI_UART3_PD, "peri_uart3_pd", "axi_sel", 20), + GATE_PERI0(CLK_PERI_UART4_PD, "peri_uart4_pd", "axi_sel", 21), + GATE_PERI0(CLK_PERI_BTIF_PD, "peri_btif_pd", "axi_sel", 22), + GATE_PERI0(CLK_PERI_I2C0_PD, "peri_i2c0_pd", "axi_sel", 23), + GATE_PERI0(CLK_PERI_I2C1_PD, "peri_i2c1_pd", "axi_sel", 24), + GATE_PERI0(CLK_PERI_I2C2_PD, "peri_i2c2_pd", "axi_sel", 25), + GATE_PERI0(CLK_PERI_SPI1_PD, "peri_spi1_pd", "spi1_sel", 26), + GATE_PERI0(CLK_PERI_AUXADC_PD, "peri_auxadc_pd", "clkxtal", 27), + GATE_PERI0(CLK_PERI_SPI0_PD, "peri_spi0_pd", "spi0_sel", 28), + GATE_PERI0(CLK_PERI_SNFI_PD, "peri_snfi_pd", "nfi_infra_sel", 29), + GATE_PERI0(CLK_PERI_NFI_PD, "peri_nfi_pd", "axi_sel", 30), + GATE_PERI0(CLK_PERI_NFIECC_PD, "peri_nfiecc_pd", "axi_sel", 31), + + /* PERI1 */ + GATE_PERI1(CLK_PERI_FLASH_PD, "peri_flash_pd", "flash_sel", 1), + GATE_PERI1(CLK_PERI_IRTX_PD, "peri_irtx_pd", "irtx_sel", 2), +}; + +static struct mtk_composite infra_muxes[] __initdata = { + MUX(CLK_INFRA_MUX1_SEL, "infra_mux1_sel", infra_mux1_parents, + 0x000, 2, 2), +}; + +static struct mtk_composite top_muxes[] = { + /* CLK_CFG_0 */ + MUX_GATE(CLK_TOP_AXI_SEL, "axi_sel", axi_parents, + 0x040, 0, 3, 7), + MUX_GATE(CLK_TOP_MEM_SEL, "mem_sel", mem_parents, + 0x040, 8, 1, 15), + MUX_GATE(CLK_TOP_DDRPHYCFG_SEL, "ddrphycfg_sel", ddrphycfg_parents, + 0x040, 16, 1, 23), + MUX_GATE(CLK_TOP_ETH_SEL, "eth_sel", eth_parents, + 0x040, 24, 3, 31), + + /* CLK_CFG_1 */ + MUX_GATE(CLK_TOP_PWM_SEL, "pwm_sel", pwm_parents, + 0x050, 0, 2, 7), + MUX_GATE(CLK_TOP_F10M_REF_SEL, "f10m_ref_sel", f10m_ref_parents, + 0x050, 8, 1, 15), + MUX_GATE(CLK_TOP_NFI_INFRA_SEL, "nfi_infra_sel", nfi_infra_parents, + 0x050, 16, 4, 23), + MUX_GATE(CLK_TOP_FLASH_SEL, "flash_sel", flash_parents, + 0x050, 24, 3, 31), + + /* CLK_CFG_2 */ + MUX_GATE(CLK_TOP_UART_SEL, "uart_sel", uart_parents, + 0x060, 0, 1, 7), + MUX_GATE(CLK_TOP_SPI0_SEL, "spi0_sel", spi0_parents, + 0x060, 8, 3, 15), + MUX_GATE(CLK_TOP_SPI1_SEL, "spi1_sel", spi1_parents, + 0x060, 16, 3, 23), + MUX_GATE(CLK_TOP_MSDC50_0_SEL, "msdc50_0_sel", uart_parents, + 0x060, 24, 3, 31), + + /* CLK_CFG_3 */ + MUX_GATE(CLK_TOP_MSDC30_0_SEL, "msdc30_0_sel", msdc30_0_parents, + 0x070, 0, 3, 7), + MUX_GATE(CLK_TOP_MSDC30_1_SEL, "msdc30_1_sel", msdc30_0_parents, + 0x070, 8, 3, 15), + MUX_GATE(CLK_TOP_A1SYS_HP_SEL, "a1sys_hp_sel", a1sys_hp_parents, + 0x070, 16, 2, 23), + MUX_GATE(CLK_TOP_A2SYS_HP_SEL, "a2sys_hp_sel", a1sys_hp_parents, + 0x070, 24, 2, 31), + + /* CLK_CFG_4 */ + MUX_GATE(CLK_TOP_INTDIR_SEL, "intdir_sel", intdir_parents, + 0x080, 0, 2, 7), + MUX_GATE(CLK_TOP_AUD_INTBUS_SEL, "aud_intbus_sel", aud_intbus_parents, + 0x080, 8, 2, 15), + MUX_GATE(CLK_TOP_PMICSPI_SEL, "pmicspi_sel", pmicspi_parents, + 0x080, 16, 3, 23), + MUX_GATE(CLK_TOP_SCP_SEL, "scp_sel", ddrphycfg_parents, + 0x080, 24, 2, 31), + + /* CLK_CFG_5 */ + MUX_GATE(CLK_TOP_ATB_SEL, "atb_sel", atb_parents, + 0x090, 0, 2, 7), + MUX_GATE(CLK_TOP_HIF_SEL, "hif_sel", eth_parents, + 0x090, 8, 3, 15), + MUX_GATE(CLK_TOP_AUDIO_SEL, "audio_sel", audio_parents, + 0x090, 16, 2, 23), + MUX_GATE(CLK_TOP_U2_SEL, "usb20_sel", usb20_parents, + 0x090, 24, 2, 31), + + /* CLK_CFG_6 */ + MUX_GATE(CLK_TOP_AUD1_SEL, "aud1_sel", aud1_parents, + 0x0A0, 0, 1, 7), + MUX_GATE(CLK_TOP_AUD2_SEL, "aud2_sel", aud2_parents, + 0x0A0, 8, 1, 15), + MUX_GATE(CLK_TOP_IRRX_SEL, "irrx_sel", f10m_ref_parents, + 0x0A0, 16, 1, 23), + MUX_GATE(CLK_TOP_IRTX_SEL, "irtx_sel", f10m_ref_parents, + 0x0A0, 24, 1, 31), + + /* CLK_CFG_7 */ + MUX_GATE(CLK_TOP_ASM_L_SEL, "asm_l_sel", asm_l_parents, + 0x0B0, 0, 2, 7), + MUX_GATE(CLK_TOP_ASM_M_SEL, "asm_m_sel", asm_l_parents, + 0x0B0, 8, 2, 15), + MUX_GATE(CLK_TOP_ASM_H_SEL, "asm_h_sel", asm_l_parents, + 0x0B0, 16, 2, 23), + + /* CLK_AUDDIV_0 */ + MUX(CLK_TOP_APLL1_SEL, "apll1_ck_sel", apll1_ck_parents, + 0x120, 6, 1), + MUX(CLK_TOP_APLL2_SEL, "apll2_ck_sel", apll1_ck_parents, + 0x120, 7, 1), + MUX(CLK_TOP_I2S0_MCK_SEL, "i2s0_mck_sel", apll1_ck_parents, + 0x120, 8, 1), + MUX(CLK_TOP_I2S1_MCK_SEL, "i2s1_mck_sel", apll1_ck_parents, + 0x120, 9, 1), + MUX(CLK_TOP_I2S2_MCK_SEL, "i2s2_mck_sel", apll1_ck_parents, + 0x120, 10, 1), + MUX(CLK_TOP_I2S3_MCK_SEL, "i2s3_mck_sel", apll1_ck_parents, + 0x120, 11, 1), +}; + +static struct mtk_composite peri_muxes[] = { + /* PERI_GLOBALCON_CKSEL */ + MUX(CLK_PERIBUS_SEL, "peribus_ck_sel", peribus_ck_parents, 0x05C, 0, 1), +}; + +static int mtk_topckgen_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + struct device_node *node = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_TOP_NR_CLK); + + mtk_clk_register_fixed_clks(top_fixed_clks, ARRAY_SIZE(top_fixed_clks), + clk_data); + + mtk_clk_register_factors(top_divs, ARRAY_SIZE(top_divs), + clk_data); + + mtk_clk_register_composites(top_muxes, ARRAY_SIZE(top_muxes), + base, &mt7622_clk_lock, clk_data); + + mtk_clk_register_dividers(top_adj_divs, ARRAY_SIZE(top_adj_divs), + base, &mt7622_clk_lock, clk_data); + + mtk_clk_register_gates(node, top_clks, ARRAY_SIZE(top_clks), + clk_data); + + clk_prepare_enable(clk_data->clks[CLK_TOP_AXI_SEL]); + clk_prepare_enable(clk_data->clks[CLK_TOP_MEM_SEL]); + clk_prepare_enable(clk_data->clks[CLK_TOP_DDRPHYCFG_SEL]); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static int __init mtk_infrasys_init(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + struct clk_onecell_data *clk_data; + int r; + + clk_data = mtk_alloc_clk_data(CLK_INFRA_NR_CLK); + + mtk_clk_register_gates(node, infra_clks, ARRAY_SIZE(infra_clks), + clk_data); + + mtk_clk_register_cpumuxes(node, infra_muxes, ARRAY_SIZE(infra_muxes), + clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, + clk_data); + if (r) + return r; + + mtk_register_reset_controller(node, 1, 0x30); + + return 0; +} + +static int mtk_apmixedsys_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + struct device_node *node = pdev->dev.of_node; + + clk_data = mtk_alloc_clk_data(CLK_APMIXED_NR_CLK); + if (!clk_data) + return -ENOMEM; + + mtk_clk_register_plls(node, plls, ARRAY_SIZE(plls), + clk_data); + + mtk_clk_register_gates(node, apmixed_clks, + ARRAY_SIZE(apmixed_clks), clk_data); + + clk_prepare_enable(clk_data->clks[CLK_APMIXED_ARMPLL]); + clk_prepare_enable(clk_data->clks[CLK_APMIXED_MAIN_CORE_EN]); + + return of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); +} + +static int mtk_pericfg_init(struct platform_device *pdev) +{ + struct clk_onecell_data *clk_data; + void __iomem *base; + int r; + struct device_node *node = pdev->dev.of_node; + struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + clk_data = mtk_alloc_clk_data(CLK_PERI_NR_CLK); + + mtk_clk_register_gates(node, peri_clks, ARRAY_SIZE(peri_clks), + clk_data); + + mtk_clk_register_composites(peri_muxes, ARRAY_SIZE(peri_muxes), base, + &mt7622_clk_lock, clk_data); + + r = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); + if (r) + return r; + + clk_prepare_enable(clk_data->clks[CLK_PERI_UART0_PD]); + + mtk_register_reset_controller(node, 2, 0x0); + + return 0; +} + +static const struct of_device_id of_match_clk_mt7622[] = { + { + .compatible = "mediatek,mt7622-apmixedsys", + .data = mtk_apmixedsys_init, + }, { + .compatible = "mediatek,mt7622-infracfg", + .data = mtk_infrasys_init, + }, { + .compatible = "mediatek,mt7622-topckgen", + .data = mtk_topckgen_init, + }, { + .compatible = "mediatek,mt7622-pericfg", + .data = mtk_pericfg_init, + }, { + /* sentinel */ + } +}; + +static int clk_mt7622_probe(struct platform_device *pdev) +{ + int (*clk_init)(struct platform_device *); + int r; + + clk_init = of_device_get_match_data(&pdev->dev); + if (!clk_init) + return -EINVAL; + + r = clk_init(pdev); + if (r) + dev_err(&pdev->dev, + "could not register clock provider: %s: %d\n", + pdev->name, r); + + return r; +} + +static struct platform_driver clk_mt7622_drv = { + .probe = clk_mt7622_probe, + .driver = { + .name = "clk-mt7622", + .of_match_table = of_match_clk_mt7622, + }, +}; + +static int clk_mt7622_init(void) +{ + return platform_driver_register(&clk_mt7622_drv); +} + +arch_initcall(clk_mt7622_init); diff --git a/drivers/clk/mediatek/clk-mtk.h b/drivers/clk/mediatek/clk-mtk.h index f5d6b70ce189..f10250dcece4 100644 --- a/drivers/clk/mediatek/clk-mtk.h +++ b/drivers/clk/mediatek/clk-mtk.h @@ -207,6 +207,8 @@ struct mtk_pll_data { uint32_t en_mask; uint32_t pd_reg; uint32_t tuner_reg; + uint32_t tuner_en_reg; + uint8_t tuner_en_bit; int pd_shift; unsigned int flags; const struct clk_ops *ops; @@ -216,6 +218,7 @@ struct mtk_pll_data { uint32_t pcw_reg; int pcw_shift; const struct mtk_pll_div_table *div_table; + const char *parent_name; }; void mtk_clk_register_plls(struct device_node *node, diff --git a/drivers/clk/mediatek/clk-pll.c b/drivers/clk/mediatek/clk-pll.c index a409142e9346..f54e4015b0b1 100644 --- a/drivers/clk/mediatek/clk-pll.c +++ b/drivers/clk/mediatek/clk-pll.c @@ -47,6 +47,7 @@ struct mtk_clk_pll { void __iomem *pd_addr; void __iomem *pwr_addr; void __iomem *tuner_addr; + void __iomem *tuner_en_addr; void __iomem *pcw_addr; const struct mtk_pll_data *data; }; @@ -227,7 +228,10 @@ static int mtk_pll_prepare(struct clk_hw *hw) r |= pll->data->en_mask; writel(r, pll->base_addr + REG_CON0); - if (pll->tuner_addr) { + if (pll->tuner_en_addr) { + r = readl(pll->tuner_en_addr) | BIT(pll->data->tuner_en_bit); + writel(r, pll->tuner_en_addr); + } else if (pll->tuner_addr) { r = readl(pll->tuner_addr) | AUDPLL_TUNER_EN; writel(r, pll->tuner_addr); } @@ -254,7 +258,10 @@ static void mtk_pll_unprepare(struct clk_hw *hw) writel(r, pll->base_addr + REG_CON0); } - if (pll->tuner_addr) { + if (pll->tuner_en_addr) { + r = readl(pll->tuner_en_addr) & ~BIT(pll->data->tuner_en_bit); + writel(r, pll->tuner_en_addr); + } else if (pll->tuner_addr) { r = readl(pll->tuner_addr) & ~AUDPLL_TUNER_EN; writel(r, pll->tuner_addr); } @@ -297,13 +304,18 @@ static struct clk *mtk_clk_register_pll(const struct mtk_pll_data *data, pll->pcw_addr = base + data->pcw_reg; if (data->tuner_reg) pll->tuner_addr = base + data->tuner_reg; + if (data->tuner_en_reg) + pll->tuner_en_addr = base + data->tuner_en_reg; pll->hw.init = &init; pll->data = data; init.name = data->name; init.flags = (data->flags & PLL_AO) ? CLK_IS_CRITICAL : 0; init.ops = &mtk_pll_ops; - init.parent_names = &parent_name; + if (data->parent_name) + init.parent_names = &data->parent_name; + else + init.parent_names = &parent_name; init.num_parents = 1; clk = clk_register(NULL, &pll->hw); diff --git a/drivers/clk/meson/gxbb.c b/drivers/clk/meson/gxbb.c index b2d1e8ed7152..ae385310e980 100644 --- a/drivers/clk/meson/gxbb.c +++ b/drivers/clk/meson/gxbb.c @@ -1131,6 +1131,253 @@ static struct clk_gate gxbb_sd_emmc_c_clk0 = { }, }; +/* VPU Clock */ + +static u32 mux_table_vpu[] = {0, 1, 2, 3}; +static const char * const gxbb_vpu_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +}; + +static struct clk_mux gxbb_vpu_0_sel = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 9, + .lock = &clk_lock, + .table = mux_table_vpu, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_sel", + .ops = &clk_mux_ops, + /* + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_names = gxbb_vpu_parent_names, + .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_vpu_0_div = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vpu_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_vpu_0 = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vpu_0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vpu_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_mux gxbb_vpu_1_sel = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 0x3, + .shift = 25, + .lock = &clk_lock, + .table = mux_table_vpu, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_sel", + .ops = &clk_mux_ops, + /* + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_names = gxbb_vpu_parent_names, + .num_parents = ARRAY_SIZE(gxbb_vpu_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_vpu_1_div = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu_1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vpu_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_vpu_1 = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vpu_1", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vpu_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_mux gxbb_vpu = { + .reg = (void *)HHI_VPU_CLK_CNTL, + .mask = 1, + .shift = 31, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vpu", + .ops = &clk_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vpu_0 or vpu_1 + */ + .parent_names = (const char *[]){ "vpu_0", "vpu_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +/* VAPB Clock */ + +static u32 mux_table_vapb[] = {0, 1, 2, 3}; +static const char * const gxbb_vapb_parent_names[] = { + "fclk_div4", "fclk_div3", "fclk_div5", "fclk_div7" +}; + +static struct clk_mux gxbb_vapb_0_sel = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 9, + .lock = &clk_lock, + .table = mux_table_vapb, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_sel", + .ops = &clk_mux_ops, + /* + * bits 9:10 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_names = gxbb_vapb_parent_names, + .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_vapb_0_div = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .shift = 0, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vapb_0_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vapb_0_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_vapb_0 = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .bit_idx = 8, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vapb_0", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vapb_0_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_mux gxbb_vapb_1_sel = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .mask = 0x3, + .shift = 25, + .lock = &clk_lock, + .table = mux_table_vapb, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_sel", + .ops = &clk_mux_ops, + /* + * bits 25:26 selects from 4 possible parents: + * fclk_div4, fclk_div3, fclk_div5, fclk_div7, + */ + .parent_names = gxbb_vapb_parent_names, + .num_parents = ARRAY_SIZE(gxbb_vapb_parent_names), + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_divider gxbb_vapb_1_div = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .shift = 16, + .width = 7, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vapb_1_div", + .ops = &clk_divider_ops, + .parent_names = (const char *[]){ "vapb_1_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT, + }, +}; + +static struct clk_gate gxbb_vapb_1 = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .bit_idx = 24, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vapb_1", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vapb_1_div" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + +static struct clk_mux gxbb_vapb_sel = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .mask = 1, + .shift = 31, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data){ + .name = "vapb_sel", + .ops = &clk_mux_ops, + /* + * bit 31 selects from 2 possible parents: + * vapb_0 or vapb_1 + */ + .parent_names = (const char *[]){ "vapb_0", "vapb_1" }, + .num_parents = 2, + .flags = CLK_SET_RATE_NO_REPARENT, + }, +}; + +static struct clk_gate gxbb_vapb = { + .reg = (void *)HHI_VAPBCLK_CNTL, + .bit_idx = 30, + .lock = &clk_lock, + .hw.init = &(struct clk_init_data) { + .name = "vapb", + .ops = &clk_gate_ops, + .parent_names = (const char *[]){ "vapb_sel" }, + .num_parents = 1, + .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED, + }, +}; + /* Everything Else (EE) domain gates */ static MESON_GATE(gxbb_ddr, HHI_GCLK_MPEG0, 0); static MESON_GATE(gxbb_dos, HHI_GCLK_MPEG0, 1); @@ -1349,6 +1596,21 @@ static struct clk_hw_onecell_data gxbb_hw_onecell_data = { [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [CLKID_VPU_0_SEL] = &gxbb_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &gxbb_vpu_0_div.hw, + [CLKID_VPU_0] = &gxbb_vpu_0.hw, + [CLKID_VPU_1_SEL] = &gxbb_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &gxbb_vpu_1_div.hw, + [CLKID_VPU_1] = &gxbb_vpu_1.hw, + [CLKID_VPU] = &gxbb_vpu.hw, + [CLKID_VAPB_0_SEL] = &gxbb_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &gxbb_vapb_0_div.hw, + [CLKID_VAPB_0] = &gxbb_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &gxbb_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &gxbb_vapb_1_div.hw, + [CLKID_VAPB_1] = &gxbb_vapb_1.hw, + [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, + [CLKID_VAPB] = &gxbb_vapb.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1481,6 +1743,21 @@ static struct clk_hw_onecell_data gxl_hw_onecell_data = { [CLKID_SD_EMMC_C_CLK0_SEL] = &gxbb_sd_emmc_c_clk0_sel.hw, [CLKID_SD_EMMC_C_CLK0_DIV] = &gxbb_sd_emmc_c_clk0_div.hw, [CLKID_SD_EMMC_C_CLK0] = &gxbb_sd_emmc_c_clk0.hw, + [CLKID_VPU_0_SEL] = &gxbb_vpu_0_sel.hw, + [CLKID_VPU_0_DIV] = &gxbb_vpu_0_div.hw, + [CLKID_VPU_0] = &gxbb_vpu_0.hw, + [CLKID_VPU_1_SEL] = &gxbb_vpu_1_sel.hw, + [CLKID_VPU_1_DIV] = &gxbb_vpu_1_div.hw, + [CLKID_VPU_1] = &gxbb_vpu_1.hw, + [CLKID_VPU] = &gxbb_vpu.hw, + [CLKID_VAPB_0_SEL] = &gxbb_vapb_0_sel.hw, + [CLKID_VAPB_0_DIV] = &gxbb_vapb_0_div.hw, + [CLKID_VAPB_0] = &gxbb_vapb_0.hw, + [CLKID_VAPB_1_SEL] = &gxbb_vapb_1_sel.hw, + [CLKID_VAPB_1_DIV] = &gxbb_vapb_1_div.hw, + [CLKID_VAPB_1] = &gxbb_vapb_1.hw, + [CLKID_VAPB_SEL] = &gxbb_vapb_sel.hw, + [CLKID_VAPB] = &gxbb_vapb.hw, [NR_CLKS] = NULL, }, .num = NR_CLKS, @@ -1600,6 +1877,11 @@ static struct clk_gate *const gxbb_clk_gates[] = { &gxbb_sd_emmc_a_clk0, &gxbb_sd_emmc_b_clk0, &gxbb_sd_emmc_c_clk0, + &gxbb_vpu_0, + &gxbb_vpu_1, + &gxbb_vapb_0, + &gxbb_vapb_1, + &gxbb_vapb, }; static struct clk_mux *const gxbb_clk_muxes[] = { @@ -1615,6 +1897,12 @@ static struct clk_mux *const gxbb_clk_muxes[] = { &gxbb_sd_emmc_a_clk0_sel, &gxbb_sd_emmc_b_clk0_sel, &gxbb_sd_emmc_c_clk0_sel, + &gxbb_vpu_0_sel, + &gxbb_vpu_1_sel, + &gxbb_vpu, + &gxbb_vapb_0_sel, + &gxbb_vapb_1_sel, + &gxbb_vapb_sel, }; static struct clk_divider *const gxbb_clk_dividers[] = { @@ -1627,6 +1915,10 @@ static struct clk_divider *const gxbb_clk_dividers[] = { &gxbb_sd_emmc_a_clk0_div, &gxbb_sd_emmc_b_clk0_div, &gxbb_sd_emmc_c_clk0_div, + &gxbb_vpu_0_div, + &gxbb_vpu_1_div, + &gxbb_vapb_0_div, + &gxbb_vapb_1_div, }; static struct meson_clk_audio_divider *const gxbb_audio_dividers[] = { diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h index 5b1d4b374d1c..aee6fbba2004 100644 --- a/drivers/clk/meson/gxbb.h +++ b/drivers/clk/meson/gxbb.h @@ -190,8 +190,12 @@ #define CLKID_SD_EMMC_B_CLK0_DIV 121 #define CLKID_SD_EMMC_C_CLK0_SEL 123 #define CLKID_SD_EMMC_C_CLK0_DIV 124 +#define CLKID_VPU_0_DIV 127 +#define CLKID_VPU_1_DIV 130 +#define CLKID_VAPB_0_DIV 134 +#define CLKID_VAPB_1_DIV 137 -#define NR_CLKS 126 +#define NR_CLKS 141 /* include the CLKIDs that have been made part of the DT binding */ #include <dt-bindings/clock/gxbb-clkc.h> diff --git a/drivers/clk/mmp/clk-apbc.c b/drivers/clk/mmp/clk-apbc.c index 4c717db05f2d..fb294ada0b03 100644 --- a/drivers/clk/mmp/clk-apbc.c +++ b/drivers/clk/mmp/clk-apbc.c @@ -114,7 +114,7 @@ static void clk_apbc_unprepare(struct clk_hw *hw) spin_unlock_irqrestore(apbc->lock, flags); } -static struct clk_ops clk_apbc_ops = { +static const struct clk_ops clk_apbc_ops = { .prepare = clk_apbc_prepare, .unprepare = clk_apbc_unprepare, }; diff --git a/drivers/clk/mmp/clk-apmu.c b/drivers/clk/mmp/clk-apmu.c index 47b5542ce50f..b7ce8f52026e 100644 --- a/drivers/clk/mmp/clk-apmu.c +++ b/drivers/clk/mmp/clk-apmu.c @@ -60,7 +60,7 @@ static void clk_apmu_disable(struct clk_hw *hw) spin_unlock_irqrestore(apmu->lock, flags); } -static struct clk_ops clk_apmu_ops = { +static const struct clk_ops clk_apmu_ops = { .enable = clk_apmu_enable, .disable = clk_apmu_disable, }; diff --git a/drivers/clk/mmp/clk-frac.c b/drivers/clk/mmp/clk-frac.c index 584a9927993b..cb43d54735b0 100644 --- a/drivers/clk/mmp/clk-frac.c +++ b/drivers/clk/mmp/clk-frac.c @@ -149,7 +149,7 @@ static void clk_factor_init(struct clk_hw *hw) spin_unlock_irqrestore(factor->lock, flags); } -static struct clk_ops clk_factor_ops = { +static const struct clk_ops clk_factor_ops = { .recalc_rate = clk_factor_recalc_rate, .round_rate = clk_factor_round_rate, .set_rate = clk_factor_set_rate, @@ -172,10 +172,8 @@ struct clk *mmp_clk_register_factor(const char *name, const char *parent_name, } factor = kzalloc(sizeof(*factor), GFP_KERNEL); - if (!factor) { - pr_err("%s: could not allocate factor clk\n", __func__); + if (!factor) return ERR_PTR(-ENOMEM); - } /* struct clk_aux assignments */ factor->base = base; diff --git a/drivers/clk/mmp/clk-gate.c b/drivers/clk/mmp/clk-gate.c index d20cd3431ac2..7355595c42e2 100644 --- a/drivers/clk/mmp/clk-gate.c +++ b/drivers/clk/mmp/clk-gate.c @@ -103,10 +103,8 @@ struct clk *mmp_clk_register_gate(struct device *dev, const char *name, /* allocate the gate */ gate = kzalloc(sizeof(*gate), GFP_KERNEL); - if (!gate) { - pr_err("%s:%s could not allocate gate clk\n", __func__, name); + if (!gate) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &mmp_clk_gate_ops; diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c index c554833cffc5..90814b2613c0 100644 --- a/drivers/clk/mmp/clk-mix.c +++ b/drivers/clk/mmp/clk-mix.c @@ -229,7 +229,7 @@ static int mmp_clk_mix_determine_rate(struct clk_hw *hw, parent_rate = clk_hw_get_rate(parent); mix_rate = parent_rate / item->divisor; gap = abs(mix_rate - req->rate); - if (parent_best == NULL || gap < gap_best) { + if (!parent_best || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; mix_rate_best = mix_rate; @@ -247,7 +247,7 @@ static int mmp_clk_mix_determine_rate(struct clk_hw *hw, div = _get_div(mix, j); mix_rate = parent_rate / div; gap = abs(mix_rate - req->rate); - if (parent_best == NULL || gap < gap_best) { + if (!parent_best || gap < gap_best) { parent_best = parent; parent_rate_best = parent_rate; mix_rate_best = mix_rate; @@ -451,11 +451,8 @@ struct clk *mmp_clk_register_mix(struct device *dev, size_t table_bytes; mix = kzalloc(sizeof(*mix), GFP_KERNEL); - if (!mix) { - pr_err("%s:%s: could not allocate mmp mix clk\n", - __func__, name); + if (!mix) return ERR_PTR(-ENOMEM); - } init.name = name; init.flags = flags | CLK_GET_RATE_NOCACHE; @@ -467,12 +464,9 @@ struct clk *mmp_clk_register_mix(struct device *dev, if (config->table) { table_bytes = sizeof(*config->table) * config->table_size; mix->table = kmemdup(config->table, table_bytes, GFP_KERNEL); - if (!mix->table) { - pr_err("%s:%s: could not allocate mmp mix table\n", - __func__, name); - kfree(mix); - return ERR_PTR(-ENOMEM); - } + if (!mix->table) + goto free_mix; + mix->table_size = config->table_size; } @@ -481,11 +475,8 @@ struct clk *mmp_clk_register_mix(struct device *dev, mix->mux_table = kmemdup(config->mux_table, table_bytes, GFP_KERNEL); if (!mix->mux_table) { - pr_err("%s:%s: could not allocate mmp mix mux-table\n", - __func__, name); kfree(mix->table); - kfree(mix); - return ERR_PTR(-ENOMEM); + goto free_mix; } } @@ -509,4 +500,8 @@ struct clk *mmp_clk_register_mix(struct device *dev, } return clk; + +free_mix: + kfree(mix); + return ERR_PTR(-ENOMEM); } diff --git a/drivers/clk/mmp/clk-mmp2.c b/drivers/clk/mmp/clk-mmp2.c index 038023483b98..7460031714da 100644 --- a/drivers/clk/mmp/clk-mmp2.c +++ b/drivers/clk/mmp/clk-mmp2.c @@ -83,19 +83,19 @@ void __init mmp2_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, void __iomem *apbc_base; mpmu_base = ioremap(mpmu_phys, SZ_4K); - if (mpmu_base == NULL) { + if (!mpmu_base) { pr_err("error to ioremap MPMU base\n"); return; } apmu_base = ioremap(apmu_phys, SZ_4K); - if (apmu_base == NULL) { + if (!apmu_base) { pr_err("error to ioremap APMU base\n"); return; } apbc_base = ioremap(apbc_phys, SZ_4K); - if (apbc_base == NULL) { + if (!apbc_base) { pr_err("error to ioremap APBC base\n"); return; } diff --git a/drivers/clk/mmp/clk-pxa168.c b/drivers/clk/mmp/clk-pxa168.c index a9ef9209532a..8e2551ab8462 100644 --- a/drivers/clk/mmp/clk-pxa168.c +++ b/drivers/clk/mmp/clk-pxa168.c @@ -75,19 +75,19 @@ void __init pxa168_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, void __iomem *apbc_base; mpmu_base = ioremap(mpmu_phys, SZ_4K); - if (mpmu_base == NULL) { + if (!mpmu_base) { pr_err("error to ioremap MPMU base\n"); return; } apmu_base = ioremap(apmu_phys, SZ_4K); - if (apmu_base == NULL) { + if (!apmu_base) { pr_err("error to ioremap APMU base\n"); return; } apbc_base = ioremap(apbc_phys, SZ_4K); - if (apbc_base == NULL) { + if (!apbc_base) { pr_err("error to ioremap APBC base\n"); return; } diff --git a/drivers/clk/mmp/clk-pxa910.c b/drivers/clk/mmp/clk-pxa910.c index a520cf7702a1..7a7965141918 100644 --- a/drivers/clk/mmp/clk-pxa910.c +++ b/drivers/clk/mmp/clk-pxa910.c @@ -74,25 +74,25 @@ void __init pxa910_clk_init(phys_addr_t mpmu_phys, phys_addr_t apmu_phys, void __iomem *apbc_base; mpmu_base = ioremap(mpmu_phys, SZ_4K); - if (mpmu_base == NULL) { + if (!mpmu_base) { pr_err("error to ioremap MPMU base\n"); return; } apmu_base = ioremap(apmu_phys, SZ_4K); - if (apmu_base == NULL) { + if (!apmu_base) { pr_err("error to ioremap APMU base\n"); return; } apbcp_base = ioremap(apbcp_phys, SZ_4K); - if (apbcp_base == NULL) { + if (!apbcp_base) { pr_err("error to ioremap APBC extension base\n"); return; } apbc_base = ioremap(apbc_phys, SZ_4K); - if (apbc_base == NULL) { + if (!apbc_base) { pr_err("error to ioremap APBC base\n"); return; } diff --git a/drivers/clk/mxs/clk-div.c b/drivers/clk/mxs/clk-div.c index f75e989c578f..ccebd014fc1e 100644 --- a/drivers/clk/mxs/clk-div.c +++ b/drivers/clk/mxs/clk-div.c @@ -67,7 +67,7 @@ static int clk_div_set_rate(struct clk_hw *hw, unsigned long rate, return ret; } -static struct clk_ops clk_div_ops = { +static const struct clk_ops clk_div_ops = { .recalc_rate = clk_div_recalc_rate, .round_rate = clk_div_round_rate, .set_rate = clk_div_set_rate, diff --git a/drivers/clk/mxs/clk-frac.c b/drivers/clk/mxs/clk-frac.c index f8dd10f6df3d..27b3372adc37 100644 --- a/drivers/clk/mxs/clk-frac.c +++ b/drivers/clk/mxs/clk-frac.c @@ -107,7 +107,7 @@ static int clk_frac_set_rate(struct clk_hw *hw, unsigned long rate, return mxs_clk_wait(frac->reg, frac->busy); } -static struct clk_ops clk_frac_ops = { +static const struct clk_ops clk_frac_ops = { .recalc_rate = clk_frac_recalc_rate, .round_rate = clk_frac_round_rate, .set_rate = clk_frac_set_rate, diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c index 74f64c3c4290..b80dc9d5855c 100644 --- a/drivers/clk/pxa/clk-pxa.c +++ b/drivers/clk/pxa/clk-pxa.c @@ -147,9 +147,7 @@ void pxa2xx_core_turbo_switch(bool on) " b 3f\n" "2: b 1b\n" "3: nop\n" - : "=&r" (unused) - : "r" (clkcfg) - : ); + : "=&r" (unused) : "r" (clkcfg)); local_irq_restore(flags); } diff --git a/drivers/clk/qcom/clk-rcg.h b/drivers/clk/qcom/clk-rcg.h index 1b3e8d265bdb..a2495457e564 100644 --- a/drivers/clk/qcom/clk-rcg.h +++ b/drivers/clk/qcom/clk-rcg.h @@ -156,7 +156,6 @@ extern const struct clk_ops clk_dyn_rcg_ops; * @hid_width: number of bits in half integer divider * @parent_map: map from software's parent index to hardware's src_sel field * @freq_tbl: frequency table - * @current_freq: last cached frequency when using branches with shared RCGs * @clkr: regmap clock handle * */ @@ -166,7 +165,6 @@ struct clk_rcg2 { u8 hid_width; const struct parent_map *parent_map; const struct freq_tbl *freq_tbl; - unsigned long current_freq; struct clk_regmap clkr; }; @@ -174,7 +172,6 @@ struct clk_rcg2 { extern const struct clk_ops clk_rcg2_ops; extern const struct clk_ops clk_rcg2_floor_ops; -extern const struct clk_ops clk_rcg2_shared_ops; extern const struct clk_ops clk_edp_pixel_ops; extern const struct clk_ops clk_byte_ops; extern const struct clk_ops clk_byte2_ops; diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c index 1a0985ae20d2..bbeaf9c09dbb 100644 --- a/drivers/clk/qcom/clk-rcg2.c +++ b/drivers/clk/qcom/clk-rcg2.c @@ -358,85 +358,6 @@ const struct clk_ops clk_rcg2_floor_ops = { }; EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops); -static int clk_rcg2_shared_force_enable(struct clk_hw *hw, unsigned long rate) -{ - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - const char *name = clk_hw_get_name(hw); - int ret, count; - - /* force enable RCG */ - ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, - CMD_ROOT_EN, CMD_ROOT_EN); - if (ret) - return ret; - - /* wait for RCG to turn ON */ - for (count = 500; count > 0; count--) { - ret = clk_rcg2_is_enabled(hw); - if (ret) - break; - udelay(1); - } - if (!count) - pr_err("%s: RCG did not turn on\n", name); - - /* set clock rate */ - ret = __clk_rcg2_set_rate(hw, rate, CEIL); - if (ret) - return ret; - - /* clear force enable RCG */ - return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, - CMD_ROOT_EN, 0); -} - -static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate, - unsigned long parent_rate) -{ - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - - /* cache the rate */ - rcg->current_freq = rate; - - if (!__clk_is_enabled(hw->clk)) - return 0; - - return clk_rcg2_shared_force_enable(hw, rcg->current_freq); -} - -static unsigned long -clk_rcg2_shared_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) -{ - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - - return rcg->current_freq = clk_rcg2_recalc_rate(hw, parent_rate); -} - -static int clk_rcg2_shared_enable(struct clk_hw *hw) -{ - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - - return clk_rcg2_shared_force_enable(hw, rcg->current_freq); -} - -static void clk_rcg2_shared_disable(struct clk_hw *hw) -{ - struct clk_rcg2 *rcg = to_clk_rcg2(hw); - - /* switch to XO, which is the lowest entry in the freq table */ - clk_rcg2_shared_set_rate(hw, rcg->freq_tbl[0].freq, 0); -} - -const struct clk_ops clk_rcg2_shared_ops = { - .enable = clk_rcg2_shared_enable, - .disable = clk_rcg2_shared_disable, - .get_parent = clk_rcg2_get_parent, - .recalc_rate = clk_rcg2_shared_recalc_rate, - .determine_rate = clk_rcg2_determine_rate, - .set_rate = clk_rcg2_shared_set_rate, -}; -EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops); - struct frac_entry { int num; int den; diff --git a/drivers/clk/qcom/clk-rpm.c b/drivers/clk/qcom/clk-rpm.c index df3e5fe8442a..c60f61b10c7f 100644 --- a/drivers/clk/qcom/clk-rpm.c +++ b/drivers/clk/qcom/clk-rpm.c @@ -56,6 +56,18 @@ }, \ } +#define DEFINE_CLK_RPM_FIXED(_platform, _name, _active, r_id, r) \ + static struct clk_rpm _platform##_##_name = { \ + .rpm_clk_id = (r_id), \ + .rate = (r), \ + .hw.init = &(struct clk_init_data){ \ + .ops = &clk_rpm_fixed_ops, \ + .name = #_name, \ + .parent_names = (const char *[]){ "pxo" }, \ + .num_parents = 1, \ + }, \ + } + #define DEFINE_CLK_RPM_PXO_BRANCH(_platform, _name, _active, r_id, r) \ static struct clk_rpm _platform##_##_active; \ static struct clk_rpm _platform##_##_name = { \ @@ -143,6 +155,13 @@ static int clk_rpm_handoff(struct clk_rpm *r) int ret; u32 value = INT_MAX; + /* + * The vendor tree simply reads the status for this + * RPM clock. + */ + if (r->rpm_clk_id == QCOM_RPM_PLL_4) + return 0; + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, r->rpm_clk_id, &value, 1); if (ret) @@ -269,6 +288,32 @@ out: mutex_unlock(&rpm_clk_lock); } +static int clk_rpm_fixed_prepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + u32 value = 1; + int ret; + + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); + if (!ret) + r->enabled = true; + + return ret; +} + +static void clk_rpm_fixed_unprepare(struct clk_hw *hw) +{ + struct clk_rpm *r = to_clk_rpm(hw); + u32 value = 0; + int ret; + + ret = qcom_rpm_write(r->rpm, QCOM_RPM_ACTIVE_STATE, + r->rpm_clk_id, &value, 1); + if (!ret) + r->enabled = false; +} + static int clk_rpm_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long parent_rate) { @@ -333,6 +378,13 @@ static unsigned long clk_rpm_recalc_rate(struct clk_hw *hw, return r->rate; } +static const struct clk_ops clk_rpm_fixed_ops = { + .prepare = clk_rpm_fixed_prepare, + .unprepare = clk_rpm_fixed_unprepare, + .round_rate = clk_rpm_round_rate, + .recalc_rate = clk_rpm_recalc_rate, +}; + static const struct clk_ops clk_rpm_ops = { .prepare = clk_rpm_prepare, .unprepare = clk_rpm_unprepare, @@ -348,6 +400,45 @@ static const struct clk_ops clk_rpm_branch_ops = { .recalc_rate = clk_rpm_recalc_rate, }; +/* MSM8660/APQ8060 */ +DEFINE_CLK_RPM(msm8660, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); +DEFINE_CLK_RPM(msm8660, sfab_clk, sfab_a_clk, QCOM_RPM_SYS_FABRIC_CLK); +DEFINE_CLK_RPM(msm8660, mmfab_clk, mmfab_a_clk, QCOM_RPM_MM_FABRIC_CLK); +DEFINE_CLK_RPM(msm8660, daytona_clk, daytona_a_clk, QCOM_RPM_DAYTONA_FABRIC_CLK); +DEFINE_CLK_RPM(msm8660, sfpb_clk, sfpb_a_clk, QCOM_RPM_SFPB_CLK); +DEFINE_CLK_RPM(msm8660, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); +DEFINE_CLK_RPM(msm8660, mmfpb_clk, mmfpb_a_clk, QCOM_RPM_MMFPB_CLK); +DEFINE_CLK_RPM(msm8660, smi_clk, smi_a_clk, QCOM_RPM_SMI_CLK); +DEFINE_CLK_RPM(msm8660, ebi1_clk, ebi1_a_clk, QCOM_RPM_EBI1_CLK); +DEFINE_CLK_RPM_FIXED(msm8660, pll4_clk, pll4_a_clk, QCOM_RPM_PLL_4, 540672000); + +static struct clk_rpm *msm8660_clks[] = { + [RPM_APPS_FABRIC_CLK] = &msm8660_afab_clk, + [RPM_APPS_FABRIC_A_CLK] = &msm8660_afab_a_clk, + [RPM_SYS_FABRIC_CLK] = &msm8660_sfab_clk, + [RPM_SYS_FABRIC_A_CLK] = &msm8660_sfab_a_clk, + [RPM_MM_FABRIC_CLK] = &msm8660_mmfab_clk, + [RPM_MM_FABRIC_A_CLK] = &msm8660_mmfab_a_clk, + [RPM_DAYTONA_FABRIC_CLK] = &msm8660_daytona_clk, + [RPM_DAYTONA_FABRIC_A_CLK] = &msm8660_daytona_a_clk, + [RPM_SFPB_CLK] = &msm8660_sfpb_clk, + [RPM_SFPB_A_CLK] = &msm8660_sfpb_a_clk, + [RPM_CFPB_CLK] = &msm8660_cfpb_clk, + [RPM_CFPB_A_CLK] = &msm8660_cfpb_a_clk, + [RPM_MMFPB_CLK] = &msm8660_mmfpb_clk, + [RPM_MMFPB_A_CLK] = &msm8660_mmfpb_a_clk, + [RPM_SMI_CLK] = &msm8660_smi_clk, + [RPM_SMI_A_CLK] = &msm8660_smi_a_clk, + [RPM_EBI1_CLK] = &msm8660_ebi1_clk, + [RPM_EBI1_A_CLK] = &msm8660_ebi1_a_clk, + [RPM_PLL4_CLK] = &msm8660_pll4_clk, +}; + +static const struct rpm_clk_desc rpm_clk_msm8660 = { + .clks = msm8660_clks, + .num_clks = ARRAY_SIZE(msm8660_clks), +}; + /* apq8064 */ DEFINE_CLK_RPM(apq8064, afab_clk, afab_a_clk, QCOM_RPM_APPS_FABRIC_CLK); DEFINE_CLK_RPM(apq8064, cfpb_clk, cfpb_a_clk, QCOM_RPM_CFPB_CLK); @@ -386,6 +477,8 @@ static const struct rpm_clk_desc rpm_clk_apq8064 = { }; static const struct of_device_id rpm_clk_match_table[] = { + { .compatible = "qcom,rpmcc-msm8660", .data = &rpm_clk_msm8660 }, + { .compatible = "qcom,rpmcc-apq8060", .data = &rpm_clk_msm8660 }, { .compatible = "qcom,rpmcc-apq8064", .data = &rpm_clk_apq8064 }, { } }; diff --git a/drivers/clk/qcom/clk-smd-rpm.c b/drivers/clk/qcom/clk-smd-rpm.c index cc03d5508627..c26d9007bfc4 100644 --- a/drivers/clk/qcom/clk-smd-rpm.c +++ b/drivers/clk/qcom/clk-smd-rpm.c @@ -530,9 +530,91 @@ static const struct rpm_smd_clk_desc rpm_clk_msm8974 = { .clks = msm8974_clks, .num_clks = ARRAY_SIZE(msm8974_clks), }; + +/* msm8996 */ +DEFINE_CLK_SMD_RPM(msm8996, pcnoc_clk, pcnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8996, snoc_clk, snoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 1); +DEFINE_CLK_SMD_RPM(msm8996, cnoc_clk, cnoc_a_clk, QCOM_SMD_RPM_BUS_CLK, 2); +DEFINE_CLK_SMD_RPM(msm8996, bimc_clk, bimc_a_clk, QCOM_SMD_RPM_MEM_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8996, mmssnoc_axi_rpm_clk, mmssnoc_axi_rpm_a_clk, + QCOM_SMD_RPM_MMAXI_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8996, ipa_clk, ipa_a_clk, QCOM_SMD_RPM_IPA_CLK, 0); +DEFINE_CLK_SMD_RPM(msm8996, ce1_clk, ce1_a_clk, QCOM_SMD_RPM_CE_CLK, 0); +DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre1_noc_clk, aggre1_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 1, 1000); +DEFINE_CLK_SMD_RPM_BRANCH(msm8996, aggre2_noc_clk, aggre2_noc_a_clk, + QCOM_SMD_RPM_AGGR_CLK, 2, 1000); +DEFINE_CLK_SMD_RPM_QDSS(msm8996, qdss_clk, qdss_a_clk, + QCOM_SMD_RPM_MISC_CLK, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk1, bb_clk1_a, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, bb_clk2, bb_clk2_a, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk1, rf_clk1_a, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, rf_clk2, rf_clk2_a, 5); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, ln_bb_clk, ln_bb_a_clk, 8); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk1, div_clk1_a, 0xb); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk2, div_clk2_a, 0xc); +DEFINE_CLK_SMD_RPM_XO_BUFFER(msm8996, div_clk3, div_clk3_a, 0xd); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk1_pin, bb_clk1_a_pin, 1); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, bb_clk2_pin, bb_clk2_a_pin, 2); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk1_pin, rf_clk1_a_pin, 4); +DEFINE_CLK_SMD_RPM_XO_BUFFER_PINCTRL(msm8996, rf_clk2_pin, rf_clk2_a_pin, 5); + +static struct clk_smd_rpm *msm8996_clks[] = { + [RPM_SMD_PCNOC_CLK] = &msm8996_pcnoc_clk, + [RPM_SMD_PCNOC_A_CLK] = &msm8996_pcnoc_a_clk, + [RPM_SMD_SNOC_CLK] = &msm8996_snoc_clk, + [RPM_SMD_SNOC_A_CLK] = &msm8996_snoc_a_clk, + [RPM_SMD_CNOC_CLK] = &msm8996_cnoc_clk, + [RPM_SMD_CNOC_A_CLK] = &msm8996_cnoc_a_clk, + [RPM_SMD_BIMC_CLK] = &msm8996_bimc_clk, + [RPM_SMD_BIMC_A_CLK] = &msm8996_bimc_a_clk, + [RPM_SMD_MMAXI_CLK] = &msm8996_mmssnoc_axi_rpm_clk, + [RPM_SMD_MMAXI_A_CLK] = &msm8996_mmssnoc_axi_rpm_a_clk, + [RPM_SMD_IPA_CLK] = &msm8996_ipa_clk, + [RPM_SMD_IPA_A_CLK] = &msm8996_ipa_a_clk, + [RPM_SMD_CE1_CLK] = &msm8996_ce1_clk, + [RPM_SMD_CE1_A_CLK] = &msm8996_ce1_a_clk, + [RPM_SMD_AGGR1_NOC_CLK] = &msm8996_aggre1_noc_clk, + [RPM_SMD_AGGR1_NOC_A_CLK] = &msm8996_aggre1_noc_a_clk, + [RPM_SMD_AGGR2_NOC_CLK] = &msm8996_aggre2_noc_clk, + [RPM_SMD_AGGR2_NOC_A_CLK] = &msm8996_aggre2_noc_a_clk, + [RPM_SMD_QDSS_CLK] = &msm8996_qdss_clk, + [RPM_SMD_QDSS_A_CLK] = &msm8996_qdss_a_clk, + [RPM_SMD_BB_CLK1] = &msm8996_bb_clk1, + [RPM_SMD_BB_CLK1_A] = &msm8996_bb_clk1_a, + [RPM_SMD_BB_CLK2] = &msm8996_bb_clk2, + [RPM_SMD_BB_CLK2_A] = &msm8996_bb_clk2_a, + [RPM_SMD_RF_CLK1] = &msm8996_rf_clk1, + [RPM_SMD_RF_CLK1_A] = &msm8996_rf_clk1_a, + [RPM_SMD_RF_CLK2] = &msm8996_rf_clk2, + [RPM_SMD_RF_CLK2_A] = &msm8996_rf_clk2_a, + [RPM_SMD_LN_BB_CLK] = &msm8996_ln_bb_clk, + [RPM_SMD_LN_BB_A_CLK] = &msm8996_ln_bb_a_clk, + [RPM_SMD_DIV_CLK1] = &msm8996_div_clk1, + [RPM_SMD_DIV_A_CLK1] = &msm8996_div_clk1_a, + [RPM_SMD_DIV_CLK2] = &msm8996_div_clk2, + [RPM_SMD_DIV_A_CLK2] = &msm8996_div_clk2_a, + [RPM_SMD_DIV_CLK3] = &msm8996_div_clk3, + [RPM_SMD_DIV_A_CLK3] = &msm8996_div_clk3_a, + [RPM_SMD_BB_CLK1_PIN] = &msm8996_bb_clk1_pin, + [RPM_SMD_BB_CLK1_A_PIN] = &msm8996_bb_clk1_a_pin, + [RPM_SMD_BB_CLK2_PIN] = &msm8996_bb_clk2_pin, + [RPM_SMD_BB_CLK2_A_PIN] = &msm8996_bb_clk2_a_pin, + [RPM_SMD_RF_CLK1_PIN] = &msm8996_rf_clk1_pin, + [RPM_SMD_RF_CLK1_A_PIN] = &msm8996_rf_clk1_a_pin, + [RPM_SMD_RF_CLK2_PIN] = &msm8996_rf_clk2_pin, + [RPM_SMD_RF_CLK2_A_PIN] = &msm8996_rf_clk2_a_pin, +}; + +static const struct rpm_smd_clk_desc rpm_clk_msm8996 = { + .clks = msm8996_clks, + .num_clks = ARRAY_SIZE(msm8996_clks), +}; + static const struct of_device_id rpm_smd_clk_match_table[] = { { .compatible = "qcom,rpmcc-msm8916", .data = &rpm_clk_msm8916 }, { .compatible = "qcom,rpmcc-msm8974", .data = &rpm_clk_msm8974 }, + { .compatible = "qcom,rpmcc-msm8996", .data = &rpm_clk_msm8996 }, { } }; MODULE_DEVICE_TABLE(of, rpm_smd_clk_match_table); diff --git a/drivers/clk/qcom/common.c b/drivers/clk/qcom/common.c index d523991c945f..b8064a336d46 100644 --- a/drivers/clk/qcom/common.c +++ b/drivers/clk/qcom/common.c @@ -111,16 +111,6 @@ qcom_pll_set_fsm_mode(struct regmap *map, u32 reg, u8 bias_count, u8 lock_count) } EXPORT_SYMBOL_GPL(qcom_pll_set_fsm_mode); -static void qcom_cc_del_clk_provider(void *data) -{ - of_clk_del_provider(data); -} - -static void qcom_cc_reset_unregister(void *data) -{ - reset_controller_unregister(data); -} - static void qcom_cc_gdsc_unregister(void *data) { gdsc_unregister(data); @@ -143,8 +133,10 @@ static int _qcom_cc_register_board_clk(struct device *dev, const char *path, int ret; clocks_node = of_find_node_by_path("/clocks"); - if (clocks_node) - node = of_find_node_by_name(clocks_node, path); + if (clocks_node) { + node = of_get_child_by_name(clocks_node, path); + of_node_put(clocks_node); + } if (!node) { fixed = devm_kzalloc(dev, sizeof(*fixed), GFP_KERNEL); @@ -248,13 +240,7 @@ int qcom_cc_really_probe(struct platform_device *pdev, return ret; } - ret = of_clk_add_hw_provider(dev->of_node, qcom_cc_clk_hw_get, cc); - if (ret) - return ret; - - ret = devm_add_action_or_reset(dev, qcom_cc_del_clk_provider, - pdev->dev.of_node); - + ret = devm_of_clk_add_hw_provider(dev, qcom_cc_clk_hw_get, cc); if (ret) return ret; @@ -266,13 +252,7 @@ int qcom_cc_really_probe(struct platform_device *pdev, reset->regmap = regmap; reset->reset_map = desc->resets; - ret = reset_controller_register(&reset->rcdev); - if (ret) - return ret; - - ret = devm_add_action_or_reset(dev, qcom_cc_reset_unregister, - &reset->rcdev); - + ret = devm_reset_controller_register(dev, &reset->rcdev); if (ret) return ret; diff --git a/drivers/clk/renesas/Kconfig b/drivers/clk/renesas/Kconfig index acbb38151ba1..43b5a89c4b28 100644 --- a/drivers/clk/renesas/Kconfig +++ b/drivers/clk/renesas/Kconfig @@ -15,6 +15,7 @@ config CLK_RENESAS select CLK_R8A7794 if ARCH_R8A7794 select CLK_R8A7795 if ARCH_R8A7795 select CLK_R8A7796 if ARCH_R8A7796 + select CLK_R8A77970 if ARCH_R8A77970 select CLK_R8A77995 if ARCH_R8A77995 select CLK_SH73A0 if ARCH_SH73A0 @@ -95,6 +96,10 @@ config CLK_R8A7796 bool "R-Car M3-W clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG +config CLK_R8A77970 + bool "R-Car V3M clock support" if COMPILE_TEST + select CLK_RCAR_GEN3_CPG + config CLK_R8A77995 bool "R-Car D3 clock support" if COMPILE_TEST select CLK_RCAR_GEN3_CPG diff --git a/drivers/clk/renesas/Makefile b/drivers/clk/renesas/Makefile index cbbb081e2145..34c4e0b37afa 100644 --- a/drivers/clk/renesas/Makefile +++ b/drivers/clk/renesas/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_CLK_R8A7792) += r8a7792-cpg-mssr.o obj-$(CONFIG_CLK_R8A7794) += r8a7794-cpg-mssr.o obj-$(CONFIG_CLK_R8A7795) += r8a7795-cpg-mssr.o obj-$(CONFIG_CLK_R8A7796) += r8a7796-cpg-mssr.o +obj-$(CONFIG_CLK_R8A77970) += r8a77970-cpg-mssr.o obj-$(CONFIG_CLK_R8A77995) += r8a77995-cpg-mssr.o obj-$(CONFIG_CLK_SH73A0) += clk-sh73a0.o diff --git a/drivers/clk/renesas/clk-div6.c b/drivers/clk/renesas/clk-div6.c index 3e0040c0ac87..151336d2ba59 100644 --- a/drivers/clk/renesas/clk-div6.c +++ b/drivers/clk/renesas/clk-div6.c @@ -14,8 +14,10 @@ #include <linux/init.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/notifier.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/pm.h> #include <linux/slab.h> #include "clk-div6.h" @@ -32,6 +34,7 @@ * @src_shift: Shift to access the register bits to select the parent clock * @src_width: Number of register bits to select the parent clock (may be 0) * @parents: Array to map from valid parent clocks indices to hardware indices + * @nb: Notifier block to save/restore clock state for system resume */ struct div6_clock { struct clk_hw hw; @@ -40,6 +43,7 @@ struct div6_clock { u32 src_shift; u32 src_width; u8 *parents; + struct notifier_block nb; }; #define to_div6_clock(_hw) container_of(_hw, struct div6_clock, hw) @@ -176,6 +180,29 @@ static const struct clk_ops cpg_div6_clock_ops = { .set_rate = cpg_div6_clock_set_rate, }; +static int cpg_div6_clock_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct div6_clock *clock = container_of(nb, struct div6_clock, nb); + + switch (action) { + case PM_EVENT_RESUME: + /* + * TODO: This does not yet support DIV6 clocks with multiple + * parents, as the parent selection bits are not restored. + * Fortunately so far such DIV6 clocks are found only on + * R/SH-Mobile SoCs, while the resume functionality is only + * needed on R-Car Gen3. + */ + if (__clk_get_enable_count(clock->hw.clk)) + cpg_div6_clock_enable(&clock->hw); + else + cpg_div6_clock_disable(&clock->hw); + return NOTIFY_OK; + } + + return NOTIFY_DONE; +} /** * cpg_div6_register - Register a DIV6 clock @@ -183,11 +210,13 @@ static const struct clk_ops cpg_div6_clock_ops = { * @num_parents: Number of parent clocks of the DIV6 clock (1, 4, or 8) * @parent_names: Array containing the names of the parent clocks * @reg: Mapped register used to control the DIV6 clock + * @notifiers: Optional notifier chain to save/restore state for system resume */ struct clk * __init cpg_div6_register(const char *name, unsigned int num_parents, const char **parent_names, - void __iomem *reg) + void __iomem *reg, + struct raw_notifier_head *notifiers) { unsigned int valid_parents; struct clk_init_data init; @@ -258,6 +287,11 @@ struct clk * __init cpg_div6_register(const char *name, if (IS_ERR(clk)) goto free_parents; + if (notifiers) { + clock->nb.notifier_call = cpg_div6_clock_notifier_call; + raw_notifier_chain_register(notifiers, &clock->nb); + } + return clk; free_parents: @@ -301,7 +335,7 @@ static void __init cpg_div6_clock_init(struct device_node *np) for (i = 0; i < num_parents; i++) parent_names[i] = of_clk_get_parent_name(np, i); - clk = cpg_div6_register(clk_name, num_parents, parent_names, reg); + clk = cpg_div6_register(clk_name, num_parents, parent_names, reg, NULL); if (IS_ERR(clk)) { pr_err("%s: failed to register %s DIV6 clock (%ld)\n", __func__, np->name, PTR_ERR(clk)); diff --git a/drivers/clk/renesas/clk-div6.h b/drivers/clk/renesas/clk-div6.h index 065dfb49adf6..3af640a0b08d 100644 --- a/drivers/clk/renesas/clk-div6.h +++ b/drivers/clk/renesas/clk-div6.h @@ -3,6 +3,7 @@ #define __RENESAS_CLK_DIV6_H__ struct clk *cpg_div6_register(const char *name, unsigned int num_parents, - const char **parent_names, void __iomem *reg); + const char **parent_names, void __iomem *reg, + struct raw_notifier_head *notifiers); #endif diff --git a/drivers/clk/renesas/clk-mstp.c b/drivers/clk/renesas/clk-mstp.c index 500a9e4e03c4..c944cc421e30 100644 --- a/drivers/clk/renesas/clk-mstp.c +++ b/drivers/clk/renesas/clk-mstp.c @@ -156,10 +156,8 @@ static struct clk * __init cpg_mstp_clock_register(const char *name, struct clk *clk; clock = kzalloc(sizeof(*clock), GFP_KERNEL); - if (!clock) { - pr_err("%s: failed to allocate MSTP clock.\n", __func__); + if (!clock) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &cpg_mstp_clock_ops; @@ -196,7 +194,6 @@ static void __init cpg_mstp_clocks_init(struct device_node *np) if (group == NULL || clks == NULL) { kfree(group); kfree(clks); - pr_err("%s: failed to allocate group\n", __func__); return; } diff --git a/drivers/clk/renesas/clk-rcar-gen2.c b/drivers/clk/renesas/clk-rcar-gen2.c index 0b2e56d0d94b..d14cbe1ca29a 100644 --- a/drivers/clk/renesas/clk-rcar-gen2.c +++ b/drivers/clk/renesas/clk-rcar-gen2.c @@ -423,7 +423,6 @@ static void __init rcar_gen2_cpg_clocks_init(struct device_node *np) /* We're leaking memory on purpose, there's no point in cleaning * up as the system won't boot anyway. */ - pr_err("%s: failed to allocate cpg\n", __func__); return; } diff --git a/drivers/clk/renesas/clk-rz.c b/drivers/clk/renesas/clk-rz.c index 5adb934326d1..127c58135c8f 100644 --- a/drivers/clk/renesas/clk-rz.c +++ b/drivers/clk/renesas/clk-rz.c @@ -1,5 +1,5 @@ /* - * rz Core CPG Clocks + * RZ/A1 Core CPG Clocks * * Copyright (C) 2013 Ideas On Board SPRL * Copyright (C) 2014 Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> diff --git a/drivers/clk/renesas/r8a7745-cpg-mssr.c b/drivers/clk/renesas/r8a7745-cpg-mssr.c index 9e2360a8e14b..2859504cc866 100644 --- a/drivers/clk/renesas/r8a7745-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7745-cpg-mssr.c @@ -129,6 +129,7 @@ static const struct mssr_mod_clk r8a7745_mod_clks[] __initconst = { DEF_MOD("scif2", 719, R8A7745_CLK_P), DEF_MOD("scif1", 720, R8A7745_CLK_P), DEF_MOD("scif0", 721, R8A7745_CLK_P), + DEF_MOD("du1", 723, R8A7745_CLK_ZX), DEF_MOD("du0", 724, R8A7745_CLK_ZX), DEF_MOD("ipmmu-sgx", 800, R8A7745_CLK_ZX), DEF_MOD("vin1", 810, R8A7745_CLK_ZG), diff --git a/drivers/clk/renesas/r8a7795-cpg-mssr.c b/drivers/clk/renesas/r8a7795-cpg-mssr.c index 762b2f8824f1..b1d9f48eae9e 100644 --- a/drivers/clk/renesas/r8a7795-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7795-cpg-mssr.c @@ -149,7 +149,7 @@ static struct mssr_mod_clk r8a7795_mod_clks[] __initdata = { DEF_MOD("usb-dmac1", 331, R8A7795_CLK_S3D1), DEF_MOD("rwdt", 402, R8A7795_CLK_R), DEF_MOD("intc-ex", 407, R8A7795_CLK_CP), - DEF_MOD("intc-ap", 408, R8A7795_CLK_S3D1), + DEF_MOD("intc-ap", 408, R8A7795_CLK_S0D3), DEF_MOD("audmac1", 501, R8A7795_CLK_S0D3), DEF_MOD("audmac0", 502, R8A7795_CLK_S0D3), DEF_MOD("drif7", 508, R8A7795_CLK_S3D2), @@ -348,6 +348,7 @@ static const struct mssr_mod_reparent r8a7795es1_mod_reparent[] __initconst = { { MOD_CLK_ID(217), R8A7795_CLK_S3D1 }, /* SYS-DMAC2 */ { MOD_CLK_ID(218), R8A7795_CLK_S3D1 }, /* SYS-DMAC1 */ { MOD_CLK_ID(219), R8A7795_CLK_S3D1 }, /* SYS-DMAC0 */ + { MOD_CLK_ID(408), R8A7795_CLK_S3D1 }, /* INTC-AP */ { MOD_CLK_ID(501), R8A7795_CLK_S3D1 }, /* AUDMAC1 */ { MOD_CLK_ID(502), R8A7795_CLK_S3D1 }, /* AUDMAC0 */ { MOD_CLK_ID(523), R8A7795_CLK_S3D4 }, /* PWM */ diff --git a/drivers/clk/renesas/r8a7796-cpg-mssr.c b/drivers/clk/renesas/r8a7796-cpg-mssr.c index e5e7fb212288..b3767472088a 100644 --- a/drivers/clk/renesas/r8a7796-cpg-mssr.c +++ b/drivers/clk/renesas/r8a7796-cpg-mssr.c @@ -143,7 +143,7 @@ static const struct mssr_mod_clk r8a7796_mod_clks[] __initconst = { DEF_MOD("usb-dmac1", 331, R8A7796_CLK_S3D1), DEF_MOD("rwdt", 402, R8A7796_CLK_R), DEF_MOD("intc-ex", 407, R8A7796_CLK_CP), - DEF_MOD("intc-ap", 408, R8A7796_CLK_S3D1), + DEF_MOD("intc-ap", 408, R8A7796_CLK_S0D3), DEF_MOD("audmac1", 501, R8A7796_CLK_S0D3), DEF_MOD("audmac0", 502, R8A7796_CLK_S0D3), DEF_MOD("drif7", 508, R8A7796_CLK_S3D2), diff --git a/drivers/clk/renesas/r8a77970-cpg-mssr.c b/drivers/clk/renesas/r8a77970-cpg-mssr.c new file mode 100644 index 000000000000..72f98527473a --- /dev/null +++ b/drivers/clk/renesas/r8a77970-cpg-mssr.c @@ -0,0 +1,199 @@ +/* + * r8a77970 Clock Pulse Generator / Module Standby and Software Reset + * + * Copyright (C) 2017 Cogent Embedded Inc. + * + * Based on r8a7795-cpg-mssr.c + * + * Copyright (C) 2015 Glider bvba + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + */ + +#include <linux/device.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/soc/renesas/rcar-rst.h> + +#include <dt-bindings/clock/r8a77970-cpg-mssr.h> + +#include "renesas-cpg-mssr.h" +#include "rcar-gen3-cpg.h" + +enum clk_ids { + /* Core Clock Outputs exported to DT */ + LAST_DT_CORE_CLK = R8A77970_CLK_OSC, + + /* External Input Clocks */ + CLK_EXTAL, + CLK_EXTALR, + + /* Internal Core Clocks */ + CLK_MAIN, + CLK_PLL0, + CLK_PLL1, + CLK_PLL3, + CLK_PLL1_DIV2, + CLK_PLL1_DIV4, + + /* Module Clocks */ + MOD_CLK_BASE +}; + +static const struct cpg_core_clk r8a77970_core_clks[] __initconst = { + /* External Clock Inputs */ + DEF_INPUT("extal", CLK_EXTAL), + DEF_INPUT("extalr", CLK_EXTALR), + + /* Internal Core Clocks */ + DEF_BASE(".main", CLK_MAIN, CLK_TYPE_GEN3_MAIN, CLK_EXTAL), + DEF_BASE(".pll0", CLK_PLL0, CLK_TYPE_GEN3_PLL0, CLK_MAIN), + DEF_BASE(".pll1", CLK_PLL1, CLK_TYPE_GEN3_PLL1, CLK_MAIN), + DEF_BASE(".pll3", CLK_PLL3, CLK_TYPE_GEN3_PLL3, CLK_MAIN), + + DEF_FIXED(".pll1_div2", CLK_PLL1_DIV2, CLK_PLL1, 2, 1), + DEF_FIXED(".pll1_div4", CLK_PLL1_DIV4, CLK_PLL1_DIV2, 2, 1), + + /* Core Clock Outputs */ + DEF_FIXED("ztr", R8A77970_CLK_ZTR, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED("ztrd2", R8A77970_CLK_ZTRD2, CLK_PLL1_DIV2, 12, 1), + DEF_FIXED("zt", R8A77970_CLK_ZT, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("zx", R8A77970_CLK_ZX, CLK_PLL1_DIV2, 3, 1), + DEF_FIXED("s1d1", R8A77970_CLK_S1D1, CLK_PLL1_DIV2, 4, 1), + DEF_FIXED("s1d2", R8A77970_CLK_S1D2, CLK_PLL1_DIV2, 8, 1), + DEF_FIXED("s1d4", R8A77970_CLK_S1D4, CLK_PLL1_DIV2, 16, 1), + DEF_FIXED("s2d1", R8A77970_CLK_S2D1, CLK_PLL1_DIV2, 6, 1), + DEF_FIXED("s2d2", R8A77970_CLK_S2D2, CLK_PLL1_DIV2, 12, 1), + DEF_FIXED("s2d4", R8A77970_CLK_S2D4, CLK_PLL1_DIV2, 24, 1), + + DEF_FIXED("cl", R8A77970_CLK_CL, CLK_PLL1_DIV2, 48, 1), + DEF_FIXED("cp", R8A77970_CLK_CP, CLK_EXTAL, 2, 1), + + DEF_DIV6P1("canfd", R8A77970_CLK_CANFD, CLK_PLL1_DIV4, 0x244), + DEF_DIV6P1("mso", R8A77970_CLK_MSO, CLK_PLL1_DIV4, 0x014), + DEF_DIV6P1("csi0", R8A77970_CLK_CSI0, CLK_PLL1_DIV4, 0x00c), + + DEF_FIXED("osc", R8A77970_CLK_OSC, CLK_PLL1_DIV2, 12*1024, 1), + DEF_FIXED("r", R8A77970_CLK_R, CLK_EXTALR, 1, 1), +}; + +static const struct mssr_mod_clk r8a77970_mod_clks[] __initconst = { + DEF_MOD("ivcp1e", 127, R8A77970_CLK_S2D1), + DEF_MOD("scif4", 203, R8A77970_CLK_S2D4), + DEF_MOD("scif3", 204, R8A77970_CLK_S2D4), + DEF_MOD("scif1", 206, R8A77970_CLK_S2D4), + DEF_MOD("scif0", 207, R8A77970_CLK_S2D4), + DEF_MOD("msiof3", 208, R8A77970_CLK_MSO), + DEF_MOD("msiof2", 209, R8A77970_CLK_MSO), + DEF_MOD("msiof1", 210, R8A77970_CLK_MSO), + DEF_MOD("msiof0", 211, R8A77970_CLK_MSO), + DEF_MOD("mfis", 213, R8A77970_CLK_S2D2), + DEF_MOD("sys-dmac2", 217, R8A77970_CLK_S2D1), + DEF_MOD("sys-dmac1", 218, R8A77970_CLK_S2D1), + DEF_MOD("rwdt", 402, R8A77970_CLK_R), + DEF_MOD("intc-ex", 407, R8A77970_CLK_CP), + DEF_MOD("intc-ap", 408, R8A77970_CLK_S2D1), + DEF_MOD("hscif3", 517, R8A77970_CLK_S2D1), + DEF_MOD("hscif2", 518, R8A77970_CLK_S2D1), + DEF_MOD("hscif1", 519, R8A77970_CLK_S2D1), + DEF_MOD("hscif0", 520, R8A77970_CLK_S2D1), + DEF_MOD("thermal", 522, R8A77970_CLK_CP), + DEF_MOD("pwm", 523, R8A77970_CLK_S2D4), + DEF_MOD("fcpvd0", 603, R8A77970_CLK_S2D1), + DEF_MOD("vspd0", 623, R8A77970_CLK_S2D1), + DEF_MOD("csi40", 716, R8A77970_CLK_CSI0), + DEF_MOD("du0", 724, R8A77970_CLK_S2D1), + DEF_MOD("vin3", 808, R8A77970_CLK_S2D1), + DEF_MOD("vin2", 809, R8A77970_CLK_S2D1), + DEF_MOD("vin1", 810, R8A77970_CLK_S2D1), + DEF_MOD("vin0", 811, R8A77970_CLK_S2D1), + DEF_MOD("etheravb", 812, R8A77970_CLK_S2D2), + DEF_MOD("gpio5", 907, R8A77970_CLK_CP), + DEF_MOD("gpio4", 908, R8A77970_CLK_CP), + DEF_MOD("gpio3", 909, R8A77970_CLK_CP), + DEF_MOD("gpio2", 910, R8A77970_CLK_CP), + DEF_MOD("gpio1", 911, R8A77970_CLK_CP), + DEF_MOD("gpio0", 912, R8A77970_CLK_CP), + DEF_MOD("can-fd", 914, R8A77970_CLK_S2D2), + DEF_MOD("i2c4", 927, R8A77970_CLK_S2D2), + DEF_MOD("i2c3", 928, R8A77970_CLK_S2D2), + DEF_MOD("i2c2", 929, R8A77970_CLK_S2D2), + DEF_MOD("i2c1", 930, R8A77970_CLK_S2D2), + DEF_MOD("i2c0", 931, R8A77970_CLK_S2D2), +}; + +static const unsigned int r8a77970_crit_mod_clks[] __initconst = { + MOD_CLK_ID(408), /* INTC-AP (GIC) */ +}; + + +/* + * CPG Clock Data + */ + +/* + * MD EXTAL PLL0 PLL1 PLL3 + * 14 13 19 (MHz) + *------------------------------------------------- + * 0 0 0 16.66 x 1 x192 x192 x96 + * 0 0 1 16.66 x 1 x192 x192 x80 + * 0 1 0 20 x 1 x160 x160 x80 + * 0 1 1 20 x 1 x160 x160 x66 + * 1 0 0 27 / 2 x236 x236 x118 + * 1 0 1 27 / 2 x236 x236 x98 + * 1 1 0 33.33 / 2 x192 x192 x96 + * 1 1 1 33.33 / 2 x192 x192 x80 + */ +#define CPG_PLL_CONFIG_INDEX(md) ((((md) & BIT(14)) >> 12) | \ + (((md) & BIT(13)) >> 12) | \ + (((md) & BIT(19)) >> 19)) + +static const struct rcar_gen3_cpg_pll_config cpg_pll_configs[8] __initconst = { + /* EXTAL div PLL1 mult/div PLL3 mult/div */ + { 1, 192, 1, 96, 1, }, + { 1, 192, 1, 80, 1, }, + { 1, 160, 1, 80, 1, }, + { 1, 160, 1, 66, 1, }, + { 2, 236, 1, 118, 1, }, + { 2, 236, 1, 98, 1, }, + { 2, 192, 1, 96, 1, }, + { 2, 192, 1, 80, 1, }, +}; + +static int __init r8a77970_cpg_mssr_init(struct device *dev) +{ + const struct rcar_gen3_cpg_pll_config *cpg_pll_config; + u32 cpg_mode; + int error; + + error = rcar_rst_read_mode_pins(&cpg_mode); + if (error) + return error; + + cpg_pll_config = &cpg_pll_configs[CPG_PLL_CONFIG_INDEX(cpg_mode)]; + + return rcar_gen3_cpg_init(cpg_pll_config, CLK_EXTALR, cpg_mode); +} + +const struct cpg_mssr_info r8a77970_cpg_mssr_info __initconst = { + /* Core Clocks */ + .core_clks = r8a77970_core_clks, + .num_core_clks = ARRAY_SIZE(r8a77970_core_clks), + .last_dt_core_clk = LAST_DT_CORE_CLK, + .num_total_core_clks = MOD_CLK_BASE, + + /* Module Clocks */ + .mod_clks = r8a77970_mod_clks, + .num_mod_clks = ARRAY_SIZE(r8a77970_mod_clks), + .num_hw_mod_clks = 12 * 32, + + /* Critical Module Clocks */ + .crit_mod_clks = r8a77970_crit_mod_clks, + .num_crit_mod_clks = ARRAY_SIZE(r8a77970_crit_mod_clks), + + /* Callbacks */ + .init = r8a77970_cpg_mssr_init, + .cpg_clk_register = rcar_gen3_cpg_clk_register, +}; diff --git a/drivers/clk/renesas/r8a77995-cpg-mssr.c b/drivers/clk/renesas/r8a77995-cpg-mssr.c index e594cf8ee63b..ea4cafbe6e85 100644 --- a/drivers/clk/renesas/r8a77995-cpg-mssr.c +++ b/drivers/clk/renesas/r8a77995-cpg-mssr.c @@ -127,7 +127,7 @@ static const struct mssr_mod_clk r8a77995_mod_clks[] __initconst = { DEF_MOD("usb-dmac1", 331, R8A77995_CLK_S3D1), DEF_MOD("rwdt", 402, R8A77995_CLK_R), DEF_MOD("intc-ex", 407, R8A77995_CLK_CP), - DEF_MOD("intc-ap", 408, R8A77995_CLK_S3D1), + DEF_MOD("intc-ap", 408, R8A77995_CLK_S1D2), DEF_MOD("audmac0", 502, R8A77995_CLK_S3D1), DEF_MOD("hscif3", 517, R8A77995_CLK_S3D1C), DEF_MOD("hscif0", 520, R8A77995_CLK_S3D1C), diff --git a/drivers/clk/renesas/rcar-gen2-cpg.c b/drivers/clk/renesas/rcar-gen2-cpg.c index 123b1e622179..feb14579a71b 100644 --- a/drivers/clk/renesas/rcar-gen2-cpg.c +++ b/drivers/clk/renesas/rcar-gen2-cpg.c @@ -262,10 +262,9 @@ static unsigned int cpg_pll0_div __initdata; static u32 cpg_mode __initdata; struct clk * __init rcar_gen2_cpg_clk_register(struct device *dev, - const struct cpg_core_clk *core, - const struct cpg_mssr_info *info, - struct clk **clks, - void __iomem *base) + const struct cpg_core_clk *core, const struct cpg_mssr_info *info, + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers) { const struct clk_div_table *table = NULL; const struct clk *parent; diff --git a/drivers/clk/renesas/rcar-gen2-cpg.h b/drivers/clk/renesas/rcar-gen2-cpg.h index 9eba07ff8b11..020a3baad015 100644 --- a/drivers/clk/renesas/rcar-gen2-cpg.h +++ b/drivers/clk/renesas/rcar-gen2-cpg.h @@ -34,9 +34,9 @@ struct rcar_gen2_cpg_pll_config { }; struct clk *rcar_gen2_cpg_clk_register(struct device *dev, - const struct cpg_core_clk *core, - const struct cpg_mssr_info *info, - struct clk **clks, void __iomem *base); + const struct cpg_core_clk *core, const struct cpg_mssr_info *info, + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers); int rcar_gen2_cpg_init(const struct rcar_gen2_cpg_pll_config *config, unsigned int pll0_div, u32 mode); diff --git a/drivers/clk/renesas/rcar-gen3-cpg.c b/drivers/clk/renesas/rcar-gen3-cpg.c index 951105816547..0904886f5501 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.c +++ b/drivers/clk/renesas/rcar-gen3-cpg.c @@ -19,6 +19,7 @@ #include <linux/err.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/pm.h> #include <linux/slab.h> #include <linux/sys_soc.h> @@ -29,6 +30,36 @@ #define CPG_PLL2CR 0x002c #define CPG_PLL4CR 0x01f4 +struct cpg_simple_notifier { + struct notifier_block nb; + void __iomem *reg; + u32 saved; +}; + +static int cpg_simple_notifier_call(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct cpg_simple_notifier *csn = + container_of(nb, struct cpg_simple_notifier, nb); + + switch (action) { + case PM_EVENT_SUSPEND: + csn->saved = readl(csn->reg); + return NOTIFY_OK; + + case PM_EVENT_RESUME: + writel(csn->saved, csn->reg); + return NOTIFY_OK; + } + return NOTIFY_DONE; +} + +static void cpg_simple_notifier_register(struct raw_notifier_head *notifiers, + struct cpg_simple_notifier *csn) +{ + csn->nb.notifier_call = cpg_simple_notifier_call; + raw_notifier_chain_register(notifiers, &csn->nb); +} /* * SDn Clock @@ -55,8 +86,8 @@ struct sd_div_table { struct sd_clock { struct clk_hw hw; - void __iomem *reg; const struct sd_div_table *div_table; + struct cpg_simple_notifier csn; unsigned int div_num; unsigned int div_min; unsigned int div_max; @@ -97,12 +128,12 @@ static const struct sd_div_table cpg_sd_div_table[] = { static int cpg_sd_clock_enable(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - u32 val = readl(clock->reg); + u32 val = readl(clock->csn.reg); val &= ~(CPG_SD_STP_MASK); val |= clock->div_table[clock->cur_div_idx].val & CPG_SD_STP_MASK; - writel(val, clock->reg); + writel(val, clock->csn.reg); return 0; } @@ -111,14 +142,14 @@ static void cpg_sd_clock_disable(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - writel(readl(clock->reg) | CPG_SD_STP_MASK, clock->reg); + writel(readl(clock->csn.reg) | CPG_SD_STP_MASK, clock->csn.reg); } static int cpg_sd_clock_is_enabled(struct clk_hw *hw) { struct sd_clock *clock = to_sd_clock(hw); - return !(readl(clock->reg) & CPG_SD_STP_MASK); + return !(readl(clock->csn.reg) & CPG_SD_STP_MASK); } static unsigned long cpg_sd_clock_recalc_rate(struct clk_hw *hw, @@ -170,10 +201,10 @@ static int cpg_sd_clock_set_rate(struct clk_hw *hw, unsigned long rate, clock->cur_div_idx = i; - val = readl(clock->reg); + val = readl(clock->csn.reg); val &= ~(CPG_SD_STP_MASK | CPG_SD_FC_MASK); val |= clock->div_table[i].val & (CPG_SD_STP_MASK | CPG_SD_FC_MASK); - writel(val, clock->reg); + writel(val, clock->csn.reg); return 0; } @@ -188,8 +219,8 @@ static const struct clk_ops cpg_sd_clock_ops = { }; static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, - void __iomem *base, - const char *parent_name) + void __iomem *base, const char *parent_name, + struct raw_notifier_head *notifiers) { struct clk_init_data init; struct sd_clock *clock; @@ -207,12 +238,12 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, init.parent_names = &parent_name; init.num_parents = 1; - clock->reg = base + core->offset; + clock->csn.reg = base + core->offset; clock->hw.init = &init; clock->div_table = cpg_sd_div_table; clock->div_num = ARRAY_SIZE(cpg_sd_div_table); - sd_fc = readl(clock->reg) & CPG_SD_FC_MASK; + sd_fc = readl(clock->csn.reg) & CPG_SD_FC_MASK; for (i = 0; i < clock->div_num; i++) if (sd_fc == (clock->div_table[i].val & CPG_SD_FC_MASK)) break; @@ -233,8 +264,13 @@ static struct clk * __init cpg_sd_clk_register(const struct cpg_core_clk *core, clk = clk_register(NULL, &clock->hw); if (IS_ERR(clk)) - kfree(clock); + goto free_clock; + cpg_simple_notifier_register(notifiers, &clock->csn); + return clk; + +free_clock: + kfree(clock); return clk; } @@ -265,7 +301,8 @@ static const struct soc_device_attribute cpg_quirks_match[] __initconst = { struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, - struct clk **clks, void __iomem *base) + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers) { const struct clk *parent; unsigned int mult = 1; @@ -331,22 +368,32 @@ struct clk * __init rcar_gen3_cpg_clk_register(struct device *dev, break; case CLK_TYPE_GEN3_SD: - return cpg_sd_clk_register(core, base, __clk_get_name(parent)); + return cpg_sd_clk_register(core, base, __clk_get_name(parent), + notifiers); case CLK_TYPE_GEN3_R: if (cpg_quirks & RCKCR_CKSEL) { + struct cpg_simple_notifier *csn; + + csn = kzalloc(sizeof(*csn), GFP_KERNEL); + if (!csn) + return ERR_PTR(-ENOMEM); + + csn->reg = base + CPG_RCKCR; + /* * RINT is default. * Only if EXTALR is populated, we switch to it. */ - value = readl(base + CPG_RCKCR) & 0x3f; + value = readl(csn->reg) & 0x3f; if (clk_get_rate(clks[cpg_clk_extalr])) { parent = clks[cpg_clk_extalr]; value |= BIT(15); } - writel(value, base + CPG_RCKCR); + writel(value, csn->reg); + cpg_simple_notifier_register(notifiers, csn); break; } diff --git a/drivers/clk/renesas/rcar-gen3-cpg.h b/drivers/clk/renesas/rcar-gen3-cpg.h index d756ef8b78eb..2e4284399f53 100644 --- a/drivers/clk/renesas/rcar-gen3-cpg.h +++ b/drivers/clk/renesas/rcar-gen3-cpg.h @@ -44,7 +44,8 @@ struct rcar_gen3_cpg_pll_config { struct clk *rcar_gen3_cpg_clk_register(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, - struct clk **clks, void __iomem *base); + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers); int rcar_gen3_cpg_init(const struct rcar_gen3_cpg_pll_config *config, unsigned int clk_extalr, u32 mode); diff --git a/drivers/clk/renesas/renesas-cpg-mssr.c b/drivers/clk/renesas/renesas-cpg-mssr.c index e580a5e6346c..e3d03ffea4bc 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.c +++ b/drivers/clk/renesas/renesas-cpg-mssr.c @@ -26,6 +26,7 @@ #include <linux/platform_device.h> #include <linux/pm_clock.h> #include <linux/pm_domain.h> +#include <linux/psci.h> #include <linux/reset-controller.h> #include <linux/slab.h> @@ -106,6 +107,9 @@ static const u16 srcr[] = { * @num_core_clks: Number of Core Clocks in clks[] * @num_mod_clks: Number of Module Clocks in clks[] * @last_dt_core_clk: ID of the last Core Clock exported to DT + * @notifiers: Notifier chain to save/restore clock state for system resume + * @smstpcr_saved[].mask: Mask of SMSTPCR[] bits under our control + * @smstpcr_saved[].val: Saved values of SMSTPCR[] */ struct cpg_mssr_priv { #ifdef CONFIG_RESET_CONTROLLER @@ -119,6 +123,12 @@ struct cpg_mssr_priv { unsigned int num_core_clks; unsigned int num_mod_clks; unsigned int last_dt_core_clk; + + struct raw_notifier_head notifiers; + struct { + u32 mask; + u32 val; + } smstpcr_saved[ARRAY_SIZE(smstpcr)]; }; @@ -293,7 +303,8 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, if (core->type == CLK_TYPE_DIV6P1) { clk = cpg_div6_register(core->name, 1, &parent_name, - priv->base + core->offset); + priv->base + core->offset, + &priv->notifiers); } else { clk = clk_register_fixed_factor(NULL, core->name, parent_name, 0, @@ -304,7 +315,8 @@ static void __init cpg_mssr_register_core_clk(const struct cpg_core_clk *core, default: if (info->cpg_clk_register) clk = info->cpg_clk_register(dev, core, info, - priv->clks, priv->base); + priv->clks, priv->base, + &priv->notifiers); else dev_err(dev, "%s has unsupported core clock type %u\n", core->name, core->type); @@ -382,6 +394,7 @@ static void __init cpg_mssr_register_mod_clk(const struct mssr_mod_clk *mod, dev_dbg(dev, "Module clock %pC at %pCr Hz\n", clk, clk); priv->clks[id] = clk; + priv->smstpcr_saved[clock->index / 32].mask |= BIT(clock->index % 32); return; fail: @@ -680,6 +693,12 @@ static const struct of_device_id cpg_mssr_match[] = { .data = &r8a7796_cpg_mssr_info, }, #endif +#ifdef CONFIG_CLK_R8A77970 + { + .compatible = "renesas,r8a77970-cpg-mssr", + .data = &r8a77970_cpg_mssr_info, + }, +#endif #ifdef CONFIG_CLK_R8A77995 { .compatible = "renesas,r8a77995-cpg-mssr", @@ -694,6 +713,85 @@ static void cpg_mssr_del_clk_provider(void *data) of_clk_del_provider(data); } +#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM_PSCI_FW) +static int cpg_mssr_suspend_noirq(struct device *dev) +{ + struct cpg_mssr_priv *priv = dev_get_drvdata(dev); + unsigned int reg; + + /* This is the best we can do to check for the presence of PSCI */ + if (!psci_ops.cpu_suspend) + return 0; + + /* Save module registers with bits under our control */ + for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { + if (priv->smstpcr_saved[reg].mask) + priv->smstpcr_saved[reg].val = + readl(priv->base + SMSTPCR(reg)); + } + + /* Save core clocks */ + raw_notifier_call_chain(&priv->notifiers, PM_EVENT_SUSPEND, NULL); + + return 0; +} + +static int cpg_mssr_resume_noirq(struct device *dev) +{ + struct cpg_mssr_priv *priv = dev_get_drvdata(dev); + unsigned int reg, i; + u32 mask, oldval, newval; + + /* This is the best we can do to check for the presence of PSCI */ + if (!psci_ops.cpu_suspend) + return 0; + + /* Restore core clocks */ + raw_notifier_call_chain(&priv->notifiers, PM_EVENT_RESUME, NULL); + + /* Restore module clocks */ + for (reg = 0; reg < ARRAY_SIZE(priv->smstpcr_saved); reg++) { + mask = priv->smstpcr_saved[reg].mask; + if (!mask) + continue; + + oldval = readl(priv->base + SMSTPCR(reg)); + newval = oldval & ~mask; + newval |= priv->smstpcr_saved[reg].val & mask; + if (newval == oldval) + continue; + + writel(newval, priv->base + SMSTPCR(reg)); + + /* Wait until enabled clocks are really enabled */ + mask &= ~priv->smstpcr_saved[reg].val; + if (!mask) + continue; + + for (i = 1000; i > 0; --i) { + oldval = readl(priv->base + MSTPSR(reg)); + if (!(oldval & mask)) + break; + cpu_relax(); + } + + if (!i) + dev_warn(dev, "Failed to enable SMSTP %p[0x%x]\n", + priv->base + SMSTPCR(reg), oldval & mask); + } + + return 0; +} + +static const struct dev_pm_ops cpg_mssr_pm = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cpg_mssr_suspend_noirq, + cpg_mssr_resume_noirq) +}; +#define DEV_PM_OPS &cpg_mssr_pm +#else +#define DEV_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP && CONFIG_ARM_PSCI_FW */ + static int __init cpg_mssr_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -729,10 +827,12 @@ static int __init cpg_mssr_probe(struct platform_device *pdev) if (!clks) return -ENOMEM; + dev_set_drvdata(dev, priv); priv->clks = clks; priv->num_core_clks = info->num_total_core_clks; priv->num_mod_clks = info->num_hw_mod_clks; priv->last_dt_core_clk = info->last_dt_core_clk; + RAW_INIT_NOTIFIER_HEAD(&priv->notifiers); for (i = 0; i < nclks; i++) clks[i] = ERR_PTR(-ENOENT); @@ -769,6 +869,7 @@ static struct platform_driver cpg_mssr_driver = { .driver = { .name = "renesas-cpg-mssr", .of_match_table = cpg_mssr_match, + .pm = DEV_PM_OPS, }, }; diff --git a/drivers/clk/renesas/renesas-cpg-mssr.h b/drivers/clk/renesas/renesas-cpg-mssr.h index 94b9071d1061..0745b0930308 100644 --- a/drivers/clk/renesas/renesas-cpg-mssr.h +++ b/drivers/clk/renesas/renesas-cpg-mssr.h @@ -127,7 +127,8 @@ struct cpg_mssr_info { struct clk *(*cpg_clk_register)(struct device *dev, const struct cpg_core_clk *core, const struct cpg_mssr_info *info, - struct clk **clks, void __iomem *base); + struct clk **clks, void __iomem *base, + struct raw_notifier_head *notifiers); }; extern const struct cpg_mssr_info r8a7743_cpg_mssr_info; @@ -138,6 +139,7 @@ extern const struct cpg_mssr_info r8a7792_cpg_mssr_info; extern const struct cpg_mssr_info r8a7794_cpg_mssr_info; extern const struct cpg_mssr_info r8a7795_cpg_mssr_info; extern const struct cpg_mssr_info r8a7796_cpg_mssr_info; +extern const struct cpg_mssr_info r8a77970_cpg_mssr_info; extern const struct cpg_mssr_info r8a77995_cpg_mssr_info; diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c index 0e09684d43a5..32c19c0f1e14 100644 --- a/drivers/clk/rockchip/clk-cpu.c +++ b/drivers/clk/rockchip/clk-cpu.c @@ -322,8 +322,6 @@ struct clk *rockchip_clk_register_cpuclk(const char *name, sizeof(*rates) * nrates, GFP_KERNEL); if (!cpuclk->rate_table) { - pr_err("%s: could not allocate memory for cpuclk rates\n", - __func__); ret = -ENOMEM; goto unregister_notifier; } diff --git a/drivers/clk/rockchip/clk-rk3188.c b/drivers/clk/rockchip/clk-rk3188.c index 00ad0e5f8d66..67e73fd71f09 100644 --- a/drivers/clk/rockchip/clk-rk3188.c +++ b/drivers/clk/rockchip/clk-rk3188.c @@ -290,15 +290,15 @@ static struct rockchip_clk_branch common_clk_branches[] __initdata = { RK2928_CLKSEL_CON(0), 6, 2, DFLAGS | CLK_DIVIDER_READ_ONLY, div_core_peri_t, RK2928_CLKGATE_CON(0), 0, GFLAGS), - COMPOSITE(0, "aclk_vepu", mux_pll_src_cpll_gpll_p, 0, + COMPOSITE(ACLK_VEPU, "aclk_vepu", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(32), 7, 1, MFLAGS, 0, 5, DFLAGS, RK2928_CLKGATE_CON(3), 9, GFLAGS), - GATE(0, "hclk_vepu", "aclk_vepu", 0, + GATE(HCLK_VEPU, "hclk_vepu", "aclk_vepu", 0, RK2928_CLKGATE_CON(3), 10, GFLAGS), - COMPOSITE(0, "aclk_vdpu", mux_pll_src_cpll_gpll_p, 0, + COMPOSITE(ACLK_VDPU, "aclk_vdpu", mux_pll_src_cpll_gpll_p, 0, RK2928_CLKSEL_CON(32), 15, 1, MFLAGS, 8, 5, DFLAGS, RK2928_CLKGATE_CON(3), 11, GFLAGS), - GATE(0, "hclk_vdpu", "aclk_vdpu", 0, + GATE(HCLK_VDPU, "hclk_vdpu", "aclk_vdpu", 0, RK2928_CLKGATE_CON(3), 12, GFLAGS), GATE(0, "gpll_ddr", "gpll", CLK_IGNORE_UNUSED, @@ -644,13 +644,13 @@ static struct rockchip_clk_branch rk3066a_clk_branches[] __initdata = { GATE(HCLK_I2S1, "hclk_i2s1", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 3, GFLAGS), GATE(HCLK_I2S2, "hclk_i2s2", "hclk_cpu", 0, RK2928_CLKGATE_CON(7), 4, GFLAGS), - GATE(0, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS), + GATE(HCLK_CIF1, "hclk_cif1", "hclk_cpu", 0, RK2928_CLKGATE_CON(6), 6, GFLAGS), GATE(0, "hclk_hdmi", "hclk_cpu", 0, RK2928_CLKGATE_CON(4), 14, GFLAGS), GATE(HCLK_OTG1, "hclk_usbotg1", "hclk_peri", CLK_IGNORE_UNUSED, RK2928_CLKGATE_CON(5), 14, GFLAGS), - GATE(0, "aclk_cif1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 7, GFLAGS), + GATE(ACLK_CIF1, "aclk_cif1", "aclk_vio1", 0, RK2928_CLKGATE_CON(6), 7, GFLAGS), GATE(PCLK_TIMER1, "pclk_timer1", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 8, GFLAGS), GATE(PCLK_TIMER2, "pclk_timer2", "pclk_cpu", 0, RK2928_CLKGATE_CON(7), 9, GFLAGS), diff --git a/drivers/clk/rockchip/clk-rk3368.c b/drivers/clk/rockchip/clk-rk3368.c index fc56565379dd..7c4d242f19c1 100644 --- a/drivers/clk/rockchip/clk-rk3368.c +++ b/drivers/clk/rockchip/clk-rk3368.c @@ -711,7 +711,7 @@ static struct rockchip_clk_branch rk3368_clk_branches[] __initdata = { GATE(PCLK_SIM, "pclk_sim", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 8, GFLAGS), GATE(PCLK_PWM1, "pclk_pwm1", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 6, GFLAGS), GATE(PCLK_UART2, "pclk_uart2", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 5, GFLAGS), - GATE(0, "pclk_efuse_256", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 1, GFLAGS), + GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 1, GFLAGS), GATE(0, "pclk_efuse_1024", "pclk_bus", 0, RK3368_CLKGATE_CON(13), 0, GFLAGS), /* diff --git a/drivers/clk/samsung/Makefile b/drivers/clk/samsung/Makefile index 23835001e8bd..ef8900bc077f 100644 --- a/drivers/clk/samsung/Makefile +++ b/drivers/clk/samsung/Makefile @@ -6,6 +6,7 @@ obj-$(CONFIG_COMMON_CLK) += clk.o clk-pll.o clk-cpu.o obj-$(CONFIG_SOC_EXYNOS3250) += clk-exynos3250.o obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4.o +obj-$(CONFIG_ARCH_EXYNOS4) += clk-exynos4412-isp.o obj-$(CONFIG_SOC_EXYNOS5250) += clk-exynos5250.o obj-$(CONFIG_SOC_EXYNOS5260) += clk-exynos5260.o obj-$(CONFIG_SOC_EXYNOS5410) += clk-exynos5410.o diff --git a/drivers/clk/samsung/clk-cpu.c b/drivers/clk/samsung/clk-cpu.c index 6686e8ba61f9..d2c99d8916b8 100644 --- a/drivers/clk/samsung/clk-cpu.c +++ b/drivers/clk/samsung/clk-cpu.c @@ -457,8 +457,6 @@ int __init exynos_register_cpu_clock(struct samsung_clk_provider *ctx, cpuclk->cfg = kmemdup(cfg, sizeof(*cfg) * num_cfgs, GFP_KERNEL); if (!cpuclk->cfg) { - pr_err("%s: could not allocate memory for cpuclk data\n", - __func__); ret = -ENOMEM; goto unregister_clk_nb; } diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c index b117783ed404..5bfc92ee3129 100644 --- a/drivers/clk/samsung/clk-exynos-audss.c +++ b/drivers/clk/samsung/clk-exynos-audss.c @@ -18,6 +18,7 @@ #include <linux/syscore_ops.h> #include <linux/module.h> #include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <dt-bindings/clock/exynos-audss-clk.h> @@ -36,14 +37,13 @@ static struct clk *epll; #define ASS_CLK_DIV 0x4 #define ASS_CLK_GATE 0x8 -#ifdef CONFIG_PM_SLEEP static unsigned long reg_save[][2] = { { ASS_CLK_SRC, 0 }, { ASS_CLK_DIV, 0 }, { ASS_CLK_GATE, 0 }, }; -static int exynos_audss_clk_suspend(struct device *dev) +static int __maybe_unused exynos_audss_clk_suspend(struct device *dev) { int i; @@ -53,7 +53,7 @@ static int exynos_audss_clk_suspend(struct device *dev) return 0; } -static int exynos_audss_clk_resume(struct device *dev) +static int __maybe_unused exynos_audss_clk_resume(struct device *dev) { int i; @@ -62,7 +62,6 @@ static int exynos_audss_clk_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ struct exynos_audss_clk_drvdata { unsigned int has_adma_clk:1; @@ -135,6 +134,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) const struct exynos_audss_clk_drvdata *variant; struct clk_hw **clk_table; struct resource *res; + struct device *dev = &pdev->dev; int i, ret = 0; variant = of_device_get_match_data(&pdev->dev); @@ -142,15 +142,15 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) return -EINVAL; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - reg_base = devm_ioremap_resource(&pdev->dev, res); + reg_base = devm_ioremap_resource(dev, res); if (IS_ERR(reg_base)) { - dev_err(&pdev->dev, "failed to map audss registers\n"); + dev_err(dev, "failed to map audss registers\n"); return PTR_ERR(reg_base); } epll = ERR_PTR(-ENODEV); - clk_data = devm_kzalloc(&pdev->dev, + clk_data = devm_kzalloc(dev, sizeof(*clk_data) + sizeof(*clk_data->hws) * EXYNOS_AUDSS_MAX_CLKS, GFP_KERNEL); @@ -160,8 +160,8 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) clk_data->num = variant->num_clks; clk_table = clk_data->hws; - pll_ref = devm_clk_get(&pdev->dev, "pll_ref"); - pll_in = devm_clk_get(&pdev->dev, "pll_in"); + pll_ref = devm_clk_get(dev, "pll_ref"); + pll_in = devm_clk_get(dev, "pll_in"); if (!IS_ERR(pll_ref)) mout_audss_p[0] = __clk_get_name(pll_ref); if (!IS_ERR(pll_in)) { @@ -172,88 +172,103 @@ static int exynos_audss_clk_probe(struct platform_device *pdev) ret = clk_prepare_enable(epll); if (ret) { - dev_err(&pdev->dev, + dev_err(dev, "failed to prepare the epll clock\n"); return ret; } } } - clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(NULL, "mout_audss", + + /* + * Enable runtime PM here to allow the clock core using runtime PM + * for the registered clocks. Additionally, we increase the runtime + * PM usage count before registering the clocks, to prevent the + * clock core from runtime suspending the device. + */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + clk_table[EXYNOS_MOUT_AUDSS] = clk_hw_register_mux(dev, "mout_audss", mout_audss_p, ARRAY_SIZE(mout_audss_p), CLK_SET_RATE_NO_REPARENT | CLK_SET_RATE_PARENT, reg_base + ASS_CLK_SRC, 0, 1, 0, &lock); - cdclk = devm_clk_get(&pdev->dev, "cdclk"); - sclk_audio = devm_clk_get(&pdev->dev, "sclk_audio"); + cdclk = devm_clk_get(dev, "cdclk"); + sclk_audio = devm_clk_get(dev, "sclk_audio"); if (!IS_ERR(cdclk)) mout_i2s_p[1] = __clk_get_name(cdclk); if (!IS_ERR(sclk_audio)) mout_i2s_p[2] = __clk_get_name(sclk_audio); - clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(NULL, "mout_i2s", + clk_table[EXYNOS_MOUT_I2S] = clk_hw_register_mux(dev, "mout_i2s", mout_i2s_p, ARRAY_SIZE(mout_i2s_p), CLK_SET_RATE_NO_REPARENT, reg_base + ASS_CLK_SRC, 2, 2, 0, &lock); - clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(NULL, "dout_srp", + clk_table[EXYNOS_DOUT_SRP] = clk_hw_register_divider(dev, "dout_srp", "mout_audss", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_DIV, 0, 4, 0, &lock); - clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(NULL, + clk_table[EXYNOS_DOUT_AUD_BUS] = clk_hw_register_divider(dev, "dout_aud_bus", "dout_srp", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_DIV, 4, 4, 0, &lock); - clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(NULL, "dout_i2s", + clk_table[EXYNOS_DOUT_I2S] = clk_hw_register_divider(dev, "dout_i2s", "mout_i2s", 0, reg_base + ASS_CLK_DIV, 8, 4, 0, &lock); - clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(NULL, "srp_clk", + clk_table[EXYNOS_SRP_CLK] = clk_hw_register_gate(dev, "srp_clk", "dout_srp", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 0, 0, &lock); - clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(NULL, "i2s_bus", + clk_table[EXYNOS_I2S_BUS] = clk_hw_register_gate(dev, "i2s_bus", "dout_aud_bus", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 2, 0, &lock); - clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(NULL, "sclk_i2s", + clk_table[EXYNOS_SCLK_I2S] = clk_hw_register_gate(dev, "sclk_i2s", "dout_i2s", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 3, 0, &lock); - clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(NULL, "pcm_bus", + clk_table[EXYNOS_PCM_BUS] = clk_hw_register_gate(dev, "pcm_bus", "sclk_pcm", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 4, 0, &lock); - sclk_pcm_in = devm_clk_get(&pdev->dev, "sclk_pcm_in"); + sclk_pcm_in = devm_clk_get(dev, "sclk_pcm_in"); if (!IS_ERR(sclk_pcm_in)) sclk_pcm_p = __clk_get_name(sclk_pcm_in); - clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(NULL, "sclk_pcm", + clk_table[EXYNOS_SCLK_PCM] = clk_hw_register_gate(dev, "sclk_pcm", sclk_pcm_p, CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 5, 0, &lock); if (variant->has_adma_clk) { - clk_table[EXYNOS_ADMA] = clk_hw_register_gate(NULL, "adma", + clk_table[EXYNOS_ADMA] = clk_hw_register_gate(dev, "adma", "dout_srp", CLK_SET_RATE_PARENT, reg_base + ASS_CLK_GATE, 9, 0, &lock); } for (i = 0; i < clk_data->num; i++) { if (IS_ERR(clk_table[i])) { - dev_err(&pdev->dev, "failed to register clock %d\n", i); + dev_err(dev, "failed to register clock %d\n", i); ret = PTR_ERR(clk_table[i]); goto unregister; } } - ret = of_clk_add_hw_provider(pdev->dev.of_node, of_clk_hw_onecell_get, + ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, clk_data); if (ret) { - dev_err(&pdev->dev, "failed to add clock provider\n"); + dev_err(dev, "failed to add clock provider\n"); goto unregister; } + pm_runtime_put_sync(dev); + return 0; unregister: exynos_audss_clk_teardown(); + pm_runtime_put_sync(dev); + pm_runtime_disable(dev); if (!IS_ERR(epll)) clk_disable_unprepare(epll); @@ -266,6 +281,7 @@ static int exynos_audss_clk_remove(struct platform_device *pdev) of_clk_del_provider(pdev->dev.of_node); exynos_audss_clk_teardown(); + pm_runtime_disable(&pdev->dev); if (!IS_ERR(epll)) clk_disable_unprepare(epll); @@ -274,8 +290,10 @@ static int exynos_audss_clk_remove(struct platform_device *pdev) } static const struct dev_pm_ops exynos_audss_clk_pm_ops = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(exynos_audss_clk_suspend, - exynos_audss_clk_resume) + SET_RUNTIME_PM_OPS(exynos_audss_clk_suspend, exynos_audss_clk_resume, + NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; static struct platform_driver exynos_audss_clk_driver = { diff --git a/drivers/clk/samsung/clk-exynos-clkout.c b/drivers/clk/samsung/clk-exynos-clkout.c index a21aea062bae..f29fb5824005 100644 --- a/drivers/clk/samsung/clk-exynos-clkout.c +++ b/drivers/clk/samsung/clk-exynos-clkout.c @@ -144,8 +144,6 @@ static void __init exynos4_clkout_init(struct device_node *node) } CLK_OF_DECLARE_DRIVER(exynos4210_clkout, "samsung,exynos4210-pmu", exynos4_clkout_init); -CLK_OF_DECLARE_DRIVER(exynos4212_clkout, "samsung,exynos4212-pmu", - exynos4_clkout_init); CLK_OF_DECLARE_DRIVER(exynos4412_clkout, "samsung,exynos4412-pmu", exynos4_clkout_init); CLK_OF_DECLARE_DRIVER(exynos3250_clkout, "samsung,exynos3250-pmu", diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c index d8d3cb67b402..134f25f2a913 100644 --- a/drivers/clk/samsung/clk-exynos4.c +++ b/drivers/clk/samsung/clk-exynos4.c @@ -550,9 +550,8 @@ static const struct samsung_fixed_factor_clock exynos4x12_fixed_factor_clks[] __ /* list of mux clocks supported in all exynos4 soc's */ static const struct samsung_mux_clock exynos4_mux_clks[] __initconst = { - MUX_FA(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, - CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0, - "mout_apll"), + MUX_F(CLK_MOUT_APLL, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + CLK_SET_RATE_PARENT | CLK_RECALC_NEW_RATES, 0), MUX(CLK_MOUT_HDMI, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1), MUX(0, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1), MUX(0, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1), @@ -737,7 +736,7 @@ static const struct samsung_div_clock exynos4_div_clks[] __initconst = { DIV(0, "div_periph", "div_core2", DIV_CPU0, 12, 3), DIV(0, "div_atb", "mout_core", DIV_CPU0, 16, 3), DIV(0, "div_pclk_dbg", "div_atb", DIV_CPU0, 20, 3), - DIV(CLK_ARM_CLK, "div_core2", "div_core", DIV_CPU0, 28, 3), + DIV(0, "div_core2", "div_core", DIV_CPU0, 28, 3), DIV(0, "div_copy", "mout_hpm", DIV_CPU1, 0, 3), DIV(0, "div_hpm", "div_copy", DIV_CPU1, 4, 3), DIV(0, "div_clkout_cpu", "mout_clkout_cpu", CLKOUT_CMU_CPU, 8, 6), @@ -837,6 +836,12 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = { DIV(0, "div_spi1_isp", "mout_spi1_isp", E4X12_DIV_ISP, 16, 4), DIV(0, "div_spi1_isp_pre", "div_spi1_isp", E4X12_DIV_ISP, 20, 8), DIV(0, "div_uart_isp", "mout_uart_isp", E4X12_DIV_ISP, 28, 4), + DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4), + DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3), + DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3), +}; + +static struct samsung_div_clock exynos4x12_isp_div_clks[] = { DIV_F(CLK_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3, CLK_GET_RATE_NOCACHE, 0), DIV_F(CLK_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3, @@ -846,18 +851,10 @@ static const struct samsung_div_clock exynos4x12_div_clks[] __initconst = { 4, 3, CLK_GET_RATE_NOCACHE, 0), DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1, 8, 3, CLK_GET_RATE_NOCACHE, 0), - DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4), - DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3), - DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3), }; /* list of gate clocks supported in all exynos4 soc's */ static const struct samsung_gate_clock exynos4_gate_clks[] __initconst = { - /* - * After all Exynos4 based platforms are migrated to use device tree, - * the device name and clock alias names specified below for some - * of the clocks can be removed. - */ GATE(CLK_PPMULEFT, "ppmuleft", "aclk200", GATE_IP_LEFTBUS, 1, 0, 0), GATE(CLK_PPMURIGHT, "ppmuright", "aclk200", GATE_IP_RIGHTBUS, 1, 0, 0), GATE(CLK_SCLK_HDMI, "sclk_hdmi", "mout_hdmi", SRC_MASK_TV, 0, 0, 0), @@ -1147,6 +1144,13 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = { 0, 0), GATE(CLK_I2S0, "i2s0", "aclk100", E4X12_GATE_IP_MAUDIO, 3, 0, 0), + GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), + GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0), + GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, + 0), +}; + +static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = { GATE(CLK_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(CLK_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, @@ -1199,24 +1203,6 @@ static const struct samsung_gate_clock exynos4x12_gate_clks[] __initconst = { CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), GATE(CLK_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, CLK_IGNORE_UNUSED | CLK_GET_RATE_NOCACHE, 0), - GATE(CLK_G2D, "g2d", "aclk200", GATE_IP_DMC, 23, 0, 0), - GATE(CLK_SMMU_G2D, "smmu_g2d", "aclk200", GATE_IP_DMC, 24, 0, 0), - GATE(CLK_TMU_APBIF, "tmu_apbif", "aclk100", E4X12_GATE_IP_PERIR, 17, 0, - 0), -}; - -static const struct samsung_clock_alias exynos4_aliases[] __initconst = { - ALIAS(CLK_MOUT_CORE, NULL, "moutcore"), - ALIAS(CLK_ARM_CLK, NULL, "armclk"), - ALIAS(CLK_SCLK_APLL, NULL, "mout_apll"), -}; - -static const struct samsung_clock_alias exynos4210_aliases[] __initconst = { - ALIAS(CLK_SCLK_MPLL, NULL, "mout_mpll"), -}; - -static const struct samsung_clock_alias exynos4x12_aliases[] __initconst = { - ALIAS(CLK_MOUT_MPLL_USER_C, NULL, "mout_mpll"), }; /* @@ -1355,14 +1341,14 @@ static const struct samsung_pll_rate_table exynos4x12_vpll_rates[] __initconst = }; static struct samsung_pll_clock exynos4210_plls[nr_plls] __initdata = { - [apll] = PLL_A(pll_4508, CLK_FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON0, "fout_apll", NULL), - [mpll] = PLL_A(pll_4508, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", - E4210_MPLL_LOCK, E4210_MPLL_CON0, "fout_mpll", NULL), - [epll] = PLL_A(pll_4600, CLK_FOUT_EPLL, "fout_epll", "fin_pll", - EPLL_LOCK, EPLL_CON0, "fout_epll", NULL), - [vpll] = PLL_A(pll_4650c, CLK_FOUT_VPLL, "fout_vpll", "mout_vpllsrc", - VPLL_LOCK, VPLL_CON0, "fout_vpll", NULL), + [apll] = PLL(pll_4508, CLK_FOUT_APLL, "fout_apll", "fin_pll", + APLL_LOCK, APLL_CON0, NULL), + [mpll] = PLL(pll_4508, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", + E4210_MPLL_LOCK, E4210_MPLL_CON0, NULL), + [epll] = PLL(pll_4600, CLK_FOUT_EPLL, "fout_epll", "fin_pll", + EPLL_LOCK, EPLL_CON0, NULL), + [vpll] = PLL(pll_4650c, CLK_FOUT_VPLL, "fout_vpll", "mout_vpllsrc", + VPLL_LOCK, VPLL_CON0, NULL), }; static struct samsung_pll_clock exynos4x12_plls[nr_plls] __initdata = { @@ -1416,24 +1402,6 @@ static const struct exynos_cpuclk_cfg_data e4210_armclk_d[] __initconst = { { 0 }, }; -static const struct exynos_cpuclk_cfg_data e4212_armclk_d[] __initconst = { - { 1500000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4210_CPU_DIV1(2, 6), }, - { 1400000, E4210_CPU_DIV0(2, 1, 6, 0, 7, 3), E4210_CPU_DIV1(2, 6), }, - { 1300000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4210_CPU_DIV1(2, 5), }, - { 1200000, E4210_CPU_DIV0(2, 1, 5, 0, 7, 3), E4210_CPU_DIV1(2, 5), }, - { 1100000, E4210_CPU_DIV0(2, 1, 4, 0, 6, 3), E4210_CPU_DIV1(2, 4), }, - { 1000000, E4210_CPU_DIV0(1, 1, 4, 0, 5, 2), E4210_CPU_DIV1(2, 4), }, - { 900000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4210_CPU_DIV1(2, 3), }, - { 800000, E4210_CPU_DIV0(1, 1, 3, 0, 5, 2), E4210_CPU_DIV1(2, 3), }, - { 700000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), }, - { 600000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), }, - { 500000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), }, - { 400000, E4210_CPU_DIV0(1, 1, 3, 0, 4, 2), E4210_CPU_DIV1(2, 3), }, - { 300000, E4210_CPU_DIV0(1, 1, 2, 0, 4, 2), E4210_CPU_DIV1(2, 3), }, - { 200000, E4210_CPU_DIV0(1, 1, 1, 0, 3, 1), E4210_CPU_DIV1(2, 3), }, - { 0 }, -}; - #define E4412_CPU_DIV1(cores, hpm, copy) \ (((cores) << 8) | ((hpm) << 4) | ((copy) << 0)) @@ -1527,8 +1495,6 @@ static void __init exynos4_clk_init(struct device_node *np, ARRAY_SIZE(exynos4210_div_clks)); samsung_clk_register_gate(ctx, exynos4210_gate_clks, ARRAY_SIZE(exynos4210_gate_clks)); - samsung_clk_register_alias(ctx, exynos4210_aliases, - ARRAY_SIZE(exynos4210_aliases)); samsung_clk_register_fixed_factor(ctx, exynos4210_fixed_factor_clks, ARRAY_SIZE(exynos4210_fixed_factor_clks)); @@ -1537,32 +1503,31 @@ static void __init exynos4_clk_init(struct device_node *np, e4210_armclk_d, ARRAY_SIZE(e4210_armclk_d), CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); } else { + struct resource res; + samsung_clk_register_mux(ctx, exynos4x12_mux_clks, ARRAY_SIZE(exynos4x12_mux_clks)); samsung_clk_register_div(ctx, exynos4x12_div_clks, ARRAY_SIZE(exynos4x12_div_clks)); samsung_clk_register_gate(ctx, exynos4x12_gate_clks, ARRAY_SIZE(exynos4x12_gate_clks)); - samsung_clk_register_alias(ctx, exynos4x12_aliases, - ARRAY_SIZE(exynos4x12_aliases)); samsung_clk_register_fixed_factor(ctx, exynos4x12_fixed_factor_clks, ARRAY_SIZE(exynos4x12_fixed_factor_clks)); - if (of_machine_is_compatible("samsung,exynos4412")) { - exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_core_p4x12[0], mout_core_p4x12[1], 0x14200, - e4412_armclk_d, ARRAY_SIZE(e4412_armclk_d), - CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); - } else { - exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", - mout_core_p4x12[0], mout_core_p4x12[1], 0x14200, - e4212_armclk_d, ARRAY_SIZE(e4212_armclk_d), - CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); + + of_address_to_resource(np, 0, &res); + if (resource_size(&res) > 0x18000) { + samsung_clk_register_div(ctx, exynos4x12_isp_div_clks, + ARRAY_SIZE(exynos4x12_isp_div_clks)); + samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks, + ARRAY_SIZE(exynos4x12_isp_gate_clks)); } - } - samsung_clk_register_alias(ctx, exynos4_aliases, - ARRAY_SIZE(exynos4_aliases)); + exynos_register_cpu_clock(ctx, CLK_ARM_CLK, "armclk", + mout_core_p4x12[0], mout_core_p4x12[1], 0x14200, + e4412_armclk_d, ARRAY_SIZE(e4412_armclk_d), + CLK_CPU_NEEDS_DEBUG_ALT_DIV | CLK_CPU_HAS_DIV1); + } if (soc == EXYNOS4X12) exynos4x12_core_down_clock(); diff --git a/drivers/clk/samsung/clk-exynos4412-isp.c b/drivers/clk/samsung/clk-exynos4412-isp.c new file mode 100644 index 000000000000..d5f1ccb36300 --- /dev/null +++ b/drivers/clk/samsung/clk-exynos4412-isp.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2017 Samsung Electronics Co., Ltd. + * Author: Marek Szyprowski <m.szyprowski@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Common Clock Framework support for Exynos4412 ISP module. +*/ + +#include <dt-bindings/clock/exynos4.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> + +#include "clk.h" + +/* Exynos4x12 specific registers, which belong to ISP power domain */ +#define E4X12_DIV_ISP0 0x0300 +#define E4X12_DIV_ISP1 0x0304 +#define E4X12_GATE_ISP0 0x0800 +#define E4X12_GATE_ISP1 0x0804 + +/* + * Support for CMU save/restore across system suspends + */ +static struct samsung_clk_reg_dump *exynos4x12_save_isp; + +static const unsigned long exynos4x12_clk_isp_save[] __initconst = { + E4X12_DIV_ISP0, + E4X12_DIV_ISP1, + E4X12_GATE_ISP0, + E4X12_GATE_ISP1, +}; + +PNAME(mout_user_aclk400_mcuisp_p4x12) = { "fin_pll", "div_aclk400_mcuisp", }; + +static struct samsung_div_clock exynos4x12_isp_div_clks[] = { + DIV(CLK_ISP_DIV_ISP0, "div_isp0", "aclk200", E4X12_DIV_ISP0, 0, 3), + DIV(CLK_ISP_DIV_ISP1, "div_isp1", "aclk200", E4X12_DIV_ISP0, 4, 3), + DIV(CLK_ISP_DIV_MCUISP0, "div_mcuisp0", "aclk400_mcuisp", + E4X12_DIV_ISP1, 4, 3), + DIV(CLK_ISP_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", + E4X12_DIV_ISP1, 8, 3), + DIV(0, "div_mpwm", "div_isp1", E4X12_DIV_ISP1, 0, 3), +}; + +static struct samsung_gate_clock exynos4x12_isp_gate_clks[] = { + GATE(CLK_ISP_FIMC_ISP, "isp", "aclk200", E4X12_GATE_ISP0, 0, 0, 0), + GATE(CLK_ISP_FIMC_DRC, "drc", "aclk200", E4X12_GATE_ISP0, 1, 0, 0), + GATE(CLK_ISP_FIMC_FD, "fd", "aclk200", E4X12_GATE_ISP0, 2, 0, 0), + GATE(CLK_ISP_FIMC_LITE0, "lite0", "aclk200", E4X12_GATE_ISP0, 3, 0, 0), + GATE(CLK_ISP_FIMC_LITE1, "lite1", "aclk200", E4X12_GATE_ISP0, 4, 0, 0), + GATE(CLK_ISP_MCUISP, "mcuisp", "aclk200", E4X12_GATE_ISP0, 5, 0, 0), + GATE(CLK_ISP_GICISP, "gicisp", "aclk200", E4X12_GATE_ISP0, 7, 0, 0), + GATE(CLK_ISP_SMMU_ISP, "smmu_isp", "aclk200", E4X12_GATE_ISP0, 8, 0, 0), + GATE(CLK_ISP_SMMU_DRC, "smmu_drc", "aclk200", E4X12_GATE_ISP0, 9, 0, 0), + GATE(CLK_ISP_SMMU_FD, "smmu_fd", "aclk200", E4X12_GATE_ISP0, 10, 0, 0), + GATE(CLK_ISP_SMMU_LITE0, "smmu_lite0", "aclk200", E4X12_GATE_ISP0, 11, + 0, 0), + GATE(CLK_ISP_SMMU_LITE1, "smmu_lite1", "aclk200", E4X12_GATE_ISP0, 12, + 0, 0), + GATE(CLK_ISP_PPMUISPMX, "ppmuispmx", "aclk200", E4X12_GATE_ISP0, 20, + 0, 0), + GATE(CLK_ISP_PPMUISPX, "ppmuispx", "aclk200", E4X12_GATE_ISP0, 21, + 0, 0), + GATE(CLK_ISP_MCUCTL_ISP, "mcuctl_isp", "aclk200", E4X12_GATE_ISP0, 23, + 0, 0), + GATE(CLK_ISP_MPWM_ISP, "mpwm_isp", "aclk200", E4X12_GATE_ISP0, 24, + 0, 0), + GATE(CLK_ISP_I2C0_ISP, "i2c0_isp", "aclk200", E4X12_GATE_ISP0, 25, + 0, 0), + GATE(CLK_ISP_I2C1_ISP, "i2c1_isp", "aclk200", E4X12_GATE_ISP0, 26, + 0, 0), + GATE(CLK_ISP_MTCADC_ISP, "mtcadc_isp", "aclk200", E4X12_GATE_ISP0, 27, + 0, 0), + GATE(CLK_ISP_PWM_ISP, "pwm_isp", "aclk200", E4X12_GATE_ISP0, 28, 0, 0), + GATE(CLK_ISP_WDT_ISP, "wdt_isp", "aclk200", E4X12_GATE_ISP0, 30, 0, 0), + GATE(CLK_ISP_UART_ISP, "uart_isp", "aclk200", E4X12_GATE_ISP0, 31, + 0, 0), + GATE(CLK_ISP_ASYNCAXIM, "asyncaxim", "aclk200", E4X12_GATE_ISP1, 0, + 0, 0), + GATE(CLK_ISP_SMMU_ISPCX, "smmu_ispcx", "aclk200", E4X12_GATE_ISP1, 4, + 0, 0), + GATE(CLK_ISP_SPI0_ISP, "spi0_isp", "aclk200", E4X12_GATE_ISP1, 12, + 0, 0), + GATE(CLK_ISP_SPI1_ISP, "spi1_isp", "aclk200", E4X12_GATE_ISP1, 13, + 0, 0), +}; + +static int __maybe_unused exynos4x12_isp_clk_suspend(struct device *dev) +{ + struct samsung_clk_provider *ctx = dev_get_drvdata(dev); + + samsung_clk_save(ctx->reg_base, exynos4x12_save_isp, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + return 0; +} + +static int __maybe_unused exynos4x12_isp_clk_resume(struct device *dev) +{ + struct samsung_clk_provider *ctx = dev_get_drvdata(dev); + + samsung_clk_restore(ctx->reg_base, exynos4x12_save_isp, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + return 0; +} + +static int __init exynos4x12_isp_clk_probe(struct platform_device *pdev) +{ + struct samsung_clk_provider *ctx; + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct resource *res; + void __iomem *reg_base; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(reg_base)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(reg_base); + } + + exynos4x12_save_isp = samsung_clk_alloc_reg_dump(exynos4x12_clk_isp_save, + ARRAY_SIZE(exynos4x12_clk_isp_save)); + if (!exynos4x12_save_isp) + return -ENOMEM; + + ctx = samsung_clk_init(np, reg_base, CLK_NR_ISP_CLKS); + ctx->dev = dev; + + platform_set_drvdata(pdev, ctx); + + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + pm_runtime_get_sync(dev); + + samsung_clk_register_div(ctx, exynos4x12_isp_div_clks, + ARRAY_SIZE(exynos4x12_isp_div_clks)); + samsung_clk_register_gate(ctx, exynos4x12_isp_gate_clks, + ARRAY_SIZE(exynos4x12_isp_gate_clks)); + + samsung_clk_of_add_provider(np, ctx); + pm_runtime_put(dev); + + return 0; +} + +static const struct of_device_id exynos4x12_isp_clk_of_match[] = { + { .compatible = "samsung,exynos4412-isp-clock", }, + { }, +}; + +static const struct dev_pm_ops exynos4x12_isp_pm_ops = { + SET_RUNTIME_PM_OPS(exynos4x12_isp_clk_suspend, + exynos4x12_isp_clk_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos4x12_isp_clk_driver __refdata = { + .driver = { + .name = "exynos4x12-isp-clk", + .of_match_table = exynos4x12_isp_clk_of_match, + .suppress_bind_attrs = true, + .pm = &exynos4x12_isp_pm_ops, + }, + .probe = exynos4x12_isp_clk_probe, +}; + +static int __init exynos4x12_isp_clk_init(void) +{ + return platform_driver_register(&exynos4x12_isp_clk_driver); +} +core_initcall(exynos4x12_isp_clk_init); diff --git a/drivers/clk/samsung/clk-exynos5250.c b/drivers/clk/samsung/clk-exynos5250.c index 27a227d6620c..9b073c98a891 100644 --- a/drivers/clk/samsung/clk-exynos5250.c +++ b/drivers/clk/samsung/clk-exynos5250.c @@ -293,14 +293,14 @@ static const struct samsung_mux_clock exynos5250_mux_clks[] __initconst = { /* * CMU_CPU */ - MUX_FA(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, - CLK_SET_RATE_PARENT, 0, "mout_apll"), - MUX_A(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1, "mout_cpu"), + MUX_F(0, "mout_apll", mout_apll_p, SRC_CPU, 0, 1, + CLK_SET_RATE_PARENT, 0), + MUX(0, "mout_cpu", mout_cpu_p, SRC_CPU, 16, 1), /* * CMU_CORE */ - MUX_A(0, "mout_mpll", mout_mpll_p, SRC_CORE1, 8, 1, "mout_mpll"), + MUX(0, "mout_mpll", mout_mpll_p, SRC_CORE1, 8, 1), /* * CMU_TOP @@ -391,7 +391,7 @@ static const struct samsung_div_clock exynos5250_div_clks[] __initconst = { */ DIV(0, "div_arm", "mout_cpu", DIV_CPU0, 0, 3), DIV(0, "div_apll", "mout_apll", DIV_CPU0, 24, 3), - DIV_A(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3, "armclk"), + DIV(0, "div_arm2", "div_arm", DIV_CPU0, 28, 3), /* * CMU_TOP @@ -743,10 +743,10 @@ static const struct samsung_pll_rate_table apll_24mhz_tbl[] __initconst = { }; static struct samsung_pll_clock exynos5250_plls[nr_plls] __initdata = { - [apll] = PLL_A(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", - APLL_LOCK, APLL_CON0, "fout_apll", NULL), - [mpll] = PLL_A(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", - MPLL_LOCK, MPLL_CON0, "fout_mpll", NULL), + [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll", APLL_LOCK, + APLL_CON0, NULL), + [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll", MPLL_LOCK, + MPLL_CON0, NULL), [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll", BPLL_LOCK, BPLL_CON0, NULL), [gpll] = PLL(pll_35xx, CLK_FOUT_GPLL, "fout_gpll", "fin_pll", GPLL_LOCK, diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c index 25601967d1cd..45d34f601e9e 100644 --- a/drivers/clk/samsung/clk-exynos5420.c +++ b/drivers/clk/samsung/clk-exynos5420.c @@ -600,8 +600,7 @@ static const struct samsung_mux_clock exynos5420_mux_clks[] __initconst = { TOP_SPARE2, 4, 1), MUX(0, "mout_aclk400_isp", mout_group1_p, SRC_TOP0, 0, 2), - MUX_A(0, "mout_aclk400_mscl", mout_group1_p, - SRC_TOP0, 4, 2, "aclk400_mscl"), + MUX(0, "mout_aclk400_mscl", mout_group1_p, SRC_TOP0, 4, 2), MUX(0, "mout_aclk400_wcore", mout_group1_p, SRC_TOP0, 16, 2), MUX(0, "mout_aclk100_noc", mout_group1_p, SRC_TOP0, 20, 2), @@ -998,7 +997,7 @@ static const struct samsung_gate_clock exynos5x_gate_clks[] __initconst = { GATE(0, "aclk400_isp", "mout_user_aclk400_isp", GATE_BUS_TOP, 16, 0, 0), GATE(0, "aclk400_mscl", "mout_user_aclk400_mscl", - GATE_BUS_TOP, 17, 0, 0), + GATE_BUS_TOP, 17, CLK_IS_CRITICAL, 0), GATE(0, "aclk200_disp1", "mout_user_aclk200_disp1", GATE_BUS_TOP, 18, CLK_IS_CRITICAL, 0), GATE(CLK_SCLK_MPHY_IXTAL24, "sclk_mphy_ixtal24", "mphy_refclk_ixtal24", diff --git a/drivers/clk/samsung/clk-exynos5433.c b/drivers/clk/samsung/clk-exynos5433.c index 11343a597093..db270908037a 100644 --- a/drivers/clk/samsung/clk-exynos5433.c +++ b/drivers/clk/samsung/clk-exynos5433.c @@ -9,9 +9,13 @@ * Common Clock Framework support for Exynos5433 SoC. */ +#include <linux/clk.h> #include <linux/clk-provider.h> #include <linux/of.h> #include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> #include <dt-bindings/clock/exynos5433.h> @@ -1991,6 +1995,14 @@ static const unsigned long fsys_clk_regs[] __initconst = { ENABLE_IP_FSYS1, }; +static const struct samsung_clk_reg_dump fsys_suspend_regs[] = { + { MUX_SEL_FSYS0, 0 }, + { MUX_SEL_FSYS1, 0 }, + { MUX_SEL_FSYS2, 0 }, + { MUX_SEL_FSYS3, 0 }, + { MUX_SEL_FSYS4, 0 }, +}; + static const struct samsung_fixed_rate_clock fsys_fixed_clks[] __initconst = { /* PHY clocks from USBDRD30_PHY */ FRATE(CLK_PHYCLK_USBDRD30_UDRD30_PHYCLOCK_PHY, @@ -2296,16 +2308,11 @@ static const struct samsung_cmu_info fsys_cmu_info __initconst = { .nr_clk_ids = FSYS_NR_CLK, .clk_regs = fsys_clk_regs, .nr_clk_regs = ARRAY_SIZE(fsys_clk_regs), + .suspend_regs = fsys_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(fsys_suspend_regs), + .clk_name = "aclk_fsys_200", }; -static void __init exynos5433_cmu_fsys_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &fsys_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_fsys, "samsung,exynos5433-cmu-fsys", - exynos5433_cmu_fsys_init); - /* * Register offset definitions for CMU_G2D */ @@ -2335,6 +2342,10 @@ static const unsigned long g2d_clk_regs[] __initconst = { DIV_ENABLE_IP_G2D_SECURE_SMMU_G2D, }; +static const struct samsung_clk_reg_dump g2d_suspend_regs[] = { + { MUX_SEL_G2D0, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aclk_g2d_266_user_p) = { "oscclk", "aclk_g2d_266", }; PNAME(mout_aclk_g2d_400_user_p) = { "oscclk", "aclk_g2d_400", }; @@ -2420,16 +2431,11 @@ static const struct samsung_cmu_info g2d_cmu_info __initconst = { .nr_clk_ids = G2D_NR_CLK, .clk_regs = g2d_clk_regs, .nr_clk_regs = ARRAY_SIZE(g2d_clk_regs), + .suspend_regs = g2d_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(g2d_suspend_regs), + .clk_name = "aclk_g2d_400", }; -static void __init exynos5433_cmu_g2d_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &g2d_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_g2d, "samsung,exynos5433-cmu-g2d", - exynos5433_cmu_g2d_init); - /* * Register offset definitions for CMU_DISP */ @@ -2494,6 +2500,18 @@ static const unsigned long disp_clk_regs[] __initconst = { CLKOUT_CMU_DISP_DIV_STAT, }; +static const struct samsung_clk_reg_dump disp_suspend_regs[] = { + /* PLL has to be enabled for suspend */ + { DISP_PLL_CON0, 0x85f40502 }, + /* ignore status of external PHY muxes during suspend to avoid hangs */ + { MUX_IGNORE_DISP2, 0x00111111 }, + { MUX_SEL_DISP0, 0 }, + { MUX_SEL_DISP1, 0 }, + { MUX_SEL_DISP2, 0 }, + { MUX_SEL_DISP3, 0 }, + { MUX_SEL_DISP4, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_disp_pll_p) = { "oscclk", "fout_disp_pll", }; PNAME(mout_sclk_dsim1_user_p) = { "oscclk", "sclk_dsim1_disp", }; @@ -2841,16 +2859,11 @@ static const struct samsung_cmu_info disp_cmu_info __initconst = { .nr_clk_ids = DISP_NR_CLK, .clk_regs = disp_clk_regs, .nr_clk_regs = ARRAY_SIZE(disp_clk_regs), + .suspend_regs = disp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(disp_suspend_regs), + .clk_name = "aclk_disp_333", }; -static void __init exynos5433_cmu_disp_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &disp_cmu_info); -} - -CLK_OF_DECLARE(exynos5433_cmu_disp, "samsung,exynos5433-cmu-disp", - exynos5433_cmu_disp_init); - /* * Register offset definitions for CMU_AUD */ @@ -2885,6 +2898,11 @@ static const unsigned long aud_clk_regs[] __initconst = { ENABLE_IP_AUD1, }; +static const struct samsung_clk_reg_dump aud_suspend_regs[] = { + { MUX_SEL_AUD0, 0 }, + { MUX_SEL_AUD1, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aud_pll_user_aud_p) = { "oscclk", "fout_aud_pll", }; PNAME(mout_sclk_aud_pcm_p) = { "mout_aud_pll_user", "ioclk_audiocdclk0",}; @@ -3011,16 +3029,11 @@ static const struct samsung_cmu_info aud_cmu_info __initconst = { .nr_clk_ids = AUD_NR_CLK, .clk_regs = aud_clk_regs, .nr_clk_regs = ARRAY_SIZE(aud_clk_regs), + .suspend_regs = aud_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(aud_suspend_regs), + .clk_name = "fout_aud_pll", }; -static void __init exynos5433_cmu_aud_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &aud_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_aud, "samsung,exynos5433-cmu-aud", - exynos5433_cmu_aud_init); - - /* * Register offset definitions for CMU_BUS{0|1|2} */ @@ -3222,6 +3235,10 @@ static const unsigned long g3d_clk_regs[] __initconst = { CLK_STOPCTRL, }; +static const struct samsung_clk_reg_dump g3d_suspend_regs[] = { + { MUX_SEL_G3D, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_aclk_g3d_400_p) = { "mout_g3d_pll", "aclk_g3d_400", }; PNAME(mout_g3d_pll_p) = { "oscclk", "fout_g3d_pll", }; @@ -3295,15 +3312,11 @@ static const struct samsung_cmu_info g3d_cmu_info __initconst = { .nr_clk_ids = G3D_NR_CLK, .clk_regs = g3d_clk_regs, .nr_clk_regs = ARRAY_SIZE(g3d_clk_regs), + .suspend_regs = g3d_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(g3d_suspend_regs), + .clk_name = "aclk_g3d_400", }; -static void __init exynos5433_cmu_g3d_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &g3d_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_g3d, "samsung,exynos5433-cmu-g3d", - exynos5433_cmu_g3d_init); - /* * Register offset definitions for CMU_GSCL */ @@ -3342,6 +3355,12 @@ static const unsigned long gscl_clk_regs[] __initconst = { ENABLE_IP_GSCL_SECURE_SMMU_GSCL2, }; +static const struct samsung_clk_reg_dump gscl_suspend_regs[] = { + { MUX_SEL_GSCL, 0 }, + { ENABLE_ACLK_GSCL, 0xfff }, + { ENABLE_PCLK_GSCL, 0xff }, +}; + /* list of all parent clock list */ PNAME(aclk_gscl_111_user_p) = { "oscclk", "aclk_gscl_111", }; PNAME(aclk_gscl_333_user_p) = { "oscclk", "aclk_gscl_333", }; @@ -3436,15 +3455,11 @@ static const struct samsung_cmu_info gscl_cmu_info __initconst = { .nr_clk_ids = GSCL_NR_CLK, .clk_regs = gscl_clk_regs, .nr_clk_regs = ARRAY_SIZE(gscl_clk_regs), + .suspend_regs = gscl_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(gscl_suspend_regs), + .clk_name = "aclk_gscl_111", }; -static void __init exynos5433_cmu_gscl_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &gscl_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_gscl, "samsung,exynos5433-cmu-gscl", - exynos5433_cmu_gscl_init); - /* * Register offset definitions for CMU_APOLLO */ @@ -3970,6 +3985,11 @@ static const unsigned long mscl_clk_regs[] __initconst = { ENABLE_IP_MSCL_SECURE_SMMU_JPEG, }; +static const struct samsung_clk_reg_dump mscl_suspend_regs[] = { + { MUX_SEL_MSCL0, 0 }, + { MUX_SEL_MSCL1, 0 }, +}; + /* list of all parent clock list */ PNAME(mout_sclk_jpeg_user_p) = { "oscclk", "sclk_jpeg_mscl", }; PNAME(mout_aclk_mscl_400_user_p) = { "oscclk", "aclk_mscl_400", }; @@ -4082,15 +4102,11 @@ static const struct samsung_cmu_info mscl_cmu_info __initconst = { .nr_clk_ids = MSCL_NR_CLK, .clk_regs = mscl_clk_regs, .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs), + .suspend_regs = mscl_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(mscl_suspend_regs), + .clk_name = "aclk_mscl_400", }; -static void __init exynos5433_cmu_mscl_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &mscl_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_mscl, "samsung,exynos5433-cmu-mscl", - exynos5433_cmu_mscl_init); - /* * Register offset definitions for CMU_MFC */ @@ -4120,6 +4136,10 @@ static const unsigned long mfc_clk_regs[] __initconst = { ENABLE_IP_MFC_SECURE_SMMU_MFC, }; +static const struct samsung_clk_reg_dump mfc_suspend_regs[] = { + { MUX_SEL_MFC, 0 }, +}; + PNAME(mout_aclk_mfc_400_user_p) = { "oscclk", "aclk_mfc_400", }; static const struct samsung_mux_clock mfc_mux_clks[] __initconst = { @@ -4190,15 +4210,11 @@ static const struct samsung_cmu_info mfc_cmu_info __initconst = { .nr_clk_ids = MFC_NR_CLK, .clk_regs = mfc_clk_regs, .nr_clk_regs = ARRAY_SIZE(mfc_clk_regs), + .suspend_regs = mfc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(mfc_suspend_regs), + .clk_name = "aclk_mfc_400", }; -static void __init exynos5433_cmu_mfc_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &mfc_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_mfc, "samsung,exynos5433-cmu-mfc", - exynos5433_cmu_mfc_init); - /* * Register offset definitions for CMU_HEVC */ @@ -4228,6 +4244,10 @@ static const unsigned long hevc_clk_regs[] __initconst = { ENABLE_IP_HEVC_SECURE_SMMU_HEVC, }; +static const struct samsung_clk_reg_dump hevc_suspend_regs[] = { + { MUX_SEL_HEVC, 0 }, +}; + PNAME(mout_aclk_hevc_400_user_p) = { "oscclk", "aclk_hevc_400", }; static const struct samsung_mux_clock hevc_mux_clks[] __initconst = { @@ -4300,15 +4320,11 @@ static const struct samsung_cmu_info hevc_cmu_info __initconst = { .nr_clk_ids = HEVC_NR_CLK, .clk_regs = hevc_clk_regs, .nr_clk_regs = ARRAY_SIZE(hevc_clk_regs), + .suspend_regs = hevc_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(hevc_suspend_regs), + .clk_name = "aclk_hevc_400", }; -static void __init exynos5433_cmu_hevc_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &hevc_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_hevc, "samsung,exynos5433-cmu-hevc", - exynos5433_cmu_hevc_init); - /* * Register offset definitions for CMU_ISP */ @@ -4342,6 +4358,10 @@ static const unsigned long isp_clk_regs[] __initconst = { ENABLE_IP_ISP3, }; +static const struct samsung_clk_reg_dump isp_suspend_regs[] = { + { MUX_SEL_ISP, 0 }, +}; + PNAME(mout_aclk_isp_dis_400_user_p) = { "oscclk", "aclk_isp_dis_400", }; PNAME(mout_aclk_isp_400_user_p) = { "oscclk", "aclk_isp_400", }; @@ -4553,15 +4573,11 @@ static const struct samsung_cmu_info isp_cmu_info __initconst = { .nr_clk_ids = ISP_NR_CLK, .clk_regs = isp_clk_regs, .nr_clk_regs = ARRAY_SIZE(isp_clk_regs), + .suspend_regs = isp_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(isp_suspend_regs), + .clk_name = "aclk_isp_400", }; -static void __init exynos5433_cmu_isp_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &isp_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_isp, "samsung,exynos5433-cmu-isp", - exynos5433_cmu_isp_init); - /* * Register offset definitions for CMU_CAM0 */ @@ -4625,6 +4641,15 @@ static const unsigned long cam0_clk_regs[] __initconst = { ENABLE_IP_CAM02, ENABLE_IP_CAM03, }; + +static const struct samsung_clk_reg_dump cam0_suspend_regs[] = { + { MUX_SEL_CAM00, 0 }, + { MUX_SEL_CAM01, 0 }, + { MUX_SEL_CAM02, 0 }, + { MUX_SEL_CAM03, 0 }, + { MUX_SEL_CAM04, 0 }, +}; + PNAME(mout_aclk_cam0_333_user_p) = { "oscclk", "aclk_cam0_333", }; PNAME(mout_aclk_cam0_400_user_p) = { "oscclk", "aclk_cam0_400", }; PNAME(mout_aclk_cam0_552_user_p) = { "oscclk", "aclk_cam0_552", }; @@ -5030,15 +5055,11 @@ static const struct samsung_cmu_info cam0_cmu_info __initconst = { .nr_clk_ids = CAM0_NR_CLK, .clk_regs = cam0_clk_regs, .nr_clk_regs = ARRAY_SIZE(cam0_clk_regs), + .suspend_regs = cam0_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(cam0_suspend_regs), + .clk_name = "aclk_cam0_400", }; -static void __init exynos5433_cmu_cam0_init(struct device_node *np) -{ - samsung_cmu_register_one(np, &cam0_cmu_info); -} -CLK_OF_DECLARE(exynos5433_cmu_cam0, "samsung,exynos5433-cmu-cam0", - exynos5433_cmu_cam0_init); - /* * Register offset definitions for CMU_CAM1 */ @@ -5085,6 +5106,12 @@ static const unsigned long cam1_clk_regs[] __initconst = { ENABLE_IP_CAM12, }; +static const struct samsung_clk_reg_dump cam1_suspend_regs[] = { + { MUX_SEL_CAM10, 0 }, + { MUX_SEL_CAM11, 0 }, + { MUX_SEL_CAM12, 0 }, +}; + PNAME(mout_sclk_isp_uart_user_p) = { "oscclk", "sclk_isp_uart_cam1", }; PNAME(mout_sclk_isp_spi1_user_p) = { "oscclk", "sclk_isp_spi1_cam1", }; PNAME(mout_sclk_isp_spi0_user_p) = { "oscclk", "sclk_isp_spi0_cam1", }; @@ -5403,11 +5430,223 @@ static const struct samsung_cmu_info cam1_cmu_info __initconst = { .nr_clk_ids = CAM1_NR_CLK, .clk_regs = cam1_clk_regs, .nr_clk_regs = ARRAY_SIZE(cam1_clk_regs), + .suspend_regs = cam1_suspend_regs, + .nr_suspend_regs = ARRAY_SIZE(cam1_suspend_regs), + .clk_name = "aclk_cam1_400", +}; + + +struct exynos5433_cmu_data { + struct samsung_clk_reg_dump *clk_save; + unsigned int nr_clk_save; + const struct samsung_clk_reg_dump *clk_suspend; + unsigned int nr_clk_suspend; + + struct clk *clk; + struct clk **pclks; + int nr_pclks; + + /* must be the last entry */ + struct samsung_clk_provider ctx; +}; + +static int __maybe_unused exynos5433_cmu_suspend(struct device *dev) +{ + struct exynos5433_cmu_data *data = dev_get_drvdata(dev); + int i; + + samsung_clk_save(data->ctx.reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + /* for suspend some registers have to be set to certain values */ + samsung_clk_restore(data->ctx.reg_base, data->clk_suspend, + data->nr_clk_suspend); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + clk_disable_unprepare(data->clk); + + return 0; +} + +static int __maybe_unused exynos5433_cmu_resume(struct device *dev) +{ + struct exynos5433_cmu_data *data = dev_get_drvdata(dev); + int i; + + clk_prepare_enable(data->clk); + + for (i = 0; i < data->nr_pclks; i++) + clk_prepare_enable(data->pclks[i]); + + samsung_clk_restore(data->ctx.reg_base, data->clk_save, + data->nr_clk_save); + + for (i = 0; i < data->nr_pclks; i++) + clk_disable_unprepare(data->pclks[i]); + + return 0; +} + +static int __init exynos5433_cmu_probe(struct platform_device *pdev) +{ + const struct samsung_cmu_info *info; + struct exynos5433_cmu_data *data; + struct samsung_clk_provider *ctx; + struct device *dev = &pdev->dev; + struct resource *res; + void __iomem *reg_base; + int i; + + info = of_device_get_match_data(dev); + + data = devm_kzalloc(dev, sizeof(*data) + + sizeof(*data->ctx.clk_data.hws) * info->nr_clk_ids, + GFP_KERNEL); + if (!data) + return -ENOMEM; + ctx = &data->ctx; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(reg_base)) { + dev_err(dev, "failed to map registers\n"); + return PTR_ERR(reg_base); + } + + for (i = 0; i < info->nr_clk_ids; ++i) + ctx->clk_data.hws[i] = ERR_PTR(-ENOENT); + + ctx->clk_data.num = info->nr_clk_ids; + ctx->reg_base = reg_base; + ctx->dev = dev; + spin_lock_init(&ctx->lock); + + data->clk_save = samsung_clk_alloc_reg_dump(info->clk_regs, + info->nr_clk_regs); + data->nr_clk_save = info->nr_clk_regs; + data->clk_suspend = info->suspend_regs; + data->nr_clk_suspend = info->nr_suspend_regs; + data->nr_pclks = of_count_phandle_with_args(dev->of_node, "clocks", + "#clock-cells"); + if (data->nr_pclks > 0) { + data->pclks = devm_kcalloc(dev, sizeof(struct clk *), + data->nr_pclks, GFP_KERNEL); + + for (i = 0; i < data->nr_pclks; i++) { + struct clk *clk = of_clk_get(dev->of_node, i); + + if (IS_ERR(clk)) + return PTR_ERR(clk); + data->pclks[i] = clk; + } + } + + if (info->clk_name) + data->clk = clk_get(dev, info->clk_name); + clk_prepare_enable(data->clk); + + platform_set_drvdata(pdev, data); + + /* + * Enable runtime PM here to allow the clock core using runtime PM + * for the registered clocks. Additionally, we increase the runtime + * PM usage count before registering the clocks, to prevent the + * clock core from runtime suspending the device. + */ + pm_runtime_get_noresume(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + + if (info->pll_clks) + samsung_clk_register_pll(ctx, info->pll_clks, info->nr_pll_clks, + reg_base); + if (info->mux_clks) + samsung_clk_register_mux(ctx, info->mux_clks, + info->nr_mux_clks); + if (info->div_clks) + samsung_clk_register_div(ctx, info->div_clks, + info->nr_div_clks); + if (info->gate_clks) + samsung_clk_register_gate(ctx, info->gate_clks, + info->nr_gate_clks); + if (info->fixed_clks) + samsung_clk_register_fixed_rate(ctx, info->fixed_clks, + info->nr_fixed_clks); + if (info->fixed_factor_clks) + samsung_clk_register_fixed_factor(ctx, info->fixed_factor_clks, + info->nr_fixed_factor_clks); + + samsung_clk_of_add_provider(dev->of_node, ctx); + pm_runtime_put_sync(dev); + + return 0; +} + +static const struct of_device_id exynos5433_cmu_of_match[] = { + { + .compatible = "samsung,exynos5433-cmu-aud", + .data = &aud_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-cam0", + .data = &cam0_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-cam1", + .data = &cam1_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-disp", + .data = &disp_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-g2d", + .data = &g2d_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-g3d", + .data = &g3d_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-fsys", + .data = &fsys_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-gscl", + .data = &gscl_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-mfc", + .data = &mfc_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-hevc", + .data = &hevc_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-isp", + .data = &isp_cmu_info, + }, { + .compatible = "samsung,exynos5433-cmu-mscl", + .data = &mscl_cmu_info, + }, { + }, +}; + +static const struct dev_pm_ops exynos5433_cmu_pm_ops = { + SET_RUNTIME_PM_OPS(exynos5433_cmu_suspend, exynos5433_cmu_resume, + NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver exynos5433_cmu_driver __refdata = { + .driver = { + .name = "exynos5433-cmu", + .of_match_table = exynos5433_cmu_of_match, + .suppress_bind_attrs = true, + .pm = &exynos5433_cmu_pm_ops, + }, + .probe = exynos5433_cmu_probe, }; -static void __init exynos5433_cmu_cam1_init(struct device_node *np) +static int __init exynos5433_cmu_init(void) { - samsung_cmu_register_one(np, &cam1_cmu_info); + return platform_driver_register(&exynos5433_cmu_driver); } -CLK_OF_DECLARE(exynos5433_cmu_cam1, "samsung,exynos5433-cmu-cam1", - exynos5433_cmu_cam1_init); +core_initcall(exynos5433_cmu_init); diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c index a80f3ef20801..b08bd54c5e76 100644 --- a/drivers/clk/samsung/clk-exynos5440.c +++ b/drivers/clk/samsung/clk-exynos5440.c @@ -53,8 +53,7 @@ static const struct samsung_fixed_factor_clock exynos5440_fixed_factor_clks[] __ /* mux clocks */ static const struct samsung_mux_clock exynos5440_mux_clks[] __initconst = { MUX(0, "mout_spi", mout_spi_p, MISC_DOUT1, 5, 1), - MUX_A(CLK_ARM_CLK, "arm_clk", mout_armclk_p, - CPU_CLK_STATUS, 0, 1, "armclk"), + MUX(CLK_ARM_CLK, "arm_clk", mout_armclk_p, CPU_CLK_STATUS, 0, 1), }; /* divider clocks */ @@ -117,6 +116,13 @@ static const struct samsung_pll_clock exynos5440_plls[] __initconst = { PLL(pll_2550x, CLK_CPLLB, "cpllb", "xtal", 0, 0x50, NULL), }; +/* + * Clock aliases for legacy clkdev look-up. + */ +static const struct samsung_clock_alias exynos5440_aliases[] __initconst = { + ALIAS(CLK_ARM_CLK, NULL, "armclk"), +}; + /* register exynos5440 clocks */ static void __init exynos5440_clk_init(struct device_node *np) { @@ -147,6 +153,8 @@ static void __init exynos5440_clk_init(struct device_node *np) ARRAY_SIZE(exynos5440_div_clks)); samsung_clk_register_gate(ctx, exynos5440_gate_clks, ARRAY_SIZE(exynos5440_gate_clks)); + samsung_clk_register_alias(ctx, exynos5440_aliases, + ARRAY_SIZE(exynos5440_aliases)); samsung_clk_of_add_provider(np, ctx); diff --git a/drivers/clk/samsung/clk-pll.c b/drivers/clk/samsung/clk-pll.c index 037c61484098..1c4c7a3039f1 100644 --- a/drivers/clk/samsung/clk-pll.c +++ b/drivers/clk/samsung/clk-pll.c @@ -1388,7 +1388,7 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, pll->lock_reg = base + pll_clk->lock_offset; pll->con_reg = base + pll_clk->con_offset; - ret = clk_hw_register(NULL, &pll->hw); + ret = clk_hw_register(ctx->dev, &pll->hw); if (ret) { pr_err("%s: failed to register pll clock %s : %d\n", __func__, pll_clk->name, ret); @@ -1397,15 +1397,6 @@ static void __init _samsung_clk_register_pll(struct samsung_clk_provider *ctx, } samsung_clk_add_lookup(ctx, &pll->hw, pll_clk->id); - - if (!pll_clk->alias) - return; - - ret = clk_hw_register_clkdev(&pll->hw, pll_clk->alias, - pll_clk->dev_name); - if (ret) - pr_err("%s: failed to register lookup for %s : %d", - __func__, pll_clk->name, ret); } void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx, diff --git a/drivers/clk/samsung/clk-s3c2443.c b/drivers/clk/samsung/clk-s3c2443.c index abb935c42916..d94b85a42356 100644 --- a/drivers/clk/samsung/clk-s3c2443.c +++ b/drivers/clk/samsung/clk-s3c2443.c @@ -117,8 +117,8 @@ struct samsung_mux_clock s3c2443_common_muxes[] __initdata = { MUX(0, "epllref", epllref_p, CLKSRC, 7, 2), MUX(ESYSCLK, "esysclk", esysclk_p, CLKSRC, 6, 1), MUX(0, "mpllref", mpllref_p, CLKSRC, 3, 1), - MUX_A(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1, "msysclk"), - MUX_A(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1, "armclk"), + MUX(MSYSCLK, "msysclk", msysclk_p, CLKSRC, 4, 1), + MUX(ARMCLK, "armclk", armclk_p, CLKDIV0, 13, 1), MUX(0, "mux_i2s0", i2s0_p, CLKSRC, 14, 2), }; @@ -189,6 +189,10 @@ struct samsung_gate_clock s3c2443_common_gates[] __initdata = { }; struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { + ALIAS(MSYSCLK, NULL, "msysclk"), + ALIAS(ARMCLK, NULL, "armclk"), + ALIAS(MPLL, NULL, "mpll"), + ALIAS(EPLL, NULL, "epll"), ALIAS(HCLK, NULL, "hclk"), ALIAS(HCLK_SSMC, NULL, "nand"), ALIAS(PCLK_UART0, "s3c2440-uart.0", "uart"), @@ -221,9 +225,9 @@ struct samsung_clock_alias s3c2443_common_aliases[] __initdata = { /* S3C2416 specific clocks */ static struct samsung_pll_clock s3c2416_pll_clks[] __initdata = { - [mpll] = PLL(pll_6552_s3c2416, 0, "mpll", "mpllref", + [mpll] = PLL(pll_6552_s3c2416, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_6553, 0, "epll", "epllref", + [epll] = PLL(pll_6553, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; @@ -275,9 +279,9 @@ struct samsung_clock_alias s3c2416_aliases[] __initdata = { /* S3C2443 specific clocks */ static struct samsung_pll_clock s3c2443_pll_clks[] __initdata = { - [mpll] = PLL(pll_3000, 0, "mpll", "mpllref", + [mpll] = PLL(pll_3000, MPLL, "mpll", "mpllref", LOCKCON0, MPLLCON, NULL), - [epll] = PLL(pll_2126, 0, "epll", "epllref", + [epll] = PLL(pll_2126, EPLL, "epll", "epllref", LOCKCON1, EPLLCON, NULL), }; diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c index 7ce0fa86c5ff..8634884aa11c 100644 --- a/drivers/clk/samsung/clk.c +++ b/drivers/clk/samsung/clk.c @@ -134,7 +134,7 @@ void __init samsung_clk_register_fixed_rate(struct samsung_clk_provider *ctx, unsigned int idx, ret; for (idx = 0; idx < nr_clk; idx++, list++) { - clk_hw = clk_hw_register_fixed_rate(NULL, list->name, + clk_hw = clk_hw_register_fixed_rate(ctx->dev, list->name, list->parent_name, list->flags, list->fixed_rate); if (IS_ERR(clk_hw)) { pr_err("%s: failed to register clock %s\n", __func__, @@ -163,7 +163,7 @@ void __init samsung_clk_register_fixed_factor(struct samsung_clk_provider *ctx, unsigned int idx; for (idx = 0; idx < nr_clk; idx++, list++) { - clk_hw = clk_hw_register_fixed_factor(NULL, list->name, + clk_hw = clk_hw_register_fixed_factor(ctx->dev, list->name, list->parent_name, list->flags, list->mult, list->div); if (IS_ERR(clk_hw)) { pr_err("%s: failed to register clock %s\n", __func__, @@ -181,10 +181,10 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx, unsigned int nr_clk) { struct clk_hw *clk_hw; - unsigned int idx, ret; + unsigned int idx; for (idx = 0; idx < nr_clk; idx++, list++) { - clk_hw = clk_hw_register_mux(NULL, list->name, + clk_hw = clk_hw_register_mux(ctx->dev, list->name, list->parent_names, list->num_parents, list->flags, ctx->reg_base + list->offset, list->shift, list->width, list->mux_flags, &ctx->lock); @@ -195,15 +195,6 @@ void __init samsung_clk_register_mux(struct samsung_clk_provider *ctx, } samsung_clk_add_lookup(ctx, clk_hw, list->id); - - /* register a clock lookup only if a clock alias is specified */ - if (list->alias) { - ret = clk_hw_register_clkdev(clk_hw, list->alias, - list->dev_name); - if (ret) - pr_err("%s: failed to register lookup %s\n", - __func__, list->alias); - } } } @@ -213,17 +204,17 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx, unsigned int nr_clk) { struct clk_hw *clk_hw; - unsigned int idx, ret; + unsigned int idx; for (idx = 0; idx < nr_clk; idx++, list++) { if (list->table) - clk_hw = clk_hw_register_divider_table(NULL, + clk_hw = clk_hw_register_divider_table(ctx->dev, list->name, list->parent_name, list->flags, ctx->reg_base + list->offset, list->shift, list->width, list->div_flags, list->table, &ctx->lock); else - clk_hw = clk_hw_register_divider(NULL, list->name, + clk_hw = clk_hw_register_divider(ctx->dev, list->name, list->parent_name, list->flags, ctx->reg_base + list->offset, list->shift, list->width, list->div_flags, &ctx->lock); @@ -234,15 +225,6 @@ void __init samsung_clk_register_div(struct samsung_clk_provider *ctx, } samsung_clk_add_lookup(ctx, clk_hw, list->id); - - /* register a clock lookup only if a clock alias is specified */ - if (list->alias) { - ret = clk_hw_register_clkdev(clk_hw, list->alias, - list->dev_name); - if (ret) - pr_err("%s: failed to register lookup %s\n", - __func__, list->alias); - } } } @@ -252,10 +234,10 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, unsigned int nr_clk) { struct clk_hw *clk_hw; - unsigned int idx, ret; + unsigned int idx; for (idx = 0; idx < nr_clk; idx++, list++) { - clk_hw = clk_hw_register_gate(NULL, list->name, list->parent_name, + clk_hw = clk_hw_register_gate(ctx->dev, list->name, list->parent_name, list->flags, ctx->reg_base + list->offset, list->bit_idx, list->gate_flags, &ctx->lock); if (IS_ERR(clk_hw)) { @@ -264,15 +246,6 @@ void __init samsung_clk_register_gate(struct samsung_clk_provider *ctx, continue; } - /* register a clock lookup only if a clock alias is specified */ - if (list->alias) { - ret = clk_hw_register_clkdev(clk_hw, list->alias, - list->dev_name); - if (ret) - pr_err("%s: failed to register lookup %s\n", - __func__, list->alias); - } - samsung_clk_add_lookup(ctx, clk_hw, list->id); } } diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h index b8ca0dd3a38b..3880d2f9d582 100644 --- a/drivers/clk/samsung/clk.h +++ b/drivers/clk/samsung/clk.h @@ -24,6 +24,7 @@ */ struct samsung_clk_provider { void __iomem *reg_base; + struct device *dev; spinlock_t lock; /* clk_data must be the last entry due to variable lenght 'hws' array */ struct clk_hw_onecell_data clk_data; @@ -106,7 +107,6 @@ struct samsung_fixed_factor_clock { /** * struct samsung_mux_clock: information about mux clock * @id: platform specific id of the clock. - * @dev_name: name of the device to which this clock belongs. * @name: name of this mux clock. * @parent_names: array of pointer to parent clock names. * @num_parents: number of parents listed in @parent_names. @@ -115,11 +115,9 @@ struct samsung_fixed_factor_clock { * @shift: starting bit location of the mux control bit-field in @reg. * @width: width of the mux control bit-field in @reg. * @mux_flags: flags for mux-type clock. - * @alias: optional clock alias name to be assigned to this clock. */ struct samsung_mux_clock { unsigned int id; - const char *dev_name; const char *name; const char *const *parent_names; u8 num_parents; @@ -128,13 +126,11 @@ struct samsung_mux_clock { u8 shift; u8 width; u8 mux_flags; - const char *alias; }; -#define __MUX(_id, dname, cname, pnames, o, s, w, f, mf, a) \ +#define __MUX(_id, cname, pnames, o, s, w, f, mf) \ { \ .id = _id, \ - .dev_name = dname, \ .name = cname, \ .parent_names = pnames, \ .num_parents = ARRAY_SIZE(pnames), \ @@ -143,36 +139,26 @@ struct samsung_mux_clock { .shift = s, \ .width = w, \ .mux_flags = mf, \ - .alias = a, \ } #define MUX(_id, cname, pnames, o, s, w) \ - __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, NULL) - -#define MUX_A(_id, cname, pnames, o, s, w, a) \ - __MUX(_id, NULL, cname, pnames, o, s, w, 0, 0, a) + __MUX(_id, cname, pnames, o, s, w, 0, 0) #define MUX_F(_id, cname, pnames, o, s, w, f, mf) \ - __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL) - -#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a) \ - __MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a) + __MUX(_id, cname, pnames, o, s, w, f, mf) /** * @id: platform specific id of the clock. * struct samsung_div_clock: information about div clock - * @dev_name: name of the device to which this clock belongs. * @name: name of this div clock. * @parent_name: name of the parent clock. * @flags: optional flags for basic clock. * @offset: offset of the register for configuring the div. * @shift: starting bit location of the div control bit-field in @reg. * @div_flags: flags for div-type clock. - * @alias: optional clock alias name to be assigned to this clock. */ struct samsung_div_clock { unsigned int id; - const char *dev_name; const char *name; const char *parent_name; unsigned long flags; @@ -180,14 +166,12 @@ struct samsung_div_clock { u8 shift; u8 width; u8 div_flags; - const char *alias; struct clk_div_table *table; }; -#define __DIV(_id, dname, cname, pname, o, s, w, f, df, a, t) \ +#define __DIV(_id, cname, pname, o, s, w, f, df, t) \ { \ .id = _id, \ - .dev_name = dname, \ .name = cname, \ .parent_name = pname, \ .flags = f, \ @@ -195,70 +179,51 @@ struct samsung_div_clock { .shift = s, \ .width = w, \ .div_flags = df, \ - .alias = a, \ .table = t, \ } #define DIV(_id, cname, pname, o, s, w) \ - __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, NULL) - -#define DIV_A(_id, cname, pname, o, s, w, a) \ - __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, a, NULL) + __DIV(_id, cname, pname, o, s, w, 0, 0, NULL) #define DIV_F(_id, cname, pname, o, s, w, f, df) \ - __DIV(_id, NULL, cname, pname, o, s, w, f, df, NULL, NULL) + __DIV(_id, cname, pname, o, s, w, f, df, NULL) #define DIV_T(_id, cname, pname, o, s, w, t) \ - __DIV(_id, NULL, cname, pname, o, s, w, 0, 0, NULL, t) + __DIV(_id, cname, pname, o, s, w, 0, 0, t) /** * struct samsung_gate_clock: information about gate clock * @id: platform specific id of the clock. - * @dev_name: name of the device to which this clock belongs. * @name: name of this gate clock. * @parent_name: name of the parent clock. * @flags: optional flags for basic clock. * @offset: offset of the register for configuring the gate. * @bit_idx: bit index of the gate control bit-field in @reg. * @gate_flags: flags for gate-type clock. - * @alias: optional clock alias name to be assigned to this clock. */ struct samsung_gate_clock { unsigned int id; - const char *dev_name; const char *name; const char *parent_name; unsigned long flags; unsigned long offset; u8 bit_idx; u8 gate_flags; - const char *alias; }; -#define __GATE(_id, dname, cname, pname, o, b, f, gf, a) \ +#define __GATE(_id, cname, pname, o, b, f, gf) \ { \ .id = _id, \ - .dev_name = dname, \ .name = cname, \ .parent_name = pname, \ .flags = f, \ .offset = o, \ .bit_idx = b, \ .gate_flags = gf, \ - .alias = a, \ } #define GATE(_id, cname, pname, o, b, f, gf) \ - __GATE(_id, NULL, cname, pname, o, b, f, gf, NULL) - -#define GATE_A(_id, cname, pname, o, b, f, gf, a) \ - __GATE(_id, NULL, cname, pname, o, b, f, gf, a) - -#define GATE_D(_id, dname, cname, pname, o, b, f, gf) \ - __GATE(_id, dname, cname, pname, o, b, f, gf, NULL) - -#define GATE_DA(_id, dname, cname, pname, o, b, f, gf, a) \ - __GATE(_id, dname, cname, pname, o, b, f, gf, a) + __GATE(_id, cname, pname, o, b, f, gf) #define PNAME(x) static const char * const x[] __initconst @@ -275,18 +240,15 @@ struct samsung_clk_reg_dump { /** * struct samsung_pll_clock: information about pll clock * @id: platform specific id of the clock. - * @dev_name: name of the device to which this clock belongs. * @name: name of this pll clock. * @parent_name: name of the parent clock. * @flags: optional flags for basic clock. * @con_offset: offset of the register for configuring the PLL. * @lock_offset: offset of the register for locking the PLL. * @type: Type of PLL to be registered. - * @alias: optional clock alias name to be assigned to this clock. */ struct samsung_pll_clock { unsigned int id; - const char *dev_name; const char *name; const char *parent_name; unsigned long flags; @@ -294,31 +256,23 @@ struct samsung_pll_clock { int lock_offset; enum samsung_pll_type type; const struct samsung_pll_rate_table *rate_table; - const char *alias; }; -#define __PLL(_typ, _id, _dname, _name, _pname, _flags, _lock, _con, \ - _rtable, _alias) \ +#define __PLL(_typ, _id, _name, _pname, _flags, _lock, _con, _rtable) \ { \ .id = _id, \ .type = _typ, \ - .dev_name = _dname, \ .name = _name, \ .parent_name = _pname, \ - .flags = CLK_GET_RATE_NOCACHE, \ + .flags = _flags, \ .con_offset = _con, \ .lock_offset = _lock, \ .rate_table = _rtable, \ - .alias = _alias, \ } #define PLL(_typ, _id, _name, _pname, _lock, _con, _rtable) \ - __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \ - _lock, _con, _rtable, _name) - -#define PLL_A(_typ, _id, _name, _pname, _lock, _con, _alias, _rtable) \ - __PLL(_typ, _id, NULL, _name, _pname, CLK_GET_RATE_NOCACHE, \ - _lock, _con, _rtable, _alias) + __PLL(_typ, _id, _name, _pname, CLK_GET_RATE_NOCACHE, _lock, \ + _con, _rtable) struct samsung_clock_reg_cache { struct list_head node; @@ -352,6 +306,12 @@ struct samsung_cmu_info { /* list and number of clocks registers */ const unsigned long *clk_regs; unsigned int nr_clk_regs; + + /* list and number of clocks registers to set before suspend */ + const struct samsung_clk_reg_dump *suspend_regs; + unsigned int nr_suspend_regs; + /* name of the parent clock needed for CMU register access */ + const char *clk_name; }; extern struct samsung_clk_provider *__init samsung_clk_init( diff --git a/drivers/clk/sirf/clk-atlas6.c b/drivers/clk/sirf/clk-atlas6.c index 665fa681b2e1..0cd11e6893af 100644 --- a/drivers/clk/sirf/clk-atlas6.c +++ b/drivers/clk/sirf/clk-atlas6.c @@ -42,7 +42,7 @@ static struct clk_dmn clk_mmc45 = { }, }; -static struct clk_init_data clk_nand_init = { +static const struct clk_init_data clk_nand_init = { .name = "nand", .ops = &dmn_ops, .parent_names = dmn_clk_parents, diff --git a/drivers/clk/sirf/clk-atlas7.c b/drivers/clk/sirf/clk-atlas7.c index d0c6c9a2d06a..be012b4bab46 100644 --- a/drivers/clk/sirf/clk-atlas7.c +++ b/drivers/clk/sirf/clk-atlas7.c @@ -392,7 +392,7 @@ static const char * const pll_clk_parents[] = { "xin", }; -static struct clk_init_data clk_cpupll_init = { +static const struct clk_init_data clk_cpupll_init = { .name = "cpupll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -406,7 +406,7 @@ static struct clk_pll clk_cpupll = { }, }; -static struct clk_init_data clk_mempll_init = { +static const struct clk_init_data clk_mempll_init = { .name = "mempll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -420,7 +420,7 @@ static struct clk_pll clk_mempll = { }, }; -static struct clk_init_data clk_sys0pll_init = { +static const struct clk_init_data clk_sys0pll_init = { .name = "sys0pll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -434,7 +434,7 @@ static struct clk_pll clk_sys0pll = { }, }; -static struct clk_init_data clk_sys1pll_init = { +static const struct clk_init_data clk_sys1pll_init = { .name = "sys1pll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -448,7 +448,7 @@ static struct clk_pll clk_sys1pll = { }, }; -static struct clk_init_data clk_sys2pll_init = { +static const struct clk_init_data clk_sys2pll_init = { .name = "sys2pll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -462,7 +462,7 @@ static struct clk_pll clk_sys2pll = { }, }; -static struct clk_init_data clk_sys3pll_init = { +static const struct clk_init_data clk_sys3pll_init = { .name = "sys3pll_vco", .ops = &ab_pll_ops, .parent_names = pll_clk_parents, @@ -596,7 +596,7 @@ static const char * const audiodto_clk_parents[] = { "sys3pll_clk1", }; -static struct clk_init_data clk_audiodto_init = { +static const struct clk_init_data clk_audiodto_init = { .name = "audio_dto", .ops = &dto_ops, .parent_names = audiodto_clk_parents, @@ -617,7 +617,7 @@ static const char * const disp0dto_clk_parents[] = { "sys3pll_clk1", }; -static struct clk_init_data clk_disp0dto_init = { +static const struct clk_init_data clk_disp0dto_init = { .name = "disp0_dto", .ops = &dto_ops, .parent_names = disp0dto_clk_parents, @@ -638,7 +638,7 @@ static const char * const disp1dto_clk_parents[] = { "sys3pll_clk1", }; -static struct clk_init_data clk_disp1dto_init = { +static const struct clk_init_data clk_disp1dto_init = { .name = "disp1_dto", .ops = &dto_ops, .parent_names = disp1dto_clk_parents, diff --git a/drivers/clk/sirf/clk-common.c b/drivers/clk/sirf/clk-common.c index 77e1e2491689..d8f9efa5129a 100644 --- a/drivers/clk/sirf/clk-common.c +++ b/drivers/clk/sirf/clk-common.c @@ -184,7 +184,7 @@ static unsigned long cpu_clk_recalc_rate(struct clk_hw *hw, return clk_hw_get_rate(parent_clk); } -static struct clk_ops std_pll_ops = { +static const struct clk_ops std_pll_ops = { .recalc_rate = pll_clk_recalc_rate, .round_rate = pll_clk_round_rate, .set_rate = pll_clk_set_rate, @@ -194,21 +194,21 @@ static const char * const pll_clk_parents[] = { "osc", }; -static struct clk_init_data clk_pll1_init = { +static const struct clk_init_data clk_pll1_init = { .name = "pll1", .ops = &std_pll_ops, .parent_names = pll_clk_parents, .num_parents = ARRAY_SIZE(pll_clk_parents), }; -static struct clk_init_data clk_pll2_init = { +static const struct clk_init_data clk_pll2_init = { .name = "pll2", .ops = &std_pll_ops, .parent_names = pll_clk_parents, .num_parents = ARRAY_SIZE(pll_clk_parents), }; -static struct clk_init_data clk_pll3_init = { +static const struct clk_init_data clk_pll3_init = { .name = "pll3", .ops = &std_pll_ops, .parent_names = pll_clk_parents, @@ -265,13 +265,13 @@ static unsigned long usb_pll_clk_recalc_rate(struct clk_hw *hw, unsigned long pa return (reg & SIRFSOC_USBPHY_PLL_BYPASS) ? parent_rate : 48*MHZ; } -static struct clk_ops usb_pll_ops = { +static const struct clk_ops usb_pll_ops = { .enable = usb_pll_clk_enable, .disable = usb_pll_clk_disable, .recalc_rate = usb_pll_clk_recalc_rate, }; -static struct clk_init_data clk_usb_pll_init = { +static const struct clk_init_data clk_usb_pll_init = { .name = "usb_pll", .ops = &usb_pll_ops, .parent_names = pll_clk_parents, @@ -437,7 +437,7 @@ static int cpu_clk_set_rate(struct clk_hw *hw, unsigned long rate, return ret2 ? ret2 : ret1; } -static struct clk_ops msi_ops = { +static const struct clk_ops msi_ops = { .set_rate = dmn_clk_set_rate, .round_rate = dmn_clk_round_rate, .recalc_rate = dmn_clk_recalc_rate, @@ -445,7 +445,7 @@ static struct clk_ops msi_ops = { .get_parent = dmn_clk_get_parent, }; -static struct clk_init_data clk_mem_init = { +static const struct clk_init_data clk_mem_init = { .name = "mem", .ops = &msi_ops, .parent_names = dmn_clk_parents, @@ -459,7 +459,7 @@ static struct clk_dmn clk_mem = { }, }; -static struct clk_init_data clk_sys_init = { +static const struct clk_init_data clk_sys_init = { .name = "sys", .ops = &msi_ops, .parent_names = dmn_clk_parents, @@ -474,7 +474,7 @@ static struct clk_dmn clk_sys = { }, }; -static struct clk_init_data clk_io_init = { +static const struct clk_init_data clk_io_init = { .name = "io", .ops = &msi_ops, .parent_names = dmn_clk_parents, @@ -488,7 +488,7 @@ static struct clk_dmn clk_io = { }, }; -static struct clk_ops cpu_ops = { +static const struct clk_ops cpu_ops = { .set_parent = dmn_clk_set_parent, .get_parent = dmn_clk_get_parent, .set_rate = cpu_clk_set_rate, @@ -496,7 +496,7 @@ static struct clk_ops cpu_ops = { .recalc_rate = cpu_clk_recalc_rate, }; -static struct clk_init_data clk_cpu_init = { +static const struct clk_init_data clk_cpu_init = { .name = "cpu", .ops = &cpu_ops, .parent_names = dmn_clk_parents, @@ -511,7 +511,7 @@ static struct clk_dmn clk_cpu = { }, }; -static struct clk_ops dmn_ops = { +static const struct clk_ops dmn_ops = { .is_enabled = std_clk_is_enabled, .enable = std_clk_enable, .disable = std_clk_disable, @@ -524,7 +524,7 @@ static struct clk_ops dmn_ops = { /* dsp, gfx, mm, lcd and vpp domain */ -static struct clk_init_data clk_dsp_init = { +static const struct clk_init_data clk_dsp_init = { .name = "dsp", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -539,7 +539,7 @@ static struct clk_dmn clk_dsp = { }, }; -static struct clk_init_data clk_gfx_init = { +static const struct clk_init_data clk_gfx_init = { .name = "gfx", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -554,7 +554,7 @@ static struct clk_dmn clk_gfx = { }, }; -static struct clk_init_data clk_mm_init = { +static const struct clk_init_data clk_mm_init = { .name = "mm", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -574,7 +574,7 @@ static struct clk_dmn clk_mm = { */ #define clk_gfx2d clk_mm -static struct clk_init_data clk_lcd_init = { +static const struct clk_init_data clk_lcd_init = { .name = "lcd", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -589,7 +589,7 @@ static struct clk_dmn clk_lcd = { }, }; -static struct clk_init_data clk_vpp_init = { +static const struct clk_init_data clk_vpp_init = { .name = "vpp", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -604,21 +604,21 @@ static struct clk_dmn clk_vpp = { }, }; -static struct clk_init_data clk_mmc01_init = { +static const struct clk_init_data clk_mmc01_init = { .name = "mmc01", .ops = &dmn_ops, .parent_names = dmn_clk_parents, .num_parents = ARRAY_SIZE(dmn_clk_parents), }; -static struct clk_init_data clk_mmc23_init = { +static const struct clk_init_data clk_mmc23_init = { .name = "mmc23", .ops = &dmn_ops, .parent_names = dmn_clk_parents, .num_parents = ARRAY_SIZE(dmn_clk_parents), }; -static struct clk_init_data clk_mmc45_init = { +static const struct clk_init_data clk_mmc45_init = { .name = "mmc45", .ops = &dmn_ops, .parent_names = dmn_clk_parents, @@ -679,13 +679,13 @@ static const char * const std_clk_io_parents[] = { "io", }; -static struct clk_ops ios_ops = { +static const struct clk_ops ios_ops = { .is_enabled = std_clk_is_enabled, .enable = std_clk_enable, .disable = std_clk_disable, }; -static struct clk_init_data clk_cphif_init = { +static const struct clk_init_data clk_cphif_init = { .name = "cphif", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -699,7 +699,7 @@ static struct clk_std clk_cphif = { }, }; -static struct clk_init_data clk_dmac0_init = { +static const struct clk_init_data clk_dmac0_init = { .name = "dmac0", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -713,7 +713,7 @@ static struct clk_std clk_dmac0 = { }, }; -static struct clk_init_data clk_dmac1_init = { +static const struct clk_init_data clk_dmac1_init = { .name = "dmac1", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -727,7 +727,7 @@ static struct clk_std clk_dmac1 = { }, }; -static struct clk_init_data clk_audio_init = { +static const struct clk_init_data clk_audio_init = { .name = "audio", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -741,7 +741,7 @@ static struct clk_std clk_audio = { }, }; -static struct clk_init_data clk_uart0_init = { +static const struct clk_init_data clk_uart0_init = { .name = "uart0", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -755,7 +755,7 @@ static struct clk_std clk_uart0 = { }, }; -static struct clk_init_data clk_uart1_init = { +static const struct clk_init_data clk_uart1_init = { .name = "uart1", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -769,7 +769,7 @@ static struct clk_std clk_uart1 = { }, }; -static struct clk_init_data clk_uart2_init = { +static const struct clk_init_data clk_uart2_init = { .name = "uart2", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -783,7 +783,7 @@ static struct clk_std clk_uart2 = { }, }; -static struct clk_init_data clk_usp0_init = { +static const struct clk_init_data clk_usp0_init = { .name = "usp0", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -797,7 +797,7 @@ static struct clk_std clk_usp0 = { }, }; -static struct clk_init_data clk_usp1_init = { +static const struct clk_init_data clk_usp1_init = { .name = "usp1", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -811,7 +811,7 @@ static struct clk_std clk_usp1 = { }, }; -static struct clk_init_data clk_usp2_init = { +static const struct clk_init_data clk_usp2_init = { .name = "usp2", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -825,7 +825,7 @@ static struct clk_std clk_usp2 = { }, }; -static struct clk_init_data clk_vip_init = { +static const struct clk_init_data clk_vip_init = { .name = "vip", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -839,7 +839,7 @@ static struct clk_std clk_vip = { }, }; -static struct clk_init_data clk_spi0_init = { +static const struct clk_init_data clk_spi0_init = { .name = "spi0", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -853,7 +853,7 @@ static struct clk_std clk_spi0 = { }, }; -static struct clk_init_data clk_spi1_init = { +static const struct clk_init_data clk_spi1_init = { .name = "spi1", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -867,7 +867,7 @@ static struct clk_std clk_spi1 = { }, }; -static struct clk_init_data clk_tsc_init = { +static const struct clk_init_data clk_tsc_init = { .name = "tsc", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -881,7 +881,7 @@ static struct clk_std clk_tsc = { }, }; -static struct clk_init_data clk_i2c0_init = { +static const struct clk_init_data clk_i2c0_init = { .name = "i2c0", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -895,7 +895,7 @@ static struct clk_std clk_i2c0 = { }, }; -static struct clk_init_data clk_i2c1_init = { +static const struct clk_init_data clk_i2c1_init = { .name = "i2c1", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -909,7 +909,7 @@ static struct clk_std clk_i2c1 = { }, }; -static struct clk_init_data clk_pwmc_init = { +static const struct clk_init_data clk_pwmc_init = { .name = "pwmc", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -923,7 +923,7 @@ static struct clk_std clk_pwmc = { }, }; -static struct clk_init_data clk_efuse_init = { +static const struct clk_init_data clk_efuse_init = { .name = "efuse", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -937,7 +937,7 @@ static struct clk_std clk_efuse = { }, }; -static struct clk_init_data clk_pulse_init = { +static const struct clk_init_data clk_pulse_init = { .name = "pulse", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -955,7 +955,7 @@ static const char * const std_clk_dsp_parents[] = { "dsp", }; -static struct clk_init_data clk_gps_init = { +static const struct clk_init_data clk_gps_init = { .name = "gps", .ops = &ios_ops, .parent_names = std_clk_dsp_parents, @@ -969,7 +969,7 @@ static struct clk_std clk_gps = { }, }; -static struct clk_init_data clk_mf_init = { +static const struct clk_init_data clk_mf_init = { .name = "mf", .ops = &ios_ops, .parent_names = std_clk_io_parents, @@ -987,7 +987,7 @@ static const char * const std_clk_sys_parents[] = { "sys", }; -static struct clk_init_data clk_security_init = { +static const struct clk_init_data clk_security_init = { .name = "security", .ops = &ios_ops, .parent_names = std_clk_sys_parents, @@ -1005,7 +1005,7 @@ static const char * const std_clk_usb_parents[] = { "usb_pll", }; -static struct clk_init_data clk_usb0_init = { +static const struct clk_init_data clk_usb0_init = { .name = "usb0", .ops = &ios_ops, .parent_names = std_clk_usb_parents, @@ -1019,7 +1019,7 @@ static struct clk_std clk_usb0 = { }, }; -static struct clk_init_data clk_usb1_init = { +static const struct clk_init_data clk_usb1_init = { .name = "usb1", .ops = &ios_ops, .parent_names = std_clk_usb_parents, diff --git a/drivers/clk/sirf/clk-prima2.c b/drivers/clk/sirf/clk-prima2.c index aac1c8ec151a..2f824320c318 100644 --- a/drivers/clk/sirf/clk-prima2.c +++ b/drivers/clk/sirf/clk-prima2.c @@ -42,7 +42,7 @@ static struct clk_dmn clk_mmc45 = { }, }; -static struct clk_init_data clk_nand_init = { +static const struct clk_init_data clk_nand_init = { .name = "nand", .ops = &ios_ops, .parent_names = std_clk_io_parents, diff --git a/drivers/clk/spear/clk-aux-synth.c b/drivers/clk/spear/clk-aux-synth.c index f271c350ef94..906410413bc1 100644 --- a/drivers/clk/spear/clk-aux-synth.c +++ b/drivers/clk/spear/clk-aux-synth.c @@ -29,7 +29,7 @@ #define to_clk_aux(_hw) container_of(_hw, struct clk_aux, hw) -static struct aux_clk_masks default_aux_masks = { +static const struct aux_clk_masks default_aux_masks = { .eq_sel_mask = AUX_EQ_SEL_MASK, .eq_sel_shift = AUX_EQ_SEL_SHIFT, .eq1_mask = AUX_EQ1_SEL, @@ -128,7 +128,7 @@ static int clk_aux_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } -static struct clk_ops clk_aux_ops = { +static const struct clk_ops clk_aux_ops = { .recalc_rate = clk_aux_recalc_rate, .round_rate = clk_aux_round_rate, .set_rate = clk_aux_set_rate, @@ -136,7 +136,7 @@ static struct clk_ops clk_aux_ops = { struct clk *clk_register_aux(const char *aux_name, const char *gate_name, const char *parent_name, unsigned long flags, void __iomem *reg, - struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, + const struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk) { struct clk_aux *aux; @@ -149,10 +149,8 @@ struct clk *clk_register_aux(const char *aux_name, const char *gate_name, } aux = kzalloc(sizeof(*aux), GFP_KERNEL); - if (!aux) { - pr_err("could not allocate aux clk\n"); + if (!aux) return ERR_PTR(-ENOMEM); - } /* struct clk_aux assignments */ if (!masks) diff --git a/drivers/clk/spear/clk-frac-synth.c b/drivers/clk/spear/clk-frac-synth.c index 58d678b5b40a..229c96daece6 100644 --- a/drivers/clk/spear/clk-frac-synth.c +++ b/drivers/clk/spear/clk-frac-synth.c @@ -116,7 +116,7 @@ static int clk_frac_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } -static struct clk_ops clk_frac_ops = { +static const struct clk_ops clk_frac_ops = { .recalc_rate = clk_frac_recalc_rate, .round_rate = clk_frac_round_rate, .set_rate = clk_frac_set_rate, @@ -136,10 +136,8 @@ struct clk *clk_register_frac(const char *name, const char *parent_name, } frac = kzalloc(sizeof(*frac), GFP_KERNEL); - if (!frac) { - pr_err("could not allocate frac clk\n"); + if (!frac) return ERR_PTR(-ENOMEM); - } /* struct clk_frac assignments */ frac->reg = reg; diff --git a/drivers/clk/spear/clk-gpt-synth.c b/drivers/clk/spear/clk-gpt-synth.c index 1a722e99e76e..28262f422562 100644 --- a/drivers/clk/spear/clk-gpt-synth.c +++ b/drivers/clk/spear/clk-gpt-synth.c @@ -105,7 +105,7 @@ static int clk_gpt_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } -static struct clk_ops clk_gpt_ops = { +static const struct clk_ops clk_gpt_ops = { .recalc_rate = clk_gpt_recalc_rate, .round_rate = clk_gpt_round_rate, .set_rate = clk_gpt_set_rate, @@ -125,10 +125,8 @@ struct clk *clk_register_gpt(const char *name, const char *parent_name, unsigned } gpt = kzalloc(sizeof(*gpt), GFP_KERNEL); - if (!gpt) { - pr_err("could not allocate gpt clk\n"); + if (!gpt) return ERR_PTR(-ENOMEM); - } /* struct clk_gpt assignments */ gpt->reg = reg; diff --git a/drivers/clk/spear/clk-vco-pll.c b/drivers/clk/spear/clk-vco-pll.c index dc21ca4601aa..c08dec30bfa6 100644 --- a/drivers/clk/spear/clk-vco-pll.c +++ b/drivers/clk/spear/clk-vco-pll.c @@ -165,7 +165,7 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } -static struct clk_ops clk_pll_ops = { +static const struct clk_ops clk_pll_ops = { .recalc_rate = clk_pll_recalc_rate, .round_rate = clk_pll_round_rate, .set_rate = clk_pll_set_rate, @@ -266,7 +266,7 @@ static int clk_vco_set_rate(struct clk_hw *hw, unsigned long drate, return 0; } -static struct clk_ops clk_vco_ops = { +static const struct clk_ops clk_vco_ops = { .recalc_rate = clk_vco_recalc_rate, .round_rate = clk_vco_round_rate, .set_rate = clk_vco_set_rate, @@ -292,16 +292,12 @@ struct clk *clk_register_vco_pll(const char *vco_name, const char *pll_name, } vco = kzalloc(sizeof(*vco), GFP_KERNEL); - if (!vco) { - pr_err("could not allocate vco clk\n"); + if (!vco) return ERR_PTR(-ENOMEM); - } pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) { - pr_err("could not allocate pll clk\n"); + if (!pll) goto free_vco; - } /* struct clk_vco assignments */ vco->mode_reg = mode_reg; diff --git a/drivers/clk/spear/clk.h b/drivers/clk/spear/clk.h index 9834944f08b1..af0e25f496c1 100644 --- a/drivers/clk/spear/clk.h +++ b/drivers/clk/spear/clk.h @@ -49,7 +49,7 @@ struct aux_rate_tbl { struct clk_aux { struct clk_hw hw; void __iomem *reg; - struct aux_clk_masks *masks; + const struct aux_clk_masks *masks; struct aux_rate_tbl *rtbl; u8 rtbl_cnt; spinlock_t *lock; @@ -112,7 +112,7 @@ typedef unsigned long (*clk_calc_rate)(struct clk_hw *hw, unsigned long prate, /* clk register routines */ struct clk *clk_register_aux(const char *aux_name, const char *gate_name, const char *parent_name, unsigned long flags, void __iomem *reg, - struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, + const struct aux_clk_masks *masks, struct aux_rate_tbl *rtbl, u8 rtbl_cnt, spinlock_t *lock, struct clk **gate_clk); struct clk *clk_register_frac(const char *name, const char *parent_name, unsigned long flags, void __iomem *reg, diff --git a/drivers/clk/spear/spear1310_clock.c b/drivers/clk/spear/spear1310_clock.c index 2f86e3f94efa..591248c9a88e 100644 --- a/drivers/clk/spear/spear1310_clock.c +++ b/drivers/clk/spear/spear1310_clock.c @@ -284,7 +284,7 @@ static struct frac_rate_tbl clcd_rtbl[] = { }; /* i2s prescaler1 masks */ -static struct aux_clk_masks i2s_prs1_masks = { +static const struct aux_clk_masks i2s_prs1_masks = { .eq_sel_mask = AUX_EQ_SEL_MASK, .eq_sel_shift = SPEAR1310_I2S_PRS1_EQ_SEL_SHIFT, .eq1_mask = AUX_EQ1_SEL, diff --git a/drivers/clk/spear/spear1340_clock.c b/drivers/clk/spear/spear1340_clock.c index cbb19a90f2d6..e5bc8c828cf0 100644 --- a/drivers/clk/spear/spear1340_clock.c +++ b/drivers/clk/spear/spear1340_clock.c @@ -323,7 +323,7 @@ static struct frac_rate_tbl clcd_rtbl[] = { }; /* i2s prescaler1 masks */ -static struct aux_clk_masks i2s_prs1_masks = { +static const struct aux_clk_masks i2s_prs1_masks = { .eq_sel_mask = AUX_EQ_SEL_MASK, .eq_sel_shift = SPEAR1340_I2S_PRS1_EQ_SEL_SHIFT, .eq1_mask = AUX_EQ1_SEL, diff --git a/drivers/clk/sunxi-ng/Makefile b/drivers/clk/sunxi-ng/Makefile index d1c2fa93ddd9..4141c3fe08ae 100644 --- a/drivers/clk/sunxi-ng/Makefile +++ b/drivers/clk/sunxi-ng/Makefile @@ -11,6 +11,7 @@ lib-$(CONFIG_SUNXI_CCU) += ccu_gate.o lib-$(CONFIG_SUNXI_CCU) += ccu_mux.o lib-$(CONFIG_SUNXI_CCU) += ccu_mult.o lib-$(CONFIG_SUNXI_CCU) += ccu_phase.o +lib-$(CONFIG_SUNXI_CCU) += ccu_sdm.o # Multi-factor clocks lib-$(CONFIG_SUNXI_CCU) += ccu_nk.o diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c index 286b0049b7b6..ffa5dac221e4 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.c +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.c @@ -28,6 +28,7 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" #include "ccu_phase.h" +#include "ccu_sdm.h" #include "ccu-sun4i-a10.h" @@ -51,16 +52,29 @@ static struct ccu_nkmp pll_core_clk = { * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names. + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN4I_PLL_AUDIO_REG 0x008 + +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + static struct ccu_nm pll_audio_base_clk = { .enable = BIT(31), .n = _SUNXI_CCU_MULT_OFFSET(8, 7, 0), .m = _SUNXI_CCU_DIV_OFFSET(0, 5, 0), + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, 0, + 0x00c, BIT(31)), .common = { .reg = 0x008, + .features = CCU_FEATURE_SIGMA_DELTA_MOD, .hw.init = CLK_HW_INIT("pll-audio-base", "hosc", &ccu_nm_ops, @@ -223,7 +237,7 @@ static struct ccu_mux cpu_clk = { .hw.init = CLK_HW_INIT_PARENTS("cpu", cpu_parents, &ccu_mux_ops, - CLK_IS_CRITICAL), + CLK_SET_RATE_PARENT | CLK_IS_CRITICAL), } }; @@ -1021,9 +1035,9 @@ static struct ccu_common *sun4i_sun7i_ccu_clks[] = { &out_b_clk.common }; -/* Post-divider for pll-audio is hardcoded to 4 */ +/* Post-divider for pll-audio is hardcoded to 1 */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", @@ -1420,10 +1434,10 @@ static void __init sun4i_ccu_init(struct device_node *node, return; } - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN4I_PLL_AUDIO_REG); val &= ~GENMASK(29, 26); - writel(val | (4 << 26), reg + SUN4I_PLL_AUDIO_REG); + writel(val | (1 << 26), reg + SUN4I_PLL_AUDIO_REG); /* * Use the peripheral PLL6 as the AHB parent, instead of CPU / diff --git a/drivers/clk/sunxi-ng/ccu-sun4i-a10.h b/drivers/clk/sunxi-ng/ccu-sun4i-a10.h index c5947c7c050e..23c908ad509f 100644 --- a/drivers/clk/sunxi-ng/ccu-sun4i-a10.h +++ b/drivers/clk/sunxi-ng/ccu-sun4i-a10.h @@ -29,7 +29,7 @@ #define CLK_PLL_AUDIO_4X 6 #define CLK_PLL_AUDIO_8X 7 #define CLK_PLL_VIDEO0 8 -#define CLK_PLL_VIDEO0_2X 9 +/* The PLL_VIDEO0_2X clock is exported */ #define CLK_PLL_VE 10 #define CLK_PLL_DDR_BASE 11 #define CLK_PLL_DDR 12 @@ -38,7 +38,7 @@ #define CLK_PLL_PERIPH 15 #define CLK_PLL_PERIPH_SATA 16 #define CLK_PLL_VIDEO1 17 -#define CLK_PLL_VIDEO1_2X 18 +/* The PLL_VIDEO1_2X clock is exported */ #define CLK_PLL_GPU 19 /* The CPU clock is exported */ diff --git a/drivers/clk/sunxi-ng/ccu-sun5i.c b/drivers/clk/sunxi-ng/ccu-sun5i.c index ab9e850b3707..fa2c2dd77102 100644 --- a/drivers/clk/sunxi-ng/ccu-sun5i.c +++ b/drivers/clk/sunxi-ng/ccu-sun5i.c @@ -26,6 +26,7 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" #include "ccu_phase.h" +#include "ccu_sdm.h" #include "ccu-sun5i.h" @@ -49,11 +50,20 @@ static struct ccu_nkmp pll_core_clk = { * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN5I_PLL_AUDIO_REG 0x008 +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + static struct ccu_nm pll_audio_base_clk = { .enable = BIT(31), .n = _SUNXI_CCU_MULT_OFFSET(8, 7, 0), @@ -63,8 +73,11 @@ static struct ccu_nm pll_audio_base_clk = { * offset */ .m = _SUNXI_CCU_DIV_OFFSET(0, 5, 0), + .sdm = _SUNXI_CCU_SDM(pll_audio_sdm_table, 0, + 0x00c, BIT(31)), .common = { .reg = 0x008, + .features = CCU_FEATURE_SIGMA_DELTA_MOD, .hw.init = CLK_HW_INIT("pll-audio-base", "hosc", &ccu_nm_ops, @@ -597,9 +610,9 @@ static struct ccu_common *sun5i_a10s_ccu_clks[] = { &iep_clk.common, }; -/* We hardcode the divider to 4 for now */ +/* We hardcode the divider to 1 for now */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", @@ -980,10 +993,10 @@ static void __init sun5i_ccu_init(struct device_node *node, return; } - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN5I_PLL_AUDIO_REG); - val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN5I_PLL_AUDIO_REG); + val &= ~GENMASK(29, 26); + writel(val | (0 << 26), reg + SUN5I_PLL_AUDIO_REG); /* * Use the peripheral PLL as the AHB parent, instead of CPU / diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c index 8af434815fba..72b16ed1012b 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.c +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.c @@ -31,6 +31,7 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" #include "ccu_phase.h" +#include "ccu_sdm.h" #include "ccu-sun6i-a31.h" @@ -48,18 +49,29 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_cpu_clk, "pll-cpu", * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN6I_A31_PLL_AUDIO_REG 0x008 -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", - "osc24M", 0x008, - 8, 7, /* N */ - 0, 5, /* M */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + pll_audio_sdm_table, BIT(24), + 0x284, BIT(31), + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video0_clk, "pll-video0", "osc24M", 0x010, @@ -608,7 +620,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(hdmi_clk, "hdmi", lcd_ch1_parents, 0x150, 0, 4, 24, 2, BIT(31), CLK_SET_RATE_PARENT); -static SUNXI_CCU_GATE(hdmi_ddc_clk, "hdmi-ddc", "osc24M", 0x150, BIT(30), 0); +static SUNXI_CCU_GATE(hdmi_ddc_clk, "ddc", "osc24M", 0x150, BIT(30), 0); static SUNXI_CCU_GATE(ps_clk, "ps", "lcd1-ch1", 0x140, BIT(31), 0); @@ -950,9 +962,9 @@ static struct ccu_common *sun6i_a31_ccu_clks[] = { &out_c_clk.common, }; -/* We hardcode the divider to 4 for now */ +/* We hardcode the divider to 1 for now */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", @@ -1221,10 +1233,10 @@ static void __init sun6i_a31_ccu_setup(struct device_node *node) return; } - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN6I_A31_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN6I_A31_PLL_AUDIO_REG); + writel(val | (0 << 16), reg + SUN6I_A31_PLL_AUDIO_REG); /* Force PLL-MIPI to MIPI mode */ val = readl(reg + SUN6I_A31_PLL_MIPI_REG); diff --git a/drivers/clk/sunxi-ng/ccu-sun6i-a31.h b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h index 4e434011e9e7..27e6ad4133ab 100644 --- a/drivers/clk/sunxi-ng/ccu-sun6i-a31.h +++ b/drivers/clk/sunxi-ng/ccu-sun6i-a31.h @@ -27,7 +27,9 @@ #define CLK_PLL_AUDIO_4X 4 #define CLK_PLL_AUDIO_8X 5 #define CLK_PLL_VIDEO0 6 -#define CLK_PLL_VIDEO0_2X 7 + +/* The PLL_VIDEO0_2X clock is exported */ + #define CLK_PLL_VE 8 #define CLK_PLL_DDR 9 @@ -35,7 +37,9 @@ #define CLK_PLL_PERIPH_2X 11 #define CLK_PLL_VIDEO1 12 -#define CLK_PLL_VIDEO1_2X 13 + +/* The PLL_VIDEO1_2X clock is exported */ + #define CLK_PLL_GPU 14 #define CLK_PLL_MIPI 15 #define CLK_PLL9 16 diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c index d93b452f0df9..a4fa2945f230 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a23.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a23.c @@ -26,6 +26,7 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" #include "ccu_phase.h" +#include "ccu_sdm.h" #include "ccu-sun8i-a23-a33.h" @@ -52,18 +53,29 @@ static struct ccu_nkmp pll_cpux_clk = { * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN8I_A23_PLL_AUDIO_REG 0x008 -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", - "osc24M", 0x008, - 8, 7, /* N */ - 0, 5, /* M */ - BIT(31), /* gate */ - BIT(28), /* lock */ - CLK_SET_RATE_UNGATE); +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + pll_audio_sdm_table, BIT(24), + 0x284, BIT(31), + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", "osc24M", 0x010, @@ -538,9 +550,9 @@ static struct ccu_common *sun8i_a23_ccu_clks[] = { &ats_clk.common, }; -/* We hardcode the divider to 4 for now */ +/* We hardcode the divider to 1 for now */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", @@ -720,10 +732,10 @@ static void __init sun8i_a23_ccu_setup(struct device_node *node) return; } - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_A23_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN8I_A23_PLL_AUDIO_REG); + writel(val | (0 << 16), reg + SUN8I_A23_PLL_AUDIO_REG); /* Force PLL-MIPI to MIPI mode */ val = readl(reg + SUN8I_A23_PLL_MIPI_REG); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c index e43acebdfbcd..5cedcd0d8be8 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-a83t.c @@ -354,9 +354,9 @@ static SUNXI_CCU_GATE(bus_tdm_clk, "bus-tdm", "apb1", static SUNXI_CCU_GATE(bus_i2c0_clk, "bus-i2c0", "apb2", 0x06c, BIT(0), 0); static SUNXI_CCU_GATE(bus_i2c1_clk, "bus-i2c1", "apb2", - 0x06c, BIT(0), 0); + 0x06c, BIT(1), 0); static SUNXI_CCU_GATE(bus_i2c2_clk, "bus-i2c2", "apb2", - 0x06c, BIT(0), 0); + 0x06c, BIT(2), 0); static SUNXI_CCU_GATE(bus_uart0_clk, "bus-uart0", "apb2", 0x06c, BIT(16), 0); static SUNXI_CCU_GATE(bus_uart1_clk, "bus-uart1", "apb2", @@ -506,7 +506,7 @@ static SUNXI_CCU_M_WITH_MUX_TABLE_GATE(csi_mclk_clk, "csi-mclk", csi_mclk_parents, csi_mclk_table, 0x134, 0, 5, /* M */ - 10, 3, /* mux */ + 8, 3, /* mux */ BIT(15), /* gate */ 0); diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c index 5cdaf52669e4..5cc9d9952121 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-de2.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-de2.c @@ -41,11 +41,16 @@ static SUNXI_CCU_GATE(wb_clk, "wb", "wb-div", static SUNXI_CCU_M(mixer0_div_clk, "mixer0-div", "de", 0x0c, 0, 4, CLK_SET_RATE_PARENT); -static SUNXI_CCU_M(mixer1_div_clk, "mixer1-div", "de", 0x0c, 4, 4, - CLK_SET_RATE_PARENT); static SUNXI_CCU_M(wb_div_clk, "wb-div", "de", 0x0c, 8, 4, CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer0_div_a83_clk, "mixer0-div", "pll-de", 0x0c, 0, 4, + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(mixer1_div_a83_clk, "mixer1-div", "pll-de", 0x0c, 4, 4, + CLK_SET_RATE_PARENT); +static SUNXI_CCU_M(wb_div_a83_clk, "wb-div", "pll-de", 0x0c, 8, 4, + CLK_SET_RATE_PARENT); + static struct ccu_common *sun8i_a83t_de2_clks[] = { &mixer0_clk.common, &mixer1_clk.common, @@ -55,9 +60,9 @@ static struct ccu_common *sun8i_a83t_de2_clks[] = { &bus_mixer1_clk.common, &bus_wb_clk.common, - &mixer0_div_clk.common, - &mixer1_div_clk.common, - &wb_div_clk.common, + &mixer0_div_a83_clk.common, + &mixer1_div_a83_clk.common, + &wb_div_a83_clk.common, }; static struct ccu_common *sun8i_v3s_de2_clks[] = { @@ -81,9 +86,9 @@ static struct clk_hw_onecell_data sun8i_a83t_de2_hw_clks = { [CLK_BUS_MIXER1] = &bus_mixer1_clk.common.hw, [CLK_BUS_WB] = &bus_wb_clk.common.hw, - [CLK_MIXER0_DIV] = &mixer0_div_clk.common.hw, - [CLK_MIXER1_DIV] = &mixer1_div_clk.common.hw, - [CLK_WB_DIV] = &wb_div_clk.common.hw, + [CLK_MIXER0_DIV] = &mixer0_div_a83_clk.common.hw, + [CLK_MIXER1_DIV] = &mixer1_div_a83_clk.common.hw, + [CLK_WB_DIV] = &wb_div_a83_clk.common.hw, }, .num = CLK_NUMBER, }; diff --git a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c index 1729ff6a5aae..29bc0566b776 100644 --- a/drivers/clk/sunxi-ng/ccu-sun8i-h3.c +++ b/drivers/clk/sunxi-ng/ccu-sun8i-h3.c @@ -26,6 +26,7 @@ #include "ccu_nkmp.h" #include "ccu_nm.h" #include "ccu_phase.h" +#include "ccu_sdm.h" #include "ccu-sun8i-h3.h" @@ -37,25 +38,36 @@ static SUNXI_CCU_NKMP_WITH_GATE_LOCK(pll_cpux_clk, "pll-cpux", 16, 2, /* P */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); /* * The Audio PLL is supposed to have 4 outputs: 3 fixed factors from * the base (2x, 4x and 8x), and one variable divider (the one true * pll audio). * - * We don't have any need for the variable divider for now, so we just - * hardcode it to match with the clock names + * With sigma-delta modulation for fractional-N on the audio PLL, + * we have to use specific dividers. This means the variable divider + * can no longer be used, as the audio codec requests the exact clock + * rates we support through this mechanism. So we now hard code the + * variable divider to 1. This means the clock rates will no longer + * match the clock names. */ #define SUN8I_H3_PLL_AUDIO_REG 0x008 -static SUNXI_CCU_NM_WITH_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", - "osc24M", 0x008, - 8, 7, /* N */ - 0, 5, /* M */ - BIT(31), /* gate */ - BIT(28), /* lock */ - 0); +static struct ccu_sdm_setting pll_audio_sdm_table[] = { + { .rate = 22579200, .pattern = 0xc0010d84, .m = 8, .n = 7 }, + { .rate = 24576000, .pattern = 0xc000ac02, .m = 14, .n = 14 }, +}; + +static SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(pll_audio_base_clk, "pll-audio-base", + "osc24M", 0x008, + 8, 7, /* N */ + 0, 5, /* M */ + pll_audio_sdm_table, BIT(24), + 0x284, BIT(31), + BIT(31), /* gate */ + BIT(28), /* lock */ + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", "osc24M", 0x0010, @@ -67,7 +79,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_video_clk, "pll-video", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", "osc24M", 0x0018, @@ -79,7 +91,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_ve_clk, "pll-ve", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", "osc24M", 0x020, @@ -88,7 +100,7 @@ static SUNXI_CCU_NKM_WITH_GATE_LOCK(pll_ddr_clk, "pll-ddr", 0, 2, /* M */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph0_clk, "pll-periph0", "osc24M", 0x028, @@ -97,7 +109,7 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph0_clk, "pll-periph0", BIT(31), /* gate */ BIT(28), /* lock */ 2, /* post-div */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", "osc24M", 0x0038, @@ -109,7 +121,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_gpu_clk, "pll-gpu", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1", "osc24M", 0x044, @@ -118,7 +130,7 @@ static SUNXI_CCU_NK_WITH_GATE_LOCK_POSTDIV(pll_periph1_clk, "pll-periph1", BIT(31), /* gate */ BIT(28), /* lock */ 2, /* post-div */ - 0); + CLK_SET_RATE_UNGATE); static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", "osc24M", 0x0048, @@ -130,7 +142,7 @@ static SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(pll_de_clk, "pll-de", 297000000, /* frac rate 1 */ BIT(31), /* gate */ BIT(28), /* lock */ - 0); + CLK_SET_RATE_UNGATE); static const char * const cpux_parents[] = { "osc32k", "osc24M", "pll-cpux" , "pll-cpux" }; @@ -484,7 +496,7 @@ static SUNXI_CCU_M_WITH_MUX_GATE(mbus_clk, "mbus", mbus_parents, 0x15c, 0, 3, 24, 2, BIT(31), CLK_IS_CRITICAL); static SUNXI_CCU_M_WITH_GATE(gpu_clk, "gpu", "pll-gpu", - 0x1a0, 0, 3, BIT(31), 0); + 0x1a0, 0, 3, BIT(31), CLK_SET_RATE_PARENT); static struct ccu_common *sun8i_h3_ccu_clks[] = { &pll_cpux_clk.common, @@ -707,9 +719,9 @@ static struct ccu_common *sun50i_h5_ccu_clks[] = { &gpu_clk.common, }; -/* We hardcode the divider to 4 for now */ +/* We hardcode the divider to 1 for now */ static CLK_FIXED_FACTOR(pll_audio_clk, "pll-audio", - "pll-audio-base", 4, 1, CLK_SET_RATE_PARENT); + "pll-audio-base", 1, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_2x_clk, "pll-audio-2x", "pll-audio-base", 2, 1, CLK_SET_RATE_PARENT); static CLK_FIXED_FACTOR(pll_audio_4x_clk, "pll-audio-4x", @@ -1129,10 +1141,10 @@ static void __init sunxi_h3_h5_ccu_init(struct device_node *node, return; } - /* Force the PLL-Audio-1x divider to 4 */ + /* Force the PLL-Audio-1x divider to 1 */ val = readl(reg + SUN8I_H3_PLL_AUDIO_REG); val &= ~GENMASK(19, 16); - writel(val | (3 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); + writel(val | (0 << 16), reg + SUN8I_H3_PLL_AUDIO_REG); sunxi_ccu_probe(node, reg, desc); diff --git a/drivers/clk/sunxi-ng/ccu_common.h b/drivers/clk/sunxi-ng/ccu_common.h index cadd1a9f93b6..5d684ce77c54 100644 --- a/drivers/clk/sunxi-ng/ccu_common.h +++ b/drivers/clk/sunxi-ng/ccu_common.h @@ -24,6 +24,7 @@ #define CCU_FEATURE_ALL_PREDIV BIT(4) #define CCU_FEATURE_LOCK_REG BIT(5) #define CCU_FEATURE_MMC_TIMING_SWITCH BIT(6) +#define CCU_FEATURE_SIGMA_DELTA_MOD BIT(7) /* MMC timing mode switch bit */ #define CCU_MMC_NEW_TIMING_MODE BIT(30) diff --git a/drivers/clk/sunxi-ng/ccu_nm.c b/drivers/clk/sunxi-ng/ccu_nm.c index a32158e8f2e3..7620aa973a6e 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.c +++ b/drivers/clk/sunxi-ng/ccu_nm.c @@ -90,6 +90,14 @@ static unsigned long ccu_nm_recalc_rate(struct clk_hw *hw, if (!m) m++; + if (ccu_sdm_helper_is_enabled(&nm->common, &nm->sdm)) { + unsigned long rate = + ccu_sdm_helper_read_rate(&nm->common, &nm->sdm, + m, n); + if (rate) + return rate; + } + return parent_rate * n / m; } @@ -99,6 +107,12 @@ static long ccu_nm_round_rate(struct clk_hw *hw, unsigned long rate, struct ccu_nm *nm = hw_to_ccu_nm(hw); struct _ccu_nm _nm; + if (ccu_frac_helper_has_rate(&nm->common, &nm->frac, rate)) + return rate; + + if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) + return rate; + _nm.min_n = nm->n.min ?: 1; _nm.max_n = nm->n.max ?: 1 << nm->n.width; _nm.min_m = 1; @@ -140,7 +154,16 @@ static int ccu_nm_set_rate(struct clk_hw *hw, unsigned long rate, _nm.min_m = 1; _nm.max_m = nm->m.max ?: 1 << nm->m.width; - ccu_nm_find_best(parent_rate, rate, &_nm); + if (ccu_sdm_helper_has_rate(&nm->common, &nm->sdm, rate)) { + ccu_sdm_helper_enable(&nm->common, &nm->sdm, rate); + + /* Sigma delta modulation requires specific N and M factors */ + ccu_sdm_helper_get_factors(&nm->common, &nm->sdm, rate, + &_nm.m, &_nm.n); + } else { + ccu_sdm_helper_disable(&nm->common, &nm->sdm); + ccu_nm_find_best(parent_rate, rate, &_nm); + } spin_lock_irqsave(nm->common.lock, flags); diff --git a/drivers/clk/sunxi-ng/ccu_nm.h b/drivers/clk/sunxi-ng/ccu_nm.h index e87fd186da78..c623b0c7a23c 100644 --- a/drivers/clk/sunxi-ng/ccu_nm.h +++ b/drivers/clk/sunxi-ng/ccu_nm.h @@ -20,6 +20,7 @@ #include "ccu_div.h" #include "ccu_frac.h" #include "ccu_mult.h" +#include "ccu_sdm.h" /* * struct ccu_nm - Definition of an N-M clock @@ -33,10 +34,34 @@ struct ccu_nm { struct ccu_mult_internal n; struct ccu_div_internal m; struct ccu_frac_internal frac; + struct ccu_sdm_internal sdm; struct ccu_common common; }; +#define SUNXI_CCU_NM_WITH_SDM_GATE_LOCK(_struct, _name, _parent, _reg, \ + _nshift, _nwidth, \ + _mshift, _mwidth, \ + _sdm_table, _sdm_en, \ + _sdm_reg, _sdm_reg_en, \ + _gate, _lock, _flags) \ + struct ccu_nm _struct = { \ + .enable = _gate, \ + .lock = _lock, \ + .n = _SUNXI_CCU_MULT(_nshift, _nwidth), \ + .m = _SUNXI_CCU_DIV(_mshift, _mwidth), \ + .sdm = _SUNXI_CCU_SDM(_sdm_table, _sdm_en, \ + _sdm_reg, _sdm_reg_en),\ + .common = { \ + .reg = _reg, \ + .features = CCU_FEATURE_SIGMA_DELTA_MOD, \ + .hw.init = CLK_HW_INIT(_name, \ + _parent, \ + &ccu_nm_ops, \ + _flags), \ + }, \ + } + #define SUNXI_CCU_NM_WITH_FRAC_GATE_LOCK(_struct, _name, _parent, _reg, \ _nshift, _nwidth, \ _mshift, _mwidth, \ diff --git a/drivers/clk/sunxi-ng/ccu_reset.c b/drivers/clk/sunxi-ng/ccu_reset.c index 1dc4e98ea802..b67149143554 100644 --- a/drivers/clk/sunxi-ng/ccu_reset.c +++ b/drivers/clk/sunxi-ng/ccu_reset.c @@ -60,8 +60,22 @@ static int ccu_reset_reset(struct reset_controller_dev *rcdev, return 0; } +static int ccu_reset_status(struct reset_controller_dev *rcdev, + unsigned long id) +{ + struct ccu_reset *ccu = rcdev_to_ccu_reset(rcdev); + const struct ccu_reset_map *map = &ccu->reset_map[id]; + + /* + * The reset control API expects 0 if reset is not asserted, + * which is the opposite of what our hardware uses. + */ + return !(map->bit & readl(ccu->base + map->reg)); +} + const struct reset_control_ops ccu_reset_ops = { .assert = ccu_reset_assert, .deassert = ccu_reset_deassert, .reset = ccu_reset_reset, + .status = ccu_reset_status, }; diff --git a/drivers/clk/sunxi-ng/ccu_sdm.c b/drivers/clk/sunxi-ng/ccu_sdm.c new file mode 100644 index 000000000000..3b3dc9bdf2b0 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu_sdm.c @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#include <linux/clk-provider.h> +#include <linux/spinlock.h> + +#include "ccu_sdm.h" + +bool ccu_sdm_helper_is_enabled(struct ccu_common *common, + struct ccu_sdm_internal *sdm) +{ + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return false; + + if (sdm->enable && !(readl(common->base + common->reg) & sdm->enable)) + return false; + + return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable); +} + +void ccu_sdm_helper_enable(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate) +{ + unsigned long flags; + unsigned int i; + u32 reg; + + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return; + + /* Set the pattern */ + for (i = 0; i < sdm->table_size; i++) + if (sdm->table[i].rate == rate) + writel(sdm->table[i].pattern, + common->base + sdm->tuning_reg); + + /* Make sure SDM is enabled */ + spin_lock_irqsave(common->lock, flags); + reg = readl(common->base + sdm->tuning_reg); + writel(reg | sdm->tuning_enable, common->base + sdm->tuning_reg); + spin_unlock_irqrestore(common->lock, flags); + + spin_lock_irqsave(common->lock, flags); + reg = readl(common->base + common->reg); + writel(reg | sdm->enable, common->base + common->reg); + spin_unlock_irqrestore(common->lock, flags); +} + +void ccu_sdm_helper_disable(struct ccu_common *common, + struct ccu_sdm_internal *sdm) +{ + unsigned long flags; + u32 reg; + + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return; + + spin_lock_irqsave(common->lock, flags); + reg = readl(common->base + common->reg); + writel(reg & ~sdm->enable, common->base + common->reg); + spin_unlock_irqrestore(common->lock, flags); + + spin_lock_irqsave(common->lock, flags); + reg = readl(common->base + sdm->tuning_reg); + writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg); + spin_unlock_irqrestore(common->lock, flags); +} + +/* + * Sigma delta modulation provides a way to do fractional-N frequency + * synthesis, in essence allowing the PLL to output any frequency + * within its operational range. On earlier SoCs such as the A10/A20, + * some PLLs support this. On later SoCs, all PLLs support this. + * + * The datasheets do not explain what the "wave top" and "wave bottom" + * parameters mean or do, nor how to calculate the effective output + * frequency. The only examples (and real world usage) are for the audio + * PLL to generate 24.576 and 22.5792 MHz clock rates used by the audio + * peripherals. The author lacks the underlying domain knowledge to + * pursue this. + * + * The goal and function of the following code is to support the two + * clock rates used by the audio subsystem, allowing for proper audio + * playback and capture without any pitch or speed changes. + */ +bool ccu_sdm_helper_has_rate(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate) +{ + unsigned int i; + + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return false; + + for (i = 0; i < sdm->table_size; i++) + if (sdm->table[i].rate == rate) + return true; + + return false; +} + +unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + u32 m, u32 n) +{ + unsigned int i; + u32 reg; + + pr_debug("%s: Read sigma-delta modulation setting\n", + clk_hw_get_name(&common->hw)); + + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return 0; + + pr_debug("%s: clock is sigma-delta modulated\n", + clk_hw_get_name(&common->hw)); + + reg = readl(common->base + sdm->tuning_reg); + + pr_debug("%s: pattern reg is 0x%x", + clk_hw_get_name(&common->hw), reg); + + for (i = 0; i < sdm->table_size; i++) + if (sdm->table[i].pattern == reg && + sdm->table[i].m == m && sdm->table[i].n == n) + return sdm->table[i].rate; + + /* We can't calculate the effective clock rate, so just fail. */ + return 0; +} + +int ccu_sdm_helper_get_factors(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate, + unsigned long *m, unsigned long *n) +{ + unsigned int i; + + if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD)) + return -EINVAL; + + for (i = 0; i < sdm->table_size; i++) + if (sdm->table[i].rate == rate) { + *m = sdm->table[i].m; + *n = sdm->table[i].n; + return 0; + } + + /* nothing found */ + return -EINVAL; +} diff --git a/drivers/clk/sunxi-ng/ccu_sdm.h b/drivers/clk/sunxi-ng/ccu_sdm.h new file mode 100644 index 000000000000..2a9b4a2584d6 --- /dev/null +++ b/drivers/clk/sunxi-ng/ccu_sdm.h @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2017 Chen-Yu Tsai. All rights reserved. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _CCU_SDM_H +#define _CCU_SDM_H + +#include <linux/clk-provider.h> + +#include "ccu_common.h" + +struct ccu_sdm_setting { + unsigned long rate; + + /* + * XXX We don't know what the step and bottom register fields + * mean. Just copy the whole register value from the vendor + * kernel for now. + */ + u32 pattern; + + /* + * M and N factors here should be the values used in + * calculation, not the raw values written to registers + */ + u32 m; + u32 n; +}; + +struct ccu_sdm_internal { + struct ccu_sdm_setting *table; + u32 table_size; + /* early SoCs don't have the SDM enable bit in the PLL register */ + u32 enable; + /* second enable bit in tuning register */ + u32 tuning_enable; + u16 tuning_reg; +}; + +#define _SUNXI_CCU_SDM(_table, _enable, \ + _reg, _reg_enable) \ + { \ + .table = _table, \ + .table_size = ARRAY_SIZE(_table), \ + .enable = _enable, \ + .tuning_enable = _reg_enable, \ + .tuning_reg = _reg, \ + } + +bool ccu_sdm_helper_is_enabled(struct ccu_common *common, + struct ccu_sdm_internal *sdm); +void ccu_sdm_helper_enable(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate); +void ccu_sdm_helper_disable(struct ccu_common *common, + struct ccu_sdm_internal *sdm); + +bool ccu_sdm_helper_has_rate(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate); + +unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + u32 m, u32 n); + +int ccu_sdm_helper_get_factors(struct ccu_common *common, + struct ccu_sdm_internal *sdm, + unsigned long rate, + unsigned long *m, unsigned long *n); + +#endif diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c index dfe5e3e32d28..856fef65433b 100644 --- a/drivers/clk/sunxi/clk-factors.c +++ b/drivers/clk/sunxi/clk-factors.c @@ -276,13 +276,11 @@ void sunxi_factors_unregister(struct device_node *node, struct clk *clk) { struct clk_hw *hw = __clk_get_hw(clk); struct clk_factors *factors; - const char *name; if (!hw) return; factors = to_clk_factors(hw); - name = clk_hw_get_name(hw); of_clk_del_provider(node); /* TODO: The composite clock stuff will leak a bit here. */ diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c index 6041bdba2e97..a1a634253d6f 100644 --- a/drivers/clk/sunxi/clk-sun9i-mmc.c +++ b/drivers/clk/sunxi/clk-sun9i-mmc.c @@ -124,7 +124,7 @@ static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev) return PTR_ERR(data->clk); } - data->reset = devm_reset_control_get(&pdev->dev, NULL); + data->reset = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(data->reset)) { dev_err(&pdev->dev, "Could not get reset control\n"); return PTR_ERR(data->reset); diff --git a/drivers/clk/tegra/clk-bpmp.c b/drivers/clk/tegra/clk-bpmp.c index 638ace64033b..a896692b74ec 100644 --- a/drivers/clk/tegra/clk-bpmp.c +++ b/drivers/clk/tegra/clk-bpmp.c @@ -55,6 +55,7 @@ struct tegra_bpmp_clk_message { struct { void *data; size_t size; + int ret; } rx; }; @@ -64,6 +65,7 @@ static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp, struct mrq_clk_request request; struct tegra_bpmp_message msg; void *req = &request; + int err; memset(&request, 0, sizeof(request)); request.cmd_and_id = (clk->cmd << 24) | clk->id; @@ -84,7 +86,13 @@ static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp, msg.rx.data = clk->rx.data; msg.rx.size = clk->rx.size; - return tegra_bpmp_transfer(bpmp, &msg); + err = tegra_bpmp_transfer(bpmp, &msg); + if (err < 0) + return err; + else if (msg.rx.ret < 0) + return -EINVAL; + + return 0; } static int tegra_bpmp_clk_prepare(struct clk_hw *hw) @@ -414,11 +422,8 @@ static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp, struct tegra_bpmp_clk_info *info = &clocks[count]; err = tegra_bpmp_clk_get_info(bpmp, id, info); - if (err < 0) { - dev_err(bpmp->dev, "failed to query clock %u: %d\n", - id, err); + if (err < 0) continue; - } if (info->num_parents >= U8_MAX) { dev_err(bpmp->dev, diff --git a/drivers/clk/tegra/clk-dfll.c b/drivers/clk/tegra/clk-dfll.c index 2c44aeb0b97c..0a7deee74eea 100644 --- a/drivers/clk/tegra/clk-dfll.c +++ b/drivers/clk/tegra/clk-dfll.c @@ -1728,10 +1728,10 @@ EXPORT_SYMBOL(tegra_dfll_register); * @pdev: DFLL platform_device * * * Unbind this driver from the DFLL hardware device represented by - * @pdev. The DFLL must be disabled for this to succeed. Returns 0 - * upon success or -EBUSY if the DFLL is still active. + * @pdev. The DFLL must be disabled for this to succeed. Returns a + * soc pointer upon success or -EBUSY if the DFLL is still active. */ -int tegra_dfll_unregister(struct platform_device *pdev) +struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev) { struct tegra_dfll *td = platform_get_drvdata(pdev); @@ -1739,7 +1739,7 @@ int tegra_dfll_unregister(struct platform_device *pdev) if (td->mode != DFLL_DISABLED) { dev_err(&pdev->dev, "must disable DFLL before removing driver\n"); - return -EBUSY; + return ERR_PTR(-EBUSY); } debugfs_remove_recursive(td->debugfs_dir); @@ -1753,6 +1753,6 @@ int tegra_dfll_unregister(struct platform_device *pdev) reset_control_assert(td->dvco_rst); - return 0; + return td->soc; } EXPORT_SYMBOL(tegra_dfll_unregister); diff --git a/drivers/clk/tegra/clk-dfll.h b/drivers/clk/tegra/clk-dfll.h index ed2ad888268f..83352c8078f2 100644 --- a/drivers/clk/tegra/clk-dfll.h +++ b/drivers/clk/tegra/clk-dfll.h @@ -43,7 +43,7 @@ struct tegra_dfll_soc_data { int tegra_dfll_register(struct platform_device *pdev, struct tegra_dfll_soc_data *soc); -int tegra_dfll_unregister(struct platform_device *pdev); +struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev); int tegra_dfll_runtime_suspend(struct device *dev); int tegra_dfll_runtime_resume(struct device *dev); diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h index 11ee5f9ce99e..b616e33c5255 100644 --- a/drivers/clk/tegra/clk-id.h +++ b/drivers/clk/tegra/clk-id.h @@ -13,6 +13,7 @@ enum clk_id { tegra_clk_amx, tegra_clk_amx1, tegra_clk_apb2ape, + tegra_clk_ahbdma, tegra_clk_apbdma, tegra_clk_apbif, tegra_clk_ape, diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c index cf80831de79d..9475c00b7cf9 100644 --- a/drivers/clk/tegra/clk-periph.c +++ b/drivers/clk/tegra/clk-periph.c @@ -203,3 +203,11 @@ struct clk *tegra_clk_register_periph_nodiv(const char *name, return _tegra_clk_register_periph(name, parent_names, num_parents, periph, clk_base, offset, CLK_SET_RATE_PARENT); } + +struct clk *tegra_clk_register_periph_data(void __iomem *clk_base, + struct tegra_periph_init_data *init) +{ + return _tegra_clk_register_periph(init->name, init->p.parent_names, + init->num_parents, &init->periph, + clk_base, init->offset, init->flags); +} diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c index 848255cc0209..c02711927d79 100644 --- a/drivers/clk/tegra/clk-tegra-periph.c +++ b/drivers/clk/tegra/clk-tegra-periph.c @@ -129,7 +129,6 @@ #define CLK_SOURCE_NVDEC 0x698 #define CLK_SOURCE_NVJPG 0x69c #define CLK_SOURCE_APE 0x6c0 -#define CLK_SOURCE_SOR1 0x410 #define CLK_SOURCE_SDMMC_LEGACY 0x694 #define CLK_SOURCE_QSPI 0x6c4 #define CLK_SOURCE_VI_I2C 0x6c8 @@ -278,7 +277,6 @@ static DEFINE_SPINLOCK(PLLP_OUTA_lock); static DEFINE_SPINLOCK(PLLP_OUTB_lock); static DEFINE_SPINLOCK(PLLP_OUTC_lock); static DEFINE_SPINLOCK(sor0_lock); -static DEFINE_SPINLOCK(sor1_lock); #define MUX_I2S_SPDIF(_id) \ static const char *mux_pllaout0_##_id##_2x_pllp_clkm[] = { "pll_a_out0", \ @@ -604,18 +602,6 @@ static u32 mux_pllp_plld_plld2_clkm_idx[] = { [0] = 0, [1] = 2, [2] = 5, [3] = 6 }; -static const char *mux_sor_safe_sor1_brick_sor1_src[] = { - /* - * Bit 0 of the mux selects sor1_brick, irrespective of bit 1, so the - * sor1_brick parent appears twice in the list below. This is merely - * to support clk_get_parent() if firmware happened to set these bits - * to 0b11. While not an invalid setting, code should always set the - * bits to 0b01 to select sor1_brick. - */ - "sor_safe", "sor1_brick", "sor1_src", "sor1_brick" -}; -#define mux_sor_safe_sor1_brick_sor1_src_idx NULL - static const char *mux_pllp_pllre_clkm[] = { "pll_p", "pll_re_out1", "clk_m" }; @@ -804,8 +790,6 @@ static struct tegra_periph_init_data periph_clks[] = { MUX8("nvdec", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVDEC, 194, 0, tegra_clk_nvdec), MUX8("nvjpg", mux_pllc2_c_c3_pllp_plla1_clkm, CLK_SOURCE_NVJPG, 195, 0, tegra_clk_nvjpg), MUX8("ape", mux_plla_pllc4_out0_pllc_pllc4_out1_pllp_pllc4_out2_clkm, CLK_SOURCE_APE, 198, TEGRA_PERIPH_ON_APB, tegra_clk_ape), - MUX8_NOGATE_LOCK("sor1_src", mux_pllp_plld_plld2_clkm, CLK_SOURCE_SOR1, tegra_clk_sor1_src, &sor1_lock), - NODIV("sor1", mux_sor_safe_sor1_brick_sor1_src, CLK_SOURCE_SOR1, 14, MASK(2), 183, 0, tegra_clk_sor1, &sor1_lock), MUX8("sdmmc_legacy", mux_pllp_out3_clkm_pllp_pllc4, CLK_SOURCE_SDMMC_LEGACY, 193, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_sdmmc_legacy), MUX8("qspi", mux_pllp_pllc_pllc_out1_pllc4_out2_pllc4_out1_clkm_pllc4_out0, CLK_SOURCE_QSPI, 211, TEGRA_PERIPH_ON_APB, tegra_clk_qspi), I2C("vii2c", mux_pllp_pllc_clkm, CLK_SOURCE_VI_I2C, 208, tegra_clk_vi_i2c), @@ -823,7 +807,8 @@ static struct tegra_periph_init_data gate_clks[] = { GATE("timer", "clk_m", 5, 0, tegra_clk_timer, CLK_IS_CRITICAL), GATE("isp", "clk_m", 23, 0, tegra_clk_isp, 0), GATE("vcp", "clk_m", 29, 0, tegra_clk_vcp, 0), - GATE("apbdma", "clk_m", 34, 0, tegra_clk_apbdma, 0), + GATE("ahbdma", "hclk", 33, 0, tegra_clk_ahbdma, 0), + GATE("apbdma", "pclk", 34, 0, tegra_clk_apbdma, 0), GATE("kbc", "clk_32k", 36, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, tegra_clk_kbc, 0), GATE("fuse", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse, 0), GATE("fuse_burn", "clk_m", 39, TEGRA_PERIPH_ON_APB, tegra_clk_fuse_burn, 0), @@ -927,10 +912,7 @@ static void __init periph_clk_init(void __iomem *clk_base, continue; data->periph.gate.regs = bank; - clk = tegra_clk_register_periph(data->name, - data->p.parent_names, data->num_parents, - &data->periph, clk_base, data->offset, - data->flags); + clk = tegra_clk_register_periph_data(clk_base, data); *dt_clk = clk; } } diff --git a/drivers/clk/tegra/clk-tegra-super-gen4.c b/drivers/clk/tegra/clk-tegra-super-gen4.c index 4f6fd307cb70..10047107c1dc 100644 --- a/drivers/clk/tegra/clk-tegra-super-gen4.c +++ b/drivers/clk/tegra/clk-tegra-super-gen4.c @@ -166,7 +166,7 @@ static void __init tegra_sclk_init(void __iomem *clk_base, clk_base + SYSTEM_CLK_RATE, 0, 2, 0, &sysrate_lock); clk = clk_register_gate(NULL, "pclk", "pclk_div", CLK_SET_RATE_PARENT | - CLK_IGNORE_UNUSED, clk_base + SYSTEM_CLK_RATE, + CLK_IS_CRITICAL, clk_base + SYSTEM_CLK_RATE, 3, CLK_GATE_SET_TO_DISABLE, &sysrate_lock); *dt_clk = clk; } diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c index fd1a99c05c2d..63087d17c3e2 100644 --- a/drivers/clk/tegra/clk-tegra114.c +++ b/drivers/clk/tegra/clk-tegra114.c @@ -1092,9 +1092,7 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base, for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, - data->p.parent_names, data->num_parents, - &data->periph, clk_base, data->offset, data->flags); + clk = tegra_clk_register_periph_data(clk_base, data); clks[data->clk_id] = clk; } diff --git a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c index ad1c1cc829cb..269d3595758b 100644 --- a/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c +++ b/drivers/clk/tegra/clk-tegra124-dfll-fcpu.c @@ -125,19 +125,17 @@ static int tegra124_dfll_fcpu_probe(struct platform_device *pdev) return err; } - platform_set_drvdata(pdev, soc); - return 0; } static int tegra124_dfll_fcpu_remove(struct platform_device *pdev) { - struct tegra_dfll_soc_data *soc = platform_get_drvdata(pdev); - int err; + struct tegra_dfll_soc_data *soc; - err = tegra_dfll_unregister(pdev); - if (err < 0) - dev_err(&pdev->dev, "failed to unregister DFLL: %d\n", err); + soc = tegra_dfll_unregister(pdev); + if (IS_ERR(soc)) + dev_err(&pdev->dev, "failed to unregister DFLL: %ld\n", + PTR_ERR(soc)); tegra_cvb_remove_opp_table(soc->dev, soc->cvb, soc->max_freq); diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c index 837e5cbd60e9..cbd5a2e5c569 100644 --- a/drivers/clk/tegra/clk-tegra20.c +++ b/drivers/clk/tegra/clk-tegra20.c @@ -522,6 +522,8 @@ static struct tegra_devclk devclks[] __initdata = { }; static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = { + [tegra_clk_ahbdma] = { .dt_id = TEGRA20_CLK_AHBDMA, .present = true }, + [tegra_clk_apbdma] = { .dt_id = TEGRA20_CLK_APBDMA, .present = true }, [tegra_clk_spdif_out] = { .dt_id = TEGRA20_CLK_SPDIF_OUT, .present = true }, [tegra_clk_spdif_in] = { .dt_id = TEGRA20_CLK_SPDIF_IN, .present = true }, [tegra_clk_sdmmc1] = { .dt_id = TEGRA20_CLK_SDMMC1, .present = true }, @@ -806,11 +808,6 @@ static void __init tegra20_periph_clk_init(void) clk_base, 0, 3, periph_clk_enb_refcnt); clks[TEGRA20_CLK_AC97] = clk; - /* apbdma */ - clk = tegra_clk_register_periph_gate("apbdma", "pclk", 0, clk_base, - 0, 34, periph_clk_enb_refcnt); - clks[TEGRA20_CLK_APBDMA] = clk; - /* emc */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, ARRAY_SIZE(mux_pllmcp_clkm), @@ -850,9 +847,7 @@ static void __init tegra20_periph_clk_init(void) for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, data->p.parent_names, - data->num_parents, &data->periph, - clk_base, data->offset, data->flags); + clk = tegra_clk_register_periph_data(clk_base, data); clks[data->clk_id] = clk; } @@ -1025,7 +1020,7 @@ static struct tegra_clk_init_table init_table[] __initdata = { { TEGRA20_CLK_PLL_P_OUT3, TEGRA20_CLK_CLK_MAX, 72000000, 1 }, { TEGRA20_CLK_PLL_P_OUT4, TEGRA20_CLK_CLK_MAX, 24000000, 1 }, { TEGRA20_CLK_PLL_C, TEGRA20_CLK_CLK_MAX, 600000000, 1 }, - { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 120000000, 1 }, + { TEGRA20_CLK_PLL_C_OUT1, TEGRA20_CLK_CLK_MAX, 216000000, 1 }, { TEGRA20_CLK_SCLK, TEGRA20_CLK_PLL_C_OUT1, 0, 1 }, { TEGRA20_CLK_HCLK, TEGRA20_CLK_CLK_MAX, 0, 1 }, { TEGRA20_CLK_PCLK, TEGRA20_CLK_CLK_MAX, 60000000, 1 }, diff --git a/drivers/clk/tegra/clk-tegra210.c b/drivers/clk/tegra/clk-tegra210.c index 6d7a613f2656..9e6260869eb9 100644 --- a/drivers/clk/tegra/clk-tegra210.c +++ b/drivers/clk/tegra/clk-tegra210.c @@ -40,6 +40,7 @@ #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c +#define CLK_SOURCE_SOR1 0x410 #define PLLC_BASE 0x80 #define PLLC_OUT 0x84 @@ -264,6 +265,7 @@ static DEFINE_SPINLOCK(pll_d_lock); static DEFINE_SPINLOCK(pll_e_lock); static DEFINE_SPINLOCK(pll_re_lock); static DEFINE_SPINLOCK(pll_u_lock); +static DEFINE_SPINLOCK(sor1_lock); static DEFINE_SPINLOCK(emc_lock); /* possible OSC frequencies in Hz */ @@ -2566,8 +2568,8 @@ static int tegra210_enable_pllu(void) reg |= PLL_ENABLE; writel(reg, clk_base + PLLU_BASE); - readl_relaxed_poll_timeout(clk_base + PLLU_BASE, reg, - reg & PLL_BASE_LOCK, 2, 1000); + readl_relaxed_poll_timeout_atomic(clk_base + PLLU_BASE, reg, + reg & PLL_BASE_LOCK, 2, 1000); if (!(reg & PLL_BASE_LOCK)) { pr_err("Timed out waiting for PLL_U to lock\n"); return -ETIMEDOUT; @@ -2628,10 +2630,35 @@ static int tegra210_init_pllu(void) return 0; } +static const char * const sor1_out_parents[] = { + /* + * Bit 0 of the mux selects sor1_pad_clkout, irrespective of bit 1, so + * the sor1_pad_clkout parent appears twice in the list below. This is + * merely to support clk_get_parent() if firmware happened to set + * these bits to 0b11. While not an invalid setting, code should + * always set the bits to 0b01 to select sor1_pad_clkout. + */ + "sor_safe", "sor1_pad_clkout", "sor1", "sor1_pad_clkout", +}; + +static const char * const sor1_parents[] = { + "pll_p", "pll_d_out0", "pll_d2_out0", "clk_m", +}; + +static u32 sor1_parents_idx[] = { 0, 2, 5, 6 }; + +static struct tegra_periph_init_data tegra210_periph[] = { + TEGRA_INIT_DATA_TABLE("sor1", NULL, NULL, sor1_parents, + CLK_SOURCE_SOR1, 29, 0x7, 0, 0, 8, 1, + TEGRA_DIVIDER_ROUND_UP, 183, 0, tegra_clk_sor1, + sor1_parents_idx, 0, &sor1_lock), +}; + static __init void tegra210_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base) { struct clk *clk; + unsigned int i; /* xusb_ss_div2 */ clk = clk_register_fixed_factor(NULL, "xusb_ss_div2", "xusb_ss_src", 0, @@ -2650,6 +2677,12 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 1, 17, 207); clks[TEGRA210_CLK_DPAUX1] = clk; + clk = clk_register_mux_table(NULL, "sor1_out", sor1_out_parents, + ARRAY_SIZE(sor1_out_parents), 0, + clk_base + CLK_SOURCE_SOR1, 14, 0x3, + 0, NULL, &sor1_lock); + clks[TEGRA210_CLK_SOR1_OUT] = clk; + /* pll_d_dsi_out */ clk = clk_register_gate(NULL, "pll_d_dsi_out", "pll_d_out0", 0, clk_base + PLLD_MISC0, 21, 0, &pll_d_lock); @@ -2694,6 +2727,20 @@ static __init void tegra210_periph_clk_init(void __iomem *clk_base, 0, NULL); clks[TEGRA210_CLK_ACLK] = clk; + for (i = 0; i < ARRAY_SIZE(tegra210_periph); i++) { + struct tegra_periph_init_data *init = &tegra210_periph[i]; + struct clk **clkp; + + clkp = tegra_lookup_dt_id(init->clk_id, tegra210_clks); + if (!clkp) { + pr_warn("clock %u not found\n", init->clk_id); + continue; + } + + clk = tegra_clk_register_periph_data(clk_base, init); + *clkp = clk; + } + tegra_periph_clk_init(clk_base, pmc_base, tegra210_clks, &pll_p_params); } diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c index a2d163f759b4..bee84c554932 100644 --- a/drivers/clk/tegra/clk-tegra30.c +++ b/drivers/clk/tegra/clk-tegra30.c @@ -359,7 +359,7 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = { }; /* PLL parameters */ -static struct tegra_clk_pll_params pll_c_params = { +static struct tegra_clk_pll_params pll_c_params __ro_after_init = { .input_min = 2000000, .input_max = 31000000, .cf_min = 1000000, @@ -388,7 +388,7 @@ static struct div_nmp pllm_nmp = { .override_divp_shift = 15, }; -static struct tegra_clk_pll_params pll_m_params = { +static struct tegra_clk_pll_params pll_m_params __ro_after_init = { .input_min = 2000000, .input_max = 31000000, .cf_min = 1000000, @@ -409,7 +409,7 @@ static struct tegra_clk_pll_params pll_m_params = { TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_FIXED, }; -static struct tegra_clk_pll_params pll_p_params = { +static struct tegra_clk_pll_params pll_p_params __ro_after_init = { .input_min = 2000000, .input_max = 31000000, .cf_min = 1000000, @@ -444,7 +444,7 @@ static struct tegra_clk_pll_params pll_a_params = { TEGRA_PLL_HAS_LOCK_ENABLE, }; -static struct tegra_clk_pll_params pll_d_params = { +static struct tegra_clk_pll_params pll_d_params __ro_after_init = { .input_min = 2000000, .input_max = 40000000, .cf_min = 1000000, @@ -461,7 +461,7 @@ static struct tegra_clk_pll_params pll_d_params = { TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, }; -static struct tegra_clk_pll_params pll_d2_params = { +static struct tegra_clk_pll_params pll_d2_params __ro_after_init = { .input_min = 2000000, .input_max = 40000000, .cf_min = 1000000, @@ -478,7 +478,7 @@ static struct tegra_clk_pll_params pll_d2_params = { TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, }; -static struct tegra_clk_pll_params pll_u_params = { +static struct tegra_clk_pll_params pll_u_params __ro_after_init = { .input_min = 2000000, .input_max = 40000000, .cf_min = 1000000, @@ -496,7 +496,7 @@ static struct tegra_clk_pll_params pll_u_params = { TEGRA_PLL_HAS_LOCK_ENABLE, }; -static struct tegra_clk_pll_params pll_x_params = { +static struct tegra_clk_pll_params pll_x_params __ro_after_init = { .input_min = 2000000, .input_max = 31000000, .cf_min = 1000000, @@ -513,7 +513,7 @@ static struct tegra_clk_pll_params pll_x_params = { TEGRA_PLL_USE_LOCK | TEGRA_PLL_HAS_LOCK_ENABLE, }; -static struct tegra_clk_pll_params pll_e_params = { +static struct tegra_clk_pll_params pll_e_params __ro_after_init = { .input_min = 12000000, .input_max = 216000000, .cf_min = 12000000, @@ -788,6 +788,7 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = { [tegra_clk_extern3] = { .dt_id = TEGRA30_CLK_EXTERN3, .present = true }, [tegra_clk_disp1] = { .dt_id = TEGRA30_CLK_DISP1, .present = true }, [tegra_clk_disp2] = { .dt_id = TEGRA30_CLK_DISP2, .present = true }, + [tegra_clk_ahbdma] = { .dt_id = TEGRA30_CLK_AHBDMA, .present = true }, [tegra_clk_apbdma] = { .dt_id = TEGRA30_CLK_APBDMA, .present = true }, [tegra_clk_rtc] = { .dt_id = TEGRA30_CLK_RTC, .present = true }, [tegra_clk_timer] = { .dt_id = TEGRA30_CLK_TIMER, .present = true }, @@ -964,7 +965,7 @@ static void __init tegra30_super_clk_init(void) * U71 divider of cclk_lp. */ clk = tegra_clk_register_divider("pll_p_out3_cclklp", "pll_p_out3", - clk_base + SUPER_CCLKG_DIVIDER, 0, + clk_base + SUPER_CCLKLP_DIVIDER, 0, TEGRA_DIVIDER_INT, 16, 8, 1, NULL); clk_register_clkdev(clk, "pll_p_out3_cclklp", NULL); @@ -1079,9 +1080,7 @@ static void __init tegra30_periph_clk_init(void) for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) { data = &tegra_periph_clk_list[i]; - clk = tegra_clk_register_periph(data->name, data->p.parent_names, - data->num_parents, &data->periph, - clk_base, data->offset, data->flags); + clk = tegra_clk_register_periph_data(clk_base, data); clks[data->clk_id] = clk; } diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index 872f1189ad7f..3b2763df51c2 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -662,6 +662,9 @@ struct tegra_periph_init_data { _clk_num, _gate_flags, _clk_id,\ NULL, 0, NULL) +struct clk *tegra_clk_register_periph_data(void __iomem *clk_base, + struct tegra_periph_init_data *init); + /** * struct clk_super_mux - super clock * diff --git a/drivers/clk/ti/clk-dra7-atl.c b/drivers/clk/ti/clk-dra7-atl.c index 13eb04f72389..148815470431 100644 --- a/drivers/clk/ti/clk-dra7-atl.c +++ b/drivers/clk/ti/clk-dra7-atl.c @@ -274,8 +274,7 @@ static int of_dra7_atl_clk_probe(struct platform_device *pdev) /* Get configuration for the ATL instances */ snprintf(prop, sizeof(prop), "atl%u", i); - of_node_get(node); - cfg_node = of_find_node_by_name(node, prop); + cfg_node = of_get_child_by_name(node, prop); if (cfg_node) { ret = of_property_read_u32(cfg_node, "bws", &cdesc->bws); diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c index 88f04a4cb890..77f93f6d2806 100644 --- a/drivers/clk/ti/divider.c +++ b/drivers/clk/ti/divider.c @@ -292,10 +292,8 @@ static struct clk *_register_divider(struct device *dev, const char *name, /* allocate the divider */ div = kzalloc(sizeof(*div), GFP_KERNEL); - if (!div) { - pr_err("%s: could not allocate divider clk\n", __func__); + if (!div) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &ti_clk_divider_ops; diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c index 18c267b38461..d4705803f3d3 100644 --- a/drivers/clk/ti/mux.c +++ b/drivers/clk/ti/mux.c @@ -108,10 +108,8 @@ static struct clk *_register_mux(struct device *dev, const char *name, /* allocate the mux */ mux = kzalloc(sizeof(*mux), GFP_KERNEL); - if (!mux) { - pr_err("%s: could not allocate mux clk\n", __func__); + if (!mux) return ERR_PTR(-ENOMEM); - } init.name = name; init.ops = &ti_clk_mux_ops; diff --git a/drivers/clk/uniphier/clk-uniphier-mio.c b/drivers/clk/uniphier/clk-uniphier-mio.c index 16e4d303f535..badc478a86c6 100644 --- a/drivers/clk/uniphier/clk-uniphier-mio.c +++ b/drivers/clk/uniphier/clk-uniphier-mio.c @@ -13,6 +13,8 @@ * GNU General Public License for more details. */ +#include <linux/stddef.h> + #include "clk-uniphier.h" #define UNIPHIER_MIO_CLK_SD_FIXED \ @@ -73,15 +75,12 @@ #define UNIPHIER_MIO_CLK_USB2_PHY(idx, ch) \ UNIPHIER_CLK_GATE("usb2" #ch "-phy", (idx), "usb2", 0x20 + 0x200 * (ch), 29) -#define UNIPHIER_MIO_CLK_DMAC(idx) \ - UNIPHIER_CLK_GATE("miodmac", (idx), "stdmac", 0x20, 25) - const struct uniphier_clk_data uniphier_ld4_mio_clk_data[] = { UNIPHIER_MIO_CLK_SD_FIXED, UNIPHIER_MIO_CLK_SD(0, 0), UNIPHIER_MIO_CLK_SD(1, 1), UNIPHIER_MIO_CLK_SD(2, 2), - UNIPHIER_MIO_CLK_DMAC(7), + UNIPHIER_CLK_GATE("miodmac", 7, NULL, 0x20, 25), UNIPHIER_MIO_CLK_USB2(8, 0), UNIPHIER_MIO_CLK_USB2(9, 1), UNIPHIER_MIO_CLK_USB2(10, 2), diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c index 07f3b91a7daf..d244e724e198 100644 --- a/drivers/clk/uniphier/clk-uniphier-sys.c +++ b/drivers/clk/uniphier/clk-uniphier-sys.c @@ -123,7 +123,7 @@ const struct uniphier_clk_data uniphier_sld8_sys_clk_data[] = { const struct uniphier_clk_data uniphier_pro5_sys_clk_data[] = { UNIPHIER_CLK_FACTOR("spll", -1, "ref", 120, 1), /* 2400 MHz */ UNIPHIER_CLK_FACTOR("dapll1", -1, "ref", 128, 1), /* 2560 MHz */ - UNIPHIER_CLK_FACTOR("dapll2", -1, "ref", 144, 125), /* 2949.12 MHz */ + UNIPHIER_CLK_FACTOR("dapll2", -1, "dapll1", 144, 125), /* 2949.12 MHz */ UNIPHIER_CLK_FACTOR("uart", 0, "dapll2", 1, 40), UNIPHIER_CLK_FACTOR("i2c", 1, "spll", 1, 48), UNIPHIER_PRO5_SYS_CLK_NAND(2), diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c index f50592775c9d..7cfb59c9136d 100644 --- a/drivers/clk/ux500/clk-prcc.c +++ b/drivers/clk/ux500/clk-prcc.c @@ -107,11 +107,9 @@ static struct clk *clk_reg_prcc(const char *name, return ERR_PTR(-EINVAL); } - clk = kzalloc(sizeof(struct clk_prcc), GFP_KERNEL); - if (!clk) { - pr_err("clk_prcc: %s could not allocate clk\n", __func__); + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) return ERR_PTR(-ENOMEM); - } clk->base = ioremap(phy_base, SZ_4K); if (!clk->base) diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c index 6e3e16b2e5ca..9d1f2d4550ad 100644 --- a/drivers/clk/ux500/clk-prcmu.c +++ b/drivers/clk/ux500/clk-prcmu.c @@ -258,11 +258,9 @@ static struct clk *clk_reg_prcmu(const char *name, return ERR_PTR(-EINVAL); } - clk = kzalloc(sizeof(struct clk_prcmu), GFP_KERNEL); - if (!clk) { - pr_err("clk_prcmu: %s could not allocate clk\n", __func__); + clk = kzalloc(sizeof(*clk), GFP_KERNEL); + if (!clk) return ERR_PTR(-ENOMEM); - } clk->cg_sel = cg_sel; clk->is_prepared = 1; diff --git a/drivers/clk/ux500/clk-sysctrl.c b/drivers/clk/ux500/clk-sysctrl.c index 8a4e93ce1e42..7c0403b733ae 100644 --- a/drivers/clk/ux500/clk-sysctrl.c +++ b/drivers/clk/ux500/clk-sysctrl.c @@ -139,11 +139,9 @@ static struct clk *clk_reg_sysctrl(struct device *dev, return ERR_PTR(-EINVAL); } - clk = devm_kzalloc(dev, sizeof(struct clk_sysctrl), GFP_KERNEL); - if (!clk) { - dev_err(dev, "clk_sysctrl: could not allocate clk\n"); + clk = devm_kzalloc(dev, sizeof(*clk), GFP_KERNEL); + if (!clk) return ERR_PTR(-ENOMEM); - } /* set main clock registers */ clk->reg_sel[0] = reg_sel[0]; diff --git a/drivers/clk/versatile/clk-icst.c b/drivers/clk/versatile/clk-icst.c index 09fbe66f1f11..dafe7a45875d 100644 --- a/drivers/clk/versatile/clk-icst.c +++ b/drivers/clk/versatile/clk-icst.c @@ -359,16 +359,13 @@ static struct clk *icst_clk_setup(struct device *dev, struct clk_init_data init; struct icst_params *pclone; - icst = kzalloc(sizeof(struct clk_icst), GFP_KERNEL); - if (!icst) { - pr_err("could not allocate ICST clock!\n"); + icst = kzalloc(sizeof(*icst), GFP_KERNEL); + if (!icst) return ERR_PTR(-ENOMEM); - } pclone = kmemdup(desc->params, sizeof(*pclone), GFP_KERNEL); if (!pclone) { kfree(icst); - pr_err("could not clone ICST params\n"); return ERR_PTR(-ENOMEM); } |