diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-21 09:24:09 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-04-21 09:24:09 -0700 |
commit | e98bf5cedf25eb32f8f224e8dff9845f0856d18f (patch) | |
tree | f8a33eb26cb9d47bfbb36e50de7ad85081cc349e /drivers/clk | |
parent | 8f443e2372ba23d51ee365974f54507acd6f69d1 (diff) | |
parent | 03bc10ab5b0f9b8f81bffbe6e40c944f9d3dbcc5 (diff) |
Merge tag 'clk-for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
Pull clock framework updates from Michael Turquette:
"The changes to the common clock framework for 4.0 are mostly new clock
drivers and updates to existing ones for feature enhancements and bug
fixes.
There is more churn than usual in the framework core due to the change
to introduce per-user unique struct clk pointers in 4.0. This caused
several regressions to surface, some of which were sent as fixes to
4.0. New generic clock drivers were added for GPIO- and PWM-based
clock controllers.
Additionally the common clk-divider code recieved several fixes to the
way it rounds rates"
* tag 'clk-for-linus-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (91 commits)
clk: check ->determine/round_rate() return value in clk_calc_new_rates
clk: at91: usb: propagate rate modification to the parent clk
clk: samsung: exynos4: Disable ARMCLK down feature on Exynos4210 SoC
clk: don't use __initconst for non-const arrays
clk: at91: change to using endian agnositc IO
clk: clk-gpio-gate: Fix active low
clk: Add PWM clock driver
clk: Add clock driver for mb86s7x
clk: pxa: pxa3xx: add missing os timer clock
clk: tegra: Use the proper parent for plld_dsi
clk: tegra: Use generic tegra_osc_clk_init() on Tegra114
clk: tegra: Model oscillator as clock
clk: tegra: Add peripheral registers for bank Y
clk: tegra: Register the proper number of resets
clk: tegra: Remove needless initializations
clk: tegra: Use consistent indentation
clk: tegra: Various whitespace cleanups
clk: tegra: Enable HDA to HDMI clocks on Tegra124
clk: tegra: Fix a bunch of sparse warnings
clk: tegra: Fix typo tabel -> table
...
Diffstat (limited to 'drivers/clk')
89 files changed, 10735 insertions, 833 deletions
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index 0b474a04730f..9897f353bf1a 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -130,6 +130,13 @@ config COMMON_CLK_PALMAS This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO using common clock framework. +config COMMON_CLK_PWM + tristate "Clock driver for PWMs used as clock outputs" + depends on PWM + ---help--- + Adapter driver so that any PWM output can be (mis)used as clock signal + at 50% duty cycle. + config COMMON_CLK_PXA def_bool COMMON_CLK && ARCH_PXA ---help--- diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile index e43ff53f85a6..3d00c25382c5 100644 --- a/drivers/clk/Makefile +++ b/drivers/clk/Makefile @@ -28,6 +28,7 @@ obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_COMMON_CLK_MAX_GEN) += clk-max-gen.o obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o obj-$(CONFIG_COMMON_CLK_MAX77802) += clk-max77802.o +obj-$(CONFIG_ARCH_MB86S7X) += clk-mb86s7x.o obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o @@ -42,6 +43,7 @@ obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o +obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ obj-$(CONFIG_ARCH_BERLIN) += berlin/ diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c index a23ac0c724f0..0b7c3e8840ba 100644 --- a/drivers/clk/at91/clk-usb.c +++ b/drivers/clk/at91/clk-usb.c @@ -56,22 +56,55 @@ static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk_hw *hw, return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1)); } -static long at91sam9x5_clk_usb_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static long at91sam9x5_clk_usb_determine_rate(struct clk_hw *hw, + unsigned long rate, + unsigned long min_rate, + unsigned long max_rate, + unsigned long *best_parent_rate, + struct clk_hw **best_parent_hw) { - unsigned long div; + struct clk *parent = NULL; + long best_rate = -EINVAL; + unsigned long tmp_rate; + int best_diff = -1; + int tmp_diff; + int i; - if (!rate) - return -EINVAL; + for (i = 0; i < __clk_get_num_parents(hw->clk); i++) { + int div; - if (rate >= *parent_rate) - return *parent_rate; + parent = clk_get_parent_by_index(hw->clk, i); + if (!parent) + continue; + + for (div = 1; div < SAM9X5_USB_MAX_DIV + 2; div++) { + unsigned long tmp_parent_rate; + + tmp_parent_rate = rate * div; + tmp_parent_rate = __clk_round_rate(parent, + tmp_parent_rate); + tmp_rate = DIV_ROUND_CLOSEST(tmp_parent_rate, div); + if (tmp_rate < rate) + tmp_diff = rate - tmp_rate; + else + tmp_diff = tmp_rate - rate; + + if (best_diff < 0 || best_diff > tmp_diff) { + best_rate = tmp_rate; + best_diff = tmp_diff; + *best_parent_rate = tmp_parent_rate; + *best_parent_hw = __clk_get_hw(parent); + } + + if (!best_diff || tmp_rate < rate) + break; + } - div = DIV_ROUND_CLOSEST(*parent_rate, rate); - if (div > SAM9X5_USB_MAX_DIV + 1) - div = SAM9X5_USB_MAX_DIV + 1; + if (!best_diff) + break; + } - return DIV_ROUND_CLOSEST(*parent_rate, div); + return best_rate; } static int at91sam9x5_clk_usb_set_parent(struct clk_hw *hw, u8 index) @@ -121,7 +154,7 @@ static int at91sam9x5_clk_usb_set_rate(struct clk_hw *hw, unsigned long rate, static const struct clk_ops at91sam9x5_usb_ops = { .recalc_rate = at91sam9x5_clk_usb_recalc_rate, - .round_rate = at91sam9x5_clk_usb_round_rate, + .determine_rate = at91sam9x5_clk_usb_determine_rate, .get_parent = at91sam9x5_clk_usb_get_parent, .set_parent = at91sam9x5_clk_usb_set_parent, .set_rate = at91sam9x5_clk_usb_set_rate, @@ -159,7 +192,7 @@ static const struct clk_ops at91sam9n12_usb_ops = { .disable = at91sam9n12_clk_usb_disable, .is_enabled = at91sam9n12_clk_usb_is_enabled, .recalc_rate = at91sam9x5_clk_usb_recalc_rate, - .round_rate = at91sam9x5_clk_usb_round_rate, + .determine_rate = at91sam9x5_clk_usb_determine_rate, .set_rate = at91sam9x5_clk_usb_set_rate, }; @@ -179,7 +212,8 @@ at91sam9x5_clk_register_usb(struct at91_pmc *pmc, const char *name, init.ops = &at91sam9x5_usb_ops; init.parent_names = parent_names; init.num_parents = num_parents; - init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; + init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | + CLK_SET_RATE_PARENT; usb->hw.init = &init; usb->pmc = pmc; @@ -207,7 +241,7 @@ at91sam9n12_clk_register_usb(struct at91_pmc *pmc, const char *name, init.ops = &at91sam9n12_usb_ops; init.parent_names = &parent_name; init.num_parents = 1; - init.flags = CLK_SET_RATE_GATE; + init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; usb->hw.init = &init; usb->pmc = pmc; diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c index c386ad25beb4..b8e4f8a822e9 100644 --- a/drivers/clk/clk-cdce706.c +++ b/drivers/clk/clk-cdce706.c @@ -58,7 +58,7 @@ #define CDCE706_CLKOUT_DIVIDER_MASK 0x7 #define CDCE706_CLKOUT_ENABLE_MASK 0x8 -static struct regmap_config cdce706_regmap_config = { +static const struct regmap_config cdce706_regmap_config = { .reg_bits = 8, .val_bits = 8, .val_format_endian = REGMAP_ENDIAN_NATIVE, diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index aad4796aa3ed..48a65b2b4027 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -13,7 +13,6 @@ #include <linux/device.h> #include <linux/of.h> #include <linux/printk.h> -#include "clk.h" static int __set_clk_parents(struct device_node *node, bool clk_supplier) { @@ -39,7 +38,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) } if (clkspec.np == node && !clk_supplier) return 0; - pclk = of_clk_get_by_clkspec(&clkspec); + pclk = of_clk_get_from_provider(&clkspec); if (IS_ERR(pclk)) { pr_warn("clk: couldn't get parent clock %d for %s\n", index, node->full_name); @@ -54,7 +53,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) rc = 0; goto err; } - clk = of_clk_get_by_clkspec(&clkspec); + clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { pr_warn("clk: couldn't get parent clock %d for %s\n", index, node->full_name); @@ -98,7 +97,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) if (clkspec.np == node && !clk_supplier) return 0; - clk = of_clk_get_by_clkspec(&clkspec); + clk = of_clk_get_from_provider(&clkspec); if (IS_ERR(clk)) { pr_warn("clk: couldn't get clock %d for %s\n", index, node->full_name); diff --git a/drivers/clk/clk-fractional-divider.c b/drivers/clk/clk-fractional-divider.c index 82a59d0086cc..6aa72d9d79ba 100644 --- a/drivers/clk/clk-fractional-divider.c +++ b/drivers/clk/clk-fractional-divider.c @@ -36,6 +36,9 @@ static unsigned long clk_fd_recalc_rate(struct clk_hw *hw, m = (val & fd->mmask) >> fd->mshift; n = (val & fd->nmask) >> fd->nshift; + if (!n || !m) + return parent_rate; + ret = (u64)parent_rate * m; do_div(ret, n); diff --git a/drivers/clk/clk-gpio-gate.c b/drivers/clk/clk-gpio-gate.c index 08e43224fd52..a71cabedda93 100644 --- a/drivers/clk/clk-gpio-gate.c +++ b/drivers/clk/clk-gpio-gate.c @@ -65,10 +65,12 @@ EXPORT_SYMBOL_GPL(clk_gpio_gate_ops); * @dev: device that is registering this clock * @name: name of this clock * @parent_name: name of this clock's parent - * @gpiod: gpio descriptor to gate this clock + * @gpio: gpio number to gate this clock + * @active_low: true if gpio should be set to 0 to enable clock + * @flags: clock flags */ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, - const char *parent_name, struct gpio_desc *gpiod, + const char *parent_name, unsigned gpio, bool active_low, unsigned long flags) { struct clk_gpio *clk_gpio = NULL; @@ -77,20 +79,19 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, unsigned long gpio_flags; int err; - if (gpiod_is_active_low(gpiod)) - gpio_flags = GPIOF_OUT_INIT_HIGH; + 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, desc_to_gpio(gpiod), - gpio_flags, name); + err = devm_gpio_request_one(dev, gpio, gpio_flags, name); else - err = gpio_request_one(desc_to_gpio(gpiod), gpio_flags, name); + err = gpio_request_one(gpio, gpio_flags, name); if (err) { pr_err("%s: %s: Error requesting clock control gpio %u\n", - __func__, name, desc_to_gpio(gpiod)); + __func__, name, gpio); return ERR_PTR(err); } @@ -111,7 +112,7 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, init.parent_names = (parent_name ? &parent_name : NULL); init.num_parents = (parent_name ? 1 : 0); - clk_gpio->gpiod = gpiod; + clk_gpio->gpiod = gpio_to_desc(gpio); clk_gpio->hw.init = &init; clk = clk_register(dev, &clk_gpio->hw); @@ -123,7 +124,8 @@ struct clk *clk_register_gpio_gate(struct device *dev, const char *name, kfree(clk_gpio); clk_register_gpio_gate_err: - gpiod_put(gpiod); + if (!dev) + gpio_free(gpio); return clk; } @@ -149,8 +151,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( struct clk *clk; const char *clk_name = data->node->name; const char *parent_name; - struct gpio_desc *gpiod; int gpio; + enum of_gpio_flags of_flags; mutex_lock(&data->lock); @@ -159,7 +161,8 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( return data->clk; } - gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, NULL); + gpio = of_get_named_gpio_flags(data->node, "enable-gpios", 0, + &of_flags); if (gpio < 0) { mutex_unlock(&data->lock); if (gpio != -EPROBE_DEFER) @@ -167,11 +170,11 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( __func__, clk_name); return ERR_PTR(gpio); } - gpiod = gpio_to_desc(gpio); parent_name = of_clk_get_parent_name(data->node, 0); - clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpiod, 0); + clk = clk_register_gpio_gate(NULL, clk_name, parent_name, gpio, + of_flags & OF_GPIO_ACTIVE_LOW, 0); if (IS_ERR(clk)) { mutex_unlock(&data->lock); return clk; diff --git a/drivers/clk/clk-mb86s7x.c b/drivers/clk/clk-mb86s7x.c new file mode 100644 index 000000000000..f39c25a22f43 --- /dev/null +++ b/drivers/clk/clk-mb86s7x.c @@ -0,0 +1,386 @@ +/* + * Copyright (C) 2013-2015 FUJITSU SEMICONDUCTOR LIMITED + * Copyright (C) 2015 Linaro Ltd. + * + * 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. + * + * 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/clkdev.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/of.h> +#include <linux/cpu.h> +#include <linux/clk-provider.h> +#include <linux/spinlock.h> +#include <linux/module.h> +#include <linux/topology.h> +#include <linux/mailbox_client.h> +#include <linux/platform_device.h> + +#include <soc/mb86s7x/scb_mhu.h> + +#define to_crg_clk(p) container_of(p, struct crg_clk, hw) +#define to_clc_clk(p) container_of(p, struct cl_clk, hw) + +struct mb86s7x_peri_clk { + |