summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-02-20 11:02:10 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-02-20 11:02:10 -0800
commit10b6339e93244156fac901560117e94bf9dca120 (patch)
tree93a86c1328f0f3b0f37af493907b32d72027c9d1
parentc6699b58f4fe2f968f036a862c09ce44b6968376 (diff)
parentfde8bc59c03c0ad1fa4f655e0ed5cc1f76d11e8b (diff)
Merge tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux
Pull clock framework update from Michael Turquette: "The common clock framework changes for 3.9 are almost entirely fixes. None are dire enough to be Cc'd to stable which may be interpreted to mean that users of the framework are reaching stability. Lots of new adoption of this framework is via DeviceTree data and that comes through the respective architecture and platform trees instead of through the clk framework tree. Two new features are improved debugfs output and an improvement to how DT clocks are initialized by reusing a common method." * tag 'clk-for-linus' of git://git.linaro.org/people/mturquette/linux: (25 commits) clk: sunxi: remove stale Makefile entry clk: vexpress: Use common of_clk_init() function clk: zynq: Use common of_clk_init() function clk: vt8500: Use common of_clk_init() function clk: highbank: Use common of_clk_init() function clk: sunxi: Use common of_clk_init() function clk: add common of_clk_init() function clk: Deduplicate exit code in clk_set_rate clk: beautify Makefile clk-divider: fix macros clk: prima2: enable dt-binding clkdev mapping clk: mxs: Index is always positive clk: max77686: Avoid double free at remove time clk: remove exported function from __init section clk: vt8500: Add support for WM8750/WM8850 PLL clocks clk: vt8500: Fix division-by-0 when requested rate=0 clk: vt8500: Fix device clock divisor calculations clk: vt8500: Fix error in PLL calculations on non-exact match. clk: max77686: Remove unnecessary NULL checking for container_of() clk: JSON debugfs clock tree summary ...
-rw-r--r--Documentation/devicetree/bindings/clock/prima2-clock.txt73
-rw-r--r--arch/arm/boot/dts/prima2.dtsi31
-rw-r--r--arch/arm/mach-highbank/core.h1
-rw-r--r--arch/arm/mach-highbank/highbank.c3
-rw-r--r--drivers/clk/Makefile10
-rw-r--r--drivers/clk/clk-divider.c6
-rw-r--r--drivers/clk/clk-fixed-factor.c5
-rw-r--r--drivers/clk/clk-fixed-rate.c3
-rw-r--r--drivers/clk/clk-highbank.c18
-rw-r--r--drivers/clk/clk-max77686.c37
-rw-r--r--drivers/clk/clk-prima2.c205
-rw-r--r--drivers/clk/clk-sunxi.c30
-rw-r--r--drivers/clk/clk-vt8500.c143
-rw-r--r--drivers/clk/clk-zynq.c14
-rw-r--r--drivers/clk/clk.c169
-rw-r--r--drivers/clk/mxs/clk-imx23.c2
-rw-r--r--drivers/clk/mxs/clk-imx28.c2
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c1
-rw-r--r--drivers/clk/versatile/clk-vexpress.c8
-rw-r--r--drivers/clocksource/sunxi_timer.c4
-rw-r--r--include/asm-generic/vmlinux.lds.h10
-rw-r--r--include/linux/clk-provider.h6
-rw-r--r--include/linux/clk/sunxi.h22
23 files changed, 527 insertions, 276 deletions
diff --git a/Documentation/devicetree/bindings/clock/prima2-clock.txt b/Documentation/devicetree/bindings/clock/prima2-clock.txt
new file mode 100644
index 00000000000..5016979c0f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/prima2-clock.txt
@@ -0,0 +1,73 @@
+* Clock bindings for CSR SiRFprimaII
+
+Required properties:
+- compatible: Should be "sirf,prima2-clkc"
+- reg: Address and length of the register set
+- interrupts: Should contain clock controller interrupt
+- #clock-cells: Should be <1>
+
+The clock consumer should specify the desired clock by having the clock
+ID in its "clocks" phandle cell. The following is a full list of prima2
+clocks and IDs.
+
+ Clock ID
+ ---------------------------
+ rtc 0
+ osc 1
+ pll1 2
+ pll2 3
+ pll3 4
+ mem 5
+ sys 6
+ security 7
+ dsp 8
+ gps 9
+ mf 10
+ io 11
+ cpu 12
+ uart0 13
+ uart1 14
+ uart2 15
+ tsc 16
+ i2c0 17
+ i2c1 18
+ spi0 19
+ spi1 20
+ pwmc 21
+ efuse 22
+ pulse 23
+ dmac0 24
+ dmac1 25
+ nand 26
+ audio 27
+ usp0 28
+ usp1 29
+ usp2 30
+ vip 31
+ gfx 32
+ mm 33
+ lcd 34
+ vpp 35
+ mmc01 36
+ mmc23 37
+ mmc45 38
+ usbpll 39
+ usb0 40
+ usb1 41
+
+Examples:
+
+clks: clock-controller@88000000 {
+ compatible = "sirf,prima2-clkc";
+ reg = <0x88000000 0x1000>;
+ interrupts = <3>;
+ #clock-cells = <1>;
+};
+
+i2c0: i2c@b00e0000 {
+ cell-index = <0>;
+ compatible = "sirf,prima2-i2c";
+ reg = <0xb00e0000 0x10000>;
+ interrupts = <24>;
+ clocks = <&clks 17>;
+};
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 055fca54212..3329719a941 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -58,10 +58,11 @@
#size-cells = <1>;
ranges = <0x88000000 0x88000000 0x40000>;
- clock-controller@88000000 {
+ clks: clock-controller@88000000 {
compatible = "sirf,prima2-clkc";
reg = <0x88000000 0x1000>;
interrupts = <3>;
+ #clock-cells = <1>;
};
reset-controller@88010000 {
@@ -85,6 +86,7 @@
compatible = "sirf,prima2-memc";
reg = <0x90000000 0x10000>;
interrupts = <27>;
+ clocks = <&clks 5>;
};
};
@@ -104,6 +106,7 @@
compatible = "sirf,prima2-vpp";
reg = <0x90020000 0x10000>;
interrupts = <31>;
+ clocks = <&clks 35>;
};
};
@@ -117,6 +120,7 @@
compatible = "powervr,sgx531";
reg = <0x98000000 0x8000000>;
interrupts = <6>;
+ clocks = <&clks 32>;
};
};
@@ -130,6 +134,7 @@
compatible = "sirf,prima2-video-codec";
reg = <0xa0000000 0x8000000>;
interrupts = <5>;
+ clocks = <&clks 33>;
};
};
@@ -149,12 +154,14 @@
compatible = "sirf,prima2-gps";
reg = <0xa8010000 0x10000>;
interrupts = <7>;
+ clocks = <&clks 9>;
};
dsp@a9000000 {
compatible = "sirf,prima2-dsp";
reg = <0xa9000000 0x1000000>;
interrupts = <8>;
+ clocks = <&clks 8>;
};
};
@@ -174,12 +181,14 @@
compatible = "sirf,prima2-nand";
reg = <0xb0030000 0x10000>;
interrupts = <41>;
+ clocks = <&clks 26>;
};
audio@b0040000 {
compatible = "sirf,prima2-audio";
reg = <0xb0040000 0x10000>;
interrupts = <35>;
+ clocks = <&clks 27>;
};
uart0: uart@b0050000 {
@@ -187,6 +196,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0050000 0x10000>;
interrupts = <17>;
+ clocks = <&clks 13>;
};
uart1: uart@b0060000 {
@@ -194,6 +204,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0060000 0x10000>;
interrupts = <18>;
+ clocks = <&clks 14>;
};
uart2: uart@b0070000 {
@@ -201,6 +212,7 @@
compatible = "sirf,prima2-uart";
reg = <0xb0070000 0x10000>;
interrupts = <19>;
+ clocks = <&clks 15>;
};
usp0: usp@b0080000 {
@@ -208,6 +220,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb0080000 0x10000>;
interrupts = <20>;
+ clocks = <&clks 28>;
};
usp1: usp@b0090000 {
@@ -215,6 +228,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb0090000 0x10000>;
interrupts = <21>;
+ clocks = <&clks 29>;
};
usp2: usp@b00a0000 {
@@ -222,6 +236,7 @@
compatible = "sirf,prima2-usp";
reg = <0xb00a0000 0x10000>;
interrupts = <22>;
+ clocks = <&clks 30>;
};
dmac0: dma-controller@b00b0000 {
@@ -229,6 +244,7 @@
compatible = "sirf,prima2-dmac";
reg = <0xb00b0000 0x10000>;
interrupts = <12>;
+ clocks = <&clks 24>;
};
dmac1: dma-controller@b0160000 {
@@ -236,11 +252,13 @@
compatible = "sirf,prima2-dmac";
reg = <0xb0160000 0x10000>;
interrupts = <13>;
+ clocks = <&clks 25>;
};
vip@b00C0000 {
compatible = "sirf,prima2-vip";
reg = <0xb00C0000 0x10000>;
+ clocks = <&clks 31>;
};
spi0: spi@b00d0000 {
@@ -248,6 +266,7 @@
compatible = "sirf,prima2-spi";
reg = <0xb00d0000 0x10000>;
interrupts = <15>;
+ clocks = <&clks 19>;
};
spi1: spi@b0170000 {
@@ -255,6 +274,7 @@
compatible = "sirf,prima2-spi";
reg = <0xb0170000 0x10000>;
interrupts = <16>;
+ clocks = <&clks 20>;
};
i2c0: i2c@b00e0000 {
@@ -262,6 +282,7 @@
compatible = "sirf,prima2-i2c";
reg = <0xb00e0000 0x10000>;
interrupts = <24>;
+ clocks = <&clks 17>;
};
i2c1: i2c@b00f0000 {
@@ -269,12 +290,14 @@
compatible = "sirf,prima2-i2c";
reg = <0xb00f0000 0x10000>;
interrupts = <25>;
+ clocks = <&clks 18>;
};
tsc@b0110000 {
compatible = "sirf,prima2-tsc";
reg = <0xb0110000 0x10000>;
interrupts = <33>;
+ clocks = <&clks 16>;
};
gpio: pinctrl@b0120000 {
@@ -507,17 +530,20 @@
pwm@b0130000 {
compatible = "sirf,prima2-pwm";
reg = <0xb0130000 0x10000>;
+ clocks = <&clks 21>;
};
efusesys@b0140000 {
compatible = "sirf,prima2-efuse";
reg = <0xb0140000 0x10000>;
+ clocks = <&clks 22>;
};
pulsec@b0150000 {
compatible = "sirf,prima2-pulsec";
reg = <0xb0150000 0x10000>;
interrupts = <48>;
+ clocks = <&clks 23>;
};
pci-iobg {
@@ -616,12 +642,14 @@
compatible = "chipidea,ci13611a-prima2";
reg = <0xb8000000 0x10000>;
interrupts = <10>;
+ clocks = <&clks 40>;
};
usb1: usb@b00f0000 {
compatible = "chipidea,ci13611a-prima2";
reg = <0xb8010000 0x10000>;
interrupts = <11>;
+ clocks = <&clks 41>;
};
sata@b00f0000 {
@@ -634,6 +662,7 @@
compatible = "sirf,prima2-security";
reg = <0xb8030000 0x10000>;
interrupts = <42>;
+ clocks = <&clks 7>;
};
};
};
diff --git a/arch/arm/mach-highbank/core.h b/arch/arm/mach-highbank/core.h
index 80235b46cb5..3f65206a9b9 100644
--- a/arch/arm/mach-highbank/core.h
+++ b/arch/arm/mach-highbank/core.h
@@ -2,7 +2,6 @@
#define __HIGHBANK_CORE_H
extern void highbank_set_cpu_jump(int cpu, void *jump_addr);
-extern void highbank_clocks_init(void);
extern void highbank_restart(char, const char *);
extern void __iomem *scu_base_addr;
diff --git a/arch/arm/mach-highbank/highbank.c b/arch/arm/mach-highbank/highbank.c
index e6c06128293..65656ff0eb3 100644
--- a/arch/arm/mach-highbank/highbank.c
+++ b/arch/arm/mach-highbank/highbank.c
@@ -25,6 +25,7 @@
#include <linux/of_address.h>
#include <linux/smp.h>
#include <linux/amba/bus.h>
+#include <linux/clk-provider.h>
#include <asm/arch_timer.h>
#include <asm/cacheflush.h>
@@ -117,7 +118,7 @@ static void __init highbank_timer_init(void)
WARN_ON(!timer_base);
irq = irq_of_parse_and_map(np, 0);
- highbank_clocks_init();
+ of_clk_init(NULL);
lookup.clk = of_clk_get(np, 0);
clkdev_add(&lookup);
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index ee90e87e767..0ad642fbe79 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -1,8 +1,13 @@
# common clock types
obj-$(CONFIG_HAVE_CLK) += clk-devres.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
-obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \
- clk-mux.o clk-divider.o clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK) += clk.o
+obj-$(CONFIG_COMMON_CLK) += clk-divider.o
+obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
+obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
+obj-$(CONFIG_COMMON_CLK) += clk-gate.o
+obj-$(CONFIG_COMMON_CLK) += clk-mux.o
+
# SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
@@ -20,7 +25,6 @@ endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
-obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
# Chip specific
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index a9204c69148..68b40210117 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -16,6 +16,7 @@
#include <linux/io.h>
#include <linux/err.h>
#include <linux/string.h>
+#include <linux/log2.h>
/*
* DOC: basic adjustable divider clock that cannot gate
@@ -29,8 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
-#define div_mask(d) ((1 << (d->width)) - 1)
-#define is_power_of_two(i) !(i & ~i)
+#define div_mask(d) ((1 << ((d)->width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
@@ -137,7 +137,7 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
{
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return is_power_of_two(div);
+ return is_power_of_2(div);
if (divider->table)
return _is_valid_table_div(divider->table, div);
return true;
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index a4899855c0f..1ef271e4759 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -28,8 +28,11 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw);
+ unsigned long long int rate;
- return parent_rate * fix->mult / fix->div;
+ rate = (unsigned long long int)parent_rate * fix->mult;
+ do_div(rate, fix->div);
+ return (unsigned long)rate;
}
static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
diff --git a/drivers/clk/clk-fixed-rate.c b/drivers/clk/clk-fixed-rate.c
index af78ed6b67e..dc58fbd8516 100644
--- a/drivers/clk/clk-fixed-rate.c
+++ b/drivers/clk/clk-fixed-rate.c
@@ -85,7 +85,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
/**
* of_fixed_clk_setup() - Setup function for simple fixed rate clock
*/
-void __init of_fixed_clk_setup(struct device_node *node)
+void of_fixed_clk_setup(struct device_node *node)
{
struct clk *clk;
const char *clk_name = node->name;
@@ -101,4 +101,5 @@ void __init of_fixed_clk_setup(struct device_node *node)
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
+CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
#endif
diff --git a/drivers/clk/clk-highbank.c b/drivers/clk/clk-highbank.c
index 52fecadf004..5d1de2e1175 100644
--- a/drivers/clk/clk-highbank.c
+++ b/drivers/clk/clk-highbank.c
@@ -314,33 +314,23 @@ static void __init hb_pll_init(struct device_node *node)
{
hb_clk_init(node, &clk_pll_ops);
}
+CLK_OF_DECLARE(hb_pll, "calxeda,hb-pll-clock", hb_pll_init);
static void __init hb_a9periph_init(struct device_node *node)
{
hb_clk_init(node, &a9periphclk_ops);
}
+CLK_OF_DECLARE(hb_a9periph, "calxeda,hb-a9periph-clock", hb_a9periph_init);
static void __init hb_a9bus_init(struct device_node *node)
{
struct clk *clk = hb_clk_init(node, &a9bclk_ops);
clk_prepare_enable(clk);
}
+CLK_OF_DECLARE(hb_a9bus, "calxeda,hb-a9bus-clock", hb_a9bus_init);
static void __init hb_emmc_init(struct device_node *node)
{
hb_clk_init(node, &periclk_ops);
}
-
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "calxeda,hb-pll-clock", .data = hb_pll_init, },
- { .compatible = "calxeda,hb-a9periph-clock", .data = hb_a9periph_init, },
- { .compatible = "calxeda,hb-a9bus-clock", .data = hb_a9bus_init, },
- { .compatible = "calxeda,hb-emmc-clock", .data = hb_emmc_init, },
- {}
-};
-
-void __init highbank_clocks_init(void)
-{
- of_clk_init(clk_match);
-}
+CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init);
diff --git a/drivers/clk/clk-max77686.c b/drivers/clk/clk-max77686.c
index d098f72e1d5..9f57bc37cd6 100644
--- a/drivers/clk/clk-max77686.c
+++ b/drivers/clk/clk-max77686.c
@@ -44,33 +44,23 @@ struct max77686_clk {
struct clk_lookup *lookup;
};
-static struct max77686_clk *get_max77686_clk(struct clk_hw *hw)
+static struct max77686_clk *to_max77686_clk(struct clk_hw *hw)
{
return container_of(hw, struct max77686_clk, hw);
}
static int max77686_clk_prepare(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
- int ret;
-
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return -ENOMEM;
-
- ret = regmap_update_bits(max77686->iodev->regmap,
- MAX77686_REG_32KHZ, max77686->mask, max77686->mask);
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
- return ret;
+ return regmap_update_bits(max77686->iodev->regmap,
+ MAX77686_REG_32KHZ, max77686->mask,
+ max77686->mask);
}
static void max77686_clk_unprepare(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
-
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return;
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
regmap_update_bits(max77686->iodev->regmap,
MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
@@ -78,14 +68,10 @@ static void max77686_clk_unprepare(struct clk_hw *hw)
static int max77686_clk_is_enabled(struct clk_hw *hw)
{
- struct max77686_clk *max77686;
+ struct max77686_clk *max77686 = to_max77686_clk(hw);
int ret;
u32 val;
- max77686 = get_max77686_clk(hw);
- if (!max77686)
- return -ENOMEM;
-
ret = regmap_read(max77686->iodev->regmap,
MAX77686_REG_32KHZ, &val);
@@ -130,9 +116,8 @@ static int max77686_clk_register(struct device *dev,
if (IS_ERR(clk))
return -ENOMEM;
- max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup),
- GFP_KERNEL);
- if (IS_ERR(max77686->lookup))
+ max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
+ if (!max77686->lookup)
return -ENOMEM;
max77686->lookup->con_id = hw->init->name;
@@ -151,13 +136,13 @@ static int max77686_clk_probe(struct platform_device *pdev)
max77686_clks = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
* MAX77686_CLKS_NUM, GFP_KERNEL);
- if (IS_ERR(max77686_clks))
+ if (!max77686_clks)
return -ENOMEM;
for (i = 0; i < MAX77686_CLKS_NUM; i++) {
max77686_clks[i] = devm_kzalloc(&pdev->dev,
sizeof(struct max77686_clk), GFP_KERNEL);
- if (IS_ERR(max77686_clks[i]))
+ if (!max77686_clks[i])
return -ENOMEM;
}
diff --git a/drivers/clk/clk-prima2.c b/drivers/clk/clk-prima2.c
index a203ecccdc4..f8e9d0c27be 100644
--- a/drivers/clk/clk-prima2.c
+++ b/drivers/clk/clk-prima2.c
@@ -1025,20 +1025,67 @@ static struct of_device_id rsc_ids[] = {
{},
};
+enum prima2_clk_index {
+ /* 0 1 2 3 4 5 6 7 8 9 */
+ rtc, osc, pll1, pll2, pll3, mem, sys, security, dsp, gps,
+ mf, io, cpu, uart0, uart1, uart2, tsc, i2c0, i2c1, spi0,
+ spi1, pwmc, efuse, pulse, dmac0, dmac1, nand, audio, usp0, usp1,
+ usp2, vip, gfx, mm, lcd, vpp, mmc01, mmc23, mmc45, usbpll,
+ usb0, usb1, maxclk,
+};
+
+static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = {
+ NULL, /* dummy */
+ NULL,
+ &clk_pll1.hw,
+ &clk_pll2.hw,
+ &clk_pll3.hw,
+ &clk_mem.hw,
+ &clk_sys.hw,
+ &clk_security.hw,
+ &clk_dsp.hw,
+ &clk_gps.hw,
+ &clk_mf.hw,
+ &clk_io.hw,
+ &clk_cpu.hw,
+ &clk_uart0.hw,
+ &clk_uart1.hw,
+ &clk_uart2.hw,
+ &clk_tsc.hw,
+ &clk_i2c0.hw,
+ &clk_i2c1.hw,
+ &clk_spi0.hw,
+ &clk_spi1.hw,
+ &clk_pwmc.hw,
+ &clk_efuse.hw,
+ &clk_pulse.hw,
+ &clk_dmac0.hw,
+ &clk_dmac1.hw,
+ &clk_nand.hw,
+ &clk_audio.hw,
+ &clk_usp0.hw,
+ &clk_usp1.hw,
+ &clk_usp2.hw,
+ &clk_vip.hw,
+ &clk_gfx.hw,
+ &clk_mm.hw,
+ &clk_lcd.hw,
+ &clk_vpp.hw,
+ &clk_mmc01.hw,
+ &clk_mmc23.hw,
+ &clk_mmc45.hw,
+ &usb_pll_clk_hw,
+ &clk_usb0.hw,
+ &clk_usb1.hw,
+};
+
+static struct clk *prima2_clks[maxclk];
+static struct clk_onecell_data clk_data;
+
void __init sirfsoc_of_clk_init(void)
{
- struct clk *clk;
struct device_node *np;
-
- np = of_find_matching_node(NULL, clkc_ids);
- if (!np)
- panic("unable to find compatible clkc node in dtb\n");
-
- sirfsoc_clk_vbase = of_iomap(np, 0);
- if (!sirfsoc_clk_vbase)
- panic("unable to map clkc registers\n");
-
- of_node_put(np);
+ int i;
np = of_find_matching_node(NULL, rsc_ids);
if (!np)
@@ -1050,122 +1097,30 @@ void __init sirfsoc_of_clk_init(void)
of_node_put(np);
+ np = of_find_matching_node(NULL, clkc_ids);
+ if (!np)
+ return;
+
+ sirfsoc_clk_vbase = of_iomap(np, 0);
+ if (!sirfsoc_clk_vbase)
+ panic("unable to map clkc registers\n");
/* These are always available (RTC and 26MHz OSC)*/
- clk = clk_register_fixed_rate(NULL, "rtc", NULL,
+ prima2_clks[rtc] = clk_register_fixed_rate(NULL, "rtc", NULL,
CLK_IS_ROOT, 32768);
- BUG_ON(IS_ERR(clk));
- clk = clk_register_fixed_rate(NULL, "osc", NULL,
+ prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000);
- BUG_ON(IS_ERR(clk));
-
- clk = clk_register(NULL, &clk_pll1.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_pll2.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_pll3.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mem.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_sys.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_security.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b8030000.security");
- clk = clk_register(NULL, &clk_dsp.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_gps.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "a8010000.gps");
- clk = clk_register(NULL, &clk_mf.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_io.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "io");
- clk = clk_register(NULL, &clk_cpu.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "cpu");
- clk = clk_register(NULL, &clk_uart0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0050000.uart");
- clk = clk_register(NULL, &clk_uart1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0060000.uart");
- clk = clk_register(NULL, &clk_uart2.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0070000.uart");
- clk = clk_register(NULL, &clk_tsc.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0110000.tsc");
- clk = clk_register(NULL, &clk_i2c0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00e0000.i2c");
- clk = clk_register(NULL, &clk_i2c1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00f0000.i2c");
- clk = clk_register(NULL, &clk_spi0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00d0000.spi");
- clk = clk_register(NULL, &clk_spi1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0170000.spi");
- clk = clk_register(NULL, &clk_pwmc.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0130000.pwm");
- clk = clk_register(NULL, &clk_efuse.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0140000.efusesys");
- clk = clk_register(NULL, &clk_pulse.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0150000.pulsec");
- clk = clk_register(NULL, &clk_dmac0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00b0000.dma-controller");
- clk = clk_register(NULL, &clk_dmac1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0160000.dma-controller");
- clk = clk_register(NULL, &clk_nand.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0030000.nand");
- clk = clk_register(NULL, &clk_audio.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0040000.audio");
- clk = clk_register(NULL, &clk_usp0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0080000.usp");
- clk = clk_register(NULL, &clk_usp1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b0090000.usp");
- clk = clk_register(NULL, &clk_usp2.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00a0000.usp");
- clk = clk_register(NULL, &clk_vip.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00c0000.vip");
- clk = clk_register(NULL, &clk_gfx.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "98000000.graphics");
- clk = clk_register(NULL, &clk_mm.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "a0000000.multimedia");
- clk = clk_register(NULL, &clk_lcd.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "90010000.display");
- clk = clk_register(NULL, &clk_vpp.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "90020000.vpp");
- clk = clk_register(NULL, &clk_mmc01.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mmc23.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_mmc45.hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &usb_pll_clk_hw);
- BUG_ON(IS_ERR(clk));
- clk = clk_register(NULL, &clk_usb0.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00e0000.usb");
- clk = clk_register(NULL, &clk_usb1.hw);
- BUG_ON(IS_ERR(clk));
- clk_register_clkdev(clk, NULL, "b00f0000.usb");
+
+ for (i = pll1; i < maxclk; i++) {
+ prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
+ BUG_ON(!prima2_clks[i]);
+ }
+ clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
+ clk_register_clkdev(prima2_clks[io], NULL, "io");
+ clk_register_clkdev(prima2_clks[mem], NULL, "mem");
+
+ clk_data.clks = prima2_clks;
+ clk_data.clk_num = maxclk;
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
diff --git a/drivers/clk/clk-sunxi.c b/drivers/clk/clk-sunxi.c
deleted file mode 100644
index 0e831b584ba..00000000000
--- a/drivers/clk/clk-sunxi.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * 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.
- *
- * 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/clkdev.h>
-#include <linux/clk/sunxi.h>
-#include <linux/of.h>
-
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- {}
-};
-
-void __init sunxi_init_clocks(void)
-{
- of_clk_init(clk_match);
-}
diff --git a/drivers/clk/clk-vt8500.c b/drivers/clk/clk-vt8500.c
index fe25570874d..b5538bba7a1 100644
--- a/drivers/clk/clk-vt8500.c
+++ b/drivers/clk/clk-vt8500.c
@@ -41,6 +41,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1
+#define PLL_TYPE_WM8750 2
struct clk_pll {
struct clk_hw hw;
@@ -121,7 +122,16 @@ static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_device *cdev = to_clk_device(hw);
- u32 divisor = *prate / rate;
+ u32 divisor;
+
+ if (rate == 0)
+ return 0;
+
+ divisor = *prate / rate;
+
+ /* If prate / rate would be decimal, incr the divisor */
+ if (rate * divisor < *prate)
+ divisor++;
/*
* If this is a request for SDMMC we have to adjust the divisor
@@ -138,9 +148,18 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_device *cdev = to_clk_device(hw);
- u32 divisor = parent_rate / rate;
+ u32 divisor;
unsigned long flags = 0;
+ if (rate == 0)
+ return 0;
+
+ divisor = parent_rate / rate;
+
+ /* If prate / rate would be decimal, incr the divisor */
+ if (rate * divisor < *prate)
+ divisor++;
+
if (divisor == cdev->div_mask + 1)
divisor = 0;
@@ -272,7 +291,7 @@ static __init void vtwm_device_clk_init(struct device_node *node)
rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL);
}
-
+CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
/* PLL clock related functions */
@@ -298,6 +317,16 @@ static __init void vtwm_device_clk_init(struct device_node *node)
#define WM8650_BITS_TO_VAL(m, d1, d2) \
((d2 << 13) | (d1 << 10) | (m & 0x3FF))
+/* Helper macros for PLL_WM8750 */
+#define WM8750_PLL_MUL(x) (((x >> 16) & 0xFF) + 1)
+#define WM8750_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 7)))
+
+#define WM8750_BITS_TO_FREQ(r, m, d1, d2) \
+ (r * (m+1) / ((d1+1) * (1 << d2)))
+
+#define WM8750_BITS_TO_VAL(f, m, d1, d2) \
+ ((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
+
static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv)
@@ -361,16 +390,87 @@ static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate,
/* if we got here, it wasn't an exact match */
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err);
- *multiplier = mul;
- *divisor1 = div1;
- *divisor2 = div2;
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
+}
+
+static u32 wm8750_get_filter(u32 parent_rate, u32 divisor1)
+{
+ /* calculate frequency (MHz) after pre-divisor */
+ u32 freq = (parent_rate / 1000000) / (divisor1 + 1);
+
+ if ((freq < 10) || (freq > 200))
+ pr_warn("%s: PLL recommended input frequency 10..200Mhz (requested %d Mhz)\n",
+ __func__, freq);
+
+ if (freq >= 166)
+ return 7;
+ else if (freq >= 104)
+ return 6;
+ else if (freq >= 65)
+ return 5;
+ else if (freq >= 42)
+ return 4;
+ else if (freq >= 26)
+ return 3;
+ else if (freq >= 16)
+ return 2;
+ else if (freq >= 10)
+ return 1;
+
+ return 0;
+}
+
+static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
+ u32 *filter, u32 *multiplier, u32 *divisor1, u32 *divisor2)
+{
+ u32 mul, div1, div2;
+ u32 best_mul, best_div1, best_div2;
+ unsigned long tclk, rate_err, best_err;
+
+ best_err = (unsigned long)-1;
+
+ /* Find the closest match (lower or equal to requested) */
+ for (div1 = 1; div1 >= 0; div1--)
+ for (div2 = 7; div2 >= 0; div2--)
+ for (mul = 0; mul <= 255; mul++) {
+ tclk = parent_rate * (mul + 1) / ((div1 + 1) * (1 << div2));
+ if (tclk > rate)
+ continue;
+ /* error will always be +ve */
+ rate_err = rate - tclk;
+ if (rate_err == 0) {
+ *filter = wm8750_get_filter(parent_rate, div1);
+ *multiplier = mul;
+ *divisor1 = div1;
+ *divisor2 = div2;
+ return;
+ }
+
+ if (rate_err < best_err) {
+ best_err = rate_err;
+ best_mul = mul;
+ best_div1 = div1;
+ best_div2 = div2;
+ }
+ }
+
+ /* if we got here, it wasn't an exact match */
+ pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
+ rate - best_err);
+
+ *filter = wm8750_get_filter(parent_rate, best_div1);
+ *multiplier = best_mul;
+ *divisor1 = best_div1;
+ *divisor2 = best_div2;
}
static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct clk_pll *pll = to_clk_pll(hw);
- u32 mul, div1, div2;
+ u32 filter, mul, div1, div2;
u32 pll_val;
unsigned long flags = 0;
@@ -385,6 +485,9 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
pll_val = WM8650_BITS_TO_VAL(mul, div1, div2);
break;
+ case PLL_TYPE_WM8750:
+ wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
+ pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@@ -405,7 +508,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct clk_pll *pll = to_clk_pll(hw);
- u32 mul, div1, div2;
+ u32 filter, mul, div1, div2;
long round_rate;
switch (pll->type) {
@@ -417,6 +520,9 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2);
round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
+ case PLL_TYPE_WM8750:
+ wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
+ round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
default:
round_rate = 0;
}
@@ -440,6 +546,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
pll_freq = parent_rate * WM8650_PLL_MUL(pll_val);
pll_freq /= WM8650_PLL_DIV(pll_val);
break;
+ case PLL_TYPE_WM8750:
+ pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
+ pll_freq /= WM8750_PLL_DIV(pll_val);
+ break;
default:
pll_freq = 0;
}
@@ -502,20 +612,19 @@ static void __init vt8500_pll_init(struct device_node *node)
{
vtwm_pll_clk_init(node, PLL_TYPE_VT8500);
}
+CLK_OF_DECLARE(vt8500_pll, "via,vt8500-pll-clock", vt8500_pll_init);
static void __init wm8650_pll_init(struct device_node *node)
{
vtwm_pll_clk_init(node, PLL_TYPE_WM8650);
}
+CLK_OF_DECLARE(wm8650_pll, "wm,wm8650-pll-clock", wm8650_pll_init);
-static const __initconst struct of_device_id clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, },
- { .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, },
- { .compatible = "via,vt8500-device-clock",
- .data = vtwm_device_clk_init, },
- { /* sentinel */ }
-};
+static void __init wm8750_pll_init(struct device_node *node)
+{
+ vtwm_pll_clk_init(node, PLL_TYPE_WM8750);
+}
+CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
void __init vtwm_clk_init(void __iomem *base)
{
@@ -524,5 +633,5 @@ void __init vtwm_clk_init(void __iomem *base)
pmc_base = base;
- of_clk_init(clk_match);
+ of_clk_init(NULL);
}
diff --git a/drivers/clk/clk-zynq.c b/drivers/clk/clk-zynq.c
index 37a30514fd6..b14a25f3925 100644
--- a/drivers/clk/clk-zynq.c
+++ b/drivers/clk/clk-zynq.c
@@ -81,6 +81,7 @@ static void __init zynq_pll_clk_setup(struct device_node *np)
if (WARN_ON(ret))
return;
}
+CLK_OF_DECLARE(zynq_pll, "xlnx,zynq-pll", zynq_pll_clk_setup);
struct zynq_periph_clk {
struct clk_hw hw;
@@ -187,6 +188,7 @@ static void __init zynq_periph_clk_setup(struct device_node *np)
if (WARN_ON(err))
return;
}
+CLK_OF_DECLARE(zynq_periph, "xlnx,zynq-periph-clock", zynq_periph_clk_setup);
/* CPU Clock domain is modelled as a mux with 4 children subclks, whose
* derivative rates depend on CLK_621_TRUE
@@ -366,18 +368,10 @@ static void __init zynq_cpu_clk_setup(struct device_node *np)
if (WARN_ON(err))
return;
}
-
-static const __initconst struct of_device_id zynq_clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "xlnx,zynq-pll", .data = zynq_pll_clk_setup, },
- { .compatible = "xlnx,zynq-periph-clock",
- .data = zynq_periph_clk_setup, },
- { .compatible = "xlnx,zynq-cpu-clock", .data = zynq_cpu_clk_setup, },
- {}
-};
+CLK_OF_DECLARE(zynq_cpu, "xlnx,zynq-cpu-clock", zynq_cpu_clk_setup);
void __init xilinx_zynq_clocks_init(void __iomem *slcr)
{
slcr_base = slcr;
- of_clk_init(zynq_clk_match);
+ of_clk_init(NULL);
}
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 251e45d6024..fabbfe1a925 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/device.h>
+#include <linux/init.h>
static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock);
@@ -35,6 +36,137 @@ static struct dentry *rootdir;
static struct dentry *orphandir;
static int inited = 0;
+static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+{
+ if (!c)
+ return;
+
+ seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
+ level * 3 + 1, "",
+ 30 - level * 3, c->name,
+ c->enable_count, c->prepare_count, c->rate);
+ seq_printf(s, "\n");
+}
+
+static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+ int level)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ if (!c)
+ return;
+
+ clk_summary_show_one(s, c, level);
+
+ hlist_for_each_entry(child, tmp, &c->children, child_node)
+ clk_summary_show_subtree(s, child, level + 1);
+}
+
+static int clk_summary_show(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ struct hlist_node *tmp;
+
+ seq_printf(s, " clock enable_cnt prepare_cnt rate\n");
+ seq_printf(s, "---------------------------------------------------------------------\n");
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(c, tmp, &clk_root_list, child_node)
+ clk_summary_show_subtree(s, c, 0);
+
+ hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node)
+ clk_summary_show_subtree(s, c, 0);
+
+ mutex_unlock(&prepare_lock);
+
+ return 0;
+}
+
+
+static int clk_summary_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_summary_show, inode->i_private);
+}
+
+static const struct file_operations clk_summary_fops = {
+ .open = clk_summary_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+{
+ if (!c)
+ return;
+
+ seq_printf(s, "\"%s\": { ", c->name);
+ seq_printf(s, "\"enable_count\": %d,", c->enable_count);
+ seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+ seq_printf(s, "\"rate\": %lu", c->rate);
+}
+
+static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ if (!c)
+ return;
+
+ clk_dump_one(s, c, level);
+
+ hlist_for_each_entry(child, tmp, &c->children, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, child, level + 1);
+ }
+
+ seq_printf(s, "}");
+}
+
+static int clk_dump(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ struct hlist_node *tmp;
+ bool first_node = true;
+
+ seq_printf(s, "{");
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(c, tmp, &clk_root_list, child_node) {
+ if (!first_node)
+ seq_printf(s, ",");
+ first_node = false;
+ clk_dump_subtree(s, c, 0);
+ }
+
+ hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, c, 0);
+ }
+
+ mutex_unlock(&prepare_lock);
+
+ seq_printf(s, "}");
+ return 0;
+}
+
+
+static int clk_dump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_dump, inode->i_private);
+}
+
+static const struct file_operations clk_dump_fops = {
+ .open = clk_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{
@@ -168,12 +300,23 @@ static int __init clk_debug_init(void)
{
struct clk *clk;
struct hlist_node *tmp;
+ struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
if (!rootdir)
return -ENOMEM;
+ d = debugfs_create_file("clk_summary", S_IRUGO, rootdir, NULL,
+ &clk_summary_fops);
+ if (!d)
+ return -ENOMEM;
+
+ d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL,
+ &clk_dump_fops);
+ if (!d)
+ return -ENOMEM;
+
orphandir = debugfs_create_dir("orphans", rootdir);
if (!orphandir)
@@ -259,32 +402,33 @@ late_initcall(clk_disable_unused);
/*** helper functions ***/
-inline const char *__clk_get_name(struct clk *clk)
+const char *__clk_get_name(struct clk *clk)
{
return !clk ? NULL : clk->name;
}
+EXPORT_SYMBOL_GPL(__clk_get_name);
-inline struct clk_hw *__clk_get_hw(struct clk *clk)
+struct clk_hw *__clk_get_hw(struct clk *clk)
{
return !clk ? NULL : clk->hw;
}
-inline u8 __clk_get_num_parents(struct clk *clk)
+u8 __clk_get_num_parents(struct clk *clk)
{
return !clk ? 0 : clk->num_parents;
}
-inline struct clk *__clk_get_parent(struct clk *clk)
+struct clk *__clk_get_parent(struct clk *clk)
{
return !clk ? NULL : clk->parent;
}
-inline unsigned int __clk_get_enable_count(struct clk *clk)
+unsigned int __clk_get_enable_count(struct clk *clk)
{
return !clk ? 0 : clk->enable_count;
}
-inline unsigned int __clk_get_prepare_count(struct clk *clk)
+unsigned int __clk_get_prepare_count(struct clk *clk)
{
return !clk ? 0 : clk->prepare_count;
}
@@ -310,7 +454,7 @@ out:
return ret;
}
-inline unsigned long __clk_get_flags(struct clk *clk)
+unsigned long __clk_get_flags(struct clk *clk)
{
return !clk ? 0 : clk->flags;
}
@@ -950,9 +1094,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* change the rates */
clk_change_rate(top);
- mutex_unlock(&prepare_lock);
-
- return 0;
out:
mutex_unlock(&prepare_lock);
@@ -1663,6 +1804,11 @@ struct of_clk_provider {
void *data;
};
+extern struct of_device_id __clk_of_table[];
+
+static const struct of_device_id __clk_of_table_sentinel
+ __used __section(__clk_of_table_end);
+
static LIST_HEAD(of_clk_providers);
static DEFINE_MUTEX(of_clk_lock);
@@ -1791,6 +1937,9 @@ void __init of_clk_init(const struct of_device_id *matches)
{
struct device_node *np;
+ if (!matches)
+ matches = __clk_of_table;
+
for_each_matching_node(np, matches) {
const struct of_device_id *match = of_match_node(matches, np);
of_clk_init_cb_t clk_init_cb = match->data;
diff --git a/drivers/clk/mxs/clk-imx23.c b/drivers/clk/mxs/clk-imx23.c
index 8dd476e2a9c..b5c06f9766f 100644
--- a/drivers/clk/mxs/clk-imx23.c
+++ b/drivers/clk/mxs/clk-imx23.c
@@ -99,7 +99,7 @@ static enum imx23_clk clks_init_on[] __initdata = {
int __init mx23_clocks_init(void)
{
struct device_node *np;
- int i;
+ u32 i;
clk_misc_init();
diff --git a/drivers/clk/mxs/clk-imx28.c b/drivers/clk/mxs/clk-imx28.c
index db3af087412..126370a62ce 100644
--- a/drivers/clk/mxs/clk-imx28.c
+++ b/drivers/clk/mxs/clk-imx28.c
@@ -154,7 +154,7 @@ static enum imx28_clk clks_init_on[] __initdata = {
int __init mx28_clocks_init(void)
{
struct device_node *np;
- int i;
+ u32 i;
clk_misc_init();
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index dcb6ae0a042..256c8be74df 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -144,3 +144,4 @@ error:
vexpress_config_func_put(osc->func);
kfree(osc);
}
+CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
index c742ac7c60b..f889f2f07b3 100644
--- a/drivers/clk/versatile/clk-vexpress.c
+++ b/drivers/clk/versatile/clk-vexpress.c
@@ -99,19 +99,13 @@ struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
return vexpress_sp810_timerclken[clkspec->args[0]];
}
-static const __initconst struct of_device_id vexpress_fixed_clk_match[] = {
- { .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
- { .compatible = "arm,vexpress-osc", .data = vexpress_osc_of_setup, },
- {}
-};
-
void __init vexpress_clk_of_init(void)
{
struct device_node *node;
struct clk *clk;
struct clk *refclk, *timclk;
- of_clk_init(vexpress_fixed_clk_match);
+ of_clk_init(NULL);
node = of_find_compatible_node(NULL, NULL, "arm,sp810");
vexpress_sp810_init(of_iomap(node, 0));
diff --git a/drivers/clocksource/sunxi_timer.c b/drivers/clocksource/sunxi_timer.c
index 3cd1bd3d7ae..93d09d0e009 100644
--- a/drivers/clocksource/sunxi_timer.c
+++ b/drivers/clocksource/sunxi_timer.c
@@ -23,7 +23,7 @@
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/sunxi_timer.h>
-#include <linux/clk/sunxi.h>
+#include <linux/clk-provider.h>
#define TIMER_CTL_REG 0x00
#define TIMER_CTL_ENABLE (1 << 0)
@@ -124,7 +124,7 @@ static void __init sunxi_timer_init(void)
if (irq <= 0)
panic("Can't parse IRQ");
- sunxi_init_clocks();
+ of_clk_init(NULL);
clk = of_clk_get(node, 0);
if (IS_ERR(clk))
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index d1ea7ce0b4c..c1fe60ad154 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -150,6 +150,15 @@
#endif
+#ifdef CONFIG_COMMON_CLK
+#define CLK_OF_TABLES() . = ALIGN(8); \
+ VMLINUX_SYMBOL(__clk_of_table) = .; \
+ *(__clk_of_table) \
+ *(__clk_of_table_end)
+#else
+#define CLK_OF_TABLES()
+#endif
+
#define KERNEL_DTB() \
STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \
@@ -493,6 +502,7 @@
DEV_DISCARD(init.rodata) \
CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.rodata) \
+ CLK_OF_TABLES() \
KERNEL_DTB()
#define INIT_TEXT \
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 4989b8a7bed..7f197d7addb 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -379,7 +379,13 @@ struct clk_onecell_data {
};
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *data);
const char *of_clk_get_parent_name(struct device_node *np, int index);
+
void of_clk_init(const struct of_device_id *matches);
+#define CLK_OF_DECLARE(name, compat, fn) \
+ static const struct of_device_id __clk_of_table_##name \
+ __used __section(__clk_of_table) \
+ = { .compatible = compat, .data = fn };
+
#endif /* CONFIG_COMMON_CLK */
#endif /* CLK_PROVIDER_H */
diff --git a/include/linux/clk/sunxi.h b/include/linux/clk/sunxi.h
deleted file mode 100644
index e074fdd5a23..00000000000
--- a/include/linux/clk/sunxi.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright 2012 Maxime Ripard
- *
- * Maxime Ripard <maxime.ripard@free-electrons.com>
- *
- * 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.
- *
- * 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 __LINUX_CLK_SUNXI_H_
-#define __LINUX_CLK_SUNXI_H_
-
-void __init sunxi_init_clocks(void);
-
-#endif