summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 11:44:20 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2014-08-04 11:44:20 -0700
commite4ca4308c055c7bfb82f6756297346760d697953 (patch)
tree886a5a0ab7184e799fdabdf91609bc25a2c12731 /drivers
parente17acfdc83b877794c119fac4627e80510ea3c09 (diff)
parentb11a6face1b6d5518319f797a74e22bb4309daa9 (diff)
Merge tag 'clk-for-linus-3.17' of git://git.linaro.org/people/mike.turquette/linux
Pull clock framework updates from Mike Turquette: "The clock framework changes for 3.17 are mostly additions of new clock drivers and fixes/enhancements to existing clock drivers. There are also some non-critical fixes and improvements to the framework core. Changes to the clock framework core include: - improvements to printks on errors - flattening the previously hierarchal structure of per-clock entries in debugfs - allow per-clock debugfs entries that are specific to a particular clock driver - configure initial clock parent and/or initial clock rate from Device Tree - several feature enhancements to the composite clock type - misc fixes New clock drivers added include: - TI Palmas PMIC - Allwinner A23 SoC - Qualcomm APQ8084 and IPQ8064 SoCs - Rockchip rk3188, rk3066 and rk3288 SoCs - STMicroelectronics STiH407 SoC - Cirrus Logic CLPS711X SoC Many fixes, feature enhancements and further clock tree support for existing clock drivers also were merged, such as Samsung's "ARMCLK down" power saving feature for their Exynos4 & Exynos5 SoCs" * tag 'clk-for-linus-3.17' of git://git.linaro.org/people/mike.turquette/linux: (86 commits) clk: Add missing of_clk_set_defaults export clk: checking wrong variable in __set_clk_parents() clk: Propagate any error return from debug_init() clk: clps711x: Add DT bindings documentation clk: Add CLPS711X clk driver clk: st: Use round to closest divider flag clk: st: Update frequency tables for fs660c32 and fs432c65 clk: st: STiH407: Support for clockgenA9 clk: st: STiH407: Support for clockgenD0/D2/D3 clk: st: STiH407: Support for clockgenC0 clk: st: Add quadfs reset handling clk: st: Add polarity bit indication clk: st: STiH407: Support for clockgenA0 clk: st: STiH407: Support for A9 MUX Clocks clk: st: STiH407: Support for Flexgen Clocks clk: st: Adds Flexgen clock binding clk: st: Remove uncessary (void *) cast clk: st: use static const for clkgen_pll_data tables clk: st: use static const for stm_fs tables clk: st: Update ST clock binding documentation ...
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/platform.c5
-rw-r--r--drivers/clk/Kconfig7
-rw-r--r--drivers/clk/Makefile5
-rw-r--r--drivers/clk/at91/clk-main.c1
-rw-r--r--drivers/clk/clk-clps711x.c192
-rw-r--r--drivers/clk/clk-composite.c79
-rw-r--r--drivers/clk/clk-conf.c144
-rw-r--r--drivers/clk/clk-palmas.c307
-rw-r--r--drivers/clk/clk-ppc-corenet.c2
-rw-r--r--drivers/clk/clk-s2mps11.c33
-rw-r--r--drivers/clk/clk.c134
-rw-r--r--drivers/clk/clkdev.c5
-rw-r--r--drivers/clk/qcom/Kconfig25
-rw-r--r--drivers/clk/qcom/Makefile3
-rw-r--r--drivers/clk/qcom/clk-pll.c15
-rw-r--r--drivers/clk/qcom/clk-pll.h2
-rw-r--r--drivers/clk/qcom/clk-rcg.c51
-rw-r--r--drivers/clk/qcom/clk-rcg.h1
-rw-r--r--drivers/clk/qcom/common.c39
-rw-r--r--drivers/clk/qcom/common.h6
-rw-r--r--drivers/clk/qcom/gcc-apq8084.c3611
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c2424
-rw-r--r--drivers/clk/qcom/gcc-msm8960.c583
-rw-r--r--drivers/clk/qcom/mmcc-apq8084.c3352
-rw-r--r--drivers/clk/qcom/mmcc-msm8960.c526
-rw-r--r--drivers/clk/qcom/mmcc-msm8974.c10
-rw-r--r--drivers/clk/rockchip/Makefile6
-rw-r--r--drivers/clk/rockchip/clk-pll.c431
-rw-r--r--drivers/clk/rockchip/clk-rk3188.c672
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c717
-rw-r--r--drivers/clk/rockchip/clk.c244
-rw-r--r--drivers/clk/rockchip/clk.h347
-rw-r--r--drivers/clk/rockchip/softrst.c118
-rw-r--r--drivers/clk/samsung/Makefile1
-rw-r--r--drivers/clk/samsung/clk-exynos-clkout.c153
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c43
-rw-r--r--drivers/clk/samsung/clk-exynos4.c231
-rw-r--r--drivers/clk/samsung/clk-exynos5250.c4
-rw-r--r--drivers/clk/samsung/clk-exynos5260.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5410.c2
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c61
-rw-r--r--drivers/clk/samsung/clk-exynos5440.c4
-rw-r--r--drivers/clk/samsung/clk-s3c2410.c2
-rw-r--r--drivers/clk/samsung/clk-s3c2412.c2
-rw-r--r--drivers/clk/samsung/clk-s3c2443.c2
-rw-r--r--drivers/clk/samsung/clk-s3c64xx.c2
-rw-r--r--drivers/clk/samsung/clk.c21
-rw-r--r--drivers/clk/samsung/clk.h4
-rw-r--r--drivers/clk/spear/spear1310_clock.c6
-rw-r--r--drivers/clk/spear/spear1340_clock.c2
-rw-r--r--drivers/clk/st/Makefile2
-rw-r--r--drivers/clk/st/clk-flexgen.c331
-rw-r--r--drivers/clk/st/clkgen-fsyn.c223
-rw-r--r--drivers/clk/st/clkgen-mux.c12
-rw-r--r--drivers/clk/st/clkgen-pll.c94
-rw-r--r--drivers/clk/sunxi/Makefile4
-rw-r--r--drivers/clk/sunxi/clk-a20-gmac.c2
-rw-r--r--drivers/clk/sunxi/clk-factors.c2
-rw-r--r--drivers/clk/sunxi/clk-factors.h1
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0-gates.c76
-rw-r--r--drivers/clk/sunxi/clk-sun6i-apb0.c2
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c4
-rw-r--r--drivers/clk/sunxi/clk-sun8i-apb0.c68
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c129
-rw-r--r--drivers/clk/tegra/clk-pll.c19
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c4
-rw-r--r--drivers/clk/tegra/clk-tegra114.c31
-rw-r--r--drivers/clk/tegra/clk-tegra124.c10
-rw-r--r--drivers/clk/tegra/clk.c6
-rw-r--r--drivers/clk/ti/clk-7xx.c11
-rw-r--r--drivers/i2c/i2c-core.c5
-rw-r--r--drivers/spi/spi.c5
72 files changed, 15355 insertions, 325 deletions
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index eee48c49f5de..00f2208949d1 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -23,6 +23,7 @@
#include <linux/pm_runtime.h>
#include <linux/idr.h>
#include <linux/acpi.h>
+#include <linux/clk/clk-conf.h>
#include "base.h"
#include "power/power.h"
@@ -499,6 +500,10 @@ static int platform_drv_probe(struct device *_dev)
struct platform_device *dev = to_platform_device(_dev);
int ret;
+ ret = of_clk_set_defaults(_dev->of_node, false);
+ if (ret < 0)
+ return ret;
+
acpi_dev_pm_attach(_dev, true);
ret = drv->probe(dev);
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 9f9c5ae5359b..cfd3af7b2cbd 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -102,6 +102,13 @@ config COMMON_CLK_KEYSTONE
Supports clock drivers for Keystone based SOCs. These SOCs have local
a power sleep control module that gate the clock to the IPs and PLLs.
+config COMMON_CLK_PALMAS
+ tristate "Clock driver for TI Palmas devices"
+ depends on MFD_PALMAS
+ ---help---
+ This driver supports TI Palmas devices 32KHz output KG and KG_AUDIO
+ using common clock framework.
+
source "drivers/clk/qcom/Kconfig"
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 567f10259029..f537a0b1f798 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -9,12 +9,16 @@ obj-$(CONFIG_COMMON_CLK) += clk-gate.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
+ifeq ($(CONFIG_OF), y)
+obj-$(CONFIG_COMMON_CLK) += clk-conf.o
+endif
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
@@ -22,6 +26,7 @@ obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
+obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
index 733306131b99..59fa3cc96c9e 100644
--- a/drivers/clk/at91/clk-main.c
+++ b/drivers/clk/at91/clk-main.c
@@ -388,6 +388,7 @@ static unsigned long clk_main_recalc_rate(struct at91_pmc *pmc,
if (parent_rate)
return parent_rate;
+ pr_warn("Main crystal frequency not set, using approximate value\n");
tmp = pmc_read(pmc, AT91_CKGR_MCFR);
if (!(tmp & AT91_PMC_MAINRDY))
return 0;
diff --git a/drivers/clk/clk-clps711x.c b/drivers/clk/clk-clps711x.c
new file mode 100644
index 000000000000..715eec1a9902
--- /dev/null
+++ b/drivers/clk/clk-clps711x.c
@@ -0,0 +1,192 @@
+/*
+ * Cirrus Logic CLPS711X CLK driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * 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.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+#include <linux/mfd/syscon/clps711x.h>
+
+#include <dt-bindings/clock/clps711x-clock.h>
+
+#define CLPS711X_SYSCON1 (0x0100)
+#define CLPS711X_SYSCON2 (0x1100)
+#define CLPS711X_SYSFLG2 (CLPS711X_SYSCON2 + SYSFLG_OFFSET)
+#define CLPS711X_PLLR (0xa5a8)
+
+#define CLPS711X_EXT_FREQ (13000000)
+#define CLPS711X_OSC_FREQ (3686400)
+
+static const struct clk_div_table spi_div_table[] = {
+ { .val = 0, .div = 32, },
+ { .val = 1, .div = 8, },
+ { .val = 2, .div = 2, },
+ { .val = 3, .div = 1, },
+};
+
+static const struct clk_div_table timer_div_table[] = {
+ { .val = 0, .div = 256, },
+ { .val = 1, .div = 1, },
+};
+
+struct clps711x_clk {
+ struct clk_onecell_data clk_data;
+ spinlock_t lock;
+ struct clk *clks[CLPS711X_CLK_MAX];
+};
+
+static struct clps711x_clk * __init _clps711x_clk_init(void __iomem *base,
+ u32 fref)
+{
+ u32 tmp, f_cpu, f_pll, f_bus, f_tim, f_pwm, f_spi;
+ struct clps711x_clk *clps711x_clk;
+ unsigned i;
+
+ if (!base)
+ return ERR_PTR(-ENOMEM);
+
+ clps711x_clk = kzalloc(sizeof(*clps711x_clk), GFP_KERNEL);
+ if (!clps711x_clk)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock_init(&clps711x_clk->lock);
+
+ /* Read PLL multiplier value and sanity check */
+ tmp = readl(base + CLPS711X_PLLR) >> 24;
+ if (((tmp >= 10) && (tmp <= 50)) || !fref)
+ f_pll = DIV_ROUND_UP(CLPS711X_OSC_FREQ * tmp, 2);
+ else
+ f_pll = fref;
+
+ tmp = readl(base + CLPS711X_SYSFLG2);
+ if (tmp & SYSFLG2_CKMODE) {
+ f_cpu = CLPS711X_EXT_FREQ;
+ f_bus = CLPS711X_EXT_FREQ;
+ f_spi = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 96);
+ f_pll = 0;
+ f_pwm = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 128);
+ } else {
+ f_cpu = f_pll;
+ if (f_cpu > 36864000)
+ f_bus = DIV_ROUND_UP(f_cpu, 2);
+ else
+ f_bus = 36864000 / 2;
+ f_spi = DIV_ROUND_CLOSEST(f_cpu, 576);
+ f_pwm = DIV_ROUND_CLOSEST(f_cpu, 768);
+ }
+
+ if (tmp & SYSFLG2_CKMODE) {
+ if (readl(base + CLPS711X_SYSCON2) & SYSCON2_OSTB)
+ f_tim = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 26);
+ else
+ f_tim = DIV_ROUND_CLOSEST(CLPS711X_EXT_FREQ, 24);
+ } else
+ f_tim = DIV_ROUND_CLOSEST(f_cpu, 144);
+
+ tmp = readl(base + CLPS711X_SYSCON1);
+ /* Timer1 in free running mode.
+ * Counter will wrap around to 0xffff when it underflows
+ * and will continue to count down.
+ */
+ tmp &= ~(SYSCON1_TC1M | SYSCON1_TC1S);
+ /* Timer2 in prescale mode.
+ * Value writen is automatically re-loaded when
+ * the counter underflows.
+ */
+ tmp |= SYSCON1_TC2M | SYSCON1_TC2S;
+ writel(tmp, base + CLPS711X_SYSCON1);
+
+ clps711x_clk->clks[CLPS711X_CLK_DUMMY] =
+ clk_register_fixed_rate(NULL, "dummy", NULL, CLK_IS_ROOT, 0);
+ clps711x_clk->clks[CLPS711X_CLK_CPU] =
+ clk_register_fixed_rate(NULL, "cpu", NULL, CLK_IS_ROOT, f_cpu);
+ clps711x_clk->clks[CLPS711X_CLK_BUS] =
+ clk_register_fixed_rate(NULL, "bus", NULL, CLK_IS_ROOT, f_bus);
+ clps711x_clk->clks[CLPS711X_CLK_PLL] =
+ clk_register_fixed_rate(NULL, "pll", NULL, CLK_IS_ROOT, f_pll);
+ clps711x_clk->clks[CLPS711X_CLK_TIMERREF] =
+ clk_register_fixed_rate(NULL, "timer_ref", NULL, CLK_IS_ROOT,
+ f_tim);
+ clps711x_clk->clks[CLPS711X_CLK_TIMER1] =
+ clk_register_divider_table(NULL, "timer1", "timer_ref", 0,
+ base + CLPS711X_SYSCON1, 5, 1, 0,
+ timer_div_table, &clps711x_clk->lock);
+ clps711x_clk->clks[CLPS711X_CLK_TIMER2] =
+ clk_register_divider_table(NULL, "timer2", "timer_ref", 0,
+ base + CLPS711X_SYSCON1, 7, 1, 0,
+ timer_div_table, &clps711x_clk->lock);
+ clps711x_clk->clks[CLPS711X_CLK_PWM] =
+ clk_register_fixed_rate(NULL, "pwm", NULL, CLK_IS_ROOT, f_pwm);
+ clps711x_clk->clks[CLPS711X_CLK_SPIREF] =
+ clk_register_fixed_rate(NULL, "spi_ref", NULL, CLK_IS_ROOT,
+ f_spi);
+ clps711x_clk->clks[CLPS711X_CLK_SPI] =
+ clk_register_divider_table(NULL, "spi", "spi_ref", 0,
+ base + CLPS711X_SYSCON1, 16, 2, 0,
+ spi_div_table, &clps711x_clk->lock);
+ clps711x_clk->clks[CLPS711X_CLK_UART] =
+ clk_register_fixed_factor(NULL, "uart", "bus", 0, 1, 10);
+ clps711x_clk->clks[CLPS711X_CLK_TICK] =
+ clk_register_fixed_rate(NULL, "tick", NULL, CLK_IS_ROOT, 64);
+
+ for (i = 0; i < CLPS711X_CLK_MAX; i++)
+ if (IS_ERR(clps711x_clk->clks[i]))
+ pr_err("clk %i: register failed with %ld\n",
+ i, PTR_ERR(clps711x_clk->clks[i]));
+
+ return clps711x_clk;
+}
+
+void __init clps711x_clk_init(void __iomem *base)
+{
+ struct clps711x_clk *clps711x_clk;
+
+ clps711x_clk = _clps711x_clk_init(base, 73728000);
+
+ BUG_ON(IS_ERR(clps711x_clk));
+
+ /* Clocksource */
+ clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER1],
+ NULL, "clps711x-timer.0");
+ clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_TIMER2],
+ NULL, "clps711x-timer.1");
+
+ /* Drivers */
+ clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_PWM],
+ NULL, "clps711x-pwm");
+ clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART],
+ NULL, "clps711x-uart.0");
+ clk_register_clkdev(clps711x_clk->clks[CLPS711X_CLK_UART],
+ NULL, "clps711x-uart.1");
+}
+
+#ifdef CONFIG_OF
+static void __init clps711x_clk_init_dt(struct device_node *np)
+{
+ void __iomem *base = of_iomap(np, 0);
+ struct clps711x_clk *clps711x_clk;
+ u32 fref = 0;
+
+ WARN_ON(of_property_read_u32(np, "startup-frequency", &fref));
+
+ clps711x_clk = _clps711x_clk_init(base, fref);
+ BUG_ON(IS_ERR(clps711x_clk));
+
+ clps711x_clk->clk_data.clks = clps711x_clk->clks;
+ clps711x_clk->clk_data.clk_num = CLPS711X_CLK_MAX;
+ of_clk_add_provider(np, of_clk_src_onecell_get,
+ &clps711x_clk->clk_data);
+}
+CLK_OF_DECLARE(clps711x, "cirrus,clps711x-clk", clps711x_clk_init_dt);
+#endif
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 57a078e06efe..b9355daf8065 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -64,11 +64,56 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *rate_hw = composite->rate_hw;
struct clk_hw *mux_hw = composite->mux_hw;
+ struct clk *parent;
+ unsigned long parent_rate;
+ long tmp_rate, best_rate = 0;
+ unsigned long rate_diff;
+ unsigned long best_rate_diff = ULONG_MAX;
+ int i;
if (rate_hw && rate_ops && rate_ops->determine_rate) {
rate_hw->clk = hw->clk;
return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
best_parent_p);
+ } else if (rate_hw && rate_ops && rate_ops->round_rate &&
+ mux_hw && mux_ops && mux_ops->set_parent) {
+ *best_parent_p = NULL;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_NO_REPARENT) {
+ *best_parent_p = clk_get_parent(mux_hw->clk);
+ *best_parent_rate = __clk_get_rate(*best_parent_p);
+
+ return rate_ops->round_rate(rate_hw, rate,
+ best_parent_rate);
+ }
+
+ for (i = 0; i < __clk_get_num_parents(mux_hw->clk); i++) {
+ parent = clk_get_parent_by_index(mux_hw->clk, i);
+ if (!parent)
+ continue;
+
+ parent_rate = __clk_get_rate(parent);
+
+ tmp_rate = rate_ops->round_rate(rate_hw, rate,
+ &parent_rate);
+ if (tmp_rate < 0)
+ continue;
+
+ rate_diff = abs(rate - tmp_rate);
+
+ if (!rate_diff || !*best_parent_p
+ || best_rate_diff > rate_diff) {
+ *best_parent_p = parent;
+ *best_parent_rate = parent_rate;
+ best_rate_diff = rate_diff;
+ best_rate = tmp_rate;
+ }
+
+ if (!rate_diff)
+ return rate;
+ }
+
+ return best_rate;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
mux_hw->clk = hw->clk;
return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
@@ -162,7 +207,7 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
clk_composite_ops = &composite->ops;
if (mux_hw && mux_ops) {
- if (!mux_ops->get_parent || !mux_ops->set_parent) {
+ if (!mux_ops->get_parent) {
clk = ERR_PTR(-EINVAL);
goto err;
}
@@ -170,7 +215,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
composite->mux_hw = mux_hw;
composite->mux_ops = mux_ops;
clk_composite_ops->get_parent = clk_composite_get_parent;
- clk_composite_ops->set_parent = clk_composite_set_parent;
+ if (mux_ops->set_parent)
+ clk_composite_ops->set_parent = clk_composite_set_parent;
if (mux_ops->determine_rate)
clk_composite_ops->determine_rate = clk_composite_determine_rate;
}
@@ -180,24 +226,27 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
clk = ERR_PTR(-EINVAL);
goto err;
}
+ clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
- /* .round_rate is a prerequisite for .set_rate */
- if (rate_ops->round_rate) {
- clk_composite_ops->round_rate = clk_composite_round_rate;
- if (rate_ops->set_rate) {
- clk_composite_ops->set_rate = clk_composite_set_rate;
- }
- } else {
- WARN(rate_ops->set_rate,
- "%s: missing round_rate op is required\n",
- __func__);
+ if (rate_ops->determine_rate)
+ clk_composite_ops->determine_rate =
+ clk_composite_determine_rate;
+ else if (rate_ops->round_rate)
+ clk_composite_ops->round_rate =
+ clk_composite_round_rate;
+
+ /* .set_rate requires either .round_rate or .determine_rate */
+ if (rate_ops->set_rate) {
+ if (rate_ops->determine_rate || rate_ops->round_rate)
+ clk_composite_ops->set_rate =
+ clk_composite_set_rate;
+ else
+ WARN(1, "%s: missing round_rate op is required\n",
+ __func__);
}
composite->rate_hw = rate_hw;
composite->rate_ops = rate_ops;
- clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
- if (rate_ops->determine_rate)
- clk_composite_ops->determine_rate = clk_composite_determine_rate;
}
if (gate_hw && gate_ops) {
diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c
new file mode 100644
index 000000000000..aad4796aa3ed
--- /dev/null
+++ b/drivers/clk/clk-conf.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2014 Samsung Electronics Co., Ltd.
+ * Sylwester Nawrocki <s.nawrocki@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.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/clk-conf.h>
+#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)
+{
+ struct of_phandle_args clkspec;
+ int index, rc, num_parents;
+ struct clk *clk, *pclk;
+
+ num_parents = of_count_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells");
+ if (num_parents == -EINVAL)
+ pr_err("clk: invalid value of clock-parents property at %s\n",
+ node->full_name);
+
+ for (index = 0; index < num_parents; index++) {
+ rc = of_parse_phandle_with_args(node, "assigned-clock-parents",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0) {
+ /* skip empty (null) phandles */
+ if (rc == -ENOENT)
+ continue;
+ else
+ return rc;
+ }
+ if (clkspec.np == node && !clk_supplier)
+ return 0;
+ pclk = of_clk_get_by_clkspec(&clkspec);
+ if (IS_ERR(pclk)) {
+ pr_warn("clk: couldn't get parent clock %d for %s\n",
+ index, node->full_name);
+ return PTR_ERR(pclk);
+ }
+
+ rc = of_parse_phandle_with_args(node, "assigned-clocks",
+ "#clock-cells", index, &clkspec);
+ if (rc < 0)
+ goto err;
+ if (clkspec.np == node && !clk_supplier) {
+ rc = 0;
+ goto err;
+ }
+ clk = of_clk_get_by_clkspec(&clkspec);
+ if (IS_ERR(clk)) {
+ pr_warn("clk: couldn't get parent clock %d for %s\n",
+ index, node->full_name);
+ rc = PTR_ERR(clk);
+ goto err;
+ }
+
+ rc = clk_set_parent(clk, pclk);
+ if (rc < 0)
+ pr_err("clk: failed to reparent %s to %s: %d\n",
+ __clk_get_name(clk), __clk_get_nam