Commit 5f1201d5 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'clk-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux

Pull clock framework updates from Michael Turquette:
 "The changes to the common clock framework for 4.2 are dominated by new
  drivers and updates to existing ones, as usual.

  There are some fixes to the framework itself and several cleanups for
  sparse warnings, etc"

* tag 'clk-for-linus-4.2' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (135 commits)
  clk: stm32: Add clock driver for STM32F4[23]xxx devices
  dt-bindings: Document the STM32F4 clock bindings
  cpufreq: exynos: remove Exynos4210 specific cpufreq driver support
  ARM: Exynos: switch to using generic cpufreq driver for Exynos4210
  clk: samsung: exynos4: add cpu clock configuration data and instantiate cpu clock
  clk: samsung: add infrastructure to register cpu clocks
  clk: add CLK_RECALC_NEW_RATES clock flag for Exynos cpu clock support
  doc: dt: add documentation for lpc1850-ccu clk driver
  clk: add lpc18xx ccu clk driver
  doc: dt: add documentation for lpc1850-cgu clk driver
  clk: add lpc18xx cgu clk driver
  clk: keystone: add support for post divider register for main pll
  clk: mvebu: flag the crypto clk as CLK_IGNORE_UNUSED
  clk: cygnus: remove Cygnus dummy clock binding
  clk: cygnus: add clock support for Broadcom Cygnus
  clk: Change bcm clocks build dependency
  clk: iproc: add initial common clock support
  clk: iproc: define Broadcom iProc clock binding
  MAINTAINERS: update email for Michael Turquette
  clk: meson: add some error handling in meson_clk_register_cpu()
  ...
parents 13d45f79 358bdf89
...@@ -230,30 +230,7 @@ clk_register(...) ...@@ -230,30 +230,7 @@ clk_register(...)
See the basic clock types in drivers/clk/clk-*.c for examples. See the basic clock types in drivers/clk/clk-*.c for examples.
Part 5 - static initialization of clock data Part 5 - Disabling clock gating of unused clocks
For platforms with many clocks (often numbering into the hundreds) it
may be desirable to statically initialize some clock data. This
presents a problem since the definition of struct clk should be hidden
from everyone except for the clock core in drivers/clk/clk.c.
To get around this problem struct clk's definition is exposed in
include/linux/clk-private.h along with some macros for more easily
initializing instances of the basic clock types. These clocks must
still be initialized with the common clock framework via a call to
__clk_init.
clk-private.h must NEVER be included by code which implements struct
clk_ops callbacks, nor must it be included by any logic which pokes
around inside of struct clk at run-time. To do so is a layering
violation.
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 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 default disabling of unused clocks. For example, if drivers aren't enabling
...@@ -264,7 +241,7 @@ are sorted out. ...@@ -264,7 +241,7 @@ are sorted out.
To bypass this disabling, include "clk_ignore_unused" in the bootargs to the To bypass this disabling, include "clk_ignore_unused" in the bootargs to the
kernel. kernel.
Part 7 - Locking Part 6 - Locking
The common clock framework uses two global locks, the prepare lock and the The common clock framework uses two global locks, the prepare lock and the
enable lock. enable lock.
......
Mediatek apmixedsys controller
==============================
The Mediatek apmixedsys controller provides the PLLs to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt8135-apmixedsys"
- "mediatek,mt8173-apmixedsys"
- #clock-cells: Must be 1
The apmixedsys controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
apmixedsys: clock-controller@10209000 {
compatible = "mediatek,mt8173-apmixedsys";
reg = <0 0x10209000 0 0x1000>;
#clock-cells = <1>;
};
Mediatek infracfg controller
============================
The Mediatek infracfg controller provides various clocks and reset
outputs to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt8135-infracfg", "syscon"
- "mediatek,mt8173-infracfg", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1
The infracfg controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Also it uses the common reset controller binding from
Documentation/devicetree/bindings/reset/reset.txt.
The available reset outputs are defined in
dt-bindings/reset-controller/mt*-resets.h
Example:
infracfg: power-controller@10001000 {
compatible = "mediatek,mt8173-infracfg", "syscon";
reg = <0 0x10001000 0 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Mediatek pericfg controller
===========================
The Mediatek pericfg controller provides various clocks and reset
outputs to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt8135-pericfg", "syscon"
- "mediatek,mt8173-pericfg", "syscon"
- #clock-cells: Must be 1
- #reset-cells: Must be 1
The pericfg controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Also it uses the common reset controller binding from
Documentation/devicetree/bindings/reset/reset.txt.
The available reset outputs are defined in
dt-bindings/reset-controller/mt*-resets.h
Example:
pericfg: power-controller@10003000 {
compatible = "mediatek,mt8173-pericfg", "syscon";
reg = <0 0x10003000 0 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Mediatek topckgen controller
============================
The Mediatek topckgen controller provides various clocks to the system.
Required Properties:
- compatible: Should be:
- "mediatek,mt8135-topckgen"
- "mediatek,mt8173-topckgen"
- #clock-cells: Must be 1
The topckgen controller uses the common clk binding from
Documentation/devicetree/bindings/clock/clock-bindings.txt
The available clocks are defined in dt-bindings/clock/mt*-clk.h.
Example:
topckgen: power-controller@10000000 {
compatible = "mediatek,mt8173-topckgen";
reg = <0 0x10000000 0 0x1000>;
#clock-cells = <1>;
};
* Amlogic Meson8b Clock and Reset Unit
The Amlogic Meson8b clock controller generates and supplies clock to various
controllers within the SoC.
Required Properties:
- compatible: should be "amlogic,meson8b-clkc"
- reg: it must be composed by two tuples:
0) physical base address of the xtal register and length of memory
mapped region.
1) physical base address of the clock controller and length of memory
mapped region.
- #clock-cells: should be 1.
Each clock is assigned an identifier and client nodes can use this identifier
to specify the clock which they consume. All available clocks are defined as
preprocessor macros in the dt-bindings/clock/meson8b-clkc.h header and can be
used in device tree sources.
Example: Clock controller node:
clkc: clock-controller@c1104000 {
#clock-cells = <1>;
compatible = "amlogic,meson8b-clkc";
reg = <0xc1108000 0x4>, <0xc1104000 0x460>;
};
Example: UART controller node that consumes the clock generated by the clock
controller:
uart_AO: serial@c81004c0 {
compatible = "amlogic,meson-uart";
reg = <0xc81004c0 0x14>;
interrupts = <0 90 1>;
clocks = <&clkc CLKID_CLK81>;
status = "disabled";
};
Broadcom Cygnus Clocks
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
Currently various "fixed" clocks are declared for peripheral drivers that use
the common clock framework to reference their core clocks. Proper support of
these clocks will be added later
Device tree example:
clocks {
#address-cells = <1>;
#size-cells = <1>;
ranges;
osc: oscillator {
compatible = "fixed-clock";
#clock-cells = <1>;
clock-frequency = <25000000>;
};
apb_clk: apb_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <1000000000>;
};
periph_clk: periph_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <500000000>;
};
};
Broadcom iProc Family Clocks
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
The iProc clock controller manages clocks that are common to the iProc family.
An SoC from the iProc family may have several PPLs, e.g., ARMPLL, GENPLL,
LCPLL0, MIPIPLL, and etc., all derived from an onboard crystal. Each PLL
comprises of several leaf clocks
Required properties for a PLL and its leaf clocks:
- compatible:
Should have a value of the form "brcm,<soc>-<pll>". For example, GENPLL on
Cygnus has a compatible string of "brcm,cygnus-genpll"
- #clock-cells:
Have a value of <1> since there are more than 1 leaf clock of a given PLL
- reg:
Define the base and range of the I/O address space that contain the iProc
clock control registers required for the PLL
- clocks:
The input parent clock phandle for the PLL. For most iProc PLLs, this is an
onboard crystal with a fixed rate
- clock-output-names:
An ordered list of strings defining the names of the clocks
Example:
osc: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <25000000>;
};
genpll: genpll {
#clock-cells = <1>;
compatible = "brcm,cygnus-genpll";
reg = <0x0301d000 0x2c>, <0x0301c020 0x4>;
clocks = <&osc>;
clock-output-names = "genpll", "axi21", "250mhz", "ihost_sys",
"enet_sw", "audio_125", "can";
};
Required properties for ASIU clocks:
ASIU clocks are a special case. These clocks are derived directly from the
reference clock of the onboard crystal
- compatible:
Should have a value of the form "brcm,<soc>-asiu-clk". For example, ASIU
clocks for Cygnus have a compatible string of "brcm,cygnus-asiu-clk"
- #clock-cells:
Have a value of <1> since there are more than 1 ASIU clocks
- reg:
Define the base and range of the I/O address space that contain the iProc
clock control registers required for ASIU clocks
- clocks:
The input parent clock phandle for the ASIU clock, i.e., the onboard
crystal
- clock-output-names:
An ordered list of strings defining the names of the ASIU clocks
Example:
osc: oscillator {
#clock-cells = <0>;
compatible = "fixed-clock";
clock-frequency = <25000000>;
};
asiu_clks: asiu_clks {
#clock-cells = <1>;
compatible = "brcm,cygnus-asiu-clk";
reg = <0x0301d048 0xc>, <0x180aa024 0x4>;
clocks = <&osc>;
clock-output-names = "keypad", "adc/touch", "pwm";
};
Cygnus
------
PLL and leaf clock compatible strings for Cygnus are:
"brcm,cygnus-armpll"
"brcm,cygnus-genpll"
"brcm,cygnus-lcpll0"
"brcm,cygnus-mipipll"
"brcm,cygnus-asiu-clk"
The following table defines the set of PLL/clock index and ID for Cygnus.
These clock IDs are defined in:
"include/dt-bindings/clock/bcm-cygnus.h"
Clock Source (Parent) Index ID
--- ----- ----- ---------
crystal N/A N/A N/A
armpll crystal N/A N/A
keypad crystal (ASIU) 0 BCM_CYGNUS_ASIU_KEYPAD_CLK
adc/tsc crystal (ASIU) 1 BCM_CYGNUS_ASIU_ADC_CLK
pwm crystal (ASIU) 2 BCM_CYGNUS_ASIU_PWM_CLK
genpll crystal 0 BCM_CYGNUS_GENPLL
axi21 genpll 1 BCM_CYGNUS_GENPLL_AXI21_CLK
250mhz genpll 2 BCM_CYGNUS_GENPLL_250MHZ_CLK
ihost_sys genpll 3 BCM_CYGNUS_GENPLL_IHOST_SYS_CLK
enet_sw genpll 4 BCM_CYGNUS_GENPLL_ENET_SW_CLK
audio_125 genpll 5 BCM_CYGNUS_GENPLL_AUDIO_125_CLK
can genpll 6 BCM_CYGNUS_GENPLL_CAN_CLK
lcpll0 crystal 0 BCM_CYGNUS_LCPLL0
pcie_phy lcpll0 1 BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK
ddr_phy lcpll0 2 BCM_CYGNUS_LCPLL0_DDR_PHY_CLK
sdio lcpll0 3 BCM_CYGNUS_LCPLL0_SDIO_CLK
usb_phy lcpll0 4 BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK
smart_card lcpll0 5 BCM_CYGNUS_LCPLL0_SMART_CARD_CLK
ch5_unused lcpll0 6 BCM_CYGNUS_LCPLL0_CH5_UNUSED
mipipll crystal 0 BCM_CYGNUS_MIPIPLL
ch0_unused mipipll 1 BCM_CYGNUS_MIPIPLL_CH0_UNUSED
ch1_lcd mipipll 2 BCM_CYGNUS_MIPIPLL_CH1_LCD
ch2_v3d mipipll 3 BCM_CYGNUS_MIPIPLL_CH2_V3D
ch3_unused mipipll 4 BCM_CYGNUS_MIPIPLL_CH3_UNUSED
ch4_unused mipipll 5 BCM_CYGNUS_MIPIPLL_CH4_UNUSED
ch5_unused mipipll 6 BCM_CYGNUS_MIPIPLL_CH5_UNUSED
...@@ -138,9 +138,10 @@ Some platforms may require initial configuration of default parent clocks ...@@ -138,9 +138,10 @@ Some platforms may require initial configuration of default parent clocks
and clock frequencies. Such a configuration can be specified in a device tree and clock frequencies. Such a configuration can be specified in a device tree
node through assigned-clocks, assigned-clock-parents and assigned-clock-rates node through assigned-clocks, assigned-clock-parents and assigned-clock-rates
properties. The assigned-clock-parents property should contain a list of parent properties. The assigned-clock-parents property should contain a list of parent
clocks in form of phandle and clock specifier pairs, the assigned-clock-parents clocks in the form of a phandle and clock specifier pair and the
property the list of assigned clock frequency values - corresponding to clocks assigned-clock-rates property should contain a list of frequencies in Hz. Both
listed in the assigned-clocks property. these properties should correspond to the clocks listed in the assigned-clocks
property.
To skip setting parent or rate of a clock its corresponding entry should be To skip setting parent or rate of a clock its corresponding entry should be
set to 0, or can be omitted if it is not followed by any non-zero entry. set to 0, or can be omitted if it is not followed by any non-zero entry.
......
* Clock and reset bindings for CSR atlas7
Required properties:
- compatible: Should be "sirf,atlas7-car"
- reg: Address and length of the register set
- #clock-cells: Should be <1>
- #reset-cells: Should be <1>
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell.
The ID list atlas7_clks defined in drivers/clk/sirf/clk-atlas7.c
The reset consumer should specify the desired reset by having the reset
ID in its "reset" phandle cell.
The ID list atlas7_reset_unit defined in drivers/clk/sirf/clk-atlas7.c
Examples: Clock and reset controller node:
car: clock-controller@18620000 {
compatible = "sirf,atlas7-car";
reg = <0x18620000 0x1000>;
#clock-cells = <1>;
#reset-cells = <1>;
};
Examples: Consumers using clock or reset:
timer@10dc0000 {
compatible = "sirf,macro-tick";
reg = <0x10dc0000 0x1000>;
clocks = <&car 54>;
interrupts = <0 0 0>,
<0 1 0>,
<0 2 0>,
<0 49 0>,
<0 50 0>,
<0 51 0>;
};
uart1: uart@18020000 {
cell-index = <1>;
compatible = "sirf,macro-uart";
reg = <0x18020000 0x1000>;
clocks = <&clks 95>;
interrupts = <0 18 0>;
fifosize = <32>;
};
vpp@13110000 {
compatible = "sirf,prima2-vpp";
reg = <0x13110000 0x10000>;
interrupts = <0 31 0>;
clocks = <&car 85>;
resets = <&car 29>;
};
...@@ -52,7 +52,7 @@ usia_u0_sclk: usia_u0_sclk { ...@@ -52,7 +52,7 @@ usia_u0_sclk: usia_u0_sclk {
Example of consumer: Example of consumer:
uart@e1020000 { serial@e1020000 {
compatible = "renesas,em-uart"; compatible = "renesas,em-uart";
reg = <0xe1020000 0x38>; reg = <0xe1020000 0x38>;
interrupts = <0 8 0>; interrupts = <0 8 0>;
......
...@@ -15,8 +15,8 @@ Required properties: ...@@ -15,8 +15,8 @@ Required properties:
- compatible : shall be "ti,keystone,main-pll-clock" or "ti,keystone,pll-clock" - compatible : shall be "ti,keystone,main-pll-clock" or "ti,keystone,pll-clock"
- clocks : parent clock phandle - clocks : parent clock phandle
- reg - pll control0 and pll multipler registers - reg - pll control0 and pll multipler registers
- reg-names : control and multiplier. The multiplier is applicable only for - reg-names : control, multiplier and post-divider. The multiplier and
main pll clock post-divider registers are applicable only for main pll clock
- fixed-postdiv : fixed post divider value. If absent, use clkod register bits - fixed-postdiv : fixed post divider value. If absent, use clkod register bits
for postdiv for postdiv
...@@ -25,8 +25,8 @@ Example: ...@@ -25,8 +25,8 @@ Example:
#clock-cells = <0>; #clock-cells = <0>;
compatible = "ti,keystone,main-pll-clock"; compatible = "ti,keystone,main-pll-clock";
clocks = <&refclksys>; clocks = <&refclksys>;
reg = <0x02620350 4>, <0x02310110 4>; reg = <0x02620350 4>, <0x02310110 4>, <0x02310108 4>;
reg-names = "control", "multiplier"; reg-names = "control", "multiplier", "post-divider";
fixed-postdiv = <2>; fixed-postdiv = <2>;
}; };
......
* NXP LPC1850 Clock Control Unit (CCU)
Each CGU base clock has several clock branches which can be turned on
or off independently by the Clock Control Units CCU1 or CCU2. The
branch clocks are distributed between CCU1 and CCU2.
- Above text taken from NXP LPC1850 User Manual.
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible:
Should be "nxp,lpc1850-ccu"
- reg:
Shall define the base and range of the address space
containing clock control registers
- #clock-cells:
Shall have value <1>. The permitted clock-specifier values
are the branch clock names defined in table below.
- clocks:
Shall contain a list of phandles for the base clocks routed
from the CGU to the specific CCU. See mapping of base clocks
and CCU in table below.
- clock-names:
Shall contain a list of names for the base clock routed
from the CGU to the specific CCU. Valid CCU clock names:
"base_usb0_clk", "base_periph_clk", "base_usb1_clk",
"base_cpu_clk", "base_spifi_clk", "base_spi_clk",
"base_apb1_clk", "base_apb3_clk", "base_adchs_clk",
"base_sdio_clk", "base_ssp0_clk", "base_ssp1_clk",
"base_uart0_clk", "base_uart1_clk", "base_uart2_clk",
"base_uart3_clk", "base_audio_clk"
Which branch clocks that are available on the CCU depends on the
specific LPC part. Check the user manual for your specific part.
A list of CCU clocks can be found in dt-bindings/clock/lpc18xx-ccu.h.
Example board file:
soc {
ccu1: clock-controller@40051000 {
compatible = "nxp,lpc1850-ccu";
reg = <0x40051000 0x1000>;
#clock-cells = <1>;
clocks = <&cgu BASE_APB3_CLK>, <&cgu BASE_APB1_CLK>,
<&cgu BASE_SPIFI_CLK>, <&cgu BASE_CPU_CLK>,
<&cgu BASE_PERIPH_CLK>, <&cgu BASE_USB0_CLK>,
<&cgu BASE_USB1_CLK>, <&cgu BASE_SPI_CLK>;
clock-names = "base_apb3_clk", "base_apb1_clk",
"base_spifi_clk", "base_cpu_clk",
"base_periph_clk", "base_usb0_clk",
"base_usb1_clk", "base_spi_clk";
};
ccu2: clock-controller@40052000 {
compatible = "nxp,lpc1850-ccu";
reg = <0x40052000 0x1000>;
#clock-cells = <1>;
clocks = <&cgu BASE_AUDIO_CLK>, <&cgu BASE_UART3_CLK>,
<&cgu BASE_UART2_CLK>, <&cgu BASE_UART1_CLK>,
<&cgu BASE_UART0_CLK>, <&cgu BASE_SSP1_CLK>,
<&cgu BASE_SSP0_CLK>, <&cgu BASE_SDIO_CLK>;
clock-names = "base_audio_clk", "base_uart3_clk",
"base_uart2_clk", "base_uart1_clk",
"base_uart0_clk", "base_ssp1_clk",
"base_ssp0_clk", "base_sdio_clk";
};
/* A user of CCU brach clocks */
uart1: serial@40082000 {
...
clocks = <&ccu2 CLK_APB0_UART1>, <&ccu1 CLK_CPU_UART1>;
...
};
};
* NXP LPC1850 Clock Generation Unit (CGU)
The CGU generates multiple independent clocks for the core and the
peripheral blocks of the LPC18xx. Each independent clock is called
a base clock and itself is one of the inputs to the two Clock
Control Units (CCUs) which control the branch clocks to the
individual peripherals.
The CGU selects the inputs to the clock generators from multiple
clock sources, controls the clock generation, and routes the outputs
of the clock generators through the clock source bus to the output
stages. Each output stage provides an independent clock source and
corresponds to one of the base clocks for the LPC18xx.
- Above text taken from NXP LPC1850 User Manual.
This binding uses the common clock binding:
Documentation/devicetree/bindings/clock/clock-bindings.txt
Required properties:
- compatible:
Should be "nxp,lpc1850-cgu"
- reg:
Shall define the base and range of the address space
containing clock control registers
- #clock-cells:
Shall have value <1>. The permitted clock-specifier values
are the base clock numbers defined below.
- clocks:
Shall contain a list of phandles for the external input
sources to the CGU. The list shall be in the following
order: xtal, 32khz, enet_rx_clk, enet_tx_clk, gp_clkin.
- clock-indices:
Shall be an ordered list of numbers defining the base clock
number provided by the CGU.
- clock-output-names:
Shall be an ordered list of strings defining the names of
the clocks provided by the CGU.
Which base clocks that are available on the CGU depends on the
specific LPC part. Base clocks are numbered from 0 to 27.
Number: Name: Description:
0 BASE_SAFE_CLK Base safe clock (always on) for WWDT
1 BASE_USB0_CLK Base clock for USB0
2 BASE_PERIPH_CLK Base clock for Cortex-M0SUB subsystem,
SPI, and SGPIO
3 BASE_USB1_CLK Base clock for USB1
4 BASE_CPU_CLK System base clock for ARM Cortex-M core
and APB peripheral blocks #0 and #2
5 BASE_SPIFI_CLK Base clock for SPIFI
6 BASE_SPI_CLK Base clock for SPI
7 BASE_PHY_RX_CLK Base clock for Ethernet PHY Receive clock
8 BASE_PHY_TX_CLK Base clock for Ethernet PHY Transmit clock
9 BASE_APB1_CLK Base clock for APB peripheral block # 1
10 BASE_APB3_CLK Base clock for APB peripheral block # 3
11 BASE_LCD_CLK Base clock for LCD
12 BASE_ADCHS_CLK Base clock for ADCHS
13 BASE_SDIO_CLK Base clock for SD/MMC
14 BASE_SSP0_CLK Base clock for SSP0
15 BASE_SSP1_CLK Base clock for SSP1
16 BASE_UART0_CLK Base clock for UART0
17 BASE_UART1_CLK Base clock for UART1
18 BASE_UART2_CLK Base clock for UART2
19 BASE_UART3_CLK Base clock for UART3
20 BASE_OUT_CLK Base clock for CLKOUT pin
24-21 - Reserved
25 BASE_AUDIO_CLK Base clock for audio system (I2S)
26 BASE_CGU_OUT0_CLK Base clock for CGU_OUT0 clock output
27 BASE_CGU_OUT1_CLK Base clock for CGU_OUT1 clock output
BASE_PERIPH_CLK and BASE_SPI_CLK is only available on LPC43xx.
BASE_ADCHS_CLK is only available on LPC4370.
Example board file:
/ {
clocks {
xtal: xtal {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <12000000>;
};
xtal32: xtal32 {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
};
enet_rx_clk: enet_rx_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <0>;
clock-output-names = "enet_rx_clk";
};
enet_tx_clk: enet_tx_clk {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <0>;
clock-output-names = "enet_tx_clk";
};
gp_clkin: gp_clkin {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <0>;
clock-output-names = "gp_clkin";
};
};
soc {
cgu: clock-controller@40050000 {
compatible = "nxp,lpc1850-cgu";
reg = <0x40050000 0x1000>;
#clock-cells = <1>;
clocks = <&xtal>, <&creg_clk 1>, <&enet_rx_clk>, <&enet_tx_clk>, <&gp_clkin>;
};
/* A CGU and CCU clock consumer */
lcdc: lcdc@40008000 {
...
clocks = <&cgu BASE_LCD_CLK>, <&ccu1 CLK_CPU_LCD>;
clock-names = "clcdclk", "apb_pclk";
...
};
};
};
* Marvell PXA1928 Clock Controllers
The PXA1928 clock subsystem generates and supplies clock to various
controllers within the PXA1928 SoC. The PXA1928 contains 3 clock controller
blocks called APMU, MPMU, and APBC roughly corresponding to internal buses.
Required Properties:
- compatible: should be one of the following.
- "marvell,pxa1928-apmu" - APMU controller compatible
- "marvell,pxa1928-mpmu" - MPMU controller compatible
- "marvell,pxa1928-apbc" - APBC controller compatible
- reg: physical base address of the clock controller and length of memory mapped
region.
- #clock-cells: should be 1.
- #reset-cells: should be 1.
Each clock is assigned an identifier and client nodes use the clock controller
phandle and this identifier to specify the clock which they consume.
All these identifiers can be found in <dt-bindings/clock/marvell,pxa1928.h>.
...@@ -19,6 +19,7 @@ ID Clock Peripheral ...@@ -19,6 +19,7 @@ ID Clock Peripheral
9 pex1 PCIe Cntrl 1 9 pex1 PCIe Cntrl 1
15 sata0 SATA Host 0 15 sata0 SATA Host 0
17 sdio SDHCI Host 17 sdio SDHCI Host
23 crypto CESA (crypto engine)
25 tdm Time Division Mplx 25 tdm Time Division Mplx
28 ddr DDR Cntrl 28 ddr DDR Cntrl
30 sata1 SATA Host 0 30 sata1 SATA Host 0
......
...@@ -20,15 +20,38 @@ Required properties : ...@@ -20,15 +20,38 @@ Required properties :
- #reset-cells : Should be 1. - #reset-cells : Should be 1.
In clock consumers, this cell represents the bit number in the CAR's In clock consumers, this cell represents the bit number in the CAR's
array of CLK_RST_CONTROLLER_RST_DEVICES_* registers. array of CLK_RST_CONTROLLER_RST_DEVICES_* registers.
- nvidia,external-memory-controller : phandle of the EMC driver.
The node should contain a "emc-timings" subnode for each supported RAM type (see
field RAM_CODE in register PMC_STRAPPING_OPT_A).
Required properties for "emc-timings" nodes :
- nvidia,ram-code : Should contain the value of RAM_CODE this timing set
is used for.
Each "emc-timings" node should contain a "timing" subnode for every supported
EMC clock rate.
Required properties for "timing" nodes :
- clock-frequency : Should contain the memory clock rate to which this timing
relates.
- nvidia,parent-clock-frequency : Should contain the rate at which the current
parent of the EMC clock should be running at this timing.
- clocks : Must contain an entry for each entry in clock-names.
See ../clocks/clock-bindings.txt for details.
- clock-names : Must include the following entries:
- emc-parent : the clock that should be the parent of the EMC clock at this
timing.
Example SoC include file: Example SoC include file:
/ { / {
tegra_car: clock { tegra_car: clock@60006000 {
compatible = "nvidia,tegra124-car"; compatible = "nvidia,tegra124-car";
reg = <0x60006000 0x1000>; reg = <0x60006000 0x1000>;
#clock-cells = <1>; #clock-cells = <1>;
#reset-cells = <1>; #reset-cells = <1>;
nvidia,external-memory-controller = <&emc>;
}; };
usb@c5004000 { usb@c5004000 {
...@@ -62,4 +85,23 @@ Example board file: ...@@ -62,4 +85,23 @@ Example board file:
&tegra_car { &tegra_car {
clocks = <&clk_32k> <&osc>; clocks = <&clk_32k> <&osc>;
}; };
clock@60006000 {
emc-timings-3 {
nvidia,ram-code = <3>;
timing-12750000 {
clock-frequency = <12750000>;
nvidia,parent-clock-frequency = <408000000>;
clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
clock-names = "emc-parent";
};
timing-20400000 {
clock-frequency = <20400000>;
nvidia,parent-clock-frequency = <408000000>;
clocks = <&tegra_car TEGRA124_CLK_PLL_P>;
clock-names = "emc-parent";
};
};
};
}; };
...@@ -10,9 +10,11 @@ Required Properties: ...@@ -10,9 +10,11 @@ Required Properties:
- "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks - "renesas,r8a73a4-div6-clock" for R8A73A4 (R-Mobile APE6) DIV6 clocks
- "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks - "renesas,r8a7740-div6-clock" for R8A7740 (R-Mobile A1) DIV6 clocks
- "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks - "renesas,r8a7790-div6-clock" for R8A7790 (R-Car H2) DIV6 clocks
- "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2) DIV6 clocks - "renesas,r8a7791-div6-clock" for R8A7791 (R-Car M2-W) DIV6 clocks
- "renesas,r8a7793-div6-clock" for R8A7793 (R-Car M2-N) DIV6 clocks
- "renesas,r8a7794-div6-clock" for R8A7794 (R-Car E2) DIV6 clocks
- "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks - "renesas,sh73a0-div6-clock" for SH73A0 (SH-Mobile AG5) DIV6 clocks
- "renesas,cpg-div6-clock" for generic DIV6 clocks and "renesas,cpg-div6-clock" as a fallback.
- reg: Base address and length of the memory resource used by the DIV6 clock - reg: Base address and length of the memory resource used by the DIV6 clock
- clocks: Reference to the parent clock(s); either one, four, or eight - clocks: Reference to the parent clock(s); either one, four, or eight
clocks must be specified. For clocks with multiple parents, invalid clocks must be specified. For clocks with multiple parents, invalid
......
...@@ -13,12 +13,14 @@ Required Properties: ...@@ -13,12 +13,14 @@ Required Properties:
- "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks - "renesas,r7s72100-mstp-clocks" for R7S72100 (RZ) MSTP gate clocks
- "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks - "renesas,r8a73a4-mstp-clocks" for R8A73A4 (R-Mobile APE6) MSTP gate clocks
- "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks - "renesas,r8a7740-mstp-clocks" for R8A7740 (R-Mobile A1) MSTP gate clocks
- "renesas,r8a7778-mstp-clocks" for R8A7778 (R-Car M1) MSTP gate clocks
- "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks - "renesas,r8a7779-mstp-clocks" for R8A7779 (R-Car H1) MSTP gate clocks
- "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks - "renesas,r8a7790-mstp-clocks" for R8A7790 (R-Car H2) MSTP gate clocks
- "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2) MSTP gate clocks - "renesas,r8a7791-mstp-clocks" for R8A7791 (R-Car M2-W) MSTP gate clocks
- "renesas,r8a7793-mstp-clocks" for R8A7793 (R-Car M2-N) MSTP gate clocks
- "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks - "renesas,r8a7794-mstp-clocks" for R8A7794 (R-Car E2) MSTP gate clocks
- "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks - "renesas,sh73a0-mstp-clocks" for SH73A0 (SH-MobileAG5) MSTP gate clocks
- "renesas,cpg-mstp-clock" for generic MSTP gate clocks and "renesas,cpg-mstp-clocks" as a fallback.
- reg: Base address and length of the I/O mapped registers used by the MSTP - reg: Base address and length of the I/O mapped registers used by the MSTP
clocks. The first register is the clock control register and is mandatory. clocks. The first register is the clock control register and is mandatory.
The second register is the clock status register and is optional when not The second register is the clock status register and is optional when not
......
...@@ -10,7 +10,7 @@ Required Properties: ...@@ -10,7 +10,7 @@ Required Properties:
- "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG - "renesas,r8a7791-cpg-clocks" for the r8a7791 CPG
- "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG - "renesas,r8a7793-cpg-clocks" for the r8a7793 CPG
- "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG - "renesas,r8a7794-cpg-clocks" for the r8a7794 CPG
- "renesas,rcar-gen2-cpg-clocks" for the generic R-Car Gen2 CPG and "renesas,rcar-gen2-cpg-clocks" as a fallback.
- reg: Base address and length of the memory resource used by the CPG - reg: Base address and length of the memory resource used by the CPG
......
...@@ -7,7 +7,7 @@ Required Properties: ...@@ -7,7 +7,7 @@ Required Properties:
- compatible: Must be one of - compatible: Must be one of
- "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG - "renesas,r7s72100-cpg-clocks" for the r7s72100 CPG
- "renesas,rz-cpg-clocks" for the generic RZ CPG and "renesas,rz-cpg-clocks" as a fallback.
- reg: Base address and length of the memory resource used by the CPG - reg: Base address and length of the memory resource used by the CPG
- clocks: References to possible parent clocks. Order must match clock modes - clocks: References to possible parent clocks. Order must match clock modes
in the datasheet. For the r7s72100, this is extal, usb_x1. in the datasheet. For the r7s72100, this is extal, usb_x1.
......
STMicroelectronics STM32 Reset and Clock Controller
===================================================
The RCC IP is both a reset and a clock controller. This documentation only
describes the clock part.
Please also refer to clock-bindings.txt in this directory for common clock
controller binding usage.
Required properties:
- compatible: Should be "st,stm32f42xx-rcc"
- reg: should be register base and length as documented in the
datasheet
- #clock-cells: 2, device nodes should specify the clock in their "clocks"
property, containing a phandle to the clock device node, an index selecting
between gated clocks and other clocks and an index specifying the clock to
use.
Example:
rcc: rcc@40023800 {
#clock-cells = <2>
compatible = "st,stm32f42xx-rcc", "st,stm32-rcc";
reg = <0x40023800 0x400>;
};
Specifying gated clocks
=======================
The primary index must be set to 0.
The secondary index is the bit number within the RCC register bank, starting
from the first RCC clock enable register (RCC_AHB1ENR, address offset 0x30).
It is calculated as: index = register_offset / 4 * 32 + bit_offset.
Where bit_offset is the bit offset within the register (LSB is 0, MSB is 31).
Example:
/* Gated clock, AHB1 bit 0 (GPIOA) */
... {
clocks = <&rcc 0 0>
};
/* Gated clock, AHB2 bit 4 (CRYP) */
... {
clocks = <&rcc 0 36>
};
Specifying other clocks
=======================
The primary index must be set to 1.
The secondary index is bound with the following magic numbers:
0 SYSTICK
1 FCLK
Example:
/* Misc clock, FCLK */
... {
clocks = <&rcc 1 1>
};
...@@ -67,6 +67,7 @@ Required properties: ...@@ -67,6 +67,7 @@ Required properties:
"allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20 "allwinner,sun4i-a10-usb-clk" - for usb gates + resets on A10 / A20
"allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13 "allwinner,sun5i-a13-usb-clk" - for usb gates + resets on A13
"allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31 "allwinner,sun6i-a31-usb-clk" - for usb gates + resets on A31
"allwinner,sun8i-a23-usb-clk" - for usb gates + resets on A23
"allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80 "allwinner,sun9i-a80-usb-mod-clk" - for usb gates + resets on A80
"allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80 "allwinner,sun9i-a80-usb-phy-clk" - for usb phy gates + resets on A80
......
Binding for TO CDCE925 programmable I2C clock synthesizers.
Reference
This binding uses the common clock binding[1].
[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
[2] http://www.ti.com/product/cdce925
The driver provides clock sources for each output Y1 through Y5.
Required properties:
- compatible: Shall be "ti,cdce925"
- reg: I2C device address.
- clocks: Points to a fixed parent clock that provides the input frequency.
- #clock-cells: From common clock bindings: Shall be 1.
Optional properties:
- xtal-load-pf: Crystal load-capacitor value to fine-tune performance on a
board, or to compensate for external influences.
For both PLL1 and PLL2 an optional child node can be used to specify spread
spectrum clocking parameters for a board.
- spread-spectrum: SSC mode as defined in the data sheet.
- spread-spectrum-center: Use "centered" mode instead of "max" mode. When
present, the clock runs at the requested frequency on average. Otherwise
the requested frequency is the maximum value of the SCC range.
Example:
clockgen: cdce925pw@64 {
compatible = "cdce925";
reg = <0x64>;
clocks = <&xtal_27Mhz>;
#clock-cells = <1>;
xtal-load-pf = <5>;
/* PLL options to get SSC 1% centered */
PLL2 {
spread-spectrum = <4>;
spread-spectrum-center;
};
};
...@@ -2763,7 +2763,7 @@ F: Documentation/devicetree/bindings/media/coda.txt ...@@ -2763,7 +2763,7 @@ F: Documentation/devicetree/bindings/media/coda.txt
F: drivers/media/platform/coda/ F: drivers/media/platform/coda/
COMMON CLK FRAMEWORK COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@linaro.org> M: Michael Turquette <mturquette@baylibre.com>
M: Stephen Boyd <sboyd@codeaurora.org> M: Stephen Boyd <sboyd@codeaurora.org>
L: linux-clk@vger.kernel.org L: linux-clk@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git
......
...@@ -38,6 +38,21 @@ cpu@1 { ...@@ -38,6 +38,21 @@ cpu@1 {
}; };
}; };
clocks {
xinw {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <32768>;
clock-output-names = "xinw";
};
xin {
compatible = "fixed-clock";
#clock-cells = <0>;
clock-frequency = <26000000>;
clock-output-names = "xin";
};
};
noc { noc {
compatible = "simple-bus"; compatible = "simple-bus";
#address-cells = <1>; #address-cells = <1>;
......
...@@ -224,6 +224,25 @@ static void __init exynos_init_irq(void) ...@@ -224,6 +224,25 @@ static void __init exynos_init_irq(void)
exynos_map_pmu(); exynos_map_pmu();
} }
static const struct of_device_id exynos_cpufreq_matches[] = {
{ .compatible = "samsung,exynos4210", .data = "cpufreq-dt" },
{ /* sentinel */ }
};
static void __init exynos_cpufreq_init(void)
{
struct device_node *root = of_find_node_by_path("/");
const struct of_device_id *match;
match = of_match_node(exynos_cpufreq_matches, root);
if (!match) {
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
return;
}
platform_device_register_simple(match->data, -1, NULL, 0);
}
static void __init exynos_dt_machine_init(void) static void __init exynos_dt_machine_init(void)
{ {
/* /*
...@@ -246,7 +265,7 @@ static void __init exynos_dt_machine_init(void) ...@@ -246,7 +265,7 @@ static void __init exynos_dt_machine_init(void)
of_machine_is_compatible("samsung,exynos5250")) of_machine_is_compatible("samsung,exynos5250"))
platform_device_register(&exynos_cpuidle); platform_device_register(&exynos_cpuidle);
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0); exynos_cpufreq_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL); of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
} }
......
...@@ -78,6 +78,23 @@ config COMMON_CLK_SI570 ...@@ -78,6 +78,23 @@ config COMMON_CLK_SI570
This driver supports Silicon Labs 570/571/598/599 programmable This driver supports Silicon Labs 570/571/598/599 programmable
clock generators. clock generators.
config COMMON_CLK_CDCE925
tristate "Clock driver for TI CDCE925 devices"
depends on I2C
depends on OF
select REGMAP_I2C
help
---help---
This driver supports the TI CDCE925 programmable clock synthesizer.
The chip contains two PLLs with spread-spectrum clocking support and
five output dividers. The driver only supports the following setup,
and uses a fixed setting for the output muxes.
Y1 is derived from the input clock
Y2 and Y3 derive from PLL1
Y4 and Y5 derive from PLL2
Given a target output frequency, the driver will set the PLL and
divider to best approximate the desired output.
config COMMON_CLK_S2MPS11 config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS1X/S5M8767 MFD" tristate "Clock driver for S2MPS1X/S5M8767 MFD"
depends on MFD_SEC_CORE depends on MFD_SEC_CORE
...@@ -150,11 +167,13 @@ config COMMON_CLK_CDCE706 ...@@ -150,11 +167,13 @@ config COMMON_CLK_CDCE706
---help--- ---help---
This driver supports TI CDCE706 programmable 3-PLL clock synthesizer. This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/hisilicon/Kconfig"
source "drivers/clk/qcom/Kconfig" source "drivers/clk/qcom/Kconfig"
endmenu endmenu
source "drivers/clk/bcm/Kconfig"
source "drivers/clk/mvebu/Kconfig" source "drivers/clk/mvebu/Kconfig"
source "drivers/clk/samsung/Kconfig" source "drivers/clk/samsung/Kconfig"
source "drivers/clk/tegra/Kconfig"
...@@ -38,6 +38,8 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o ...@@ -38,6 +38,8 @@ obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
obj-$(CONFIG_COMMON_CLK_CDCE925) += clk-cdce925.o
obj-$(CONFIG_ARCH_STM32) += clk-stm32f4.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_ARCH_U300) += clk-u300.o obj-$(CONFIG_ARCH_U300) += clk-u300.o
obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o obj-$(CONFIG_ARCH_VT8500) += clk-vt8500.o
...@@ -45,19 +47,20 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o ...@@ -45,19 +47,20 @@ obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o obj-$(CONFIG_COMMON_CLK_XGENE) += clk-xgene.o
obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o obj-$(CONFIG_COMMON_CLK_PWM) += clk-pwm.o
obj-$(CONFIG_COMMON_CLK_AT91) += at91/ obj-$(CONFIG_COMMON_CLK_AT91) += at91/
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm/ obj-$(CONFIG_ARCH_BCM) += bcm/
obj-$(CONFIG_ARCH_BERLIN) += berlin/ obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-$(CONFIG_ARCH_HI3xxx) += hisilicon/ obj-$(CONFIG_ARCH_HISI) += hisilicon/
obj-$(CONFIG_ARCH_HIP04) += hisilicon/
obj-$(CONFIG_ARCH_HIX5HD2) += hisilicon/
obj-$(CONFIG_ARCH_MXC) += imx/ obj-$(CONFIG_ARCH_MXC) += imx/
obj-$(CONFIG_MACH_INGENIC) += ingenic/ obj-$(CONFIG_MACH_INGENIC) += ingenic/
obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/ obj-$(CONFIG_COMMON_CLK_KEYSTONE) += keystone/
obj-$(CONFIG_ARCH_MEDIATEK) += mediatek/
ifeq ($(CONFIG_COMMON_CLK), y) ifeq ($(CONFIG_COMMON_CLK), y)
obj-$(CONFIG_ARCH_MMP) += mmp/ obj-$(CONFIG_ARCH_MMP) += mmp/
endif endif
obj-$(CONFIG_PLAT_ORION) += mvebu/ obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_MESON) += meson/
obj-$(CONFIG_ARCH_MXS) += mxs/ obj-$(CONFIG_ARCH_MXS) += mxs/
obj-$(CONFIG_ARCH_LPC18XX) += nxp/
obj-$(CONFIG_MACH_PISTACHIO) += pistachio/ obj-$(CONFIG_MACH_PISTACHIO) += pistachio/
obj-$(CONFIG_COMMON_CLK_PXA) += pxa/ obj-$(CONFIG_COMMON_CLK_PXA) += pxa/
obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/ obj-$(CONFIG_COMMON_CLK_QCOM) += qcom/
......
...@@ -614,7 +614,7 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np, ...@@ -614,7 +614,7 @@ void __init of_at91sam9x5_clk_main_setup(struct device_node *np,
const char *name = np->name; const char *name = np->name;
int i; int i;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > 2) if (num_parents <= 0 || num_parents > 2)
return; return;
......
...@@ -224,7 +224,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -224,7 +224,7 @@ of_at91_clk_master_setup(struct device_node *np, struct at91_pmc *pmc,
const char *name = np->name; const char *name = np->name;
struct clk_master_characteristics *characteristics; struct clk_master_characteristics *characteristics;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX) if (num_parents <= 0 || num_parents > MASTER_SOURCE_MAX)
return; return;
......
...@@ -237,7 +237,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc, ...@@ -237,7 +237,7 @@ of_at91_clk_prog_setup(struct device_node *np, struct at91_pmc *pmc,
const char *name; const char *name;
struct device_node *progclknp; struct device_node *progclknp;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX) if (num_parents <= 0 || num_parents > PROG_SOURCE_MAX)
return; return;
......
...@@ -373,7 +373,7 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np, ...@@ -373,7 +373,7 @@ void __init of_at91sam9x5_clk_slow_setup(struct device_node *np,
const char *name = np->name; const char *name = np->name;
int i; int i;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > 2) if (num_parents <= 0 || num_parents > 2)
return; return;
...@@ -451,7 +451,7 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np, ...@@ -451,7 +451,7 @@ void __init of_at91sam9260_clk_slow_setup(struct device_node *np,
const char *name = np->name; const char *name = np->name;
int i; int i;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents != 2) if (num_parents != 2)
return; return;
......
...@@ -150,7 +150,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np, ...@@ -150,7 +150,7 @@ void __init of_at91sam9x5_clk_smd_setup(struct device_node *np,
const char *parent_names[SMD_SOURCE_MAX]; const char *parent_names[SMD_SOURCE_MAX];
const char *name = np->name; const char *name = np->name;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX) if (num_parents <= 0 || num_parents > SMD_SOURCE_MAX)
return; return;
......
...@@ -378,7 +378,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np, ...@@ -378,7 +378,7 @@ void __init of_at91sam9x5_clk_usb_setup(struct device_node *np,
const char *parent_names[USB_SOURCE_MAX]; const char *parent_names[USB_SOURCE_MAX];
const char *name = np->name; const char *name = np->name;
num_parents = of_count_phandle_with_args(np, "clocks", "#clock-cells"); num_parents = of_clk_get_parent_count(np);
if (num_parents <= 0 || num_parents > USB_SOURCE_MAX) if (num_parents <= 0 || num_parents > USB_SOURCE_MAX)
return; return;
......
...@@ -153,7 +153,7 @@ static int pmc_irq_domain_xlate(struct irq_domain *d, ...@@ -153,7 +153,7 @@ static int pmc_irq_domain_xlate(struct irq_domain *d,
return 0; return 0;
} }
static struct irq_domain_ops pmc_irq_ops = { static const struct irq_domain_ops pmc_irq_ops = {
.map = pmc_irq_map, .map = pmc_irq_map,
.xlate = pmc_irq_domain_xlate, .xlate = pmc_irq_domain_xlate,
}; };
......
...@@ -7,3 +7,12 @@ config CLK_BCM_KONA ...@@ -7,3 +7,12 @@ config CLK_BCM_KONA
Enable common clock framework support for Broadcom SoCs Enable common clock framework support for Broadcom SoCs
using "Kona" style clock control units, including those using "Kona" style clock control units, including those
in the BCM281xx and BCM21664 families. in the BCM281xx and BCM21664 families.
config COMMON_CLK_IPROC
bool "Broadcom iProc clock support"
depends on ARCH_BCM_IPROC
depends on COMMON_CLK
default ARCH_BCM_IPROC
help
Enable common clock framework support for Broadcom SoCs
based on the iProc architecture
...@@ -2,3 +2,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o ...@@ -2,3 +2,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-kona.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o obj-$(CONFIG_CLK_BCM_KONA) += clk-kona-setup.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281xx.o
obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
/*
* Copyright (C) 2014 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <dt-bindings/clock/bcm-cygnus.h>
#include "clk-iproc.h"
#define reg_val(o, s, w) { .offset = o, .shift = s, .width = w, }
#define aon_val(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
.pwr_shift = ps, .iso_shift = is }
#define sw_ctrl_val(o, s) { .offset = o, .shift = s, }
#define asiu_div_val(o, es, hs, hw, ls, lw) \
{ .offset = o, .en_shift = es, .high_shift = hs, \
.high_width = hw, .low_shift = ls, .low_width = lw }
#define reset_val(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
.reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
.ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
.ka_width = kaw }
#define vco_ctrl_val(uo, lo) { .u_offset = uo, .l_offset = lo }
#define enable_val(o, es, hs, bs) { .offset = o, .enable_shift = es, \
.hold_shift = hs, .bypass_shift = bs }
#define asiu_gate_val(o, es) { .offset = o, .en_shift = es }
static void __init cygnus_armpll_init(struct device_node *node)
{
iproc_armpll_setup(node);
}
CLK_OF_DECLARE(cygnus_armpll, "brcm,cygnus-armpll", cygnus_armpll_init);
static const struct iproc_pll_ctrl genpll = {
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
IPROC_CLK_PLL_NEEDS_SW_CFG,
.aon = aon_val(0x0, 2, 1, 0),
.reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
.sw_ctrl = sw_ctrl_val(0x10, 31),
.ndiv_int = reg_val(0x10, 20, 10),
.ndiv_frac = reg_val(0x10, 0, 20),
.pdiv = reg_val(0x14, 0, 4),
.vco_ctrl = vco_ctrl_val(0x18, 0x1c),
.status = reg_val(0x28, 12, 1),
};
static const struct iproc_clk_ctrl genpll_clk[] = {
[BCM_CYGNUS_GENPLL_AXI21_CLK] = {
.channel = BCM_CYGNUS_GENPLL_AXI21_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 6, 0, 12),
.mdiv = reg_val(0x20, 0, 8),
},
[BCM_CYGNUS_GENPLL_250MHZ_CLK] = {
.channel = BCM_CYGNUS_GENPLL_250MHZ_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 7, 1, 13),
.mdiv = reg_val(0x20, 10, 8),
},
[BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = {
.channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 8, 2, 14),
.mdiv = reg_val(0x20, 20, 8),
},
[BCM_CYGNUS_GENPLL_ENET_SW_CLK] = {
.channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 9, 3, 15),
.mdiv = reg_val(0x24, 0, 8),
},
[BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = {
.channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 10, 4, 16),
.mdiv = reg_val(0x24, 10, 8),
},
[BCM_CYGNUS_GENPLL_CAN_CLK] = {
.channel = BCM_CYGNUS_GENPLL_CAN_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x4, 11, 5, 17),
.mdiv = reg_val(0x24, 20, 8),
},
};
static void __init cygnus_genpll_clk_init(struct device_node *node)
{
iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk,
ARRAY_SIZE(genpll_clk));
}
CLK_OF_DECLARE(cygnus_genpll, "brcm,cygnus-genpll", cygnus_genpll_clk_init);
static const struct iproc_pll_ctrl lcpll0 = {
.flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
.aon = aon_val(0x0, 2, 5, 4),
.reset = reset_val(0x0, 31, 30, 27, 3, 23, 4, 19, 4),
.sw_ctrl = sw_ctrl_val(0x4, 31),
.ndiv_int = reg_val(0x4, 16, 10),
.pdiv = reg_val(0x4, 26, 4),
.vco_ctrl = vco_ctrl_val(0x10, 0x14),
.status = reg_val(0x18, 12, 1),
};
static const struct iproc_clk_ctrl lcpll0_clk[] = {
[BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = {
.channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 7, 1, 13),
.mdiv = reg_val(0x8, 0, 8),
},
[BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = {
.channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 8, 2, 14),
.mdiv = reg_val(0x8, 10, 8),
},
[BCM_CYGNUS_LCPLL0_SDIO_CLK] = {
.channel = BCM_CYGNUS_LCPLL0_SDIO_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 9, 3, 15),
.mdiv = reg_val(0x8, 20, 8),
},
[BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = {
.channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 10, 4, 16),
.mdiv = reg_val(0xc, 0, 8),
},
[BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = {
.channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 11, 5, 17),
.mdiv = reg_val(0xc, 10, 8),
},
[BCM_CYGNUS_LCPLL0_CH5_UNUSED] = {
.channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED,
.flags = IPROC_CLK_AON,
.enable = enable_val(0x0, 12, 6, 18),
.mdiv = reg_val(0xc, 20, 8),
},
};
static void __init cygnus_lcpll0_clk_init(struct device_node *node)
{
iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
ARRAY_SIZE(lcpll0_clk));
}
CLK_OF_DECLARE(cygnus_lcpll0, "brcm,cygnus-lcpll0", cygnus_lcpll0_clk_init);
/*
* MIPI PLL VCO frequency parameter table
*/
static const struct iproc_pll_vco_param mipipll_vco_params[] = {
/* rate (Hz) ndiv_int ndiv_frac pdiv */
{ 750000000UL, 30, 0, 1 },
{ 1000000000UL, 40, 0, 1 },
{ 1350000000ul, 54, 0, 1 },
{ 2000000000UL, 80, 0, 1 },
{ 2100000000UL, 84, 0, 1 },
{ 2250000000UL, 90, 0, 1 },
{ 2500000000UL, 100, 0, 1 },
{ 2700000000UL, 54, 0, 0 },
{ 2975000000UL, 119, 0, 1 },
{ 3100000000UL, 124, 0, 1 },
{ 3150000000UL, 126, 0, 1 },
};
static const struct iproc_pll_ctrl mipipll = {
.flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC |
IPROC_CLK_NEEDS_READ_BACK,
.aon = aon_val(0x0, 4, 17, 16),
.asiu = asiu_gate_val(0x0, 3),
.reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 4),
.ndiv_int = reg_val(0x10, 20, 10),
.ndiv_frac = reg_val(0x10, 0, 20),
.pdiv = reg_val(0x14, 0, 4),
.vco_ctrl = vco_ctrl_val(0x18, 0x1c),
.status = reg_val(0x28, 12, 1),
};
static const struct iproc_clk_ctrl mipipll_clk[] = {
[BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = {
.channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 12, 6, 18),
.mdiv = reg_val(0x20, 0, 8),
},
[BCM_CYGNUS_MIPIPLL_CH1_LCD] = {
.channel = BCM_CYGNUS_MIPIPLL_CH1_LCD,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 13, 7, 19),
.mdiv = reg_val(0x20, 10, 8),
},
[BCM_CYGNUS_MIPIPLL_CH2_V3D] = {
.channel = BCM_CYGNUS_MIPIPLL_CH2_V3D,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 14, 8, 20),
.mdiv = reg_val(0x20, 20, 8),
},
[BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = {
.channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 15, 9, 21),
.mdiv = reg_val(0x24, 0, 8),
},
[BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = {
.channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 16, 10, 22),
.mdiv = reg_val(0x24, 10, 8),
},
[BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = {
.channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED,
.flags = IPROC_CLK_NEEDS_READ_BACK,
.enable = enable_val(0x4, 17, 11, 23),
.mdiv = reg_val(0x24, 20, 8),
},
};
static void __init cygnus_mipipll_clk_init(struct device_node *node)
{
iproc_pll_clk_setup(node, &mipipll, mipipll_vco_params,
ARRAY_SIZE(mipipll_vco_params), mipipll_clk,
ARRAY_SIZE(mipipll_clk));
}
CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init);
static const struct iproc_asiu_div asiu_div[] = {
[BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_div_val(0x0, 31, 16, 10, 0, 10),
[BCM_CYGNUS_ASIU_ADC_CLK] = asiu_div_val(0x4, 31, 16, 10, 0, 10),
[BCM_CYGNUS_ASIU_PWM_CLK] = asiu_div_val(0x8, 31, 16, 10, 0, 10),
};
static const struct iproc_asiu_gate asiu_gate[] = {
[BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_gate_val(0x0, 7),
[BCM_CYGNUS_ASIU_ADC_CLK] = asiu_gate_val(0x0, 9),
[BCM_CYGNUS_ASIU_PWM_CLK] = asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0),
};
static void __init cygnus_asiu_init(struct device_node *node)
{
iproc_asiu_setup(node, asiu_div, asiu_gate, ARRAY_SIZE(asiu_div));
}
CLK_OF_DECLARE(cygnus_asiu_clk, "brcm,cygnus-asiu-clk", cygnus_asiu_init);
/*
* Copyright (C) 2014 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
#define IPROC_CLK_MAX_FREQ_POLICY 0x3
#define IPROC_CLK_POLICY_FREQ_OFFSET 0x008
#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT 8
#define IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK 0x7
#define IPROC_CLK_PLLARMA_OFFSET 0xc00
#define IPROC_CLK_PLLARMA_LOCK_SHIFT 28
#define IPROC_CLK_PLLARMA_PDIV_SHIFT 24
#define IPROC_CLK_PLLARMA_PDIV_MASK 0xf
#define IPROC_CLK_PLLARMA_NDIV_INT_SHIFT 8
#define IPROC_CLK_PLLARMA_NDIV_INT_MASK 0x3ff
#define IPROC_CLK_PLLARMB_OFFSET 0xc04
#define IPROC_CLK_PLLARMB_NDIV_FRAC_MASK 0xfffff
#define IPROC_CLK_PLLARMC_OFFSET 0xc08
#define IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT 8
#define IPROC_CLK_PLLARMC_MDIV_MASK 0xff
#define IPROC_CLK_PLLARMCTL5_OFFSET 0xc20
#define IPROC_CLK_PLLARMCTL5_H_MDIV_MASK 0xff
#define IPROC_CLK_PLLARM_OFFSET_OFFSET 0xc24
#define IPROC_CLK_PLLARM_SW_CTL_SHIFT 29
#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT 20
#define IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK 0xff
#define IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK 0xfffff
#define IPROC_CLK_ARM_DIV_OFFSET 0xe00
#define IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT 4
#define IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK 0xf
#define IPROC_CLK_POLICY_DBG_OFFSET 0xec0
#define IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT 12
#define IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK 0x7
enum iproc_arm_pll_fid {
ARM_PLL_FID_CRYSTAL_CLK = 0,
ARM_PLL_FID_SYS_CLK = 2,
ARM_PLL_FID_CH0_SLOW_CLK = 6,
ARM_PLL_FID_CH1_FAST_CLK = 7
};
struct iproc_arm_pll {
struct clk_hw hw;
void __iomem *base;
unsigned long rate;
};
#define to_iproc_arm_pll(hw) container_of(hw, struct iproc_arm_pll, hw)
static unsigned int __get_fid(struct iproc_arm_pll *pll)
{
u32 val;
unsigned int policy, fid, active_fid;
val = readl(pll->base + IPROC_CLK_ARM_DIV_OFFSET);
if (val & (1 << IPROC_CLK_ARM_DIV_PLL_SELECT_OVERRIDE_SHIFT))
policy = val & IPROC_CLK_ARM_DIV_ARM_PLL_SELECT_MASK;
else
policy = 0;
/* something is seriously wrong */
BUG_ON(policy > IPROC_CLK_MAX_FREQ_POLICY);
val = readl(pll->base + IPROC_CLK_POLICY_FREQ_OFFSET);
fid = (val >> (IPROC_CLK_POLICY_FREQ_POLICY_FREQ_SHIFT * policy)) &
IPROC_CLK_POLICY_FREQ_POLICY_FREQ_MASK;
val = readl(pll->base + IPROC_CLK_POLICY_DBG_OFFSET);
active_fid = IPROC_CLK_POLICY_DBG_ACT_FREQ_MASK &
(val >> IPROC_CLK_POLICY_DBG_ACT_FREQ_SHIFT);
if (fid != active_fid) {
pr_debug("%s: fid override %u->%u\n", __func__, fid,
active_fid);
fid = active_fid;
}
pr_debug("%s: active fid: %u\n", __func__, fid);
return fid;
}
/*
* Determine the mdiv (post divider) based on the frequency ID being used.
* There are 4 sources that can be used to derive the output clock rate:
* - 25 MHz Crystal
* - System clock
* - PLL channel 0 (slow clock)
* - PLL channel 1 (fast clock)
*/
static int __get_mdiv(struct iproc_arm_pll *pll)
{
unsigned int fid;
int mdiv;
u32 val;
fid = __get_fid(pll);
switch (fid) {
case ARM_PLL_FID_CRYSTAL_CLK:
case ARM_PLL_FID_SYS_CLK:
mdiv = 1;
break;
case ARM_PLL_FID_CH0_SLOW_CLK:
val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
mdiv = val & IPROC_CLK_PLLARMC_MDIV_MASK;
if (mdiv == 0)
mdiv = 256;
break;
case ARM_PLL_FID_CH1_FAST_CLK:
val = readl(pll->base + IPROC_CLK_PLLARMCTL5_OFFSET);
mdiv = val & IPROC_CLK_PLLARMCTL5_H_MDIV_MASK;
if (mdiv == 0)
mdiv = 256;
break;
default:
mdiv = -EFAULT;
}
return mdiv;
}
static unsigned int __get_ndiv(struct iproc_arm_pll *pll)
{
u32 val;
unsigned int ndiv_int, ndiv_frac, ndiv;
val = readl(pll->base + IPROC_CLK_PLLARM_OFFSET_OFFSET);
if (val & (1 << IPROC_CLK_PLLARM_SW_CTL_SHIFT)) {
/*
* offset mode is active. Read the ndiv from the PLLARM OFFSET
* register
*/
ndiv_int = (val >> IPROC_CLK_PLLARM_NDIV_INT_OFFSET_SHIFT) &
IPROC_CLK_PLLARM_NDIV_INT_OFFSET_MASK;
if (ndiv_int == 0)
ndiv_int = 256;
ndiv_frac = val & IPROC_CLK_PLLARM_NDIV_FRAC_OFFSET_MASK;
} else {
/* offset mode not active */
val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
ndiv_int = (val >> IPROC_CLK_PLLARMA_NDIV_INT_SHIFT) &
IPROC_CLK_PLLARMA_NDIV_INT_MASK;
if (ndiv_int == 0)
ndiv_int = 1024;
val = readl(pll->base + IPROC_CLK_PLLARMB_OFFSET);
ndiv_frac = val & IPROC_CLK_PLLARMB_NDIV_FRAC_MASK;
}
ndiv = (ndiv_int << 20) | ndiv_frac;
return ndiv;
}
/*
* The output frequency of the ARM PLL is calculated based on the ARM PLL
* divider values:
* pdiv = ARM PLL pre-divider
* ndiv = ARM PLL multiplier
* mdiv = ARM PLL post divider
*
* The frequency is calculated by:
* ((ndiv * parent clock rate) / pdiv) / mdiv
*/
static unsigned long iproc_arm_pll_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct iproc_arm_pll *pll = to_iproc_arm_pll(hw);
u32 val;
int mdiv;
u64 ndiv;
unsigned int pdiv;
/* in bypass mode, use parent rate */
val = readl(pll->base + IPROC_CLK_PLLARMC_OFFSET);
if (val & (1 << IPROC_CLK_PLLARMC_BYPCLK_EN_SHIFT)) {
pll->rate = parent_rate;
return pll->rate;
}
/* PLL needs to be locked */
val = readl(pll->base + IPROC_CLK_PLLARMA_OFFSET);
if (!(val & (1 << IPROC_CLK_PLLARMA_LOCK_SHIFT))) {
pll->rate = 0;
return 0;
}
pdiv = (val >> IPROC_CLK_PLLARMA_PDIV_SHIFT) &
IPROC_CLK_PLLARMA_PDIV_MASK;
if (pdiv == 0)
pdiv = 16;
ndiv = __get_ndiv(pll);
mdiv = __get_mdiv(pll);
if (mdiv <= 0) {
pll->rate = 0;
return 0;
}
pll->rate = (ndiv * parent_rate) >> 20;
pll->rate = (pll->rate / pdiv) / mdiv;
pr_debug("%s: ARM PLL rate: %lu. parent rate: %lu\n", __func__,
pll->rate, parent_rate);
pr_debug("%s: ndiv_int: %u, pdiv: %u, mdiv: %d\n", __func__,
(unsigned int)(ndiv >> 20), pdiv, mdiv);
return pll->rate;
}
static const struct clk_ops iproc_arm_pll_ops = {
.recalc_rate = iproc_arm_pll_recalc_rate,
};
void __init iproc_armpll_setup(struct device_node *node)
{
int ret;
struct clk *clk;
struct iproc_arm_pll *pll;
struct clk_init_data init;
const char *parent_name;
pll = kzalloc(sizeof(*pll), GFP_KERNEL);
if (WARN_ON(!pll))
return;
pll->base = of_iomap(node, 0);
if (WARN_ON(!pll->base))
goto err_free_pll;
init.name = node->name;
init.ops = &iproc_arm_pll_ops;
init.flags = 0;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
pll->hw.init = &init;
clk = clk_register(NULL, &pll->hw);
if (WARN_ON(IS_ERR(clk)))
goto err_iounmap;
ret = of_clk_add_provider(node, of_clk_src_simple_get, clk);
if (WARN_ON(ret))
goto err_clk_unregister;
return;
err_clk_unregister:
clk_unregister(clk);
err_iounmap:
iounmap(pll->base);
err_free_pll:
kfree(pll);
}
/*
* Copyright (C) 2014 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
#include <linux/err.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include "clk-iproc.h"
struct iproc_asiu;
struct iproc_asiu_clk {
struct clk_hw hw;
const char *name;
struct iproc_asiu *asiu;
unsigned long rate;
struct iproc_asiu_div div;
struct iproc_asiu_gate gate;
};
struct iproc_asiu {
void __iomem *div_base;
void __iomem *gate_base;
struct clk_onecell_data clk_data;
struct iproc_asiu_clk *clks;
};
#define to_asiu_clk(hw) container_of(hw, struct iproc_asiu_clk, hw)
static int iproc_asiu_clk_enable(struct clk_hw *hw)
{
struct iproc_asiu_clk *clk = to_asiu_clk(hw);
struct iproc_asiu *asiu = clk->asiu;
u32 val;
/* some clocks at the ASIU level are always enabled */
if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
return 0;
val = readl(asiu->gate_base + clk->gate.offset);
val |= (1 << clk->gate.en_shift);
writel(val, asiu->gate_base + clk->gate.offset);
return 0;
}
static void iproc_asiu_clk_disable(struct clk_hw *hw)
{
struct iproc_asiu_clk *clk = to_asiu_clk(hw);
struct iproc_asiu *asiu = clk->asiu;
u32 val;
/* some clocks at the ASIU level are always enabled */
if (clk->gate.offset == IPROC_CLK_INVALID_OFFSET)
return;
val = readl(asiu->gate_base + clk->gate.offset);
val &= ~(1 << clk->gate.en_shift);
writel(val, asiu->gate_base + clk->gate.offset);
}
static unsigned long iproc_asiu_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct iproc_asiu_clk *clk = to_asiu_clk(hw);
struct iproc_asiu *asiu = clk->asiu;
u32 val;
unsigned int div_h, div_l;
if (parent_rate == 0) {
clk->rate = 0;
return 0;
}
/* if clock divisor is not enabled, simply return parent rate */
val = readl(asiu->div_base + clk->div.offset);
if ((val & (1 << clk->div.en_shift)) == 0) {
clk->rate = parent_rate;
return parent_rate;
}
/* clock rate = parent rate / (high_div + 1) + (low_div + 1) */
div_h = (val >> clk->div.high_shift) & bit_mask(clk->div.high_width);
div_h++;
div_l = (val >> clk->div.low_shift) & bit_mask(clk->div.low_width);
div_l++;
clk->rate = parent_rate / (div_h + div_l);
pr_debug("%s: rate: %lu. parent rate: %lu div_h: %u div_l: %u\n",
__func__, clk->rate, parent_rate, div_h, div_l);
return clk->rate;
}
static long iproc_asiu_clk_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *parent_rate)
{
unsigned int div;
if (rate == 0 || *parent_rate == 0)
return -EINVAL;
if (rate == *parent_rate)
return *parent_rate;
div = DIV_ROUND_UP(*parent_rate, rate);
if (div < 2)
return *parent_rate;
return *parent_rate / div;
}
static int iproc_asiu_clk_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct iproc_asiu_clk *clk = to_asiu_clk(hw);
struct iproc_asiu *asiu = clk->asiu;
unsigned int div, div_h, div_l;
u32 val;
if (rate == 0 || parent_rate == 0)
return -EINVAL;
/* simply disable the divisor if one wants the same rate as parent */
if (rate == parent_rate) {
val = readl(asiu->div_base + clk->div.offset);
val &= ~(1 << clk->div.en_shift);
writel(val, asiu->div_base + clk->div.offset);
return 0;
}
div = DIV_ROUND_UP(parent_rate, rate);
if (div < 2)
return -EINVAL;
div_h = div_l = div >> 1;
div_h--;
div_l--;
val = readl(asiu->div_base + clk->div.offset);
val |= 1 << clk->div.en_shift;
if (div_h) {
val &= ~(bit_mask(clk->div.high_width)
<< clk->div.high_shift);
val |= div_h << clk->div.high_shift;
} else {
val &= ~(bit_mask(clk->div.high_width)
<< clk->div.high_shift);
}
if (div_l) {
val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
val |= div_l << clk->div.low_shift;
} else {
val &= ~(bit_mask(clk->div.low_width) << clk->div.low_shift);
}
writel(val, asiu->div_base + clk->div.offset);
return 0;
}
static const struct clk_ops iproc_asiu_ops = {
.enable = iproc_asiu_clk_enable,
.disable = iproc_asiu_clk_disable,
.recalc_rate = iproc_asiu_clk_recalc_rate,
.round_rate = iproc_asiu_clk_round_rate,
.set_rate = iproc_asiu_clk_set_rate,
};
void __init iproc_asiu_setup(struct device_node *node,
const struct iproc_asiu_div *div,
const struct iproc_asiu_gate *gate,
unsigned int num_clks)
{
int i, ret;
struct iproc_asiu *asiu;
if (WARN_ON(!gate || !div))
return;
asiu = kzalloc(sizeof(*asiu), GFP_KERNEL);
if (WARN_ON(!asiu))
return;
asiu->clk_data.clk_num = num_clks;
asiu->clk_data.clks = kcalloc(num_clks, sizeof(*asiu->clk_data.clks),
GFP_KERNEL);
if (WARN_ON(!asiu->clk_data.clks))
goto err_clks;
asiu->clks = kcalloc(num_clks, sizeof(*asiu->clks), GFP_KERNEL);
if (WARN_ON(!asiu->clks))
goto err_asiu_clks;
asiu->div_base = of_iomap(node, 0);
if (WARN_ON(!asiu->div_base))
goto err_iomap_div;
asiu->gate_base = of_iomap(node, 1);
if (WARN_ON(!asiu->gate_base))
goto err_iomap_gate;
for (i = 0; i < num_clks; i++) {
struct clk_init_data init;
struct clk *clk;
const char *parent_name;
struct iproc_asiu_clk *asiu_clk;
const char *clk_name;
clk_name = kzalloc(IPROC_CLK_NAME_LEN, GFP_KERNEL);
if (WARN_ON(!clk_name))
goto err_clk_register;
ret = of_property_read_string_index(node, "clock-output-names",
i, &clk_name);
if (WARN_ON(ret))
goto err_clk_register;
asiu_clk = &asiu->clks[i];
asiu_clk->name = clk_name;
asiu_clk->asiu = asiu;
asiu_clk->div = div[i];
asiu_clk->gate = gate[i];
init.name = clk_name;
init.ops = &iproc_asiu_ops;
init.flags = 0;
parent_name = of_clk_get_parent_name(node, 0);
init.parent_names = (parent_name ? &parent_name : NULL);
init.num_parents = (parent_name ? 1 : 0);
asiu_clk->hw.init = &init;
clk = clk_register(NULL, &asiu_clk->hw);
if (WARN_ON(IS_ERR(clk)))
goto err_clk_register;
asiu->clk_data.clks[i] = clk;
}
ret = of_clk_add_provider(node, of_clk_src_onecell_get,
&asiu->clk_data);
if (WARN_ON(ret))
goto err_clk_register;
return;
err_clk_register:
for (i = 0; i < num_clks; i++)
kfree(asiu->clks[i].name);
iounmap(asiu->gate_base);
err_iomap_gate:
iounmap(asiu->div_base);
err_iomap_div:
kfree(asiu->clks);
err_asiu_clks:
kfree(asiu->clk_data.clks);
err_clks:
kfree(asiu);
}
This diff is collapsed.
/*
* Copyright (C) 2014 Broadcom Corporation
*
* 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 version 2.
*
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
* kind, whether express or implied; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _CLK_IPROC_H
#define _CLK_IPROC_H
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/of.h>
#include <linux/clk-provider.h>
#define IPROC_CLK_NAME_LEN 25
#define IPROC_CLK_INVALID_OFFSET 0xffffffff
#define bit_mask(width) ((1 << (width)) - 1)
/* clocks that should not be disabled at runtime */
#define IPROC_CLK_AON BIT(0)
/* PLL that requires gating through ASIU */
#define IPROC_CLK_PLL_ASIU BIT(1)
/* PLL that has fractional part of the NDIV */
#define IPROC_CLK_PLL_HAS_NDIV_FRAC BIT(2)
/*
* Some of the iProc PLL/clocks may have an ASIC bug that requires read back
* of the same register following the write to flush the write transaction into
* the intended register
*/
#define IPROC_CLK_NEEDS_READ_BACK BIT(3)
/*
* Some PLLs require the PLL SW override bit to be set before changes can be
* applied to the PLL
*/
#define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4)
/*
* Parameters for VCO frequency configuration
*
* VCO frequency =
* ((ndiv_int + ndiv_frac / 2^20) * (ref freqeuncy / pdiv)
*/
struct iproc_pll_vco_param {
unsigned long rate;
unsigned int ndiv_int;
unsigned int ndiv_frac;
unsigned int pdiv;
};
struct iproc_clk_reg_op {
unsigned int offset;
unsigned int shift;
unsigned int width;
};
/*
* Clock gating control at the top ASIU level
*/
struct iproc_asiu_gate {
unsigned int offset;
unsigned int en_shift;
};
/*
* Control of powering on/off of a PLL
*
* Before powering off a PLL, input isolation (ISO) needs to be enabled
*/
struct iproc_pll_aon_pwr_ctrl {
unsigned int offset;
unsigned int pwr_width;
unsigned int pwr_shift;
unsigned int iso_shift;
};
/*
* Control of the PLL reset, with Ki, Kp, and Ka parameters
*/
struct iproc_pll_reset_ctrl {
unsigned int offset;
unsigned int reset_shift;
unsigned int p_reset_shift;
unsigned int ki_shift;
unsigned int ki_width;
unsigned int kp_shift;
unsigned int kp_width;
unsigned int ka_shift;
unsigned int ka_width;
};
/*
* To enable SW control of the PLL
*/
struct iproc_pll_sw_ctrl {
unsigned int offset;
unsigned int shift;
};
struct iproc_pll_vco_ctrl {
unsigned int u_offset;
unsigned int l_offset;
};
/*
* Main PLL control parameters
*/
struct iproc_pll_ctrl {
unsigned long flags;
struct iproc_pll_aon_pwr_ctrl aon;
struct iproc_asiu_gate asiu;
struct iproc_pll_reset_ctrl reset;
struct iproc_pll_sw_ctrl sw_ctrl;
struct iproc_clk_reg_op ndiv_int;
struct iproc_clk_reg_op ndiv_frac;
struct iproc_clk_reg_op pdiv;
struct iproc_pll_vco_ctrl vco_ctrl;
struct iproc_clk_reg_op status;
};
/*
* Controls enabling/disabling a PLL derived clock
*/
struct iproc_clk_enable_ctrl {
unsigned int offset;
unsigned int enable_shift;
unsigned int hold_shift;
unsigned int bypass_shift;
};
/*
* Main clock control parameters for clocks derived from the PLLs
*/
struct iproc_clk_ctrl {
unsigned int channel;
unsigned long flags;
struct iproc_clk_enable_ctrl enable;
struct iproc_clk_reg_op mdiv;
};
/*
* Divisor of the ASIU clocks
*/
struct iproc_asiu_div {
unsigned int offset;
unsigned int en_shift;
unsigned int high_shift;
unsigned int high_width;
unsigned int low_shift;
unsigned int low_width;
};
void __init iproc_armpll_setup(struct device_node *node);
void __init iproc_pll_clk_setup(struct device_node *node,
const struct iproc_pll_ctrl *pll_ctrl,
const struct iproc_pll_vco_param *vco,
unsigned int num_vco_entries,
const struct iproc_clk_ctrl *clk_ctrl,
unsigned int num_clks);
void __init iproc_asiu_setup(struct device_node *node,
const struct iproc_asiu_div *div,
const struct iproc_asiu_gate *gate,
unsigned int num_clks);
#endif /* _CLK_IPROC_H */
...@@ -21,8 +21,6 @@ ...@@ -21,8 +21,6 @@
#define selector_clear_exists(sel) ((sel)->width = 0) #define selector_clear_exists(sel) ((sel)->width = 0)
#define trigger_clear_exists(trig) FLAG_CLEAR(trig, TRIG, EXISTS) #define trigger_clear_exists(trig) FLAG_CLEAR(trig, TRIG, EXISTS)
LIST_HEAD(ccu_list); /* The list of set up CCUs */
/* Validity checking */ /* Validity checking */
static bool ccu_data_offsets_valid(struct ccu_data *ccu) static bool ccu_data_offsets_valid(struct ccu_data *ccu)
...@@ -773,7 +771,6 @@ static void kona_ccu_teardown(struct ccu_data *ccu) ...@@ -773,7 +771,6 @@ static void kona_ccu_teardown(struct ccu_data *ccu)
of_clk_del_provider(ccu->node); /* safe if never added */ of_clk_del_provider(ccu->node); /* safe if never added */
ccu_clks_teardown(ccu); ccu_clks_teardown(ccu);
list_del(&ccu->links);
of_node_put(ccu->node); of_node_put(ccu->node);
ccu->node = NULL; ccu->node = NULL;
iounmap(ccu->base); iounmap(ccu->base);
...@@ -847,7 +844,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu, ...@@ -847,7 +844,6 @@ void __init kona_dt_ccu_setup(struct ccu_data *ccu,
goto out_err; goto out_err;
} }
ccu->node = of_node_get(node); ccu->node = of_node_get(node);
list_add_tail(&ccu->links, &ccu_list);
/* /*
* Set up each defined kona clock and save the result in * Set up each defined kona clock and save the result in
......
...@@ -1240,7 +1240,7 @@ static bool __kona_clk_init(struct kona_clk *bcm_clk) ...@@ -1240,7 +1240,7 @@ static bool __kona_clk_init(struct kona_clk *bcm_clk)
default: default:
BUG(); BUG();
} }
return -EINVAL; return false;
} }
/* Set a CCU and all its clocks into their desired initial state */ /* Set a CCU and all its clocks into their desired initial state */
......
...@@ -480,7 +480,6 @@ struct ccu_data { ...@@ -480,7 +480,6 @@ struct ccu_data {
spinlock_t lock; /* serialization lock */ spinlock_t lock; /* serialization lock */
bool write_enabled; /* write access is currently enabled */ bool write_enabled; /* write access is currently enabled */
struct ccu_policy policy; struct ccu_policy policy;
struct list_head links; /* for ccu_list */
struct device_node *node; struct device_node *node;
struct clk_onecell_data clk_data; struct clk_onecell_data clk_data;
const char *name; const char *name;
...@@ -492,7 +491,6 @@ struct ccu_data { ...@@ -492,7 +491,6 @@ struct ccu_data {
#define KONA_CCU_COMMON(_prefix, _name, _ccuname) \ #define KONA_CCU_COMMON(_prefix, _name, _ccuname) \
.name = #_name "_ccu", \ .name = #_name "_ccu", \
.lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \ .lock = __SPIN_LOCK_UNLOCKED(_name ## _ccu_data.lock), \
.links = LIST_HEAD_INIT(_name ## _ccu_data.links), \
.clk_data = { \ .clk_data = { \
.clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \ .clk_num = _prefix ## _ ## _ccuname ## _CCU_CLOCK_COUNT, \
} }
......
...@@ -25,14 +25,7 @@ ...@@ -25,14 +25,7 @@
#include <asm/div64.h> #include <asm/div64.h>
#include "berlin2-div.h" #include "berlin2-div.h"
#include "berlin2-pll.h"
struct berlin2_pll_map {
const u8 vcodiv[16];
u8 mult;
u8 fbdiv_shift;
u8 rfdiv_shift;
u8 divsel_shift;
};
struct berlin2_pll { struct berlin2_pll {
struct clk_hw hw; struct clk_hw hw;
......
...@@ -274,7 +274,7 @@ static void __init asm9260_acc_init(struct device_node *np) ...@@ -274,7 +274,7 @@ static void __init asm9260_acc_init(struct device_node *np)
u32 accuracy = 0; u32 accuracy = 0;
base = of_io_request_and_map(np, 0, np->name); base = of_io_request_and_map(np, 0, np->name);
if (!base) if (IS_ERR(base))
panic("%s: unable to map resource", np->name); panic("%s: unable to map resource", np->name);
/* register pll */ /* register pll */
......
...@@ -556,7 +556,7 @@ static int axmclk_probe(struct platform_device *pdev) ...@@ -556,7 +556,7 @@ static int axmclk_probe(struct platform_device *pdev)
return PTR_ERR(regmap); return PTR_ERR(regmap);
num_clks = ARRAY_SIZE(axmclk_clocks); num_clks = ARRAY_SIZE(axmclk_clocks);
pr_info("axmclk: supporting %u clocks\n", num_clks); pr_info("axmclk: supporting %zu clocks\n", num_clks);
priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks, priv = devm_kzalloc(dev, sizeof(*priv) + sizeof(*priv->clks) * num_clks,
GFP_KERNEL); GFP_KERNEL);
if (!priv) if (!priv)
......
...@@ -94,7 +94,7 @@ static const char * const cdce706_source_name[] = { ...@@ -94,7 +94,7 @@ static const char * const cdce706_source_name[] = {
"clk_in0", "clk_in1", "clk_in0", "clk_in1",
}; };
static const char *cdce706_clkin_name[] = { static const char * const cdce706_clkin_name[] = {
"clk_in", "clk_in",
}; };
...@@ -102,7 +102,7 @@ static const char * const cdce706_pll_name[] = { ...@@ -102,7 +102,7 @@ static const char * const cdce706_pll_name[] = {
"pll1", "pll2", "pll3", "pll1", "pll2", "pll3",
}; };
static const char *cdce706_divider_parent_name[] = { static const char * const cdce706_divider_parent_name[] = {
"clk_in", "pll1", "pll2", "pll2", "pll3", "clk_in", "pll1", "pll2", "pll2", "pll3",
}; };
...@@ -666,6 +666,7 @@ static int cdce706_probe(struct i2c_client *client, ...@@ -666,6 +666,7 @@ static int cdce706_probe(struct i2c_client *client,
static int cdce706_remove(struct i2c_client *client) static int cdce706_remove(struct i2c_client *client)
{ {
of_clk_del_provider(client->dev.of_node);
return 0; return 0;
} }
......
This diff is collapsed.
...@@ -188,7 +188,7 @@ static void clk_composite_disable(struct clk_hw *hw) ...@@ -188,7 +188,7 @@ static void clk_composite_disable(struct clk_hw *hw)
} }
struct clk *clk_register_composite(struct device *dev, const char *name, struct clk *clk_register_composite(struct device *dev, const char *name,
const char **parent_names, int num_parents, const char * const *parent_names, int num_parents,
struct clk_hw *mux_hw, const struct clk_ops *mux_ops, 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 *rate_hw, const struct clk_ops *rate_ops,
struct clk_hw *gate_hw, const struct clk_ops *gate_ops, struct clk_hw *gate_hw, const struct clk_ops *gate_ops,
...@@ -200,10 +200,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name, ...@@ -200,10 +200,8 @@ struct clk *clk_register_composite(struct device *dev, const char *name,
struct clk_ops *clk_composite_ops; struct clk_ops *clk_composite_ops;
composite = kzalloc(sizeof(*composite), GFP_KERNEL); composite = kzalloc(sizeof(*composite), GFP_KERNEL);
if (!composite) { if (!composite)
pr_err("%s: could not allocate composite clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.flags = flags | CLK_IS_BASIC; init.flags = flags | CLK_IS_BASIC;
......
...@@ -106,8 +106,9 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) ...@@ -106,8 +106,9 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
rc = clk_set_rate(clk, rate); rc = clk_set_rate(clk, rate);
if (rc < 0) if (rc < 0)
pr_err("clk: couldn't set %s clock rate: %d\n", pr_err("clk: couldn't set %s clk rate to %d (%d), current rate: %ld\n",
__clk_get_name(clk), rc); __clk_get_name(clk), rate, rc,
clk_get_rate(clk));
clk_put(clk); clk_put(clk);
} }
index++; index++;
...@@ -124,7 +125,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier) ...@@ -124,7 +125,7 @@ static int __set_clk_rates(struct device_node *node, bool clk_supplier)
* and sets any specified clock parents and rates. The @clk_supplier argument * and sets any specified clock parents and rates. The @clk_supplier argument
* should be set to true if @node may be also a clock supplier of any clock * should be set to true if @node may be also a clock supplier of any clock
* listed in its 'assigned-clocks' or 'assigned-clock-parents' properties. * listed in its 'assigned-clocks' or 'assigned-clock-parents' properties.
* If @clk_supplier is false the function exits returnning 0 as soon as it * If @clk_supplier is false the function exits returning 0 as soon as it
* determines the @node is also a supplier of any of the clocks. * determines the @node is also a supplier of any of the clocks.
*/ */
int of_clk_set_defaults(struct device_node *node, bool clk_supplier) int of_clk_set_defaults(struct device_node *node, bool clk_supplier)
......
...@@ -430,11 +430,9 @@ static struct clk *_register_divider(struct device *dev, const char *name, ...@@ -430,11 +430,9 @@ static struct clk *_register_divider(struct device *dev, const char *name,
} }
/* allocate the divider */ /* allocate the divider */
div = kzalloc(sizeof(struct clk_divider), GFP_KERNEL); div = kzalloc(sizeof(*div), GFP_KERNEL);
if (!div) { if (!div)
pr_err("%s: could not allocate divider clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &clk_divider_ops; init.ops = &clk_divider_ops;
......
...@@ -55,10 +55,16 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -55,10 +55,16 @@ static long clk_factor_round_rate(struct clk_hw *hw, unsigned long rate,
static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate, static int clk_factor_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate) unsigned long parent_rate)
{ {
/*
* We must report success but we can do so unconditionally because
* clk_factor_round_rate returns values that ensure this call is a
* nop.
*/
return 0; return 0;
} }
struct clk_ops clk_fixed_factor_ops = { const struct clk_ops clk_fixed_factor_ops = {
.round_rate = clk_factor_round_rate, .round_rate = clk_factor_round_rate,
.set_rate = clk_factor_set_rate, .set_rate = clk_factor_set_rate,
.recalc_rate = clk_factor_recalc_rate, .recalc_rate = clk_factor_recalc_rate,
...@@ -74,10 +80,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name, ...@@ -74,10 +80,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
struct clk *clk; struct clk *clk;
fix = kmalloc(sizeof(*fix), GFP_KERNEL); fix = kmalloc(sizeof(*fix), GFP_KERNEL);
if (!fix) { if (!fix)
pr_err("%s: could not allocate fixed factor clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
/* struct clk_fixed_factor assignments */ /* struct clk_fixed_factor assignments */
fix->mult = mult; fix->mult = mult;
......
...@@ -65,11 +65,9 @@ struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev, ...@@ -65,11 +65,9 @@ struct clk *clk_register_fixed_rate_with_accuracy(struct device *dev,
struct clk_init_data init; struct clk_init_data init;
/* allocate fixed-rate clock */ /* allocate fixed-rate clock */
fixed = kzalloc(sizeof(struct clk_fixed_rate), GFP_KERNEL); fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
if (!fixed) { if (!fixed)
pr_err("%s: could not allocate fixed clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &clk_fixed_rate_ops; init.ops = &clk_fixed_rate_ops;
......
...@@ -109,10 +109,8 @@ struct clk *clk_register_fractional_divider(struct device *dev, ...@@ -109,10 +109,8 @@ struct clk *clk_register_fractional_divider(struct device *dev,
struct clk *clk; struct clk *clk;
fd = kzalloc(sizeof(*fd), GFP_KERNEL); fd = kzalloc(sizeof(*fd), GFP_KERNEL);
if (!fd) { if (!fd)
dev_err(dev, "could not allocate fractional divider clk\n");
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &clk_fractional_divider_ops; init.ops = &clk_fractional_divider_ops;
......
...@@ -135,11 +135,9 @@ struct clk *clk_register_gate(struct device *dev, const char *name, ...@@ -135,11 +135,9 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
} }
/* allocate the gate */ /* allocate the gate */
gate = kzalloc(sizeof(struct clk_gate), GFP_KERNEL); gate = kzalloc(sizeof(*gate), GFP_KERNEL);
if (!gate) { if (!gate)
pr_err("%s: could not allocate gated clk\n", __func__);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
}
init.name = name; init.name = name;
init.ops = &clk_gate_ops; init.ops = &clk_gate_ops;
......
...@@ -189,7 +189,7 @@ static struct clk *of_clk_gpio_gate_delayed_register_get( ...@@ -189,7 +189,7 @@ static struct clk *of_clk_gpio_gate_delayed_register_get(
/** /**
* of_gpio_gate_clk_setup() - Setup function for gpio controlled clock * of_gpio_gate_clk_setup() - Setup function for gpio controlled clock
*/ */
void __init of_gpio_gate_clk_setup(struct device_node *node) static void __init of_gpio_gate_clk_setup(struct device_node *node)
{ {
struct clk_gpio_gate_delayed_register_data *data; struct clk_gpio_gate_delayed_register_data *data;
...@@ -203,6 +203,5 @@ void __init of_gpio_gate_clk_setup(struct device_node *node) ...@@ -203,6 +203,5 @@ void __init of_gpio_gate_clk_setup(struct device_node *node)
of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data); of_clk_add_provider(node, of_clk_gpio_gate_delayed_register_get, data);
} }
EXPORT_SYMBOL_GPL(of_gpio_gate_clk_setup);
CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup); CLK_OF_DECLARE(gpio_gate_clk, "gpio-gate-clock", of_gpio_gate_clk_setup);
#endif #endif
...@@ -80,9 +80,9 @@ static struct clk *__init clk_register_pll(struct device *dev, ...@@ -80,9 +80,9 @@ static struct clk *__init clk_register_pll(struct device *dev,
return clk; return clk;
} }
static const char const *cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", }; static const char * const cpu_parents[] = { "cpu_clk_div", "osc_33m_clk", };
static const char const *ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", }; static const char * const ahb_parents[] = { "ahb_clk_div", "osc_33m_clk", };
static const char const *dc_parents[] = { "dc_clk_div", "osc_33m_clk", }; static const char * const dc_parents[] = { "dc_clk_div", "osc_33m_clk", };
void __init ls1x_clk_init(void) void __init ls1x_clk_init(void)
{ {
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/export.h> #include <linux/export.h>
#include "clk-max-gen.h"
struct max_gen_clk { struct max_gen_clk {
struct regmap *regmap; struct regmap *regmap;
u32 mask; u32 mask;
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
#include <linux/of_address.h> #include <linux/of_address.h>
#include <linux/clkdev.h> #include <linux/clkdev.h>
void __init moxart_of_pll_clk_init(struct device_node *node) static void __init moxart_of_pll_clk_init(struct device_node *node)
{ {
static void __iomem *base; static void __iomem *base;
struct clk *clk, *ref_clk; struct clk *clk, *ref_clk;
...@@ -53,7 +53,7 @@ void __init moxart_of_pll_clk_init(struct device_node *node) ...@@ -53,7 +53,7 @@ void __init moxart_of_pll_clk_init(struct device_node *node)
CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock", CLK_OF_DECLARE(moxart_pll_clock, "moxa,moxart-pll-clock",
moxart_of_pll_clk_init); moxart_of_pll_clk_init);
void __init moxart_of_apb_clk_init(struct device_node *node) static void __init moxart_of_apb_clk_init(struct device_node *node)
{ {
static void __iomem *base; static void __iomem *base;
struct clk *clk, *pll_clk; struct clk *clk, *pll_clk;
......
...@@ -114,7 +114,8 @@ const struct clk_ops clk_mux_ro_ops = { ...@@ -114,7 +114,8 @@ const struct clk_ops clk_mux_ro_ops = {
EXPORT_SYMBOL_GPL(clk_mux_ro_ops); EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
struct clk *clk_register_mux_table(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, const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u32 mask, void __iomem *reg, u8 shift, u32 mask,
u8 clk_mux_flags, u32 *table, spinlock_t *lock) u8 clk_mux_flags, u32 *table, spinlock_t *lock)
{ {
...@@ -166,7 +167,8 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name, ...@@ -166,7 +167,8 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
EXPORT_SYMBOL_GPL(clk_register_mux_table); EXPORT_SYMBOL_GPL(clk_register_mux_table);
struct clk *clk_register_mux(struct device *dev, const char *name, struct clk *clk_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags, const char * const *parent_names, u8 num_parents,
unsigned long flags,
void __iomem *reg, u8 shift, u8 width, void __iomem *reg, u8 shift, u8 width,
u8 clk_mux_flags, spinlock_t *lock) u8 clk_mux_flags, spinlock_t *lock)
{ {
......
...@@ -552,7 +552,8 @@ static const struct clk_ops si5351_pll_ops = { ...@@ -552,7 +552,8 @@ static const struct clk_ops si5351_pll_ops = {
* MSx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c * MSx_P2[19:0] = 128 * b - c * floor(128 * b/c) = (128*b) mod c
* MSx_P3[19:0] = c * MSx_P3[19:0] = c
* *
* MS[6,7] are integer (P1) divide only, P2 = 0, P3 = 0 * MS[6,7] are integer (P1) divide only, P1 = divide value,
* P2 and P3 are not applicable
* *
* for 150MHz < fOUT <= 160MHz: * for 150MHz < fOUT <= 160MHz:
* *
...@@ -606,9 +607,6 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw, ...@@ -606,9 +607,6 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
if (!hwdata->params.valid) if (!hwdata->params.valid)
si5351_read_parameters(hwdata->drvdata, reg, &hwdata->params); si5351_read_parameters(hwdata->drvdata, reg, &hwdata->params);
if (hwdata->params.p3 == 0)
return parent_rate;
/* /*
* multisync0-5: fOUT = (128 * P3 * fIN) / (P1*P3 + P2 + 512*P3) * multisync0-5: fOUT = (128 * P3 * fIN) / (P1*P3 + P2 + 512*P3)
* multisync6-7: fOUT = fIN / P1 * multisync6-7: fOUT = fIN / P1
...@@ -616,6 +614,8 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw, ...@@ -616,6 +614,8 @@ static unsigned long si5351_msynth_recalc_rate(struct clk_hw *hw,
rate = parent_rate; rate = parent_rate;
if (hwdata->num > 5) { if (hwdata->num > 5) {
m = hwdata->params.p1; m = hwdata->params.p1;
} else if (hwdata->params.p3 == 0) {
return parent_rate;
} else if ((si5351_reg_read(hwdata->drvdata, reg + 2) & } else if ((si5351_reg_read(hwdata->drvdata, reg + 2) &
SI5351_OUTPUT_CLK_DIVBY4) == SI5351_OUTPUT_CLK_DIVBY4) { SI5351_OUTPUT_CLK_DIVBY4) == SI5351_OUTPUT_CLK_DIVBY4) {
m = 4; m = 4;
...@@ -679,6 +679,16 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -679,6 +679,16 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
c = 1; c = 1;
*parent_rate = a * rate; *parent_rate = a * rate;
} else if (hwdata->num >= 6) {
/* determine the closest integer divider */
a = DIV_ROUND_CLOSEST(*parent_rate, rate);
if (a < SI5351_MULTISYNTH_A_MIN)
a = SI5351_MULTISYNTH_A_MIN;
if (a > SI5351_MULTISYNTH67_A_MAX)
a = SI5351_MULTISYNTH67_A_MAX;
b = 0;
c = 1;
} else { } else {
unsigned long rfrac, denom; unsigned long rfrac, denom;
...@@ -692,9 +702,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -692,9 +702,7 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
a = *parent_rate / rate; a = *parent_rate / rate;
if (a < SI5351_MULTISYNTH_A_MIN) if (a < SI5351_MULTISYNTH_A_MIN)
a = SI5351_MULTISYNTH_A_MIN; a = SI5351_MULTISYNTH_A_MIN;
if (hwdata->num >= 6 && a > SI5351_MULTISYNTH67_A_MAX) if (a > SI5351_MULTISYNTH_A_MAX)
a = SI5351_MULTISYNTH67_A_MAX;
else if (a > SI5351_MULTISYNTH_A_MAX)
a = SI5351_MULTISYNTH_A_MAX; a = SI5351_MULTISYNTH_A_MAX;
/* find best approximation for b/c = fVCO mod fOUT */ /* find best approximation for b/c = fVCO mod fOUT */
...@@ -723,6 +731,10 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -723,6 +731,10 @@ static long si5351_msynth_round_rate(struct clk_hw *hw, unsigned long rate,
hwdata->params.p3 = 1; hwdata->params.p3 = 1;
hwdata->params.p2 = 0; hwdata->params.p2 = 0;
hwdata->params.p1 = 0; hwdata->params.p1 = 0;
} else if (hwdata->num >= 6) {
hwdata->params.p3 = 0;
hwdata->params.p2 = 0;
hwdata->params.p1 = a;
} else { } else {
hwdata->params.p3 = c; hwdata->params.p3 = c;
hwdata->params.p2 = (128 * b) % c; hwdata->params.p2 = (128 * b) % c;
......
This diff is collapsed.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/clk-provider.h> #include <linux/clk-provider.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_data/clk-u300.h>
/* APP side SYSCON registers */ /* APP side SYSCON registers */
/* CLK Control Register 16bit (R/W) */ /* CLK Control Register 16bit (R/W) */
......
...@@ -42,12 +42,12 @@ ...@@ -42,12 +42,12 @@
static DEFINE_SPINLOCK(clk_lock); static DEFINE_SPINLOCK(clk_lock);
static inline u32 xgene_clk_read(void *csr) static inline u32 xgene_clk_read(void __iomem *csr)
{ {
return readl_relaxed(csr); return readl_relaxed(csr);
} }
static inline void xgene_clk_write(u32 data, void *csr) static inline void xgene_clk_write(u32 data, void __iomem *csr)
{ {
return writel_relaxed(data, csr); return writel_relaxed(data, csr);
} }
...@@ -119,7 +119,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw, ...@@ -119,7 +119,7 @@ static unsigned long xgene_clk_pll_recalc_rate(struct clk_hw *hw,
return fvco / nout; return fvco / nout;
} }
const struct clk_ops xgene_clk_pll_ops = { static const struct clk_ops xgene_clk_pll_ops = {
.is_enabled = xgene_clk_pll_is_enabled, .is_enabled = xgene_clk_pll_is_enabled,
.recalc_rate = xgene_clk_pll_recalc_rate, .recalc_rate = xgene_clk_pll_recalc_rate,
}; };
...@@ -167,7 +167,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty ...@@ -167,7 +167,7 @@ static void xgene_pllclk_init(struct device_node *np, enum xgene_pll_type pll_ty
{ {
const char *clk_name = np->full_name; const char *clk_name = np->full_name;
struct clk *clk; struct clk *clk;
void *reg; void __iomem *reg;
reg = of_iomap(np, 0); reg = of_iomap(np, 0);
if (reg == NULL) { if (reg == NULL) {
...@@ -222,20 +222,22 @@ static int xgene_clk_enable(struct clk_hw *hw) ...@@ -222,20 +222,22 @@ static int xgene_clk_enable(struct clk_hw *hw)
struct xgene_clk *pclk = to_xgene_clk(hw); struct xgene_clk *pclk = to_xgene_clk(hw);
unsigned long flags = 0; unsigned long flags = 0;
u32 data; u32 data;
phys_addr_t reg;
if (pclk->lock) if (pclk->lock)
spin_lock_irqsave(pclk->lock, flags); spin_lock_irqsave(pclk->lock, flags);
if (pclk->param.csr_reg != NULL) { if (pclk->param.csr_reg != NULL) {
pr_debug("%s clock enabled\n", pclk->name); pr_debug("%s clock enabled\n", pclk->name);
reg = __pa(pclk->param.csr_reg);
/* First enable the clock */ /* First enable the clock */
data = xgene_clk_read(pclk->param.csr_reg + data = xgene_clk_read(pclk->param.csr_reg +
pclk->param.reg_clk_offset); pclk->param.reg_clk_offset);
data |= pclk->param.reg_clk_mask; data |= pclk->param.reg_clk_mask;
xgene_clk_write(data, pclk->param.csr_reg + xgene_clk_write(data, pclk->param.csr_reg +
pclk->param.reg_clk_offset); pclk->param.reg_clk_offset);
pr_debug("%s clock PADDR base 0x%016LX clk offset 0x%08X mask 0x%08X value 0x%08X\n", pr_debug("%s clock PADDR base %pa clk offset 0x%08X mask 0x%08X value 0x%08X\n",
pclk->name, __pa(pclk->param.csr_reg), pclk->name, &reg,
pclk->param.reg_clk_offset, pclk->param.reg_clk_mask, pclk->param.reg_clk_offset, pclk->param.reg_clk_mask,
data); data);
...@@ -245,8 +247,8 @@ static int xgene_clk_enable(struct clk_hw *hw) ...@@ -245,8 +247,8 @@ static int xgene_clk_enable(struct clk_hw *hw)
data &= ~pclk->param.reg_csr_mask; data &= ~pclk->param.reg_csr_mask;
xgene_clk_write(data, pclk->param.csr_reg + xgene_clk_write(data, pclk->param.csr_reg +
pclk->param.reg_csr_offset); pclk->param.reg_csr_offset);
pr_debug("%s CSR RESET PADDR base 0x%016LX csr offset 0x%08X mask 0x%08X value 0x%08X\n", pr_debug("%s CSR RESET PADDR base %pa csr offset 0x%08X mask 0x%08X value 0x%08X\n",
pclk->name, __pa(pclk->param.csr_reg), pclk->name, &reg,
pclk->param.reg_csr_offset, pclk->param.reg_csr_mask, pclk->param.reg_csr_offset, pclk->param.reg_csr_mask,
data); data);
} }
...@@ -386,7 +388,7 @@ static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate, ...@@ -386,7 +388,7 @@ static long xgene_clk_round_rate(struct clk_hw *hw, unsigned long rate,
return parent_rate / divider; return parent_rate / divider;
} }
const struct clk_ops xgene_clk_ops = { static const struct clk_ops xgene_clk_ops = {
.enable = xgene_clk_enable, .enable = xgene_clk_enable,
.disable = xgene_clk_disable, .disable = xgene_clk_disable,
.is_enabled = xgene_clk_is_enabled, .is_enabled = xgene_clk_is_enabled,
...@@ -456,7 +458,7 @@ static void __init xgene_devclk_init(struct device_node *np) ...@@ -456,7 +458,7 @@ static void __init xgene_devclk_init(struct device_node *np)
parameters.csr_reg = NULL; parameters.csr_reg = NULL;
parameters.divider_reg = NULL; parameters.divider_reg = NULL;
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
void *map_res; void __iomem *map_res;
rc = of_address_to_resource(np, i, &res); rc = of_address_to_resource(np, i, &res);
if (rc != 0) { if (rc != 0) {
if (i == 0) { if (i == 0) {
......
This diff is collapsed.
config COMMON_CLK_HI6220
bool "Hi6220 Clock Driver"
depends on ARCH_HISI || COMPILE_TEST
default ARCH_HISI
help
Build the Hisilicon Hi6220 clock driver based on the common clock framework.
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
# Hisilicon Clock specific Makefile # Hisilicon Clock specific Makefile
# #
obj-y += clk.o clkgate-separated.o obj-y += clk.o clkgate-separated.o clkdivider-hi6220.o
obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o obj-$(CONFIG_ARCH_HI3xxx) += clk-hi3620.o
obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o obj-$(CONFIG_ARCH_HIP04) += clk-hip04.o
obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o obj-$(CONFIG_ARCH_HIX5HD2) += clk-hix5hd2.o
obj-$(CONFIG_COMMON_CLK_HI6220) += clk-hi6220.o
...@@ -38,44 +38,44 @@ ...@@ -38,44 +38,44 @@
#include "clk.h" #include "clk.h"
/* clock parent list */ /* clock parent list */
static const char *timer0_mux_p[] __initdata = { "osc32k", "timerclk01", }; static const char *const timer0_mux_p[] __initconst = { "osc32k", "timerclk01", };
static const char *timer1_mux_p[] __initdata = { "osc32k", "timerclk01", }; static const char *const timer1_mux_p[] __initconst = { "osc32k", "timerclk01", };
static const char *timer2_mux_p[] __initdata = { "osc32k", "timerclk23", }; static const char *const timer2_mux_p[] __initconst = { "osc32k", "timerclk23", };
static const char *timer3_mux_p[] __initdata = { "osc32k", "timerclk23", }; static const char *const timer3_mux_p[] __initconst = { "osc32k", "timerclk23", };
static const char *timer4_mux_p[] __initdata = { "osc32k", "timerclk45", }; static const char *const timer4_mux_p[] __initconst = { "osc32k", "timerclk45", };
static const char *timer5_mux_p[] __initdata = { "osc32k", "timerclk45", }; static const char *const timer5_mux_p[] __initconst = { "osc32k", "timerclk45", };
static const char *timer6_mux_p[] __initdata = { "osc32k", "timerclk67", }; static const char *const timer6_mux_p[] __initconst = { "osc32k", "timerclk67", };
static const char *timer7_mux_p[] __initdata = { "osc32k", "timerclk67", }; static const char *const timer7_mux_p[] __initconst = { "osc32k", "timerclk67", };
static const char *timer8_mux_p[] __initdata = { "osc32k", "timerclk89", }; static const char *const timer8_mux_p[] __initconst = { "osc32k", "timerclk89", };
static const char *timer9_mux_p[] __initdata = { "osc32k", "timerclk89", }; static const char *const timer9_mux_p[] __initconst = { "osc32k", "timerclk89", };
static const char *uart0_mux_p[] __initdata = { "osc26m", "pclk", }; static const char *const uart0_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *uart1_mux_p[] __initdata = { "osc26m", "pclk", }; static const char *const uart1_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *uart2_mux_p[] __initdata = { "osc26m", "pclk", }; static const char *const uart2_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *uart3_mux_p[] __initdata = { "osc26m", "pclk", }; static const char *const uart3_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *uart4_mux_p[] __initdata = { "osc26m", "pclk", }; static const char *const uart4_mux_p[] __initconst = { "osc26m", "pclk", };
static const char *spi0_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; static const char *const spi0_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
static const char *spi1_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; static const char *const spi1_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
static const char *spi2_mux_p[] __initdata = { "osc26m", "rclk_cfgaxi", }; static const char *const spi2_mux_p[] __initconst = { "osc26m", "rclk_cfgaxi", };
/* share axi parent */ /* share axi parent */
static const char *saxi_mux_p[] __initdata = { "armpll3", "armpll2", }; static const char *const saxi_mux_p[] __initconst = { "armpll3", "armpll2", };
static const char *pwm0_mux_p[] __initdata = { "osc32k", "osc26m", }; static const char *const pwm0_mux_p[] __initconst = { "osc32k", "osc26m", };
static const char *pwm1_mux_p[] __initdata = { "osc32k", "osc26m", }; static const char *const pwm1_mux_p[] __initconst = { "osc32k", "osc26m", };
static const char *sd_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const sd_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *mmc1_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const mmc1_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *mmc1_mux2_p[] __initdata = { "osc26m", "mmc1_div", }; static const char *const mmc1_mux2_p[] __initconst = { "osc26m", "mmc1_div", };
static const char *g2d_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const g2d_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *venc_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const venc_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *vdec_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const vdec_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *vpp_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const vpp_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *edc0_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const edc0_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *ldi0_mux_p[] __initdata = { "armpll2", "armpll4", static const char *const ldi0_mux_p[] __initconst = { "armpll2", "armpll4",
"armpll3", "armpll5", }; "armpll3", "armpll5", };
static const char *edc1_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const edc1_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *ldi1_mux_p[] __initdata = { "armpll2", "armpll4", static const char *const ldi1_mux_p[] __initconst = { "armpll2", "armpll4",
"armpll3", "armpll5", }; "armpll3", "armpll5", };
static const char *rclk_hsic_p[] __initdata = { "armpll3", "armpll2", }; static const char *const rclk_hsic_p[] __initconst = { "armpll3", "armpll2", };
static const char *mmc2_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const mmc2_mux_p[] __initconst = { "armpll2", "armpll3", };
static const char *mmc3_mux_p[] __initdata = { "armpll2", "armpll3", }; static const char *const mmc3_mux_p[] __initconst = { "armpll2", "armpll3", };
/* fixed rate clocks */ /* fixed rate clocks */
......
This diff is collapsed.
...@@ -46,15 +46,15 @@ static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = { ...@@ -46,15 +46,15 @@ static struct hisi_fixed_rate_clock hix5hd2_fixed_rate_clks[] __initdata = {
{ HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, }, { HIX5HD2_FIXED_83M, "83m", NULL, CLK_IS_ROOT, 83333333, },
}; };
static const char *sfc_mux_p[] __initdata = { static const char *const sfc_mux_p[] __initconst = {
"24m", "150m", "200m", "100m", "75m", }; "24m", "150m", "200m", "100m", "75m", };
static u32 sfc_mux_table[] = {0, 4, 5, 6, 7}; static u32 sfc_mux_table[] = {0, 4, 5, 6, 7};
static const char *sdio_mux_p[] __initdata = { static const char *const sdio_mux_p[] __initconst = {
"75m", "100m", "50m", "15m", }; "75m", "100m", "50m", "15m", };
static u32 sdio_mux_table[] = {0, 1, 2, 3}; static u32 sdio_mux_table[] = {0, 1, 2, 3};
static const char *fephy_mux_p[] __initdata = { "25m", "125m"}; static const char *const fephy_mux_p[] __initconst = { "25m", "125m"};
static u32 fephy_mux_table[] = {0, 1}; static u32 fephy_mux_table[] = {0, 1};
...@@ -252,8 +252,9 @@ static struct clk_ops clk_complex_ops = { ...@@ -252,8 +252,9 @@ static struct clk_ops clk_complex_ops = {
.disable = clk_complex_disable, .disable = clk_complex_disable,
}; };
void __init hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, static void __init
int nums, struct hisi_clock_data *data) hix5hd2_clk_register_complex(struct hix5hd2_complex_clock *clks, int nums,
struct hisi_clock_data *data)
{ {
void __iomem *base = data->base; void __iomem *base = data->base;
int i; int i;
......
...@@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks, ...@@ -232,3 +232,32 @@ void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *clks,
data->clk_data.clks[clks[i].id] = clk; data->clk_data.clks[clks[i].id] = clk;
} }
} }
void __init hi6220_clk_register_divider(struct hi6220_divider_clock *clks,
int nums, struct hisi_clock_data *data)
{
struct clk *clk;
void __iomem *base = data->base;
int i;
for (i = 0; i < nums; i++) {
clk = hi6220_register_clkdiv(NULL, clks[i].name,
clks[i].parent_name,
clks[i].flags,
base + clks[i].offset,
clks[i].shift,
clks[i].width,
clks[i].mask_bit,
&hisi_clk_lock);
if (IS_ERR(clk)) {
pr_err("%s: failed to register clock %s\n",
__func__, clks[i].name);
continue;
}
if (clks[i].alias)
clk_register_clkdev(clk, clks[i].alias, NULL);
data->clk_data.clks[clks[i].id] = clk;
}
}
...@@ -55,7 +55,7 @@ struct hisi_fixed_factor_clock { ...@@ -55,7 +55,7 @@ struct hisi_fixed_factor_clock {
struct hisi_mux_clock { struct hisi_mux_clock {
unsigned int id; unsigned int id;
const char *name; const char *name;
const char **parent_names; const char *const *parent_names;
u8 num_parents; u8 num_parents;
unsigned long flags; unsigned long flags;
unsigned long offset; unsigned long offset;
...@@ -79,6 +79,18 @@ struct hisi_divider_clock { ...@@ -79,6 +79,18 @@ struct hisi_divider_clock {
const char *alias; const char *alias;
}; };
struct hi6220_divider_clock {
unsigned int id;
const char *name;
const char *parent_name;
unsigned long flags;
unsigned long offset;
u8 shift;
u8 width;
u32 mask_bit;
const char *alias;
};
struct hisi_gate_clock { struct hisi_gate_clock {
unsigned int id; unsigned int id;
const char *name; const char *name;
...@@ -94,18 +106,23 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *, ...@@ -94,18 +106,23 @@ struct clk *hisi_register_clkgate_sep(struct device *, const char *,
const char *, unsigned long, const char *, unsigned long,
void __iomem *, u8, void __iomem *, u8,
u8, spinlock_t *); u8, spinlock_t *);
struct clk *hi6220_register_clkdiv(struct device *dev, const char *name,
const char *parent_name, unsigned long flags, void __iomem *reg,
u8 shift, u8 width, u32 mask_bit, spinlock_t *lock);
struct hisi_clock_data __init *hisi_clk_init(struct device_node *, int); struct hisi_clock_data *hisi_clk_init(struct device_node *, int);
void __init hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *, void hisi_clk_register_fixed_rate(struct hisi_fixed_rate_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
void __init hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *, void hisi_clk_register_fixed_factor(struct hisi_fixed_factor_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
void __init hisi_clk_register_mux(struct hisi_mux_clock *, int, void hisi_clk_register_mux(struct hisi_mux_clock *, int,
struct hisi_clock_data *); struct hisi_clock_data *);
void __init hisi_clk_register_divider(struct hisi_divider_clock *, void hisi_clk_register_divider(struct hisi_divider_clock *,
int, struct hisi_clock_data *);
void hisi_clk_register_gate(struct hisi_gate_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
void __init hisi_clk_register_gate(struct hisi_gate_clock *, void hisi_clk_register_gate_sep(struct hisi_gate_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
void __init hisi_clk_register_gate_sep(struct hisi_gate_clock *, void hi6220_clk_register_divider(struct hi6220_divider_clock *,
int, struct hisi_clock_data *); int, struct hisi_clock_data *);
#endif /* __HISI_CLK_H */ #endif /* __HISI_CLK_H */
This diff is collapsed.
...@@ -37,7 +37,8 @@ ...@@ -37,7 +37,8 @@
* Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL * Main PLL or any other PLLs in the device such as ARM PLL, DDR PLL
* or PA PLL available on keystone2. These PLLs are controlled by * or PA PLL available on keystone2. These PLLs are controlled by
* this register. Main PLL is controlled by a PLL controller. * this register. Main PLL is controlled by a PLL controller.
* @pllm: PLL register map address * @pllm: PLL register map address for multiplier bits
* @pllod: PLL register map address for post divider bits
* @pll_ctl0: PLL controller map address * @pll_ctl0: PLL controller map address
* @pllm_lower_mask: multiplier lower mask * @pllm_lower_mask: multiplier lower mask
* @pllm_upper_mask: multiplier upper mask * @pllm_upper_mask: multiplier upper mask
...@@ -53,6 +54,7 @@ struct clk_pll_data { ...@@ -53,6 +54,7 @@ struct clk_pll_data {
u32 phy_pllm; u32 phy_pllm;
u32 phy_pll_ctl0; u32 phy_pll_ctl0;
void __iomem *pllm; void __iomem *pllm;
void __iomem *pllod;
void __iomem *pll_ctl0; void __iomem *pll_ctl0;
u32 pllm_lower_mask; u32 pllm_lower_mask;
u32 pllm_upper_mask; u32 pllm_upper_mask;
...@@ -102,7 +104,11 @@ static unsigned long clk_pllclk_recalc(struct clk_hw *hw, ...@@ -102,7 +104,11 @@ static unsigned long clk_pllclk_recalc(struct clk_hw *hw,
/* read post divider from od bits*/ /* read post divider from od bits*/
postdiv = ((val & pll_data->clkod_mask) >> postdiv = ((val & pll_data->clkod_mask) >>
pll_data->clkod_shift) + 1; pll_data->clkod_shift) + 1;
else else if (pll_data->pllod) {
postdiv = readl(pll_data->pllod);
postdiv = ((postdiv & pll_data->clkod_mask) >>
pll_data->clkod_shift) + 1;
} else
postdiv = pll_data->postdiv; postdiv = pll_data->postdiv;
rate /= (prediv + 1); rate /= (prediv + 1);
...@@ -172,12 +178,21 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) ...@@ -172,12 +178,21 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
/* assume the PLL has output divider register bits */ /* assume the PLL has output divider register bits */
pll_data->clkod_mask = CLKOD_MASK; pll_data->clkod_mask = CLKOD_MASK;
pll_data->clkod_shift = CLKOD_SHIFT; pll_data->clkod_shift = CLKOD_SHIFT;
/*
* Check if there is an post-divider register. If not
* assume od bits are part of control register.
*/
i = of_property_match_string(node, "reg-names",
"post-divider");
pll_data->pllod = of_iomap(node, i);
} }
i = of_property_match_string(node, "reg-names", "control"); i = of_property_match_string(node, "reg-names", "control");
pll_data->pll_ctl0 = of_iomap(node, i); pll_data->pll_ctl0 = of_iomap(node, i);
if (!pll_data->pll_ctl0) { if (!pll_data->pll_ctl0) {
pr_err("%s: ioremap failed\n", __func__); pr_err("%s: ioremap failed\n", __func__);
iounmap(pll_data->pllod);
goto out; goto out;
} }
...@@ -193,6 +208,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl) ...@@ -193,6 +208,7 @@ static void __init _of_pll_clk_init(struct device_node *node, bool pllctrl)
pll_data->pllm = of_iomap(node, i); pll_data->pllm = of_iomap(node, i);
if (!pll_data->pllm) { if (!pll_data->pllm) {
iounmap(pll_data->pll_ctl0); iounmap(pll_data->pll_ctl0);
iounmap(pll_data->pllod);
goto out; goto out;
} }
} }
......
obj-y += clk-mtk.o clk-pll.o clk-gate.o
obj-$(CONFIG_RESET_CONTROLLER) += reset.o
obj-y += clk-mt8135.o
obj-y += clk-mt8173.o
This diff is collapsed.
/*
* Copyright (c) 2014 MediaTek Inc.
* Author: James Liao <jamesjj.liao@mediatek.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __DRV_CLK_GATE_H
#define __DRV_CLK_GATE_H
#include <linux/regmap.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
struct mtk_clk_gate {
struct clk_hw hw;
struct regmap *regmap;
int set_ofs;
int clr_ofs;
int sta_ofs;
u8 bit;
};
static inline struct mtk_clk_gate *to_clk_gate(struct clk_hw *hw)
{
return container_of(hw, struct mtk_clk_gate, hw);
}
extern const struct clk_ops mtk_clk_gate_ops_setclr;
extern const struct clk_ops mtk_clk_gate_ops_setclr_inv;
struct clk *mtk_clk_register_gate(
const char *name,
const char *parent_name,
struct regmap *regmap,
int set_ofs,
int clr_ofs,
int sta_ofs,
u8 bit,
const struct clk_ops *ops);
#endif /* __DRV_CLK_GATE_H */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment