diff options
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); } |