提交 10b6339e 编写于 作者: L Linus Torvalds

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
  ...
* 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>;
};
...@@ -58,10 +58,11 @@ ...@@ -58,10 +58,11 @@
#size-cells = <1>; #size-cells = <1>;
ranges = <0x88000000 0x88000000 0x40000>; ranges = <0x88000000 0x88000000 0x40000>;
clock-controller@88000000 { clks: clock-controller@88000000 {
compatible = "sirf,prima2-clkc"; compatible = "sirf,prima2-clkc";
reg = <0x88000000 0x1000>; reg = <0x88000000 0x1000>;
interrupts = <3>; interrupts = <3>;
#clock-cells = <1>;
}; };
reset-controller@88010000 { reset-controller@88010000 {
...@@ -85,6 +86,7 @@ ...@@ -85,6 +86,7 @@
compatible = "sirf,prima2-memc"; compatible = "sirf,prima2-memc";
reg = <0x90000000 0x10000>; reg = <0x90000000 0x10000>;
interrupts = <27>; interrupts = <27>;
clocks = <&clks 5>;
}; };
}; };
...@@ -104,6 +106,7 @@ ...@@ -104,6 +106,7 @@
compatible = "sirf,prima2-vpp"; compatible = "sirf,prima2-vpp";
reg = <0x90020000 0x10000>; reg = <0x90020000 0x10000>;
interrupts = <31>; interrupts = <31>;
clocks = <&clks 35>;
}; };
}; };
...@@ -117,6 +120,7 @@ ...@@ -117,6 +120,7 @@
compatible = "powervr,sgx531"; compatible = "powervr,sgx531";
reg = <0x98000000 0x8000000>; reg = <0x98000000 0x8000000>;
interrupts = <6>; interrupts = <6>;
clocks = <&clks 32>;
}; };
}; };
...@@ -130,6 +134,7 @@ ...@@ -130,6 +134,7 @@
compatible = "sirf,prima2-video-codec"; compatible = "sirf,prima2-video-codec";
reg = <0xa0000000 0x8000000>; reg = <0xa0000000 0x8000000>;
interrupts = <5>; interrupts = <5>;
clocks = <&clks 33>;
}; };
}; };
...@@ -149,12 +154,14 @@ ...@@ -149,12 +154,14 @@
compatible = "sirf,prima2-gps"; compatible = "sirf,prima2-gps";
reg = <0xa8010000 0x10000>; reg = <0xa8010000 0x10000>;
interrupts = <7>; interrupts = <7>;
clocks = <&clks 9>;
}; };
dsp@a9000000 { dsp@a9000000 {
compatible = "sirf,prima2-dsp"; compatible = "sirf,prima2-dsp";
reg = <0xa9000000 0x1000000>; reg = <0xa9000000 0x1000000>;
interrupts = <8>; interrupts = <8>;
clocks = <&clks 8>;
}; };
}; };
...@@ -174,12 +181,14 @@ ...@@ -174,12 +181,14 @@
compatible = "sirf,prima2-nand"; compatible = "sirf,prima2-nand";
reg = <0xb0030000 0x10000>; reg = <0xb0030000 0x10000>;
interrupts = <41>; interrupts = <41>;
clocks = <&clks 26>;
}; };
audio@b0040000 { audio@b0040000 {
compatible = "sirf,prima2-audio"; compatible = "sirf,prima2-audio";
reg = <0xb0040000 0x10000>; reg = <0xb0040000 0x10000>;
interrupts = <35>; interrupts = <35>;
clocks = <&clks 27>;
}; };
uart0: uart@b0050000 { uart0: uart@b0050000 {
...@@ -187,6 +196,7 @@ ...@@ -187,6 +196,7 @@
compatible = "sirf,prima2-uart"; compatible = "sirf,prima2-uart";
reg = <0xb0050000 0x10000>; reg = <0xb0050000 0x10000>;
interrupts = <17>; interrupts = <17>;
clocks = <&clks 13>;
}; };
uart1: uart@b0060000 { uart1: uart@b0060000 {
...@@ -194,6 +204,7 @@ ...@@ -194,6 +204,7 @@
compatible = "sirf,prima2-uart"; compatible = "sirf,prima2-uart";
reg = <0xb0060000 0x10000>; reg = <0xb0060000 0x10000>;
interrupts = <18>; interrupts = <18>;
clocks = <&clks 14>;
}; };
uart2: uart@b0070000 { uart2: uart@b0070000 {
...@@ -201,6 +212,7 @@ ...@@ -201,6 +212,7 @@
compatible = "sirf,prima2-uart"; compatible = "sirf,prima2-uart";
reg = <0xb0070000 0x10000>; reg = <0xb0070000 0x10000>;
interrupts = <19>; interrupts = <19>;
clocks = <&clks 15>;
}; };
usp0: usp@b0080000 { usp0: usp@b0080000 {
...@@ -208,6 +220,7 @@ ...@@ -208,6 +220,7 @@
compatible = "sirf,prima2-usp"; compatible = "sirf,prima2-usp";
reg = <0xb0080000 0x10000>; reg = <0xb0080000 0x10000>;
interrupts = <20>; interrupts = <20>;
clocks = <&clks 28>;
}; };
usp1: usp@b0090000 { usp1: usp@b0090000 {
...@@ -215,6 +228,7 @@ ...@@ -215,6 +228,7 @@
compatible = "sirf,prima2-usp"; compatible = "sirf,prima2-usp";
reg = <0xb0090000 0x10000>; reg = <0xb0090000 0x10000>;
interrupts = <21>; interrupts = <21>;
clocks = <&clks 29>;
}; };
usp2: usp@b00a0000 { usp2: usp@b00a0000 {
...@@ -222,6 +236,7 @@ ...@@ -222,6 +236,7 @@
compatible = "sirf,prima2-usp"; compatible = "sirf,prima2-usp";
reg = <0xb00a0000 0x10000>; reg = <0xb00a0000 0x10000>;
interrupts = <22>; interrupts = <22>;
clocks = <&clks 30>;
}; };
dmac0: dma-controller@b00b0000 { dmac0: dma-controller@b00b0000 {
...@@ -229,6 +244,7 @@ ...@@ -229,6 +244,7 @@
compatible = "sirf,prima2-dmac"; compatible = "sirf,prima2-dmac";
reg = <0xb00b0000 0x10000>; reg = <0xb00b0000 0x10000>;
interrupts = <12>; interrupts = <12>;
clocks = <&clks 24>;
}; };
dmac1: dma-controller@b0160000 { dmac1: dma-controller@b0160000 {
...@@ -236,11 +252,13 @@ ...@@ -236,11 +252,13 @@
compatible = "sirf,prima2-dmac"; compatible = "sirf,prima2-dmac";
reg = <0xb0160000 0x10000>; reg = <0xb0160000 0x10000>;
interrupts = <13>; interrupts = <13>;
clocks = <&clks 25>;
}; };
vip@b00C0000 { vip@b00C0000 {
compatible = "sirf,prima2-vip"; compatible = "sirf,prima2-vip";
reg = <0xb00C0000 0x10000>; reg = <0xb00C0000 0x10000>;
clocks = <&clks 31>;
}; };
spi0: spi@b00d0000 { spi0: spi@b00d0000 {
...@@ -248,6 +266,7 @@ ...@@ -248,6 +266,7 @@
compatible = "sirf,prima2-spi"; compatible = "sirf,prima2-spi";
reg = <0xb00d0000 0x10000>; reg = <0xb00d0000 0x10000>;
interrupts = <15>; interrupts = <15>;
clocks = <&clks 19>;
}; };
spi1: spi@b0170000 { spi1: spi@b0170000 {
...@@ -255,6 +274,7 @@ ...@@ -255,6 +274,7 @@
compatible = "sirf,prima2-spi"; compatible = "sirf,prima2-spi";
reg = <0xb0170000 0x10000>; reg = <0xb0170000 0x10000>;
interrupts = <16>; interrupts = <16>;
clocks = <&clks 20>;
}; };
i2c0: i2c@b00e0000 { i2c0: i2c@b00e0000 {
...@@ -262,6 +282,7 @@ ...@@ -262,6 +282,7 @@
compatible = "sirf,prima2-i2c"; compatible = "sirf,prima2-i2c";
reg = <0xb00e0000 0x10000>; reg = <0xb00e0000 0x10000>;
interrupts = <24>; interrupts = <24>;
clocks = <&clks 17>;
}; };
i2c1: i2c@b00f0000 { i2c1: i2c@b00f0000 {
...@@ -269,12 +290,14 @@ ...@@ -269,12 +290,14 @@
compatible = "sirf,prima2-i2c"; compatible = "sirf,prima2-i2c";
reg = <0xb00f0000 0x10000>; reg = <0xb00f0000 0x10000>;
interrupts = <25>; interrupts = <25>;
clocks = <&clks 18>;
}; };
tsc@b0110000 { tsc@b0110000 {
compatible = "sirf,prima2-tsc"; compatible = "sirf,prima2-tsc";
reg = <0xb0110000 0x10000>; reg = <0xb0110000 0x10000>;
interrupts = <33>; interrupts = <33>;
clocks = <&clks 16>;
}; };
gpio: pinctrl@b0120000 { gpio: pinctrl@b0120000 {
...@@ -507,17 +530,20 @@ ...@@ -507,17 +530,20 @@
pwm@b0130000 { pwm@b0130000 {
compatible = "sirf,prima2-pwm"; compatible = "sirf,prima2-pwm";
reg = <0xb0130000 0x10000>; reg = <0xb0130000 0x10000>;
clocks = <&clks 21>;
}; };
efusesys@b0140000 { efusesys@b0140000 {
compatible = "sirf,prima2-efuse"; compatible = "sirf,prima2-efuse";
reg = <0xb0140000 0x10000>; reg = <0xb0140000 0x10000>;
clocks = <&clks 22>;
}; };
pulsec@b0150000 { pulsec@b0150000 {
compatible = "sirf,prima2-pulsec"; compatible = "sirf,prima2-pulsec";
reg = <0xb0150000 0x10000>; reg = <0xb0150000 0x10000>;
interrupts = <48>; interrupts = <48>;
clocks = <&clks 23>;
}; };
pci-iobg { pci-iobg {
...@@ -616,12 +642,14 @@ ...@@ -616,12 +642,14 @@
compatible = "chipidea,ci13611a-prima2"; compatible = "chipidea,ci13611a-prima2";
reg = <0xb8000000 0x10000>; reg = <0xb8000000 0x10000>;
interrupts = <10>; interrupts = <10>;
clocks = <&clks 40>;
}; };
usb1: usb@b00f0000 { usb1: usb@b00f0000 {
compatible = "chipidea,ci13611a-prima2"; compatible = "chipidea,ci13611a-prima2";
reg = <0xb8010000 0x10000>; reg = <0xb8010000 0x10000>;
interrupts = <11>; interrupts = <11>;
clocks = <&clks 41>;
}; };
sata@b00f0000 { sata@b00f0000 {
...@@ -634,6 +662,7 @@ ...@@ -634,6 +662,7 @@
compatible = "sirf,prima2-security"; compatible = "sirf,prima2-security";
reg = <0xb8030000 0x10000>; reg = <0xb8030000 0x10000>;
interrupts = <42>; interrupts = <42>;
clocks = <&clks 7>;
}; };
}; };
}; };
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
#define __HIGHBANK_CORE_H #define __HIGHBANK_CORE_H
extern void highbank_set_cpu_jump(int cpu, void *jump_addr); 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 highbank_restart(char, const char *);
extern void __iomem *scu_base_addr; extern void __iomem *scu_base_addr;
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/clk-provider.h>
#include <asm/arch_timer.h> #include <asm/arch_timer.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -117,7 +118,7 @@ static void __init highbank_timer_init(void) ...@@ -117,7 +118,7 @@ static void __init highbank_timer_init(void)
WARN_ON(!timer_base); WARN_ON(!timer_base);
irq = irq_of_parse_and_map(np, 0); irq = irq_of_parse_and_map(np, 0);
highbank_clocks_init(); of_clk_init(NULL);
lookup.clk = of_clk_get(np, 0); lookup.clk = of_clk_get(np, 0);
clkdev_add(&lookup); clkdev_add(&lookup);
......
# common clock types # common clock types
obj-$(CONFIG_HAVE_CLK) += clk-devres.o obj-$(CONFIG_HAVE_CLK) += clk-devres.o
obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
obj-$(CONFIG_COMMON_CLK) += clk.o clk-fixed-rate.o clk-gate.o \ obj-$(CONFIG_COMMON_CLK) += clk.o
clk-mux.o clk-divider.o clk-fixed-factor.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 # SoCs specific
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
...@@ -20,7 +25,6 @@ endif ...@@ -20,7 +25,6 @@ endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_ARCH_U8500) += ux500/ obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
obj-$(CONFIG_ARCH_SUNXI) += clk-sunxi.o
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
# Chip specific # Chip specific
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/log2.h>
/* /*
* DOC: basic adjustable divider clock that cannot gate * DOC: basic adjustable divider clock that cannot gate
...@@ -29,8 +30,7 @@ ...@@ -29,8 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw) #define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#define div_mask(d) ((1 << (d->width)) - 1) #define div_mask(d) ((1 << ((d)->width)) - 1)
#define is_power_of_two(i) !(i & ~i)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table) 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, ...@@ -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) static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
{ {
if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_two(div); return is_power_of_2(div);
if (divider->table) if (divider->table)
return _is_valid_table_div(divider->table, div); return _is_valid_table_div(divider->table, div);
return true; return true;
......
...@@ -28,8 +28,11 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw, ...@@ -28,8 +28,11 @@ static unsigned long clk_factor_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_fixed_factor *fix = to_clk_fixed_factor(hw); 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, static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
......
...@@ -85,7 +85,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name, ...@@ -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 * 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; struct clk *clk;
const char *clk_name = node->name; const char *clk_name = node->name;
...@@ -101,4 +101,5 @@ void __init of_fixed_clk_setup(struct device_node *node) ...@@ -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); of_clk_add_provider(node, of_clk_src_simple_get, clk);
} }
EXPORT_SYMBOL_GPL(of_fixed_clk_setup); EXPORT_SYMBOL_GPL(of_fixed_clk_setup);
CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
#endif #endif
...@@ -314,33 +314,23 @@ static void __init hb_pll_init(struct device_node *node) ...@@ -314,33 +314,23 @@ static void __init hb_pll_init(struct device_node *node)
{ {
hb_clk_init(node, &clk_pll_ops); 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) static void __init hb_a9periph_init(struct device_node *node)
{ {
hb_clk_init(node, &a9periphclk_ops); 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) static void __init hb_a9bus_init(struct device_node *node)
{ {
struct clk *clk = hb_clk_init(node, &a9bclk_ops); struct clk *clk = hb_clk_init(node, &a9bclk_ops);
clk_prepare_enable(clk); 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) static void __init hb_emmc_init(struct device_node *node)
{ {
hb_clk_init(node, &periclk_ops); hb_clk_init(node, &periclk_ops);
} }
CLK_OF_DECLARE(hb_emmc, "calxeda,hb-emmc-clock", hb_emmc_init);
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);
}
...@@ -44,33 +44,23 @@ struct max77686_clk { ...@@ -44,33 +44,23 @@ struct max77686_clk {
struct clk_lookup *lookup; 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); return container_of(hw, struct max77686_clk, hw);
} }
static int max77686_clk_prepare(struct clk_hw *hw) static int max77686_clk_prepare(struct clk_hw *hw)
{ {
struct max77686_clk *max77686; struct max77686_clk *max77686 = to_max77686_clk(hw);
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);
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) static void max77686_clk_unprepare(struct clk_hw *hw)
{ {
struct max77686_clk *max77686; struct max77686_clk *max77686 = to_max77686_clk(hw);
max77686 = get_max77686_clk(hw);
if (!max77686)
return;
regmap_update_bits(max77686->iodev->regmap, regmap_update_bits(max77686->iodev->regmap,
MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask); MAX77686_REG_32KHZ, max77686->mask, ~max77686->mask);
...@@ -78,14 +68,10 @@ static void max77686_clk_unprepare(struct clk_hw *hw) ...@@ -78,14 +68,10 @@ static void max77686_clk_unprepare(struct clk_hw *hw)
static int max77686_clk_is_enabled(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; int ret;
u32 val; u32 val;
max77686 = get_max77686_clk(hw);
if (!max77686)
return -ENOMEM;
ret = regmap_read(max77686->iodev->regmap, ret = regmap_read(max77686->iodev->regmap,
MAX77686_REG_32KHZ, &val); MAX77686_REG_32KHZ, &val);
...@@ -130,9 +116,8 @@ static int max77686_clk_register(struct device *dev, ...@@ -130,9 +116,8 @@ static int max77686_clk_register(struct device *dev,
if (IS_ERR(clk)) if (IS_ERR(clk))
return -ENOMEM; return -ENOMEM;
max77686->lookup = devm_kzalloc(dev, sizeof(struct clk_lookup), max77686->lookup = kzalloc(sizeof(struct clk_lookup), GFP_KERNEL);
GFP_KERNEL); if (!max77686->lookup)
if (IS_ERR(max77686->lookup))
return -ENOMEM; return -ENOMEM;
max77686->lookup->con_id = hw->init->name; max77686->lookup->con_id = hw->init->name;
...@@ -151,13 +136,13 @@ static int max77686_clk_probe(struct platform_device *pdev) ...@@ -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 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_clk *)
* MAX77686_CLKS_NUM, GFP_KERNEL); * MAX77686_CLKS_NUM, GFP_KERNEL);
if (IS_ERR(max77686_clks)) if (!max77686_clks)
return -ENOMEM; return -ENOMEM;
for (i = 0; i < MAX77686_CLKS_NUM; i++) { for (i = 0; i < MAX77686_CLKS_NUM; i++) {
max77686_clks[i] = devm_kzalloc(&pdev->dev, max77686_clks[i] = devm_kzalloc(&pdev->dev,
sizeof(struct max77686_clk), GFP_KERNEL); sizeof(struct max77686_clk), GFP_KERNEL);
if (IS_ERR(max77686_clks[i])) if (!max77686_clks[i])
return -ENOMEM; return -ENOMEM;
} }
......
...@@ -1025,20 +1025,67 @@ static struct of_device_id rsc_ids[] = { ...@@ -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) void __init sirfsoc_of_clk_init(void)
{ {
struct clk *clk;
struct device_node *np; struct device_node *np;
int i;
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);
np = of_find_matching_node(NULL, rsc_ids); np = of_find_matching_node(NULL, rsc_ids);
if (!np) if (!np)
...@@ -1050,122 +1097,30 @@ void __init sirfsoc_of_clk_init(void) ...@@ -1050,122 +1097,30 @@ void __init sirfsoc_of_clk_init(void)
of_node_put(np); 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)*/ /* 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); CLK_IS_ROOT, 32768);
BUG_ON(IS_ERR(clk)); prima2_clks[osc]= clk_register_fixed_rate(NULL, "osc", NULL,
clk = clk_register_fixed_rate(NULL, "osc", NULL,
CLK_IS_ROOT, 26000000); CLK_IS_ROOT, 26000000);
BUG_ON(IS_ERR(clk));
for (i = pll1; i < maxclk; i++) {
clk = clk_register(NULL, &clk_pll1.hw); prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
BUG_ON(IS_ERR(clk)); BUG_ON(!prima2_clks[i]);
clk = clk_register(NULL, &clk_pll2.hw); }
BUG_ON(IS_ERR(clk)); clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
clk = clk_register(NULL, &clk_pll3.hw); clk_register_clkdev(prima2_clks[io], NULL, "io");
BUG_ON(IS_ERR(clk)); clk_register_clkdev(prima2_clks[mem], NULL, "mem");
clk = clk_register(NULL, &clk_mem.hw);
BUG_ON(IS_ERR(clk)); clk_data.clks = prima2_clks;
clk = clk_register(NULL, &clk_sys.hw); clk_data.clk_num = maxclk;
BUG_ON(IS_ERR(clk));
clk = clk_register(NULL, &clk_security.hw); of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
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");
} }
/*
* 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);
}
...@@ -41,6 +41,7 @@ struct clk_device { ...@@ -41,6 +41,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0 #define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1 #define PLL_TYPE_WM8650 1
#define PLL_TYPE_WM8750 2
struct clk_pll { struct clk_pll {
struct clk_hw hw; struct clk_hw hw;
...@@ -121,7 +122,16 @@ static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -121,7 +122,16 @@ static long vt8500_dclk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate) unsigned long *prate)
{ {
struct clk_device *cdev = to_clk_device(hw); 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 * 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, ...@@ -138,9 +148,18 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_device *cdev = to_clk_device(hw); struct clk_device *cdev = to_clk_device(hw);
u32 divisor = parent_rate / rate; u32 divisor;
unsigned long flags = 0; 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) if (divisor == cdev->div_mask + 1)
divisor = 0; divisor = 0;
...@@ -272,7 +291,7 @@ static __init void vtwm_device_clk_init(struct device_node *node) ...@@ -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); rc = of_clk_add_provider(node, of_clk_src_simple_get, clk);
clk_register_clkdev(clk, clk_name, NULL); clk_register_clkdev(clk, clk_name, NULL);
} }
CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
/* PLL clock related functions */ /* PLL clock related functions */
...@@ -298,6 +317,16 @@ static __init void vtwm_device_clk_init(struct device_node *node) ...@@ -298,6 +317,16 @@ static __init void vtwm_device_clk_init(struct device_node *node)
#define WM8650_BITS_TO_VAL(m, d1, d2) \ #define WM8650_BITS_TO_VAL(m, d1, d2) \
((d2 << 13) | (d1 << 10) | (m & 0x3FF)) ((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, static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv) u32 *multiplier, u32 *prediv)
...@@ -361,16 +390,87 @@ static void wm8650_find_pll_bits(unsigned long rate, unsigned long parent_rate, ...@@ -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 */ /* if we got here, it wasn't an exact match */
pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate, pr_warn("%s: requested rate %lu, found rate %lu\n", __func__, rate,
rate - best_err); rate - best_err);
*multiplier = mul; *multiplier = best_mul;
*divisor1 = div1; *divisor1 = best_div1;
*divisor2 = div2; *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, static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
u32 mul, div1, div2; u32 filter, mul, div1, div2;
u32 pll_val; u32 pll_val;
unsigned long flags = 0; unsigned long flags = 0;
...@@ -385,6 +485,9 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate, ...@@ -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); wm8650_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
pll_val = WM8650_BITS_TO_VAL(mul, div1, div2); pll_val = WM8650_BITS_TO_VAL(mul, div1, div2);
break; 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: default:
pr_err("%s: invalid pll type\n", __func__); pr_err("%s: invalid pll type\n", __func__);
return 0; return 0;
...@@ -405,7 +508,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -405,7 +508,7 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate) unsigned long *prate)
{ {
struct clk_pll *pll = to_clk_pll(hw); struct clk_pll *pll = to_clk_pll(hw);
u32 mul, div1, div2; u32 filter, mul, div1, div2;
long round_rate; long round_rate;
switch (pll->type) { switch (pll->type) {
...@@ -417,6 +520,9 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -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); wm8650_find_pll_bits(rate, *prate, &mul, &div1, &div2);
round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2); round_rate = WM8650_BITS_TO_FREQ(*prate, mul, div1, div2);
break; 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: default:
round_rate = 0; round_rate = 0;
} }
...@@ -440,6 +546,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw, ...@@ -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 = parent_rate * WM8650_PLL_MUL(pll_val);
pll_freq /= WM8650_PLL_DIV(pll_val); pll_freq /= WM8650_PLL_DIV(pll_val);
break; break;
case PLL_TYPE_WM8750:
pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
pll_freq /= WM8750_PLL_DIV(pll_val);
break;
default: default:
pll_freq = 0; pll_freq = 0;
} }
...@@ -502,20 +612,19 @@ static void __init vt8500_pll_init(struct device_node *node) ...@@ -502,20 +612,19 @@ static void __init vt8500_pll_init(struct device_node *node)
{ {
vtwm_pll_clk_init(node, PLL_TYPE_VT8500); 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) static void __init wm8650_pll_init(struct device_node *node)
{ {
vtwm_pll_clk_init(node, PLL_TYPE_WM8650); 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[] = { static void __init wm8750_pll_init(struct device_node *node)
{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, }, {
{ .compatible = "via,vt8500-pll-clock", .data = vt8500_pll_init, }, vtwm_pll_clk_init(node, PLL_TYPE_WM8750);
{ .compatible = "wm,wm8650-pll-clock", .data = wm8650_pll_init, }, }
{ .compatible = "via,vt8500-device-clock", CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
.data = vtwm_device_clk_init, },
{ /* sentinel */ }
};
void __init vtwm_clk_init(void __iomem *base) void __init vtwm_clk_init(void __iomem *base)
{ {
...@@ -524,5 +633,5 @@ void __init vtwm_clk_init(void __iomem *base) ...@@ -524,5 +633,5 @@ void __init vtwm_clk_init(void __iomem *base)
pmc_base = base; pmc_base = base;
of_clk_init(clk_match); of_clk_init(NULL);
} }
...@@ -81,6 +81,7 @@ static void __init zynq_pll_clk_setup(struct device_node *np) ...@@ -81,6 +81,7 @@ static void __init zynq_pll_clk_setup(struct device_node *np)
if (WARN_ON(ret)) if (WARN_ON(ret))
return; return;
} }
CLK_OF_DECLARE(zynq_pll, "xlnx,zynq-pll", zynq_pll_clk_setup);
struct zynq_periph_clk { struct zynq_periph_clk {
struct clk_hw hw; struct clk_hw hw;
...@@ -187,6 +188,7 @@ static void __init zynq_periph_clk_setup(struct device_node *np) ...@@ -187,6 +188,7 @@ static void __init zynq_periph_clk_setup(struct device_node *np)
if (WARN_ON(err)) if (WARN_ON(err))
return; 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 /* CPU Clock domain is modelled as a mux with 4 children subclks, whose
* derivative rates depend on CLK_621_TRUE * derivative rates depend on CLK_621_TRUE
...@@ -366,18 +368,10 @@ static void __init zynq_cpu_clk_setup(struct device_node *np) ...@@ -366,18 +368,10 @@ static void __init zynq_cpu_clk_setup(struct device_node *np)
if (WARN_ON(err)) if (WARN_ON(err))
return; return;
} }
CLK_OF_DECLARE(zynq_cpu, "xlnx,zynq-cpu-clock", zynq_cpu_clk_setup);
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, },
{}
};
void __init xilinx_zynq_clocks_init(void __iomem *slcr) void __init xilinx_zynq_clocks_init(void __iomem *slcr)
{ {
slcr_base = slcr; slcr_base = slcr;
of_clk_init(zynq_clk_match); of_clk_init(NULL);
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/init.h>
static DEFINE_SPINLOCK(enable_lock); static DEFINE_SPINLOCK(enable_lock);
static DEFINE_MUTEX(prepare_lock); static DEFINE_MUTEX(prepare_lock);
...@@ -35,6 +36,137 @@ static struct dentry *rootdir; ...@@ -35,6 +36,137 @@ static struct dentry *rootdir;
static struct dentry *orphandir; static struct dentry *orphandir;
static int inited = 0; 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 */ /* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{ {
...@@ -168,12 +300,23 @@ static int __init clk_debug_init(void) ...@@ -168,12 +300,23 @@ static int __init clk_debug_init(void)
{ {
struct clk *clk; struct clk *clk;
struct hlist_node *tmp; struct hlist_node *tmp;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL); rootdir = debugfs_create_dir("clk", NULL);
if (!rootdir) if (!rootdir)
return -ENOMEM; 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); orphandir = debugfs_create_dir("orphans", rootdir);
if (!orphandir) if (!orphandir)
...@@ -259,32 +402,33 @@ late_initcall(clk_disable_unused); ...@@ -259,32 +402,33 @@ late_initcall(clk_disable_unused);
/*** helper functions ***/ /*** helper functions ***/
inline const char *__clk_get_name(struct clk *clk) const char *__clk_get_name(struct clk *clk)
{ {
return !clk ? NULL : clk->name; 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; 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; 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; 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; 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; return !clk ? 0 : clk->prepare_count;
} }
...@@ -310,7 +454,7 @@ unsigned long __clk_get_rate(struct clk *clk) ...@@ -310,7 +454,7 @@ unsigned long __clk_get_rate(struct clk *clk)
return ret; return ret;
} }
inline unsigned long __clk_get_flags(struct clk *clk) unsigned long __clk_get_flags(struct clk *clk)
{ {
return !clk ? 0 : clk->flags; return !clk ? 0 : clk->flags;
} }
...@@ -950,9 +1094,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate) ...@@ -950,9 +1094,6 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* change the rates */ /* change the rates */
clk_change_rate(top); clk_change_rate(top);
mutex_unlock(&prepare_lock);
return 0;
out: out:
mutex_unlock(&prepare_lock); mutex_unlock(&prepare_lock);
...@@ -1663,6 +1804,11 @@ struct of_clk_provider { ...@@ -1663,6 +1804,11 @@ struct of_clk_provider {
void *data; 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 LIST_HEAD(of_clk_providers);
static DEFINE_MUTEX(of_clk_lock); static DEFINE_MUTEX(of_clk_lock);
...@@ -1791,6 +1937,9 @@ void __init of_clk_init(const struct of_device_id *matches) ...@@ -1791,6 +1937,9 @@ void __init of_clk_init(const struct of_device_id *matches)
{ {
struct device_node *np; struct device_node *np;
if (!matches)
matches = __clk_of_table;
for_each_matching_node(np, matches) { for_each_matching_node(np, matches) {
const struct of_device_id *match = of_match_node(matches, np); const struct of_device_id *match = of_match_node(matches, np);
of_clk_init_cb_t clk_init_cb = match->data; of_clk_init_cb_t clk_init_cb = match->data;
......
...@@ -99,7 +99,7 @@ static enum imx23_clk clks_init_on[] __initdata = { ...@@ -99,7 +99,7 @@ static enum imx23_clk clks_init_on[] __initdata = {
int __init mx23_clocks_init(void) int __init mx23_clocks_init(void)
{ {
struct device_node *np; struct device_node *np;
int i; u32 i;
clk_misc_init(); clk_misc_init();
......
...@@ -154,7 +154,7 @@ static enum imx28_clk clks_init_on[] __initdata = { ...@@ -154,7 +154,7 @@ static enum imx28_clk clks_init_on[] __initdata = {
int __init mx28_clocks_init(void) int __init mx28_clocks_init(void)
{ {
struct device_node *np; struct device_node *np;
int i; u32 i;
clk_misc_init(); clk_misc_init();
......
...@@ -144,3 +144,4 @@ void __init vexpress_osc_of_setup(struct device_node *node) ...@@ -144,3 +144,4 @@ void __init vexpress_osc_of_setup(struct device_node *node)
vexpress_config_func_put(osc->func); vexpress_config_func_put(osc->func);
kfree(osc); kfree(osc);
} }
CLK_OF_DECLARE(vexpress_soc, "arm,vexpress-osc", vexpress_osc_of_setup);
...@@ -99,19 +99,13 @@ struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data) ...@@ -99,19 +99,13 @@ struct clk *vexpress_sp810_of_get(struct of_phandle_args *clkspec, void *data)
return vexpress_sp810_timerclken[clkspec->args[0]]; 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) void __init vexpress_clk_of_init(void)
{ {
struct device_node *node; struct device_node *node;
struct clk *clk; struct clk *clk;
struct clk *refclk, *timclk; struct clk *refclk, *timclk;
of_clk_init(vexpress_fixed_clk_match); of_clk_init(NULL);
node = of_find_compatible_node(NULL, NULL, "arm,sp810"); node = of_find_compatible_node(NULL, NULL, "arm,sp810");
vexpress_sp810_init(of_iomap(node, 0)); vexpress_sp810_init(of_iomap(node, 0));
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/sunxi_timer.h> #include <linux/sunxi_timer.h>
#include <linux/clk/sunxi.h> #include <linux/clk-provider.h>
#define TIMER_CTL_REG 0x00 #define TIMER_CTL_REG 0x00
#define TIMER_CTL_ENABLE (1 << 0) #define TIMER_CTL_ENABLE (1 << 0)
...@@ -124,7 +124,7 @@ static void __init sunxi_timer_init(void) ...@@ -124,7 +124,7 @@ static void __init sunxi_timer_init(void)
if (irq <= 0) if (irq <= 0)
panic("Can't parse IRQ"); panic("Can't parse IRQ");
sunxi_init_clocks(); of_clk_init(NULL);
clk = of_clk_get(node, 0); clk = of_clk_get(node, 0);
if (IS_ERR(clk)) if (IS_ERR(clk))
......
...@@ -150,6 +150,15 @@ ...@@ -150,6 +150,15 @@
#endif #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() \ #define KERNEL_DTB() \
STRUCT_ALIGN(); \ STRUCT_ALIGN(); \
VMLINUX_SYMBOL(__dtb_start) = .; \ VMLINUX_SYMBOL(__dtb_start) = .; \
...@@ -493,6 +502,7 @@ ...@@ -493,6 +502,7 @@
DEV_DISCARD(init.rodata) \ DEV_DISCARD(init.rodata) \
CPU_DISCARD(init.rodata) \ CPU_DISCARD(init.rodata) \
MEM_DISCARD(init.rodata) \ MEM_DISCARD(init.rodata) \
CLK_OF_TABLES() \
KERNEL_DTB() KERNEL_DTB()
#define INIT_TEXT \ #define INIT_TEXT \
......
...@@ -379,7 +379,13 @@ struct clk_onecell_data { ...@@ -379,7 +379,13 @@ struct clk_onecell_data {
}; };
struct clk *of_clk_src_onecell_get(struct of_phandle_args *clkspec, void *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); const char *of_clk_get_parent_name(struct device_node *np, int index);
void of_clk_init(const struct of_device_id *matches); 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 /* CONFIG_COMMON_CLK */
#endif /* CLK_PROVIDER_H */ #endif /* CLK_PROVIDER_H */
/*
* 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
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册