The common clock framework changes for 3.10 include many fixes for
existing platforms, as well as adoption of the framework by new platforms and devices. Some long-needed fixes to the core framework are here as well as new features such as improved initialization of clocks from DT as well as framework reentrancy for nested clock operations. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.11 (GNU/Linux) iQIcBAABAgAGBQJRfqtLAAoJEDqPOy9afJhJsxwP/RLvfeeMIU3804ahVNK2C59h ehJ06ZP+b0u0A7+YSC7CX1pHXIFW+UoZgYLJiLdV2kEdpOIKMELZyUcEVB97u1Of TVlsmHfTLv2zVAq/LYRVSKFYeMUd/6RRoq7Cm6hoj638IVeXG7C+8pei2aVZe++t 1ENmb4UGFJ7NLfpE5zQ3fEuIfHfuWA8Od6SmPaV/YG5Io8HgkDGF3/tCJURJGII6 xLN2Rh8qbFktJLVvKe6yLyvUEZiWh8A6HNPyNiFYYGX11wU76zK2wMN3BW6Nn/kW 3PubzISoKRaoCZvuVK+CoLWnhFl2LteFVVmL1TBc/jxJe6q+rLX33sXl1q9K+SLt POnHf/7nDyO3zbZWgfRR1r3FdeZqdLYw8HVsLcOKFcv9n1UligzuUNml5PklKwNh BDMmSo5ytS1QPV1e9ZtVrk6IyvDyrenwfDW1Mw43ST6D23FVrivywB4X9ur6WljI d1/CBvQXQZ11Hd4OAvqRL8QYFJvc5WlERjSd1j6I6XS6xioKOTKMkUC/KpRcCid9 avA6mJ5k/a1jTojvh2wl37paI//OzY0VDlxRSeMZIu9Dsn29DnPlE5CLg535Ovu+ mn9OtLFEDNnlgWCMQYUehGd7ITgtwrB/fxxNeBbMYjDz4AIirR2BIvMR7I8CMTQz M0rHu8NpwKH6eqC6kAup =+LO3 -----END PGP SIGNATURE----- Merge tag 'clk-for-linus-3.10' of git://git.linaro.org/people/mturquette/linux Pull clock framework update from Michael Turquette: "The common clock framework changes for 3.10 include many fixes for existing platforms, as well as adoption of the framework by new platforms and devices. Some long-needed fixes to the core framework are here as well as new features such as improved initialization of clocks from DT as well as framework reentrancy for nested clock operations." * tag 'clk-for-linus-3.10' of git://git.linaro.org/people/mturquette/linux: (44 commits) clk: add clk_ignore_unused option to keep boot clocks on clk: ux500: fix mismatched types clk: vexpress: Add separate SP810 driver clk: si5351: make clk-si5351 depend on CONFIG_OF clk: export __clk_get_flags for modular clock providers clk: vt8500: Missing breaks in vtwm_pll_round_rate/_set_rate. clk: sunxi: Unify oscillator clock clk: composite: allow fixed rates & fixed dividers clk: composite: rename 'div' references to 'rate' clk: add si5351 i2c common clock driver clk: add device tree fixed-factor-clock binding support clk: Properly handle notifier return values clk: ux500: abx500: Define clock tree for ab850x clk: ux500: Add support for sysctrl clocks clk: mvebu: Fix valid value range checking for cpu_freq_select clk: Fixup locking issues for clk_set_parent clk: Fixup errorhandling for clk_set_parent clk: Restructure code for __clk_reparent clk: sunxi: drop an unnecesary kmalloc clk: sunxi: drop CLK_IGNORE_UNUSED ...
This commit is contained in:
commit
362ed48dee
48 changed files with 4518 additions and 304 deletions
56
Documentation/arm/sunxi/clocks.txt
Normal file
56
Documentation/arm/sunxi/clocks.txt
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
Frequently asked questions about the sunxi clock system
|
||||
=======================================================
|
||||
|
||||
This document contains useful bits of information that people tend to ask
|
||||
about the sunxi clock system, as well as accompanying ASCII art when adequate.
|
||||
|
||||
Q: Why is the main 24MHz oscillator gatable? Wouldn't that break the
|
||||
system?
|
||||
|
||||
A: The 24MHz oscillator allows gating to save power. Indeed, if gated
|
||||
carelessly the system would stop functioning, but with the right
|
||||
steps, one can gate it and keep the system running. Consider this
|
||||
simplified suspend example:
|
||||
|
||||
While the system is operational, you would see something like
|
||||
|
||||
24MHz 32kHz
|
||||
|
|
||||
PLL1
|
||||
\
|
||||
\_ CPU Mux
|
||||
|
|
||||
[CPU]
|
||||
|
||||
When you are about to suspend, you switch the CPU Mux to the 32kHz
|
||||
oscillator:
|
||||
|
||||
24Mhz 32kHz
|
||||
| |
|
||||
PLL1 |
|
||||
/
|
||||
CPU Mux _/
|
||||
|
|
||||
[CPU]
|
||||
|
||||
Finally you can gate the main oscillator
|
||||
|
||||
32kHz
|
||||
|
|
||||
|
|
||||
/
|
||||
CPU Mux _/
|
||||
|
|
||||
[CPU]
|
||||
|
||||
Q: Were can I learn more about the sunxi clocks?
|
||||
|
||||
A: The linux-sunxi wiki contains a page documenting the clock registers,
|
||||
you can find it at
|
||||
|
||||
http://linux-sunxi.org/A10/CCM
|
||||
|
||||
The authoritative source for information at this time is the ccmu driver
|
||||
released by Allwinner, you can find it at
|
||||
|
||||
https://github.com/linux-sunxi/linux-sunxi/tree/sunxi-3.0/arch/arm/mach-sun4i/clock/ccmu
|
||||
|
|
@ -174,9 +174,9 @@ int clk_foo_enable(struct clk_hw *hw)
|
|||
};
|
||||
|
||||
Below is a matrix detailing which clk_ops are mandatory based upon the
|
||||
hardware capbilities of that clock. A cell marked as "y" means
|
||||
hardware capabilities of that clock. A cell marked as "y" means
|
||||
mandatory, a cell marked as "n" implies that either including that
|
||||
callback is invalid or otherwise uneccesary. Empty cells are either
|
||||
callback is invalid or otherwise unnecessary. Empty cells are either
|
||||
optional or must be evaluated on a case-by-case basis.
|
||||
|
||||
clock hardware characteristics
|
||||
|
|
@ -231,3 +231,14 @@ To better enforce this policy, always follow this simple rule: any
|
|||
statically initialized clock data MUST be defined in a separate file
|
||||
from the logic that implements its ops. Basically separate the logic
|
||||
from the data and all is well.
|
||||
|
||||
Part 6 - Disabling clock gating of unused clocks
|
||||
|
||||
Sometimes during development it can be useful to be able to bypass the
|
||||
default disabling of unused clocks. For example, if drivers aren't enabling
|
||||
clocks properly but rely on them being on from the bootloader, bypassing
|
||||
the disabling means that the driver will remain functional while the issues
|
||||
are sorted out.
|
||||
|
||||
To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
|
||||
kernel.
|
||||
|
|
|
|||
22
Documentation/devicetree/bindings/clock/axi-clkgen.txt
Normal file
22
Documentation/devicetree/bindings/clock/axi-clkgen.txt
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
Binding for the axi-clkgen clock generator
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "adi,axi-clkgen".
|
||||
- #clock-cells : from common clock binding; Should always be set to 0.
|
||||
- reg : Address and length of the axi-clkgen register set.
|
||||
- clocks : Phandle and clock specifier for the parent clock.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
clock@0xff000000 {
|
||||
compatible = "adi,axi-clkgen";
|
||||
#clock-cells = <0>;
|
||||
reg = <0xff000000 0x1000>;
|
||||
clocks = <&osc 1>;
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
Binding for simple fixed factor rate clock sources.
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be "fixed-factor-clock".
|
||||
- #clock-cells : from common clock binding; shall be set to 0.
|
||||
- clock-div: fixed divider.
|
||||
- clock-mult: fixed multiplier.
|
||||
- clocks: parent clock.
|
||||
|
||||
Optional properties:
|
||||
- clock-output-names : From common clock binding.
|
||||
|
||||
Example:
|
||||
clock {
|
||||
compatible = "fixed-factor-clock";
|
||||
clocks = <&parentclk>;
|
||||
#clock-cells = <0>;
|
||||
div = <2>;
|
||||
mult = <1>;
|
||||
};
|
||||
114
Documentation/devicetree/bindings/clock/silabs,si5351.txt
Normal file
114
Documentation/devicetree/bindings/clock/silabs,si5351.txt
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
Binding for Silicon Labs Si5351a/b/c programmable i2c clock generator.
|
||||
|
||||
Reference
|
||||
[1] Si5351A/B/C Data Sheet
|
||||
http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351.pdf
|
||||
|
||||
The Si5351a/b/c are programmable i2c clock generators with upto 8 output
|
||||
clocks. Si5351a also has a reduced pin-count package (MSOP10) where only
|
||||
3 output clocks are accessible. The internal structure of the clock
|
||||
generators can be found in [1].
|
||||
|
||||
==I2C device node==
|
||||
|
||||
Required properties:
|
||||
- compatible: shall be one of "silabs,si5351{a,a-msop,b,c}".
|
||||
- reg: i2c device address, shall be 0x60 or 0x61.
|
||||
- #clock-cells: from common clock binding; shall be set to 1.
|
||||
- clocks: from common clock binding; list of parent clock
|
||||
handles, shall be xtal reference clock or xtal and clkin for
|
||||
si5351c only.
|
||||
- #address-cells: shall be set to 1.
|
||||
- #size-cells: shall be set to 0.
|
||||
|
||||
Optional properties:
|
||||
- silabs,pll-source: pair of (number, source) for each pll. Allows
|
||||
to overwrite clock source of pll A (number=0) or B (number=1).
|
||||
|
||||
==Child nodes==
|
||||
|
||||
Each of the clock outputs can be overwritten individually by
|
||||
using a child node to the I2C device node. If a child node for a clock
|
||||
output is not set, the eeprom configuration is not overwritten.
|
||||
|
||||
Required child node properties:
|
||||
- reg: number of clock output.
|
||||
|
||||
Optional child node properties:
|
||||
- silabs,clock-source: source clock of the output divider stage N, shall be
|
||||
0 = multisynth N
|
||||
1 = multisynth 0 for output clocks 0-3, else multisynth4
|
||||
2 = xtal
|
||||
3 = clkin (si5351c only)
|
||||
- silabs,drive-strength: output drive strength in mA, shall be one of {2,4,6,8}.
|
||||
- silabs,multisynth-source: source pll A(0) or B(1) of corresponding multisynth
|
||||
divider.
|
||||
- silabs,pll-master: boolean, multisynth can change pll frequency.
|
||||
|
||||
==Example==
|
||||
|
||||
/* 25MHz reference crystal */
|
||||
ref25: ref25M {
|
||||
compatible = "fixed-clock";
|
||||
#clock-cells = <0>;
|
||||
clock-frequency = <25000000>;
|
||||
};
|
||||
|
||||
i2c-master-node {
|
||||
|
||||
/* Si5351a msop10 i2c clock generator */
|
||||
si5351a: clock-generator@60 {
|
||||
compatible = "silabs,si5351a-msop";
|
||||
reg = <0x60>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
#clock-cells = <1>;
|
||||
|
||||
/* connect xtal input to 25MHz reference */
|
||||
clocks = <&ref25>;
|
||||
|
||||
/* connect xtal input as source of pll0 and pll1 */
|
||||
silabs,pll-source = <0 0>, <1 0>;
|
||||
|
||||
/*
|
||||
* overwrite clkout0 configuration with:
|
||||
* - 8mA output drive strength
|
||||
* - pll0 as clock source of multisynth0
|
||||
* - multisynth0 as clock source of output divider
|
||||
* - multisynth0 can change pll0
|
||||
* - set initial clock frequency of 74.25MHz
|
||||
*/
|
||||
clkout0 {
|
||||
reg = <0>;
|
||||
silabs,drive-strength = <8>;
|
||||
silabs,multisynth-source = <0>;
|
||||
silabs,clock-source = <0>;
|
||||
silabs,pll-master;
|
||||
clock-frequency = <74250000>;
|
||||
};
|
||||
|
||||
/*
|
||||
* overwrite clkout1 configuration with:
|
||||
* - 4mA output drive strength
|
||||
* - pll1 as clock source of multisynth1
|
||||
* - multisynth1 as clock source of output divider
|
||||
* - multisynth1 can change pll1
|
||||
*/
|
||||
clkout1 {
|
||||
reg = <1>;
|
||||
silabs,drive-strength = <4>;
|
||||
silabs,multisynth-source = <1>;
|
||||
silabs,clock-source = <0>;
|
||||
pll-master;
|
||||
};
|
||||
|
||||
/*
|
||||
* overwrite clkout2 configuration with:
|
||||
* - xtal as clock source of output divider
|
||||
*/
|
||||
clkout2 {
|
||||
reg = <2>;
|
||||
silabs,clock-source = <2>;
|
||||
};
|
||||
};
|
||||
};
|
||||
151
Documentation/devicetree/bindings/clock/sunxi.txt
Normal file
151
Documentation/devicetree/bindings/clock/sunxi.txt
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
Device Tree Clock bindings for arch-sunxi
|
||||
|
||||
This binding uses the common clock binding[1].
|
||||
|
||||
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
|
||||
|
||||
Required properties:
|
||||
- compatible : shall be one of the following:
|
||||
"allwinner,sun4i-osc-clk" - for a gatable oscillator
|
||||
"allwinner,sun4i-pll1-clk" - for the main PLL clock
|
||||
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
|
||||
"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-apb0-clk" - for the APB0 clock
|
||||
"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates
|
||||
"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
|
||||
|
||||
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
|
||||
|
||||
Additionally, "allwinner,sun4i-*-gates-clk" clocks require:
|
||||
- clock-output-names : the corresponding gate names that the clock controls
|
||||
|
||||
For example:
|
||||
|
||||
osc24M: osc24M@01c20050 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-osc-clk";
|
||||
reg = <0x01c20050 0x4>;
|
||||
clocks = <&osc24M_fixed>;
|
||||
};
|
||||
|
||||
pll1: pll1@01c20000 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-pll1-clk";
|
||||
reg = <0x01c20000 0x4>;
|
||||
clocks = <&osc24M>;
|
||||
};
|
||||
|
||||
cpu: cpu@01c20054 {
|
||||
#clock-cells = <0>;
|
||||
compatible = "allwinner,sun4i-cpu-clk";
|
||||
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
|
||||
|
|
@ -49,6 +49,7 @@ samsung Samsung Semiconductor
|
|||
sbs Smart Battery System
|
||||
schindler Schindler
|
||||
sil Silicon Image
|
||||
silabs Silicon Laboratories
|
||||
simtek
|
||||
sirf SiRF Technology, Inc.
|
||||
snps Synopsys, Inc.
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ parameter is applicable:
|
|||
AVR32 AVR32 architecture is enabled.
|
||||
AX25 Appropriate AX.25 support is enabled.
|
||||
BLACKFIN Blackfin architecture is enabled.
|
||||
CLK Common clock infrastructure is enabled.
|
||||
DRM Direct Rendering Management support is enabled.
|
||||
DYNAMIC_DEBUG Build in debug messages and enable them at runtime
|
||||
EDD BIOS Enhanced Disk Drive Services (EDD) is enabled
|
||||
|
|
@ -472,6 +473,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||
|
||||
cio_ignore= [S390]
|
||||
See Documentation/s390/CommonIO for details.
|
||||
clk_ignore_unused
|
||||
[CLK]
|
||||
Keep all clocks already enabled by bootloader on,
|
||||
even if no driver has claimed them. This is useful
|
||||
for debug and development, but should not be
|
||||
needed on a platform with proper driver support.
|
||||
For more information, see Documentation/clk.txt.
|
||||
|
||||
clock= [BUGS=X86-32, HW] gettimeofday clocksource override.
|
||||
[Deprecated]
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ struct clk *imx_clk_busy_mux(const char *name, void __iomem *reg, u8 shift,
|
|||
|
||||
busy->mux.reg = reg;
|
||||
busy->mux.shift = shift;
|
||||
busy->mux.width = width;
|
||||
busy->mux.mask = BIT(width) - 1;
|
||||
busy->mux.lock = &imx_ccm_lock;
|
||||
busy->mux_ops = &clk_mux_ops;
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include <linux/regulator/fixed.h>
|
||||
#include <linux/regulator/machine.h>
|
||||
#include <linux/vexpress.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clkdev.h>
|
||||
|
||||
#include <asm/arch_timer.h>
|
||||
#include <asm/mach-types.h>
|
||||
|
|
@ -433,7 +435,7 @@ static void __init v2m_dt_timer_init(void)
|
|||
{
|
||||
struct device_node *node = NULL;
|
||||
|
||||
vexpress_clk_of_init();
|
||||
of_clk_init(NULL);
|
||||
|
||||
do {
|
||||
node = of_find_compatible_node(node, NULL, "arm,sp804");
|
||||
|
|
@ -441,6 +443,10 @@ static void __init v2m_dt_timer_init(void)
|
|||
if (node) {
|
||||
pr_info("Using SP804 '%s' as a clock & events source\n",
|
||||
node->full_name);
|
||||
WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
|
||||
"timclken1"), "v2m-timer0", "sp804"));
|
||||
WARN_ON(clk_register_clkdev(of_clk_get_by_name(node,
|
||||
"timclken2"), "v2m-timer1", "sp804"));
|
||||
v2m_sp804_init(of_iomap(node, 0),
|
||||
irq_of_parse_and_map(node, 0));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,16 @@ config COMMON_CLK_MAX77686
|
|||
---help---
|
||||
This driver supports Maxim 77686 crystal oscillator clock.
|
||||
|
||||
config COMMON_CLK_SI5351
|
||||
tristate "Clock driver for SiLabs 5351A/B/C"
|
||||
depends on I2C
|
||||
depends on OF
|
||||
select REGMAP_I2C
|
||||
select RATIONAL
|
||||
---help---
|
||||
This driver supports Silicon Labs 5351A/B/C programmable clock
|
||||
generators.
|
||||
|
||||
config CLK_TWL6040
|
||||
tristate "External McPDM functional clock from twl6040"
|
||||
depends on TWL6040_CORE
|
||||
|
|
@ -63,6 +73,14 @@ config CLK_TWL6040
|
|||
McPDM. McPDM module is using the external bit clock on the McPDM bus
|
||||
as functional clock.
|
||||
|
||||
config COMMON_CLK_AXI_CLKGEN
|
||||
tristate "AXI clkgen driver"
|
||||
depends on ARCH_ZYNQ || MICROBLAZE
|
||||
help
|
||||
---help---
|
||||
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
|
||||
FPGAs. It is commonly used in Analog Devices' reference designs.
|
||||
|
||||
endmenu
|
||||
|
||||
source "drivers/clk/mvebu/Kconfig"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
|
|||
obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-gate.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
|
||||
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
|
||||
|
||||
# SoCs specific
|
||||
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
|
||||
|
|
@ -23,6 +24,7 @@ ifeq ($(CONFIG_COMMON_CLK), y)
|
|||
obj-$(CONFIG_ARCH_MMP) += mmp/
|
||||
endif
|
||||
obj-$(CONFIG_MACH_LOONGSON1) += clk-ls1x.o
|
||||
obj-$(CONFIG_ARCH_SUNXI) += sunxi/
|
||||
obj-$(CONFIG_ARCH_U8500) += ux500/
|
||||
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
|
||||
obj-$(CONFIG_ARCH_ZYNQ) += clk-zynq.o
|
||||
|
|
@ -31,6 +33,8 @@ obj-$(CONFIG_ARCH_TEGRA) += tegra/
|
|||
obj-$(CONFIG_X86) += x86/
|
||||
|
||||
# Chip specific
|
||||
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
|
||||
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
|
||||
|
|
|
|||
331
drivers/clk/clk-axi-clkgen.c
Normal file
331
drivers/clk/clk-axi-clkgen.c
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
/*
|
||||
* AXI clkgen driver
|
||||
*
|
||||
* Copyright 2012-2013 Analog Devices Inc.
|
||||
* Author: Lars-Peter Clausen <lars@metafoo.de>
|
||||
*
|
||||
* Licensed under the GPL-2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#define AXI_CLKGEN_REG_UPDATE_ENABLE 0x04
|
||||
#define AXI_CLKGEN_REG_CLK_OUT1 0x08
|
||||
#define AXI_CLKGEN_REG_CLK_OUT2 0x0c
|
||||
#define AXI_CLKGEN_REG_CLK_DIV 0x10
|
||||
#define AXI_CLKGEN_REG_CLK_FB1 0x14
|
||||
#define AXI_CLKGEN_REG_CLK_FB2 0x18
|
||||
#define AXI_CLKGEN_REG_LOCK1 0x1c
|
||||
#define AXI_CLKGEN_REG_LOCK2 0x20
|
||||
#define AXI_CLKGEN_REG_LOCK3 0x24
|
||||
#define AXI_CLKGEN_REG_FILTER1 0x28
|
||||
#define AXI_CLKGEN_REG_FILTER2 0x2c
|
||||
|
||||
struct axi_clkgen {
|
||||
void __iomem *base;
|
||||
struct clk_hw clk_hw;
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_filter(unsigned int m)
|
||||
{
|
||||
switch (m) {
|
||||
case 0:
|
||||
return 0x01001990;
|
||||
case 1:
|
||||
return 0x01001190;
|
||||
case 2:
|
||||
return 0x01009890;
|
||||
case 3:
|
||||
return 0x01001890;
|
||||
case 4:
|
||||
return 0x01008890;
|
||||
case 5 ... 8:
|
||||
return 0x01009090;
|
||||
case 9 ... 11:
|
||||
return 0x01000890;
|
||||
case 12:
|
||||
return 0x08009090;
|
||||
case 13 ... 22:
|
||||
return 0x01001090;
|
||||
case 23 ... 36:
|
||||
return 0x01008090;
|
||||
case 37 ... 46:
|
||||
return 0x08001090;
|
||||
default:
|
||||
return 0x08008090;
|
||||
}
|
||||
}
|
||||
|
||||
static const uint32_t axi_clkgen_lock_table[] = {
|
||||
0x060603e8, 0x060603e8, 0x080803e8, 0x0b0b03e8,
|
||||
0x0e0e03e8, 0x111103e8, 0x131303e8, 0x161603e8,
|
||||
0x191903e8, 0x1c1c03e8, 0x1f1f0384, 0x1f1f0339,
|
||||
0x1f1f02ee, 0x1f1f02bc, 0x1f1f028a, 0x1f1f0271,
|
||||
0x1f1f023f, 0x1f1f0226, 0x1f1f020d, 0x1f1f01f4,
|
||||
0x1f1f01db, 0x1f1f01c2, 0x1f1f01a9, 0x1f1f0190,
|
||||
0x1f1f0190, 0x1f1f0177, 0x1f1f015e, 0x1f1f015e,
|
||||
0x1f1f0145, 0x1f1f0145, 0x1f1f012c, 0x1f1f012c,
|
||||
0x1f1f012c, 0x1f1f0113, 0x1f1f0113, 0x1f1f0113,
|
||||
};
|
||||
|
||||
static uint32_t axi_clkgen_lookup_lock(unsigned int m)
|
||||
{
|
||||
if (m < ARRAY_SIZE(axi_clkgen_lock_table))
|
||||
return axi_clkgen_lock_table[m];
|
||||
return 0x1f1f00fa;
|
||||
}
|
||||
|
||||
static const unsigned int fpfd_min = 10000;
|
||||
static const unsigned int fpfd_max = 300000;
|
||||
static const unsigned int fvco_min = 600000;
|
||||
static const unsigned int fvco_max = 1200000;
|
||||
|
||||
static void axi_clkgen_calc_params(unsigned long fin, unsigned long fout,
|
||||
unsigned int *best_d, unsigned int *best_m, unsigned int *best_dout)
|
||||
{
|
||||
unsigned long d, d_min, d_max, _d_min, _d_max;
|
||||
unsigned long m, m_min, m_max;
|
||||
unsigned long f, dout, best_f, fvco;
|
||||
|
||||
fin /= 1000;
|
||||
fout /= 1000;
|
||||
|
||||
best_f = ULONG_MAX;
|
||||
*best_d = 0;
|
||||
*best_m = 0;
|
||||
*best_dout = 0;
|
||||
|
||||
d_min = max_t(unsigned long, DIV_ROUND_UP(fin, fpfd_max), 1);
|
||||
d_max = min_t(unsigned long, fin / fpfd_min, 80);
|
||||
|
||||
m_min = max_t(unsigned long, DIV_ROUND_UP(fvco_min, fin) * d_min, 1);
|
||||
m_max = min_t(unsigned long, fvco_max * d_max / fin, 64);
|
||||
|
||||
for (m = m_min; m <= m_max; m++) {
|
||||
_d_min = max(d_min, DIV_ROUND_UP(fin * m, fvco_max));
|
||||
_d_max = min(d_max, fin * m / fvco_min);
|
||||
|
||||
for (d = _d_min; d <= _d_max; d++) {
|
||||
fvco = fin * m / d;
|
||||
|
||||
dout = DIV_ROUND_CLOSEST(fvco, fout);
|
||||
dout = clamp_t(unsigned long, dout, 1, 128);
|
||||
f = fvco / dout;
|
||||
if (abs(f - fout) < abs(best_f - fout)) {
|
||||
best_f = f;
|
||||
*best_d = d;
|
||||
*best_m = m;
|
||||
*best_dout = dout;
|
||||
if (best_f == fout)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void axi_clkgen_calc_clk_params(unsigned int divider, unsigned int *low,
|
||||
unsigned int *high, unsigned int *edge, unsigned int *nocount)
|
||||
{
|
||||
if (divider == 1)
|
||||
*nocount = 1;
|
||||
else
|
||||
*nocount = 0;
|
||||
|
||||
*high = divider / 2;
|
||||
*edge = divider % 2;
|
||||
*low = divider - *high;
|
||||
}
|
||||
|
||||
static void axi_clkgen_write(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg, unsigned int val)
|
||||
{
|
||||
writel(val, axi_clkgen->base + reg);
|
||||
}
|
||||
|
||||
static void axi_clkgen_read(struct axi_clkgen *axi_clkgen,
|
||||
unsigned int reg, unsigned int *val)
|
||||
{
|
||||
*val = readl(axi_clkgen->base + reg);
|
||||
}
|
||||
|
||||
static struct axi_clkgen *clk_hw_to_axi_clkgen(struct clk_hw *clk_hw)
|
||||
{
|
||||
return container_of(clk_hw, struct axi_clkgen, clk_hw);
|
||||
}
|
||||
|
||||
static int axi_clkgen_set_rate(struct clk_hw *clk_hw,
|
||||
unsigned long rate, unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int nocount;
|
||||
unsigned int high;
|
||||
unsigned int edge;
|
||||
unsigned int low;
|
||||
uint32_t filter;
|
||||
uint32_t lock;
|
||||
|
||||
if (parent_rate == 0 || rate == 0)
|
||||
return -EINVAL;
|
||||
|
||||
axi_clkgen_calc_params(parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
filter = axi_clkgen_lookup_filter(m - 1);
|
||||
lock = axi_clkgen_lookup_lock(m - 1);
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 0);
|
||||
|
||||
axi_clkgen_calc_clk_params(dout, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1,
|
||||
(high << 6) | low);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT2,
|
||||
(edge << 7) | (nocount << 6));
|
||||
|
||||
axi_clkgen_calc_clk_params(d, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV,
|
||||
(edge << 13) | (nocount << 12) | (high << 6) | low);
|
||||
|
||||
axi_clkgen_calc_clk_params(m, &low, &high, &edge, &nocount);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1,
|
||||
(high << 6) | low);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_CLK_FB2,
|
||||
(edge << 7) | (nocount << 6));
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK1, lock & 0x3ff);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK2,
|
||||
(((lock >> 16) & 0x1f) << 10) | 0x1);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_LOCK3,
|
||||
(((lock >> 24) & 0x1f) << 10) | 0x3e9);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER1, filter >> 16);
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_FILTER2, filter);
|
||||
|
||||
axi_clkgen_write(axi_clkgen, AXI_CLKGEN_REG_UPDATE_ENABLE, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long axi_clkgen_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *parent_rate)
|
||||
{
|
||||
unsigned int d, m, dout;
|
||||
|
||||
axi_clkgen_calc_params(*parent_rate, rate, &d, &m, &dout);
|
||||
|
||||
if (d == 0 || dout == 0 || m == 0)
|
||||
return -EINVAL;
|
||||
|
||||
return *parent_rate / d * m / dout;
|
||||
}
|
||||
|
||||
static unsigned long axi_clkgen_recalc_rate(struct clk_hw *clk_hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen = clk_hw_to_axi_clkgen(clk_hw);
|
||||
unsigned int d, m, dout;
|
||||
unsigned int reg;
|
||||
unsigned long long tmp;
|
||||
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_OUT1, ®);
|
||||
dout = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_DIV, ®);
|
||||
d = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
axi_clkgen_read(axi_clkgen, AXI_CLKGEN_REG_CLK_FB1, ®);
|
||||
m = (reg & 0x3f) + ((reg >> 6) & 0x3f);
|
||||
|
||||
if (d == 0 || dout == 0)
|
||||
return 0;
|
||||
|
||||
tmp = (unsigned long long)(parent_rate / d) * m;
|
||||
do_div(tmp, dout);
|
||||
|
||||
if (tmp > ULONG_MAX)
|
||||
return ULONG_MAX;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
static const struct clk_ops axi_clkgen_ops = {
|
||||
.recalc_rate = axi_clkgen_recalc_rate,
|
||||
.round_rate = axi_clkgen_round_rate,
|
||||
.set_rate = axi_clkgen_set_rate,
|
||||
};
|
||||
|
||||
static int axi_clkgen_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct axi_clkgen *axi_clkgen;
|
||||
struct clk_init_data init;
|
||||
const char *parent_name;
|
||||
const char *clk_name;
|
||||
struct resource *mem;
|
||||
struct clk *clk;
|
||||
|
||||
axi_clkgen = devm_kzalloc(&pdev->dev, sizeof(*axi_clkgen), GFP_KERNEL);
|
||||
if (!axi_clkgen)
|
||||
return -ENOMEM;
|
||||
|
||||
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
axi_clkgen->base = devm_ioremap_resource(&pdev->dev, mem);
|
||||
if (IS_ERR(axi_clkgen->base))
|
||||
return PTR_ERR(axi_clkgen->base);
|
||||
|
||||
parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
|
||||
if (!parent_name)
|
||||
return -EINVAL;
|
||||
|
||||
clk_name = pdev->dev.of_node->name;
|
||||
of_property_read_string(pdev->dev.of_node, "clock-output-names",
|
||||
&clk_name);
|
||||
|
||||
init.name = clk_name;
|
||||
init.ops = &axi_clkgen_ops;
|
||||
init.flags = 0;
|
||||
init.parent_names = &parent_name;
|
||||
init.num_parents = 1;
|
||||
|
||||
axi_clkgen->clk_hw.init = &init;
|
||||
clk = devm_clk_register(&pdev->dev, &axi_clkgen->clk_hw);
|
||||
if (IS_ERR(clk))
|
||||
return PTR_ERR(clk);
|
||||
|
||||
return of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
|
||||
clk);
|
||||
}
|
||||
|
||||
static int axi_clkgen_remove(struct platform_device *pdev)
|
||||
{
|
||||
of_clk_del_provider(pdev->dev.of_node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id axi_clkgen_ids[] = {
|
||||
{ .compatible = "adi,axi-clkgen-1.00.a" },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, axi_clkgen_ids);
|
||||
|
||||
static struct platform_driver axi_clkgen_driver = {
|
||||
.driver = {
|
||||
.name = "adi-axi-clkgen",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = axi_clkgen_ids,
|
||||
},
|
||||
.probe = axi_clkgen_probe,
|
||||
.remove = axi_clkgen_remove,
|
||||
};
|
||||
module_platform_driver(axi_clkgen_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
|
||||
MODULE_DESCRIPTION("Driver for the Analog Devices' AXI clkgen pcore clock generator");
|
||||
210
drivers/clk/clk-composite.c
Normal file
210
drivers/clk/clk-composite.c
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
* Copyright (c) 2013 NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
|
||||
|
||||
static u8 clk_composite_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->get_parent(mux_hw);
|
||||
}
|
||||
|
||||
static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *mux_ops = composite->mux_ops;
|
||||
struct clk_hw *mux_hw = composite->mux_hw;
|
||||
|
||||
mux_hw->clk = hw->clk;
|
||||
|
||||
return mux_ops->set_parent(mux_hw, index);
|
||||
}
|
||||
|
||||
static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *rate_ops = composite->rate_ops;
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
|
||||
rate_hw->clk = hw->clk;
|
||||
|
||||
return rate_ops->recalc_rate(rate_hw, parent_rate);
|
||||
}
|
||||
|
||||
static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long *prate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *rate_ops = composite->rate_ops;
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
|
||||
rate_hw->clk = hw->clk;
|
||||
|
||||
return rate_ops->round_rate(rate_hw, rate, prate);
|
||||
}
|
||||
|
||||
static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *rate_ops = composite->rate_ops;
|
||||
struct clk_hw *rate_hw = composite->rate_hw;
|
||||
|
||||
rate_hw->clk = hw->clk;
|
||||
|
||||
return rate_ops->set_rate(rate_hw, rate, parent_rate);
|
||||
}
|
||||
|
||||
static int clk_composite_is_enabled(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->is_enabled(gate_hw);
|
||||
}
|
||||
|
||||
static int clk_composite_enable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
return gate_ops->enable(gate_hw);
|
||||
}
|
||||
|
||||
static void clk_composite_disable(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_composite *composite = to_clk_composite(hw);
|
||||
const struct clk_ops *gate_ops = composite->gate_ops;
|
||||
struct clk_hw *gate_hw = composite->gate_hw;
|
||||
|
||||
gate_hw->clk = hw->clk;
|
||||
|
||||
gate_ops->disable(gate_hw);
|
||||
}
|
||||
|
||||
struct clk *clk_register_composite(struct device *dev, const char *name,
|
||||
const char **parent_names, int num_parents,
|
||||
struct clk_hw *mux_hw, const struct clk_ops *mux_ops,
|
||||
struct clk_hw *rate_hw, const struct clk_ops *rate_ops,
|
||||
struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
|
||||
unsigned long flags)
|
||||
{
|
||||
struct clk *clk;
|
||||
struct clk_init_data init;
|
||||
struct clk_composite *composite;
|
||||
struct clk_ops *clk_composite_ops;
|
||||
|
||||
composite = kzalloc(sizeof(*composite), GFP_KERNEL);
|
||||
if (!composite) {
|
||||
pr_err("%s: could not allocate composite clk\n", __func__);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
init.name = name;
|
||||
init.flags = flags | CLK_IS_BASIC;
|
||||
init.parent_names = parent_names;
|
||||
init.num_parents = num_parents;
|
||||
|
||||
clk_composite_ops = &composite->ops;
|
||||
|
||||
if (mux_hw && mux_ops) {
|
||||
if (!mux_ops->get_parent || !mux_ops->set_parent) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
composite->mux_hw = mux_hw;
|
||||
composite->mux_ops = mux_ops;
|
||||
clk_composite_ops->get_parent = clk_composite_get_parent;
|
||||
clk_composite_ops->set_parent = clk_composite_set_parent;
|
||||
}
|
||||
|
||||
if (rate_hw && rate_ops) {
|
||||
if (!rate_ops->recalc_rate) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* .round_rate is a prerequisite for .set_rate */
|
||||
if (rate_ops->round_rate) {
|
||||
clk_composite_ops->round_rate = clk_composite_round_rate;
|
||||
if (rate_ops->set_rate) {
|
||||
clk_composite_ops->set_rate = clk_composite_set_rate;
|
||||
}
|
||||
} else {
|
||||
WARN(rate_ops->set_rate,
|
||||
"%s: missing round_rate op is required\n",
|
||||
__func__);
|
||||
}
|
||||
|
||||
composite->rate_hw = rate_hw;
|
||||
composite->rate_ops = rate_ops;
|
||||
clk_composite_ops->recalc_rate = clk_composite_recalc_rate;
|
||||
}
|
||||
|
||||
if (gate_hw && gate_ops) {
|
||||
if (!gate_ops->is_enabled || !gate_ops->enable ||
|
||||
!gate_ops->disable) {
|
||||
clk = ERR_PTR(-EINVAL);
|
||||
goto err;
|
||||
}
|
||||
|
||||
composite->gate_hw = gate_hw;
|
||||
composite->gate_ops = gate_ops;
|
||||
clk_composite_ops->is_enabled = clk_composite_is_enabled;
|
||||
clk_composite_ops->enable = clk_composite_enable;
|
||||
clk_composite_ops->disable = clk_composite_disable;
|
||||
}
|
||||
|
||||
init.ops = clk_composite_ops;
|
||||
composite->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &composite->hw);
|
||||
if (IS_ERR(clk))
|
||||
goto err;
|
||||
|
||||
if (composite->mux_hw)
|
||||
composite->mux_hw->clk = clk;
|
||||
|
||||
if (composite->rate_hw)
|
||||
composite->rate_hw->clk = clk;
|
||||
|
||||
if (composite->gate_hw)
|
||||
composite->gate_hw->clk = clk;
|
||||
|
||||
return clk;
|
||||
|
||||
err:
|
||||
kfree(composite);
|
||||
return clk;
|
||||
}
|
||||
|
|
@ -109,8 +109,9 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
|
|||
|
||||
div = _get_div(divider, val);
|
||||
if (!div) {
|
||||
WARN(1, "%s: Invalid divisor for clock %s\n", __func__,
|
||||
__clk_get_name(hw->clk));
|
||||
WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
|
||||
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
|
||||
__clk_get_name(hw->clk));
|
||||
return parent_rate;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/clk-provider.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* DOC: basic fixed multiplier and divider clock that cannot gate
|
||||
|
|
@ -96,3 +97,38 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
|
|||
|
||||
return clk;
|
||||
}
|
||||
#ifdef CONFIG_OF
|
||||
/**
|
||||
* of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
|
||||
*/
|
||||
void __init of_fixed_factor_clk_setup(struct device_node *node)
|
||||
{
|
||||
struct clk *clk;
|
||||
const char *clk_name = node->name;
|
||||
const char *parent_name;
|
||||
u32 div, mult;
|
||||
|
||||
if (of_property_read_u32(node, "clock-div", &div)) {
|
||||
pr_err("%s Fixed factor clock <%s> must have a clock-div property\n",
|
||||
__func__, node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (of_property_read_u32(node, "clock-mult", &mult)) {
|
||||
pr_err("%s Fixed factor clock <%s> must have a clokc-mult property\n",
|
||||
__func__, node->name);
|
||||
return;
|
||||
}
|
||||
|
||||
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,
|
||||
mult, div);
|
||||
if (!IS_ERR(clk))
|
||||
of_clk_add_provider(node, of_clk_src_simple_get, clk);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_fixed_factor_clk_setup);
|
||||
CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
|
||||
of_fixed_factor_clk_setup);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
static u8 clk_mux_get_parent(struct clk_hw *hw)
|
||||
{
|
||||
struct clk_mux *mux = to_clk_mux(hw);
|
||||
int num_parents = __clk_get_num_parents(hw->clk);
|
||||
u32 val;
|
||||
|
||||
/*
|
||||
|
|
@ -42,7 +43,16 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
|
|||
* val = 0x4 really means "bit 2, index starts at bit 0"
|
||||
*/
|
||||
val = readl(mux->reg) >> mux->shift;
|
||||
val &= (1 << mux->width) - 1;
|
||||
val &= mux->mask;
|
||||
|
||||
if (mux->table) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < num_parents; i++)
|
||||
if (mux->table[i] == val)
|
||||
return i;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (val && (mux->flags & CLK_MUX_INDEX_BIT))
|
||||
val = ffs(val) - 1;
|
||||
|
|
@ -50,7 +60,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
|
|||
if (val && (mux->flags & CLK_MUX_INDEX_ONE))
|
||||
val--;
|
||||
|
||||
if (val >= __clk_get_num_parents(hw->clk))
|
||||
if (val >= num_parents)
|
||||
return -EINVAL;
|
||||
|
||||
return val;
|
||||
|
|
@ -62,17 +72,22 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
|
|||
u32 val;
|
||||
unsigned long flags = 0;
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_BIT)
|
||||
index = (1 << ffs(index));
|
||||
if (mux->table)
|
||||
index = mux->table[index];
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_ONE)
|
||||
index++;
|
||||
else {
|
||||
if (mux->flags & CLK_MUX_INDEX_BIT)
|
||||
index = (1 << ffs(index));
|
||||
|
||||
if (mux->flags & CLK_MUX_INDEX_ONE)
|
||||
index++;
|
||||
}
|
||||
|
||||
if (mux->lock)
|
||||
spin_lock_irqsave(mux->lock, flags);
|
||||
|
||||
val = readl(mux->reg);
|
||||
val &= ~(((1 << mux->width) - 1) << mux->shift);
|
||||
val &= ~(mux->mask << mux->shift);
|
||||
val |= index << mux->shift;
|
||||
writel(val, mux->reg);
|
||||
|
||||
|
|
@ -88,10 +103,10 @@ const struct clk_ops clk_mux_ops = {
|
|||
};
|
||||
EXPORT_SYMBOL_GPL(clk_mux_ops);
|
||||
|
||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
struct clk *clk_register_mux_table(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_mux_flags, spinlock_t *lock)
|
||||
void __iomem *reg, u8 shift, u32 mask,
|
||||
u8 clk_mux_flags, u32 *table, spinlock_t *lock)
|
||||
{
|
||||
struct clk_mux *mux;
|
||||
struct clk *clk;
|
||||
|
|
@ -113,9 +128,10 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
|
|||
/* struct clk_mux assignments */
|
||||
mux->reg = reg;
|
||||
mux->shift = shift;
|
||||
mux->width = width;
|
||||
mux->mask = mask;
|
||||
mux->flags = clk_mux_flags;
|
||||
mux->lock = lock;
|
||||
mux->table = table;
|
||||
mux->hw.init = &init;
|
||||
|
||||
clk = clk_register(dev, &mux->hw);
|
||||
|
|
@ -125,3 +141,15 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
|
|||
|
||||
return clk;
|
||||
}
|
||||
|
||||
struct clk *clk_register_mux(struct device *dev, const char *name,
|
||||
const char **parent_names, u8 num_parents, unsigned long flags,
|
||||
void __iomem *reg, u8 shift, u8 width,
|
||||
u8 clk_mux_flags, spinlock_t *lock)
|
||||
{
|
||||
u32 mask = BIT(width) - 1;
|
||||
|
||||
return clk_register_mux_table(dev, name, parent_names, num_parents,
|
||||
flags, reg, shift, mask, clk_mux_flags,
|
||||
NULL, lock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1113,7 +1113,7 @@ void __init sirfsoc_of_clk_init(void)
|
|||
|
||||
for (i = pll1; i < maxclk; i++) {
|
||||
prima2_clks[i] = clk_register(NULL, prima2_clk_hw_array[i]);
|
||||
BUG_ON(!prima2_clks[i]);
|
||||
BUG_ON(IS_ERR(prima2_clks[i]));
|
||||
}
|
||||
clk_register_clkdev(prima2_clks[cpu], NULL, "cpu");
|
||||
clk_register_clkdev(prima2_clks[io], NULL, "io");
|
||||
|
|
|
|||
1510
drivers/clk/clk-si5351.c
Normal file
1510
drivers/clk/clk-si5351.c
Normal file
File diff suppressed because it is too large
Load diff
155
drivers/clk/clk-si5351.h
Normal file
155
drivers/clk/clk-si5351.h
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* clk-si5351.h: Silicon Laboratories Si5351A/B/C I2C Clock Generator
|
||||
*
|
||||
* Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
|
||||
* Rabeeh Khoury <rabeeh@solid-run.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the
|
||||
* Free Software Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _CLK_SI5351_H_
|
||||
#define _CLK_SI5351_H_
|
||||
|
||||
#define SI5351_BUS_BASE_ADDR 0x60
|
||||
|
||||
#define SI5351_PLL_VCO_MIN 600000000
|
||||
#define SI5351_PLL_VCO_MAX 900000000
|
||||
#define SI5351_MULTISYNTH_MIN_FREQ 1000000
|
||||
#define SI5351_MULTISYNTH_DIVBY4_FREQ 150000000
|
||||
#define SI5351_MULTISYNTH_MAX_FREQ 160000000
|
||||
#define SI5351_MULTISYNTH67_MAX_FREQ SI5351_MULTISYNTH_DIVBY4_FREQ
|
||||
#define SI5351_CLKOUT_MIN_FREQ 8000
|
||||
#define SI5351_CLKOUT_MAX_FREQ SI5351_MULTISYNTH_MAX_FREQ
|
||||
#define SI5351_CLKOUT67_MAX_FREQ SI5351_MULTISYNTH67_MAX_FREQ
|
||||
|
||||
#define SI5351_PLL_A_MIN 15
|
||||
#define SI5351_PLL_A_MAX 90
|
||||
#define SI5351_PLL_B_MAX (SI5351_PLL_C_MAX-1)
|
||||
#define SI5351_PLL_C_MAX 1048575
|
||||
#define SI5351_MULTISYNTH_A_MIN 6
|
||||
#define SI5351_MULTISYNTH_A_MAX 1800
|
||||
#define SI5351_MULTISYNTH67_A_MAX 254
|
||||
#define SI5351_MULTISYNTH_B_MAX (SI5351_MULTISYNTH_C_MAX-1)
|
||||
#define SI5351_MULTISYNTH_C_MAX 1048575
|
||||
#define SI5351_MULTISYNTH_P1_MAX ((1<<18)-1)
|
||||
#define SI5351_MULTISYNTH_P2_MAX ((1<<20)-1)
|
||||
#define SI5351_MULTISYNTH_P3_MAX ((1<<20)-1)
|
||||
|
||||
#define SI5351_DEVICE_STATUS 0
|
||||
#define SI5351_INTERRUPT_STATUS 1
|
||||
#define SI5351_INTERRUPT_MASK 2
|
||||
#define SI5351_STATUS_SYS_INIT (1<<7)
|
||||
#define SI5351_STATUS_LOL_B (1<<6)
|
||||
#define SI5351_STATUS_LOL_A (1<<5)
|
||||
#define SI5351_STATUS_LOS (1<<4)
|
||||
#define SI5351_OUTPUT_ENABLE_CTRL 3
|
||||
#define SI5351_OEB_PIN_ENABLE_CTRL 9
|
||||
#define SI5351_PLL_INPUT_SOURCE 15
|
||||
#define SI5351_CLKIN_DIV_MASK (3<<6)
|
||||
#define SI5351_CLKIN_DIV_1 (0<<6)
|
||||
#define SI5351_CLKIN_DIV_2 (1<<6)
|
||||
#define SI5351_CLKIN_DIV_4 (2<<6)
|
||||
#define SI5351_CLKIN_DIV_8 (3<<6)
|
||||
#define SI5351_PLLB_SOURCE (1<<3)
|
||||
#define SI5351_PLLA_SOURCE (1<<2)
|
||||
|
||||
#define SI5351_CLK0_CTRL 16
|
||||
#define SI5351_CLK1_CTRL 17
|
||||
#define SI5351_CLK2_CTRL 18
|
||||
#define SI5351_CLK3_CTRL 19
|
||||
#define SI5351_CLK4_CTRL 20
|
||||
#define SI5351_CLK5_CTRL 21
|
||||
#define SI5351_CLK6_CTRL 22
|
||||
#define SI5351_CLK7_CTRL 23
|
||||
#define SI5351_CLK_POWERDOWN (1<<7)
|
||||
#define SI5351_CLK_INTEGER_MODE (1<<6)
|
||||
#define SI5351_CLK_PLL_SELECT (1<<5)
|
||||
#define SI5351_CLK_INVERT (1<<4)
|
||||
#define SI5351_CLK_INPUT_MASK (3<<2)
|
||||
#define SI5351_CLK_INPUT_XTAL (0<<2)
|
||||
#define SI5351_CLK_INPUT_CLKIN (1<<2)
|
||||
#define SI5351_CLK_INPUT_MULTISYNTH_0_4 (2<<2)
|
||||
#define SI5351_CLK_INPUT_MULTISYNTH_N (3<<2)
|
||||
#define SI5351_CLK_DRIVE_STRENGTH_MASK (3<<0)
|
||||
#define SI5351_CLK_DRIVE_STRENGTH_2MA (0<<0)
|
||||
#define SI5351_CLK_DRIVE_STRENGTH_4MA (1<<0)
|
||||
#define SI5351_CLK_DRIVE_STRENGTH_6MA (2<<0)
|
||||
#define SI5351_CLK_DRIVE_STRENGTH_8MA (3<<0)
|
||||
|
||||
#define SI5351_CLK3_0_DISABLE_STATE 24
|
||||
#define SI5351_CLK7_4_DISABLE_STATE 25
|
||||
#define SI5351_CLK_DISABLE_STATE_LOW 0
|
||||
#define SI5351_CLK_DISABLE_STATE_HIGH 1
|
||||
#define SI5351_CLK_DISABLE_STATE_FLOAT 2
|
||||
#define SI5351_CLK_DISABLE_STATE_NEVER 3
|
||||
|
||||
#define SI5351_PARAMETERS_LENGTH 8
|
||||
#define SI5351_PLLA_PARAMETERS 26
|
||||
#define SI5351_PLLB_PARAMETERS 34
|
||||
#define SI5351_CLK0_PARAMETERS 42
|
||||
#define SI5351_CLK1_PARAMETERS 50
|
||||
#define SI5351_CLK2_PARAMETERS 58
|
||||
#define SI5351_CLK3_PARAMETERS 66
|
||||
#define SI5351_CLK4_PARAMETERS 74
|
||||
#define SI5351_CLK5_PARAMETERS 82
|
||||
#define SI5351_CLK6_PARAMETERS 90
|
||||
#define SI5351_CLK7_PARAMETERS 91
|
||||
#define SI5351_CLK6_7_OUTPUT_DIVIDER 92
|
||||
#define SI5351_OUTPUT_CLK_DIV_MASK (7 << 4)
|
||||
#define SI5351_OUTPUT_CLK6_DIV_MASK (7 << 0)
|
||||
#define SI5351_OUTPUT_CLK_DIV_SHIFT 4
|
||||
#define SI5351_OUTPUT_CLK_DIV6_SHIFT 0
|
||||
#define SI5351_OUTPUT_CLK_DIV_1 0
|
||||
#define SI5351_OUTPUT_CLK_DIV_2 1
|
||||
#define SI5351_OUTPUT_CLK_DIV_4 2
|
||||
#define SI5351_OUTPUT_CLK_DIV_8 3
|
||||
#define SI5351_OUTPUT_CLK_DIV_16 4
|
||||
#define SI5351_OUTPUT_CLK_DIV_32 5
|
||||
#define SI5351_OUTPUT_CLK_DIV_64 6
|
||||
#define SI5351_OUTPUT_CLK_DIV_128 7
|
||||
#define SI5351_OUTPUT_CLK_DIVBY4 (3<<2)
|
||||
|
||||
#define SI5351_SSC_PARAM0 149
|
||||
#define SI5351_SSC_PARAM1 150
|
||||
#define SI5351_SSC_PARAM2 151
|
||||
#define SI5351_SSC_PARAM3 152
|
||||
#define SI5351_SSC_PARAM4 153
|
||||
#define SI5351_SSC_PARAM5 154
|
||||
#define SI5351_SSC_PARAM6 155
|
||||
#define SI5351_SSC_PARAM7 156
|
||||
#define SI5351_SSC_PARAM8 157
|
||||
#define SI5351_SSC_PARAM9 158
|
||||
#define SI5351_SSC_PARAM10 159
|
||||
#define SI5351_SSC_PARAM11 160
|
||||
#define SI5351_SSC_PARAM12 161
|
||||
|
||||
#define SI5351_VXCO_PARAMETERS_LOW 162
|
||||
#define SI5351_VXCO_PARAMETERS_MID 163
|
||||
#define SI5351_VXCO_PARAMETERS_HIGH 164
|
||||
|
||||
#define SI5351_CLK0_PHASE_OFFSET 165
|
||||
#define SI5351_CLK1_PHASE_OFFSET 166
|
||||
#define SI5351_CLK2_PHASE_OFFSET 167
|
||||
#define SI5351_CLK3_PHASE_OFFSET 168
|
||||
#define SI5351_CLK4_PHASE_OFFSET 169
|
||||
#define SI5351_CLK5_PHASE_OFFSET 170
|
||||
|
||||
#define SI5351_PLL_RESET 177
|
||||
#define SI5351_PLL_RESET_B (1<<7)
|
||||
#define SI5351_PLL_RESET_A (1<<5)
|
||||
|
||||
#define SI5351_CRYSTAL_LOAD 183
|
||||
#define SI5351_CRYSTAL_LOAD_MASK (3<<6)
|
||||
#define SI5351_CRYSTAL_LOAD_6PF (1<<6)
|
||||
#define SI5351_CRYSTAL_LOAD_8PF (2<<6)
|
||||
#define SI5351_CRYSTAL_LOAD_10PF (3<<6)
|
||||
|
||||
#define SI5351_FANOUT_ENABLE 187
|
||||
#define SI5351_CLKIN_ENABLE (1<<7)
|
||||
#define SI5351_XTAL_ENABLE (1<<6)
|
||||
#define SI5351_MULTISYNTH_ENABLE (1<<4)
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue