All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/3] Add clock driver for Actions S900 SoC
@ 2017-11-06 19:45 ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: mturquette, sboyd, afaerber, robh+dt, mark.rutland
  Cc: liuwei, mp-cs, 96boards, devicetree, arnd, davem, mchehab,
	daniel.thompson, amit.kucheria, linux-kernel, linux-clk,
	linux-arm-kernel, viresh.kumar, manivannanece23,
	Manivannan Sadhasivam

This patchset adds clock driver for Actions Semi OWL series
S900 SoC with relevant clock bindings and device tree data.

This series also addresses the review comments from previous
submission happened last year.

https://patchwork.kernel.org/patch/9254471/

Driver has been validated on Bubblegum-96 board.

Thanks,
Mani

Manivannan Sadhasivam (3):
  dt-bindings: clock: Add Actions S900 clock bindings
  arm64: dts: actions: Add S900 clock management unit nodes
  clk: actions: Add clock driver for Actions S900 SoC

 .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 ++
 MAINTAINERS                                        |   8 +
 arch/arm64/boot/dts/actions/s900.dtsi              |  20 +
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/actions/Kconfig                        |   6 +
 drivers/clk/actions/Makefile                       |   2 +
 drivers/clk/actions/owl-clk.c                      | 316 +++++++++++
 drivers/clk/actions/owl-clk.h                      | 298 +++++++++++
 drivers/clk/actions/owl-factor.c                   | 268 ++++++++++
 drivers/clk/actions/owl-pll.c                      | 344 ++++++++++++
 drivers/clk/actions/owl-s900.c                     | 585 +++++++++++++++++++++
 include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++
 13 files changed, 2035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
 create mode 100644 drivers/clk/actions/Kconfig
 create mode 100644 drivers/clk/actions/Makefile
 create mode 100644 drivers/clk/actions/owl-clk.c
 create mode 100644 drivers/clk/actions/owl-clk.h
 create mode 100644 drivers/clk/actions/owl-factor.c
 create mode 100644 drivers/clk/actions/owl-pll.c
 create mode 100644 drivers/clk/actions/owl-s900.c
 create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 0/3] Add clock driver for Actions S900 SoC
@ 2017-11-06 19:45 ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: mturquette-rdvid1DuHRBWk0Htik3J/w, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
	afaerber-l3A5Bk7waGM, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8
  Cc: liuwei-/sSyCTpAT0ql5r2w9Jh5Rg, mp-cs-/sSyCTpAT0ql5r2w9Jh5Rg,
	96boards-Ty1hIZOCd2XuufBYgWm87A,
	devicetree-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, mchehab-DgEjT+Ai2ygdnm+yROfE0A,
	daniel.thompson-QSEj5FYQhm4dnm+yROfE0A,
	amit.kucheria-QSEj5FYQhm4dnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	viresh.kumar-QSEj5FYQhm4dnm+yROfE0A,
	manivannanece23-Re5JQEeQqe8AvxtiuMwx3w, Manivannan Sadhasivam

This patchset adds clock driver for Actions Semi OWL series
S900 SoC with relevant clock bindings and device tree data.

This series also addresses the review comments from previous
submission happened last year.

https://patchwork.kernel.org/patch/9254471/

Driver has been validated on Bubblegum-96 board.

Thanks,
Mani

Manivannan Sadhasivam (3):
  dt-bindings: clock: Add Actions S900 clock bindings
  arm64: dts: actions: Add S900 clock management unit nodes
  clk: actions: Add clock driver for Actions S900 SoC

 .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 ++
 MAINTAINERS                                        |   8 +
 arch/arm64/boot/dts/actions/s900.dtsi              |  20 +
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/actions/Kconfig                        |   6 +
 drivers/clk/actions/Makefile                       |   2 +
 drivers/clk/actions/owl-clk.c                      | 316 +++++++++++
 drivers/clk/actions/owl-clk.h                      | 298 +++++++++++
 drivers/clk/actions/owl-factor.c                   | 268 ++++++++++
 drivers/clk/actions/owl-pll.c                      | 344 ++++++++++++
 drivers/clk/actions/owl-s900.c                     | 585 +++++++++++++++++++++
 include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++
 13 files changed, 2035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
 create mode 100644 drivers/clk/actions/Kconfig
 create mode 100644 drivers/clk/actions/Makefile
 create mode 100644 drivers/clk/actions/owl-clk.c
 create mode 100644 drivers/clk/actions/owl-clk.h
 create mode 100644 drivers/clk/actions/owl-factor.c
 create mode 100644 drivers/clk/actions/owl-pll.c
 create mode 100644 drivers/clk/actions/owl-s900.c
 create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 0/3] Add clock driver for Actions S900 SoC
@ 2017-11-06 19:45 ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patchset adds clock driver for Actions Semi OWL series
S900 SoC with relevant clock bindings and device tree data.

This series also addresses the review comments from previous
submission happened last year.

https://patchwork.kernel.org/patch/9254471/

Driver has been validated on Bubblegum-96 board.

Thanks,
Mani

Manivannan Sadhasivam (3):
  dt-bindings: clock: Add Actions S900 clock bindings
  arm64: dts: actions: Add S900 clock management unit nodes
  clk: actions: Add clock driver for Actions S900 SoC

 .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 ++
 MAINTAINERS                                        |   8 +
 arch/arm64/boot/dts/actions/s900.dtsi              |  20 +
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/actions/Kconfig                        |   6 +
 drivers/clk/actions/Makefile                       |   2 +
 drivers/clk/actions/owl-clk.c                      | 316 +++++++++++
 drivers/clk/actions/owl-clk.h                      | 298 +++++++++++
 drivers/clk/actions/owl-factor.c                   | 268 ++++++++++
 drivers/clk/actions/owl-pll.c                      | 344 ++++++++++++
 drivers/clk/actions/owl-s900.c                     | 585 +++++++++++++++++++++
 include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++
 13 files changed, 2035 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
 create mode 100644 drivers/clk/actions/Kconfig
 create mode 100644 drivers/clk/actions/Makefile
 create mode 100644 drivers/clk/actions/owl-clk.c
 create mode 100644 drivers/clk/actions/owl-clk.h
 create mode 100644 drivers/clk/actions/owl-factor.c
 create mode 100644 drivers/clk/actions/owl-pll.c
 create mode 100644 drivers/clk/actions/owl-s900.c
 create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

-- 
2.7.4

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/3] dt-bindings: clock: Add Actions S900 clock bindings
  2017-11-06 19:45 ` Manivannan Sadhasivam
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  -1 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: mturquette, sboyd, afaerber, robh+dt, mark.rutland
  Cc: liuwei, mp-cs, 96boards, devicetree, arnd, davem, mchehab,
	daniel.thompson, amit.kucheria, linux-kernel, linux-clk,
	linux-arm-kernel, viresh.kumar, manivannanece23,
	Manivannan Sadhasivam

Add Actions Semi S900 clock bindings.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Added binding header to this patch
2. Changed clock-controller node name to cmu
3. Added clocks property to cmu node
4. Changed compatible property value to "actions,s900-cmu"
5. Fixed example UART controller node
6. Fixed tab vs space issue

 .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 +++++++
 include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++++++++++++++++++
 2 files changed, 186 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
 create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

diff --git a/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt b/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
new file mode 100644
index 0000000..6e2c038
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
@@ -0,0 +1,47 @@
+* Actions S900 Clock Management Unit (CMU)
+
+The Actions S900 clock management unit generates and supplies clock to various
+controllers within the SoC. The clock binding described here is applicable to
+S900 SoC.
+
+Required Properties:
+
+- compatible: should be "actions,s900-cmu"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks: Reference to the parent clocks ("hosc", "losc")
+- #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
+dt-bindings/clock/actions,s900-cmu.h header and can be used in device
+tree sources.
+
+External clocks:
+
+The hosc clock used as input for the plls is generated outside the SoC. It is
+expected that it is defined using standard clock bindings as "hosc".
+
+Actions S900 CMU also requires one more clock:
+ - "losc" - internal low frequency oscillator
+
+Example: Clock Management Unit node:
+
+        cmu: clock-controller@e0160000 {
+                compatible = "actions,s900-cmu";
+                reg = <0 0xe0160000 0 0x1000>;
+                clocks = <&hosc>, <&losc>;
+                #clock-cells = <1>;
+        };
+
+Example: UART controller node that consumes clock generated by the clock
+management unit:
+
+        uart: serial@e012a000 {
+                compatible = "actions,s900-uart", "actions,owl-uart";
+                reg = <0x0 0xe012a000 0x0 0x2000>;
+                interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cmu CLK_UART5>;
+        };
diff --git a/include/dt-bindings/clock/actions,s900-cmu.h b/include/dt-bindings/clock/actions,s900-cmu.h
new file mode 100644
index 0000000..2155449
--- /dev/null
+++ b/include/dt-bindings/clock/actions,s900-cmu.h
@@ -0,0 +1,139 @@
+/*
+ * Device Tree binding constants for Actions S900 Clock Management Unit
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Copyright (c) 2017 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_S900_CMU_H
+#define __DT_BINDINGS_CLOCK_S900_CMU_H
+
+#define CLK_NONE			0
+
+/* fixed rate clocks */
+#define CLK_LOSC			1
+#define CLK_HOSC			2
+
+/* pll clocks */
+#define CLK_CORE_PLL			3
+#define CLK_DEV_PLL			4
+#define CLK_DDR_PLL			5
+#define CLK_NAND_PLL			6
+#define CLK_DISPLAY_PLL			7
+#define CLK_DSI_PLL			8
+#define CLK_ASSIST_PLL			9
+#define CLK_AUDIO_PLL			10
+
+/* system clock */
+#define CLK_CPU				15
+#define CLK_DEV				16
+#define CLK_NOC				17
+#define CLK_NOC_CLK_MUX			18
+#define CLK_NOC_CLK_DIV			19
+#define CLK_AHB				20
+#define CLK_APB				21
+#define CLK_DMAC			22
+
+/* peripheral device clock */
+#define CLK_GPIO			23
+
+#define CLK_BISP			24
+#define CLK_CSI0			25
+#define CLK_CSI1			26
+
+#define CLK_DE				27
+#define CLK_DE1				28
+#define CLK_DE2				29
+#define CLK_DE3				30
+#define CLK_DSI				32
+
+#define CLK_GPU				33
+#define CLK_GPU_CORE			34
+#define CLK_GPU_MEM			35
+#define CLK_GPU_SYS			36
+
+#define CLK_HDE				37
+#define CLK_I2C0			38
+#define CLK_I2C1			39
+#define CLK_I2C2			40
+#define CLK_I2C3			41
+#define CLK_I2C4			42
+#define CLK_I2C5			43
+#define CLK_I2SRX			44
+#define CLK_I2STX			45
+#define CLK_IMX				46
+#define CLK_LCD				47
+#define CLK_NAND0			48
+#define CLK_NAND1			49
+#define CLK_PWM0			50
+#define CLK_PWM1			51
+#define CLK_PWM2			52
+#define CLK_PWM3			53
+#define CLK_PWM4			54
+#define CLK_PWM5			55
+#define CLK_SD0				56
+#define CLK_SD1				57
+#define CLK_SD2				58
+#define CLK_SD3				59
+#define CLK_SENSOR			60
+#define CLK_SPEED_SENSOR		61
+#define CLK_SPI0			62
+#define CLK_SPI1			63
+#define CLK_SPI2			64
+#define CLK_SPI3			65
+#define CLK_THERMAL_SENSOR		66
+#define CLK_UART0			67
+#define CLK_UART1			68
+#define CLK_UART2			69
+#define CLK_UART3			70
+#define CLK_UART4			71
+#define CLK_UART5			72
+#define CLK_UART6			73
+#define CLK_VCE				74
+#define CLK_VDE				75
+
+#define CLK_USB3_480MPLL0		76
+#define CLK_USB3_480MPHY0		77
+#define CLK_USB3_5GPHY			78
+#define CLK_USB3_CCE			79
+#define CLK_USB3_MAC			80
+
+#define CLK_TIMER			83
+
+#define CLK_HDMI_AUDIO			84
+
+#define CLK_24M				85
+
+#define CLK_EDP				86
+
+#define CLK_24M_EDP			87
+#define CLK_EDP_PLL			88
+#define CLK_EDP_LINK			89
+
+#define CLK_USB2H0_PLLEN		90
+#define CLK_USB2H0_PHY			91
+#define CLK_USB2H0_CCE			92
+#define CLK_USB2H1_PLLEN		93
+#define CLK_USB2H1_PHY			94
+#define CLK_USB2H1_CCE			95
+
+#define CLK_DDR0			96
+#define CLK_DDR1			97
+#define CLK_DMM				98
+
+#define CLK_ETH_MAC			99
+#define CLK_RMII_REF			100
+
+#define CLK_NR_CLKS			110
+
+#endif /* __DT_BINDINGS_CLOCK_S900_CMU_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 1/3] dt-bindings: clock: Add Actions S900 clock bindings
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

Add Actions Semi S900 clock bindings.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Added binding header to this patch
2. Changed clock-controller node name to cmu
3. Added clocks property to cmu node
4. Changed compatible property value to "actions,s900-cmu"
5. Fixed example UART controller node
6. Fixed tab vs space issue

 .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 +++++++
 include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++++++++++++++++++
 2 files changed, 186 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
 create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

diff --git a/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt b/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
new file mode 100644
index 0000000..6e2c038
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
@@ -0,0 +1,47 @@
+* Actions S900 Clock Management Unit (CMU)
+
+The Actions S900 clock management unit generates and supplies clock to various
+controllers within the SoC. The clock binding described here is applicable to
+S900 SoC.
+
+Required Properties:
+
+- compatible: should be "actions,s900-cmu"
+- reg: physical base address of the controller and length of memory mapped
+  region.
+- clocks: Reference to the parent clocks ("hosc", "losc")
+- #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
+dt-bindings/clock/actions,s900-cmu.h header and can be used in device
+tree sources.
+
+External clocks:
+
+The hosc clock used as input for the plls is generated outside the SoC. It is
+expected that it is defined using standard clock bindings as "hosc".
+
+Actions S900 CMU also requires one more clock:
+ - "losc" - internal low frequency oscillator
+
+Example: Clock Management Unit node:
+
+        cmu: clock-controller at e0160000 {
+                compatible = "actions,s900-cmu";
+                reg = <0 0xe0160000 0 0x1000>;
+                clocks = <&hosc>, <&losc>;
+                #clock-cells = <1>;
+        };
+
+Example: UART controller node that consumes clock generated by the clock
+management unit:
+
+        uart: serial at e012a000 {
+                compatible = "actions,s900-uart", "actions,owl-uart";
+                reg = <0x0 0xe012a000 0x0 0x2000>;
+                interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+                clocks = <&cmu CLK_UART5>;
+        };
diff --git a/include/dt-bindings/clock/actions,s900-cmu.h b/include/dt-bindings/clock/actions,s900-cmu.h
new file mode 100644
index 0000000..2155449
--- /dev/null
+++ b/include/dt-bindings/clock/actions,s900-cmu.h
@@ -0,0 +1,139 @@
+/*
+ * Device Tree binding constants for Actions S900 Clock Management Unit
+ *
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Copyright (c) 2017 Linaro Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_S900_CMU_H
+#define __DT_BINDINGS_CLOCK_S900_CMU_H
+
+#define CLK_NONE			0
+
+/* fixed rate clocks */
+#define CLK_LOSC			1
+#define CLK_HOSC			2
+
+/* pll clocks */
+#define CLK_CORE_PLL			3
+#define CLK_DEV_PLL			4
+#define CLK_DDR_PLL			5
+#define CLK_NAND_PLL			6
+#define CLK_DISPLAY_PLL			7
+#define CLK_DSI_PLL			8
+#define CLK_ASSIST_PLL			9
+#define CLK_AUDIO_PLL			10
+
+/* system clock */
+#define CLK_CPU				15
+#define CLK_DEV				16
+#define CLK_NOC				17
+#define CLK_NOC_CLK_MUX			18
+#define CLK_NOC_CLK_DIV			19
+#define CLK_AHB				20
+#define CLK_APB				21
+#define CLK_DMAC			22
+
+/* peripheral device clock */
+#define CLK_GPIO			23
+
+#define CLK_BISP			24
+#define CLK_CSI0			25
+#define CLK_CSI1			26
+
+#define CLK_DE				27
+#define CLK_DE1				28
+#define CLK_DE2				29
+#define CLK_DE3				30
+#define CLK_DSI				32
+
+#define CLK_GPU				33
+#define CLK_GPU_CORE			34
+#define CLK_GPU_MEM			35
+#define CLK_GPU_SYS			36
+
+#define CLK_HDE				37
+#define CLK_I2C0			38
+#define CLK_I2C1			39
+#define CLK_I2C2			40
+#define CLK_I2C3			41
+#define CLK_I2C4			42
+#define CLK_I2C5			43
+#define CLK_I2SRX			44
+#define CLK_I2STX			45
+#define CLK_IMX				46
+#define CLK_LCD				47
+#define CLK_NAND0			48
+#define CLK_NAND1			49
+#define CLK_PWM0			50
+#define CLK_PWM1			51
+#define CLK_PWM2			52
+#define CLK_PWM3			53
+#define CLK_PWM4			54
+#define CLK_PWM5			55
+#define CLK_SD0				56
+#define CLK_SD1				57
+#define CLK_SD2				58
+#define CLK_SD3				59
+#define CLK_SENSOR			60
+#define CLK_SPEED_SENSOR		61
+#define CLK_SPI0			62
+#define CLK_SPI1			63
+#define CLK_SPI2			64
+#define CLK_SPI3			65
+#define CLK_THERMAL_SENSOR		66
+#define CLK_UART0			67
+#define CLK_UART1			68
+#define CLK_UART2			69
+#define CLK_UART3			70
+#define CLK_UART4			71
+#define CLK_UART5			72
+#define CLK_UART6			73
+#define CLK_VCE				74
+#define CLK_VDE				75
+
+#define CLK_USB3_480MPLL0		76
+#define CLK_USB3_480MPHY0		77
+#define CLK_USB3_5GPHY			78
+#define CLK_USB3_CCE			79
+#define CLK_USB3_MAC			80
+
+#define CLK_TIMER			83
+
+#define CLK_HDMI_AUDIO			84
+
+#define CLK_24M				85
+
+#define CLK_EDP				86
+
+#define CLK_24M_EDP			87
+#define CLK_EDP_PLL			88
+#define CLK_EDP_LINK			89
+
+#define CLK_USB2H0_PLLEN		90
+#define CLK_USB2H0_PHY			91
+#define CLK_USB2H0_CCE			92
+#define CLK_USB2H1_PLLEN		93
+#define CLK_USB2H1_PHY			94
+#define CLK_USB2H1_CCE			95
+
+#define CLK_DDR0			96
+#define CLK_DDR1			97
+#define CLK_DMM				98
+
+#define CLK_ETH_MAC			99
+#define CLK_RMII_REF			100
+
+#define CLK_NR_CLKS			110
+
+#endif /* __DT_BINDINGS_CLOCK_S900_CMU_H */
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/3] arm64: dts: actions: Add S900 clock management unit nodes
  2017-11-06 19:45 ` Manivannan Sadhasivam
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  -1 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: mturquette, sboyd, afaerber, robh+dt, mark.rutland
  Cc: liuwei, mp-cs, 96boards, devicetree, arnd, davem, mchehab,
	daniel.thompson, amit.kucheria, linux-kernel, linux-clk,
	linux-arm-kernel, viresh.kumar, manivannanece23,
	Manivannan Sadhasivam

Add Actions Semi S900 Clock Management Unit (CMU) nodes

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Fixed commit message
2. Changed "diff_24M" to "diff24M"
3. Changed clock-controller node name to "cmu"
4. Added clocks property
5. Moved "cmu" node under "soc" node
6. Sorted headers in alphabetical order

 arch/arm64/boot/dts/actions/s900.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/boot/dts/actions/s900.dtsi b/arch/arm64/boot/dts/actions/s900.dtsi
index 11406f6..bc0963e 100644
--- a/arch/arm64/boot/dts/actions/s900.dtsi
+++ b/arch/arm64/boot/dts/actions/s900.dtsi
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  */
 
+#include <dt-bindings/clock/actions,s900-cmu.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -88,6 +89,18 @@
 		#clock-cells = <0>;
 	};
 
+	losc: losc {
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+		#clock-cells = <0>;
+	};
+
+	diff24M: diff24M {
+		compatible = "fixed-clock";
+		clock-frequency = <24000000>;
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
@@ -154,6 +167,13 @@
 			status = "disabled";
 		};
 
+		cmu: clock-controller@e0160000 {
+			compatible = "actions,s900-cmu";
+			reg = <0 0xe0160000 0 0x1000>;
+			clocks = <&hosc>, <&losc>;
+			#clock-cells = <1>;
+		};
+
 		timer: timer@e0228000 {
 			compatible = "actions,s900-timer";
 			reg = <0x0 0xe0228000 0x0 0x8000>;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 2/3] arm64: dts: actions: Add S900 clock management unit nodes
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

Add Actions Semi S900 Clock Management Unit (CMU) nodes

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Fixed commit message
2. Changed "diff_24M" to "diff24M"
3. Changed clock-controller node name to "cmu"
4. Added clocks property
5. Moved "cmu" node under "soc" node
6. Sorted headers in alphabetical order

 arch/arm64/boot/dts/actions/s900.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/boot/dts/actions/s900.dtsi b/arch/arm64/boot/dts/actions/s900.dtsi
index 11406f6..bc0963e 100644
--- a/arch/arm64/boot/dts/actions/s900.dtsi
+++ b/arch/arm64/boot/dts/actions/s900.dtsi
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: (GPL-2.0+ OR MIT)
  */
 
+#include <dt-bindings/clock/actions,s900-cmu.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -88,6 +89,18 @@
 		#clock-cells = <0>;
 	};
 
+	losc: losc {
+		compatible = "fixed-clock";
+		clock-frequency = <32768>;
+		#clock-cells = <0>;
+	};
+
+	diff24M: diff24M {
+		compatible = "fixed-clock";
+		clock-frequency = <24000000>;
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
@@ -154,6 +167,13 @@
 			status = "disabled";
 		};
 
+		cmu: clock-controller at e0160000 {
+			compatible = "actions,s900-cmu";
+			reg = <0 0xe0160000 0 0x1000>;
+			clocks = <&hosc>, <&losc>;
+			#clock-cells = <1>;
+		};
+
 		timer: timer at e0228000 {
 			compatible = "actions,s900-timer";
 			reg = <0x0 0xe0228000 0x0 0x8000>;
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC
  2017-11-06 19:45 ` Manivannan Sadhasivam
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  -1 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: mturquette, sboyd, afaerber, robh+dt, mark.rutland
  Cc: liuwei, mp-cs, 96boards, devicetree, arnd, davem, mchehab,
	daniel.thompson, amit.kucheria, linux-kernel, linux-clk,
	linux-arm-kernel, viresh.kumar, manivannanece23,
	Manivannan Sadhasivam

Add clock driver for Actions Semi OWL series S900 SoC

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Changed the directory structure to actions/ and used owl- prefix
   for sources.
2. Fixed MAINTAINERS and added Andreas as Designated Reviewer (R:).
3. Introduced new Kconfig for S900 code part (CONFIG_CLK_OWL_S900).
4. Changed the license from GPLv2 to GPLv2+.
5. Added CLK_IGNORE_UNUSED flag to some essential PLL's

 MAINTAINERS                      |   8 +
 drivers/clk/Kconfig              |   1 +
 drivers/clk/Makefile             |   1 +
 drivers/clk/actions/Kconfig      |   6 +
 drivers/clk/actions/Makefile     |   2 +
 drivers/clk/actions/owl-clk.c    | 316 +++++++++++++++++++++
 drivers/clk/actions/owl-clk.h    | 298 ++++++++++++++++++++
 drivers/clk/actions/owl-factor.c | 268 ++++++++++++++++++
 drivers/clk/actions/owl-pll.c    | 344 +++++++++++++++++++++++
 drivers/clk/actions/owl-s900.c   | 585 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 1829 insertions(+)
 create mode 100644 drivers/clk/actions/Kconfig
 create mode 100644 drivers/clk/actions/Makefile
 create mode 100644 drivers/clk/actions/owl-clk.c
 create mode 100644 drivers/clk/actions/owl-clk.h
 create mode 100644 drivers/clk/actions/owl-factor.c
 create mode 100644 drivers/clk/actions/owl-pll.c
 create mode 100644 drivers/clk/actions/owl-s900.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2d3d750..b774081 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1098,6 +1098,14 @@ F:	arch/arm/mach-*/
 F:	arch/arm/plat-*/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 
+ARM/ACTIONS SEMI SoC CLOCK SUPPORT
+M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+R:	Andreas Färber <afaerber@suse.de>
+S:	Maintained
+F:	drivers/clk/actions/
+F:	include/dt-bindings/clock/actions,s900-cmu.h
+F:	Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
+
 ARM/ACTIONS SEMI ARCHITECTURE
 M:	Andreas Färber <afaerber@suse.de>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1c4e1aa..b063ce8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -226,6 +226,7 @@ config COMMON_CLK_VC5
 	  This driver supports the IDT VersaClock 5 and VersaClock 6
 	  programmable clock generators.
 
+source "drivers/clk/actions/Kconfig"
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/imgtec/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c99f363..5fc361b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 
 # please keep this section sorted lexicographically by directory path name
+obj-$(CONFIG_ARCH_ACTIONS)		+= actions/
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_ARTPEC)		+= axis/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
new file mode 100644
index 0000000..0de7a03
--- /dev/null
+++ b/drivers/clk/actions/Kconfig
@@ -0,0 +1,6 @@
+config CLK_OWL_S900
+	bool "Clock Driver for Actions S900 SoC"
+	depends on ARCH_ACTIONS || COMPILE_TEST
+	default ARCH_ACTIONS
+	help
+	  Build the clock driver for Actions S900 SoC.
diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
new file mode 100644
index 0000000..83bef30
--- /dev/null
+++ b/drivers/clk/actions/Makefile
@@ -0,0 +1,2 @@
+obj-y				+= owl-clk.o owl-pll.o owl-factor.o
+obj-$(CONFIG_CLK_OWL_S900)	+= owl-s900.o
diff --git a/drivers/clk/actions/owl-clk.c b/drivers/clk/actions/owl-clk.c
new file mode 100644
index 0000000..4fb1aee
--- /dev/null
+++ b/drivers/clk/actions/owl-clk.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * based on
+ *
+ * samsung/clk.c
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@owl.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "owl-clk.h"
+
+void owl_clk_add_hw_data(struct owl_clk_provider *ctx, struct clk_hw *clk_hw,
+				unsigned int id)
+{
+	if (id)
+		ctx->clk_data.hws[id] = clk_hw;
+}
+
+/* register a list of fixed factor clocks */
+void owl_clk_register_fixed_factor(struct owl_clk_provider *ctx,
+			struct owl_fixed_factor_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_fixed_factor(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				clks[i].mult, clks[i].div);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of pll clocks */
+void owl_clk_register_pll(struct owl_clk_provider *ctx,
+			struct owl_pll_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = owl_pll_clk_register(clks[i].name, clks[i].parent_name,
+				clks[i].flags, ctx->reg_base + clks[i].offset,
+				clks[i].bfreq, clks[i].enable_bit,
+				clks[i].shift, clks[i].width,
+				clks[i].min_mul, clks[i].max_mul,
+				clks[i].pll_flags, clks[i].table,
+				&ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of divider clocks */
+void owl_clk_register_divider(struct owl_clk_provider *ctx,
+		struct owl_divider_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_divider_table(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset, clks[i].shift,
+				clks[i].width, clks[i].div_flags,
+				clks[i].table, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of factor divider clocks */
+void owl_clk_register_factor(struct owl_clk_provider *ctx,
+		struct owl_factor_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = owl_factor_clk_register(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset, clks[i].shift,
+				clks[i].width, clks[i].div_flags,
+				clks[i].table, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of mux clocks */
+void owl_clk_register_mux(struct owl_clk_provider *ctx,
+		struct owl_mux_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_mux(NULL, clks[i].name,
+				clks[i].parent_names, clks[i].num_parents,
+				clks[i].flags, ctx->reg_base + clks[i].offset,
+				clks[i].shift, clks[i].width,
+				clks[i].mux_flags, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of gate clocks */
+void owl_clk_register_gate(struct owl_clk_provider *ctx,
+		struct owl_gate_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_gate(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset,
+				clks[i].bit_idx, clks[i].gate_flags,
+				&ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+static struct clk_hw *_register_composite(struct owl_clk_provider *ctx,
+			struct owl_composite_clock *cclk)
+{
+	struct clk_hw *clk_hw;
+	struct owl_mux_clock *amux;
+	struct owl_gate_clock *agate;
+	union rate_clock *arate;
+	struct clk_gate *gate = NULL;
+	struct clk_mux *mux = NULL;
+	struct clk_fixed_factor *fixed_factor = NULL;
+	struct clk_divider *div = NULL;
+	struct owl_factor *factor = NULL;
+	struct clk_hw *mux_hw = NULL;
+	struct clk_hw *gate_hw = NULL;
+	struct clk_hw *rate_hw = NULL;
+	const struct clk_ops *rate_ops = NULL;
+	const char *clk_name = cclk->name;
+	const char **parent_names;
+	int i, num_parents;
+
+	amux = &cclk->mux;
+	agate = &cclk->gate;
+	arate = &cclk->rate;
+
+	parent_names = NULL;
+	num_parents = 0;
+
+	if (amux->id) {
+		num_parents = amux->num_parents;
+		if (num_parents > 0) {
+			parent_names = kzalloc((sizeof(char *) * num_parents),
+					GFP_KERNEL);
+			if (!parent_names)
+				return ERR_PTR(-ENOMEM);
+
+			for (i = 0; i < num_parents; i++)
+				parent_names[i] = kstrdup(amux->parent_names[i],
+						GFP_KERNEL);
+		}
+
+		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+		if (!mux)
+			return NULL;
+
+		/* set up gate properties */
+		mux->reg = ctx->reg_base + amux->offset;
+		mux->shift = amux->shift;
+		mux->mask = BIT(amux->width) - 1;
+		mux->flags = amux->mux_flags;
+		mux->lock = &ctx->lock;
+		mux_hw = &mux->hw;
+	}
+
+	if (arate->fixed_factor.id) {
+		switch (cclk->type) {
+		case OWL_COMPOSITE_TYPE_FIXED_FACTOR:
+			fixed_factor = kzalloc(sizeof(*fixed_factor),
+					GFP_KERNEL);
+			if (!fixed_factor)
+				return NULL;
+			fixed_factor->mult = arate->fixed_factor.mult;
+			fixed_factor->div = arate->fixed_factor.div;
+
+			rate_ops = &clk_fixed_factor_ops;
+			rate_hw = &fixed_factor->hw;
+			break;
+
+		case OWL_COMPOSITE_TYPE_DIVIDER:
+			div = kzalloc(sizeof(*div), GFP_KERNEL);
+			if (!div)
+				return NULL;
+			div->reg = ctx->reg_base + arate->div.offset;
+			div->shift = arate->div.shift;
+			div->width = arate->div.width;
+			div->flags = arate->div.div_flags;
+			div->table = arate->div.table;
+			div->lock = &ctx->lock;
+
+			rate_ops = &clk_divider_ops;
+			rate_hw = &div->hw;
+			break;
+
+		case OWL_COMPOSITE_TYPE_FACTOR:
+			factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+			if (!factor)
+				return NULL;
+			factor->reg = ctx->reg_base + arate->factor.offset;
+			factor->shift = arate->factor.shift;
+			factor->width = arate->factor.width;
+			factor->flags = arate->factor.div_flags;
+			factor->table = arate->factor.table;
+			factor->lock = &ctx->lock;
+
+			rate_ops = &owl_factor_ops;
+			rate_hw = &factor->hw;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (agate->id) {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate)
+			return ERR_PTR(-ENOMEM);
+
+		/* set up gate properties */
+		gate->reg = ctx->reg_base + agate->offset;
+		gate->bit_idx = agate->bit_idx;
+		gate->lock = &ctx->lock;
+		gate_hw = &gate->hw;
+	}
+
+	clk_hw = clk_hw_register_composite(NULL, clk_name,
+			parent_names, num_parents,
+			mux_hw, &clk_mux_ops,
+			rate_hw, rate_ops,
+			gate_hw, &clk_gate_ops, cclk->flags);
+
+	return clk_hw;
+}
+
+/* register a list of composite clocks */
+void owl_clk_register_composite(struct owl_clk_provider *ctx,
+		struct owl_composite_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = _register_composite(ctx, &clks[i]);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
diff --git a/drivers/clk/actions/owl-clk.h b/drivers/clk/actions/owl-clk.h
new file mode 100644
index 0000000..8e61f17b
--- /dev/null
+++ b/drivers/clk/actions/owl-clk.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * based on
+ *
+ * samsung/clk.h
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@owl.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __OWL_CLK_H
+#define __OWL_CLK_H
+
+#include <linux/clk-provider.h>
+
+struct owl_clk_provider {
+	void __iomem		*reg_base;
+	struct clk_hw_onecell_data clk_data;
+	spinlock_t		lock;
+};
+
+struct owl_fixed_factor_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned int		mult;
+	unsigned int		div;
+};
+
+/* last entry should have rate = 0 */
+struct clk_pll_table {
+	unsigned int		val;
+	unsigned long		rate;
+};
+
+struct owl_pll_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	unsigned long		bfreq;
+	u8			enable_bit;
+	u8			shift;
+	u8			width;
+	u8			min_mul;
+	u8			max_mul;
+	u8			pll_flags;
+	const struct clk_pll_table *table;
+};
+
+#define CLK_OWL_PLL_FIXED_FREQ	BIT(0)
+
+struct owl_divider_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_div_table	*table;
+	const char		*alias;
+};
+
+struct clk_factor_table {
+	unsigned int		val;
+	unsigned int		mul;
+	unsigned int		div;
+};
+
+struct owl_factor_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_factor_table	*table;
+	const char		*alias;
+};
+
+struct owl_factor {
+	struct clk_hw		hw;
+	void __iomem		*reg;
+	u8			shift;
+	u8			width;
+	u8			flags;
+	const struct clk_factor_table *table;
+	spinlock_t		*lock;
+};
+
+extern const struct clk_ops owl_factor_ops;
+
+struct owl_mux_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+	const char		*alias;
+};
+
+struct owl_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+	const char		*alias;
+};
+
+union rate_clock {
+	struct owl_fixed_factor_clock	fixed_factor;
+	struct owl_divider_clock	div;
+	struct owl_factor_clock		factor;
+};
+
+struct owl_composite_clock {
+	unsigned int		id;
+	const char		*name;
+	unsigned int		type;
+	unsigned long		flags;
+
+	struct owl_mux_clock	mux;
+	struct owl_gate_clock	gate;
+	union rate_clock	rate;
+};
+
+#define OWL_COMPOSITE_TYPE_DIVIDER         1
+#define OWL_COMPOSITE_TYPE_FACTOR          2
+#define OWL_COMPOSITE_TYPE_FIXED_FACTOR    3
+#define OWL_COMPOSITE_TYPE_PASS            10
+
+#define COMP_FIXED_FACTOR_CLK(_id, _name, _flags, _mux, _gate, _fixed_factor) \
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_FIXED_FACTOR,	\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.fixed_factor = _fixed_factor,			\
+	}
+
+#define COMP_DIV_CLK(_id, _name, _flags, _mux, _gate, _div)		\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_DIVIDER,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.div	= _div,					\
+	}
+
+#define COMP_FACTOR_CLK(_id, _name, _flags, _mux, _gate, _factor)	\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_FACTOR,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.factor	= _factor,				\
+	}
+
+#define COMP_PASS_CLK(_id, _name, _flags, _mux, _gate)			\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_PASS,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+	}
+
+#define C_MUX(p, o, s, w, mf)						\
+	{								\
+		.id		= -1,					\
+		.parent_names	= p,					\
+		.num_parents	= ARRAY_SIZE(p),			\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.mux_flags	= mf,					\
+	}
+
+/* fixed mux, only one parent */
+#define C_MUX_F(p, mf)							\
+	{								\
+		.id		= -1,					\
+		.parent_names	= p,					\
+		.num_parents	= 1,					\
+		.mux_flags = mf,					\
+	}
+
+#define C_GATE(o, b, gf)						\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.bit_idx	= b,					\
+		.gate_flags	= gf,					\
+	}
+
+#define C_NULL								\
+	{								\
+		.id		= 0,					\
+	}
+
+#define C_FIXED_FACTOR(m, d)						\
+	{								\
+		.id		= -1,					\
+		.mult		= m,					\
+		.div		= d,					\
+	}
+
+#define C_DIVIDER(o, s, w, t, df)					\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.table		= t,					\
+		.div_flags	= df,					\
+	}
+
+#define C_FACTOR(o, s, w, t, df)					\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.table		= t,					\
+		.div_flags	= df,					\
+	}
+
+extern void owl_clk_register_pll(struct owl_clk_provider *ctx,
+		struct owl_pll_clock *clks, int nums);
+
+extern void owl_clk_register_fixed_factor(
+		struct owl_clk_provider *ctx,
+		struct owl_fixed_factor_clock *clks,
+		int nums);
+
+extern void owl_clk_register_divider(struct owl_clk_provider *ctx,
+		struct owl_divider_clock *clks, int nums);
+
+extern void owl_clk_register_factor(struct owl_clk_provider *ctx,
+		struct owl_factor_clock *clks, int nums);
+
+extern void owl_clk_register_mux(struct owl_clk_provider *ctx,
+		struct owl_mux_clock *clks, int nums);
+
+extern void owl_clk_register_gate(struct owl_clk_provider *ctx,
+		struct owl_gate_clock *clks, int nums);
+
+extern void owl_clk_register_composite(struct owl_clk_provider *ctx,
+		struct owl_composite_clock *clks, int nums);
+
+extern struct clk_hw *owl_pll_clk_register(const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, unsigned long bfreq, u8 enable_bit,
+		u8 shift, u8 width, u8 min_mul, u8 max_mul, u8 pll_flags,
+		const struct clk_pll_table *table, spinlock_t *lock);
+
+extern struct clk_hw *owl_factor_clk_register(struct device *dev,
+		const char *name, const char *parent_name,
+		unsigned long flags, void __iomem *reg, u8 shift,
+		u8 width, u8 clk_factor_flags,
+		const struct clk_factor_table *table, spinlock_t *lock);
+
+#endif /* __OWL_CLK_H */
diff --git a/drivers/clk/actions/owl-factor.c b/drivers/clk/actions/owl-factor.c
new file mode 100644
index 0000000..18471ec
--- /dev/null
+++ b/drivers/clk/actions/owl-factor.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "owl-clk.h"
+
+#define to_owl_factor(_hw)	container_of(_hw, struct owl_factor, hw)
+#define div_mask(d)		((1 << ((d)->width)) - 1)
+
+static unsigned int _get_table_maxval(const struct clk_factor_table *table)
+{
+	unsigned int maxval = 0;
+	const struct clk_factor_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val > maxval)
+			maxval = clkt->val;
+	return maxval;
+}
+
+static int _get_table_div_mul(const struct clk_factor_table *table,
+			unsigned int val, unsigned int *mul, unsigned int *div)
+{
+	const struct clk_factor_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++) {
+		if (clkt->val == val) {
+			*mul = clkt->mul;
+			*div = clkt->div;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static unsigned int _get_table_val(const struct clk_factor_table *table,
+			unsigned long rate, unsigned long parent_rate)
+{
+	const struct clk_factor_table *clkt;
+	int val = -1;
+	u64 calc_rate;
+
+	for (clkt = table; clkt->div; clkt++) {
+		calc_rate = parent_rate * clkt->mul;
+		do_div(calc_rate, clkt->div);
+
+		if ((unsigned long)calc_rate <= rate) {
+			val = clkt->val;
+			break;
+		}
+	}
+
+	if (val == -1)
+		val = _get_table_maxval(table);
+
+	return val;
+}
+
+static int clk_val_best(struct clk_hw *hw, unsigned long rate,
+			unsigned long *best_parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
+	unsigned long parent_rate_saved = *best_parent_rate;
+	int bestval = 0;
+
+	if (!rate)
+		rate = 1;
+
+	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+		parent_rate = *best_parent_rate;
+		bestval = _get_table_val(clkt, rate, parent_rate);
+		return bestval;
+	}
+
+	for (clkt = factor->table; clkt->div; clkt++) {
+		try_parent_rate = rate * clkt->div / clkt->mul;
+
+		if (try_parent_rate == parent_rate_saved) {
+			pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
+				__func__, clkt->val, clkt->mul, clkt->div,
+				try_parent_rate);
+			/*
+			 * It's the most ideal case if the requested rate can be
+			 * divided from parent clock without any need to change
+			 * parent rate, so return the divider immediately.
+			 */
+			*best_parent_rate = parent_rate_saved;
+			return clkt->val;
+		}
+
+		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+				try_parent_rate);
+		cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul;
+		if (cur_rate <= rate && cur_rate > best) {
+			bestval = clkt->val;
+			best = cur_rate;
+			*best_parent_rate = parent_rate;
+		}
+	}
+
+	if (!bestval) {
+		bestval = _get_table_maxval(clkt);
+		*best_parent_rate = clk_hw_round_rate(
+				clk_hw_get_parent(hw), 1);
+	}
+
+	pr_debug("%s: return bestval %d\n", __func__, bestval);
+
+	return bestval;
+}
+
+/**
+ * owl_factor_round_rate() - round a clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @prate: clock frequency of parent clock
+ */
+static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long *parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	unsigned int val, mul = 0, div = 1;
+
+	val = clk_val_best(hw, rate, parent_rate);
+	_get_table_div_mul(clkt, val, &mul, &div);
+
+	return *parent_rate * mul / div;
+}
+
+/**
+ * owl_factor_recalc_rate() - recalculate clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static unsigned long owl_factor_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	u64 rate;
+	u32 val, mul, div;
+
+	div = 0;
+	mul = 0;
+
+	val = readl(factor->reg) >> factor->shift;
+	val &= div_mask(factor);
+
+	_get_table_div_mul(clkt, val, &mul, &div);
+	if (!div) {
+		WARN(!(factor->flags & CLK_DIVIDER_ALLOW_ZERO),
+			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+			__clk_get_name(hw->clk));
+		return parent_rate;
+	}
+
+	rate = (u64)parent_rate * mul;
+	do_div(rate, div);
+
+	return rate;
+}
+
+/**
+ * owl_factor_set_rate() - set clock frequency
+ * @hw: handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	unsigned long flags = 0;
+	u32 val, v;
+
+	val = _get_table_val(factor->table, rate, parent_rate);
+
+	pr_debug("%s: get_table_val %d\n", __func__, val);
+
+	if (val > div_mask(factor))
+		val = div_mask(factor);
+
+	if (factor->lock)
+		spin_lock_irqsave(factor->lock, flags);
+
+	v = readl(factor->reg);
+	v &= ~(div_mask(factor) << factor->shift);
+	v |= val << factor->shift;
+	writel(v, factor->reg);
+
+	if (factor->lock)
+		spin_unlock_irqrestore(factor->lock, flags);
+
+	return 0;
+}
+
+const struct clk_ops owl_factor_ops = {
+	.round_rate	= owl_factor_round_rate,
+	.recalc_rate	= owl_factor_recalc_rate,
+	.set_rate	= owl_factor_set_rate,
+};
+
+/**
+ * owl_factor_clk_register() - register pll with the clock framework
+ * @name: pll name
+ * @parent: parent clock name
+ * @reg: pointer to pll control register
+ * @pll_status: pointer to pll status register
+ * @lock_index: bit index to this pll's lock status bit in pll_status
+ * @lock: register lock
+ */
+struct clk_hw *owl_factor_clk_register(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_factor_flags, const struct clk_factor_table *table,
+		spinlock_t *lock)
+
+{
+	struct owl_factor *factor;
+	struct clk_init_data initd;
+	struct clk_hw *clk_hw;
+	int ret;
+
+	factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+	if (!factor)
+		return ERR_PTR(-ENOMEM);
+
+	initd.name = name;
+	initd.ops = &owl_factor_ops;
+	initd.flags = flags;
+	initd.parent_names = (parent_name ? &parent_name : NULL);
+	initd.num_parents = (parent_name ? 1 : 0);
+
+	factor->reg = reg;
+	factor->shift = shift;
+	factor->width = width;
+	factor->flags = clk_factor_flags;
+	factor->lock = lock;
+	factor->hw.init = &initd;
+	factor->table = table;
+
+	clk_hw = &factor->hw;
+	ret = clk_hw_register(dev, clk_hw);
+	if (ret) {
+		kfree(factor);
+		clk_hw = ERR_PTR(ret);
+	}
+
+	return clk_hw;
+}
diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c
new file mode 100644
index 0000000..942b528
--- /dev/null
+++ b/drivers/clk/actions/owl-pll.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include "owl-clk.h"
+
+/**
+ * struct owl_pll
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: pll control register
+ * @lock: register lock
+ * @bfreq: base frequency of the pll. pll frequency = bfreq * mul
+ * @enable_bit: enable bit for pll
+ * @shift: shift to the multiplier bit field
+ * @width: width of the multiplier bit field
+ * @min_mul: minimum multiple for the pll
+ * @max_mul: maximum multiple for the pll
+ * @pll_flags: flags for the pll
+ * @table: pll table
+ */
+struct owl_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg;
+	spinlock_t		*lock;
+	unsigned long		bfreq;
+	u8			enable_bit;
+	u8			shift;
+	u8			width;
+	u8			min_mul;
+	u8			max_mul;
+	u8			pll_flags;
+	const struct clk_pll_table *table;
+};
+
+#define to_owl_pll(_hw)		container_of(_hw, struct owl_pll, hw)
+#define mul_mask(m)		((1 << ((m)->width)) - 1)
+#define PLL_STABILITY_WAIT_US	(50)
+
+/**
+ * owl_pll_calculate_mul() - calculate multiple for specific rate
+ * @pll: owl pll
+ * @rate: desired clock frequency
+ */
+static u32 owl_pll_calculate_mul(struct owl_pll *pll, unsigned long rate)
+{
+	u32 mul;
+
+	mul = DIV_ROUND_CLOSEST(rate, pll->bfreq);
+	if (mul < pll->min_mul)
+		mul = pll->min_mul;
+	else if (mul > pll->max_mul)
+		mul = pll->max_mul;
+
+	return mul &= mul_mask(pll);
+}
+
+static unsigned int _get_table_rate(const struct clk_pll_table *table,
+		unsigned int val)
+{
+	const struct clk_pll_table *clkt;
+
+	for (clkt = table; clkt->rate; clkt++)
+		if (clkt->val == val)
+			return clkt->rate;
+
+	return 0;
+}
+
+static const struct clk_pll_table *_get_pll_table(
+		const struct clk_pll_table *table, unsigned long rate)
+{
+	const struct clk_pll_table *clkt;
+
+	for (clkt = table; clkt->rate; clkt++) {
+		if (clkt->rate == rate) {
+			table = clkt;
+			break;
+		} else if (clkt->rate < rate)
+			table = clkt;
+	}
+
+	return table;
+}
+
+/**
+ * owl_pll_round_rate() - round a clock frequency
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @parent_rate: clock frequency of parent clock
+ */
+static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	const struct clk_pll_table *clkt;
+	u32 mul;
+
+	if (pll->table) {
+		clkt = _get_pll_table(pll->table, rate);
+		return clkt->rate;
+	}
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return pll->bfreq;
+
+	mul = owl_pll_calculate_mul(pll, rate);
+
+	return pll->bfreq * mul;
+}
+
+/**
+ * owl_pll_recalc_rate() - recalculate pll clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static unsigned long owl_pll_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long rate;
+	u32 val, mul;
+
+	if (pll->table) {
+		val = readl(pll->reg) >> pll->shift;
+		val &= mul_mask(pll);
+
+		rate = _get_table_rate(pll->table, val);
+
+		return rate;
+	}
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return pll->bfreq;
+
+	mul = (readl(pll->reg) >> pll->shift) & mul_mask(pll);
+
+	return pll->bfreq * mul;
+}
+
+/**
+ * owl_pll_is_enabled - check if pll is enabled
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * Not sure this is a good idea, but since disabled means bypassed for
+ * this clock implementation we say we are always enabled.
+ */
+static int owl_pll_is_enabled(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return !!(v & BIT(pll->enable_bit));
+}
+
+/**
+ * owl_pll_enable - enable pll clock
+ * @hw:	handle between common and hardware-specific interfaces
+ */
+static int owl_pll_enable(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	/* exit if pll is enabled */
+	if (owl_pll_is_enabled(hw))
+		return 0;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v |= BIT(pll->enable_bit);
+	writel(v, pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	udelay(PLL_STABILITY_WAIT_US);
+
+	return 0;
+}
+
+/**
+ * owl_pll_disable - disable pll clock
+ * @hw:	handle between common and hardware-specific interfaces
+ */
+static void owl_pll_disable(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	/* exit if pll is disabled */
+	if (!owl_pll_is_enabled(hw))
+		return;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v &= ~BIT(pll->enable_bit);
+	writel(v, pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+}
+
+/**
+ * owl_pll_set_rate - set pll rate
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @parent_rate: clock frequency of parent
+ */
+static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	const struct clk_pll_table *clkt;
+	unsigned long flags = 0;
+	u32 val, v;
+
+	pr_debug("%s: rate %ld, parent_rate %ld, before set rate: reg 0x%x\n",
+		__func__, rate, parent_rate, readl(pll->reg));
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return 0;
+
+	if (pll->table) {
+		clkt = _get_pll_table(pll->table, rate);
+		val = clkt->val;
+	} else {
+		val = owl_pll_calculate_mul(pll, rate);
+	}
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v &= ~mul_mask(pll);
+	v |= val << pll->shift;
+	writel(v, pll->reg);
+
+	udelay(PLL_STABILITY_WAIT_US);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	pr_debug("%s: after set rate: reg 0x%x\n", __func__,
+		readl(pll->reg));
+
+	return 0;
+}
+
+static const struct clk_ops owl_pll_ops = {
+	.enable = owl_pll_enable,
+	.disable = owl_pll_disable,
+	.is_enabled = owl_pll_is_enabled,
+	.round_rate = owl_pll_round_rate,
+	.recalc_rate = owl_pll_recalc_rate,
+	.set_rate = owl_pll_set_rate,
+};
+
+/**
+ * owl_pll_clk_register() - register pll with the clock framework
+ * @name: pll name
+ * @parent: parent clock name
+ * @reg: pointer to pll control register
+ * @pll_status: pointer to pll status register
+ * @lock_index: bit index to this pll's lock status bit in @pll_status
+ * @lock: register lock
+ */
+struct clk_hw *owl_pll_clk_register(const char *name, const char *parent_name,
+		unsigned long flags, void __iomem *reg, unsigned long bfreq,
+		u8 enable_bit, u8 shift, u8 width, u8 min_mul, u8 max_mul,
+		u8 pll_flags, const struct clk_pll_table *table,
+		spinlock_t *lock)
+{
+	struct owl_pll *pll;
+	struct clk_hw *clk_hw;
+	struct clk_init_data initd;
+	int ret;
+
+	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	initd.name = name;
+	initd.parent_names = (parent_name ? &parent_name : NULL);
+	initd.num_parents = (parent_name ? 1 : 0);
+	initd.ops = &owl_pll_ops;
+	initd.flags = flags;
+
+	pll->hw.init = &initd;
+	pll->bfreq = bfreq;
+	pll->enable_bit = enable_bit;
+	pll->shift = shift;
+	pll->width = width;
+	pll->min_mul = min_mul;
+	pll->max_mul = max_mul;
+	pll->pll_flags = pll_flags;
+	pll->table = table;
+	pll->reg = reg;
+	pll->lock = lock;
+
+	clk_hw = &pll->hw;
+	ret = clk_hw_register(NULL, clk_hw);
+	if (ret) {
+		kfree(pll);
+		clk_hw = ERR_PTR(ret);
+	}
+
+	return clk_hw;
+}
diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
new file mode 100644
index 0000000..51e297f
--- /dev/null
+++ b/drivers/clk/actions/owl-s900.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/actions,s900-cmu.h>
+#include "owl-clk.h"
+
+#define CMU_COREPLL		(0x0000)
+#define CMU_DEVPLL		(0x0004)
+#define CMU_DDRPLL		(0x0008)
+#define CMU_NANDPLL		(0x000C)
+#define CMU_DISPLAYPLL		(0x0010)
+#define CMU_AUDIOPLL		(0x0014)
+#define CMU_TVOUTPLL		(0x0018)
+#define CMU_BUSCLK		(0x001C)
+#define CMU_SENSORCLK		(0x0020)
+#define CMU_LCDCLK		(0x0024)
+#define CMU_DSICLK		(0x0028)
+#define CMU_CSICLK		(0x002C)
+#define CMU_DECLK		(0x0030)
+#define CMU_BISPCLK		(0x0034)
+#define CMU_IMXCLK		(0x0038)
+#define CMU_HDECLK		(0x003C)
+#define CMU_VDECLK		(0x0040)
+#define CMU_VCECLK		(0x0044)
+#define CMU_NANDCCLK		(0x004C)
+#define CMU_SD0CLK		(0x0050)
+#define CMU_SD1CLK		(0x0054)
+#define CMU_SD2CLK		(0x0058)
+#define CMU_UART0CLK		(0x005C)
+#define CMU_UART1CLK		(0x0060)
+#define CMU_UART2CLK		(0x0064)
+#define CMU_PWM0CLK		(0x0070)
+#define CMU_PWM1CLK		(0x0074)
+#define CMU_PWM2CLK		(0x0078)
+#define CMU_PWM3CLK		(0x007C)
+#define CMU_USBPLL		(0x0080)
+#define CMU_ASSISTPLL		(0x0084)
+#define CMU_EDPCLK		(0x0088)
+#define CMU_GPU3DCLK		(0x0090)
+#define CMU_CORECTL		(0x009C)
+#define CMU_DEVCLKEN0		(0x00A0)
+#define CMU_DEVCLKEN1		(0x00A4)
+#define CMU_DEVRST0		(0x00A8)
+#define CMU_DEVRST1		(0x00AC)
+#define CMU_UART3CLK		(0x00B0)
+#define CMU_UART4CLK		(0x00B4)
+#define CMU_UART5CLK		(0x00B8)
+#define CMU_UART6CLK		(0x00BC)
+#define CMU_TLSCLK		(0x00C0)
+#define CMU_SD3CLK		(0x00C4)
+#define CMU_PWM4CLK		(0x00C8)
+#define CMU_PWM5CLK		(0x00CC)
+
+static struct clk_pll_table clk_audio_pll_table[] = {
+	{0, 45158400}, {1, 49152000},
+	{0, 0},
+};
+
+static struct clk_pll_table clk_edp_pll_table[] = {
+	{0, 810000000}, {1, 1350000000}, {2, 2700000000},
+	{0, 0},
+};
+
+/* pll clocks */
+static struct owl_pll_clock s900_pll_clks[] = {
+	{ CLK_CORE_PLL, "core_pll", NULL, CLK_IGNORE_UNUSED, CMU_COREPLL, 24000000, 9, 0, 8,  5, 107, 0, NULL, },
+	{ CLK_DEV_PLL, "dev_pll",  NULL, CLK_IGNORE_UNUSED, CMU_DEVPLL, 6000000, 8, 0, 8, 20, 180, 0, NULL, },
+	{ CLK_DDR_PLL, "ddr_pll",  NULL, CLK_IGNORE_UNUSED, CMU_DDRPLL, 24000000, 8, 0, 8,  5,  45, 0, NULL, },
+	{ CLK_NAND_PLL, "nand_pll", NULL, CLK_IGNORE_UNUSED, CMU_NANDPLL, 6000000, 8, 0, 8,  4, 100, 0, NULL, },
+	{ CLK_DISPLAY_PLL, "display_pll", NULL, CLK_IGNORE_UNUSED, 0, 6000000, 8, 0, 8, 20, 180, 0, NULL, },
+	{ CLK_ASSIST_PLL, "assist_pll", NULL, CLK_IGNORE_UNUSED, 0, 500000000, 0, 0, 0, 0, 0, CLK_OWL_PLL_FIXED_FREQ, NULL, },
+	{ CLK_AUDIO_PLL, "audio_pll", NULL, CLK_IGNORE_UNUSED, 0, 0, 4, 0, 1, 0, 0, 0, clk_audio_pll_table, },
+
+	{ CLK_EDP_PLL, "edp_pll", "24M_edp", CLK_IGNORE_UNUSED, 0, 0, 9, 0, 2, 0, 0, 0, clk_edp_pll_table, },
+};
+
+static const char *cpu_clk_mux_p[] = { "losc", "hosc", "core_pll", };
+static const char *dev_clk_p[] = { "hosc", "dev_pll", };
+static const char *noc_clk_mux_p[] = { "dev_clk", "assist_pll", };
+static const char *dmm_clk_mux_p[] = { "dev_clk", "nand_pll", "assist_pll", "ddr_clk_src", };
+
+static const char *bisp_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *csi_clk_mux_p[] = { "display_pll", "dev_clk", };
+static const char *de_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *eth_mac_clk_mux_p[] = { "assist_pll", };
+static const char *gpu_clk_mux_p[] = { "dev_clk", "display_pll", "", "ddr_clk_src", };
+static const char *hde_clk_mux_p[] = { "dev_clk", "display_pll", "", "ddr_clk_src", };
+static const char *i2c_clk_mux_p[] = { "assist_pll", };
+static const char *imx_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *lcd_clk_mux_p[] = { "display_pll", "nand_pll", };
+static const char *nand_clk_mux_p[] = { "dev_clk", "nand_pll", };
+static const char *pwm_clk_mux_p[] = { "hosc" };
+static const char *sd_clk_mux_p[] = { "dev_clk", "nand_pll", };
+static const char *sensor_clk_mux_p[] = { "hosc", "bisp", };
+static const char *speed_sensor_clk_mux_p[] = { "hosc", };
+static const char *spi_clk_mux_p[] = { "ahb_clk", };
+static const char *thermal_sensor_clk_mux_p[] = { "hosc", };
+static const char *uart_clk_mux_p[] = { "hosc", "dev_pll", };
+static const char *vce_clk_mux_p[] = { "dev_clk", "display_pll", "assist_pll", "ddr_clk_src", };
+static const char *i2s_clk_mux_p[] = { "audio_pll", };
+
+static const char *edp_clk_mux_p[] = { "assist_pll", "display_pll", };
+
+/* mux clocks */
+static struct owl_mux_clock s900_mux_clks[] = {
+	{ CLK_CPU,  "cpu_clk", cpu_clk_mux_p, ARRAY_SIZE(cpu_clk_mux_p), CLK_SET_RATE_PARENT, CMU_BUSCLK, 0, 2, 0, "cpu_clk", },
+	{ CLK_DEV,  "dev_clk", dev_clk_p, ARRAY_SIZE(dev_clk_p), CLK_SET_RATE_PARENT, CMU_DEVPLL, 12, 1, 0, "dev_clk", },
+	{ CLK_NOC_CLK_MUX,  "noc_clk_mux", noc_clk_mux_p, ARRAY_SIZE(noc_clk_mux_p), CLK_SET_RATE_PARENT, CMU_BUSCLK, 7, 1, 0, },
+};
+
+static struct clk_div_table nand_div_table[] = {
+	{0, 1},   {1, 2},   {2, 4},   {3, 6},
+	{4, 8},   {5, 10},  {6, 12},  {7, 14},
+	{8, 16},  {9, 18},  {10, 20}, {11, 22},
+	{12, 24}, {13, 26}, {14, 28}, {15, 30},
+	{0, 0},
+};
+
+static struct clk_factor_table sd_factor_table[] = {
+	/* bit0 ~ 4 */
+	{0, 1, 1}, {1, 1, 2}, {2, 1, 3}, {3, 1, 4},
+	{4, 1, 5}, {5, 1, 6}, {6, 1, 7}, {7, 1, 8},
+	{8, 1, 9}, {9, 1, 10}, {10, 1, 11}, {11, 1, 12},
+	{12, 1, 13}, {13, 1, 14}, {14, 1, 15}, {15, 1, 16},
+	{16, 1, 17}, {17, 1, 18}, {18, 1, 19}, {19, 1, 20},
+	{20, 1, 21}, {21, 1, 22}, {22, 1, 23}, {23, 1, 24},
+	{24, 1, 25}, {25, 1, 26}, {26, 1, 27}, {27, 1, 28},
+	{28, 1, 29}, {29, 1, 30}, {30, 1, 31}, {31, 1, 32},
+
+	/* bit8: /128 */
+	{256, 1, 1 * 128}, {257, 1, 2 * 128}, {258, 1, 3 * 128}, {259, 1, 4 * 128},
+	{260, 1, 5 * 128}, {261, 1, 6 * 128}, {262, 1, 7 * 128}, {263, 1, 8 * 128},
+	{264, 1, 9 * 128}, {265, 1, 10 * 128}, {266, 1, 11 * 128}, {267, 1, 12 * 128},
+	{268, 1, 13 * 128}, {269, 1, 14 * 128}, {270, 1, 15 * 128}, {271, 1, 16 * 128},
+	{272, 1, 17 * 128}, {273, 1, 18 * 128}, {274, 1, 19 * 128}, {275, 1, 20 * 128},
+	{276, 1, 21 * 128}, {277, 1, 22 * 128}, {278, 1, 23 * 128}, {279, 1, 24 * 128},
+	{280, 1, 25 * 128}, {281, 1, 26 * 128}, {282, 1, 27 * 128}, {283, 1, 28 * 128},
+	{284, 1, 29 * 128}, {285, 1, 30 * 128}, {286, 1, 31 * 128}, {287, 1, 32 * 128},
+
+	{0, 0},
+};
+
+static struct clk_div_table apb_div_table[] = {
+	{1, 2},   {2, 3},   {3, 4},
+	{0, 0},
+};
+
+static struct clk_div_table eth_mac_div_table[] = {
+	{0, 2},   {1, 4},
+	{0, 0},
+};
+
+static struct clk_div_table rmii_ref_div_table[] = {
+	{0, 4},   {1, 10},
+	{0, 0},
+};
+
+static struct clk_div_table usb3_mac_div_table[] = {
+	{1, 2},   {2, 3},   {3, 4},
+	{0, 8},
+};
+
+static struct clk_div_table i2s_div_table[] = {
+	{0, 1},   {1, 2},   {2, 3},   {3, 4},
+	{4, 6},   {5, 8},   {6, 12},  {7, 16},
+	{8, 24},
+	{0, 0},
+};
+
+static struct clk_div_table hdmia_div_table[] = {
+	{0, 1},   {1, 2},   {2, 3},   {3, 4},
+	{4, 6},   {5, 8},   {6, 12},  {7, 16},
+	{8, 24},
+	{0, 0},
+};
+
+
+/* divider clocks */
+static struct owl_divider_clock s900_div_clks[] = {
+	{ CLK_NOC_CLK_DIV, "noc_clk_div", "noc_clk", 0, CMU_BUSCLK, 19, 1, 0, NULL, },
+	{ CLK_AHB, "ahb_clk", "noc_clk_div", 0, CMU_BUSCLK, 4, 1, 0, NULL, "ahb_clk", },
+	{ CLK_APB, "apb_clk", "ahb_clk", 0, CMU_BUSCLK, 8, 2, 0, apb_div_table, "apb_clk", },
+	{ CLK_USB3_MAC, "usb3_mac", "assist_pll", 0, CMU_ASSISTPLL, 12, 2, 0, usb3_mac_div_table, "usb3_mac", },
+	{ CLK_RMII_REF, "rmii_ref", "assist_pll", 0, CMU_ASSISTPLL, 8, 1, 0, rmii_ref_div_table, "rmii_ref", },
+};
+
+static struct clk_factor_table dmm_factor_table[] = {
+	{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 1, 3},
+	{4, 1, 4},
+	{0, 0, 0},
+};
+
+static struct clk_factor_table noc_factor_table[] = {
+	{0, 1, 1},   {1, 2, 3},   {2, 1, 2}, {3, 1, 3},  {4, 1, 4},
+	{0, 0, 0},
+};
+
+static struct clk_factor_table bisp_factor_table[] = {
+	{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5},
+	{4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8},
+	{0, 0, 0},
+};
+
+/* divider clocks */
+static struct owl_factor_clock s900_factor_clks[] = {
+	{ CLK_NOC, "noc_clk", "noc_clk_mux", 0, CMU_BUSCLK, 16, 3, 0, noc_factor_table, "noc_clk", },
+	{ CLK_DE1, "de_clk1", "de_clk", 0, CMU_DECLK, 0, 3, 0, bisp_factor_table, "de_clk1", },
+	{ CLK_DE2, "de_clk2", "de_clk", 0, CMU_DECLK, 4, 3, 0, bisp_factor_table, "de_clk2", },
+	{ CLK_DE3, "de_clk3", "de_clk", 0, CMU_DECLK, 8, 3, 0, bisp_factor_table, "de_clk3", },
+};
+
+/* gate clocks */
+static struct owl_gate_clock s900_gate_clks[] = {
+	{ CLK_GPIO,  "gpio", "apb_clk", 0, CMU_DEVCLKEN0, 18, 0, "gpio", },
+	{ CLK_GPU,   "gpu", NULL, 0, CMU_DEVCLKEN0, 30, 0, "gpu", },
+	{ CLK_DMAC,  "dmac", "noc_clk_div", 0, CMU_DEVCLKEN0, 1, 0, "dmac", },
+	{ CLK_TIMER,  "timer", "hosc", 0, CMU_DEVCLKEN1, 27, 0, "timer", },
+	{ CLK_DSI,  "dsi_clk", NULL, 0, CMU_DEVCLKEN0, 12, 0, "dsi", },
+
+	{ CLK_DDR0,  "ddr0_clk", "ddr_pll", CLK_IGNORE_UNUSED, CMU_DEVCLKEN0, 31, 0, "ddr0", },
+	{ CLK_DDR1,  "ddr1_clk", "ddr_pll", CLK_IGNORE_UNUSED, CMU_DEVCLKEN0, 29, 0, "ddr1", },
+
+	{ CLK_USB3_480MPLL0,	"usb3_480mpll0",	NULL, 0, CMU_USBPLL, 3, 0, "usb3_480mpll0", },
+	{ CLK_USB3_480MPHY0,	"usb3_480mphy0",	NULL, 0, CMU_USBPLL, 2, 0, "usb3_480mphy0", },
+	{ CLK_USB3_5GPHY,	"usb3_5gphy",		NULL, 0, CMU_USBPLL, 1, 0, "usb3_5gphy", },
+	{ CLK_USB3_CCE,		"usb3_cce",		NULL, 0, CMU_USBPLL, 0, 0, "usb3_cce", },
+
+	{ CLK_24M_EDP,		"24M_edp",		"diff24M", 0, CMU_EDPCLK, 8, 0, "24M_edp", },
+	{ CLK_EDP_LINK,		"edp_link",		"edp_pll", 0, CMU_DEVCLKEN0, 10, 0, "edp_link", },
+
+	{ CLK_USB2H0_PLLEN,	"usbh0_pllen",	NULL, 0, CMU_USBPLL, 12, 0, "usbh0_pllen", },
+	{ CLK_USB2H0_PHY,	"usbh0_phy",	NULL, 0, CMU_USBPLL, 10, 0, "usbh0_phy", },
+	{ CLK_USB2H0_CCE,	"usbh0_cce",		NULL, 0, CMU_USBPLL, 8, 0, "usbh0_cce", },
+
+	{ CLK_USB2H1_PLLEN,	"usbh1_pllen",	NULL, 0, CMU_USBPLL, 13, 0, "usbh1_pllen", },
+	{ CLK_USB2H1_PHY,	"usbh1_phy",	NULL, 0, CMU_USBPLL, 11, 0, "usbh1_phy", },
+	{ CLK_USB2H1_CCE,	"usbh1_cce",		NULL, 0, CMU_USBPLL, 9, 0, "usbh1_cce", },
+};
+
+static struct owl_composite_clock s900_composite_clks[] = {
+	COMP_FACTOR_CLK(CLK_BISP, "bisp", 0,
+			C_MUX(bisp_clk_mux_p, CMU_BISPCLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 14, 0),
+			C_FACTOR(CMU_BISPCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_CSI0, "csi0", 0,
+			C_MUX(csi_clk_mux_p, CMU_CSICLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 13, 0),
+			C_DIVIDER(CMU_CSICLK, 0, 4, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_CSI1, "csi1", 0,
+			C_MUX(csi_clk_mux_p, CMU_CSICLK, 20, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 15, 0),
+			C_DIVIDER(CMU_CSICLK, 16, 4, NULL, 0)),
+
+	COMP_PASS_CLK(CLK_DE, "de_clk", 0,
+			C_MUX(de_clk_mux_p, CMU_DECLK, 12, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 8, 0)),
+
+	COMP_FACTOR_CLK(CLK_DMM, "dmm", CLK_IGNORE_UNUSED,
+			C_MUX(dmm_clk_mux_p, CMU_BUSCLK, 10, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 19, 0),
+			C_FACTOR(CMU_BUSCLK, 12, 3, dmm_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_EDP, "edp_clk", 0,
+			C_MUX(edp_clk_mux_p, CMU_EDPCLK, 19, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 10, 0),
+			C_FACTOR(CMU_EDPCLK, 16, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_ETH_MAC, "eth_mac", 0,
+			C_MUX_F(eth_mac_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 22, 0),
+			C_DIVIDER(CMU_ASSISTPLL, 10, 1, eth_mac_div_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_CORE, "gpu_core", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 4, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 15, 0),
+			C_FACTOR(CMU_GPU3DCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_MEM, "gpu_mem", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 20, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 14, 0),
+			C_FACTOR(CMU_GPU3DCLK, 16, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_SYS, "gpu_sys", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 28, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 13, 0),
+			C_FACTOR(CMU_GPU3DCLK, 24, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_HDE, "hde", 0,
+			C_MUX(hde_clk_mux_p, CMU_HDECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 27, 0),
+			C_FACTOR(CMU_HDECLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_HDMI_AUDIO, "hdmia", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 22, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 24, 4, hdmia_div_table, 0)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C0, "i2c0", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 14, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C1, "i2c1", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 15, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C2, "i2c2", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 30, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C3, "i2c3", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 31, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C4, "i2c4", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN0, 17, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C5, "i2c5", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 1, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_DIV_CLK(CLK_I2SRX, "i2srx", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 21, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 20, 4, i2s_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_I2STX, "i2stx", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 20, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 16, 4, i2s_div_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_IMX, "imx", 0,
+			C_MUX(imx_clk_mux_p, CMU_IMXCLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 17, 0),
+			C_FACTOR(CMU_IMXCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_LCD, "lcd", 0,
+			C_MUX(lcd_clk_mux_p, CMU_LCDCLK, 12, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 9, 0),
+			C_DIVIDER(CMU_LCDCLK, 0, 5, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_NAND0, "nand0", CLK_SET_RATE_PARENT,
+			C_MUX(nand_clk_mux_p, CMU_NANDCCLK, 8, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 4, 0),
+			C_DIVIDER(CMU_NANDCCLK, 0, 4, nand_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_NAND1, "nand1", CLK_SET_RATE_PARENT,
+			C_MUX(nand_clk_mux_p, CMU_NANDCCLK, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 11, 0),
+			C_DIVIDER(CMU_NANDCCLK, 16, 4, nand_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm0", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 23, 0),
+			C_DIVIDER(CMU_PWM0CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm1", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 24, 0),
+			C_DIVIDER(CMU_PWM1CLK, 0, 6, NULL, 0)),
+	/*
+	 * pwm2 may be for backlight, do not gate it
+	 * even it is "unused", because it may be
+	 * enabled at boot stage, and in kernel, driver
+	 * has no effective method to know the real status,
+	 * so, the best way is keeping it as what it was.
+	 */
+	COMP_DIV_CLK(CLK_PWM0, "pwm2", CLK_IGNORE_UNUSED,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 25, 0),
+			C_DIVIDER(CMU_PWM2CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm3", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 26, 0),
+			C_DIVIDER(CMU_PWM3CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm4", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 4, 0),
+			C_DIVIDER(CMU_PWM4CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM5, "pwm5", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 5, 0),
+			C_DIVIDER(CMU_PWM5CLK, 0, 6, NULL, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD0, "sd0", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD0CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 5, 0),
+			C_FACTOR(CMU_SD0CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD1, "sd1", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD1CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 6, 0),
+			C_FACTOR(CMU_SD1CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD2, "sd2", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD2CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 7, 0),
+			C_FACTOR(CMU_SD2CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD3, "sd3", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD3CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 16, 0),
+			C_FACTOR(CMU_SD3CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_SENSOR, "sensor", 0,
+			C_MUX(sensor_clk_mux_p, CMU_SENSORCLK, 4, 1, 0),
+			C_NULL,
+			C_DIVIDER(CMU_SENSORCLK, 0, 4, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_SPEED_SENSOR, "speed_sensor", 0,
+			C_MUX_F(speed_sensor_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 0, 0),
+			C_DIVIDER(CMU_TLSCLK, 0, 4, NULL, CLK_DIVIDER_POWER_OF_TWO)),
+
+	COMP_PASS_CLK(CLK_SPI0, "spi0", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 10, 0)),
+
+	COMP_PASS_CLK(CLK_SPI1, "spi1", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 11, 0)),
+
+	COMP_PASS_CLK(CLK_SPI2, "spi2", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 12, 0)),
+
+	COMP_PASS_CLK(CLK_SPI3, "spi3", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 13, 0)),
+
+	COMP_DIV_CLK(CLK_THERMAL_SENSOR, "thermal_sensor", 0,
+			C_MUX_F(thermal_sensor_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 2, 0),
+			C_DIVIDER(CMU_TLSCLK, 8, 4, NULL, CLK_DIVIDER_POWER_OF_TWO)),
+
+	COMP_DIV_CLK(CLK_UART0, "uart0", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART0CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 6, 0),
+			C_DIVIDER(CMU_UART0CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART1, "uart1", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART1CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 7, 0),
+			C_DIVIDER(CMU_UART1CLK, 1, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART2, "uart2", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART2CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 8, 0),
+			C_DIVIDER(CMU_UART2CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART3, "uart3", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART3CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 19, 0),
+			C_DIVIDER(CMU_UART3CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART4, "uart4", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART4CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 20, 0),
+			C_DIVIDER(CMU_UART4CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART5, "uart5", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART5CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 21, 0),
+			C_DIVIDER(CMU_UART5CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART6, "uart6", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART6CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 18, 0),
+			C_DIVIDER(CMU_UART6CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_FACTOR_CLK(CLK_VCE, "vce", 0,
+			C_MUX(vce_clk_mux_p, CMU_VCECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 26, 0),
+			C_FACTOR(CMU_VCECLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_VDE, "vde", 0,
+			C_MUX(hde_clk_mux_p, CMU_VDECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 25, 0),
+			C_FACTOR(CMU_VDECLK, 0, 3, bisp_factor_table, 0)),
+};
+
+static int s900_clk_probe(struct platform_device *pdev)
+{
+	struct owl_clk_provider *ctx;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	void __iomem *base;
+	int i;
+
+	ctx = kzalloc(sizeof(struct owl_clk_provider) +
+			sizeof(*ctx->clk_data.hws) * CLK_NR_CLKS, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	for (i = 0; i < CLK_NR_CLKS; ++i)
+		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
+
+	ctx->reg_base = base;
+	ctx->clk_data.num = CLK_NR_CLKS;
+	spin_lock_init(&ctx->lock);
+
+	/* register pll clocks */
+	owl_clk_register_pll(ctx, s900_pll_clks,
+			ARRAY_SIZE(s900_pll_clks));
+
+	/* register divider clocks */
+	owl_clk_register_divider(ctx, s900_div_clks,
+			ARRAY_SIZE(s900_div_clks));
+
+	/* register factor divider clocks */
+	owl_clk_register_factor(ctx, s900_factor_clks,
+			ARRAY_SIZE(s900_factor_clks));
+
+	/* register mux clocks */
+	owl_clk_register_mux(ctx, s900_mux_clks,
+			ARRAY_SIZE(s900_mux_clks));
+
+	/* register gate clocks */
+	owl_clk_register_gate(ctx, s900_gate_clks,
+			ARRAY_SIZE(s900_gate_clks));
+
+	/* register composite clocks */
+	owl_clk_register_composite(ctx, s900_composite_clks,
+			ARRAY_SIZE(s900_composite_clks));
+
+	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				&ctx->clk_data);
+
+}
+
+static const struct of_device_id s900_clk_of_match[] = {
+	{ .compatible = "actions,s900-cmu", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s900_clk_of_match);
+
+static struct platform_driver s900_clk_driver = {
+	.probe = s900_clk_probe,
+	.driver = {
+		.name = "s900-cmu",
+		.of_match_table = s900_clk_of_match,
+	},
+};
+
+static int __init s900_clk_init(void)
+{
+	return platform_driver_register(&s900_clk_driver);
+}
+core_initcall(s900_clk_init);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC
@ 2017-11-06 19:45   ` Manivannan Sadhasivam
  0 siblings, 0 replies; 14+ messages in thread
From: Manivannan Sadhasivam @ 2017-11-06 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

Add clock driver for Actions Semi OWL series S900 SoC

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
Changes in v2:

1. Changed the directory structure to actions/ and used owl- prefix
   for sources.
2. Fixed MAINTAINERS and added Andreas as Designated Reviewer (R:).
3. Introduced new Kconfig for S900 code part (CONFIG_CLK_OWL_S900).
4. Changed the license from GPLv2 to GPLv2+.
5. Added CLK_IGNORE_UNUSED flag to some essential PLL's

 MAINTAINERS                      |   8 +
 drivers/clk/Kconfig              |   1 +
 drivers/clk/Makefile             |   1 +
 drivers/clk/actions/Kconfig      |   6 +
 drivers/clk/actions/Makefile     |   2 +
 drivers/clk/actions/owl-clk.c    | 316 +++++++++++++++++++++
 drivers/clk/actions/owl-clk.h    | 298 ++++++++++++++++++++
 drivers/clk/actions/owl-factor.c | 268 ++++++++++++++++++
 drivers/clk/actions/owl-pll.c    | 344 +++++++++++++++++++++++
 drivers/clk/actions/owl-s900.c   | 585 +++++++++++++++++++++++++++++++++++++++
 10 files changed, 1829 insertions(+)
 create mode 100644 drivers/clk/actions/Kconfig
 create mode 100644 drivers/clk/actions/Makefile
 create mode 100644 drivers/clk/actions/owl-clk.c
 create mode 100644 drivers/clk/actions/owl-clk.h
 create mode 100644 drivers/clk/actions/owl-factor.c
 create mode 100644 drivers/clk/actions/owl-pll.c
 create mode 100644 drivers/clk/actions/owl-s900.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 2d3d750..b774081 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1098,6 +1098,14 @@ F:	arch/arm/mach-*/
 F:	arch/arm/plat-*/
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
 
+ARM/ACTIONS SEMI SoC CLOCK SUPPORT
+M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+R:	Andreas F?rber <afaerber@suse.de>
+S:	Maintained
+F:	drivers/clk/actions/
+F:	include/dt-bindings/clock/actions,s900-cmu.h
+F:	Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
+
 ARM/ACTIONS SEMI ARCHITECTURE
 M:	Andreas F?rber <afaerber@suse.de>
 L:	linux-arm-kernel at lists.infradead.org (moderated for non-subscribers)
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1c4e1aa..b063ce8 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -226,6 +226,7 @@ config COMMON_CLK_VC5
 	  This driver supports the IDT VersaClock 5 and VersaClock 6
 	  programmable clock generators.
 
+source "drivers/clk/actions/Kconfig"
 source "drivers/clk/bcm/Kconfig"
 source "drivers/clk/hisilicon/Kconfig"
 source "drivers/clk/imgtec/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index c99f363..5fc361b 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_COMMON_CLK_WM831X)		+= clk-wm831x.o
 obj-$(CONFIG_COMMON_CLK_XGENE)		+= clk-xgene.o
 
 # please keep this section sorted lexicographically by directory path name
+obj-$(CONFIG_ARCH_ACTIONS)		+= actions/
 obj-$(CONFIG_COMMON_CLK_AT91)		+= at91/
 obj-$(CONFIG_ARCH_ARTPEC)		+= axis/
 obj-$(CONFIG_ARC_PLAT_AXS10X)		+= axs10x/
diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
new file mode 100644
index 0000000..0de7a03
--- /dev/null
+++ b/drivers/clk/actions/Kconfig
@@ -0,0 +1,6 @@
+config CLK_OWL_S900
+	bool "Clock Driver for Actions S900 SoC"
+	depends on ARCH_ACTIONS || COMPILE_TEST
+	default ARCH_ACTIONS
+	help
+	  Build the clock driver for Actions S900 SoC.
diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
new file mode 100644
index 0000000..83bef30
--- /dev/null
+++ b/drivers/clk/actions/Makefile
@@ -0,0 +1,2 @@
+obj-y				+= owl-clk.o owl-pll.o owl-factor.o
+obj-$(CONFIG_CLK_OWL_S900)	+= owl-s900.o
diff --git a/drivers/clk/actions/owl-clk.c b/drivers/clk/actions/owl-clk.c
new file mode 100644
index 0000000..4fb1aee
--- /dev/null
+++ b/drivers/clk/actions/owl-clk.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * based on
+ *
+ * samsung/clk.c
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@owl.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "owl-clk.h"
+
+void owl_clk_add_hw_data(struct owl_clk_provider *ctx, struct clk_hw *clk_hw,
+				unsigned int id)
+{
+	if (id)
+		ctx->clk_data.hws[id] = clk_hw;
+}
+
+/* register a list of fixed factor clocks */
+void owl_clk_register_fixed_factor(struct owl_clk_provider *ctx,
+			struct owl_fixed_factor_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_fixed_factor(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				clks[i].mult, clks[i].div);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of pll clocks */
+void owl_clk_register_pll(struct owl_clk_provider *ctx,
+			struct owl_pll_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = owl_pll_clk_register(clks[i].name, clks[i].parent_name,
+				clks[i].flags, ctx->reg_base + clks[i].offset,
+				clks[i].bfreq, clks[i].enable_bit,
+				clks[i].shift, clks[i].width,
+				clks[i].min_mul, clks[i].max_mul,
+				clks[i].pll_flags, clks[i].table,
+				&ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of divider clocks */
+void owl_clk_register_divider(struct owl_clk_provider *ctx,
+		struct owl_divider_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_divider_table(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset, clks[i].shift,
+				clks[i].width, clks[i].div_flags,
+				clks[i].table, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of factor divider clocks */
+void owl_clk_register_factor(struct owl_clk_provider *ctx,
+		struct owl_factor_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = owl_factor_clk_register(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset, clks[i].shift,
+				clks[i].width, clks[i].div_flags,
+				clks[i].table, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of mux clocks */
+void owl_clk_register_mux(struct owl_clk_provider *ctx,
+		struct owl_mux_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_mux(NULL, clks[i].name,
+				clks[i].parent_names, clks[i].num_parents,
+				clks[i].flags, ctx->reg_base + clks[i].offset,
+				clks[i].shift, clks[i].width,
+				clks[i].mux_flags, &ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+/* register a list of gate clocks */
+void owl_clk_register_gate(struct owl_clk_provider *ctx,
+		struct owl_gate_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = clk_hw_register_gate(NULL, clks[i].name,
+				clks[i].parent_name, clks[i].flags,
+				ctx->reg_base + clks[i].offset,
+				clks[i].bit_idx, clks[i].gate_flags,
+				&ctx->lock);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
+
+static struct clk_hw *_register_composite(struct owl_clk_provider *ctx,
+			struct owl_composite_clock *cclk)
+{
+	struct clk_hw *clk_hw;
+	struct owl_mux_clock *amux;
+	struct owl_gate_clock *agate;
+	union rate_clock *arate;
+	struct clk_gate *gate = NULL;
+	struct clk_mux *mux = NULL;
+	struct clk_fixed_factor *fixed_factor = NULL;
+	struct clk_divider *div = NULL;
+	struct owl_factor *factor = NULL;
+	struct clk_hw *mux_hw = NULL;
+	struct clk_hw *gate_hw = NULL;
+	struct clk_hw *rate_hw = NULL;
+	const struct clk_ops *rate_ops = NULL;
+	const char *clk_name = cclk->name;
+	const char **parent_names;
+	int i, num_parents;
+
+	amux = &cclk->mux;
+	agate = &cclk->gate;
+	arate = &cclk->rate;
+
+	parent_names = NULL;
+	num_parents = 0;
+
+	if (amux->id) {
+		num_parents = amux->num_parents;
+		if (num_parents > 0) {
+			parent_names = kzalloc((sizeof(char *) * num_parents),
+					GFP_KERNEL);
+			if (!parent_names)
+				return ERR_PTR(-ENOMEM);
+
+			for (i = 0; i < num_parents; i++)
+				parent_names[i] = kstrdup(amux->parent_names[i],
+						GFP_KERNEL);
+		}
+
+		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+		if (!mux)
+			return NULL;
+
+		/* set up gate properties */
+		mux->reg = ctx->reg_base + amux->offset;
+		mux->shift = amux->shift;
+		mux->mask = BIT(amux->width) - 1;
+		mux->flags = amux->mux_flags;
+		mux->lock = &ctx->lock;
+		mux_hw = &mux->hw;
+	}
+
+	if (arate->fixed_factor.id) {
+		switch (cclk->type) {
+		case OWL_COMPOSITE_TYPE_FIXED_FACTOR:
+			fixed_factor = kzalloc(sizeof(*fixed_factor),
+					GFP_KERNEL);
+			if (!fixed_factor)
+				return NULL;
+			fixed_factor->mult = arate->fixed_factor.mult;
+			fixed_factor->div = arate->fixed_factor.div;
+
+			rate_ops = &clk_fixed_factor_ops;
+			rate_hw = &fixed_factor->hw;
+			break;
+
+		case OWL_COMPOSITE_TYPE_DIVIDER:
+			div = kzalloc(sizeof(*div), GFP_KERNEL);
+			if (!div)
+				return NULL;
+			div->reg = ctx->reg_base + arate->div.offset;
+			div->shift = arate->div.shift;
+			div->width = arate->div.width;
+			div->flags = arate->div.div_flags;
+			div->table = arate->div.table;
+			div->lock = &ctx->lock;
+
+			rate_ops = &clk_divider_ops;
+			rate_hw = &div->hw;
+			break;
+
+		case OWL_COMPOSITE_TYPE_FACTOR:
+			factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+			if (!factor)
+				return NULL;
+			factor->reg = ctx->reg_base + arate->factor.offset;
+			factor->shift = arate->factor.shift;
+			factor->width = arate->factor.width;
+			factor->flags = arate->factor.div_flags;
+			factor->table = arate->factor.table;
+			factor->lock = &ctx->lock;
+
+			rate_ops = &owl_factor_ops;
+			rate_hw = &factor->hw;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if (agate->id) {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate)
+			return ERR_PTR(-ENOMEM);
+
+		/* set up gate properties */
+		gate->reg = ctx->reg_base + agate->offset;
+		gate->bit_idx = agate->bit_idx;
+		gate->lock = &ctx->lock;
+		gate_hw = &gate->hw;
+	}
+
+	clk_hw = clk_hw_register_composite(NULL, clk_name,
+			parent_names, num_parents,
+			mux_hw, &clk_mux_ops,
+			rate_hw, rate_ops,
+			gate_hw, &clk_gate_ops, cclk->flags);
+
+	return clk_hw;
+}
+
+/* register a list of composite clocks */
+void owl_clk_register_composite(struct owl_clk_provider *ctx,
+		struct owl_composite_clock *clks, int nums)
+{
+	struct clk_hw *clk_hw;
+	int i;
+
+	for (i = 0; i < nums; i++) {
+		clk_hw = _register_composite(ctx, &clks[i]);
+		if (IS_ERR(clk_hw)) {
+			pr_err("%s: failed to register clock %s\n",
+				__func__, clks[i].name);
+			continue;
+		}
+
+		owl_clk_add_hw_data(ctx, clk_hw, clks[i].id);
+	}
+}
diff --git a/drivers/clk/actions/owl-clk.h b/drivers/clk/actions/owl-clk.h
new file mode 100644
index 0000000..8e61f17b
--- /dev/null
+++ b/drivers/clk/actions/owl-clk.h
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * based on
+ *
+ * samsung/clk.h
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2013 Linaro Ltd.
+ * Author: Thomas Abraham <thomas.ab@owl.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __OWL_CLK_H
+#define __OWL_CLK_H
+
+#include <linux/clk-provider.h>
+
+struct owl_clk_provider {
+	void __iomem		*reg_base;
+	struct clk_hw_onecell_data clk_data;
+	spinlock_t		lock;
+};
+
+struct owl_fixed_factor_clock {
+	unsigned int		id;
+	char			*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned int		mult;
+	unsigned int		div;
+};
+
+/* last entry should have rate = 0 */
+struct clk_pll_table {
+	unsigned int		val;
+	unsigned long		rate;
+};
+
+struct owl_pll_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	unsigned long		bfreq;
+	u8			enable_bit;
+	u8			shift;
+	u8			width;
+	u8			min_mul;
+	u8			max_mul;
+	u8			pll_flags;
+	const struct clk_pll_table *table;
+};
+
+#define CLK_OWL_PLL_FIXED_FREQ	BIT(0)
+
+struct owl_divider_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_div_table	*table;
+	const char		*alias;
+};
+
+struct clk_factor_table {
+	unsigned int		val;
+	unsigned int		mul;
+	unsigned int		div;
+};
+
+struct owl_factor_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			div_flags;
+	struct clk_factor_table	*table;
+	const char		*alias;
+};
+
+struct owl_factor {
+	struct clk_hw		hw;
+	void __iomem		*reg;
+	u8			shift;
+	u8			width;
+	u8			flags;
+	const struct clk_factor_table *table;
+	spinlock_t		*lock;
+};
+
+extern const struct clk_ops owl_factor_ops;
+
+struct owl_mux_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		**parent_names;
+	u8			num_parents;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			shift;
+	u8			width;
+	u8			mux_flags;
+	const char		*alias;
+};
+
+struct owl_gate_clock {
+	unsigned int		id;
+	const char		*name;
+	const char		*parent_name;
+	unsigned long		flags;
+	unsigned long		offset;
+	u8			bit_idx;
+	u8			gate_flags;
+	const char		*alias;
+};
+
+union rate_clock {
+	struct owl_fixed_factor_clock	fixed_factor;
+	struct owl_divider_clock	div;
+	struct owl_factor_clock		factor;
+};
+
+struct owl_composite_clock {
+	unsigned int		id;
+	const char		*name;
+	unsigned int		type;
+	unsigned long		flags;
+
+	struct owl_mux_clock	mux;
+	struct owl_gate_clock	gate;
+	union rate_clock	rate;
+};
+
+#define OWL_COMPOSITE_TYPE_DIVIDER         1
+#define OWL_COMPOSITE_TYPE_FACTOR          2
+#define OWL_COMPOSITE_TYPE_FIXED_FACTOR    3
+#define OWL_COMPOSITE_TYPE_PASS            10
+
+#define COMP_FIXED_FACTOR_CLK(_id, _name, _flags, _mux, _gate, _fixed_factor) \
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_FIXED_FACTOR,	\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.fixed_factor = _fixed_factor,			\
+	}
+
+#define COMP_DIV_CLK(_id, _name, _flags, _mux, _gate, _div)		\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_DIVIDER,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.div	= _div,					\
+	}
+
+#define COMP_FACTOR_CLK(_id, _name, _flags, _mux, _gate, _factor)	\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_FACTOR,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+		.rate.factor	= _factor,				\
+	}
+
+#define COMP_PASS_CLK(_id, _name, _flags, _mux, _gate)			\
+	{								\
+		.id		= _id,					\
+		.name		= _name,				\
+		.type		= OWL_COMPOSITE_TYPE_PASS,		\
+		.flags		= _flags,				\
+		.mux		= _mux,					\
+		.gate		= _gate,				\
+	}
+
+#define C_MUX(p, o, s, w, mf)						\
+	{								\
+		.id		= -1,					\
+		.parent_names	= p,					\
+		.num_parents	= ARRAY_SIZE(p),			\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.mux_flags	= mf,					\
+	}
+
+/* fixed mux, only one parent */
+#define C_MUX_F(p, mf)							\
+	{								\
+		.id		= -1,					\
+		.parent_names	= p,					\
+		.num_parents	= 1,					\
+		.mux_flags = mf,					\
+	}
+
+#define C_GATE(o, b, gf)						\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.bit_idx	= b,					\
+		.gate_flags	= gf,					\
+	}
+
+#define C_NULL								\
+	{								\
+		.id		= 0,					\
+	}
+
+#define C_FIXED_FACTOR(m, d)						\
+	{								\
+		.id		= -1,					\
+		.mult		= m,					\
+		.div		= d,					\
+	}
+
+#define C_DIVIDER(o, s, w, t, df)					\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.table		= t,					\
+		.div_flags	= df,					\
+	}
+
+#define C_FACTOR(o, s, w, t, df)					\
+	{								\
+		.id		= -1,					\
+		.offset		= o,					\
+		.shift		= s,					\
+		.width		= w,					\
+		.table		= t,					\
+		.div_flags	= df,					\
+	}
+
+extern void owl_clk_register_pll(struct owl_clk_provider *ctx,
+		struct owl_pll_clock *clks, int nums);
+
+extern void owl_clk_register_fixed_factor(
+		struct owl_clk_provider *ctx,
+		struct owl_fixed_factor_clock *clks,
+		int nums);
+
+extern void owl_clk_register_divider(struct owl_clk_provider *ctx,
+		struct owl_divider_clock *clks, int nums);
+
+extern void owl_clk_register_factor(struct owl_clk_provider *ctx,
+		struct owl_factor_clock *clks, int nums);
+
+extern void owl_clk_register_mux(struct owl_clk_provider *ctx,
+		struct owl_mux_clock *clks, int nums);
+
+extern void owl_clk_register_gate(struct owl_clk_provider *ctx,
+		struct owl_gate_clock *clks, int nums);
+
+extern void owl_clk_register_composite(struct owl_clk_provider *ctx,
+		struct owl_composite_clock *clks, int nums);
+
+extern struct clk_hw *owl_pll_clk_register(const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, unsigned long bfreq, u8 enable_bit,
+		u8 shift, u8 width, u8 min_mul, u8 max_mul, u8 pll_flags,
+		const struct clk_pll_table *table, spinlock_t *lock);
+
+extern struct clk_hw *owl_factor_clk_register(struct device *dev,
+		const char *name, const char *parent_name,
+		unsigned long flags, void __iomem *reg, u8 shift,
+		u8 width, u8 clk_factor_flags,
+		const struct clk_factor_table *table, spinlock_t *lock);
+
+#endif /* __OWL_CLK_H */
diff --git a/drivers/clk/actions/owl-factor.c b/drivers/clk/actions/owl-factor.c
new file mode 100644
index 0000000..18471ec
--- /dev/null
+++ b/drivers/clk/actions/owl-factor.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include "owl-clk.h"
+
+#define to_owl_factor(_hw)	container_of(_hw, struct owl_factor, hw)
+#define div_mask(d)		((1 << ((d)->width)) - 1)
+
+static unsigned int _get_table_maxval(const struct clk_factor_table *table)
+{
+	unsigned int maxval = 0;
+	const struct clk_factor_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++)
+		if (clkt->val > maxval)
+			maxval = clkt->val;
+	return maxval;
+}
+
+static int _get_table_div_mul(const struct clk_factor_table *table,
+			unsigned int val, unsigned int *mul, unsigned int *div)
+{
+	const struct clk_factor_table *clkt;
+
+	for (clkt = table; clkt->div; clkt++) {
+		if (clkt->val == val) {
+			*mul = clkt->mul;
+			*div = clkt->div;
+			return 1;
+		}
+	}
+	return 0;
+}
+
+static unsigned int _get_table_val(const struct clk_factor_table *table,
+			unsigned long rate, unsigned long parent_rate)
+{
+	const struct clk_factor_table *clkt;
+	int val = -1;
+	u64 calc_rate;
+
+	for (clkt = table; clkt->div; clkt++) {
+		calc_rate = parent_rate * clkt->mul;
+		do_div(calc_rate, clkt->div);
+
+		if ((unsigned long)calc_rate <= rate) {
+			val = clkt->val;
+			break;
+		}
+	}
+
+	if (val == -1)
+		val = _get_table_maxval(table);
+
+	return val;
+}
+
+static int clk_val_best(struct clk_hw *hw, unsigned long rate,
+			unsigned long *best_parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	unsigned long parent_rate, try_parent_rate, best = 0, cur_rate;
+	unsigned long parent_rate_saved = *best_parent_rate;
+	int bestval = 0;
+
+	if (!rate)
+		rate = 1;
+
+	if (!(clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT)) {
+		parent_rate = *best_parent_rate;
+		bestval = _get_table_val(clkt, rate, parent_rate);
+		return bestval;
+	}
+
+	for (clkt = factor->table; clkt->div; clkt++) {
+		try_parent_rate = rate * clkt->div / clkt->mul;
+
+		if (try_parent_rate == parent_rate_saved) {
+			pr_debug("%s: [%d %d %d] found try_parent_rate %ld\n",
+				__func__, clkt->val, clkt->mul, clkt->div,
+				try_parent_rate);
+			/*
+			 * It's the most ideal case if the requested rate can be
+			 * divided from parent clock without any need to change
+			 * parent rate, so return the divider immediately.
+			 */
+			*best_parent_rate = parent_rate_saved;
+			return clkt->val;
+		}
+
+		parent_rate = clk_hw_round_rate(clk_hw_get_parent(hw),
+				try_parent_rate);
+		cur_rate = DIV_ROUND_UP(parent_rate, clkt->div) * clkt->mul;
+		if (cur_rate <= rate && cur_rate > best) {
+			bestval = clkt->val;
+			best = cur_rate;
+			*best_parent_rate = parent_rate;
+		}
+	}
+
+	if (!bestval) {
+		bestval = _get_table_maxval(clkt);
+		*best_parent_rate = clk_hw_round_rate(
+				clk_hw_get_parent(hw), 1);
+	}
+
+	pr_debug("%s: return bestval %d\n", __func__, bestval);
+
+	return bestval;
+}
+
+/**
+ * owl_factor_round_rate() - round a clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @prate: clock frequency of parent clock
+ */
+static long owl_factor_round_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long *parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	unsigned int val, mul = 0, div = 1;
+
+	val = clk_val_best(hw, rate, parent_rate);
+	_get_table_div_mul(clkt, val, &mul, &div);
+
+	return *parent_rate * mul / div;
+}
+
+/**
+ * owl_factor_recalc_rate() - recalculate clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static unsigned long owl_factor_recalc_rate(struct clk_hw *hw,
+			unsigned long parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	const struct clk_factor_table *clkt = factor->table;
+	u64 rate;
+	u32 val, mul, div;
+
+	div = 0;
+	mul = 0;
+
+	val = readl(factor->reg) >> factor->shift;
+	val &= div_mask(factor);
+
+	_get_table_div_mul(clkt, val, &mul, &div);
+	if (!div) {
+		WARN(!(factor->flags & CLK_DIVIDER_ALLOW_ZERO),
+			"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+			__clk_get_name(hw->clk));
+		return parent_rate;
+	}
+
+	rate = (u64)parent_rate * mul;
+	do_div(rate, div);
+
+	return rate;
+}
+
+/**
+ * owl_factor_set_rate() - set clock frequency
+ * @hw: handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static int owl_factor_set_rate(struct clk_hw *hw, unsigned long rate,
+			unsigned long parent_rate)
+{
+	struct owl_factor *factor = to_owl_factor(hw);
+	unsigned long flags = 0;
+	u32 val, v;
+
+	val = _get_table_val(factor->table, rate, parent_rate);
+
+	pr_debug("%s: get_table_val %d\n", __func__, val);
+
+	if (val > div_mask(factor))
+		val = div_mask(factor);
+
+	if (factor->lock)
+		spin_lock_irqsave(factor->lock, flags);
+
+	v = readl(factor->reg);
+	v &= ~(div_mask(factor) << factor->shift);
+	v |= val << factor->shift;
+	writel(v, factor->reg);
+
+	if (factor->lock)
+		spin_unlock_irqrestore(factor->lock, flags);
+
+	return 0;
+}
+
+const struct clk_ops owl_factor_ops = {
+	.round_rate	= owl_factor_round_rate,
+	.recalc_rate	= owl_factor_recalc_rate,
+	.set_rate	= owl_factor_set_rate,
+};
+
+/**
+ * owl_factor_clk_register() - register pll with the clock framework
+ * @name: pll name
+ * @parent: parent clock name
+ * @reg: pointer to pll control register
+ * @pll_status: pointer to pll status register
+ * @lock_index: bit index to this pll's lock status bit in pll_status
+ * @lock: register lock
+ */
+struct clk_hw *owl_factor_clk_register(struct device *dev, const char *name,
+		const char *parent_name, unsigned long flags,
+		void __iomem *reg, u8 shift, u8 width,
+		u8 clk_factor_flags, const struct clk_factor_table *table,
+		spinlock_t *lock)
+
+{
+	struct owl_factor *factor;
+	struct clk_init_data initd;
+	struct clk_hw *clk_hw;
+	int ret;
+
+	factor = kzalloc(sizeof(*factor), GFP_KERNEL);
+	if (!factor)
+		return ERR_PTR(-ENOMEM);
+
+	initd.name = name;
+	initd.ops = &owl_factor_ops;
+	initd.flags = flags;
+	initd.parent_names = (parent_name ? &parent_name : NULL);
+	initd.num_parents = (parent_name ? 1 : 0);
+
+	factor->reg = reg;
+	factor->shift = shift;
+	factor->width = width;
+	factor->flags = clk_factor_flags;
+	factor->lock = lock;
+	factor->hw.init = &initd;
+	factor->table = table;
+
+	clk_hw = &factor->hw;
+	ret = clk_hw_register(dev, clk_hw);
+	if (ret) {
+		kfree(factor);
+		clk_hw = ERR_PTR(ret);
+	}
+
+	return clk_hw;
+}
diff --git a/drivers/clk/actions/owl-pll.c b/drivers/clk/actions/owl-pll.c
new file mode 100644
index 0000000..942b528
--- /dev/null
+++ b/drivers/clk/actions/owl-pll.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include "owl-clk.h"
+
+/**
+ * struct owl_pll
+ * @hw: handle between common and hardware-specific interfaces
+ * @reg: pll control register
+ * @lock: register lock
+ * @bfreq: base frequency of the pll. pll frequency = bfreq * mul
+ * @enable_bit: enable bit for pll
+ * @shift: shift to the multiplier bit field
+ * @width: width of the multiplier bit field
+ * @min_mul: minimum multiple for the pll
+ * @max_mul: maximum multiple for the pll
+ * @pll_flags: flags for the pll
+ * @table: pll table
+ */
+struct owl_pll {
+	struct clk_hw		hw;
+	void __iomem		*reg;
+	spinlock_t		*lock;
+	unsigned long		bfreq;
+	u8			enable_bit;
+	u8			shift;
+	u8			width;
+	u8			min_mul;
+	u8			max_mul;
+	u8			pll_flags;
+	const struct clk_pll_table *table;
+};
+
+#define to_owl_pll(_hw)		container_of(_hw, struct owl_pll, hw)
+#define mul_mask(m)		((1 << ((m)->width)) - 1)
+#define PLL_STABILITY_WAIT_US	(50)
+
+/**
+ * owl_pll_calculate_mul() - calculate multiple for specific rate
+ * @pll: owl pll
+ * @rate: desired clock frequency
+ */
+static u32 owl_pll_calculate_mul(struct owl_pll *pll, unsigned long rate)
+{
+	u32 mul;
+
+	mul = DIV_ROUND_CLOSEST(rate, pll->bfreq);
+	if (mul < pll->min_mul)
+		mul = pll->min_mul;
+	else if (mul > pll->max_mul)
+		mul = pll->max_mul;
+
+	return mul &= mul_mask(pll);
+}
+
+static unsigned int _get_table_rate(const struct clk_pll_table *table,
+		unsigned int val)
+{
+	const struct clk_pll_table *clkt;
+
+	for (clkt = table; clkt->rate; clkt++)
+		if (clkt->val == val)
+			return clkt->rate;
+
+	return 0;
+}
+
+static const struct clk_pll_table *_get_pll_table(
+		const struct clk_pll_table *table, unsigned long rate)
+{
+	const struct clk_pll_table *clkt;
+
+	for (clkt = table; clkt->rate; clkt++) {
+		if (clkt->rate == rate) {
+			table = clkt;
+			break;
+		} else if (clkt->rate < rate)
+			table = clkt;
+	}
+
+	return table;
+}
+
+/**
+ * owl_pll_round_rate() - round a clock frequency
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @parent_rate: clock frequency of parent clock
+ */
+static long owl_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long *parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	const struct clk_pll_table *clkt;
+	u32 mul;
+
+	if (pll->table) {
+		clkt = _get_pll_table(pll->table, rate);
+		return clkt->rate;
+	}
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return pll->bfreq;
+
+	mul = owl_pll_calculate_mul(pll, rate);
+
+	return pll->bfreq * mul;
+}
+
+/**
+ * owl_pll_recalc_rate() - recalculate pll clock frequency
+ * @hw:	handle between common and hardware-specific interfaces
+ * @parent_rate: clock frequency of parent clock
+ */
+static unsigned long owl_pll_recalc_rate(struct clk_hw *hw,
+		unsigned long parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long rate;
+	u32 val, mul;
+
+	if (pll->table) {
+		val = readl(pll->reg) >> pll->shift;
+		val &= mul_mask(pll);
+
+		rate = _get_table_rate(pll->table, val);
+
+		return rate;
+	}
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return pll->bfreq;
+
+	mul = (readl(pll->reg) >> pll->shift) & mul_mask(pll);
+
+	return pll->bfreq * mul;
+}
+
+/**
+ * owl_pll_is_enabled - check if pll is enabled
+ * @hw: handle between common and hardware-specific interfaces
+ *
+ * Not sure this is a good idea, but since disabled means bypassed for
+ * this clock implementation we say we are always enabled.
+ */
+static int owl_pll_is_enabled(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	return !!(v & BIT(pll->enable_bit));
+}
+
+/**
+ * owl_pll_enable - enable pll clock
+ * @hw:	handle between common and hardware-specific interfaces
+ */
+static int owl_pll_enable(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	/* exit if pll is enabled */
+	if (owl_pll_is_enabled(hw))
+		return 0;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v |= BIT(pll->enable_bit);
+	writel(v, pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	udelay(PLL_STABILITY_WAIT_US);
+
+	return 0;
+}
+
+/**
+ * owl_pll_disable - disable pll clock
+ * @hw:	handle between common and hardware-specific interfaces
+ */
+static void owl_pll_disable(struct clk_hw *hw)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	unsigned long flags = 0;
+	u32 v;
+
+	/* exit if pll is disabled */
+	if (!owl_pll_is_enabled(hw))
+		return;
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v &= ~BIT(pll->enable_bit);
+	writel(v, pll->reg);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+}
+
+/**
+ * owl_pll_set_rate - set pll rate
+ * @hw: handle between common and hardware-specific interfaces
+ * @rate: desired clock frequency
+ * @parent_rate: clock frequency of parent
+ */
+static int owl_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+		unsigned long parent_rate)
+{
+	struct owl_pll *pll = to_owl_pll(hw);
+	const struct clk_pll_table *clkt;
+	unsigned long flags = 0;
+	u32 val, v;
+
+	pr_debug("%s: rate %ld, parent_rate %ld, before set rate: reg 0x%x\n",
+		__func__, rate, parent_rate, readl(pll->reg));
+
+	/* fixed frequency */
+	if (pll->width == 0)
+		return 0;
+
+	if (pll->table) {
+		clkt = _get_pll_table(pll->table, rate);
+		val = clkt->val;
+	} else {
+		val = owl_pll_calculate_mul(pll, rate);
+	}
+
+	if (pll->lock)
+		spin_lock_irqsave(pll->lock, flags);
+
+	v = readl(pll->reg);
+	v &= ~mul_mask(pll);
+	v |= val << pll->shift;
+	writel(v, pll->reg);
+
+	udelay(PLL_STABILITY_WAIT_US);
+
+	if (pll->lock)
+		spin_unlock_irqrestore(pll->lock, flags);
+
+	pr_debug("%s: after set rate: reg 0x%x\n", __func__,
+		readl(pll->reg));
+
+	return 0;
+}
+
+static const struct clk_ops owl_pll_ops = {
+	.enable = owl_pll_enable,
+	.disable = owl_pll_disable,
+	.is_enabled = owl_pll_is_enabled,
+	.round_rate = owl_pll_round_rate,
+	.recalc_rate = owl_pll_recalc_rate,
+	.set_rate = owl_pll_set_rate,
+};
+
+/**
+ * owl_pll_clk_register() - register pll with the clock framework
+ * @name: pll name
+ * @parent: parent clock name
+ * @reg: pointer to pll control register
+ * @pll_status: pointer to pll status register
+ * @lock_index: bit index to this pll's lock status bit in @pll_status
+ * @lock: register lock
+ */
+struct clk_hw *owl_pll_clk_register(const char *name, const char *parent_name,
+		unsigned long flags, void __iomem *reg, unsigned long bfreq,
+		u8 enable_bit, u8 shift, u8 width, u8 min_mul, u8 max_mul,
+		u8 pll_flags, const struct clk_pll_table *table,
+		spinlock_t *lock)
+{
+	struct owl_pll *pll;
+	struct clk_hw *clk_hw;
+	struct clk_init_data initd;
+	int ret;
+
+	pll = kmalloc(sizeof(*pll), GFP_KERNEL);
+	if (!pll)
+		return ERR_PTR(-ENOMEM);
+
+	initd.name = name;
+	initd.parent_names = (parent_name ? &parent_name : NULL);
+	initd.num_parents = (parent_name ? 1 : 0);
+	initd.ops = &owl_pll_ops;
+	initd.flags = flags;
+
+	pll->hw.init = &initd;
+	pll->bfreq = bfreq;
+	pll->enable_bit = enable_bit;
+	pll->shift = shift;
+	pll->width = width;
+	pll->min_mul = min_mul;
+	pll->max_mul = max_mul;
+	pll->pll_flags = pll_flags;
+	pll->table = table;
+	pll->reg = reg;
+	pll->lock = lock;
+
+	clk_hw = &pll->hw;
+	ret = clk_hw_register(NULL, clk_hw);
+	if (ret) {
+		kfree(pll);
+		clk_hw = ERR_PTR(ret);
+	}
+
+	return clk_hw;
+}
diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
new file mode 100644
index 0000000..51e297f
--- /dev/null
+++ b/drivers/clk/actions/owl-s900.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014 Actions Semi Inc.
+ * Author: David Liu <liuwei@actions-semi.com>
+ *
+ * Copyright (c) 2017 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/actions,s900-cmu.h>
+#include "owl-clk.h"
+
+#define CMU_COREPLL		(0x0000)
+#define CMU_DEVPLL		(0x0004)
+#define CMU_DDRPLL		(0x0008)
+#define CMU_NANDPLL		(0x000C)
+#define CMU_DISPLAYPLL		(0x0010)
+#define CMU_AUDIOPLL		(0x0014)
+#define CMU_TVOUTPLL		(0x0018)
+#define CMU_BUSCLK		(0x001C)
+#define CMU_SENSORCLK		(0x0020)
+#define CMU_LCDCLK		(0x0024)
+#define CMU_DSICLK		(0x0028)
+#define CMU_CSICLK		(0x002C)
+#define CMU_DECLK		(0x0030)
+#define CMU_BISPCLK		(0x0034)
+#define CMU_IMXCLK		(0x0038)
+#define CMU_HDECLK		(0x003C)
+#define CMU_VDECLK		(0x0040)
+#define CMU_VCECLK		(0x0044)
+#define CMU_NANDCCLK		(0x004C)
+#define CMU_SD0CLK		(0x0050)
+#define CMU_SD1CLK		(0x0054)
+#define CMU_SD2CLK		(0x0058)
+#define CMU_UART0CLK		(0x005C)
+#define CMU_UART1CLK		(0x0060)
+#define CMU_UART2CLK		(0x0064)
+#define CMU_PWM0CLK		(0x0070)
+#define CMU_PWM1CLK		(0x0074)
+#define CMU_PWM2CLK		(0x0078)
+#define CMU_PWM3CLK		(0x007C)
+#define CMU_USBPLL		(0x0080)
+#define CMU_ASSISTPLL		(0x0084)
+#define CMU_EDPCLK		(0x0088)
+#define CMU_GPU3DCLK		(0x0090)
+#define CMU_CORECTL		(0x009C)
+#define CMU_DEVCLKEN0		(0x00A0)
+#define CMU_DEVCLKEN1		(0x00A4)
+#define CMU_DEVRST0		(0x00A8)
+#define CMU_DEVRST1		(0x00AC)
+#define CMU_UART3CLK		(0x00B0)
+#define CMU_UART4CLK		(0x00B4)
+#define CMU_UART5CLK		(0x00B8)
+#define CMU_UART6CLK		(0x00BC)
+#define CMU_TLSCLK		(0x00C0)
+#define CMU_SD3CLK		(0x00C4)
+#define CMU_PWM4CLK		(0x00C8)
+#define CMU_PWM5CLK		(0x00CC)
+
+static struct clk_pll_table clk_audio_pll_table[] = {
+	{0, 45158400}, {1, 49152000},
+	{0, 0},
+};
+
+static struct clk_pll_table clk_edp_pll_table[] = {
+	{0, 810000000}, {1, 1350000000}, {2, 2700000000},
+	{0, 0},
+};
+
+/* pll clocks */
+static struct owl_pll_clock s900_pll_clks[] = {
+	{ CLK_CORE_PLL, "core_pll", NULL, CLK_IGNORE_UNUSED, CMU_COREPLL, 24000000, 9, 0, 8,  5, 107, 0, NULL, },
+	{ CLK_DEV_PLL, "dev_pll",  NULL, CLK_IGNORE_UNUSED, CMU_DEVPLL, 6000000, 8, 0, 8, 20, 180, 0, NULL, },
+	{ CLK_DDR_PLL, "ddr_pll",  NULL, CLK_IGNORE_UNUSED, CMU_DDRPLL, 24000000, 8, 0, 8,  5,  45, 0, NULL, },
+	{ CLK_NAND_PLL, "nand_pll", NULL, CLK_IGNORE_UNUSED, CMU_NANDPLL, 6000000, 8, 0, 8,  4, 100, 0, NULL, },
+	{ CLK_DISPLAY_PLL, "display_pll", NULL, CLK_IGNORE_UNUSED, 0, 6000000, 8, 0, 8, 20, 180, 0, NULL, },
+	{ CLK_ASSIST_PLL, "assist_pll", NULL, CLK_IGNORE_UNUSED, 0, 500000000, 0, 0, 0, 0, 0, CLK_OWL_PLL_FIXED_FREQ, NULL, },
+	{ CLK_AUDIO_PLL, "audio_pll", NULL, CLK_IGNORE_UNUSED, 0, 0, 4, 0, 1, 0, 0, 0, clk_audio_pll_table, },
+
+	{ CLK_EDP_PLL, "edp_pll", "24M_edp", CLK_IGNORE_UNUSED, 0, 0, 9, 0, 2, 0, 0, 0, clk_edp_pll_table, },
+};
+
+static const char *cpu_clk_mux_p[] = { "losc", "hosc", "core_pll", };
+static const char *dev_clk_p[] = { "hosc", "dev_pll", };
+static const char *noc_clk_mux_p[] = { "dev_clk", "assist_pll", };
+static const char *dmm_clk_mux_p[] = { "dev_clk", "nand_pll", "assist_pll", "ddr_clk_src", };
+
+static const char *bisp_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *csi_clk_mux_p[] = { "display_pll", "dev_clk", };
+static const char *de_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *eth_mac_clk_mux_p[] = { "assist_pll", };
+static const char *gpu_clk_mux_p[] = { "dev_clk", "display_pll", "", "ddr_clk_src", };
+static const char *hde_clk_mux_p[] = { "dev_clk", "display_pll", "", "ddr_clk_src", };
+static const char *i2c_clk_mux_p[] = { "assist_pll", };
+static const char *imx_clk_mux_p[] = { "assist_pll", "dev_clk", };
+static const char *lcd_clk_mux_p[] = { "display_pll", "nand_pll", };
+static const char *nand_clk_mux_p[] = { "dev_clk", "nand_pll", };
+static const char *pwm_clk_mux_p[] = { "hosc" };
+static const char *sd_clk_mux_p[] = { "dev_clk", "nand_pll", };
+static const char *sensor_clk_mux_p[] = { "hosc", "bisp", };
+static const char *speed_sensor_clk_mux_p[] = { "hosc", };
+static const char *spi_clk_mux_p[] = { "ahb_clk", };
+static const char *thermal_sensor_clk_mux_p[] = { "hosc", };
+static const char *uart_clk_mux_p[] = { "hosc", "dev_pll", };
+static const char *vce_clk_mux_p[] = { "dev_clk", "display_pll", "assist_pll", "ddr_clk_src", };
+static const char *i2s_clk_mux_p[] = { "audio_pll", };
+
+static const char *edp_clk_mux_p[] = { "assist_pll", "display_pll", };
+
+/* mux clocks */
+static struct owl_mux_clock s900_mux_clks[] = {
+	{ CLK_CPU,  "cpu_clk", cpu_clk_mux_p, ARRAY_SIZE(cpu_clk_mux_p), CLK_SET_RATE_PARENT, CMU_BUSCLK, 0, 2, 0, "cpu_clk", },
+	{ CLK_DEV,  "dev_clk", dev_clk_p, ARRAY_SIZE(dev_clk_p), CLK_SET_RATE_PARENT, CMU_DEVPLL, 12, 1, 0, "dev_clk", },
+	{ CLK_NOC_CLK_MUX,  "noc_clk_mux", noc_clk_mux_p, ARRAY_SIZE(noc_clk_mux_p), CLK_SET_RATE_PARENT, CMU_BUSCLK, 7, 1, 0, },
+};
+
+static struct clk_div_table nand_div_table[] = {
+	{0, 1},   {1, 2},   {2, 4},   {3, 6},
+	{4, 8},   {5, 10},  {6, 12},  {7, 14},
+	{8, 16},  {9, 18},  {10, 20}, {11, 22},
+	{12, 24}, {13, 26}, {14, 28}, {15, 30},
+	{0, 0},
+};
+
+static struct clk_factor_table sd_factor_table[] = {
+	/* bit0 ~ 4 */
+	{0, 1, 1}, {1, 1, 2}, {2, 1, 3}, {3, 1, 4},
+	{4, 1, 5}, {5, 1, 6}, {6, 1, 7}, {7, 1, 8},
+	{8, 1, 9}, {9, 1, 10}, {10, 1, 11}, {11, 1, 12},
+	{12, 1, 13}, {13, 1, 14}, {14, 1, 15}, {15, 1, 16},
+	{16, 1, 17}, {17, 1, 18}, {18, 1, 19}, {19, 1, 20},
+	{20, 1, 21}, {21, 1, 22}, {22, 1, 23}, {23, 1, 24},
+	{24, 1, 25}, {25, 1, 26}, {26, 1, 27}, {27, 1, 28},
+	{28, 1, 29}, {29, 1, 30}, {30, 1, 31}, {31, 1, 32},
+
+	/* bit8: /128 */
+	{256, 1, 1 * 128}, {257, 1, 2 * 128}, {258, 1, 3 * 128}, {259, 1, 4 * 128},
+	{260, 1, 5 * 128}, {261, 1, 6 * 128}, {262, 1, 7 * 128}, {263, 1, 8 * 128},
+	{264, 1, 9 * 128}, {265, 1, 10 * 128}, {266, 1, 11 * 128}, {267, 1, 12 * 128},
+	{268, 1, 13 * 128}, {269, 1, 14 * 128}, {270, 1, 15 * 128}, {271, 1, 16 * 128},
+	{272, 1, 17 * 128}, {273, 1, 18 * 128}, {274, 1, 19 * 128}, {275, 1, 20 * 128},
+	{276, 1, 21 * 128}, {277, 1, 22 * 128}, {278, 1, 23 * 128}, {279, 1, 24 * 128},
+	{280, 1, 25 * 128}, {281, 1, 26 * 128}, {282, 1, 27 * 128}, {283, 1, 28 * 128},
+	{284, 1, 29 * 128}, {285, 1, 30 * 128}, {286, 1, 31 * 128}, {287, 1, 32 * 128},
+
+	{0, 0},
+};
+
+static struct clk_div_table apb_div_table[] = {
+	{1, 2},   {2, 3},   {3, 4},
+	{0, 0},
+};
+
+static struct clk_div_table eth_mac_div_table[] = {
+	{0, 2},   {1, 4},
+	{0, 0},
+};
+
+static struct clk_div_table rmii_ref_div_table[] = {
+	{0, 4},   {1, 10},
+	{0, 0},
+};
+
+static struct clk_div_table usb3_mac_div_table[] = {
+	{1, 2},   {2, 3},   {3, 4},
+	{0, 8},
+};
+
+static struct clk_div_table i2s_div_table[] = {
+	{0, 1},   {1, 2},   {2, 3},   {3, 4},
+	{4, 6},   {5, 8},   {6, 12},  {7, 16},
+	{8, 24},
+	{0, 0},
+};
+
+static struct clk_div_table hdmia_div_table[] = {
+	{0, 1},   {1, 2},   {2, 3},   {3, 4},
+	{4, 6},   {5, 8},   {6, 12},  {7, 16},
+	{8, 24},
+	{0, 0},
+};
+
+
+/* divider clocks */
+static struct owl_divider_clock s900_div_clks[] = {
+	{ CLK_NOC_CLK_DIV, "noc_clk_div", "noc_clk", 0, CMU_BUSCLK, 19, 1, 0, NULL, },
+	{ CLK_AHB, "ahb_clk", "noc_clk_div", 0, CMU_BUSCLK, 4, 1, 0, NULL, "ahb_clk", },
+	{ CLK_APB, "apb_clk", "ahb_clk", 0, CMU_BUSCLK, 8, 2, 0, apb_div_table, "apb_clk", },
+	{ CLK_USB3_MAC, "usb3_mac", "assist_pll", 0, CMU_ASSISTPLL, 12, 2, 0, usb3_mac_div_table, "usb3_mac", },
+	{ CLK_RMII_REF, "rmii_ref", "assist_pll", 0, CMU_ASSISTPLL, 8, 1, 0, rmii_ref_div_table, "rmii_ref", },
+};
+
+static struct clk_factor_table dmm_factor_table[] = {
+	{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 1, 3},
+	{4, 1, 4},
+	{0, 0, 0},
+};
+
+static struct clk_factor_table noc_factor_table[] = {
+	{0, 1, 1},   {1, 2, 3},   {2, 1, 2}, {3, 1, 3},  {4, 1, 4},
+	{0, 0, 0},
+};
+
+static struct clk_factor_table bisp_factor_table[] = {
+	{0, 1, 1}, {1, 2, 3}, {2, 1, 2}, {3, 2, 5},
+	{4, 1, 3}, {5, 1, 4}, {6, 1, 6}, {7, 1, 8},
+	{0, 0, 0},
+};
+
+/* divider clocks */
+static struct owl_factor_clock s900_factor_clks[] = {
+	{ CLK_NOC, "noc_clk", "noc_clk_mux", 0, CMU_BUSCLK, 16, 3, 0, noc_factor_table, "noc_clk", },
+	{ CLK_DE1, "de_clk1", "de_clk", 0, CMU_DECLK, 0, 3, 0, bisp_factor_table, "de_clk1", },
+	{ CLK_DE2, "de_clk2", "de_clk", 0, CMU_DECLK, 4, 3, 0, bisp_factor_table, "de_clk2", },
+	{ CLK_DE3, "de_clk3", "de_clk", 0, CMU_DECLK, 8, 3, 0, bisp_factor_table, "de_clk3", },
+};
+
+/* gate clocks */
+static struct owl_gate_clock s900_gate_clks[] = {
+	{ CLK_GPIO,  "gpio", "apb_clk", 0, CMU_DEVCLKEN0, 18, 0, "gpio", },
+	{ CLK_GPU,   "gpu", NULL, 0, CMU_DEVCLKEN0, 30, 0, "gpu", },
+	{ CLK_DMAC,  "dmac", "noc_clk_div", 0, CMU_DEVCLKEN0, 1, 0, "dmac", },
+	{ CLK_TIMER,  "timer", "hosc", 0, CMU_DEVCLKEN1, 27, 0, "timer", },
+	{ CLK_DSI,  "dsi_clk", NULL, 0, CMU_DEVCLKEN0, 12, 0, "dsi", },
+
+	{ CLK_DDR0,  "ddr0_clk", "ddr_pll", CLK_IGNORE_UNUSED, CMU_DEVCLKEN0, 31, 0, "ddr0", },
+	{ CLK_DDR1,  "ddr1_clk", "ddr_pll", CLK_IGNORE_UNUSED, CMU_DEVCLKEN0, 29, 0, "ddr1", },
+
+	{ CLK_USB3_480MPLL0,	"usb3_480mpll0",	NULL, 0, CMU_USBPLL, 3, 0, "usb3_480mpll0", },
+	{ CLK_USB3_480MPHY0,	"usb3_480mphy0",	NULL, 0, CMU_USBPLL, 2, 0, "usb3_480mphy0", },
+	{ CLK_USB3_5GPHY,	"usb3_5gphy",		NULL, 0, CMU_USBPLL, 1, 0, "usb3_5gphy", },
+	{ CLK_USB3_CCE,		"usb3_cce",		NULL, 0, CMU_USBPLL, 0, 0, "usb3_cce", },
+
+	{ CLK_24M_EDP,		"24M_edp",		"diff24M", 0, CMU_EDPCLK, 8, 0, "24M_edp", },
+	{ CLK_EDP_LINK,		"edp_link",		"edp_pll", 0, CMU_DEVCLKEN0, 10, 0, "edp_link", },
+
+	{ CLK_USB2H0_PLLEN,	"usbh0_pllen",	NULL, 0, CMU_USBPLL, 12, 0, "usbh0_pllen", },
+	{ CLK_USB2H0_PHY,	"usbh0_phy",	NULL, 0, CMU_USBPLL, 10, 0, "usbh0_phy", },
+	{ CLK_USB2H0_CCE,	"usbh0_cce",		NULL, 0, CMU_USBPLL, 8, 0, "usbh0_cce", },
+
+	{ CLK_USB2H1_PLLEN,	"usbh1_pllen",	NULL, 0, CMU_USBPLL, 13, 0, "usbh1_pllen", },
+	{ CLK_USB2H1_PHY,	"usbh1_phy",	NULL, 0, CMU_USBPLL, 11, 0, "usbh1_phy", },
+	{ CLK_USB2H1_CCE,	"usbh1_cce",		NULL, 0, CMU_USBPLL, 9, 0, "usbh1_cce", },
+};
+
+static struct owl_composite_clock s900_composite_clks[] = {
+	COMP_FACTOR_CLK(CLK_BISP, "bisp", 0,
+			C_MUX(bisp_clk_mux_p, CMU_BISPCLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 14, 0),
+			C_FACTOR(CMU_BISPCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_CSI0, "csi0", 0,
+			C_MUX(csi_clk_mux_p, CMU_CSICLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 13, 0),
+			C_DIVIDER(CMU_CSICLK, 0, 4, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_CSI1, "csi1", 0,
+			C_MUX(csi_clk_mux_p, CMU_CSICLK, 20, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 15, 0),
+			C_DIVIDER(CMU_CSICLK, 16, 4, NULL, 0)),
+
+	COMP_PASS_CLK(CLK_DE, "de_clk", 0,
+			C_MUX(de_clk_mux_p, CMU_DECLK, 12, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 8, 0)),
+
+	COMP_FACTOR_CLK(CLK_DMM, "dmm", CLK_IGNORE_UNUSED,
+			C_MUX(dmm_clk_mux_p, CMU_BUSCLK, 10, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 19, 0),
+			C_FACTOR(CMU_BUSCLK, 12, 3, dmm_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_EDP, "edp_clk", 0,
+			C_MUX(edp_clk_mux_p, CMU_EDPCLK, 19, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 10, 0),
+			C_FACTOR(CMU_EDPCLK, 16, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_ETH_MAC, "eth_mac", 0,
+			C_MUX_F(eth_mac_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 22, 0),
+			C_DIVIDER(CMU_ASSISTPLL, 10, 1, eth_mac_div_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_CORE, "gpu_core", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 4, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 15, 0),
+			C_FACTOR(CMU_GPU3DCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_MEM, "gpu_mem", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 20, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 14, 0),
+			C_FACTOR(CMU_GPU3DCLK, 16, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_GPU_SYS, "gpu_sys", 0,
+			C_MUX(gpu_clk_mux_p, CMU_GPU3DCLK, 28, 2, 0),
+			C_GATE(CMU_GPU3DCLK, 13, 0),
+			C_FACTOR(CMU_GPU3DCLK, 24, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_HDE, "hde", 0,
+			C_MUX(hde_clk_mux_p, CMU_HDECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 27, 0),
+			C_FACTOR(CMU_HDECLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_HDMI_AUDIO, "hdmia", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 22, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 24, 4, hdmia_div_table, 0)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C0, "i2c0", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 14, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C1, "i2c1", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 15, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C2, "i2c2", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 30, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C3, "i2c3", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 31, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C4, "i2c4", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN0, 17, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_FIXED_FACTOR_CLK(CLK_I2C5, "i2c5", 0,
+			C_MUX_F(i2c_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 1, 0),
+			C_FIXED_FACTOR(1, 5)),
+
+	COMP_DIV_CLK(CLK_I2SRX, "i2srx", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 21, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 20, 4, i2s_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_I2STX, "i2stx", 0,
+			C_MUX(i2s_clk_mux_p, CMU_AUDIOPLL, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 20, 0),
+			C_DIVIDER(CMU_AUDIOPLL, 16, 4, i2s_div_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_IMX, "imx", 0,
+			C_MUX(imx_clk_mux_p, CMU_IMXCLK, 4, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 17, 0),
+			C_FACTOR(CMU_IMXCLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_LCD, "lcd", 0,
+			C_MUX(lcd_clk_mux_p, CMU_LCDCLK, 12, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 9, 0),
+			C_DIVIDER(CMU_LCDCLK, 0, 5, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_NAND0, "nand0", CLK_SET_RATE_PARENT,
+			C_MUX(nand_clk_mux_p, CMU_NANDCCLK, 8, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 4, 0),
+			C_DIVIDER(CMU_NANDCCLK, 0, 4, nand_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_NAND1, "nand1", CLK_SET_RATE_PARENT,
+			C_MUX(nand_clk_mux_p, CMU_NANDCCLK, 24, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 11, 0),
+			C_DIVIDER(CMU_NANDCCLK, 16, 4, nand_div_table, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm0", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 23, 0),
+			C_DIVIDER(CMU_PWM0CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm1", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 24, 0),
+			C_DIVIDER(CMU_PWM1CLK, 0, 6, NULL, 0)),
+	/*
+	 * pwm2 may be for backlight, do not gate it
+	 * even it is "unused", because it may be
+	 * enabled at boot stage, and in kernel, driver
+	 * has no effective method to know the real status,
+	 * so, the best way is keeping it as what it was.
+	 */
+	COMP_DIV_CLK(CLK_PWM0, "pwm2", CLK_IGNORE_UNUSED,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 25, 0),
+			C_DIVIDER(CMU_PWM2CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm3", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 26, 0),
+			C_DIVIDER(CMU_PWM3CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM0, "pwm4", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 4, 0),
+			C_DIVIDER(CMU_PWM4CLK, 0, 6, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_PWM5, "pwm5", 0,
+			C_MUX_F(pwm_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 5, 0),
+			C_DIVIDER(CMU_PWM5CLK, 0, 6, NULL, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD0, "sd0", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD0CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 5, 0),
+			C_FACTOR(CMU_SD0CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD1, "sd1", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD1CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 6, 0),
+			C_FACTOR(CMU_SD1CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD2, "sd2", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD2CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 7, 0),
+			C_FACTOR(CMU_SD2CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_SD3, "sd3", 0,
+			C_MUX(sd_clk_mux_p, CMU_SD3CLK, 9, 1, 0),
+			C_GATE(CMU_DEVCLKEN0, 16, 0),
+			C_FACTOR(CMU_SD3CLK, 0, 9, sd_factor_table, 0)),
+
+	COMP_DIV_CLK(CLK_SENSOR, "sensor", 0,
+			C_MUX(sensor_clk_mux_p, CMU_SENSORCLK, 4, 1, 0),
+			C_NULL,
+			C_DIVIDER(CMU_SENSORCLK, 0, 4, NULL, 0)),
+
+	COMP_DIV_CLK(CLK_SPEED_SENSOR, "speed_sensor", 0,
+			C_MUX_F(speed_sensor_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 0, 0),
+			C_DIVIDER(CMU_TLSCLK, 0, 4, NULL, CLK_DIVIDER_POWER_OF_TWO)),
+
+	COMP_PASS_CLK(CLK_SPI0, "spi0", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 10, 0)),
+
+	COMP_PASS_CLK(CLK_SPI1, "spi1", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 11, 0)),
+
+	COMP_PASS_CLK(CLK_SPI2, "spi2", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 12, 0)),
+
+	COMP_PASS_CLK(CLK_SPI3, "spi3", 0,
+			C_MUX_F(spi_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 13, 0)),
+
+	COMP_DIV_CLK(CLK_THERMAL_SENSOR, "thermal_sensor", 0,
+			C_MUX_F(thermal_sensor_clk_mux_p, 0),
+			C_GATE(CMU_DEVCLKEN1, 2, 0),
+			C_DIVIDER(CMU_TLSCLK, 8, 4, NULL, CLK_DIVIDER_POWER_OF_TWO)),
+
+	COMP_DIV_CLK(CLK_UART0, "uart0", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART0CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 6, 0),
+			C_DIVIDER(CMU_UART0CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART1, "uart1", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART1CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 7, 0),
+			C_DIVIDER(CMU_UART1CLK, 1, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART2, "uart2", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART2CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 8, 0),
+			C_DIVIDER(CMU_UART2CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART3, "uart3", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART3CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 19, 0),
+			C_DIVIDER(CMU_UART3CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART4, "uart4", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART4CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 20, 0),
+			C_DIVIDER(CMU_UART4CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART5, "uart5", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART5CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 21, 0),
+			C_DIVIDER(CMU_UART5CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_DIV_CLK(CLK_UART6, "uart6", 0,
+			C_MUX(uart_clk_mux_p, CMU_UART6CLK, 16, 1, 0),
+			C_GATE(CMU_DEVCLKEN1, 18, 0),
+			C_DIVIDER(CMU_UART6CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
+
+	COMP_FACTOR_CLK(CLK_VCE, "vce", 0,
+			C_MUX(vce_clk_mux_p, CMU_VCECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 26, 0),
+			C_FACTOR(CMU_VCECLK, 0, 3, bisp_factor_table, 0)),
+
+	COMP_FACTOR_CLK(CLK_VDE, "vde", 0,
+			C_MUX(hde_clk_mux_p, CMU_VDECLK, 4, 2, 0),
+			C_GATE(CMU_DEVCLKEN0, 25, 0),
+			C_FACTOR(CMU_VDECLK, 0, 3, bisp_factor_table, 0)),
+};
+
+static int s900_clk_probe(struct platform_device *pdev)
+{
+	struct owl_clk_provider *ctx;
+	struct device_node *np = pdev->dev.of_node;
+	struct resource *res;
+	void __iomem *base;
+	int i;
+
+	ctx = kzalloc(sizeof(struct owl_clk_provider) +
+			sizeof(*ctx->clk_data.hws) * CLK_NR_CLKS, GFP_KERNEL);
+	if (!ctx)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	for (i = 0; i < CLK_NR_CLKS; ++i)
+		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
+
+	ctx->reg_base = base;
+	ctx->clk_data.num = CLK_NR_CLKS;
+	spin_lock_init(&ctx->lock);
+
+	/* register pll clocks */
+	owl_clk_register_pll(ctx, s900_pll_clks,
+			ARRAY_SIZE(s900_pll_clks));
+
+	/* register divider clocks */
+	owl_clk_register_divider(ctx, s900_div_clks,
+			ARRAY_SIZE(s900_div_clks));
+
+	/* register factor divider clocks */
+	owl_clk_register_factor(ctx, s900_factor_clks,
+			ARRAY_SIZE(s900_factor_clks));
+
+	/* register mux clocks */
+	owl_clk_register_mux(ctx, s900_mux_clks,
+			ARRAY_SIZE(s900_mux_clks));
+
+	/* register gate clocks */
+	owl_clk_register_gate(ctx, s900_gate_clks,
+			ARRAY_SIZE(s900_gate_clks));
+
+	/* register composite clocks */
+	owl_clk_register_composite(ctx, s900_composite_clks,
+			ARRAY_SIZE(s900_composite_clks));
+
+	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
+				&ctx->clk_data);
+
+}
+
+static const struct of_device_id s900_clk_of_match[] = {
+	{ .compatible = "actions,s900-cmu", },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, s900_clk_of_match);
+
+static struct platform_driver s900_clk_driver = {
+	.probe = s900_clk_probe,
+	.driver = {
+		.name = "s900-cmu",
+		.of_match_table = s900_clk_of_match,
+	},
+};
+
+static int __init s900_clk_init(void)
+{
+	return platform_driver_register(&s900_clk_driver);
+}
+core_initcall(s900_clk_init);
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 1/3] dt-bindings: clock: Add Actions S900 clock bindings
  2017-11-06 19:45   ` Manivannan Sadhasivam
@ 2017-11-06 22:44     ` Rob Herring
  -1 siblings, 0 replies; 14+ messages in thread
From: Rob Herring @ 2017-11-06 22:44 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: mturquette, sboyd, afaerber, mark.rutland, liuwei, mp-cs,
	96boards, devicetree, arnd, davem, mchehab, daniel.thompson,
	amit.kucheria, linux-kernel, linux-clk, linux-arm-kernel,
	viresh.kumar, manivannanece23

On Tue, Nov 07, 2017 at 01:15:50AM +0530, Manivannan Sadhasivam wrote:
> Add Actions Semi S900 clock bindings.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
> Changes in v2:
> 
> 1. Added binding header to this patch
> 2. Changed clock-controller node name to cmu
> 3. Added clocks property to cmu node
> 4. Changed compatible property value to "actions,s900-cmu"
> 5. Fixed example UART controller node
> 6. Fixed tab vs space issue
> 
>  .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 +++++++
>  include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++++++++++++++++++
>  2 files changed, 186 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
>  create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 1/3] dt-bindings: clock: Add Actions S900 clock bindings
@ 2017-11-06 22:44     ` Rob Herring
  0 siblings, 0 replies; 14+ messages in thread
From: Rob Herring @ 2017-11-06 22:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Tue, Nov 07, 2017 at 01:15:50AM +0530, Manivannan Sadhasivam wrote:
> Add Actions Semi S900 clock bindings.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
> Changes in v2:
> 
> 1. Added binding header to this patch
> 2. Changed clock-controller node name to cmu
> 3. Added clocks property to cmu node
> 4. Changed compatible property value to "actions,s900-cmu"
> 5. Fixed example UART controller node
> 6. Fixed tab vs space issue
> 
>  .../devicetree/bindings/clock/actions,s900-cmu.txt |  47 +++++++
>  include/dt-bindings/clock/actions,s900-cmu.h       | 139 +++++++++++++++++++++
>  2 files changed, 186 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/actions,s900-cmu.txt
>  create mode 100644 include/dt-bindings/clock/actions,s900-cmu.h

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC
@ 2017-12-21 23:56     ` Stephen Boyd
  0 siblings, 0 replies; 14+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: mturquette, afaerber, robh+dt, mark.rutland, liuwei, mp-cs,
	96boards, devicetree, arnd, davem, mchehab, daniel.thompson,
	amit.kucheria, linux-kernel, linux-clk, linux-arm-kernel,
	viresh.kumar, manivannanece23

On 11/07, Manivannan Sadhasivam wrote:
> diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
> new file mode 100644
> index 0000000..0de7a03
> --- /dev/null
> +++ b/drivers/clk/actions/Kconfig
> @@ -0,0 +1,6 @@
> +config CLK_OWL_S900
> +	bool "Clock Driver for Actions S900 SoC"

Can it be a module too? Otherwise drop module.h and anything that
does to the driver.

> +	depends on ARCH_ACTIONS || COMPILE_TEST

Can you try compiling this with COMPILE_TEST=y and
ARCH_ACTIONS=n? It may be that drivers/clk/Makefile needs to be
obj-y and then the owl-clk, owl-pll, owl-factor files need to be
compiled only when CONFIG_CLK_OWL_S900 is y. If there becomes
more than one actions driver, then the clk, pll, factor files
will need to be compiled with some new CLK_ACTIONS kconfig symbol
or something.


> +	default ARCH_ACTIONS
> +	help
> +	  Build the clock driver for Actions S900 SoC.
> diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
> new file mode 100644
> index 0000000..83bef30
> --- /dev/null
> +++ b/drivers/clk/actions/Makefile
> @@ -0,0 +1,2 @@
> +obj-y				+= owl-clk.o owl-pll.o owl-factor.o
> +obj-$(CONFIG_CLK_OWL_S900)	+= owl-s900.o
> diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
> new file mode 100644
> index 0000000..51e297f
> --- /dev/null
> +++ b/drivers/clk/actions/owl-s900.c
> @@ -0,0 +1,585 @@
> +/*
> + * Copyright (c) 2014 Actions Semi Inc.
> + * Author: David Liu <liuwei@actions-semi.com>
> + *
> + * Copyright (c) 2017 Linaro Ltd.
> + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> + *
> + * 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.
> + */

Can you move to the SPDX tags please?

> +	COMP_DIV_CLK(CLK_UART3, "uart3", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART3CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 19, 0),
> +			C_DIVIDER(CMU_UART3CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART4, "uart4", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART4CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 20, 0),
> +			C_DIVIDER(CMU_UART4CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART5, "uart5", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART5CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 21, 0),
> +			C_DIVIDER(CMU_UART5CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART6, "uart6", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART6CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 18, 0),
> +			C_DIVIDER(CMU_UART6CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_FACTOR_CLK(CLK_VCE, "vce", 0,
> +			C_MUX(vce_clk_mux_p, CMU_VCECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 26, 0),
> +			C_FACTOR(CMU_VCECLK, 0, 3, bisp_factor_table, 0)),
> +
> +	COMP_FACTOR_CLK(CLK_VDE, "vde", 0,
> +			C_MUX(hde_clk_mux_p, CMU_VDECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 25, 0),
> +			C_FACTOR(CMU_VDECLK, 0, 3, bisp_factor_table, 0)),
> +};
> +
> +static int s900_clk_probe(struct platform_device *pdev)
> +{
> +	struct owl_clk_provider *ctx;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct resource *res;
> +	void __iomem *base;
> +	int i;
> +
> +	ctx = kzalloc(sizeof(struct owl_clk_provider) +
> +			sizeof(*ctx->clk_data.hws) * CLK_NR_CLKS, GFP_KERNEL);

It would be nice to avoid this. If the structs can all be
configured properly, it should be possible to have an array of
clk_hw pointers that are registered directly with
clk_hw_register(), and then index directly into that array to
return clk_hw pointers for the clk_hw provider function.

> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	for (i = 0; i < CLK_NR_CLKS; ++i)
> +		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
> +
> +	ctx->reg_base = base;
> +	ctx->clk_data.num = CLK_NR_CLKS;

Hopefully CLK_NR_CLKS isn't coming from the DT header file.

> +	spin_lock_init(&ctx->lock);
> +
> +	/* register pll clocks */
> +	owl_clk_register_pll(ctx, s900_pll_clks,
> +			ARRAY_SIZE(s900_pll_clks));
> +
> +	/* register divider clocks */
> +	owl_clk_register_divider(ctx, s900_div_clks,
> +			ARRAY_SIZE(s900_div_clks));
> +
> +	/* register factor divider clocks */
> +	owl_clk_register_factor(ctx, s900_factor_clks,
> +			ARRAY_SIZE(s900_factor_clks));
> +
> +	/* register mux clocks */
> +	owl_clk_register_mux(ctx, s900_mux_clks,
> +			ARRAY_SIZE(s900_mux_clks));
> +
> +	/* register gate clocks */
> +	owl_clk_register_gate(ctx, s900_gate_clks,
> +			ARRAY_SIZE(s900_gate_clks));
> +
> +	/* register composite clocks */
> +	owl_clk_register_composite(ctx, s900_composite_clks,
> +			ARRAY_SIZE(s900_composite_clks));
> +
> +	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
> +				&ctx->clk_data);
> +
> +}
> +
> +static const struct of_device_id s900_clk_of_match[] = {
> +	{ .compatible = "actions,s900-cmu", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s900_clk_of_match);

This isn't necessary? It's not a module?

> +
> +static struct platform_driver s900_clk_driver = {
> +	.probe = s900_clk_probe,
> +	.driver = {
> +		.name = "s900-cmu",
> +		.of_match_table = s900_clk_of_match,

You need to supress_bind_attrs here or implement the remove
function for this driver that would unregister all the clks and
provider.

> +	},

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC
@ 2017-12-21 23:56     ` Stephen Boyd
  0 siblings, 0 replies; 14+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:56 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: mturquette-rdvid1DuHRBWk0Htik3J/w, afaerber-l3A5Bk7waGM,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	liuwei-/sSyCTpAT0ql5r2w9Jh5Rg, mp-cs-/sSyCTpAT0ql5r2w9Jh5Rg,
	96boards-Ty1hIZOCd2XuufBYgWm87A,
	devicetree-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
	davem-fT/PcQaiUtIeIZ0/mPfg9Q, mchehab-DgEjT+Ai2ygdnm+yROfE0A,
	daniel.thompson-QSEj5FYQhm4dnm+yROfE0A,
	amit.kucheria-QSEj5FYQhm4dnm+yROfE0A,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	linux-clk-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	viresh.kumar-QSEj5FYQhm4dnm+yROfE0A,
	manivannanece23-Re5JQEeQqe8AvxtiuMwx3w

On 11/07, Manivannan Sadhasivam wrote:
> diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
> new file mode 100644
> index 0000000..0de7a03
> --- /dev/null
> +++ b/drivers/clk/actions/Kconfig
> @@ -0,0 +1,6 @@
> +config CLK_OWL_S900
> +	bool "Clock Driver for Actions S900 SoC"

Can it be a module too? Otherwise drop module.h and anything that
does to the driver.

> +	depends on ARCH_ACTIONS || COMPILE_TEST

Can you try compiling this with COMPILE_TEST=y and
ARCH_ACTIONS=n? It may be that drivers/clk/Makefile needs to be
obj-y and then the owl-clk, owl-pll, owl-factor files need to be
compiled only when CONFIG_CLK_OWL_S900 is y. If there becomes
more than one actions driver, then the clk, pll, factor files
will need to be compiled with some new CLK_ACTIONS kconfig symbol
or something.


> +	default ARCH_ACTIONS
> +	help
> +	  Build the clock driver for Actions S900 SoC.
> diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
> new file mode 100644
> index 0000000..83bef30
> --- /dev/null
> +++ b/drivers/clk/actions/Makefile
> @@ -0,0 +1,2 @@
> +obj-y				+= owl-clk.o owl-pll.o owl-factor.o
> +obj-$(CONFIG_CLK_OWL_S900)	+= owl-s900.o
> diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
> new file mode 100644
> index 0000000..51e297f
> --- /dev/null
> +++ b/drivers/clk/actions/owl-s900.c
> @@ -0,0 +1,585 @@
> +/*
> + * Copyright (c) 2014 Actions Semi Inc.
> + * Author: David Liu <liuwei-/sSyCTpAT0ql5r2w9Jh5Rg@public.gmane.org>
> + *
> + * Copyright (c) 2017 Linaro Ltd.
> + * Author: Manivannan Sadhasivam <manivannan.sadhasivam-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> + *
> + * 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.
> + */

Can you move to the SPDX tags please?

> +	COMP_DIV_CLK(CLK_UART3, "uart3", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART3CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 19, 0),
> +			C_DIVIDER(CMU_UART3CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART4, "uart4", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART4CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 20, 0),
> +			C_DIVIDER(CMU_UART4CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART5, "uart5", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART5CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 21, 0),
> +			C_DIVIDER(CMU_UART5CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART6, "uart6", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART6CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 18, 0),
> +			C_DIVIDER(CMU_UART6CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_FACTOR_CLK(CLK_VCE, "vce", 0,
> +			C_MUX(vce_clk_mux_p, CMU_VCECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 26, 0),
> +			C_FACTOR(CMU_VCECLK, 0, 3, bisp_factor_table, 0)),
> +
> +	COMP_FACTOR_CLK(CLK_VDE, "vde", 0,
> +			C_MUX(hde_clk_mux_p, CMU_VDECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 25, 0),
> +			C_FACTOR(CMU_VDECLK, 0, 3, bisp_factor_table, 0)),
> +};
> +
> +static int s900_clk_probe(struct platform_device *pdev)
> +{
> +	struct owl_clk_provider *ctx;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct resource *res;
> +	void __iomem *base;
> +	int i;
> +
> +	ctx = kzalloc(sizeof(struct owl_clk_provider) +
> +			sizeof(*ctx->clk_data.hws) * CLK_NR_CLKS, GFP_KERNEL);

It would be nice to avoid this. If the structs can all be
configured properly, it should be possible to have an array of
clk_hw pointers that are registered directly with
clk_hw_register(), and then index directly into that array to
return clk_hw pointers for the clk_hw provider function.

> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	for (i = 0; i < CLK_NR_CLKS; ++i)
> +		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
> +
> +	ctx->reg_base = base;
> +	ctx->clk_data.num = CLK_NR_CLKS;

Hopefully CLK_NR_CLKS isn't coming from the DT header file.

> +	spin_lock_init(&ctx->lock);
> +
> +	/* register pll clocks */
> +	owl_clk_register_pll(ctx, s900_pll_clks,
> +			ARRAY_SIZE(s900_pll_clks));
> +
> +	/* register divider clocks */
> +	owl_clk_register_divider(ctx, s900_div_clks,
> +			ARRAY_SIZE(s900_div_clks));
> +
> +	/* register factor divider clocks */
> +	owl_clk_register_factor(ctx, s900_factor_clks,
> +			ARRAY_SIZE(s900_factor_clks));
> +
> +	/* register mux clocks */
> +	owl_clk_register_mux(ctx, s900_mux_clks,
> +			ARRAY_SIZE(s900_mux_clks));
> +
> +	/* register gate clocks */
> +	owl_clk_register_gate(ctx, s900_gate_clks,
> +			ARRAY_SIZE(s900_gate_clks));
> +
> +	/* register composite clocks */
> +	owl_clk_register_composite(ctx, s900_composite_clks,
> +			ARRAY_SIZE(s900_composite_clks));
> +
> +	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
> +				&ctx->clk_data);
> +
> +}
> +
> +static const struct of_device_id s900_clk_of_match[] = {
> +	{ .compatible = "actions,s900-cmu", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s900_clk_of_match);

This isn't necessary? It's not a module?

> +
> +static struct platform_driver s900_clk_driver = {
> +	.probe = s900_clk_probe,
> +	.driver = {
> +		.name = "s900-cmu",
> +		.of_match_table = s900_clk_of_match,

You need to supress_bind_attrs here or implement the remove
function for this driver that would unregister all the clks and
provider.

> +	},

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC
@ 2017-12-21 23:56     ` Stephen Boyd
  0 siblings, 0 replies; 14+ messages in thread
From: Stephen Boyd @ 2017-12-21 23:56 UTC (permalink / raw)
  To: linux-arm-kernel

On 11/07, Manivannan Sadhasivam wrote:
> diff --git a/drivers/clk/actions/Kconfig b/drivers/clk/actions/Kconfig
> new file mode 100644
> index 0000000..0de7a03
> --- /dev/null
> +++ b/drivers/clk/actions/Kconfig
> @@ -0,0 +1,6 @@
> +config CLK_OWL_S900
> +	bool "Clock Driver for Actions S900 SoC"

Can it be a module too? Otherwise drop module.h and anything that
does to the driver.

> +	depends on ARCH_ACTIONS || COMPILE_TEST

Can you try compiling this with COMPILE_TEST=y and
ARCH_ACTIONS=n? It may be that drivers/clk/Makefile needs to be
obj-y and then the owl-clk, owl-pll, owl-factor files need to be
compiled only when CONFIG_CLK_OWL_S900 is y. If there becomes
more than one actions driver, then the clk, pll, factor files
will need to be compiled with some new CLK_ACTIONS kconfig symbol
or something.


> +	default ARCH_ACTIONS
> +	help
> +	  Build the clock driver for Actions S900 SoC.
> diff --git a/drivers/clk/actions/Makefile b/drivers/clk/actions/Makefile
> new file mode 100644
> index 0000000..83bef30
> --- /dev/null
> +++ b/drivers/clk/actions/Makefile
> @@ -0,0 +1,2 @@
> +obj-y				+= owl-clk.o owl-pll.o owl-factor.o
> +obj-$(CONFIG_CLK_OWL_S900)	+= owl-s900.o
> diff --git a/drivers/clk/actions/owl-s900.c b/drivers/clk/actions/owl-s900.c
> new file mode 100644
> index 0000000..51e297f
> --- /dev/null
> +++ b/drivers/clk/actions/owl-s900.c
> @@ -0,0 +1,585 @@
> +/*
> + * Copyright (c) 2014 Actions Semi Inc.
> + * Author: David Liu <liuwei@actions-semi.com>
> + *
> + * Copyright (c) 2017 Linaro Ltd.
> + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> + *
> + * 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.
> + */

Can you move to the SPDX tags please?

> +	COMP_DIV_CLK(CLK_UART3, "uart3", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART3CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 19, 0),
> +			C_DIVIDER(CMU_UART3CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART4, "uart4", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART4CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 20, 0),
> +			C_DIVIDER(CMU_UART4CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART5, "uart5", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART5CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 21, 0),
> +			C_DIVIDER(CMU_UART5CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_DIV_CLK(CLK_UART6, "uart6", 0,
> +			C_MUX(uart_clk_mux_p, CMU_UART6CLK, 16, 1, 0),
> +			C_GATE(CMU_DEVCLKEN1, 18, 0),
> +			C_DIVIDER(CMU_UART6CLK, 0, 8, NULL, CLK_DIVIDER_ROUND_CLOSEST)),
> +
> +	COMP_FACTOR_CLK(CLK_VCE, "vce", 0,
> +			C_MUX(vce_clk_mux_p, CMU_VCECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 26, 0),
> +			C_FACTOR(CMU_VCECLK, 0, 3, bisp_factor_table, 0)),
> +
> +	COMP_FACTOR_CLK(CLK_VDE, "vde", 0,
> +			C_MUX(hde_clk_mux_p, CMU_VDECLK, 4, 2, 0),
> +			C_GATE(CMU_DEVCLKEN0, 25, 0),
> +			C_FACTOR(CMU_VDECLK, 0, 3, bisp_factor_table, 0)),
> +};
> +
> +static int s900_clk_probe(struct platform_device *pdev)
> +{
> +	struct owl_clk_provider *ctx;
> +	struct device_node *np = pdev->dev.of_node;
> +	struct resource *res;
> +	void __iomem *base;
> +	int i;
> +
> +	ctx = kzalloc(sizeof(struct owl_clk_provider) +
> +			sizeof(*ctx->clk_data.hws) * CLK_NR_CLKS, GFP_KERNEL);

It would be nice to avoid this. If the structs can all be
configured properly, it should be possible to have an array of
clk_hw pointers that are registered directly with
clk_hw_register(), and then index directly into that array to
return clk_hw pointers for the clk_hw provider function.

> +	if (!ctx)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	for (i = 0; i < CLK_NR_CLKS; ++i)
> +		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
> +
> +	ctx->reg_base = base;
> +	ctx->clk_data.num = CLK_NR_CLKS;

Hopefully CLK_NR_CLKS isn't coming from the DT header file.

> +	spin_lock_init(&ctx->lock);
> +
> +	/* register pll clocks */
> +	owl_clk_register_pll(ctx, s900_pll_clks,
> +			ARRAY_SIZE(s900_pll_clks));
> +
> +	/* register divider clocks */
> +	owl_clk_register_divider(ctx, s900_div_clks,
> +			ARRAY_SIZE(s900_div_clks));
> +
> +	/* register factor divider clocks */
> +	owl_clk_register_factor(ctx, s900_factor_clks,
> +			ARRAY_SIZE(s900_factor_clks));
> +
> +	/* register mux clocks */
> +	owl_clk_register_mux(ctx, s900_mux_clks,
> +			ARRAY_SIZE(s900_mux_clks));
> +
> +	/* register gate clocks */
> +	owl_clk_register_gate(ctx, s900_gate_clks,
> +			ARRAY_SIZE(s900_gate_clks));
> +
> +	/* register composite clocks */
> +	owl_clk_register_composite(ctx, s900_composite_clks,
> +			ARRAY_SIZE(s900_composite_clks));
> +
> +	return of_clk_add_hw_provider(np, of_clk_hw_onecell_get,
> +				&ctx->clk_data);
> +
> +}
> +
> +static const struct of_device_id s900_clk_of_match[] = {
> +	{ .compatible = "actions,s900-cmu", },
> +	{ /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, s900_clk_of_match);

This isn't necessary? It's not a module?

> +
> +static struct platform_driver s900_clk_driver = {
> +	.probe = s900_clk_probe,
> +	.driver = {
> +		.name = "s900-cmu",
> +		.of_match_table = s900_clk_of_match,

You need to supress_bind_attrs here or implement the remove
function for this driver that would unregister all the clks and
provider.

> +	},

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2017-12-21 23:56 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-06 19:45 [PATCH v2 0/3] Add clock driver for Actions S900 SoC Manivannan Sadhasivam
2017-11-06 19:45 ` Manivannan Sadhasivam
2017-11-06 19:45 ` Manivannan Sadhasivam
2017-11-06 19:45 ` [PATCH v2 1/3] dt-bindings: clock: Add Actions S900 clock bindings Manivannan Sadhasivam
2017-11-06 19:45   ` Manivannan Sadhasivam
2017-11-06 22:44   ` Rob Herring
2017-11-06 22:44     ` Rob Herring
2017-11-06 19:45 ` [PATCH v2 2/3] arm64: dts: actions: Add S900 clock management unit nodes Manivannan Sadhasivam
2017-11-06 19:45   ` Manivannan Sadhasivam
2017-11-06 19:45 ` [PATCH v2 3/3] clk: actions: Add clock driver for Actions S900 SoC Manivannan Sadhasivam
2017-11-06 19:45   ` Manivannan Sadhasivam
2017-12-21 23:56   ` Stephen Boyd
2017-12-21 23:56     ` Stephen Boyd
2017-12-21 23:56     ` Stephen Boyd

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.