Browse Source

The common clk framework changes for 3.12 are dominated by clock driver

patches, both new drivers and fixes to existing. A high percentage of
 these are for Samsung platforms like Exynos. Core framework fixes and
 some new features like automagical clock re-parenting round out the
 patches.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.12 (GNU/Linux)
 
 iQIcBAABAgAGBQJSLkImAAoJEDqPOy9afJhJOjsP/Ri26AW7XB9pPWJRSU9REBZA
 31wxcFo2T+PNir9duwDwjFBFycC3MisaKFlg7D134M+7txbYqm1TRvfu9OEDxpSP
 4b/Yl6TarN4dhCN2R+BREO8PnxCBVpspDcsdh6Esuwuet2xUom3UtN8yvSjhPP/u
 qGNmXQYXyQy4fom5r+GsDVW+HIhLkaX9b0fYc9EN/bqfgv94PMZAxAxsK9CroAGZ
 0m0g9ZXw9iSvVfz+iQEqPINtvpTLHk0FGyimoSR7kvW4o4o47tVtLEWp7VjG6mr5
 zvBsycaQq6NgxPu96iUWWhsO9Uj2I7/7JgidXF7r+wvEFs1mcgZtkkirSA/n4zUN
 C8a87rvQrZRLr+xXhVuqiVHCgCY8vXoHqkWg6SrZ62ORL8C7uYRpog5SEe2ZzLJX
 l5uGAsDM6el+Uc/YviCPoZbeFr3h3CQvvFo8+i2eN0v/Phf30rq4lotBvpQj894G
 ngEIMj+D8wshdYSF2dNJ0rLnkLHTgCbiA28L6Cl5TRzRMj3Uaj9aT3cmoLUnimZu
 7F7nWU4Iu/vzQKCTQ+eTvwxXJqIlE0JeVbJilqH1f2a68JdXP1LOId+2w/CP8gqQ
 i2odj6JHMgBzM9rNs+y0Ir9X/bXIVi6F341c19Nl15srEiLLl8xQIpcPDaI/Kvzs
 pefYgF2yS5AZAW3ac90r
 =5GfA
 -----END PGP SIGNATURE-----

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

Pull clock framework changes from Michael Turquette:
 "The common clk framework changes for 3.12 are dominated by clock
  driver patches, both new drivers and fixes to existing.  A high
  percentage of these are for Samsung platforms like Exynos.  Core
  framework fixes and some new features like automagical clock
  re-parenting round out the patches"

* tag 'clk-for-linus-3.12' of git://git.linaro.org/people/mturquette/linux: (102 commits)
  clk: only call get_parent if there is one
  clk: samsung: exynos5250: Simplify registration of PLL rate tables
  clk: samsung: exynos4: Register PLL rate tables for Exynos4x12
  clk: samsung: exynos4: Register PLL rate tables for Exynos4210
  clk: samsung: exynos4: Reorder registration of mout_vpllsrc
  clk: samsung: pll: Add support for rate configuration of PLL46xx
  clk: samsung: pll: Use new registration method for PLL46xx
  clk: samsung: pll: Add support for rate configuration of PLL45xx
  clk: samsung: pll: Use new registration method for PLL45xx
  clk: samsung: exynos4: Rename exynos4_plls to exynos4x12_plls
  clk: samsung: exynos4: Remove checks for DT node
  clk: samsung: exynos4: Remove unused static clkdev aliases
  clk: samsung: Modify _get_rate() helper to use __clk_lookup()
  clk: samsung: exynos4: Use separate aliases for cpufreq related clocks
  clocksource: samsung_pwm_timer: Get clock from device tree
  ARM: dts: exynos4: Specify PWM clocks in PWM node
  pwm: samsung: Update DT bindings documentation to cover clocks
  clk: Move symbol export to proper location
  clk: fix new_parent dereference before null check
  clk: wm831x: Initialise wm831x pointer on init
  ...
master
Linus Torvalds 8 years ago
parent
commit
bef4a0ab98
  1. 46
      Documentation/clk.txt
  2. 1
      Documentation/devicetree/bindings/clock/exynos4-clock.txt
  3. 14
      Documentation/devicetree/bindings/clock/exynos5250-clock.txt
  4. 12
      Documentation/devicetree/bindings/clock/exynos5420-clock.txt
  5. 77
      Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt
  6. 12
      Documentation/devicetree/bindings/clock/sunxi.txt
  7. 75
      Documentation/devicetree/bindings/clock/sunxi/sun5i-a10s-gates.txt
  8. 83
      Documentation/devicetree/bindings/clock/sunxi/sun6i-a31-gates.txt
  9. 98
      Documentation/devicetree/bindings/clock/sunxi/sun7i-a20-gates.txt
  10. 7
      Documentation/devicetree/bindings/gpu/samsung-g2d.txt
  11. 12
      Documentation/devicetree/bindings/pwm/pwm-samsung.txt
  12. 2
      arch/arm/boot/dts/exynos4.dtsi
  13. 5
      arch/arm/mach-imx/clk.h
  14. 8
      drivers/clk/Kconfig
  15. 1
      drivers/clk/Makefile
  16. 2
      drivers/clk/clk-bcm2835.c
  17. 8
      drivers/clk/clk-divider.c
  18. 2
      drivers/clk/clk-fixed-factor.c
  19. 1
      drivers/clk/clk-fixed-rate.c
  20. 7
      drivers/clk/clk-gate.c
  21. 19
      drivers/clk/clk-mux.c
  22. 4
      drivers/clk/clk-nomadik.c
  23. 2
      drivers/clk/clk-prima2.c
  24. 273
      drivers/clk/clk-s2mps11.c
  25. 4
      drivers/clk/clk-u300.c
  26. 16
      drivers/clk/clk-wm831x.c
  27. 450
      drivers/clk/clk.c
  28. 39
      drivers/clk/mmp/clk-mmp2.c
  29. 40
      drivers/clk/mmp/clk-pxa168.c
  30. 31
      drivers/clk/mmp/clk-pxa910.c
  31. 14
      drivers/clk/mvebu/armada-370.c
  32. 12
      drivers/clk/mvebu/armada-xp.c
  33. 4
      drivers/clk/mvebu/clk-cpu.c
  34. 18
      drivers/clk/mvebu/common.c
  35. 12
      drivers/clk/mvebu/dove.c
  36. 14
      drivers/clk/mvebu/kirkwood.c
  37. 1
      drivers/clk/mxs/clk-imx23.c
  38. 4
      drivers/clk/mxs/clk.h
  39. 3
      drivers/clk/samsung/Makefile
  40. 8
      drivers/clk/samsung/clk-exynos-audss.c
  41. 605
      drivers/clk/samsung/clk-exynos4.c
  42. 129
      drivers/clk/samsung/clk-exynos5250.c
  43. 123
      drivers/clk/samsung/clk-exynos5420.c
  44. 18
      drivers/clk/samsung/clk-exynos5440.c
  45. 701
      drivers/clk/samsung/clk-pll.c
  46. 85
      drivers/clk/samsung/clk-pll.h
  47. 473
      drivers/clk/samsung/clk-s3c64xx.c
  48. 10
      drivers/clk/samsung/clk.c
  49. 55
      drivers/clk/samsung/clk.h
  50. 179
      drivers/clk/spear/spear1310_clock.c
  51. 97
      drivers/clk/spear/spear1340_clock.c
  52. 57
      drivers/clk/spear/spear3xx_clock.c
  53. 35
      drivers/clk/spear/spear6xx_clock.c
  54. 270
      drivers/clk/sunxi/clk-sunxi.c
  55. 38
      drivers/clk/tegra/clk-tegra114.c
  56. 8
      drivers/clk/tegra/clk-tegra20.c
  57. 37
      drivers/clk/tegra/clk-tegra30.c
  58. 4
      drivers/clk/versatile/clk-vexpress.c
  59. 82
      drivers/clk/zynq/clkc.c
  60. 19
      drivers/clk/zynq/pll.c
  61. 12
      drivers/clocksource/samsung_pwm_timer.c
  62. 178
      include/dt-bindings/clock/samsung,s3c64xx-clock.h
  63. 3
      include/linux/clk-private.h
  64. 31
      include/linux/clk-provider.h

46
Documentation/clk.txt

@ -70,6 +70,10 @@ the operations defined in clk.h:
unsigned long parent_rate);
long (*round_rate)(struct clk_hw *hw, unsigned long,
unsigned long *);
long (*determine_rate)(struct clk_hw *hw,
unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_clk);
int (*set_parent)(struct clk_hw *hw, u8 index);
u8 (*get_parent)(struct clk_hw *hw);
int (*set_rate)(struct clk_hw *hw, unsigned long);
@ -179,26 +183,28 @@ mandatory, a cell marked as "n" implies that either including that
callback is invalid or otherwise unnecessary. Empty cells are either
optional or must be evaluated on a case-by-case basis.
clock hardware characteristics
-----------------------------------------------------------
| gate | change rate | single parent | multiplexer | root |
|------|-------------|---------------|-------------|------|
.prepare | | | | | |
.unprepare | | | | | |
| | | | | |
.enable | y | | | | |
.disable | y | | | | |
.is_enabled | y | | | | |
| | | | | |
.recalc_rate | | y | | | |
.round_rate | | y | | | |
.set_rate | | y | | | |
| | | | | |
.set_parent | | | n | y | n |
.get_parent | | | n | y | n |
| | | | | |
.init | | | | | |
-----------------------------------------------------------
clock hardware characteristics
-----------------------------------------------------------
| gate | change rate | single parent | multiplexer | root |
|------|-------------|---------------|-------------|------|
.prepare | | | | | |
.unprepare | | | | | |
| | | | | |
.enable | y | | | | |
.disable | y | | | | |
.is_enabled | y | | | | |
| | | | | |
.recalc_rate | | y | | | |
.round_rate | | y [1] | | | |
.determine_rate | | y [1] | | | |
.set_rate | | y | | | |
| | | | | |
.set_parent | | | n | y | n |
.get_parent | | | n | y | n |
| | | | | |
.init | | | | | |
-----------------------------------------------------------
[1] either one of round_rate or determine_rate is required.
Finally, register your clock at run-time with a hardware-specific
registration function. This function simply populates struct clk_foo's

1
Documentation/devicetree/bindings/clock/exynos4-clock.txt

@ -236,6 +236,7 @@ Exynos4 SoC and this is specified where applicable.
spi0_isp_sclk 380 Exynos4x12
spi1_isp_sclk 381 Exynos4x12
uart_isp_sclk 382 Exynos4x12
tmu_apbif 383
[Mux Clocks]

14
Documentation/devicetree/bindings/clock/exynos5250-clock.txt

@ -59,6 +59,9 @@ clock which they consume.
sclk_spi0 154
sclk_spi1 155
sclk_spi2 156
div_i2s1 157
div_i2s2 158
sclk_hdmiphy 159
[Peripheral Clock Gates]
@ -154,7 +157,16 @@ clock which they consume.
dsim0 341
dp 342
mixer 343
hdmi 345
hdmi 344
g2d 345
[Clock Muxes]
Clock ID
----------------------------
mout_hdmi 1024
Example 1: An example of a clock controller node is listed below.

12
Documentation/devicetree/bindings/clock/exynos5420-clock.txt

@ -59,6 +59,7 @@ clock which they consume.
sclk_pwm 155
sclk_gscl_wa 156
sclk_gscl_wb 157
sclk_hdmiphy 158
[Peripheral Clock Gates]
@ -179,6 +180,17 @@ clock which they consume.
fimc_lite3 495
aclk_g3d 500
g3d 501
smmu_mixer 502
Mux ID
----------------------------
mout_hdmi 640
Divider ID
----------------------------
dout_pixel 768
Example 1: An example of a clock controller node is listed below.

77
Documentation/devicetree/bindings/clock/samsung,s3c64xx-clock.txt

@ -0,0 +1,77 @@
* Samsung S3C64xx Clock Controller
The S3C64xx clock controller generates and supplies clock to various controllers
within the SoC. The clock binding described here is applicable to all SoCs in
the S3C64xx family.
Required Properties:
- compatible: should be one of the following.
- "samsung,s3c6400-clock" - controller compatible with S3C6400 SoC.
- "samsung,s3c6410-clock" - controller compatible with S3C6410 SoC.
- reg: physical base address of the 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. Some of the clocks are available only
on a particular S3C64xx SoC and this is specified where applicable.
All available clocks are defined as preprocessor macros in
dt-bindings/clock/samsung,s3c64xx-clock.h header and can be used in device
tree sources.
External clocks:
There are several clocks that are generated outside the SoC. It is expected
that they are defined using standard clock bindings with following
clock-output-names:
- "fin_pll" - PLL input clock (xtal/extclk) - required,
- "xusbxti" - USB xtal - required,
- "iiscdclk0" - I2S0 codec clock - optional,
- "iiscdclk1" - I2S1 codec clock - optional,
- "iiscdclk2" - I2S2 codec clock - optional,
- "pcmcdclk0" - PCM0 codec clock - optional,
- "pcmcdclk1" - PCM1 codec clock - optional, only S3C6410.
Example: Clock controller node:
clock: clock-controller@7e00f000 {
compatible = "samsung,s3c6410-clock";
reg = <0x7e00f000 0x1000>;
#clock-cells = <1>;
};
Example: Required external clocks:
fin_pll: clock-fin-pll {
compatible = "fixed-clock";
clock-output-names = "fin_pll";
clock-frequency = <12000000>;
#clock-cells = <0>;
};
xusbxti: clock-xusbxti {
compatible = "fixed-clock";
clock-output-names = "xusbxti";
clock-frequency = <48000000>;
#clock-cells = <0>;
};
Example: UART controller node that consumes the clock generated by the clock
controller (refer to the standard clock bindings for information about
"clocks" and "clock-names" properties):
uart0: serial@7f005000 {
compatible = "samsung,s3c6400-uart";
reg = <0x7f005000 0x100>;
interrupt-parent = <&vic1>;
interrupts = <5>;
clock-names = "uart", "clk_uart_baud2",
"clk_uart_baud3";
clocks = <&clock PCLK_UART0>, <&clocks PCLK_UART0>,
<&clock SCLK_UART>;
status = "disabled";
};

12
Documentation/devicetree/bindings/clock/sunxi.txt

@ -8,19 +8,31 @@ Required properties:
- compatible : shall be one of the following:
"allwinner,sun4i-osc-clk" - for a gatable oscillator
"allwinner,sun4i-pll1-clk" - for the main PLL clock
"allwinner,sun6i-a31-pll1-clk" - for the main PLL clock on A31
"allwinner,sun4i-cpu-clk" - for the CPU multiplexer clock
"allwinner,sun4i-axi-clk" - for the AXI clock
"allwinner,sun4i-axi-gates-clk" - for the AXI gates
"allwinner,sun4i-ahb-clk" - for the AHB clock
"allwinner,sun4i-ahb-gates-clk" - for the AHB gates on A10
"allwinner,sun5i-a13-ahb-gates-clk" - for the AHB gates on A13
"allwinner,sun5i-a10s-ahb-gates-clk" - for the AHB gates on A10s
"allwinner,sun7i-a20-ahb-gates-clk" - for the AHB gates on A20
"allwinner,sun6i-a31-ahb1-mux-clk" - for the AHB1 multiplexer on A31
"allwinner,sun6i-a31-ahb1-gates-clk" - for the AHB1 gates on A31
"allwinner,sun4i-apb0-clk" - for the APB0 clock
"allwinner,sun4i-apb0-gates-clk" - for the APB0 gates on A10
"allwinner,sun5i-a13-apb0-gates-clk" - for the APB0 gates on A13
"allwinner,sun5i-a10s-apb0-gates-clk" - for the APB0 gates on A10s
"allwinner,sun7i-a20-apb0-gates-clk" - for the APB0 gates on A20
"allwinner,sun4i-apb1-clk" - for the APB1 clock
"allwinner,sun4i-apb1-mux-clk" - for the APB1 clock muxing
"allwinner,sun4i-apb1-gates-clk" - for the APB1 gates on A10
"allwinner,sun5i-a13-apb1-gates-clk" - for the APB1 gates on A13
"allwinner,sun5i-a10s-apb1-gates-clk" - for the APB1 gates on A10s
"allwinner,sun6i-a31-apb1-gates-clk" - for the APB1 gates on A31
"allwinner,sun7i-a20-apb1-gates-clk" - for the APB1 gates on A20
"allwinner,sun6i-a31-apb2-div-clk" - for the APB2 gates on A31
"allwinner,sun6i-a31-apb2-gates-clk" - for the APB2 gates on A31
Required properties for all clocks:
- reg : shall be the control register address for the clock.

75
Documentation/devicetree/bindings/clock/sunxi/sun5i-a10s-gates.txt

@ -0,0 +1,75 @@
Gate clock outputs
------------------
* AXI gates ("allwinner,sun4i-axi-gates-clk")
DRAM 0
* AHB gates ("allwinner,sun5i-a10s-ahb-gates-clk")
USB0 0
EHCI0 1
OHCI0 2
SS 5
DMA 6
BIST 7
MMC0 8
MMC1 9
MMC2 10
NAND 13
SDRAM 14
EMAC 17
TS 18
SPI0 20
SPI1 21
SPI2 22
GPS 26
HSTIMER 28
VE 32
TVE 34
LCD 36
CSI 40
HDMI 43
DE_BE 44
DE_FE 46
IEP 51
MALI400 52
* APB0 gates ("allwinner,sun5i-a10s-apb0-gates-clk")
CODEC 0
IIS 3
PIO 5
IR 6
KEYPAD 10
* APB1 gates ("allwinner,sun5i-a10s-apb1-gates-clk")
I2C0 0
I2C1 1
I2C2 2
UART0 16
UART1 17
UART2 18
UART3 19
Notation:
[*]: The datasheet didn't mention these, but they are present on AW code
[**]: The datasheet had this marked as "NC" but they are used on AW code

83
Documentation/devicetree/bindings/clock/sunxi/sun6i-a31-gates.txt

@ -0,0 +1,83 @@
Gate clock outputs
------------------
* AHB1 gates ("allwinner,sun6i-a31-ahb1-gates-clk")
MIPI DSI 1
SS 5
DMA 6
MMC0 8
MMC1 9
MMC2 10
MMC3 11
NAND1 12
NAND0 13
SDRAM 14
GMAC 17
TS 18
HSTIMER 19
SPI0 20
SPI1 21
SPI2 22
SPI3 23
USB_OTG 24
EHCI0 26
EHCI1 27
OHCI0 29
OHCI1 30
OHCI2 31
VE 32
LCD0 36
LCD1 37
CSI 40
HDMI 43
DE_BE0 44
DE_BE1 45
DE_FE1 46
DE_FE1 47
MP 50
GPU 52
DEU0 55
DEU1 56
DRC0 57
DRC1 58
* APB1 gates ("allwinner,sun6i-a31-apb1-gates-clk")
CODEC 0
DIGITAL MIC 4
PIO 5
DAUDIO0 12
DAUDIO1 13
* APB2 gates ("allwinner,sun6i-a31-apb2-gates-clk")
I2C0 0
I2C1 1
I2C2 2
I2C3 3
UART0 16
UART1 17
UART2 18
UART3 19
UART4 20
UART5 21
Notation:
[*]: The datasheet didn't mention these, but they are present on AW code
[**]: The datasheet had this marked as "NC" but they are used on AW code

98
Documentation/devicetree/bindings/clock/sunxi/sun7i-a20-gates.txt

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

7
Documentation/devicetree/bindings/gpu/samsung-g2d.txt

@ -11,8 +11,11 @@ Required properties:
- interrupts : G2D interrupt number to the CPU.
- clocks : from common clock binding: handle to G2D clocks.
- clock-names : from common clock binding: must contain "sclk_fimg2d" and
"fimg2d", corresponding to entries in the clocks property.
- clock-names : names of clocks listed in clocks property, in the same
order, depending on SoC type:
- for S5PV210 and Exynos4 based SoCs: "fimg2d" and
"sclk_fimg2d"
- for Exynos5250 SoC: "fimg2d".
Example:
g2d@12800000 {

12
Documentation/devicetree/bindings/pwm/pwm-samsung.txt

@ -19,6 +19,16 @@ Required properties:
- reg: base address and size of register area
- interrupts: list of timer interrupts (one interrupt per timer, starting at
timer 0)
- clock-names: should contain all following required clock names:
- "timers" - PWM base clock used to generate PWM signals,
and any subset of following optional clock names:
- "pwm-tclk0" - first external PWM clock source,
- "pwm-tclk1" - second external PWM clock source.
Note that not all IP variants allow using all external clock sources.
Refer to SoC documentation to learn which clock source configurations
are available.
- clocks: should contain clock specifiers of all clocks, which input names
have been specified in clock-names property, in same order.
- #pwm-cells: should be 3. See pwm.txt in this directory for a description of
the cells format. The only third cell flag supported by this binding is
PWM_POLARITY_INVERTED.
@ -34,6 +44,8 @@ Example:
reg = <0x7f006000 0x1000>;
interrupt-parent = <&vic0>;
interrupts = <23>, <24>, <25>, <27>, <28>;
clocks = <&clock 67>;
clock-names = "timers";
samsung,pwm-outputs = <0>, <1>;
#pwm-cells = <3>;
}

2
arch/arm/boot/dts/exynos4.dtsi

@ -448,6 +448,8 @@
compatible = "samsung,exynos4210-pwm";
reg = <0x139D0000 0x1000>;
interrupts = <0 37 0>, <0 38 0>, <0 39 0>, <0 40 0>, <0 41 0>;
clocks = <&clock 336>;
clock-names = "timers";
#pwm-cells = <2>;
status = "disabled";
};

5
arch/arm/mach-imx/clk.h

@ -89,7 +89,8 @@ static inline struct clk *imx_clk_gate(const char *name, const char *parent,
static inline struct clk *imx_clk_mux(const char *name, void __iomem *reg,
u8 shift, u8 width, const char **parents, int num_parents)
{
return clk_register_mux(NULL, name, parents, num_parents, 0, reg, shift,
return clk_register_mux(NULL, name, parents, num_parents,
CLK_SET_RATE_NO_REPARENT, reg, shift,
width, 0, &imx_ccm_lock);
}
@ -98,7 +99,7 @@ static inline struct clk *imx_clk_mux_flags(const char *name,
int num_parents, unsigned long flags)
{
return clk_register_mux(NULL, name, parents, num_parents,
flags, reg, shift, width, 0,
flags | CLK_SET_RATE_NO_REPARENT, reg, shift, width, 0,
&imx_ccm_lock);
}

8
drivers/clk/Kconfig

@ -27,7 +27,7 @@ config COMMON_CLK_DEBUG
bool "DebugFS representation of clock tree"
select DEBUG_FS
---help---
Creates a directory hierchy in debugfs for visualizing the clk
Creates a directory hierarchy in debugfs for visualizing the clk
tree structure. Each directory contains read-only members
that export information specific to that clk node: clk_rate,
clk_flags, clk_prepare_count, clk_enable_count &
@ -64,6 +64,12 @@ config COMMON_CLK_SI5351
This driver supports Silicon Labs 5351A/B/C programmable clock
generators.
config COMMON_CLK_S2MPS11
tristate "Clock driver for S2MPS11 MFD"
depends on MFD_SEC_CORE
---help---
This driver supports S2MPS11 crystal oscillator clock.
config CLK_TWL6040
tristate "External McPDM functional clock from twl6040"
depends on TWL6040_CORE

1
drivers/clk/Makefile

@ -40,5 +40,6 @@ obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_CLK_TWL6040) += clk-twl6040.o
obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o

2
drivers/clk/clk-bcm2835.c

@ -23,7 +23,7 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
static const __initconst struct of_device_id clk_match[] = {
static const struct of_device_id clk_match[] __initconst = {
{ .compatible = "fixed-clock", .data = of_fixed_clk_setup, },
{ }
};

8
drivers/clk/clk-divider.c

@ -104,7 +104,7 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
struct clk_divider *divider = to_clk_divider(hw);
unsigned int div, val;
val = readl(divider->reg) >> divider->shift;
val = clk_readl(divider->reg) >> divider->shift;
val &= div_mask(divider);
div = _get_div(divider, val);
@ -230,11 +230,11 @@ static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
val = div_mask(divider) << (divider->shift + 16);
} else {
val = readl(divider->reg);
val = clk_readl(divider->reg);
val &= ~(div_mask(divider) << divider->shift);
}
val |= value << divider->shift;
writel(val, divider->reg);
clk_writel(val, divider->reg);
if (divider->lock)
spin_unlock_irqrestore(divider->lock, flags);
@ -317,6 +317,7 @@ struct clk *clk_register_divider(struct device *dev, const char *name,
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_divider);
/**
* clk_register_divider_table - register a table based divider clock with
@ -341,3 +342,4 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
return _register_divider(dev, name, parent_name, flags, reg, shift,
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_register_divider_table);

2
drivers/clk/clk-fixed-factor.c

@ -97,6 +97,8 @@ struct clk *clk_register_fixed_factor(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_fixed_factor);
#ifdef CONFIG_OF
/**
* of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock

1
drivers/clk/clk-fixed-rate.c

@ -80,6 +80,7 @@ struct clk *clk_register_fixed_rate(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_fixed_rate);
#ifdef CONFIG_OF
/**

7
drivers/clk/clk-gate.c

@ -58,7 +58,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
if (set)
reg |= BIT(gate->bit_idx);
} else {
reg = readl(gate->reg);
reg = clk_readl(gate->reg);
if (set)
reg |= BIT(gate->bit_idx);
@ -66,7 +66,7 @@ static void clk_gate_endisable(struct clk_hw *hw, int enable)
reg &= ~BIT(gate->bit_idx);
}
writel(reg, gate->reg);
clk_writel(reg, gate->reg);
if (gate->lock)
spin_unlock_irqrestore(gate->lock, flags);
@ -89,7 +89,7 @@ static int clk_gate_is_enabled(struct clk_hw *hw)
u32 reg;
struct clk_gate *gate = to_clk_gate(hw);
reg = readl(gate->reg);
reg = clk_readl(gate->reg);
/* if a set bit disables this clk, flip it before masking */
if (gate->flags & CLK_GATE_SET_TO_DISABLE)
@ -161,3 +161,4 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_gate);

19
drivers/clk/clk-mux.c

@ -42,7 +42,7 @@ static u8 clk_mux_get_parent(struct clk_hw *hw)
* OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
* val = 0x4 really means "bit 2, index starts at bit 0"
*/
val = readl(mux->reg) >> mux->shift;
val = clk_readl(mux->reg) >> mux->shift;
val &= mux->mask;
if (mux->table) {
@ -89,11 +89,11 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
if (mux->flags & CLK_MUX_HIWORD_MASK) {
val = mux->mask << (mux->shift + 16);
} else {
val = readl(mux->reg);
val = clk_readl(mux->reg);
val &= ~(mux->mask << mux->shift);
}
val |= index << mux->shift;
writel(val, mux->reg);
clk_writel(val, mux->reg);
if (mux->lock)
spin_unlock_irqrestore(mux->lock, flags);
@ -104,9 +104,15 @@ static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops clk_mux_ops = {
.get_parent = clk_mux_get_parent,
.set_parent = clk_mux_set_parent,
.determine_rate = __clk_mux_determine_rate,
};
EXPORT_SYMBOL_GPL(clk_mux_ops);
const struct clk_ops clk_mux_ro_ops = {
.get_parent = clk_mux_get_parent,
};
EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
struct clk *clk_register_mux_table(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
void __iomem *reg, u8 shift, u32 mask,
@ -133,7 +139,10 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
}
init.name = name;
init.ops = &clk_mux_ops;
if (clk_mux_flags & CLK_MUX_READ_ONLY)
init.ops = &clk_mux_ro_ops;
else
init.ops = &clk_mux_ops;
init.flags = flags | CLK_IS_BASIC;
init.parent_names = parent_names;
init.num_parents = num_parents;
@ -154,6 +163,7 @@ struct clk *clk_register_mux_table(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_mux_table);
struct clk *clk_register_mux(struct device *dev, const char *name,
const char **parent_names, u8 num_parents, unsigned long flags,
@ -166,3 +176,4 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
flags, reg, shift, mask, clk_mux_flags,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);

4
drivers/clk/clk-nomadik.c

@ -479,12 +479,12 @@ static void __init of_nomadik_src_clk_setup(struct device_node *np)
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
static const __initconst struct of_device_id nomadik_src_match[] = {
static const struct of_device_id nomadik_src_match[] __initconst = {
{ .compatible = "stericsson,nomadik-src" },
{ /* sentinel */ }
};
static const __initconst struct of_device_id nomadik_src_clk_match[] = {
static const struct of_device_id nomadik_src_clk_match[] __initconst = {
{
.compatible = "fixed-clock",
.data = of_fixed_clk_setup,

2
drivers/clk/clk-prima2.c

@ -1034,7 +1034,7 @@ enum prima2_clk_index {
usb0, usb1, maxclk,
};
static __initdata struct clk_hw* prima2_clk_hw_array[maxclk] = {
static struct clk_hw *prima2_clk_hw_array[maxclk] __initdata = {
NULL, /* dummy */
NULL,
&clk_pll1.hw,

273
drivers/clk/clk-s2mps11.c

@ -0,0 +1,273 @@
/*
* clk-s2mps11.c - Clock driver for S2MPS11.
*
* Copyright (C) 2013 Samsung Electornics
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/module.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/clkdev.h>
#include <linux/regmap.h>
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/mfd/samsung/s2mps11.h>
#include <linux/mfd/samsung/core.h>
#define s2mps11_name(a) (a->hw.init->name)
static struct clk **clk_table;
static struct clk_onecell_data clk_data;
enum {
S2MPS11_CLK_AP = 0,
S2MPS11_CLK_CP,
S2MPS11_CLK_BT,
S2MPS11_CLKS_NUM,
};
struct s2mps11_clk {
struct sec_pmic_dev *iodev;
struct clk_hw hw;
struct clk *clk;
struct clk_lookup *lookup;
u32 mask;
bool enabled;
};
static struct s2mps11_clk *to_s2mps11_clk(struct clk_hw *hw)
{
return container_of(hw, struct s2mps11_clk, hw);
}
static int s2mps11_clk_prepare(struct clk_hw *hw)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
int ret;
ret = regmap_update_bits(s2mps11->iodev->regmap,
S2MPS11_REG_RTC_CTRL,
s2mps11->mask, s2mps11->mask);
if (!ret)
s2mps11->enabled = true;
return ret;
}
static void s2mps11_clk_unprepare(struct clk_hw *hw)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
int ret;
ret = regmap_update_bits(s2mps11->iodev->regmap, S2MPS11_REG_RTC_CTRL,
s2mps11->mask, ~s2mps11->mask);
if (!ret)
s2mps11->enabled = false;
}
static int s2mps11_clk_is_enabled(struct clk_hw *hw)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
return s2mps11->enabled;
}
static unsigned long s2mps11_clk_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct s2mps11_clk *s2mps11 = to_s2mps11_clk(hw);
if (s2mps11->enabled)
return 32768;
else
return 0;
}
static struct clk_ops s2mps11_clk_ops = {
.prepare = s2mps11_clk_prepare,
.unprepare = s2mps11_clk_unprepare,
.is_enabled = s2mps11_clk_is_enabled,
.recalc_rate = s2mps11_clk_recalc_rate,
};
static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
[S2MPS11_CLK_AP] = {
.name = "s2mps11_ap",
.ops = &s2mps11_clk_ops,
.flags = CLK_IS_ROOT,
},
[S2MPS11_CLK_CP] = {
.name = "s2mps11_cp",
.ops = &s2mps11_clk_ops,
.flags = CLK_IS_ROOT,
},
[S2MPS11_CLK_BT] = {
.name = "s2mps11_bt",
.ops = &s2mps11_clk_ops,
.flags = CLK_IS_ROOT,
},
};
static struct device_node *s2mps11_clk_parse_dt(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct device_node *clk_np;
int i;
if (!iodev->dev->of_node)
return NULL;
clk_np = of_find_node_by_name(iodev->dev->of_node, "clocks");
if (!clk_np) {
dev_err(&pdev->dev, "could not find clock sub-node\n");
return ERR_PTR(-EINVAL);
}
clk_table = devm_kzalloc(&pdev->dev, sizeof(struct clk *) *
S2MPS11_CLKS_NUM, GFP_KERNEL);
if (!clk_table)
return ERR_PTR(-ENOMEM);
for (i = 0; i < S2MPS11_CLKS_NUM; i++)
of_property_read_string_index(clk_np, "clock-output-names", i,
&s2mps11_clks_init[i].name);
return clk_np;
}
static int s2mps11_clk_probe(struct platform_device *pdev)
{
struct sec_pmic_dev *iodev = dev_get_drvdata(pdev->dev.parent);
struct s2mps11_clk *s2mps11_clks, *s2mps11_clk;
struct device_node *clk_np = NULL;
int i, ret = 0;
u32 val;
s2mps11_clks = devm_kzalloc(&pdev->dev, sizeof(*s2mps11_clk) *
S2MPS11_CLKS_NUM, GFP_KERNEL);
if (!s2mps11_clks)
return -ENOMEM;
s2mps11_clk = s2mps11_clks;
clk_np = s2mps11_clk_parse_dt(pdev);
if (IS_ERR(clk_np))
return PTR_ERR(clk_np);
for (i = 0; i < S2MPS11_CLKS_NUM; i++, s2mps11_clk++) {
s2mps11_clk->iodev = iodev;
s2mps11_clk->hw.init = &s2mps11_clks_init[i];
s2mps11_clk->mask = 1 << i;
ret = regmap_read(s2mps11_clk->iodev->regmap,
S2MPS11_REG_RTC_CTRL, &val);
if (ret < 0)
goto err_reg;
s2mps11_clk->enabled = val & s2mps11_clk->mask;
s2mps11_clk->clk = devm_clk_register(&pdev->dev,
&s2mps11_clk->hw);
if (IS_ERR(s2mps11_clk->clk)) {
dev_err(&pdev->dev, "Fail to register : %s\n",
s2mps11_name(s2mps11_clk));
ret = PTR_ERR(s2mps11_clk->clk);
goto err_reg;
}
s2mps11_clk->lookup = devm_kzalloc(&pdev->dev,
sizeof(struct clk_lookup), GFP_KERNEL);
if (!s2mps11_clk->lookup) {
ret = -ENOMEM;
goto err_lup;
}
s2mps11_clk->lookup->con_id = s2mps11_name(s2mps11_clk);
s2mps11_clk->lookup->clk = s2mps11_clk->clk;
clkdev_add(s2mps11_clk->lookup);
}
if (clk_table) {
for (i = 0; i < S2MPS11_CLKS_NUM; i++)
clk_table[i] = s2mps11_clks[i].clk;
clk_data.clks = clk_table;
clk_data.clk_num = S2MPS11_CLKS_NUM;
of_clk_add_provider(clk_np, of_clk_src_onecell_get, &clk_data);
}
platform_set_drvdata(pdev, s2mps11_clks);
return ret;
err_lup:
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
err_reg:
while (s2mps11_clk > s2mps11_clks) {
if (s2mps11_clk->lookup) {
clkdev_drop(s2mps11_clk->lookup);
devm_clk_unregister(&pdev->dev, s2mps11_clk->clk);
}
s2mps11_clk--;
}
return ret;
}
static int s2mps11_clk_remove(struct platform_device *pdev)
{
struct s2mps11_clk *s2mps11_clks = platform_get_drvdata(pdev);
int i;
for (i = 0; i < S2MPS11_CLKS_NUM; i++)
clkdev_drop(s2mps11_clks[i].lookup);
return 0;
}
static const struct platform_device_id s2mps11_clk_id[] = {
{ "s2mps11-clk", 0},
{ },
};
MODULE_DEVICE_TABLE(platform, s2mps11_clk_id);
static struct platform_driver s2mps11_clk_driver = {
.driver = {
.name = "s2mps11-clk",
.owner = THIS_MODULE,
},
.probe = s2mps11_clk_probe,
.remove = s2mps11_clk_remove,
.id_table = s2mps11_clk_id,
};
static int __init s2mps11_clk_init(void)
{
return platform_driver_register(&s2mps11_clk_driver);
}
subsys_initcall(s2mps11_clk_init);
static void __init s2mps11_clk_cleanup(void)
{
platform_driver_unregister(&s2mps11_clk_driver);
}
module_exit(s2mps11_clk_cleanup);
MODULE_DESCRIPTION("S2MPS11 Clock Driver");
MODULE_AUTHOR("Yadwinder Singh Brar <yadi.brar@samsung.com>");
MODULE_LICENSE("GPL");

4
drivers/clk/clk-u300.c

@ -746,7 +746,7 @@ struct u300_clock {
u16 clk_val;
};
struct u300_clock const __initconst u300_clk_lookup[] = {
static struct u300_clock const u300_clk_lookup[] __initconst = {
{
.type = U300_CLK_TYPE_REST,
.id = 3,
@ -1151,7 +1151,7 @@ static void __init of_u300_syscon_mclk_init(struct device_node *np)
of_clk_add_provider(np, of_clk_src_simple_get, clk);
}
static const __initconst struct of_device_id u300_clk_match[] = {
static const struct of_device_id u300_clk_match[] __initconst = {
{
.compatible = "fixed-clock",
.data = of_fixed_clk_setup,

16
drivers/clk/clk-wm831x.c

@ -31,7 +31,7 @@ struct wm831x_clk {
bool xtal_ena;
};
static int wm831x_xtal_is_enabled(struct clk_hw *hw)
static int wm831x_xtal_is_prepared(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
xtal_hw);
@ -52,7 +52,7 @@ static unsigned long wm831x_xtal_recalc_rate(struct clk_hw *hw,
}
static const struct clk_ops wm831x_xtal_ops = {
.is_enabled = wm831x_xtal_is_enabled,
.is_prepared = wm831x_xtal_is_prepared,
.recalc_rate = wm831x_xtal_recalc_rate,
};
@ -73,7 +73,7 @@ static const unsigned long wm831x_fll_auto_rates[] = {
24576000,
};
static int wm831x_fll_is_enabled(struct clk_hw *hw)
static int wm831x_fll_is_prepared(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
fll_hw);
@ -170,7 +170,7 @@ static int wm831x_fll_set_rate(struct clk_hw *hw, unsigned long rate,
if (i == ARRAY_SIZE(wm831x_fll_auto_rates))
return -EINVAL;
if (wm831x_fll_is_enabled(hw))
if (wm831x_fll_is_prepared(hw))
return -EPERM;
return wm831x_set_bits(wm831x, WM831X_CLOCK_CONTROL_2,
@ -220,7 +220,7 @@ static u8 wm831x_fll_get_parent(struct clk_hw *hw)
}
static const struct clk_ops wm831x_fll_ops = {
.is_enabled = wm831x_fll_is_enabled,
.is_prepared = wm831x_fll_is_prepared,
.prepare = wm831x_fll_prepare,
.unprepare = wm831x_fll_unprepare,
.round_rate = wm831x_fll_round_rate,
@ -237,7 +237,7 @@ static struct clk_init_data wm831x_fll_init = {
.flags = CLK_SET_RATE_GATE,
};
static int wm831x_clkout_is_enabled(struct clk_hw *hw)
static int wm831x_clkout_is_prepared(struct clk_hw *hw)
{
struct wm831x_clk *clkdata = container_of(hw, struct wm831x_clk,
clkout_hw);
@ -335,7 +335,7 @@ static int wm831x_clkout_set_parent(struct clk_hw *hw, u8 parent)
}
static const struct clk_ops wm831x_clkout_ops = {
.is_enabled = wm831x_clkout_is_enabled,
.is_prepared = wm831x_clkout_is_prepared,
.prepare = wm831x_clkout_prepare,
.unprepare = wm831x_clkout_unprepare,
.get_parent = wm831x_clkout_get_parent,
@ -360,6 +360,8 @@ static int wm831x_clk_probe(struct platform_device *pdev)
if (!clkdata)
return -ENOMEM;
clkdata->wm831x = wm831x;
/* XTAL_ENA can only be set via OTP/InstantConfig so just read once */
ret = wm831x_reg_read(wm831x, WM831X_CLOCK_CONTROL_2);
if (ret < 0) {

450
drivers/clk/clk.c

@ -458,7 +458,6 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
clk->ops->unprepare(clk->hw);
}
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
/* caller must hold prepare_lock */
static void clk_disable_unused_subtree(struct clk *clk)
@ -559,6 +558,19 @@ struct clk *__clk_get_parent(struct clk *clk)
return !clk ? NULL : clk->parent;
}
struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
{
if (!clk || index >= clk->num_parents)
return NULL;
else if (!clk->parents)
return __clk_lookup(clk->parent_names[index]);
else if (!clk->parents[index])
return clk->parents[index] =
__clk_lookup(clk->parent_names[index]);
else
return clk->parents[index];
}
unsigned int __clk_get_enable_count(struct clk *clk)
{
return !clk ? 0 : clk->enable_count;
@ -594,6 +606,7 @@ unsigned long __clk_get_flags(struct clk *clk)
{
return !clk ? 0 : clk->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
bool __clk_is_prepared(struct clk *clk)
{
@ -679,6 +692,55 @@ struct clk *__clk_lookup(const char *name)
return NULL;
}
/*
* Helper for finding best parent to provide a given frequency. This can be used
* directly as a determine_rate callback (e.g. for a mux), or from a more
* complex clock that may combine a mux with other operations.
*/
long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *best_parent_rate,
struct clk **best_parent_p)
{
struct clk *clk = hw->clk, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0;
/* if NO_REPARENT flag set, pass through to current parent */
if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
parent = clk->parent;
if (clk->flags & CLK_SET_RATE_PARENT)
best = __clk_round_rate(parent, rate);
else if (parent)
best = __clk_get_rate(parent);
else
best = __clk_get_rate(clk);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
num_parents = clk->num_parents;
for (i = 0; i < num_parents; i++) {
parent = clk_get_parent_by_index(clk, i);
if (!parent)
continue;
if (clk->flags & CLK_SET_RATE_PARENT)
parent_rate = __clk_round_rate(parent, rate);
else
parent_rate = __clk_get_rate(parent);
if (parent_rate <= rate && parent_rate > best) {
best_parent = parent;
best = parent_rate;
}
}
out:
if (best_parent)
*best_parent_p = best_parent;
*best_parent_rate = best;
return best;
}
/*** clk api ***/
void __clk_unprepare(struct clk *clk)
@ -702,7 +764,7 @@ void __clk_unprepare(struct clk *clk)
/**
* clk_unprepare - undo preparation of a clock source
* @clk: the clk being unprepare
* @clk: the clk being unprepared
*
* clk_unprepare may sleep, which differentiates it from clk_disable. In a
* simple case, clk_unprepare can be used instead of clk_disable to gate a clk
@ -869,27 +931,31 @@ EXPORT_SYMBOL_GPL(clk_enable);
/**
* __clk_round_rate - round the given rate for a clk
* @clk: round the rate of this clock
* @rate: the rate which is to be rounded
*
* Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
*/
unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long parent_rate = 0;
struct clk *parent;
if (!clk)
return 0;
if (!clk->ops->round_rate) {
if (clk->flags & CLK_SET_RATE_PARENT)
return __clk_round_rate(clk->parent, rate);
else
return clk->rate;
}
if (clk->parent)
parent_rate = clk->parent->rate;
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
parent = clk->parent;
if (parent)
parent_rate = parent->rate;
if (clk->ops->determine_rate)
return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
&parent);
else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
return __clk_round_rate(clk->parent, rate);
else
return clk->rate;
}
/**
@ -956,7 +1022,7 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
*
* Walks the subtree of clks starting with clk and recalculates rates as it
* goes. Note that if a clk does not implement the .recalc_rate callback then
* it is assumed that the clock will take on the rate of it's parent.
* it is assumed that the clock will take on the rate of its parent.
*
* clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
* if necessary.
@ -1014,6 +1080,115 @@ unsigned long clk_get_rate(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_get_rate);
static u8 clk_fetch_parent_index(struct clk *clk, struct clk *parent)
{
u8 i;
if (!clk->parents)
clk->parents = kzalloc((sizeof(struct clk*) * clk->num_parents),
GFP_KERNEL);
/*
* find index of new parent clock using cached parent ptrs,
* or if not yet cached, use string name comparison and cache
* them now to avoid future calls to __clk_lookup.
*/
for (i = 0; i < clk->num_parents; i++) {
if (clk->parents && clk->parents[i] == parent)
break;
else if (!strcmp(clk->parent_names[i], parent->name)) {
if (clk->parents)
clk->parents[i] = __clk_lookup(parent->name);
break;
}
}
return i;
}
static void clk_reparent(struct clk *clk, struct clk *new_parent)
{
hlist_del(&clk->child_node);
if (new_parent) {
/* avoid duplicate POST_RATE_CHANGE notifications */
if (new_parent->new_child == clk)
new_parent->new_child = NULL;
hlist_add_head(&clk->child_node, &new_parent->children);
} else {
hlist_add_head(&clk->child_node, &clk_orphan_list);
}
clk->parent = new_parent;
}
static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
{
unsigned long flags;
int ret = 0;
struct clk *old_parent = clk->parent;
/*
* Migrate prepare state between parents and prevent race with
* clk_enable().
*
* If the clock is not prepared, then a race with
* clk_enable/disable() is impossible since we already have the
* prepare lock (future calls to clk_enable() need to be preceded by
* a clk_prepare()).
*
* If the clock is prepared, migrate the prepared state to the new
* parent and also protect against a race with clk_enable() by
* forcing the clock and the new parent on. This ensures that all
* future calls to clk_enable() are practically NOPs with respect to
* hardware and software states.
*
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
__clk_prepare(parent);
clk_enable(parent);
clk_enable(clk);
}
/* update the clk tree topology */
flags = clk_enable_lock();
clk_reparent(clk, parent);
clk_enable_unlock(flags);
/* change clock input source */
if (parent && clk->ops->set_parent)
ret = clk->ops->set_parent(clk->hw, p_index);
if (ret) {
flags = clk_enable_lock();
clk_reparent(clk, old_parent);
clk_enable_unlock(flags);
if (clk->prepare_count) {
clk_disable(clk);
clk_disable(parent);
__clk_unprepare(parent);
}
return ret;
}
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
if (clk->prepare_count) {
clk_disable(clk);
clk_disable(old_parent);
__clk_unprepare(old_parent);
}
/* update debugfs with new clk tree topology */
clk_debug_reparent(clk, parent);
return 0;
}
/**
* __clk_speculate_rates
* @clk: first clk in the subtree
@ -1026,7 +1201,7 @@ EXPORT_SYMBOL_GPL(clk_get_rate);
* pre-rate change notifications and returns early if no clks in the
* subtree have subscribed to the notifications. Note that if a clk does not
* implement the .recalc_rate callback then it is assumed that the clock will
* take on the rate of it's parent.
* take on the rate of its parent.
*
* Caller must hold prepare_lock.
*/
@ -1058,18 +1233,25 @@ out:
return ret;
}
static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)
static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
struct clk *new_parent, u8 p_index)
{
struct clk *child;
clk->new_rate = new_rate;
clk->new_parent = new_parent;
clk->new_parent_index = p_index;
/* include clk in new parent's PRE_RATE_CHANGE notifications */
clk->new_child = NULL;
if (new_parent && new_parent != clk->parent)
new_parent->new_child = clk;
hlist_for_each_entry(child, &clk->children, child_node) {
if (child->ops->recalc_rate)
child->new_rate = child->ops->recalc_rate(child->hw, new_rate);
else
child->new_rate = new_rate;
clk_calc_subtree(child, child->new_rate);
clk_calc_subtree(child, child->new_rate, NULL, 0);
}
}
@ -1080,50 +1262,63 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate)