2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-26 19:44:21 +08:00

The common clock framework changes for 3.11 include new clock drivers

across several different platforms and architectures, fixes to existing
 drivers, a MAINTAINERS file fix and improvements to the basic clock
 types that allow them to be of use to more platforms than before. Only a
 few fixes to the core framework are included with most all of the
 changes landing in the various clock drivers themselves.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJR0hFpAAoJEDqPOy9afJhJcr4P/iA83uEGXIncUzFsbCIsKNGl
 g8yoasz1mpcAng31kK54lasNpFvUYIEBLKWkJBN56h2J5gJ3OKpi7basnQGRykjh
 +rCg2dV4gKDBQzypdeg5kPxf0YLJ8KrwyngcRm5KA3oxKYtmLHt/M2jmDd3DXP0h
 dKo2bkR52eQ7E+ij6/MWgUObxWiFnH0C5Lf+L0tGHsRlRvZTV6NMymX2v0sIOCw9
 hpsrL+7Hqf/+PBfWBljH0IAiI72I5dGEaJoesdTRWz8qut+duwF+OGlzMZnkclMf
 XU444HnvCq3bWGP5NYf9ASO4RRA2IGEoN/eDeiVX5hvkAjeUNHVNhkcUk28Xn9vI
 ZxCxwBXki4wGayiQm4TTgORozmp4i+NwbOuG+s3For1qQU43aA7ppwysFHGXngQa
 bxXT2pNECLX8WR91vkmEdqeQVm6s++R3zltHFUry1VRjTIs5y18Dt9kR6T16NKKQ
 ztoegeQQ8SI7HOLd+tR2v19VXH4zoV3NYAdkCKJX+VXFg+4mgJERmXoU350V3d8D
 wxde7WU4KLO4+1Fngror8wocP8jRRHfhx5jbBVVJ5n6BnF/Mos24g7KI1VPis3Wr
 XZQibxLW0kZ7/hTHykZCff8D4aNqR4fT/UCKyy2Xw1aR0zkD9ZAQq5oWhL99lsnt
 cCe9GBP0Lum9Zq9jjMwL
 =SwMB
 -----END PGP SIGNATURE-----

Merge tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux

Pull clock framework updates from Mike Turquette:
 "The common clock framework changes for 3.11 include new clock drivers
  across several different platforms and architectures, fixes to
  existing drivers, a MAINTAINERS file fix and improvements to the basic
  clock types that allow them to be of use to more platforms than before.

  Only a few fixes to the core framework are included with most all of
  the changes landing in the various clock drivers themselves."

* tag 'clk-for-linus-3.11' of git://git.linaro.org/people/mturquette/linux: (55 commits)
  clk: tegra: fix ifdef for tegra_periph_reset_assert inline
  clk: tegra: provide tegra_periph_reset_assert alternative
  clk: exynos4: Fix clock aliases for cpufreq related clocks
  clk: samsung: Add MUX_FA macro to pass flag and alias
  clk: add support for Rockchip gate clocks
  clk: vexpress: Make the clock drivers directly available for arm64
  clk: vexpress: Use full node name to identify individual clocks
  clk: tegra: T114: add DFLL DVCO reset control
  clk: tegra: T114: add DFLL source clocks
  clk: tegra: T114: add FCPU clock shaper programming, needed by the DFLL
  clk: gate: add CLK_GATE_HIWORD_MASK
  clk: divider: add CLK_DIVIDER_HIWORD_MASK flag
  clk: mux: add CLK_MUX_HIWORD_MASK
  clk: Always notify whole subtree when reparenting
  MAINTAINERS: make drivers/clk entry match subdirs
  clk: honor CLK_GET_RATE_NOCACHE in clk_set_rate
  clk: use clk_get_rate() for debugfs
  clk: tegra: Use override bits when needed
  clk: tegra: override bits for Tegra30 PLLM
  clk: tegra: override bits for Tegra114 PLLM
  ...
This commit is contained in:
Linus Torvalds 2013-07-03 11:54:50 -07:00
commit 92295f632c
47 changed files with 2259 additions and 413 deletions

View File

@ -0,0 +1,24 @@
TI-NSPIRE Clocks
Required properties:
- compatible: Valid compatible properties include:
"lsi,nspire-cx-ahb-divider" for the AHB divider in the CX model
"lsi,nspire-classic-ahb-divider" for the AHB divider in the older model
"lsi,nspire-cx-clock" for the base clock in the CX model
"lsi,nspire-classic-clock" for the base clock in the older model
- reg: Physical base address of the controller and length of memory mapped
region.
Optional:
- clocks: For the "nspire-*-ahb-divider" compatible clocks, this is the parent
clock where it divides the rate from.
Example:
ahb_clk {
#clock-cells = <0>;
compatible = "lsi,nspire-cx-clock";
reg = <0x900B0000 0x4>;
clocks = <&base_clk>;
};

View File

@ -0,0 +1,74 @@
Device Tree Clock bindings for arch-rockchip
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
== Gate clocks ==
The gate registers form a continuos block which makes the dt node
structure a matter of taste, as either all gates can be put into
one gate clock spanning all registers or they can be divided into
the 10 individual gates containing 16 clocks each.
The code supports both approaches.
Required properties:
- compatible : "rockchip,rk2928-gate-clk"
- reg : shall be the control register address(es) for the clock.
- #clock-cells : from common clock binding; shall be set to 1
- clock-output-names : the corresponding gate names that the clock controls
- clocks : should contain the parent clock for each individual gate,
therefore the number of clocks elements should match the number of
clock-output-names
Example using multiple gate clocks:
clk_gates0: gate-clk@200000d0 {
compatible = "rockchip,rk2928-gate-clk";
reg = <0x200000d0 0x4>;
clocks = <&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>,
<&dummy>, <&dummy>;
clock-output-names =
"gate_core_periph", "gate_cpu_gpll",
"gate_ddrphy", "gate_aclk_cpu",
"gate_hclk_cpu", "gate_pclk_cpu",
"gate_atclk_cpu", "gate_i2s0",
"gate_i2s0_frac", "gate_i2s1",
"gate_i2s1_frac", "gate_i2s2",
"gate_i2s2_frac", "gate_spdif",
"gate_spdif_frac", "gate_testclk";
#clock-cells = <1>;
};
clk_gates1: gate-clk@200000d4 {
compatible = "rockchip,rk2928-gate-clk";
reg = <0x200000d4 0x4>;
clocks = <&xin24m>, <&xin24m>,
<&xin24m>, <&dummy>,
<&dummy>, <&xin24m>,
<&xin24m>, <&dummy>,
<&xin24m>, <&dummy>,
<&xin24m>, <&dummy>,
<&xin24m>, <&dummy>,
<&xin24m>, <&dummy>;
clock-output-names =
"gate_timer0", "gate_timer1",
"gate_timer2", "gate_jtag",
"gate_aclk_lcdc1_src", "gate_otgphy0",
"gate_otgphy1", "gate_ddr_gpll",
"gate_uart0", "gate_frac_uart0",
"gate_uart1", "gate_frac_uart1",
"gate_uart2", "gate_frac_uart2",
"gate_uart3", "gate_frac_uart3";
#clock-cells = <1>;
};

View File

@ -44,6 +44,11 @@ Optional child node properties:
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
divider.
- silabs,pll-master: boolean, multisynth can change pll frequency.
- silabs,disable-state : clock output disable state, shall be
0 = clock output is driven LOW when disabled
1 = clock output is driven HIGH when disabled
2 = clock output is FLOATING (HIGH-Z) when disabled
3 = clock output is NEVER disabled
==Example==

View File

@ -12,22 +12,30 @@ Required properties:
"allwinner,sun4i-axi-clk" - for the AXI clock
"allwinner,sun4i-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-ahb-clk" - for the AHB clock
"allwinner,sun4i-ahb-gates-clk" - for the AHB gates
"allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
"allwinner,sun4i-apb0-clk" - for the APB0 clock
"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun4i-apb1-clk" - for the APB1 clock
"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates
"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
"allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
Required properties for all clocks:
- reg : shall be the control register address for the clock.
- clocks : shall be the input parent clock(s) phandle for the clock
- #clock-cells : from common clock binding; shall be set to 0 except for
"allwinner,sun4i-*-gates-clk" where it shall be set to 1
"allwinner,*-gates-clk" where it shall be set to 1
Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
Additionally, "allwinner,*-gates-clk" clocks require:
- clock-output-names : the corresponding gate names that the clock controls
Clock consumers should specify the desired clocks they use with a
"clocks" phandle cell. Consumers that are using a gated clock should
provide an additional ID in their clock property. The values of this
ID are documented in sunxi/<soc>-gates.txt.
For example:
osc24M: osc24M@01c20050 {
@ -50,102 +58,3 @@ cpu: cpu@01c20054 {
reg = <0x01c20054 0x4>;
clocks = <&osc32k>, <&osc24M>, <&pll1>;
};
Gate clock outputs
The "allwinner,sun4i-*-gates-clk" clocks provide several gatable outputs;
their corresponding offsets as present on sun4i are listed below. Note that
some of these gates are not present on sun5i.
* AXI gates ("allwinner,sun4i-axi-gates-clk")
DRAM 0
* AHB gates ("allwinner,sun4i-ahb-gates-clk")
USB0 0
EHCI0 1
OHCI0 2*
EHCI1 3
OHCI1 4*
SS 5
DMA 6
BIST 7
MMC0 8
MMC1 9
MMC2 10
MMC3 11
MS 12**
NAND 13
SDRAM 14
ACE 16
EMAC 17
TS 18
SPI0 20
SPI1 21
SPI2 22
SPI3 23
PATA 24
SATA 25**
GPS 26*
VE 32
TVD 33
TVE0 34
TVE1 35
LCD0 36
LCD1 37
CSI0 40
CSI1 41
HDMI 43
DE_BE0 44
DE_BE1 45
DE_FE0 46
DE_FE1 47
MP 50
MALI400 52
* APB0 gates ("allwinner,sun4i-apb0-gates-clk")
CODEC 0
SPDIF 1*
AC97 2
IIS 3
PIO 5
IR0 6
IR1 7
KEYPAD 10
* APB1 gates ("allwinner,sun4i-apb1-gates-clk")
I2C0 0
I2C1 1
I2C2 2
CAN 4
SCR 5
PS20 6
PS21 7
UART0 16
UART1 17
UART2 18
UART3 19
UART4 20
UART5 21
UART6 22
UART7 23
Notation:
[*]: The datasheet didn't mention these, but they are present on AW code
[**]: The datasheet had this marked as "NC" but they are used on AW code

View File

@ -0,0 +1,93 @@
Gate clock outputs
------------------
* AXI gates ("allwinner,sun4i-axi-gates-clk")
DRAM 0
* AHB gates ("allwinner,sun4i-ahb-gates-clk")
USB0 0
EHCI0 1
OHCI0 2*
EHCI1 3
OHCI1 4*
SS 5
DMA 6
BIST 7
MMC0 8
MMC1 9
MMC2 10
MMC3 11
MS 12**
NAND 13
SDRAM 14
ACE 16
EMAC 17
TS 18
SPI0 20
SPI1 21
SPI2 22
SPI3 23
PATA 24
SATA 25**
GPS 26*
VE 32
TVD 33
TVE0 34
TVE1 35
LCD0 36
LCD1 37
CSI0 40
CSI1 41
HDMI 43
DE_BE0 44
DE_BE1 45
DE_FE1 46
DE_FE1 47
MP 50
MALI400 52
* APB0 gates ("allwinner,sun4i-apb0-gates-clk")
CODEC 0
SPDIF 1*
AC97 2
IIS 3
PIO 5
IR0 6
IR1 7
KEYPAD 10
* APB1 gates ("allwinner,sun4i-apb1-gates-clk")
I2C0 0
I2C1 1
I2C2 2
CAN 4
SCR 5
PS20 6
PS21 7
UART0 16
UART1 17
UART2 18
UART3 19
UART4 20
UART5 21
UART6 22
UART7 23
Notation:
[*]: The datasheet didn't mention these, but they are present on AW code
[**]: The datasheet had this marked as "NC" but they are used on AW code

View File

@ -0,0 +1,58 @@
Gate clock outputs
------------------
* AXI gates ("allwinner,sun4i-axi-gates-clk")
DRAM 0
* AHB gates ("allwinner,sun5i-a13-ahb-gates-clk")
USBOTG 0
EHCI 1
OHCI 2
SS 5
DMA 6
BIST 7
MMC0 8
MMC1 9
MMC2 10
NAND 13
SDRAM 14
SPI0 20
SPI1 21
SPI2 22
STIMER 28
VE 32
LCD 36
CSI 40
DE_BE 44
DE_FE 46
IEP 51
MALI400 52
* APB0 gates ("allwinner,sun5i-a13-apb0-gates-clk")
CODEC 0
PIO 5
IR 6
* APB1 gates ("allwinner,sun5i-a13-apb1-gates-clk")
I2C0 0
I2C1 1
I2C2 2
UART1 17
UART3 19

View File

@ -8,6 +8,8 @@ Required properties:
- compatible : shall be one of the following:
"via,vt8500-pll-clock" - for a VT8500/WM8505 PLL clock
"wm,wm8650-pll-clock" - for a WM8650 PLL clock
"wm,wm8750-pll-clock" - for a WM8750 PLL clock
"wm,wm8850-pll-clock" - for a WM8850 PLL clock
"via,vt8500-device-clock" - for a VT/WM device clock
Required properties for PLL clocks:

View File

@ -2131,9 +2131,10 @@ M: Mike Turquette <mturquette@linaro.org>
L: linux-arm-kernel@lists.infradead.org (same as CLK API & CLKDEV)
T: git git://git.linaro.org/people/mturquette/linux.git
S: Maintained
F: drivers/clk/clk.c
F: drivers/clk/clk-*
F: drivers/clk/
X: drivers/clk/clkdev.c
F: include/linux/clk-pr*
F: include/linux/clk/
COMMON INTERNET FILE SYSTEM (CIFS)
M: Steve French <sfrench@samba.org>

View File

@ -23,7 +23,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/irqchip.h>
#include <linux/clk/tegra.h>
#include <linux/clk-provider.h>
#include <asm/hardware/cache-l2x0.h>
@ -60,7 +60,7 @@ u32 tegra_uart_config[4] = {
#ifdef CONFIG_OF
void __init tegra_dt_init_irq(void)
{
tegra_clocks_init();
of_clk_init(NULL);
tegra_pmc_init();
tegra_init_irq();
irqchip_init();

View File

@ -76,13 +76,15 @@ void __init ux500_init_irq(void)
} else if (cpu_is_u9540()) {
prcmu_early_init(U8500_PRCMU_BASE, SZ_8K - 1);
ux500_pm_init(U8500_PRCMU_BASE, SZ_8K - 1);
u8500_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
u9540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
U8500_CLKRST6_BASE);
} else if (cpu_is_u8540()) {
prcmu_early_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
ux500_pm_init(U8500_PRCMU_BASE, SZ_8K + SZ_4K - 1);
u8540_clk_init();
u8540_clk_init(U8500_CLKRST1_BASE, U8500_CLKRST2_BASE,
U8500_CLKRST3_BASE, U8500_CLKRST5_BASE,
U8500_CLKRST6_BASE);
}
}

View File

@ -158,6 +158,7 @@ config E500
config PPC_E500MC
bool "e500mc Support"
select PPC_FPU
select COMMON_CLK
depends on E500
help
This must be enabled for running on e500mc (and derivatives

View File

@ -42,7 +42,7 @@ config COMMON_CLK_WM831X
config COMMON_CLK_VERSATILE
bool "Clock driver for ARM Reference designs"
depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS
depends on ARCH_INTEGRATOR || ARCH_REALVIEW || ARCH_VEXPRESS || ARM64
---help---
Supports clocking on ARM Reference designs:
- Integrator/AP and Integrator/CP
@ -58,7 +58,6 @@ config COMMON_CLK_MAX77686
config COMMON_CLK_SI5351
tristate "Clock driver for SiLabs 5351A/B/C"
depends on I2C
depends on OF
select REGMAP_I2C
select RATIONAL
---help---
@ -81,6 +80,13 @@ config COMMON_CLK_AXI_CLKGEN
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
FPGAs. It is commonly used in Analog Devices' reference designs.
config CLK_PPC_CORENET
bool "Clock driver for PowerPC corenet platforms"
depends on PPC_E500MC && OF
---help---
This adds the clock driver support for Freescale PowerPC corenet
platforms using common clock framework.
endmenu
source "drivers/clk/mvebu/Kconfig"

View File

@ -13,6 +13,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_SOCFPGA) += socfpga/
obj-$(CONFIG_PLAT_SPEAR) += spear/
@ -24,6 +25,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/
endif
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
obj-$(CONFIG_ARCH_U8500) += ux500/
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
@ -39,3 +41,4 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o

View File

@ -150,6 +150,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
struct clk_divider *divider = to_clk_divider(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
if (!rate)
rate = 1;
@ -173,6 +174,15 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
for (i = 1; i <= maxdiv; i++) {
if (!_is_valid_div(divider, i))
continue;
if (rate * i == parent_rate_saved) {
/*
* It's the most ideal case if the requested rate can be
* divided from parent clock without needing to change
* parent rate, so return the divider immediately.
*/
*best_parent_rate = parent_rate_saved;
return i;
}
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = parent_rate / i;
@ -217,8 +227,12 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
val = readl(divider->reg);
val &= ~(div_mask(divider) << divider->shift);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider) << (divider->shift + 16);
} else {
val = readl(divider->reg);
val &= ~(div_mask(divider) << divider->shift);
}
val |= value << divider->shift;
writel(val, divider->reg);
@ -245,6 +259,13 @@ static struct clk *_register_divider(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
if (width + shift > 16) {
pr_warn("divider value exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
}
/* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL);
if (!div) {

View File

@ -53,12 +53,18 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (gate->lock)
spin_lock_irqsave(gate->lock, flags);
reg = readl(gate->reg);
if (gate->flags & CLK_GATE_HIWORD_MASK) {
reg = BIT(gate->bit_idx + 16);
if (set)
reg |= BIT(gate->bit_idx);
} else {
reg = readl(gate->reg);
if (set)
reg |= BIT(gate->bit_idx);
else
reg &= ~BIT(gate->bit_idx);
if (set)
reg |= BIT(gate->bit_idx);
else
reg &= ~BIT(gate->bit_idx);
}
writel(reg, gate->reg);
@ -121,6 +127,13 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk *clk;
struct clk_init_data init;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
if (bit_idx > 16) {
pr_err("gate bit exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
}
/* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL);
if (!gate) {

View File

@ -86,8 +86,12 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->lock)
spin_lock_irqsave(mux->lock, flags);
val = readl(mux->reg);
val &= ~(mux->mask << mux->shift);
if (mux->flags & CLK_MUX_HIWORD_MASK) {
val = mux->mask << (mux->shift + 16);
} else {
val = readl(mux->reg);
val &= ~(mux->mask << mux->shift);
}
val |= index << mux->shift;
writel(val, mux->reg);
@ -111,6 +115,15 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
struct clk_mux *mux;
struct clk *clk;
struct clk_init_data init;
u8 width = 0;
if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
width = fls(mask) - ffs(mask) + 1;
if (width + shift > 16) {
pr_err("mux value exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
}
/* allocate the mux */
mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);

153
drivers/clk/clk-nspire.c Normal file
View File

@ -0,0 +1,153 @@
/*
*
* Copyright (C) 2013 Daniel Tang <tangrs@tangrs.id.au>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2, as
* published by the Free Software Foundation.
*
*/
#include <linux/clk-provider.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
#define MHZ (1000 * 1000)
#define BASE_CPU_SHIFT 1
#define BASE_CPU_MASK 0x7F
#define CPU_AHB_SHIFT 12
#define CPU_AHB_MASK 0x07
#define FIXED_BASE_SHIFT 8
#define FIXED_BASE_MASK 0x01
#define CLASSIC_BASE_SHIFT 16
#define CLASSIC_BASE_MASK 0x1F
#define CX_BASE_SHIFT 15
#define CX_BASE_MASK 0x3F
#define CX_UNKNOWN_SHIFT 21
#define CX_UNKNOWN_MASK 0x03
struct nspire_clk_info {
u32 base_clock;
u16 base_cpu_ratio;
u16 base_ahb_ratio;
};
#define EXTRACT(var, prop) (((var)>>prop##_SHIFT) & prop##_MASK)
static void nspire_clkinfo_cx(u32 val, struct nspire_clk_info *clk)
{
if (EXTRACT(val, FIXED_BASE))
clk->base_clock = 48 * MHZ;
else
clk->base_clock = 6 * EXTRACT(val, CX_BASE) * MHZ;
clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * EXTRACT(val, CX_UNKNOWN);
clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
}
static void nspire_clkinfo_classic(u32 val, struct nspire_clk_info *clk)
{
if (EXTRACT(val, FIXED_BASE))
clk->base_clock = 27 * MHZ;
else
clk->base_clock = (300 - 6 * EXTRACT(val, CLASSIC_BASE)) * MHZ;
clk->base_cpu_ratio = EXTRACT(val, BASE_CPU) * 2;
clk->base_ahb_ratio = clk->base_cpu_ratio * (EXTRACT(val, CPU_AHB) + 1);
}
static void __init nspire_ahbdiv_setup(struct device_node *node,
void (*get_clkinfo)(u32, struct nspire_clk_info *))
{
u32 val;
void __iomem *io;
struct clk *clk;
const char *clk_name = node->name;
const char *parent_name;
struct nspire_clk_info info;
io = of_iomap(node, 0);
if (!io)
return;
val = readl(io);
iounmap(io);
get_clkinfo(val, &info);
of_property_read_string(node, "clock-output-names", &clk_name);
parent_name = of_clk_get_parent_name(node, 0);
clk = clk_register_fixed_factor(NULL, clk_name, parent_name, 0,
1, info.base_ahb_ratio);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
static void __init nspire_ahbdiv_setup_cx(struct device_node *node)
{
nspire_ahbdiv_setup(node, nspire_clkinfo_cx);
}
static void __init nspire_ahbdiv_setup_classic(struct device_node *node)
{
nspire_ahbdiv_setup(node, nspire_clkinfo_classic);
}
CLK_OF_DECLARE(nspire_ahbdiv_cx, "lsi,nspire-cx-ahb-divider",
nspire_ahbdiv_setup_cx);
CLK_OF_DECLARE(nspire_ahbdiv_classic, "lsi,nspire-classic-ahb-divider",
nspire_ahbdiv_setup_classic);
static void __init nspire_clk_setup(struct device_node *node,
void (*get_clkinfo)(u32, struct nspire_clk_info *))
{
u32 val;
void __iomem *io;
struct clk *clk;
const char *clk_name = node->name;
struct nspire_clk_info info;
io = of_iomap(node, 0);
if (!io)
return;
val = readl(io);
iounmap(io);
get_clkinfo(val, &info);
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT,
info.base_clock);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
else
return;
pr_info("TI-NSPIRE Base: %uMHz CPU: %uMHz AHB: %uMHz\n",
info.base_clock / MHZ,
info.base_clock / info.base_cpu_ratio / MHZ,
info.base_clock / info.base_ahb_ratio / MHZ);
}
static void __init nspire_clk_setup_cx(struct device_node *node)
{
nspire_clk_setup(node, nspire_clkinfo_cx);
}
static void __init nspire_clk_setup_classic(struct device_node *node)
{
nspire_clk_setup(node, nspire_clkinfo_classic);
}
CLK_OF_DECLARE(nspire_clk_cx, "lsi,nspire-cx-clock", nspire_clk_setup_cx);
CLK_OF_DECLARE(nspire_clk_classic, "lsi,nspire-classic-clock",
nspire_clk_setup_classic);

View File

@ -0,0 +1,280 @@
/*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* clock driver for Freescale PowerPC corenet SoCs.
*/
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/of.h>
#include <linux/slab.h>
struct cmux_clk {
struct clk_hw hw;
void __iomem *reg;
u32 flags;
};
#define PLL_KILL BIT(31)
#define CLKSEL_SHIFT 27
#define CLKSEL_ADJUST BIT(0)
#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
static void __iomem *base;
static unsigned int clocks_per_pll;
static int cmux_set_parent(struct clk_hw *hw, u8 idx)
{
struct cmux_clk *clk = to_cmux_clk(hw);
u32 clksel;
clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
if (clk->flags & CLKSEL_ADJUST)
clksel += 8;
clksel = (clksel & 0xf) << CLKSEL_SHIFT;
iowrite32be(clksel, clk->reg);
return 0;
}
static u8 cmux_get_parent(struct clk_hw *hw)
{
struct cmux_clk *clk = to_cmux_clk(hw);
u32 clksel;
clksel = ioread32be(clk->reg);
clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
if (clk->flags & CLKSEL_ADJUST)
clksel -= 8;
clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
return clksel;
}
const struct clk_ops cmux_ops = {
.get_parent = cmux_get_parent,
.set_parent = cmux_set_parent,
};
static void __init core_mux_init(struct device_node *np)
{
struct clk *clk;
struct clk_init_data init;
struct cmux_clk *cmux_clk;
struct device_node *node;
int rc, count, i;
u32 offset;
const char *clk_name;
const char **parent_names;
rc = of_property_read_u32(np, "reg", &offset);
if (rc) {
pr_err("%s: could not get reg property\n", np->name);
return;
}
/* get the input clock source count */
count = of_property_count_strings(np, "clock-names");
if (count < 0) {
pr_err("%s: get clock count error\n", np->name);
return;
}
parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
if (!parent_names) {
pr_err("%s: could not allocate parent_names\n", __func__);
return;
}
for (i = 0; i < count; i++)
parent_names[i] = of_clk_get_parent_name(np, i);
cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
if (!cmux_clk) {
pr_err("%s: could not allocate cmux_clk\n", __func__);
goto err_name;
}
cmux_clk->reg = base + offset;
node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
if (node && (offset >= 0x80))
cmux_clk->flags = CLKSEL_ADJUST;
rc = of_property_read_string_index(np, "clock-output-names",
0, &clk_name);
if (rc) {
pr_err("%s: read clock names error\n", np->name);
goto err_clk;
}
init.name = clk_name;
init.ops = &cmux_ops;
init.parent_names = parent_names;
init.num_parents = count;
init.flags = 0;
cmux_clk->hw.init = &init;
clk = clk_register(NULL, &cmux_clk->hw);
if (IS_ERR(clk)) {
pr_err("%s: could not register clock\n", clk_name);
goto err_clk;
}
rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
if (rc) {
pr_err("Could not register clock provider for node:%s\n",
np->name);
goto err_clk;
}
goto err_name;
err_clk:
kfree(cmux_clk);
err_name:
/* free *_names because they are reallocated when registered */
kfree(parent_names);
}
static void __init core_pll_init(struct device_node *np)
{
u32 offset, mult;
int i, rc, count;
const char *clk_name, *parent_name;
struct clk_onecell_data *onecell_data;
struct clk **subclks;
rc = of_property_read_u32(np, "reg", &offset);
if (rc) {
pr_err("%s: could not get reg property\n", np->name);
return;
}
/* get the multiple of PLL */
mult = ioread32be(base + offset);
/* check if this PLL is disabled */
if (mult & PLL_KILL) {
pr_debug("PLL:%s is disabled\n", np->name);
return;
}
mult = (mult >> 1) & 0x3f;
parent_name = of_clk_get_parent_name(np, 0);
if (!parent_name) {
pr_err("PLL: %s must have a parent\n", np->name);
return;
}
count = of_property_count_strings(np, "clock-output-names");
if (count < 0 || count > 4) {
pr_err("%s: clock is not supported\n", np->name);
return;
}
/* output clock number per PLL */
clocks_per_pll = count;
subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
if (!subclks) {
pr_err("%s: could not allocate subclks\n", __func__);
return;
}
onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
if (!onecell_data) {
pr_err("%s: could not allocate onecell_data\n", __func__);
goto err_clks;
}
for (i = 0; i < count; i++) {
rc = of_property_read_string_index(np, "clock-output-names",
i, &clk_name);
if (rc) {
pr_err("%s: could not get clock names\n", np->name);
goto err_cell;
}
/*
* when count == 4, there are 4 output clocks:
* /1, /2, /3, /4 respectively
* when count < 4, there are at least 2 output clocks:
* /1, /2, (/4, if count == 3) respectively.
*/
if (count == 4)
subclks[i] = clk_register_fixed_factor(NULL, clk_name,
parent_name, 0, mult, 1 + i);
else
subclks[i] = clk_register_fixed_factor(NULL, clk_name,
parent_name, 0, mult, 1 << i);
if (IS_ERR(subclks[i])) {
pr_err("%s: could not register clock\n", clk_name);
goto err_cell;
}
}
onecell_data->clks = subclks;
onecell_data->clk_num = count;
rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
if (rc) {
pr_err("Could not register clk provider for node:%s\n",
np->name);
goto err_cell;
}
return;
err_cell:
kfree(onecell_data);
err_clks:
kfree(subclks);
}
static const struct of_device_id clk_match[] __initconst = {
{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
{ .compatible = "fsl,core-pll-clock", .data = core_pll_init, },
{ .compatible = "fsl,core-mux-clock", .data = core_mux_init, },
{}
};
static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
{
struct device_node *np;
np = pdev->dev.of_node;
base = of_iomap(np, 0);
if (!base) {
dev_err(&pdev->dev, "iomap error\n");
return -ENOMEM;
}
of_clk_init(clk_match);
return 0;
}
static const struct of_device_id ppc_clk_ids[] __initconst = {
{ .compatible = "fsl,qoriq-clockgen-1.0", },
{ .compatible = "fsl,qoriq-clockgen-2.0", },
{}
};
static struct platform_driver ppc_corenet_clk_driver = {
.driver = {
.name = "ppc_corenet_clock",
.owner = THIS_MODULE,
.of_match_table = ppc_clk_ids,
},
.probe = ppc_corenet_clk_probe,
};
static int __init ppc_corenet_clk_init(void)
{
return platform_driver_register(&ppc_corenet_clk_driver);
}
subsys_initcall(ppc_corenet_clk_init);

View File

@ -851,6 +851,41 @@ static int _si5351_clkout_set_drive_strength(
return 0;
}
static int _si5351_clkout_set_disable_state(
struct si5351_driver_data *drvdata, int num,
enum si5351_disable_state state)
{
u8 reg = (num < 4) ? SI5351_CLK3_0_DISABLE_STATE :
SI5351_CLK7_4_DISABLE_STATE;
u8 shift = (num < 4) ? (2 * num) : (2 * (num-4));
u8 mask = SI5351_CLK_DISABLE_STATE_MASK << shift;
u8 val;
if (num > 8)
return -EINVAL;
switch (state) {
case SI5351_DISABLE_LOW:
val = SI5351_CLK_DISABLE_STATE_LOW;
break;
case SI5351_DISABLE_HIGH:
val = SI5351_CLK_DISABLE_STATE_HIGH;
break;
case SI5351_DISABLE_FLOATING:
val = SI5351_CLK_DISABLE_STATE_FLOAT;
break;
case SI5351_DISABLE_NEVER:
val = SI5351_CLK_DISABLE_STATE_NEVER;
break;
default:
return 0;
}
si5351_set_bits(drvdata, reg, mask, val << shift);
return 0;
}
static int si5351_clkout_prepare(struct clk_hw *hw)
{
struct si5351_hw_data *hwdata =
@ -1225,6 +1260,33 @@ static int si5351_dt_parse(struct i2c_client *client)
}
}
if (!of_property_read_u32(child, "silabs,disable-state",
&val)) {
switch (val) {
case 0:
pdata->clkout[num].disable_state =
SI5351_DISABLE_LOW;
break;
case 1:
pdata->clkout[num].disable_state =
SI5351_DISABLE_HIGH;
break;
case 2:
pdata->clkout[num].disable_state =
SI5351_DISABLE_FLOATING;
break;
case 3:
pdata->clkout[num].disable_state =
SI5351_DISABLE_NEVER;
break;
default:
dev_err(&client->dev,
"invalid disable state %d for clkout %d\n",
val, num);
return -EINVAL;
}
}
if (!of_property_read_u32(child, "clock-frequency", &val))
pdata->clkout[num].rate = val;
@ -1281,9 +1343,6 @@ static int si5351_i2c_probe(struct i2c_client *client,
/* Disable interrupts */
si5351_reg_write(drvdata, SI5351_INTERRUPT_MASK, 0xf0);
/* Set disabled output drivers to drive low */
si5351_reg_write(drvdata, SI5351_CLK3_0_DISABLE_STATE, 0x00);
si5351_reg_write(drvdata, SI5351_CLK7_4_DISABLE_STATE, 0x00);
/* Ensure pll select is on XTAL for Si5351A/B */
if (drvdata->variant != SI5351_VARIANT_C)
si5351_set_bits(drvdata, SI5351_PLL_INPUT_SOURCE,
@ -1327,6 +1386,15 @@ static int si5351_i2c_probe(struct i2c_client *client,
n, pdata->clkout[n].drive);
return ret;
}
ret = _si5351_clkout_set_disable_state(drvdata, n,
pdata->clkout[n].disable_state);
if (ret) {
dev_err(&client->dev,
"failed set disable state of clkout%d to %d\n",
n, pdata->clkout[n].disable_state);
return ret;
}
}
/* register xtal input clock gate */
@ -1500,7 +1568,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
}
static const struct i2c_device_id si5351_i2c_ids[] = {
{ "silabs,si5351", 0 },
{ "si5351a", 0 },
{ "si5351a-msop", 0 },
{ "si5351b", 0 },
{ "si5351c", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);

View File

@ -81,6 +81,7 @@
#define SI5351_CLK3_0_DISABLE_STATE 24
#define SI5351_CLK7_4_DISABLE_STATE 25
#define SI5351_CLK_DISABLE_STATE_MASK 3
#define SI5351_CLK_DISABLE_STATE_LOW 0
#define SI5351_CLK_DISABLE_STATE_HIGH 1
#define SI5351_CLK_DISABLE_STATE_FLOAT 2

View File

@ -95,14 +95,14 @@ static int twl6040_clk_probe(struct platform_device *pdev)
if (IS_ERR(clkdata->clk))
return PTR_ERR(clkdata->clk);
dev_set_drvdata(&pdev->dev, clkdata);
platform_set_drvdata(pdev, clkdata);
return 0;
}
static int twl6040_clk_remove(struct platform_device *pdev)
{
struct twl6040_clk *clkdata = dev_get_drvdata(&pdev->dev);
struct twl6040_clk *clkdata = platform_get_drvdata(pdev);
clk_unregister(clkdata->clk);

View File

@ -42,6 +42,7 @@ struct clk_device {
#define PLL_TYPE_VT8500 0
#define PLL_TYPE_WM8650 1
#define PLL_TYPE_WM8750 2
#define PLL_TYPE_WM8850 3
struct clk_pll {
struct clk_hw hw;
@ -156,10 +157,6 @@ static int vt8500_dclk_set_rate(struct clk_hw *hw, unsigned long rate,
divisor = parent_rate / rate;
/* If prate / rate would be decimal, incr the divisor */
if (rate * divisor < parent_rate)
divisor++;
if (divisor == cdev->div_mask + 1)
divisor = 0;
@ -327,6 +324,15 @@ CLK_OF_DECLARE(vt8500_device, "via,vt8500-device-clock", vtwm_device_clk_init);
#define WM8750_BITS_TO_VAL(f, m, d1, d2) \
((f << 24) | ((m - 1) << 16) | ((d1 - 1) << 8) | d2)
/* Helper macros for PLL_WM8850 */
#define WM8850_PLL_MUL(x) ((((x >> 16) & 0x7F) + 1) * 2)
#define WM8850_PLL_DIV(x) ((((x >> 8) & 1) + 1) * (1 << (x & 3)))
#define WM8850_BITS_TO_FREQ(r, m, d1, d2) \
(r * ((m + 1) * 2) / ((d1+1) * (1 << d2)))
#define WM8850_BITS_TO_VAL(m, d1, d2) \
((((m / 2) - 1) << 16) | ((d1 - 1) << 8) | d2)
static void vt8500_find_pll_bits(unsigned long rate, unsigned long parent_rate,
u32 *multiplier, u32 *prediv)
@ -466,6 +472,49 @@ static void wm8750_find_pll_bits(unsigned long rate, unsigned long parent_rate,
*divisor2 = best_div2;
}
static void wm8850_find_pll_bits(unsigned long rate, unsigned long parent_rate,
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 = 3; div2 >= 0; div2--)
for (mul = 0; mul <= 127; mul++) {
tclk = parent_rate * ((mul + 1) * 2) /
((div1 + 1) * (1 << div2));
if (tclk > rate)
continue;
/* error will always be +ve */
rate_err = rate - tclk;
if (rate_err == 0) {
*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);
*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)
{
@ -489,6 +538,10 @@ static int vtwm_pll_set_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, parent_rate, &filter, &mul, &div1, &div2);
pll_val = WM8750_BITS_TO_VAL(filter, mul, div1, div2);
break;
case PLL_TYPE_WM8850:
wm8850_find_pll_bits(rate, parent_rate, &mul, &div1, &div2);
pll_val = WM8850_BITS_TO_VAL(mul, div1, div2);
break;
default:
pr_err("%s: invalid pll type\n", __func__);
return 0;
@ -525,6 +578,10 @@ static long vtwm_pll_round_rate(struct clk_hw *hw, unsigned long rate,
wm8750_find_pll_bits(rate, *prate, &filter, &mul, &div1, &div2);
round_rate = WM8750_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
case PLL_TYPE_WM8850:
wm8850_find_pll_bits(rate, *prate, &mul, &div1, &div2);
round_rate = WM8850_BITS_TO_FREQ(*prate, mul, div1, div2);
break;
default:
round_rate = 0;
}
@ -552,6 +609,10 @@ static unsigned long vtwm_pll_recalc_rate(struct clk_hw *hw,
pll_freq = parent_rate * WM8750_PLL_MUL(pll_val);
pll_freq /= WM8750_PLL_DIV(pll_val);
break;
case PLL_TYPE_WM8850:
pll_freq = parent_rate * WM8850_PLL_MUL(pll_val);
pll_freq /= WM8850_PLL_DIV(pll_val);
break;
default:
pll_freq = 0;
}
@ -628,6 +689,12 @@ static void __init wm8750_pll_init(struct device_node *node)
}
CLK_OF_DECLARE(wm8750_pll, "wm,wm8750-pll-clock", wm8750_pll_init);
static void __init wm8850_pll_init(struct device_node *node)
{
vtwm_pll_clk_init(node, PLL_TYPE_WM8850);
}
CLK_OF_DECLARE(wm8850_pll, "wm,wm8850-pll-clock", wm8850_pll_init);
void __init vtwm_clk_init(void __iomem *base)
{
if (!base)

View File

@ -97,7 +97,7 @@ static int wm831x_fll_prepare(struct clk_hw *hw)
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2,
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1,
WM831X_FLL_ENA, WM831X_FLL_ENA);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to enable FLL: %d\n", ret);
@ -114,9 +114,9 @@ static void wm831x_fll_unprepare(struct clk_hw *hw)
struct wm831x *wm831x = clkdata->wm831x;
int ret;
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_2, WM831X_FLL_ENA, 0);
ret = wm831x_set_bits(wm831x, WM831X_FLL_CONTROL_1, WM831X_FLL_ENA, 0);
if (ret != 0)
dev_crit(wm831x->dev, "Failed to disaable FLL: %d\n", ret);
dev_crit(wm831x->dev, "Failed to disable FLL: %d\n", ret);
}
static unsigned long wm831x_fll_recalc_rate(struct clk_hw *hw,
@ -299,8 +299,8 @@ static void wm831x_clkout_unprepare(struct clk_hw *hw)
}
static const char *wm831x_clkout_parents[] = {
"xtal",
"fll",
"xtal",
};
static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
@ -318,9 +318,9 @@ static u8 wm831x_clkout_get_parent(struct clk_hw *hw)
}
if (ret & WM831X_CLKOUT_SRC)
return 0;
else
return 1;
else
return 0;
}
static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
@ -384,7 +384,7 @@ static int wm831x_clk_probe(struct platform_device *pdev)
if (IS_ERR(clkdata->clkout))
return PTR_ERR(clkdata->clkout);
dev_set_drvdata(&pdev->dev, clkdata);
platform_set_drvdata(pdev, clkdata);
return 0;
}

View File

@ -107,7 +107,7 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "%*s%-*s %-11d %-12d %-10lu",
level * 3 + 1, "",
30 - level * 3, c->name,
c->enable_count, c->prepare_count, c->rate);
c->enable_count, c->prepare_count, clk_get_rate(c));
seq_printf(s, "\n");
}
@ -166,7 +166,7 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
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);
seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
}
static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
@ -534,7 +534,7 @@ static int clk_disable_unused(void)
return 0;
}
late_initcall(clk_disable_unused);
late_initcall_sync(clk_disable_unused);
/*** helper functions ***/
@ -1216,7 +1216,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
clk_prepare_lock();
/* bail early if nothing to do */
if (rate == clk->rate)
if (rate == clk_get_rate(clk))
goto out;
if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
@ -1377,23 +1377,33 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
unsigned long flags;
int ret = 0;
struct clk *old_parent = clk->parent;
bool migrated_enable = false;
/* migrate prepare */
if (clk->prepare_count)
/*
* Migrate prepare state between parents and prevent race with
* clk_enable().
*
* If the clock is not prepared, then a race with
* clk_enable/disable() is impossible since we already have the
* prepare lock (future calls to clk_enable() need to be preceded by
* a clk_prepare()).
*
* If the clock is prepared, migrate the prepared state to the new
* parent and also protect against a race with clk_enable() by
* forcing the clock and the new parent on. This ensures that all
* future calls to clk_enable() are practically NOPs with respect to
* hardware and software states.
*
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
__clk_prepare(parent);
flags = clk_enable_lock();
/* migrate enable */
if (clk->enable_count) {
__clk_enable(parent);
migrated_enable = true;
clk_enable(parent);
clk_enable(clk);
}
/* update the clk tree topology */
flags = clk_enable_lock();
clk_reparent(clk, parent);
clk_enable_unlock(flags);
/* change clock input source */
@ -1401,43 +1411,27 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
ret = clk->ops->set_parent(clk->hw, p_index);
if (ret) {
/*
* The error handling is tricky due to that we need to release
* the spinlock while issuing the .set_parent callback. This
* means the new parent might have been enabled/disabled in
* between, which must be considered when doing rollback.
*/
flags = clk_enable_lock();
clk_reparent(clk, old_parent);
if (migrated_enable && clk->enable_count) {
__clk_disable(parent);
} else if (migrated_enable && (clk->enable_count == 0)) {
__clk_disable(old_parent);
} else if (!migrated_enable && clk->enable_count) {
__clk_disable(parent);
__clk_enable(old_parent);
}
clk_enable_unlock(flags);
if (clk->prepare_count)
if (clk->prepare_count) {
clk_disable(clk);
clk_disable(parent);
__clk_unprepare(parent);
}
return ret;
}
/* clean up enable for old parent if migration was done */
if (migrated_enable) {
flags = clk_enable_lock();
__clk_disable(old_parent);
clk_enable_unlock(flags);
}
/* clean up prepare for old parent if migration was done */
if (clk->prepare_count)
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
if (clk->prepare_count) {
clk_disable(clk);
clk_disable(old_parent);
__clk_unprepare(old_parent);
}
/* update debugfs with new clk tree topology */
clk_debug_reparent(clk, parent);
@ -1449,12 +1443,17 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
* @clk: the mux clk whose input we are switching
* @parent: the new input to clk
*
* Re-parent clk to use parent as it's new input source. If clk has the
* CLK_SET_PARENT_GATE flag set then clk must be gated for this
* operation to succeed. After successfully changing clk's parent
* clk_set_parent will update the clk topology, sysfs topology and
* propagate rate recalculation via __clk_recalc_rates. Returns 0 on
* success, -EERROR otherwise.
* Re-parent clk to use parent as its new input source. If clk is in
* prepared state, the clk will get enabled for the duration of this call. If
* that's not acceptable for a specific clk (Eg: the consumer can't handle
* that, the reparenting is glitchy in hardware, etc), use the
* CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
*
* After successfully changing clk's parent clk_set_parent will update the
* clk topology, sysfs topology and propagate rate recalculation via
* __clk_recalc_rates.
*
* Returns 0 on success, -EERROR otherwise.
*/
int clk_set_parent(struct clk *clk, struct clk *parent)
{
@ -1494,8 +1493,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
}
/* propagate PRE_RATE_CHANGE notifications */
if (clk->notifier_count)
ret = __clk_speculate_rates(clk, p_rate);
ret = __clk_speculate_rates(clk, p_rate);
/* abort if a driver objects */
if (ret & NOTIFY_STOP_MASK)

View File

@ -0,0 +1,5 @@
#
# Rockchip Clock specific Makefile
#
obj-y += clk-rockchip.o

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013 MundoReader S.L.
* Author: Heiko Stuebner <heiko@sntech.de>
*
* 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/of.h>
#include <linux/of_address.h>
static DEFINE_SPINLOCK(clk_lock);
/*
* Gate clocks
*/
static void __init rk2928_gate_clk_init(struct device_node *node,
void *data)
{
struct clk_onecell_data *clk_data;
const char *clk_parent;
const char *clk_name;
void __iomem *reg;
void __iomem *reg_idx;
int flags;
int qty;
int reg_bit;
int clkflags = CLK_SET_RATE_PARENT;
int i;
qty = of_property_count_strings(node, "clock-output-names");
if (qty < 0) {
pr_err("%s: error in clock-output-names %d\n", __func__, qty);
return;
}
if (qty == 0) {
pr_info("%s: nothing to do\n", __func__);
return;
}
reg = of_iomap(node, 0);
clk_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
if (!clk_data)
return;
clk_data->clks = kzalloc(qty * sizeof(struct clk *), GFP_KERNEL);
if (!clk_data->clks) {
kfree(clk_data);
return;
}
flags = CLK_GATE_HIWORD_MASK | CLK_GATE_SET_TO_DISABLE;
for (i = 0; i < qty; i++) {
of_property_read_string_index(node, "clock-output-names",
i, &clk_name);
/* ignore empty slots */
if (!strcmp("reserved", clk_name))
continue;
clk_parent = of_clk_get_parent_name(node, i);
/* keep all gates untouched for now */
clkflags |= CLK_IGNORE_UNUSED;
reg_idx = reg + (4 * (i / 16));
reg_bit = (i % 16);
clk_data->clks[i] = clk_register_gate(NULL, clk_name,
clk_parent, clkflags,
reg_idx, reg_bit,
flags,
&clk_lock);
WARN_ON(IS_ERR(clk_data->clks[i]));
}
clk_data->clk_num = qty;
of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
}
CLK_OF_DECLARE(rk2928_gate, "rockchip,rk2928-gate-clk", rk2928_gate_clk_init);

View File

@ -356,8 +356,8 @@ struct samsung_fixed_rate_clock exynos4210_fixed_rate_clks[] __initdata = {
/* list of mux clocks supported in all exynos4 soc's */
struct samsung_mux_clock exynos4_mux_clks[] __initdata = {
MUX_F(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
CLK_SET_RATE_PARENT, 0),
MUX_FA(mout_apll, "mout_apll", mout_apll_p, SRC_CPU, 0, 1,
CLK_SET_RATE_PARENT, 0, "mout_apll"),
MUX(none, "mout_hdmi", mout_hdmi_p, SRC_TV, 0, 1),
MUX(none, "mout_mfc1", sclk_evpll_p, SRC_MFC, 4, 1),
MUX(none, "mout_mfc", mout_mfc_p, SRC_MFC, 8, 1),
@ -385,9 +385,9 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
MUX(none, "mout_g2d", mout_g2d_p, E4210_SRC_IMAGE, 8, 1),
MUX(none, "mout_fimd1", group1_p4210, E4210_SRC_LCD1, 0, 4),
MUX(none, "mout_mipi1", group1_p4210, E4210_SRC_LCD1, 12, 4),
MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "sclk_mpll"),
MUX_A(sclk_mpll, "sclk_mpll", mout_mpll_p, SRC_CPU, 8, 1, "mout_mpll"),
MUX_A(mout_core, "mout_core", mout_core_p4210,
SRC_CPU, 16, 1, "mout_core"),
SRC_CPU, 16, 1, "moutcore"),
MUX_A(sclk_vpll, "sclk_vpll", sclk_vpll_p4210,
SRC_TOP0, 8, 1, "sclk_vpll"),
MUX(mout_fimc0, "mout_fimc0", group1_p4210, SRC_CAM, 0, 4),
@ -424,8 +424,8 @@ struct samsung_mux_clock exynos4210_mux_clks[] __initdata = {
/* list of mux clocks supported in exynos4x12 soc */
struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
MUX(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
SRC_CPU, 24, 1),
MUX_A(mout_mpll_user_c, "mout_mpll_user_c", mout_mpll_user_p4x12,
SRC_CPU, 24, 1, "mout_mpll"),
MUX(none, "mout_aclk266_gps", aclk_p4412, SRC_TOP1, 4, 1),
MUX(none, "mout_aclk400_mcuisp", aclk_p4412, SRC_TOP1, 8, 1),
MUX(mout_mpll_user_t, "mout_mpll_user_t", mout_mpll_user_p4x12,
@ -449,7 +449,8 @@ struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
SRC_DMC, 12, 1, "sclk_mpll"),
MUX_A(sclk_vpll, "sclk_vpll", mout_vpll_p,
SRC_TOP0, 8, 1, "sclk_vpll"),
MUX(mout_core, "mout_core", mout_core_p4x12, SRC_CPU, 16, 1),
MUX_A(mout_core, "mout_core", mout_core_p4x12,
SRC_CPU, 16, 1, "moutcore"),
MUX(mout_fimc0, "mout_fimc0", group1_p4x12, SRC_CAM, 0, 4),
MUX(mout_fimc1, "mout_fimc1", group1_p4x12, SRC_CAM, 4, 4),
MUX(mout_fimc2, "mout_fimc2", group1_p4x12, SRC_CAM, 8, 4),
@ -537,7 +538,7 @@ struct samsung_div_clock exynos4_div_clks[] __initdata = {
DIV(none, "div_spi_pre2", "div_spi2", DIV_PERIL2, 8, 8),
DIV(none, "div_audio1", "mout_audio1", DIV_PERIL4, 0, 4),
DIV(none, "div_audio2", "mout_audio2", DIV_PERIL4, 16, 4),
DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "arm_clk"),
DIV_A(arm_clk, "arm_clk", "div_core2", DIV_CPU0, 28, 3, "armclk"),
DIV_A(sclk_apll, "sclk_apll", "mout_apll",
DIV_CPU0, 24, 3, "sclk_apll"),
DIV_F(none, "div_mipi_pre0", "div_mipi0", DIV_LCD0, 20, 4,
@ -1070,9 +1071,9 @@ void __init exynos4_clk_init(struct device_node *np, enum exynos4_soc exynos4_so
pr_info("%s clocks: sclk_apll = %ld, sclk_mpll = %ld\n"
"\tsclk_epll = %ld, sclk_vpll = %ld, arm_clk = %ld\n",
exynos4_soc == EXYNOS4210 ? "Exynos4210" : "Exynos4x12",
_get_rate("sclk_apll"), _get_rate("sclk_mpll"),
_get_rate("sclk_apll"), _get_rate("mout_mpll"),
_get_rate("sclk_epll"), _get_rate("sclk_vpll"),
_get_rate("arm_clk"));
_get_rate("armclk"));
}

View File

@ -144,6 +144,9 @@ struct samsung_mux_clock {
#define MUX_F(_id, cname, pnames, o, s, w, f, mf) \
__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, NULL)
#define MUX_FA(_id, cname, pnames, o, s, w, f, mf, a) \
__MUX(_id, NULL, cname, pnames, o, s, w, f, mf, a)
/**
* @id: platform specific id of the clock.
* struct samsung_div_clock: information about div clock

View File

@ -239,7 +239,7 @@ struct mux_data {
u8 shift;
};
static const __initconst struct mux_data cpu_data = {
static const __initconst struct mux_data cpu_mux_data = {
.shift = 16,
};
@ -333,22 +333,34 @@ struct gates_data {
DECLARE_BITMAP(mask, SUNXI_GATES_MAX_SIZE);
};
static const __initconst struct gates_data axi_gates_data = {
static const __initconst struct gates_data sun4i_axi_gates_data = {
.mask = {1},
};
static const __initconst struct gates_data ahb_gates_data = {
static const __initconst struct gates_data sun4i_ahb_gates_data = {
.mask = {0x7F77FFF, 0x14FB3F},
};
static const __initconst struct gates_data apb0_gates_data = {
static const __initconst struct gates_data sun5i_a13_ahb_gates_data = {
.mask = {0x107067e7, 0x185111},
};
static const __initconst struct gates_data sun4i_apb0_gates_data = {
.mask = {0x4EF},
};
static const __initconst struct gates_data apb1_gates_data = {
static const __initconst struct gates_data sun5i_a13_apb0_gates_data = {
.mask = {0x61},
};
static const __initconst struct gates_data sun4i_apb1_gates_data = {
.mask = {0xFF00F7},
};
static const __initconst struct gates_data sun5i_a13_apb1_gates_data = {
.mask = {0xa0007},
};
static void __init sunxi_gates_clk_setup(struct device_node *node,
struct gates_data *data)
{
@ -421,17 +433,20 @@ static const __initconst struct of_device_id clk_div_match[] = {
/* Matches for mux clocks */
static const __initconst struct of_device_id clk_mux_match[] = {
{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_data,},
{.compatible = "allwinner,sun4i-cpu-clk", .data = &cpu_mux_data,},
{.compatible = "allwinner,sun4i-apb1-mux-clk", .data = &apb1_mux_data,},
{}
};
/* Matches for gate clocks */
static const __initconst struct of_device_id clk_gates_match[] = {
{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &axi_gates_data,},
{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &ahb_gates_data,},
{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &apb0_gates_data,},
{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &apb1_gates_data,},
{.compatible = "allwinner,sun4i-axi-gates-clk", .data = &sun4i_axi_gates_data,},
{.compatible = "allwinner,sun4i-ahb-gates-clk", .data = &sun4i_ahb_gates_data,},
{.compatible = "allwinner,sun5i-a13-ahb-gates-clk", .data = &sun5i_a13_ahb_gates_data,},
{.compatible = "allwinner,sun4i-apb0-gates-clk", .data = &sun4i_apb0_gates_data,},
{.compatible = "allwinner,sun5i-a13-apb0-gates-clk", .data = &sun5i_a13_apb0_gates_data,},
{.compatible = "allwinner,sun4i-apb1-gates-clk", .data = &sun4i_apb1_gates_data,},
{.compatible = "allwinner,sun5i-a13-apb1-gates-clk", .data = &sun5i_a13_apb1_gates_data,},
{}
};

View File

@ -117,10 +117,6 @@
#define PLLCX_MISC2_DEFAULT 0x30211200
#define PLLCX_MISC3_DEFAULT 0x200
#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
#define PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK BIT(27)
#define PMC_SATA_PWRGT 0x1ac
#define PMC_SATA_PWRGT_PLLE_IDDQ_VALUE BIT(5)
#define PMC_SATA_PWRGT_PLLE_IDDQ_SWCTL BIT(4)
@ -128,39 +124,32 @@
#define pll_readl(offset, p) readl_relaxed(p->clk_base + offset)
#define pll_readl_base(p) pll_readl(p->params->base_reg, p)
#define pll_readl_misc(p) pll_readl(p->params->misc_reg, p)
#define pll_override_readl(offset, p) readl_relaxed(p->pmc + offset)
#define pll_writel(val, offset, p) writel_relaxed(val, p->clk_base + offset)
#define pll_writel_base(val, p) pll_writel(val, p->params->base_reg, p)
#define pll_writel_misc(val, p) pll_writel(val, p->params->misc_reg, p)
#define pll_override_writel(val, offset, p) writel(val, p->pmc + offset)
#define mask(w) ((1 << (w)) - 1)
#define divm_mask(p) mask(p->divm_width)
#define divn_mask(p) mask(p->divn_width)
#define divm_mask(p) mask(p->params->div_nmp->divm_width)
#define divn_mask(p) mask(p->params->div_nmp->divn_width)
#define divp_mask(p) (p->flags & TEGRA_PLLU ? PLLU_POST_DIVP_MASK : \
mask(p->divp_width))
mask(p->params->div_nmp->divp_width))
#define divm_max(p) (divm_mask(p))
#define divn_max(p) (divn_mask(p))
#define divp_max(p) (1 << (divp_mask(p)))
#ifdef CONFIG_ARCH_TEGRA_114_SOC
/* PLLXC has 4-bit PDIV, but entry 15 is not allowed in h/w */
#define PLLXC_PDIV_MAX 14
/* non-monotonic mapping below is not a typo */
static u8 pllxc_p[PLLXC_PDIV_MAX + 1] = {
/* PDIV: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32
static struct div_nmp default_nmp = {
.divn_shift = PLL_BASE_DIVN_SHIFT,
.divn_width = PLL_BASE_DIVN_WIDTH,
.divm_shift = PLL_BASE_DIVM_SHIFT,
.divm_width = PLL_BASE_DIVM_WIDTH,
.divp_shift = PLL_BASE_DIVP_SHIFT,
.divp_width = PLL_BASE_DIVP_WIDTH,
};
#define PLLCX_PDIV_MAX 7
static u8 pllcx_p[PLLCX_PDIV_MAX + 1] = {
/* PDIV: 0, 1, 2, 3, 4, 5, 6, 7 */
/* p: */ 1, 2, 3, 4, 6, 8, 12, 16
};
#endif
static void clk_pll_enable_lock(struct tegra_clk_pll *pll)
{
u32 val;
@ -297,6 +286,39 @@ static void clk_pll_disable(struct clk_hw *hw)
spin_unlock_irqrestore(pll->lock, flags);
}
static int _p_div_to_hw(struct clk_hw *hw, u8 p_div)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
if (p_tohw) {
while (p_tohw->pdiv) {
if (p_div <= p_tohw->pdiv)
return p_tohw->hw_val;
p_tohw++;
}
return -EINVAL;
}
return -EINVAL;
}
static int _hw_to_p_div(struct clk_hw *hw, u8 p_div_hw)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
if (p_tohw) {
while (p_tohw->pdiv) {
if (p_div_hw == p_tohw->hw_val)
return p_tohw->pdiv;
p_tohw++;
}
return -EINVAL;
}
return 1 << p_div_hw;
}
static int _get_table_rate(struct clk_hw *hw,
struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
@ -326,9 +348,9 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
unsigned long cfreq;
u32 p_div = 0;
int ret;
switch (parent_rate) {
case 12000000:
@ -369,20 +391,16 @@ static int _calc_rate(struct clk_hw *hw, struct tegra_clk_pll_freq_table *cfg,
|| cfg->output_rate > pll->params->vco_max) {
pr_err("%s: Failed to set %s rate %lu\n",
__func__, __clk_get_name(hw->clk), rate);
WARN_ON(1);
return -EINVAL;
}
if (p_tohw) {
p_div = 1 << p_div;
while (p_tohw->pdiv) {
if (p_div <= p_tohw->pdiv) {
cfg->p = p_tohw->hw_val;
break;
}
p_tohw++;
}
if (!p_tohw->pdiv)
return -EINVAL;
if (pll->params->pdiv_tohw) {
ret = _p_div_to_hw(hw, 1 << p_div);
if (ret < 0)
return ret;
else
cfg->p = ret;
} else
cfg->p = p_div;
@ -393,29 +411,61 @@ static void _update_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;
val = pll_readl_base(pll);
if ((pll->flags & TEGRA_PLLM) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
val &= ~(divp_mask(pll) << div_nmp->override_divp_shift);
val |= cfg->p << div_nmp->override_divp_shift;
pll_override_writel(val, params->pmc_divp_reg, pll);
val &= ~((divm_mask(pll) << pll->divm_shift) |
(divn_mask(pll) << pll->divn_shift) |
(divp_mask(pll) << pll->divp_shift));
val |= ((cfg->m << pll->divm_shift) |
(cfg->n << pll->divn_shift) |
(cfg->p << pll->divp_shift));
val = pll_override_readl(params->pmc_divnm_reg, pll);
val &= ~(divm_mask(pll) << div_nmp->override_divm_shift) |
~(divn_mask(pll) << div_nmp->override_divn_shift);
val |= (cfg->m << div_nmp->override_divm_shift) |
(cfg->n << div_nmp->override_divn_shift);
pll_override_writel(val, params->pmc_divnm_reg, pll);
} else {
val = pll_readl_base(pll);
pll_writel_base(val, pll);
val &= ~((divm_mask(pll) << div_nmp->divm_shift) |
(divn_mask(pll) << div_nmp->divn_shift) |
(divp_mask(pll) << div_nmp->divp_shift));
val |= ((cfg->m << div_nmp->divm_shift) |
(cfg->n << div_nmp->divn_shift) |
(cfg->p << div_nmp->divp_shift));
pll_writel_base(val, pll);
}
}
static void _get_pll_mnp(struct tegra_clk_pll *pll,
struct tegra_clk_pll_freq_table *cfg)
{
u32 val;
struct tegra_clk_pll_params *params = pll->params;
struct div_nmp *div_nmp = params->div_nmp;
val = pll_readl_base(pll);
if ((pll->flags & TEGRA_PLLM) &&
(pll_override_readl(PMC_PLLP_WB0_OVERRIDE, pll) &
PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)) {
val = pll_override_readl(params->pmc_divp_reg, pll);
cfg->p = (val >> div_nmp->override_divp_shift) & divp_mask(pll);
cfg->m = (val >> pll->divm_shift) & (divm_mask(pll));
cfg->n = (val >> pll->divn_shift) & (divn_mask(pll));
cfg->p = (val >> pll->divp_shift) & (divp_mask(pll));
val = pll_override_readl(params->pmc_divnm_reg, pll);
cfg->m = (val >> div_nmp->override_divm_shift) & divm_mask(pll);
cfg->n = (val >> div_nmp->override_divn_shift) & divn_mask(pll);
} else {
val = pll_readl_base(pll);
cfg->m = (val >> div_nmp->divm_shift) & divm_mask(pll);
cfg->n = (val >> div_nmp->divn_shift) & divn_mask(pll);
cfg->p = (val >> div_nmp->divp_shift) & divp_mask(pll);
}
}
static void _update_pll_cpcon(struct tegra_clk_pll *pll,
@ -485,9 +535,10 @@ static int clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
}
if (_get_table_rate(hw, &cfg, rate, parent_rate) &&
_calc_rate(hw, &cfg, rate, parent_rate))
_calc_rate(hw, &cfg, rate, parent_rate)) {
WARN_ON(1);
return -EINVAL;
}
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@ -507,7 +558,6 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
u64 output_rate = *prate;
if (pll->flags & TEGRA_PLL_FIXED)
return pll->fixed_rate;
@ -517,13 +567,12 @@ static long clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
return __clk_get_rate(hw->clk);
if (_get_table_rate(hw, &cfg, rate, *prate) &&
_calc_rate(hw, &cfg, rate, *prate))
_calc_rate(hw, &cfg, rate, *prate)) {
WARN_ON(1);
return -EINVAL;
}
output_rate *= cfg.n;
do_div(output_rate, cfg.m * (1 << cfg.p));
return output_rate;
return cfg.output_rate;
}
static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
@ -531,7 +580,6 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
struct tegra_clk_pll_freq_table cfg;
struct pdiv_map *p_tohw = pll->params->pdiv_tohw;
u32 val;
u64 rate = parent_rate;
int pdiv;
@ -553,21 +601,11 @@ static unsigned long clk_pll_recalc_rate(struct clk_hw *hw,
_get_pll_mnp(pll, &cfg);
if (p_tohw) {
while (p_tohw->pdiv) {
if (cfg.p == p_tohw->hw_val) {
pdiv = p_tohw->pdiv;
break;
}
p_tohw++;
}
if (!p_tohw->pdiv) {
WARN_ON(1);
pdiv = 1;
}
} else
pdiv = 1 << cfg.p;
pdiv = _hw_to_p_div(hw, cfg.p);
if (pdiv < 0) {
WARN_ON(1);
pdiv = 1;
}
cfg.m *= pdiv;
@ -647,9 +685,9 @@ static int clk_plle_enable(struct clk_hw *hw)
val = pll_readl_base(pll);
val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
val |= sel.m << pll->divm_shift;
val |= sel.n << pll->divn_shift;
val |= sel.p << pll->divp_shift;
val |= sel.m << pll->params->div_nmp->divm_shift;
val |= sel.n << pll->params->div_nmp->divn_shift;
val |= sel.p << pll->params->div_nmp->divp_shift;
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
}
@ -680,9 +718,9 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
u32 divn = 0, divm = 0, divp = 0;
u64 rate = parent_rate;
divp = (val >> pll->divp_shift) & (divp_mask(pll));
divn = (val >> pll->divn_shift) & (divn_mask(pll));
divm = (val >> pll->divm_shift) & (divm_mask(pll));
divp = (val >> pll->params->div_nmp->divp_shift) & (divp_mask(pll));
divn = (val >> pll->params->div_nmp->divn_shift) & (divn_mask(pll));
divm = (val >> pll->params->div_nmp->divm_shift) & (divm_mask(pll));
divm *= divp;
rate *= divn;
@ -769,16 +807,22 @@ static int _calc_dynamic_ramp_rate(struct clk_hw *hw,
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned int p;
int p_div;
if (!rate)
return -EINVAL;
p = DIV_ROUND_UP(pll->params->vco_min, rate);
cfg->m = _pll_fixed_mdiv(pll->params, parent_rate);
cfg->p = p;
cfg->output_rate = rate * cfg->p;
cfg->output_rate = rate * p;
cfg->n = cfg->output_rate * cfg->m / parent_rate;
p_div = _p_div_to_hw(hw, p);
if (p_div < 0)
return p_div;
else
cfg->p = p_div;
if (cfg->n > divn_max(pll) || cfg->output_rate > pll->params->vco_max)
return -EINVAL;
@ -790,18 +834,25 @@ static int _pll_ramp_calc_pll(struct clk_hw *hw,
unsigned long rate, unsigned long parent_rate)
{
struct tegra_clk_pll *pll = to_clk_pll(hw);
int err = 0;
int err = 0, p_div;
err = _get_table_rate(hw, cfg, rate, parent_rate);
if (err < 0)
err = _calc_dynamic_ramp_rate(hw, cfg, rate, parent_rate);
else if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
else {
if (cfg->m != _pll_fixed_mdiv(pll->params, parent_rate)) {
WARN_ON(1);
err = -EINVAL;
goto out;
}
p_div = _p_div_to_hw(hw, cfg->p);
if (p_div < 0)
return p_div;
else
cfg->p = p_div;
}
if (!cfg->p || (cfg->p > pll->params->max_p))
if (cfg->p > pll->params->max_p)
err = -EINVAL;
out:
@ -815,7 +866,6 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll_freq_table cfg, old_cfg;
unsigned long flags = 0;
int ret = 0;
u8 old_p;
ret = _pll_ramp_calc_pll(hw, &cfg, rate, parent_rate);
if (ret < 0)
@ -826,11 +876,8 @@ static int clk_pllxc_set_rate(struct clk_hw *hw, unsigned long rate,
_get_pll_mnp(pll, &old_cfg);
old_p = pllxc_p[old_cfg.p];
if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_p != cfg.p) {
cfg.p -= 1;
if (old_cfg.m != cfg.m || old_cfg.n != cfg.n || old_cfg.p != cfg.p)
ret = _program_pll(hw, &cfg, rate);
}
if (pll->lock)
spin_unlock_irqrestore(pll->lock, flags);
@ -842,15 +889,19 @@ static long clk_pll_ramp_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
struct tegra_clk_pll_freq_table cfg;
int ret = 0;
int ret = 0, p_div;
u64 output_rate = *prate;
ret = _pll_ramp_calc_pll(hw, &cfg, rate, *prate);
if (ret < 0)
return ret;
p_div = _hw_to_p_div(hw, cfg.p);
if (p_div < 0)
return p_div;
output_rate *= cfg.n;
do_div(output_rate, cfg.m * cfg.p);
do_div(output_rate, cfg.m * p_div);
return output_rate;
}
@ -862,7 +913,6 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long flags = 0;
int state, ret = 0;
u32 val;
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@ -881,22 +931,7 @@ static int clk_pllm_set_rate(struct clk_hw *hw, unsigned long rate,
if (ret < 0)
goto out;
cfg.p -= 1;
val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE) {
val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
val = cfg.p ? (val | PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK) :
(val & ~PMC_PLLM_WB0_OVERRIDE_2_DIVP_MASK);
writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE_2);
val = readl_relaxed(pll->pmc + PMC_PLLM_WB0_OVERRIDE);
val &= ~(divn_mask(pll) | divm_mask(pll));
val |= (cfg.m << pll->divm_shift) | (cfg.n << pll->divn_shift);
writel_relaxed(val, pll->pmc + PMC_PLLM_WB0_OVERRIDE);
} else
_update_pll_mnp(pll, &cfg);
_update_pll_mnp(pll, &cfg);
out:
if (pll->lock)
@ -1010,13 +1045,10 @@ static int _pllcx_update_dynamic_coef(struct tegra_clk_pll *pll,
static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct tegra_clk_pll_freq_table cfg;
struct tegra_clk_pll_freq_table cfg, old_cfg;
struct tegra_clk_pll *pll = to_clk_pll(hw);
unsigned long flags = 0;
int state, ret = 0;
u32 val;
u16 old_m, old_n;
u8 old_p;
if (pll->lock)
spin_lock_irqsave(pll->lock, flags);
@ -1025,21 +1057,16 @@ static int clk_pllc_set_rate(struct clk_hw *hw, unsigned long rate,
if (ret < 0)
goto out;
val = pll_readl_base(pll);
old_m = (val >> pll->divm_shift) & (divm_mask(pll));
old_n = (val >> pll->divn_shift) & (divn_mask(pll));
old_p = pllcx_p[(val >> pll->divp_shift) & (divp_mask(pll))];
_get_pll_mnp(pll, &old_cfg);
if (cfg.m != old_m) {
if (cfg.m != old_cfg.m) {
WARN_ON(1);
goto out;
}
if (old_n == cfg.n && old_p == cfg.p)
if (old_cfg.n == cfg.n && old_cfg.p == cfg.p)
goto out;
cfg.p -= 1;
state = clk_pll_is_enabled(hw);
if (state)
_clk_pllc_disable(hw);
@ -1178,8 +1205,8 @@ static int clk_plle_tegra114_enable(struct clk_hw *hw)
val = pll_readl_base(pll);
val &= ~(divm_mask(pll) | divn_mask(pll) | divp_mask(pll));
val &= ~(PLLE_BASE_DIVCML_WIDTH << PLLE_BASE_DIVCML_SHIFT);
val |= sel.m << pll->divm_shift;
val |= sel.n << pll->divn_shift;
val |= sel.m << pll->params->div_nmp->divm_shift;
val |= sel.n << pll->params->div_nmp->divn_shift;
val |= sel.cpcon << PLLE_BASE_DIVCML_SHIFT;
pll_writel_base(val, pll);
udelay(1);
@ -1240,12 +1267,8 @@ static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
pll->flags = pll_flags;
pll->lock = lock;
pll->divp_shift = PLL_BASE_DIVP_SHIFT;
pll->divp_width = PLL_BASE_DIVP_WIDTH;
pll->divn_shift = PLL_BASE_DIVN_SHIFT;
pll->divn_width = PLL_BASE_DIVN_WIDTH;
pll->divm_shift = PLL_BASE_DIVM_SHIFT;
pll->divm_width = PLL_BASE_DIVM_WIDTH;
if (!pll_params->div_nmp)
pll_params->div_nmp = &default_nmp;
return pll;
}
@ -1401,7 +1424,7 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
struct tegra_clk_pll *pll;
struct clk *clk;
pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE | TEGRA_PLL_LOCK_MISC;
pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
freq_table, lock);
if (IS_ERR(pll))
@ -1428,7 +1451,6 @@ struct clk *tegra_clk_register_pllre(const char *name, const char *parent_name,
val &= ~BIT(29);
pll_writel_misc(val, pll);
pll_flags |= TEGRA_PLL_LOCK_MISC;
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
&tegra_clk_pllre_ops);
if (IS_ERR(clk))
@ -1453,6 +1475,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
pll_flags |= TEGRA_PLL_BYPASS;
pll_flags |= TEGRA_PLL_HAS_LOCK_ENABLE;
pll_flags |= TEGRA_PLLM;
pll = _tegra_init_pll(clk_base, pmc, fixed_rate, pll_params, pll_flags,
freq_table, lock);
if (IS_ERR(pll))

View File

@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <linux/export.h>
#include <linux/clk/tegra.h>
#include "clk.h"
@ -28,6 +29,7 @@
#define RST_DEVICES_L 0x004
#define RST_DEVICES_H 0x008
#define RST_DEVICES_U 0x00C
#define RST_DFLL_DVCO 0x2F4
#define RST_DEVICES_V 0x358
#define RST_DEVICES_W 0x35C
#define RST_DEVICES_X 0x28C
@ -41,8 +43,36 @@
#define RST_DEVICES_CLR_V 0x434
#define RST_DEVICES_SET_W 0x438
#define RST_DEVICES_CLR_W 0x43c
#define CPU_FINETRIM_SELECT 0x4d4 /* override default prop dlys */
#define CPU_FINETRIM_DR 0x4d8 /* rise->rise prop dly A */
#define CPU_FINETRIM_R 0x4e4 /* rise->rise prop dly inc A */
#define RST_DEVICES_NUM 5
/* RST_DFLL_DVCO bitfields */
#define DVFS_DFLL_RESET_SHIFT 0
/* CPU_FINETRIM_SELECT and CPU_FINETRIM_DR bitfields */
#define CPU_FINETRIM_1_FCPU_1 BIT(0) /* fcpu0 */
#define CPU_FINETRIM_1_FCPU_2 BIT(1) /* fcpu1 */
#define CPU_FINETRIM_1_FCPU_3 BIT(2) /* fcpu2 */
#define CPU_FINETRIM_1_FCPU_4 BIT(3) /* fcpu3 */
#define CPU_FINETRIM_1_FCPU_5 BIT(4) /* fl2 */
#define CPU_FINETRIM_1_FCPU_6 BIT(5) /* ftop */
/* CPU_FINETRIM_R bitfields */
#define CPU_FINETRIM_R_FCPU_1_SHIFT 0 /* fcpu0 */
#define CPU_FINETRIM_R_FCPU_1_MASK (0x3 << CPU_FINETRIM_R_FCPU_1_SHIFT)
#define CPU_FINETRIM_R_FCPU_2_SHIFT 2 /* fcpu1 */
#define CPU_FINETRIM_R_FCPU_2_MASK (0x3 << CPU_FINETRIM_R_FCPU_2_SHIFT)
#define CPU_FINETRIM_R_FCPU_3_SHIFT 4 /* fcpu2 */
#define CPU_FINETRIM_R_FCPU_3_MASK (0x3 << CPU_FINETRIM_R_FCPU_3_SHIFT)
#define CPU_FINETRIM_R_FCPU_4_SHIFT 6 /* fcpu3 */
#define CPU_FINETRIM_R_FCPU_4_MASK (0x3 << CPU_FINETRIM_R_FCPU_4_SHIFT)
#define CPU_FINETRIM_R_FCPU_5_SHIFT 8 /* fl2 */
#define CPU_FINETRIM_R_FCPU_5_MASK (0x3 << CPU_FINETRIM_R_FCPU_5_SHIFT)
#define CPU_FINETRIM_R_FCPU_6_SHIFT 10 /* ftop */
#define CPU_FINETRIM_R_FCPU_6_MASK (0x3 << CPU_FINETRIM_R_FCPU_6_SHIFT)
#define CLK_OUT_ENB_L 0x010
#define CLK_OUT_ENB_H 0x014
#define CLK_OUT_ENB_U 0x018
@ -127,6 +157,7 @@
#define PMC_DPD_PADS_ORIDE_BLINK_ENB 20
#define PMC_CTRL 0
#define PMC_CTRL_BLINK_ENB 7
#define PMC_BLINK_TIMER 0x40
#define OSC_CTRL 0x50
#define OSC_CTRL_OSC_FREQ_SHIFT 28
@ -242,6 +273,8 @@
#define CLK_SOURCE_I2CSLOW 0x3fc
#define CLK_SOURCE_SE 0x42c
#define CLK_SOURCE_MSELECT 0x3b4
#define CLK_SOURCE_DFLL_REF 0x62c
#define CLK_SOURCE_DFLL_SOC 0x630
#define CLK_SOURCE_SOC_THERM 0x644
#define CLK_SOURCE_XUSB_HOST_SRC 0x600
#define CLK_SOURCE_XUSB_FALCON_SRC 0x604
@ -250,6 +283,10 @@
#define CLK_SOURCE_XUSB_DEV_SRC 0x60c
#define CLK_SOURCE_EMC 0x19c
/* PLLM override registers */
#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#define PMC_PLLM_WB0_OVERRIDE_2 0x2b0
/* Tegra CPU clock and reset control regs */
#define CLK_RST_CONTROLLER_CPU_CMPLX_STATUS 0x470
@ -267,6 +304,15 @@ static DEFINE_SPINLOCK(clk_doubler_lock);
static DEFINE_SPINLOCK(clk_out_lock);
static DEFINE_SPINLOCK(sysrate_lock);
static struct div_nmp pllxc_nmp = {
.divm_shift = 0,
.divm_width = 8,
.divn_shift = 8,
.divn_width = 8,
.divp_shift = 20,
.divp_width = 4,
};
static struct pdiv_map pllxc_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@ -315,6 +361,16 @@ static struct tegra_clk_pll_params pll_c_params = {
.stepa_shift = 17,
.stepb_shift = 9,
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
};
static struct div_nmp pllcx_nmp = {
.divm_shift = 0,
.divm_width = 2,
.divn_shift = 8,
.divn_width = 8,
.divp_shift = 20,
.divp_width = 3,
};
static struct pdiv_map pllc_p[] = {
@ -348,6 +404,8 @@ static struct tegra_clk_pll_params pll_c2_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
.div_nmp = &pllcx_nmp,
.max_p = 7,
.ext_misc_reg[0] = 0x4f0,
.ext_misc_reg[1] = 0x4f4,
.ext_misc_reg[2] = 0x4f8,
@ -366,11 +424,25 @@ static struct tegra_clk_pll_params pll_c3_params = {
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.pdiv_tohw = pllc_p,
.div_nmp = &pllcx_nmp,
.max_p = 7,
.ext_misc_reg[0] = 0x504,
.ext_misc_reg[1] = 0x508,
.ext_misc_reg[2] = 0x50c,
};
static struct div_nmp pllm_nmp = {
.divm_shift = 0,
.divm_width = 8,
.override_divm_shift = 0,
.divn_shift = 8,
.divn_width = 8,
.override_divn_shift = 8,
.divp_shift = 20,
.divp_width = 1,
.override_divp_shift = 27,
};
static struct pdiv_map pllm_p[] = {
{ .pdiv = 1, .hw_val = 0 },
{ .pdiv = 2, .hw_val = 1 },
@ -400,6 +472,18 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_delay = 300,
.max_p = 2,
.pdiv_tohw = pllm_p,
.div_nmp = &pllm_nmp,
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE_2,
};
static struct div_nmp pllp_nmp = {
.divm_shift = 0,
.divm_width = 5,
.divn_shift = 8,
.divn_width = 10,
.divp_shift = 20,
.divp_width = 3,
};
static struct tegra_clk_pll_freq_table pll_p_freq_table[] = {
@ -423,6 +507,7 @@ static struct tegra_clk_pll_params pll_p_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_a_freq_table[] = {
@ -449,6 +534,7 @@ static struct tegra_clk_pll_params pll_a_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_freq_table pll_d_freq_table[] = {
@ -484,6 +570,7 @@ static struct tegra_clk_pll_params pll_d_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.div_nmp = &pllp_nmp,
};
static struct tegra_clk_pll_params pll_d2_params = {
@ -498,6 +585,7 @@ static struct tegra_clk_pll_params pll_d2_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.div_nmp = &pllp_nmp,
};
static struct pdiv_map pllu_p[] = {
@ -506,6 +594,15 @@ static struct pdiv_map pllu_p[] = {
{ .pdiv = 0, .hw_val = 0 },
};
static struct div_nmp pllu_nmp = {
.divm_shift = 0,
.divm_width = 5,
.divn_shift = 8,
.divn_width = 10,
.divp_shift = 20,
.divp_width = 1,
};
static struct tegra_clk_pll_freq_table pll_u_freq_table[] = {
{12000000, 480000000, 960, 12, 0, 12},
{13000000, 480000000, 960, 13, 0, 12},
@ -528,6 +625,7 @@ static struct tegra_clk_pll_params pll_u_params = {
.lock_enable_bit_idx = PLLDU_MISC_LOCK_ENABLE,
.lock_delay = 1000,
.pdiv_tohw = pllu_p,
.div_nmp = &pllu_nmp,
};
static struct tegra_clk_pll_freq_table pll_x_freq_table[] = {
@ -560,6 +658,7 @@ static struct tegra_clk_pll_params pll_x_params = {
.stepa_shift = 16,
.stepb_shift = 24,
.pdiv_tohw = pllxc_p,
.div_nmp = &pllxc_nmp,
};
static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
@ -569,6 +668,15 @@ static struct tegra_clk_pll_freq_table pll_e_freq_table[] = {
{0, 0, 0, 0, 0, 0},
};
static struct div_nmp plle_nmp = {
.divm_shift = 0,
.divm_width = 8,
.divn_shift = 8,
.divn_width = 8,
.divp_shift = 24,
.divp_width = 4,
};
static struct tegra_clk_pll_params pll_e_params = {
.input_min = 12000000,
.input_max = 1000000000,
@ -582,6 +690,16 @@ static struct tegra_clk_pll_params pll_e_params = {
.lock_mask = PLLE_MISC_LOCK,
.lock_enable_bit_idx = PLLE_MISC_LOCK_ENABLE,
.lock_delay = 300,
.div_nmp = &plle_nmp,
};
static struct div_nmp pllre_nmp = {
.divm_shift = 0,
.divm_width = 8,
.divn_shift = 8,
.divn_width = 8,
.divp_shift = 16,
.divp_width = 4,
};
static struct tegra_clk_pll_params pll_re_vco_params = {
@ -598,6 +716,7 @@ static struct tegra_clk_pll_params pll_re_vco_params = {
.lock_delay = 300,
.iddq_reg = PLLRE_MISC,
.iddq_bit_idx = PLLRE_IDDQ_BIT,
.div_nmp = &pllre_nmp,
};
/* Peripheral clock registers */
@ -765,6 +884,7 @@ enum tegra114_clk {
audio1, audio2, audio3, audio4, spdif, clk_out_1, clk_out_2, clk_out_3,
blink, xusb_host_src = 252, xusb_falcon_src, xusb_fs_src, xusb_ss_src,
xusb_dev_src, xusb_dev, xusb_hs_src, sclk, hclk, pclk, cclk_g, cclk_lp,
dfll_ref = 264, dfll_soc,
/* Mux clocks */
@ -1202,8 +1322,8 @@ static void __init tegra114_pll_init(void __iomem *clk_base,
/* PLLP_OUT2 */
clk = tegra_clk_register_divider("pll_p_out2_div", "pll_p",
clk_base + PLLP_OUTA, 0, TEGRA_DIVIDER_FIXED |
TEGRA_DIVIDER_ROUND_UP, 24, 8, 1,
&pll_div_lock);
TEGRA_DIVIDER_ROUND_UP | TEGRA_DIVIDER_INT, 24,
8, 1, &pll_div_lock);
clk = tegra_clk_register_pll_out("pll_p_out2", "pll_p_out2_div",
clk_base + PLLP_OUTA, 17, 16,
CLK_IGNORE_UNUSED | CLK_SET_RATE_PARENT, 0,
@ -1605,7 +1725,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
/* clk_out_2 */
clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
ARRAY_SIZE(clk_out1_parents), 0,
ARRAY_SIZE(clk_out2_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
&clk_out_lock);
clks[clk_out_2_mux] = clk;
@ -1617,7 +1737,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
/* clk_out_3 */
clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
ARRAY_SIZE(clk_out1_parents), 0,
ARRAY_SIZE(clk_out3_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
&clk_out_lock);
clks[clk_out_3_mux] = clk;
@ -1628,6 +1748,8 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
clks[clk_out_3] = clk;
/* blink */
/* clear the blink timer register to directly output clk_32k */
writel_relaxed(0, pmc_base + PMC_BLINK_TIMER);
clk = clk_register_gate(NULL, "blink_override", "clk_32k", 0,
pmc_base + PMC_DPD_PADS_ORIDE,
PMC_DPD_PADS_ORIDE_BLINK_ENB, 0, NULL);
@ -1640,7 +1762,7 @@ static void __init tegra114_pmc_clk_init(void __iomem *pmc_base)
}
static const char *sclk_parents[] = { "clk_m", "pll_c_out1", "pll_p_out4",
"pll_p_out3", "pll_p_out2", "unused",
"pll_p", "pll_p_out2", "unused",
"clk_32k", "pll_m_out1" };
static const char *cclk_g_parents[] = { "clk_m", "pll_c", "clk_32k", "pll_m",
@ -1750,7 +1872,7 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("vi_sensor", "vi_sensor", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR, 20, &periph_l_regs, TEGRA_PERIPH_NO_RESET, vi_sensor),
TEGRA_INIT_DATA_INT8("vi", "vi", "tegra_camera", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI, 20, &periph_l_regs, 0, vi),
TEGRA_INIT_DATA_INT8("epp", NULL, "epp", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_EPP, 19, &periph_l_regs, 0, epp),
TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_h_regs, TEGRA_PERIPH_WAR_1005168, msenc),
TEGRA_INIT_DATA_INT8("msenc", NULL, "msenc", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_MSENC, 91, &periph_u_regs, TEGRA_PERIPH_WAR_1005168, msenc),
TEGRA_INIT_DATA_INT8("tsec", NULL, "tsec", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_TSEC, 83, &periph_u_regs, 0, tsec),
TEGRA_INIT_DATA_INT8("host1x", NULL, "host1x", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_HOST1X, 28, &periph_l_regs, 0, host1x),
TEGRA_INIT_DATA_MUX8("hdmi", NULL, "hdmi", mux_pllp_pllm_plld_plla_pllc_plld2_clkm, CLK_SOURCE_HDMI, 51, &periph_h_regs, 0, hdmi),
@ -1767,6 +1889,8 @@ static struct tegra_periph_init_data tegra_periph_clk_list[] = {
TEGRA_INIT_DATA_MUX("i2cslow", NULL, "i2cslow", mux_pllp_pllc_clk32_clkm, CLK_SOURCE_I2CSLOW, 81, &periph_u_regs, TEGRA_PERIPH_ON_APB, i2cslow),
TEGRA_INIT_DATA_INT8("se", NULL, "se", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SE, 127, &periph_v_regs, TEGRA_PERIPH_ON_APB, se),
TEGRA_INIT_DATA_INT_FLAGS("mselect", NULL, "mselect", mux_pllp_clkm, CLK_SOURCE_MSELECT, 99, &periph_v_regs, 0, mselect, CLK_IGNORE_UNUSED),
TEGRA_INIT_DATA_MUX("dfll_ref", "ref", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_REF, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_ref),
TEGRA_INIT_DATA_MUX("dfll_soc", "soc", "t114_dfll", mux_pllp_clkm, CLK_SOURCE_DFLL_SOC, 155, &periph_w_regs, TEGRA_PERIPH_ON_APB, dfll_soc),
TEGRA_INIT_DATA_MUX8("soc_therm", NULL, "soc_therm", mux_pllm_pllc_pllp_plla, CLK_SOURCE_SOC_THERM, 78, &periph_u_regs, TEGRA_PERIPH_ON_APB, soc_therm),
TEGRA_INIT_DATA_XUSB("xusb_host_src", "host_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_HOST_SRC, 143, &periph_w_regs, TEGRA_PERIPH_ON_APB | TEGRA_PERIPH_NO_RESET, xusb_host_src),
TEGRA_INIT_DATA_XUSB("xusb_falcon_src", "falcon_src", "tegra_xhci", mux_clkm_pllp_pllc_pllre, CLK_SOURCE_XUSB_FALCON_SRC, 143, &periph_w_regs, TEGRA_PERIPH_NO_RESET, xusb_falcon_src),
@ -2028,6 +2152,10 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
/*
* dfll_soc/dfll_ref apparently must be kept enabled, otherwise I2C5
* breaks
*/
static __initdata struct tegra_clk_init_table init_table[] = {
{uarta, pll_p, 408000000, 0},
{uartb, pll_p, 408000000, 0},
@ -2043,6 +2171,8 @@ static __initdata struct tegra_clk_init_table init_table[] = {
{i2s2, pll_a_out0, 11289600, 0},
{i2s3, pll_a_out0, 11289600, 0},
{i2s4, pll_a_out0, 11289600, 0},
{dfll_soc, pll_p, 51000000, 1},
{dfll_ref, pll_p, 51000000, 1},
{clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
};
@ -2051,7 +2181,132 @@ static void __init tegra114_clock_apply_init_table(void)
tegra_init_from_table(init_table, clks, clk_max);
}
void __init tegra114_clock_init(struct device_node *np)
/**
* tegra114_car_barrier - wait for pending writes to the CAR to complete
*
* Wait for any outstanding writes to the CAR MMIO space from this CPU
* to complete before continuing execution. No return value.
*/
static void tegra114_car_barrier(void)
{
wmb(); /* probably unnecessary */
readl_relaxed(clk_base + CPU_FINETRIM_SELECT);
}
/**
* tegra114_clock_tune_cpu_trimmers_high - use high-voltage propagation delays
*
* When the CPU rail voltage is in the high-voltage range, use the
* built-in hardwired clock propagation delays in the CPU clock
* shaper. No return value.
*/
void tegra114_clock_tune_cpu_trimmers_high(void)
{
u32 select = 0;
/* Use hardwired rise->rise & fall->fall clock propagation delays */
select |= ~(CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
tegra114_car_barrier();
}
EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_high);
/**
* tegra114_clock_tune_cpu_trimmers_low - use low-voltage propagation delays
*
* When the CPU rail voltage is in the low-voltage range, use the
* extended clock propagation delays set by
* tegra114_clock_tune_cpu_trimmers_init(). The intention is to
* maintain the input clock duty cycle that the FCPU subsystem
* expects. No return value.
*/
void tegra114_clock_tune_cpu_trimmers_low(void)
{
u32 select = 0;
/*
* Use software-specified rise->rise & fall->fall clock
* propagation delays (from
* tegra114_clock_tune_cpu_trimmers_init()
*/
select |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
writel_relaxed(select, clk_base + CPU_FINETRIM_SELECT);
tegra114_car_barrier();
}
EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_low);
/**
* tegra114_clock_tune_cpu_trimmers_init - set up and enable clk prop delays
*
* Program extended clock propagation delays into the FCPU clock
* shaper and enable them. XXX Define the purpose - peak current
* reduction? No return value.
*/
/* XXX Initial voltage rail state assumption issues? */
void tegra114_clock_tune_cpu_trimmers_init(void)
{
u32 dr = 0, r = 0;
/* Increment the rise->rise clock delay by four steps */
r |= (CPU_FINETRIM_R_FCPU_1_MASK | CPU_FINETRIM_R_FCPU_2_MASK |
CPU_FINETRIM_R_FCPU_3_MASK | CPU_FINETRIM_R_FCPU_4_MASK |
CPU_FINETRIM_R_FCPU_5_MASK | CPU_FINETRIM_R_FCPU_6_MASK);
writel_relaxed(r, clk_base + CPU_FINETRIM_R);
/*
* Use the rise->rise clock propagation delay specified in the
* r field
*/
dr |= (CPU_FINETRIM_1_FCPU_1 | CPU_FINETRIM_1_FCPU_2 |
CPU_FINETRIM_1_FCPU_3 | CPU_FINETRIM_1_FCPU_4 |
CPU_FINETRIM_1_FCPU_5 | CPU_FINETRIM_1_FCPU_6);
writel_relaxed(dr, clk_base + CPU_FINETRIM_DR);
tegra114_clock_tune_cpu_trimmers_low();
}
EXPORT_SYMBOL(tegra114_clock_tune_cpu_trimmers_init);
/**
* tegra114_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset
*
* Assert the reset line of the DFLL's DVCO. No return value.
*/
void tegra114_clock_assert_dfll_dvco_reset(void)
{
u32 v;
v = readl_relaxed(clk_base + RST_DFLL_DVCO);
v |= (1 << DVFS_DFLL_RESET_SHIFT);
writel_relaxed(v, clk_base + RST_DFLL_DVCO);
tegra114_car_barrier();
}
EXPORT_SYMBOL(tegra114_clock_assert_dfll_dvco_reset);
/**
* tegra114_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset
*
* Deassert the reset line of the DFLL's DVCO, allowing the DVCO to
* operate. No return value.
*/
void tegra114_clock_deassert_dfll_dvco_reset(void)
{
u32 v;
v = readl_relaxed(clk_base + RST_DFLL_DVCO);
v &= ~(1 << DVFS_DFLL_RESET_SHIFT);
writel_relaxed(v, clk_base + RST_DFLL_DVCO);
tegra114_car_barrier();
}
EXPORT_SYMBOL(tegra114_clock_deassert_dfll_dvco_reset);
static void __init tegra114_clock_init(struct device_node *np)
{
struct device_node *node;
int i;
@ -2104,3 +2359,4 @@ void __init tegra114_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra114_cpu_car_ops;
}
CLK_OF_DECLARE(tegra114, "nvidia,tegra114-car", tegra114_clock_init);

View File

@ -1287,7 +1287,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
void __init tegra20_clock_init(struct device_node *np)
static void __init tegra20_clock_init(struct device_node *np)
{
int i;
struct device_node *node;
@ -1339,3 +1339,4 @@ void __init tegra20_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra20_cpu_car_ops;
}
CLK_OF_DECLARE(tegra20, "nvidia,tegra20-car", tegra20_clock_init);

View File

@ -252,6 +252,9 @@
#define CLK_RESET_CCLK_RUN_POLICY 2
#define CLK_RESET_CCLK_BURST_POLICY_PLLX 8
/* PLLM override registers */
#define PMC_PLLM_WB0_OVERRIDE 0x1dc
#ifdef CONFIG_PM_SLEEP
static struct cpu_clk_suspend_context {
u32 pllx_misc;
@ -563,6 +566,18 @@ static struct tegra_clk_pll_params pll_c_params = {
.lock_delay = 300,
};
static struct div_nmp pllm_nmp = {
.divn_shift = 8,
.divn_width = 10,
.override_divn_shift = 5,
.divm_shift = 0,
.divm_width = 5,
.override_divm_shift = 0,
.divp_shift = 20,
.divp_width = 3,
.override_divp_shift = 15,
};
static struct tegra_clk_pll_params pll_m_params = {
.input_min = 2000000,
.input_max = 31000000,
@ -575,6 +590,9 @@ static struct tegra_clk_pll_params pll_m_params = {
.lock_mask = PLL_BASE_LOCK,
.lock_enable_bit_idx = PLL_MISC_LOCK_ENABLE,
.lock_delay = 300,
.div_nmp = &pllm_nmp,
.pmc_divnm_reg = PMC_PLLM_WB0_OVERRIDE,
.pmc_divp_reg = PMC_PLLM_WB0_OVERRIDE,
};
static struct tegra_clk_pll_params pll_p_params = {
@ -1223,7 +1241,7 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_2 */
clk = clk_register_mux(NULL, "clk_out_2_mux", clk_out2_parents,
ARRAY_SIZE(clk_out1_parents), 0,
ARRAY_SIZE(clk_out2_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 14, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_2", "clk_out_2_mux", 0,
@ -1234,7 +1252,7 @@ static void __init tegra30_pmc_clk_init(void)
/* clk_out_3 */
clk = clk_register_mux(NULL, "clk_out_3_mux", clk_out3_parents,
ARRAY_SIZE(clk_out1_parents), 0,
ARRAY_SIZE(clk_out3_parents), 0,
pmc_base + PMC_CLK_OUT_CNTRL, 22, 3, 0,
&clk_out_lock);
clk = clk_register_gate(NULL, "clk_out_3", "clk_out_3_mux", 0,
@ -1954,7 +1972,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
void __init tegra30_clock_init(struct device_node *np)
static void __init tegra30_clock_init(struct device_node *np)
{
struct device_node *node;
int i;
@ -2005,3 +2023,4 @@ void __init tegra30_clock_init(struct device_node *np)
tegra_cpu_car_ops = &tegra30_cpu_car_ops;
}
CLK_OF_DECLARE(tegra30, "nvidia,tegra30-car", tegra30_clock_init);

View File

@ -74,18 +74,6 @@ void __init tegra_init_from_table(struct tegra_clk_init_table *tbl,
}
}
static const struct of_device_id tegra_dt_clk_match[] = {
{ .compatible = "nvidia,tegra20-car", .data = tegra20_clock_init },
{ .compatible = "nvidia,tegra30-car", .data = tegra30_clock_init },
{ .compatible = "nvidia,tegra114-car", .data = tegra114_clock_init },
{ }
};
void __init tegra_clocks_init(void)
{
of_clk_init(tegra_dt_clk_match);
}
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
void __init tegra_clocks_apply_init_table(void)

View File

@ -127,6 +127,31 @@ struct pdiv_map {
u8 hw_val;
};
/**
* struct div_nmp - offset and width of m,n and p fields
*
* @divn_shift: shift to the feedback divider bit field
* @divn_width: width of the feedback divider bit field
* @divm_shift: shift to the input divider bit field
* @divm_width: width of the input divider bit field
* @divp_shift: shift to the post divider bit field
* @divp_width: width of the post divider bit field
* @override_divn_shift: shift to the feedback divider bitfield in override reg
* @override_divm_shift: shift to the input divider bitfield in override reg
* @override_divp_shift: shift to the post divider bitfield in override reg
*/
struct div_nmp {
u8 divn_shift;
u8 divn_width;
u8 divm_shift;
u8 divm_width;
u8 divp_shift;
u8 divp_width;
u8 override_divn_shift;
u8 override_divm_shift;
u8 override_divp_shift;
};
/**
* struct clk_pll_params - PLL parameters
*
@ -161,11 +186,14 @@ struct tegra_clk_pll_params {
u32 aux_reg;
u32 dyn_ramp_reg;
u32 ext_misc_reg[3];
u32 pmc_divnm_reg;
u32 pmc_divp_reg;
int stepa_shift;
int stepb_shift;
int lock_delay;
int max_p;
struct pdiv_map *pdiv_tohw;
struct div_nmp *div_nmp;
};
/**
@ -179,12 +207,6 @@ struct tegra_clk_pll_params {
* @flags: PLL flags
* @fixed_rate: PLL rate if it is fixed
* @lock: register lock
* @divn_shift: shift to the feedback divider bit field
* @divn_width: width of the feedback divider bit field
* @divm_shift: shift to the input divider bit field
* @divm_width: width of the input divider bit field
* @divp_shift: shift to the post divider bit field
* @divp_width: width of the post divider bit field
*
* Flags:
* TEGRA_PLL_USE_LOCK - This flag indicated to use lock bits for
@ -214,12 +236,6 @@ struct tegra_clk_pll {
u32 flags;
unsigned long fixed_rate;
spinlock_t *lock;
u8 divn_shift;
u8 divn_width;
u8 divm_shift;
u8 divm_width;
u8 divp_shift;
u8 divp_width;
struct tegra_clk_pll_freq_table *freq_table;
struct tegra_clk_pll_params *params;
};
@ -571,23 +587,11 @@ void tegra_init_from_table(struct tegra_clk_init_table *tbl,
void tegra_init_dup_clks(struct tegra_clk_duplicate *dup_list,
struct clk *clks[], int clk_max);
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
void tegra20_clock_init(struct device_node *np);
#else
static inline void tegra20_clock_init(struct device_node *np) {}
#endif /* CONFIG_ARCH_TEGRA_2x_SOC */
#ifdef CONFIG_ARCH_TEGRA_3x_SOC
void tegra30_clock_init(struct device_node *np);
#else
static inline void tegra30_clock_init(struct device_node *np) {}
#endif /* CONFIG_ARCH_TEGRA_3x_SOC */
#ifdef CONFIG_ARCH_TEGRA_114_SOC
void tegra114_clock_init(struct device_node *np);
#else
static inline void tegra114_clock_init(struct device_node *np) {}
#endif /* CONFIG_ARCH_TEGRA114_SOC */
void tegra114_clock_tune_cpu_trimmers_high(void);
void tegra114_clock_tune_cpu_trimmers_low(void);
void tegra114_clock_tune_cpu_trimmers_init(void);
void tegra114_clock_assert_dfll_dvco_reset(void);
void tegra114_clock_deassert_dfll_dvco_reset(void);
typedef void (*tegra_clk_apply_init_table_func)(void);
extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;

View File

@ -45,7 +45,7 @@ static int ab8500_reg_clks(struct device *dev)
CLK_IS_ROOT);
clk_register_clkdev(clk, "sysclk", "ab8500-usb.0");
clk_register_clkdev(clk, "sysclk", "ab-iddet.0");
clk_register_clkdev(clk, "sysclk", "ab85xx-codec.0");
clk_register_clkdev(clk, "sysclk", "snd-soc-mop500.0");
clk_register_clkdev(clk, "sysclk", "shrm_bus");
/* ab8500_sysclk2 */
@ -70,19 +70,19 @@ static int ab8500_reg_clks(struct device *dev)
AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
AB8500_SYSULPCLKCTRL1_ULPCLKREQ,
38400000, 9000, CLK_IS_ROOT);
clk_register_clkdev(clk, "ulpclk", "ab85xx-codec.0");
clk_register_clkdev(clk, "ulpclk", "snd-soc-mop500.0");
/* ab8500_intclk */
clk = clk_reg_sysctrl_set_parent(dev , "intclk", intclk_parents, 2,
intclk_reg_sel, intclk_reg_mask, intclk_reg_bits, 0);
clk_register_clkdev(clk, "intclk", "ab85xx-codec.0");
clk_register_clkdev(clk, "intclk", "snd-soc-mop500.0");
clk_register_clkdev(clk, NULL, "ab8500-pwm.1");
/* ab8500_audioclk */
clk = clk_reg_sysctrl_gate(dev , "audioclk", "intclk",
AB8500_SYSULPCLKCTRL1, AB8500_SYSULPCLKCTRL1_AUDIOCLKENA,
AB8500_SYSULPCLKCTRL1_AUDIOCLKENA, 0, 0);
clk_register_clkdev(clk, "audioclk", "ab85xx-codec.0");
clk_register_clkdev(clk, "audioclk", "ab8500-codec.0");
return 0;
}

View File

@ -12,10 +12,568 @@
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
void u8540_clk_init(void)
void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
u32 clkrst5_base, u32 clkrst6_base)
{
/* register clocks here */
struct clk *clk;
/* Clock sources. */
/* Fixed ClockGen */
clk = clk_reg_prcmu_gate("soc0_pll", NULL, PRCMU_PLLSOC0,
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
clk_register_clkdev(clk, "soc0_pll", NULL);
clk = clk_reg_prcmu_gate("soc1_pll", NULL, PRCMU_PLLSOC1,
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
clk_register_clkdev(clk, "soc1_pll", NULL);
clk = clk_reg_prcmu_gate("ddr_pll", NULL, PRCMU_PLLDDR,
CLK_IS_ROOT|CLK_IGNORE_UNUSED);
clk_register_clkdev(clk, "ddr_pll", NULL);
clk = clk_register_fixed_rate(NULL, "rtc32k", NULL,
CLK_IS_ROOT|CLK_IGNORE_UNUSED,
32768);
clk_register_clkdev(clk, "clk32k", NULL);
clk_register_clkdev(clk, "apb_pclk", "rtc-pl031");
clk = clk_register_fixed_rate(NULL, "ulp38m4", NULL,
CLK_IS_ROOT|CLK_IGNORE_UNUSED,
38400000);
clk = clk_reg_prcmu_gate("uartclk", NULL, PRCMU_UARTCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "UART");
/* msp02clk needs a abx500 clk as parent. Handle by abx500 clk driver */
clk = clk_reg_prcmu_gate("msp02clk", "ab9540_sysclk12_b1",
PRCMU_MSP02CLK, 0);
clk_register_clkdev(clk, NULL, "MSP02");
clk = clk_reg_prcmu_gate("msp1clk", NULL, PRCMU_MSP1CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "MSP1");
clk = clk_reg_prcmu_gate("i2cclk", NULL, PRCMU_I2CCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "I2C");
clk = clk_reg_prcmu_gate("slimclk", NULL, PRCMU_SLIMCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "slim");
clk = clk_reg_prcmu_gate("per1clk", NULL, PRCMU_PER1CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH1");
clk = clk_reg_prcmu_gate("per2clk", NULL, PRCMU_PER2CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH2");
clk = clk_reg_prcmu_gate("per3clk", NULL, PRCMU_PER3CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH3");
clk = clk_reg_prcmu_gate("per5clk", NULL, PRCMU_PER5CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH5");
clk = clk_reg_prcmu_gate("per6clk", NULL, PRCMU_PER6CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH6");
clk = clk_reg_prcmu_gate("per7clk", NULL, PRCMU_PER7CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "PERIPH7");
clk = clk_reg_prcmu_scalable("lcdclk", NULL, PRCMU_LCDCLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "lcd");
clk_register_clkdev(clk, "lcd", "mcde");
clk = clk_reg_prcmu_opp_gate("bmlclk", NULL, PRCMU_BML8580CLK,
CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "bml");
clk = clk_reg_prcmu_scalable("hsitxclk", NULL, PRCMU_HSITXCLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk = clk_reg_prcmu_scalable("hsirxclk", NULL, PRCMU_HSIRXCLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk = clk_reg_prcmu_scalable("hdmiclk", NULL, PRCMU_HDMICLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "hdmi");
clk_register_clkdev(clk, "hdmi", "mcde");
clk = clk_reg_prcmu_gate("apeatclk", NULL, PRCMU_APEATCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "apeat");
clk = clk_reg_prcmu_gate("apetraceclk", NULL, PRCMU_APETRACECLK,
CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "apetrace");
clk = clk_reg_prcmu_gate("mcdeclk", NULL, PRCMU_MCDECLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "mcde");
clk_register_clkdev(clk, "mcde", "mcde");
clk_register_clkdev(clk, NULL, "dsilink.0");
clk_register_clkdev(clk, NULL, "dsilink.1");
clk_register_clkdev(clk, NULL, "dsilink.2");
clk = clk_reg_prcmu_opp_gate("ipi2cclk", NULL, PRCMU_IPI2CCLK,
CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "ipi2");
clk = clk_reg_prcmu_gate("dsialtclk", NULL, PRCMU_DSIALTCLK,
CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "dsialt");
clk = clk_reg_prcmu_gate("dmaclk", NULL, PRCMU_DMACLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "dma40.0");
clk = clk_reg_prcmu_gate("b2r2clk", NULL, PRCMU_B2R2CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "b2r2");
clk_register_clkdev(clk, NULL, "b2r2_core");
clk_register_clkdev(clk, NULL, "U8500-B2R2.0");
clk_register_clkdev(clk, NULL, "b2r2_1_core");
clk = clk_reg_prcmu_scalable("tvclk", NULL, PRCMU_TVCLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "tv");
clk_register_clkdev(clk, "tv", "mcde");
clk = clk_reg_prcmu_gate("sspclk", NULL, PRCMU_SSPCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "SSP");
clk = clk_reg_prcmu_gate("rngclk", NULL, PRCMU_RNGCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "rngclk");
clk = clk_reg_prcmu_gate("uiccclk", NULL, PRCMU_UICCCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "uicc");
clk = clk_reg_prcmu_gate("timclk", NULL, PRCMU_TIMCLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "mtu0");
clk_register_clkdev(clk, NULL, "mtu1");
clk = clk_reg_prcmu_opp_volt_scalable("sdmmcclk", NULL,
PRCMU_SDMMCCLK, 100000000,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdmmc");
clk = clk_reg_prcmu_opp_volt_scalable("sdmmchclk", NULL,
PRCMU_SDMMCHCLK, 400000000,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdmmchclk");
clk = clk_reg_prcmu_gate("hvaclk", NULL, PRCMU_HVACLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "hva");
clk = clk_reg_prcmu_gate("g1clk", NULL, PRCMU_G1CLK, CLK_IS_ROOT);
clk_register_clkdev(clk, NULL, "g1");
clk = clk_reg_prcmu_scalable("spare1clk", NULL, PRCMU_SPARE1CLK, 0,
CLK_IS_ROOT|CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsilcd", "mcde");
clk = clk_reg_prcmu_scalable("dsi_pll", "hdmiclk",
PRCMU_PLLDSI, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs2", "mcde");
clk_register_clkdev(clk, "hs_clk", "dsilink.2");
clk = clk_reg_prcmu_scalable("dsilcd_pll", "spare1clk",
PRCMU_PLLDSI_LCD, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsilcd_pll", "mcde");
clk = clk_reg_prcmu_scalable("dsi0clk", "dsi_pll",
PRCMU_DSI0CLK, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs0", "mcde");
clk = clk_reg_prcmu_scalable("dsi0lcdclk", "dsilcd_pll",
PRCMU_DSI0CLK_LCD, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs0", "mcde");
clk_register_clkdev(clk, "hs_clk", "dsilink.0");
clk = clk_reg_prcmu_scalable("dsi1clk", "dsi_pll",
PRCMU_DSI1CLK, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs1", "mcde");
clk = clk_reg_prcmu_scalable("dsi1lcdclk", "dsilcd_pll",
PRCMU_DSI1CLK_LCD, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "dsihs1", "mcde");
clk_register_clkdev(clk, "hs_clk", "dsilink.1");
clk = clk_reg_prcmu_scalable("dsi0escclk", "tvclk",
PRCMU_DSI0ESCCLK, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "lp_clk", "dsilink.0");
clk_register_clkdev(clk, "dsilp0", "mcde");
clk = clk_reg_prcmu_scalable("dsi1escclk", "tvclk",
PRCMU_DSI1ESCCLK, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "lp_clk", "dsilink.1");
clk_register_clkdev(clk, "dsilp1", "mcde");
clk = clk_reg_prcmu_scalable("dsi2escclk", "tvclk",
PRCMU_DSI2ESCCLK, 0, CLK_SET_RATE_GATE);
clk_register_clkdev(clk, "lp_clk", "dsilink.2");
clk_register_clkdev(clk, "dsilp2", "mcde");
clk = clk_reg_prcmu_scalable_rate("armss", NULL,
PRCMU_ARMSS, 0, CLK_IS_ROOT|CLK_IGNORE_UNUSED);
clk_register_clkdev(clk, "armss", NULL);
clk = clk_register_fixed_factor(NULL, "smp_twd", "armss",
CLK_IGNORE_UNUSED, 1, 2);
clk_register_clkdev(clk, NULL, "smp_twd");
/* PRCC P-clocks */
/* Peripheral 1 : PRCC P-clocks */
clk = clk_reg_prcc_pclk("p1_pclk0", "per1clk", clkrst1_base,
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "uart0");
clk = clk_reg_prcc_pclk("p1_pclk1", "per1clk", clkrst1_base,
BIT(1), 0);
clk_register_clkdev(clk, "apb_pclk", "uart1");
clk = clk_reg_prcc_pclk("p1_pclk2", "per1clk", clkrst1_base,
BIT(2), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.1");
clk = clk_reg_prcc_pclk("p1_pclk3", "per1clk", clkrst1_base,
BIT(3), 0);
clk_register_clkdev(clk, "apb_pclk", "msp0");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.0");
clk = clk_reg_prcc_pclk("p1_pclk4", "per1clk", clkrst1_base,
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "msp1");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.1");
clk = clk_reg_prcc_pclk("p1_pclk5", "per1clk", clkrst1_base,
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi0");
clk = clk_reg_prcc_pclk("p1_pclk6", "per1clk", clkrst1_base,
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.2");
clk = clk_reg_prcc_pclk("p1_pclk7", "per1clk", clkrst1_base,
BIT(7), 0);
clk_register_clkdev(clk, NULL, "spi3");
clk = clk_reg_prcc_pclk("p1_pclk8", "per1clk", clkrst1_base,
BIT(8), 0);
clk_register_clkdev(clk, "apb_pclk", "slimbus0");
clk = clk_reg_prcc_pclk("p1_pclk9", "per1clk", clkrst1_base,
BIT(9), 0);
clk_register_clkdev(clk, NULL, "gpio.0");
clk_register_clkdev(clk, NULL, "gpio.1");
clk_register_clkdev(clk, NULL, "gpioblock0");
clk_register_clkdev(clk, "apb_pclk", "ab85xx-codec.0");
clk = clk_reg_prcc_pclk("p1_pclk10", "per1clk", clkrst1_base,
BIT(10), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.4");
clk = clk_reg_prcc_pclk("p1_pclk11", "per1clk", clkrst1_base,
BIT(11), 0);
clk_register_clkdev(clk, "apb_pclk", "msp3");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.3");
/* Peripheral 2 : PRCC P-clocks */
clk = clk_reg_prcc_pclk("p2_pclk0", "per2clk", clkrst2_base,
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.3");
clk = clk_reg_prcc_pclk("p2_pclk1", "per2clk", clkrst2_base,
BIT(1), 0);
clk_register_clkdev(clk, NULL, "spi2");
clk = clk_reg_prcc_pclk("p2_pclk2", "per2clk", clkrst2_base,
BIT(2), 0);
clk_register_clkdev(clk, NULL, "spi1");
clk = clk_reg_prcc_pclk("p2_pclk3", "per2clk", clkrst2_base,
BIT(3), 0);
clk_register_clkdev(clk, NULL, "pwl");
clk = clk_reg_prcc_pclk("p2_pclk4", "per2clk", clkrst2_base,
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi4");
clk = clk_reg_prcc_pclk("p2_pclk5", "per2clk", clkrst2_base,
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "msp2");
clk_register_clkdev(clk, "apb_pclk", "dbx5x0-msp-i2s.2");
clk = clk_reg_prcc_pclk("p2_pclk6", "per2clk", clkrst2_base,
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi1");
clk = clk_reg_prcc_pclk("p2_pclk7", "per2clk", clkrst2_base,
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi3");
clk = clk_reg_prcc_pclk("p2_pclk8", "per2clk", clkrst2_base,
BIT(8), 0);
clk_register_clkdev(clk, NULL, "spi0");
clk = clk_reg_prcc_pclk("p2_pclk9", "per2clk", clkrst2_base,
BIT(9), 0);
clk_register_clkdev(clk, "hsir_hclk", "ste_hsi.0");
clk = clk_reg_prcc_pclk("p2_pclk10", "per2clk", clkrst2_base,
BIT(10), 0);
clk_register_clkdev(clk, "hsit_hclk", "ste_hsi.0");
clk = clk_reg_prcc_pclk("p2_pclk11", "per2clk", clkrst2_base,
BIT(11), 0);
clk_register_clkdev(clk, NULL, "gpio.6");
clk_register_clkdev(clk, NULL, "gpio.7");
clk_register_clkdev(clk, NULL, "gpioblock1");
clk = clk_reg_prcc_pclk("p2_pclk12", "per2clk", clkrst2_base,
BIT(12), 0);
clk_register_clkdev(clk, "msp4-pclk", "ab85xx-codec.0");
/* Peripheral 3 : PRCC P-clocks */
clk = clk_reg_prcc_pclk("p3_pclk0", "per3clk", clkrst3_base,
BIT(0), 0);
clk_register_clkdev(clk, NULL, "fsmc");
clk = clk_reg_prcc_pclk("p3_pclk1", "per3clk", clkrst3_base,
BIT(1), 0);
clk_register_clkdev(clk, "apb_pclk", "ssp0");
clk = clk_reg_prcc_pclk("p3_pclk2", "per3clk", clkrst3_base,
BIT(2), 0);
clk_register_clkdev(clk, "apb_pclk", "ssp1");
clk = clk_reg_prcc_pclk("p3_pclk3", "per3clk", clkrst3_base,
BIT(3), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.0");
clk = clk_reg_prcc_pclk("p3_pclk4", "per3clk", clkrst3_base,
BIT(4), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi2");
clk = clk_reg_prcc_pclk("p3_pclk5", "per3clk", clkrst3_base,
BIT(5), 0);
clk_register_clkdev(clk, "apb_pclk", "ske");
clk_register_clkdev(clk, "apb_pclk", "nmk-ske-keypad");
clk = clk_reg_prcc_pclk("p3_pclk6", "per3clk", clkrst3_base,
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "uart2");
clk = clk_reg_prcc_pclk("p3_pclk7", "per3clk", clkrst3_base,
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "sdi5");
clk = clk_reg_prcc_pclk("p3_pclk8", "per3clk", clkrst3_base,
BIT(8), 0);
clk_register_clkdev(clk, NULL, "gpio.2");
clk_register_clkdev(clk, NULL, "gpio.3");
clk_register_clkdev(clk, NULL, "gpio.4");
clk_register_clkdev(clk, NULL, "gpio.5");
clk_register_clkdev(clk, NULL, "gpioblock2");
clk = clk_reg_prcc_pclk("p3_pclk9", "per3clk", clkrst3_base,
BIT(9), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.5");
clk = clk_reg_prcc_pclk("p3_pclk10", "per3clk", clkrst3_base,
BIT(10), 0);
clk_register_clkdev(clk, "apb_pclk", "nmk-i2c.6");
clk = clk_reg_prcc_pclk("p3_pclk11", "per3clk", clkrst3_base,
BIT(11), 0);
clk_register_clkdev(clk, "apb_pclk", "uart3");
clk = clk_reg_prcc_pclk("p3_pclk12", "per3clk", clkrst3_base,
BIT(12), 0);
clk_register_clkdev(clk, "apb_pclk", "uart4");
/* Peripheral 5 : PRCC P-clocks */
clk = clk_reg_prcc_pclk("p5_pclk0", "per5clk", clkrst5_base,
BIT(0), 0);
clk_register_clkdev(clk, "usb", "musb-ux500.0");
clk_register_clkdev(clk, "usbclk", "ab-iddet.0");
clk = clk_reg_prcc_pclk("p5_pclk1", "per5clk", clkrst5_base,
BIT(1), 0);
clk_register_clkdev(clk, NULL, "gpio.8");
clk_register_clkdev(clk, NULL, "gpioblock3");
/* Peripheral 6 : PRCC P-clocks */
clk = clk_reg_prcc_pclk("p6_pclk0", "per6clk", clkrst6_base,
BIT(0), 0);
clk_register_clkdev(clk, "apb_pclk", "rng");
clk = clk_reg_prcc_pclk("p6_pclk1", "per6clk", clkrst6_base,
BIT(1), 0);
clk_register_clkdev(clk, NULL, "cryp0");
clk_register_clkdev(clk, NULL, "cryp1");
clk = clk_reg_prcc_pclk("p6_pclk2", "per6clk", clkrst6_base,
BIT(2), 0);
clk_register_clkdev(clk, NULL, "hash0");
clk = clk_reg_prcc_pclk("p6_pclk3", "per6clk", clkrst6_base,
BIT(3), 0);
clk_register_clkdev(clk, NULL, "pka");
clk = clk_reg_prcc_pclk("p6_pclk4", "per6clk", clkrst6_base,
BIT(4), 0);
clk_register_clkdev(clk, NULL, "db8540-hash1");
clk = clk_reg_prcc_pclk("p6_pclk5", "per6clk", clkrst6_base,
BIT(5), 0);
clk_register_clkdev(clk, NULL, "cfgreg");
clk = clk_reg_prcc_pclk("p6_pclk6", "per6clk", clkrst6_base,
BIT(6), 0);
clk_register_clkdev(clk, "apb_pclk", "mtu0");
clk = clk_reg_prcc_pclk("p6_pclk7", "per6clk", clkrst6_base,
BIT(7), 0);
clk_register_clkdev(clk, "apb_pclk", "mtu1");
/*
* PRCC K-clocks ==> see table PRCC_PCKEN/PRCC_KCKEN
* This differs from the internal implementation:
* We don't use the PERPIH[n| clock as parent, since those _should_
* only be used as parents for the P-clocks.
* TODO: "parentjoin" with corresponding P-clocks for all K-clocks.
*/
/* Peripheral 1 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p1_uart0_kclk", "uartclk",
clkrst1_base, BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart0");
clk = clk_reg_prcc_kclk("p1_uart1_kclk", "uartclk",
clkrst1_base, BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart1");
clk = clk_reg_prcc_kclk("p1_i2c1_kclk", "i2cclk",
clkrst1_base, BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.1");
clk = clk_reg_prcc_kclk("p1_msp0_kclk", "msp02clk",
clkrst1_base, BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp0");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.0");
clk = clk_reg_prcc_kclk("p1_msp1_kclk", "msp1clk",
clkrst1_base, BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp1");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.1");
clk = clk_reg_prcc_kclk("p1_sdi0_kclk", "sdmmchclk",
clkrst1_base, BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi0");
clk = clk_reg_prcc_kclk("p1_i2c2_kclk", "i2cclk",
clkrst1_base, BIT(6), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.2");
clk = clk_reg_prcc_kclk("p1_slimbus0_kclk", "slimclk",
clkrst1_base, BIT(8), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "slimbus0");
clk = clk_reg_prcc_kclk("p1_i2c4_kclk", "i2cclk",
clkrst1_base, BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.4");
clk = clk_reg_prcc_kclk("p1_msp3_kclk", "msp1clk",
clkrst1_base, BIT(10), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp3");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.3");
/* Peripheral 2 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p2_i2c3_kclk", "i2cclk",
clkrst2_base, BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.3");
clk = clk_reg_prcc_kclk("p2_pwl_kclk", "rtc32k",
clkrst2_base, BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "pwl");
clk = clk_reg_prcc_kclk("p2_sdi4_kclk", "sdmmchclk",
clkrst2_base, BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi4");
clk = clk_reg_prcc_kclk("p2_msp2_kclk", "msp02clk",
clkrst2_base, BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp2");
clk_register_clkdev(clk, NULL, "dbx5x0-msp-i2s.2");
clk = clk_reg_prcc_kclk("p2_sdi1_kclk", "sdmmchclk",
clkrst2_base, BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi1");
clk = clk_reg_prcc_kclk("p2_sdi3_kclk", "sdmmcclk",
clkrst2_base, BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi3");
clk = clk_reg_prcc_kclk("p2_ssirx_kclk", "hsirxclk",
clkrst2_base, BIT(6),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
clk_register_clkdev(clk, "hsir_hsirxclk", "ste_hsi.0");
clk = clk_reg_prcc_kclk("p2_ssitx_kclk", "hsitxclk",
clkrst2_base, BIT(7),
CLK_SET_RATE_GATE|CLK_SET_RATE_PARENT);
clk_register_clkdev(clk, "hsit_hsitxclk", "ste_hsi.0");
/* Should only be 9540, but might be added for 85xx as well */
clk = clk_reg_prcc_kclk("p2_msp4_kclk", "msp02clk",
clkrst2_base, BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "msp4");
clk_register_clkdev(clk, "msp4", "ab85xx-codec.0");
/* Peripheral 3 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p3_ssp0_kclk", "sspclk",
clkrst3_base, BIT(1), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ssp0");
clk = clk_reg_prcc_kclk("p3_ssp1_kclk", "sspclk",
clkrst3_base, BIT(2), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ssp1");
clk = clk_reg_prcc_kclk("p3_i2c0_kclk", "i2cclk",
clkrst3_base, BIT(3), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.0");
clk = clk_reg_prcc_kclk("p3_sdi2_kclk", "sdmmchclk",
clkrst3_base, BIT(4), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi2");
clk = clk_reg_prcc_kclk("p3_ske_kclk", "rtc32k",
clkrst3_base, BIT(5), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "ske");
clk_register_clkdev(clk, NULL, "nmk-ske-keypad");
clk = clk_reg_prcc_kclk("p3_uart2_kclk", "uartclk",
clkrst3_base, BIT(6), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart2");
clk = clk_reg_prcc_kclk("p3_sdi5_kclk", "sdmmcclk",
clkrst3_base, BIT(7), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "sdi5");
clk = clk_reg_prcc_kclk("p3_i2c5_kclk", "i2cclk",
clkrst3_base, BIT(8), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.5");
clk = clk_reg_prcc_kclk("p3_i2c6_kclk", "i2cclk",
clkrst3_base, BIT(9), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "nmk-i2c.6");
clk = clk_reg_prcc_kclk("p3_uart3_kclk", "uartclk",
clkrst3_base, BIT(10), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart3");
clk = clk_reg_prcc_kclk("p3_uart4_kclk", "uartclk",
clkrst3_base, BIT(11), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "uart4");
/* Peripheral 6 : PRCC K-clocks */
clk = clk_reg_prcc_kclk("p6_rng_kclk", "rngclk",
clkrst6_base, BIT(0), CLK_SET_RATE_GATE);
clk_register_clkdev(clk, NULL, "rng");
}

View File

@ -12,10 +12,10 @@
#include <linux/clk-provider.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/platform_data/clk-ux500.h>
#include "clk.h"
void u9540_clk_init(void)
void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
u32 clkrst5_base, u32 clkrst6_base)
{
/* register clocks here */
}

View File

@ -107,7 +107,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
osc->func = vexpress_config_func_get_by_node(node);
if (!osc->func) {
pr_err("Failed to obtain config func for node '%s'!\n",
node->name);
node->full_name);
goto error;
}
@ -119,7 +119,7 @@ void __init vexpress_osc_of_setup(struct device_node *node)
of_property_read_string(node, "clock-output-names", &init.name);
if (!init.name)
init.name = node->name;
init.name = node->full_name;
init.ops = &vexpress_osc_ops;
init.flags = CLK_IS_ROOT;

View File

@ -480,6 +480,7 @@ struct clk_mgt clk_mgt[PRCMU_NUM_REG_CLOCKS] = {
CLK_MGT_ENTRY(PER6CLK, PLL_DIV, true),
CLK_MGT_ENTRY(PER7CLK, PLL_DIV, true),
CLK_MGT_ENTRY(LCDCLK, PLL_FIX, true),
CLK_MGT_ENTRY(BML8580CLK, PLL_DIV, true),
CLK_MGT_ENTRY(BMLCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSITXCLK, PLL_DIV, true),
CLK_MGT_ENTRY(HSIRXCLK, PLL_DIV, true),

View File

@ -32,6 +32,7 @@
#define PRCM_PER7CLK_MGT (0x040)
#define PRCM_LCDCLK_MGT (0x044)
#define PRCM_BMLCLK_MGT (0x04C)
#define PRCM_BML8580CLK_MGT (0x108)
#define PRCM_HSITXCLK_MGT (0x050)
#define PRCM_HSIRXCLK_MGT (0x054)
#define PRCM_HDMICLK_MGT (0x058)

View File

@ -210,6 +210,10 @@ void of_fixed_clk_setup(struct device_node *np);
* CLK_GATE_SET_TO_DISABLE - by default this clock sets the bit at bit_idx to
* enable the clock. Setting this flag does the opposite: setting the bit
* disable the clock and clearing it enables the clock
* CLK_GATE_HIWORD_MASK - The gate settings are only in lower 16-bit
* of this register, and mask of gate bits are in higher 16-bit of this
* register. While setting the gate bits, higher 16-bit should also be
* updated to indicate changing gate bits.
*/
struct clk_gate {
struct clk_hw hw;
@ -220,6 +224,7 @@ struct clk_gate {
};
#define CLK_GATE_SET_TO_DISABLE BIT(0)
#define CLK_GATE_HIWORD_MASK BIT(1)
extern const struct clk_ops clk_gate_ops;
struct clk *clk_register_gate(struct device *dev, const char *name,
@ -257,6 +262,10 @@ struct clk_div_table {
* Some hardware implementations gracefully handle this case and allow a
* zero divisor by not modifying their input clock
* (divide by one / bypass).
* CLK_DIVIDER_HIWORD_MASK - The divider settings are only in lower 16-bit
* of this register, and mask of divider bits are in higher 16-bit of this
* register. While setting the divider bits, higher 16-bit should also be
* updated to indicate changing divider bits.
*/
struct clk_divider {
struct clk_hw hw;
@ -271,6 +280,7 @@ struct clk_divider {
#define CLK_DIVIDER_ONE_BASED BIT(0)
#define CLK_DIVIDER_POWER_OF_TWO BIT(1)
#define CLK_DIVIDER_ALLOW_ZERO BIT(2)
#define CLK_DIVIDER_HIWORD_MASK BIT(3)
extern const struct clk_ops clk_divider_ops;
struct clk *clk_register_divider(struct device *dev, const char *name,
@ -299,6 +309,10 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
* Flags:
* CLK_MUX_INDEX_ONE - register index starts at 1, not 0
* CLK_MUX_INDEX_BIT - register index is a single bit (power of two)
* CLK_MUX_HIWORD_MASK - The mux settings are only in lower 16-bit of this
* register, and mask of mux bits are in higher 16-bit of this register.
* While setting the mux bits, higher 16-bit should also be updated to
* indicate changing mux bits.
*/
struct clk_mux {
struct clk_hw hw;
@ -312,6 +326,7 @@ struct clk_mux {
#define CLK_MUX_INDEX_ONE BIT(0)
#define CLK_MUX_INDEX_BIT BIT(1)
#define CLK_MUX_HIWORD_MASK BIT(2)
extern const struct clk_ops clk_mux_ops;
@ -423,6 +438,17 @@ struct of_device_id;
typedef void (*of_clk_init_cb_t)(struct device_node *);
struct clk_onecell_data {
struct clk **clks;
unsigned int clk_num;
};
#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 };
#ifdef CONFIG_OF
int of_clk_add_provider(struct device_node *np,
struct clk *(*clk_src_get)(struct of_phandle_args *args,
void *data),
@ -430,19 +456,39 @@ int of_clk_add_provider(struct device_node *np,
void of_clk_del_provider(struct device_node *np);
struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec,
void *data);
struct clk_onecell_data {
struct clk **clks;
unsigned int clk_num;
};
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 };
#else /* !CONFIG_OF */
static inline int of_clk_add_provider(struct device_node *np,
struct clk *(*clk_src_get)(struct of_phandle_args *args,
void *data),
void *data)
{
return 0;
}
#define of_clk_del_provider(np) \
{ while (0); }
static inline struct clk *of_clk_src_simple_get(
struct of_phandle_args *clkspec, void *data)
{
return ERR_PTR(-ENOENT);
}
static inline struct clk *of_clk_src_onecell_get(
struct of_phandle_args *clkspec, void *data)
{
return ERR_PTR(-ENOENT);
}
static inline const char *of_clk_get_parent_name(struct device_node *np,
int index)
{
return NULL;
}
#define of_clk_init(matches) \
{ while (0); }
#endif /* CONFIG_OF */
#endif /* CONFIG_COMMON_CLK */
#endif /* CLK_PROVIDER_H */

View File

@ -120,9 +120,13 @@ static inline void tegra_cpu_clock_resume(void)
}
#endif
#ifdef CONFIG_ARCH_TEGRA
void tegra_periph_reset_deassert(struct clk *c);
void tegra_periph_reset_assert(struct clk *c);
void tegra_clocks_init(void);
#else
static inline void tegra_periph_reset_deassert(struct clk *c) {}
static inline void tegra_periph_reset_assert(struct clk *c) {}
#endif
void tegra_clocks_apply_init_table(void);
#endif /* __LINUX_CLK_TEGRA_H_ */

View File

@ -278,8 +278,8 @@ struct ab8500_sysctrl_platform_data {
#define AB9540_SYSCLK12CONFCTRL_PLL26TO38ENA BIT(0)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12USBMUXSEL BIT(1)
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_MASK 0x0C
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL_SHIFT 2
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL0 BIT(2)
#define AB9540_SYSCLK12CONFCTRL_INT384MHZMUXSEL1 BIT(3)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12BUFMUX BIT(4)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK12PLLMUX BIT(5)
#define AB9540_SYSCLK12CONFCTRL_SYSCLK2MUXVALID BIT(6)

View File

@ -134,6 +134,11 @@ enum prcmu_clock {
PRCMU_SIACLK,
PRCMU_SVACLK,
PRCMU_ACLK,
PRCMU_HVACLK, /* Ux540 only */
PRCMU_G1CLK, /* Ux540 only */
PRCMU_SDMMCHCLK,
PRCMU_CAMCLK,
PRCMU_BML8580CLK,
PRCMU_NUM_REG_CLOCKS,
PRCMU_SYSCLK = PRCMU_NUM_REG_CLOCKS,
PRCMU_CDCLK,
@ -148,6 +153,13 @@ enum prcmu_clock {
PRCMU_DSI0ESCCLK,
PRCMU_DSI1ESCCLK,
PRCMU_DSI2ESCCLK,
/* LCD DSI PLL - Ux540 only */
PRCMU_PLLDSI_LCD,
PRCMU_DSI0CLK_LCD,
PRCMU_DSI1CLK_LCD,
PRCMU_DSI0ESCCLK_LCD,
PRCMU_DSI1ESCCLK_LCD,
PRCMU_DSI2ESCCLK_LCD,
};
/**

View File

@ -12,7 +12,9 @@
void u8500_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
u32 clkrst5_base, u32 clkrst6_base);
void u9540_clk_init(void);
void u8540_clk_init(void);
void u9540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
u32 clkrst5_base, u32 clkrst6_base);
void u8540_clk_init(u32 clkrst1_base, u32 clkrst2_base, u32 clkrst3_base,
u32 clkrst5_base, u32 clkrst6_base);
#endif /* __CLK_UX500_H */

View File

@ -78,6 +78,23 @@ enum si5351_drive_strength {
SI5351_DRIVE_8MA = 8,
};
/**
* enum si5351_disable_state - Si5351 clock output disable state
* @SI5351_DISABLE_DEFAULT: default, do not change eeprom config
* @SI5351_DISABLE_LOW: CLKx is set to a LOW state when disabled
* @SI5351_DISABLE_HIGH: CLKx is set to a HIGH state when disabled
* @SI5351_DISABLE_FLOATING: CLKx is set to a FLOATING state when
* disabled
* @SI5351_DISABLE_NEVER: CLKx is NEVER disabled
*/
enum si5351_disable_state {
SI5351_DISABLE_DEFAULT = 0,
SI5351_DISABLE_LOW,
SI5351_DISABLE_HIGH,
SI5351_DISABLE_FLOATING,
SI5351_DISABLE_NEVER,
};
/**
* struct si5351_clkout_config - Si5351 clock output configuration
* @clkout: clkout number
@ -91,6 +108,7 @@ struct si5351_clkout_config {
enum si5351_multisynth_src multisynth_src;
enum si5351_clkout_src clkout_src;
enum si5351_drive_strength drive;
enum si5351_disable_state disable_state;
bool pll_master;
unsigned long rate;
};