Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH 0/5] Add Bitmain BM1880 clock driver
@ 2019-07-05 15:14 Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
                   ` (5 more replies)
  0 siblings, 6 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Hello,

This patchset adds common clock driver for Bitmain BM1880 SoC clock
controller. The clock controller consists of gate, divider, mux
and pll clocks with different compositions. Hence, the driver uses
composite clock structure in place where multiple clocking units are
combined together.

This patchset also removes UART fixed clock and sources clocks from clock
controller for Sophon Edge board where the driver has been validated.

Thanks,
Mani

Manivannan Sadhasivam (5):
  dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  arm64: dts: bitmain: Add clock controller support for BM1880 SoC
  arm64: dts: bitmain: Source common clock for UART controllers
  clk: Add driver for Bitmain BM1880 SoC clock controller
  MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver

 .../bindings/clock/bitmain,bm1880-clk.txt     |  47 +
 MAINTAINERS                                   |   2 +
 .../boot/dts/bitmain/bm1880-sophon-edge.dts   |   9 -
 arch/arm64/boot/dts/bitmain/bm1880.dtsi       |  27 +
 drivers/clk/Kconfig                           |   6 +
 drivers/clk/Makefile                          |   1 +
 drivers/clk/clk-bm1880.c                      | 947 ++++++++++++++++++
 include/dt-bindings/clock/bm1880-clock.h      |  82 ++
 8 files changed, 1112 insertions(+), 9 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
 create mode 100644 drivers/clk/clk-bm1880.c
 create mode 100644 include/dt-bindings/clock/bm1880-clock.h

-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
@ 2019-07-05 15:14 ` Manivannan Sadhasivam
  2019-07-24 16:18   ` Rob Herring
  2019-08-08  5:01   ` Stephen Boyd
  2019-07-05 15:14 ` [PATCH 2/5] arm64: dts: bitmain: Add clock controller support for BM1880 SoC Manivannan Sadhasivam
                   ` (4 subsequent siblings)
  5 siblings, 2 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Add devicetree binding for Bitmain BM1880 SoC clock controller.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 .../bindings/clock/bitmain,bm1880-clk.txt     | 47 +++++++++++
 include/dt-bindings/clock/bm1880-clock.h      | 82 +++++++++++++++++++
 2 files changed, 129 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
 create mode 100644 include/dt-bindings/clock/bm1880-clock.h

diff --git a/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
new file mode 100644
index 000000000000..9c967095d430
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
@@ -0,0 +1,47 @@
+* Bitmain BM1880 Clock Controller
+
+The Bitmain BM1880 clock controler generates and supplies clock to
+various peripherals within the SoC.
+
+Required Properties:
+
+- compatible: Should be "bitmain,bm1880-clk"
+- reg :	Register address and size of PLL and SYS control domains
+- reg-names : Register domain names: "pll" and "sys"
+- clocks : Phandle of the input reference clock.
+- #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 corresponding
+dt-bindings/clock/bm1880-clock.h header and can be used in device tree sources.
+
+External clocks:
+
+The osc clock used as the input for the plls is generated outside the SoC.
+It is expected that it is defined using standard clock bindings as "osc".
+
+Example: 
+
+        clk: clock-controller@800 {
+                compatible = "bitmain,bm1880-clk";
+                reg = <0xe8 0x0c>,<0x800 0xb0>;
+                reg-names = "pll", "sys";
+                clocks = <&osc>;
+                #clock-cells = <1>;
+        };
+
+Example: UART controller node that consumes clock generated by the clock
+controller:
+
+        uart0: serial@58018000 {
+                compatible = "snps,dw-apb-uart";
+                reg = <0x0 0x58018000 0x0 0x2000>;
+                clocks = <&clk BM1880_CLK_UART_500M>;
+                         <&clk BM1880_CLK_APB_UART>;
+                clock-names = "baudclk", "apb_pclk";
+                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+                reg-shift = <2>;
+                reg-io-width = <4>;
+        };
diff --git a/include/dt-bindings/clock/bm1880-clock.h b/include/dt-bindings/clock/bm1880-clock.h
new file mode 100644
index 000000000000..764472b9a4fd
--- /dev/null
+++ b/include/dt-bindings/clock/bm1880-clock.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Device Tree binding constants for Bitmain BM1880 SoC
+ *
+ * Copyright (c) 2019 Linaro Ltd.
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_BM1880_H
+#define __DT_BINDINGS_CLOCK_BM1880_H
+
+#define BM1880_CLK_OSC			0
+#define BM1880_CLK_MPLL			1
+#define BM1880_CLK_SPLL			2
+#define BM1880_CLK_FPLL			3
+#define BM1880_CLK_DDRPLL 		4
+#define BM1880_CLK_A53			5
+#define BM1880_CLK_50M_A53		6
+#define BM1880_CLK_AHB_ROM		7
+#define BM1880_CLK_AXI_SRAM		8
+#define BM1880_CLK_DDR_AXI		9
+#define BM1880_CLK_EFUSE		10
+#define BM1880_CLK_APB_EFUSE		11
+#define BM1880_CLK_AXI5_EMMC		12
+#define BM1880_CLK_EMMC			13
+#define BM1880_CLK_100K_EMMC		14
+#define BM1880_CLK_AXI5_SD		15
+#define BM1880_CLK_SD			16
+#define BM1880_CLK_100K_SD		17
+#define BM1880_CLK_500M_ETH0		18
+#define BM1880_CLK_AXI4_ETH0		19
+#define BM1880_CLK_500M_ETH1		20
+#define BM1880_CLK_AXI4_ETH1		21
+#define BM1880_CLK_AXI1_GDMA		22
+#define BM1880_CLK_APB_GPIO		23
+#define BM1880_CLK_APB_GPIO_INTR	24
+#define BM1880_CLK_GPIO_DB		25
+#define BM1880_CLK_AXI1_MINER		26
+#define BM1880_CLK_AHB_SF		27
+#define BM1880_CLK_SDMA_AXI		28
+#define BM1880_CLK_SDMA_AUD		29
+#define BM1880_CLK_APB_I2C		30
+#define BM1880_CLK_APB_WDT		31
+#define BM1880_CLK_APB_JPEG		32
+#define BM1880_CLK_JPEG_AXI		33
+#define BM1880_CLK_AXI5_NF		34
+#define BM1880_CLK_APB_NF		35
+#define BM1880_CLK_NF			36
+#define BM1880_CLK_APB_PWM		37
+#define BM1880_CLK_DIV_0_RV		38
+#define BM1880_CLK_DIV_1_RV		39
+#define BM1880_CLK_MUX_RV		40
+#define BM1880_CLK_RV			41
+#define BM1880_CLK_APB_SPI		42
+#define BM1880_CLK_TPU_AXI		43
+#define BM1880_CLK_DIV_UART_500M	44
+#define BM1880_CLK_UART_500M		45
+#define BM1880_CLK_APB_UART		46
+#define BM1880_CLK_APB_I2S		47
+#define BM1880_CLK_AXI4_USB		48
+#define BM1880_CLK_APB_USB		49
+#define BM1880_CLK_125M_USB		50
+#define BM1880_CLK_33K_USB		51
+#define BM1880_CLK_DIV_12M_USB		52
+#define BM1880_CLK_12M_USB		53
+#define BM1880_CLK_APB_VIDEO		54
+#define BM1880_CLK_VIDEO_AXI		55
+#define BM1880_CLK_VPP_AXI		56
+#define BM1880_CLK_APB_VPP		57
+#define BM1880_CLK_DIV_0_AXI1		58
+#define BM1880_CLK_DIV_1_AXI1		59
+#define BM1880_CLK_AXI1			60
+#define BM1880_CLK_AXI2			61
+#define BM1880_CLK_AXI3			62
+#define BM1880_CLK_AXI4			63
+#define BM1880_CLK_AXI5			64
+#define BM1880_CLK_DIV_0_AXI6		65
+#define BM1880_CLK_DIV_1_AXI6		66
+#define BM1880_CLK_MUX_AXI6		67
+#define BM1880_CLK_AXI6			68
+#define BM1880_NR_CLKS			69
+
+#endif /* __DT_BINDINGS_CLOCK_BM1880_H */
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 2/5] arm64: dts: bitmain: Add clock controller support for BM1880 SoC
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
@ 2019-07-05 15:14 ` Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 3/5] arm64: dts: bitmain: Source common clock for UART controllers Manivannan Sadhasivam
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Add clock controller support for Bitmain BM1880 SoC.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm64/boot/dts/bitmain/bm1880.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/bitmain/bm1880.dtsi b/arch/arm64/boot/dts/bitmain/bm1880.dtsi
index 86e73af1629c..d2edb2e28bf2 100644
--- a/arch/arm64/boot/dts/bitmain/bm1880.dtsi
+++ b/arch/arm64/boot/dts/bitmain/bm1880.dtsi
@@ -4,6 +4,7 @@
  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
  */
 
+#include <dt-bindings/clock/bm1880-clock.h>
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 
 / {
@@ -65,6 +66,12 @@
 			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
 	};
 
+	osc: osc {
+		compatible = "fixed-clock";
+		clock-frequency = <25000000>;
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <2>;
@@ -93,6 +100,14 @@
 				reg = <0x400 0x120>;
 			};
 
+			clk: clock-controller {
+				compatible = "bitmain,bm1880-clk";
+				reg = <0xe8 0x0c>,<0x800 0xb0>;
+				reg-names = "pll", "sys";
+				clocks = <&osc>;
+				#clock-cells = <1>;
+			};
+
 			rst: reset-controller@c00 {
 				compatible = "bitmain,bm1880-reset";
 				reg = <0xc00 0x8>;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 3/5] arm64: dts: bitmain: Source common clock for UART controllers
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 2/5] arm64: dts: bitmain: Add clock controller support for BM1880 SoC Manivannan Sadhasivam
@ 2019-07-05 15:14 ` Manivannan Sadhasivam
  2019-07-05 15:14 ` [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller Manivannan Sadhasivam
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Remove fixed clock and source common clock for UART controllers.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts |  9 ---------
 arch/arm64/boot/dts/bitmain/bm1880.dtsi            | 12 ++++++++++++
 2 files changed, 12 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts b/arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts
index 3e8c70778e24..7a2c7f9c2660 100644
--- a/arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts
+++ b/arch/arm64/boot/dts/bitmain/bm1880-sophon-edge.dts
@@ -49,12 +49,6 @@
 		reg = <0x1 0x00000000 0x0 0x40000000>; // 1GB
 	};
 
-	uart_clk: uart-clk {
-		compatible = "fixed-clock";
-		clock-frequency = <500000000>;
-		#clock-cells = <0>;
-	};
-
 	soc {
 		gpio0: gpio@50027000 {
 			porta: gpio-controller@0 {
@@ -173,21 +167,18 @@
 
 &uart0 {
 	status = "okay";
-	clocks = <&uart_clk>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart0_default>;
 };
 
 &uart1 {
 	status = "okay";
-	clocks = <&uart_clk>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1_default>;
 };
 
 &uart2 {
 	status = "okay";
-	clocks = <&uart_clk>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart2_default>;
 };
diff --git a/arch/arm64/boot/dts/bitmain/bm1880.dtsi b/arch/arm64/boot/dts/bitmain/bm1880.dtsi
index d2edb2e28bf2..408b76087762 100644
--- a/arch/arm64/boot/dts/bitmain/bm1880.dtsi
+++ b/arch/arm64/boot/dts/bitmain/bm1880.dtsi
@@ -172,6 +172,9 @@
 		uart0: serial@58018000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x58018000 0x0 0x2000>;
+			clocks = <&clk BM1880_CLK_UART_500M>,
+				 <&clk BM1880_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
 			interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
@@ -182,6 +185,9 @@
 		uart1: serial@5801A000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x5801a000 0x0 0x2000>;
+			clocks = <&clk BM1880_CLK_UART_500M>,
+				 <&clk BM1880_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
 			interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
@@ -192,6 +198,9 @@
 		uart2: serial@5801C000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x5801c000 0x0 0x2000>;
+			clocks = <&clk BM1880_CLK_UART_500M>,
+				 <&clk BM1880_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
 			interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
@@ -202,6 +211,9 @@
 		uart3: serial@5801E000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x5801e000 0x0 0x2000>;
+			clocks = <&clk BM1880_CLK_UART_500M>,
+				 <&clk BM1880_CLK_APB_UART>;
+			clock-names = "baudclk", "apb_pclk";
 			interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
 			reg-shift = <2>;
 			reg-io-width = <4>;
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
                   ` (2 preceding siblings ...)
  2019-07-05 15:14 ` [PATCH 3/5] arm64: dts: bitmain: Source common clock for UART controllers Manivannan Sadhasivam
@ 2019-07-05 15:14 ` Manivannan Sadhasivam
  2019-08-08  5:15   ` Stephen Boyd
  2019-07-05 15:14 ` [PATCH 5/5] MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver Manivannan Sadhasivam
  2019-07-22  6:20 ` [PATCH 0/5] Add Bitmain BM1880 " Manivannan Sadhasivam
  5 siblings, 1 reply; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Add common clock driver for Bitmain BM1880 SoC clock controller.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 drivers/clk/Kconfig      |   6 +
 drivers/clk/Makefile     |   1 +
 drivers/clk/clk-bm1880.c | 947 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 954 insertions(+)
 create mode 100644 drivers/clk/clk-bm1880.c

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index fc1e0cf44995..ffc61ed85ade 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -304,6 +304,12 @@ config COMMON_CLK_FIXED_MMIO
 	help
 	  Support for Memory Mapped IO Fixed clocks
 
+config COMMON_CLK_BM1880
+	bool "Clock driver for Bitmain BM1880 SoC"
+	depends on ARCH_BITMAIN || COMPILE_TEST
+	help
+	  This driver supports the clocks on Bitmain BM1880 SoC.
+
 source "drivers/clk/actions/Kconfig"
 source "drivers/clk/analogbits/Kconfig"
 source "drivers/clk/bcm/Kconfig"
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 9ef4305d55e0..66c44b84a6f2 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_MACH_ASM9260)		+= clk-asm9260.o
 obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)	+= clk-axi-clkgen.o
 obj-$(CONFIG_ARCH_AXXIA)		+= clk-axm5516.o
 obj-$(CONFIG_COMMON_CLK_BD718XX)	+= clk-bd718x7.o
+obj-$(CONFIG_COMMON_CLK_BM1880)		+= clk-bm1880.o
 obj-$(CONFIG_COMMON_CLK_CDCE706)	+= clk-cdce706.o
 obj-$(CONFIG_COMMON_CLK_CDCE925)	+= clk-cdce925.o
 obj-$(CONFIG_ARCH_CLPS711X)		+= clk-clps711x.o
diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c
new file mode 100644
index 000000000000..26cdb75bb936
--- /dev/null
+++ b/drivers/clk/clk-bm1880.c
@@ -0,0 +1,947 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Bitmain BM1880 SoC clock driver
+ *
+ * Copyright (c) 2019 Linaro Ltd.
+ * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/of_address.h>
+#include <linux/slab.h>
+
+#include <dt-bindings/clock/bm1880-clock.h>
+
+#define BM1880_CLK_MPLL_CTL	0x00
+#define BM1880_CLK_SPLL_CTL	0x04
+#define BM1880_CLK_FPLL_CTL	0x08
+#define BM1880_CLK_DDRPLL_CTL	0x0c
+
+#define BM1880_CLK_ENABLE0	0x00
+#define BM1880_CLK_ENABLE1	0x04
+#define BM1880_CLK_SELECT	0x20
+#define BM1880_CLK_DIV0		0x40
+#define BM1880_CLK_DIV1		0x44
+#define BM1880_CLK_DIV2		0x48
+#define BM1880_CLK_DIV3		0x4c
+#define BM1880_CLK_DIV4		0x50
+#define BM1880_CLK_DIV5		0x54
+#define BM1880_CLK_DIV6		0x58
+#define BM1880_CLK_DIV7		0x5c
+#define BM1880_CLK_DIV8		0x60
+#define BM1880_CLK_DIV9		0x64
+#define BM1880_CLK_DIV10	0x68
+#define BM1880_CLK_DIV11	0x6c
+#define BM1880_CLK_DIV12	0x70
+#define BM1880_CLK_DIV13	0x74
+#define BM1880_CLK_DIV14	0x78
+#define BM1880_CLK_DIV15	0x7c
+#define BM1880_CLK_DIV16	0x80
+#define BM1880_CLK_DIV17	0x84
+#define BM1880_CLK_DIV18	0x88
+#define BM1880_CLK_DIV19	0x8c
+#define BM1880_CLK_DIV20	0x90
+#define BM1880_CLK_DIV21	0x94
+#define BM1880_CLK_DIV22	0x98
+#define BM1880_CLK_DIV23	0x9c
+#define BM1880_CLK_DIV24	0xa0
+#define BM1880_CLK_DIV25	0xa4
+#define BM1880_CLK_DIV26	0xa8
+#define BM1880_CLK_DIV27	0xac
+#define BM1880_CLK_DIV28	0xb0
+
+#define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw)
+#define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw)
+
+static DEFINE_SPINLOCK(bm1880_clk_lock);
+
+struct bm1880_clock_data {
+	void __iomem *pll_base;
+	void __iomem *sys_base;
+	struct clk_onecell_data clk_data;
+};
+
+struct bm1880_gate_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	*parent;
+	u32		gate_reg;
+	s8		gate_shift;
+	unsigned long	flags;
+};
+
+struct bm1880_mux_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	* const * parents;
+	s8		num_parents;
+	u32		reg;
+	s8		shift;
+	unsigned long	flags;
+};
+
+struct bm1880_div_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	*parent;
+	u32		reg;
+	u8		shift;
+	u8		width;
+	u32		initval;
+	struct clk_div_table *table;
+	unsigned long	flags;
+};
+
+struct bm1880_div_hw_clock {
+	struct bm1880_div_clock div;
+	void __iomem *base;
+	spinlock_t *lock;
+	struct clk_hw hw;
+};
+
+struct bm1880_composite_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	*parent;
+	const char	* const * parents;
+	unsigned int	num_parents;
+	unsigned long	flags;
+
+	u32		gate_reg;
+	u32		mux_reg;
+	u32		div_reg;
+
+	s8		gate_shift;
+	s8		mux_shift;
+	s8		div_shift;
+	s8		div_width;
+	s16		div_initval;
+	struct clk_div_table *table;
+};
+
+struct bm1880_pll_clock {
+	unsigned int	id;
+	const char	*name;
+	const char	*parent;
+	u32		reg;
+	unsigned long	flags;
+};
+
+struct bm1880_pll_hw_clock {
+	struct bm1880_pll_clock pll;
+	void __iomem *base;
+	struct clk_hw hw;
+};
+
+#define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,	\
+			_div_shift, _div_width, _div_initval, _table,	\
+			_flags) {					\
+		.id = _id,						\
+		.parent = _parent,					\
+		.name = _name,						\
+		.gate_reg = _gate_reg,					\
+		.gate_shift = _gate_shift,				\
+		.div_reg = _div_reg,					\
+		.div_shift = _div_shift,				\
+		.div_width = _div_width,				\
+		.div_initval = _div_initval,				\
+		.table = _table,					\
+		.mux_shift = -1,					\
+		.flags = _flags,					\
+	}
+
+#define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift,		\
+			_mux_reg, _mux_shift, _flags) {			\
+		.id = _id,						\
+		.parents = _parents,					\
+		.num_parents = ARRAY_SIZE(_parents),			\
+		.name = _name,						\
+		.gate_reg = _gate_reg,					\
+		.gate_shift = _gate_shift,				\
+		.div_shift = -1,					\
+		.mux_reg = _mux_reg,					\
+		.mux_shift = _mux_shift,				\
+		.flags = _flags,					\
+	}
+
+static const struct bm1880_pll_clock bm1880_pll_clks[] = {
+	{ BM1880_CLK_MPLL, "clk_mpll", "osc", BM1880_CLK_MPLL_CTL,
+	  CLK_IS_CRITICAL },
+	{ BM1880_CLK_SPLL, "clk_spll", "osc", BM1880_CLK_SPLL_CTL,
+	  CLK_IS_CRITICAL },
+	{ BM1880_CLK_FPLL, "clk_fpll", "osc", BM1880_CLK_FPLL_CTL,
+	  CLK_IS_CRITICAL },
+	{ BM1880_CLK_DDRPLL, "clk_ddrpll", "osc", BM1880_CLK_DDRPLL_CTL,
+	  CLK_IS_CRITICAL },
+};
+
+static const struct bm1880_gate_clock bm1880_gate_clks[] = {
+	{ BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 2, CLK_IS_CRITICAL },
+	{ BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1",
+	  BM1880_CLK_ENABLE0, 3, CLK_IS_CRITICAL },
+	{ BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL },
+	{ BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 6, CLK_IS_CRITICAL },
+	{ BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5",
+	  BM1880_CLK_ENABLE0, 7, 0 },
+	{ BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5",
+	  BM1880_CLK_ENABLE0, 10, 0 },
+	{ BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4",
+	  BM1880_CLK_ENABLE0, 14, 0 },
+	{ BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4",
+	  BM1880_CLK_ENABLE0, 16, 0 },
+	{ BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1",
+	  BM1880_CLK_ENABLE0, 17, 0 },
+	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */
+	{ BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED },
+	{ BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED },
+	{ BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1",
+	  BM1880_CLK_ENABLE0, 21, 0 },
+	{ BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 22, 0 },
+	{ BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5",
+	  BM1880_CLK_ENABLE0, 23, 0 },
+	{ BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 25, 0 },
+	{ BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE0, 26, 0 },
+	{ BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6",
+	  BM1880_CLK_ENABLE0, 27, 0 },
+	{ BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5",
+	  BM1880_CLK_ENABLE0, 29, 0 },
+	{ BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6",
+	  BM1880_CLK_ENABLE0, 30, 0 },
+	{ BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE1, 0, 0 },
+	{ BM1880_CLK_RV, "clk_rv", "clk_mux_rv",
+	  BM1880_CLK_ENABLE1, 1, 0 },
+	{ BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE1, 2, 0 },
+	{ BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m",
+	  BM1880_CLK_ENABLE1, 4, 0 },
+	{ BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6",
+	  BM1880_CLK_ENABLE1, 5, 0 },
+	{ BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6",
+	  BM1880_CLK_ENABLE1, 6, 0 },
+	{ BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4",
+	  BM1880_CLK_ENABLE1, 7, 0 },
+	{ BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6",
+	  BM1880_CLK_ENABLE1, 8, 0 },
+	{ BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb",
+	  BM1880_CLK_ENABLE1, 11, 0 },
+	{ BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6",
+	  BM1880_CLK_ENABLE1, 12, 0 },
+	{ BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6",
+	  BM1880_CLK_ENABLE1, 15, 0 },
+	{ BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6",
+	  BM1880_CLK_ENABLE1, 21, CLK_IS_CRITICAL },
+};
+
+static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" };
+static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" };
+static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" };
+static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" };
+
+static const struct bm1880_mux_clock bm1880_mux_clks[] = {
+	{ BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2,
+	  BM1880_CLK_SELECT, 1, 0 },
+	{ BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2,
+	  BM1880_CLK_SELECT, 3, 0 },
+};
+
+static struct clk_div_table bm1880_div_table_0[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
+	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
+	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
+	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
+	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
+	{ 0, 0 }
+};
+
+static struct clk_div_table bm1880_div_table_1[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
+	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
+	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
+	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
+	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
+	{ 127, 128 }, { 0, 0 }
+};
+
+static struct clk_div_table bm1880_div_table_2[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
+	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
+	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
+	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
+	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
+	{ 127, 128 }, { 255, 256 }, { 0, 0 }
+};
+
+static struct clk_div_table bm1880_div_table_3[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
+	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
+	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
+	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
+	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
+	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 }
+};
+
+static struct clk_div_table bm1880_div_table_4[] = {
+	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
+	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
+	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
+	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
+	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
+	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
+	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
+	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
+	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 },
+	{ 0, 0 }
+};
+
+static const struct bm1880_div_clock bm1880_div_clks[] = {
+	{ BM1880_CLK_DIV_0_RV, "clk_div_0_rv", "clk_spll",
+	  BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
+	{ BM1880_CLK_DIV_1_RV, "clk_div_1_rv", "clk_fpll",
+	  BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
+	{ BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", "clk_fpll",
+	  BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0 },
+	{ BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", "clk_mpll",
+	  BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0, CLK_IS_CRITICAL },
+	{ BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", "clk_fpll",
+	  BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0, CLK_IS_CRITICAL },
+	{ BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", "clk_fpll",
+	  BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0, CLK_IS_CRITICAL },
+	{ BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", "clk_mpll",
+	  BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0, CLK_IS_CRITICAL },
+	{ BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", "clk_fpll",
+	  BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0 },
+};
+
+static struct bm1880_composite_clock bm1880_composite_clks[] = {
+	GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents,
+		 BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0,
+		 CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30,
+		 bm1880_div_table_0, CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60,
+		 bm1880_div_table_1, 0),
+	GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb",
+		 BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120,
+		 bm1880_div_table_2, 0),
+	GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb",
+		 BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120,
+		 bm1880_div_table_2, 0),
+	GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3,
+		 bm1880_div_table_0, 0),
+	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */
+	GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb",
+		 BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120,
+		 bm1880_div_table_4, CLK_IGNORE_UNUSED),
+	GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61,
+		 bm1880_div_table_1, 0),
+	GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll",
+		 BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll",
+		 BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb",
+		 BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363,
+		 bm1880_div_table_3, 0),
+	GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4,
+		 bm1880_div_table_0, 0),
+	GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4,
+		 bm1880_div_table_0, 0),
+	GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents,
+		 BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2,
+		 CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3,
+		 bm1880_div_table_0, CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv",
+		 BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2,
+		 bm1880_div_table_0, CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6,
+		 bm1880_div_table_0, CLK_IS_CRITICAL),
+	GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll",
+		 BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15,
+		 bm1880_div_table_0, CLK_IS_CRITICAL),
+};
+
+static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)
+{
+	u32 fbdiv, fref, refdiv;
+	u32 postdiv1, postdiv2;
+	unsigned long rate, numerator, denominator;
+
+	fbdiv = (regval >> 16) & 0xfff;
+	fref = parent_rate;
+	refdiv = regval & 0x1f;
+	postdiv1 = (regval >> 8) & 0x7;
+	postdiv2 = (regval >> 12) & 0x7;
+
+	numerator = parent_rate * fbdiv;
+	denominator = refdiv * postdiv1 * postdiv2;
+	do_div(numerator, denominator);
+	rate = numerator;
+
+	return rate;
+}
+
+static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw,
+					    unsigned long parent_rate)
+{
+	struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);
+	unsigned long rate;
+	u32 regval;
+
+	regval = readl(pll_hw->base + pll_hw->pll.reg);
+	rate = bm1880_pll_rate_calc(regval, parent_rate);
+
+	return rate;
+}
+
+static const struct clk_ops bm1880_pll_ops = {
+	.recalc_rate	= bm1880_pll_recalc_rate,
+};
+
+struct clk *bm1880_clk_register_pll(const struct bm1880_pll_clock *pll_clk,
+				    void __iomem *sys_base)
+{
+	struct bm1880_pll_hw_clock *pll_hw;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int err;
+
+	pll_hw = kzalloc(sizeof(*pll_hw), GFP_KERNEL);
+	if (!pll_hw)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = pll_clk->name;
+	init.ops = &bm1880_pll_ops;
+	init.flags = pll_clk->flags;
+	init.parent_names = &pll_clk->parent;
+	init.num_parents = 1;
+
+	pll_hw->hw.init = &init;
+	pll_hw->pll.reg = pll_clk->reg;
+	pll_hw->base = sys_base;
+
+	hw = &pll_hw->hw;
+	err = clk_hw_register(NULL, hw);
+
+	if (err) {
+		kfree(pll_hw);
+		return ERR_PTR(err);
+	}
+
+	return hw->clk;
+}
+
+void bm1880_clk_unregister_pll(struct clk *clk)
+{
+	struct bm1880_pll_hw_clock *pll_hw;
+	struct clk_hw *hw;
+
+	hw = __clk_get_hw(clk);
+	if (!hw)
+		return;
+
+	pll_hw = to_bm1880_pll_clk(hw);
+
+	clk_unregister(clk);
+	kfree(pll_hw);
+}
+
+int bm1880_clk_register_plls(const struct bm1880_pll_clock *clks,
+			     int num_clks, struct bm1880_clock_data *data)
+{
+	struct clk *clk;
+	void __iomem *pll_base = data->pll_base;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		const struct bm1880_pll_clock *bm1880_clk = &clks[i];
+
+		clk = bm1880_clk_register_pll(bm1880_clk, pll_base);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, bm1880_clk->name);
+			goto err_clk;
+		}
+
+		data->clk_data.clks[clks[i].id] = clk;
+	}
+
+	return 0;
+
+err_clk:
+	while (i--)
+		bm1880_clk_unregister_pll(data->clk_data.clks[clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,
+			    int num_clks, struct bm1880_clock_data *data)
+{
+	struct clk *clk;
+	void __iomem *sys_base = data->sys_base;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		clk = clk_register_mux(NULL, clks[i].name,
+				       clks[i].parents,
+				       clks[i].num_parents,
+				       clks[i].flags,
+				       sys_base + clks[i].reg,
+				       clks[i].shift, 1, 0,
+				       &bm1880_clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			goto err_clk;
+		}
+
+		data->clk_data.clks[clks[i].id] = clk;
+	}
+
+	return 0;
+
+err_clk:
+	while (i--)
+		clk_unregister_gate(data->clk_data.clks[clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,
+						unsigned long parent_rate)
+{
+	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
+	struct bm1880_div_clock *div = &div_hw->div;
+	void __iomem *reg_addr = div_hw->base + div->reg;
+	unsigned int val;
+	unsigned long rate;
+
+	if (!(readl(reg_addr) & BIT(3))) {
+		val = div->initval;
+	} else {
+		val = readl(reg_addr) >> div->shift;
+		val &= clk_div_mask(div->width);
+	}
+
+	rate = divider_recalc_rate(hw, parent_rate, val, div->table,
+				   div->flags, div->width);
+
+	return rate;
+}
+
+static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
+				      unsigned long *prate)
+{
+	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
+	struct bm1880_div_clock *div = &div_hw->div;
+	void __iomem *reg_addr = div_hw->base + div->reg;
+
+	if (div->flags & CLK_DIVIDER_READ_ONLY) {
+		u32 val;
+
+		val = readl(reg_addr) >> div->shift;
+		val &= clk_div_mask(div->width);
+
+		return divider_ro_round_rate(hw, rate, prate, div->table,
+					     div->width, div->flags,
+					     val);
+	}
+
+	return divider_round_rate(hw, rate, prate, div->table,
+				  div->width, div->flags);
+}
+
+static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
+				   unsigned long parent_rate)
+{
+	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
+	struct bm1880_div_clock *div = &div_hw->div;
+	void __iomem *reg_addr = div_hw->base + div->reg;
+	unsigned long flags = 0;
+	int value;
+	u32 val;
+
+	value = divider_get_val(rate, parent_rate, div->table,
+				div->width, div_hw->div.flags);
+	if (value < 0)
+		return value;
+
+	if (div_hw->lock)
+		spin_lock_irqsave(div_hw->lock, flags);
+	else
+		__acquire(div_hw->lock);
+
+	if (div->flags & CLK_DIVIDER_HIWORD_MASK) {
+		val = clk_div_mask(div->width) << (div_hw->div.shift + 16);
+	} else {
+		val = readl(reg_addr);
+		val &= ~(clk_div_mask(div->width) << div_hw->div.shift);
+	}
+	val |= (u32)value << div->shift;
+	writel(val, reg_addr);
+
+	if (div_hw->lock)
+		spin_unlock_irqrestore(div_hw->lock, flags);
+	else
+		__release(div_hw->lock);
+
+	return 0;
+}
+
+const struct clk_ops bm1880_clk_div_ops = {
+	.recalc_rate = bm1880_clk_div_recalc_rate,
+	.round_rate = bm1880_clk_div_round_rate,
+	.set_rate = bm1880_clk_div_set_rate,
+};
+
+struct clk *bm1880_clk_register_div(const struct bm1880_div_clock *div_clk,
+				    void __iomem *sys_base)
+{
+	struct bm1880_div_hw_clock *div_hw;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int err;
+
+	div_hw = kzalloc(sizeof(*div_hw), GFP_KERNEL);
+	if (!div_hw)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = div_clk->name;
+	init.ops = &bm1880_clk_div_ops;
+	init.flags = div_clk->flags;
+	init.parent_names = &div_clk->parent;
+	init.num_parents = 1;
+
+	div_hw->hw.init = &init;
+	div_hw->div.reg = div_clk->reg;
+	div_hw->div.shift = div_clk->shift;
+	div_hw->div.width = div_clk->width;
+	div_hw->div.initval = div_clk->initval;
+	div_hw->div.table = div_clk->table;
+	div_hw->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
+	div_hw->base = sys_base;
+	div_hw->lock = &bm1880_clk_lock;
+
+	hw = &div_hw->hw;
+	err = clk_hw_register(NULL, hw);
+
+	if (err) {
+		kfree(div_hw);
+		return ERR_PTR(err);
+	}
+
+	return hw->clk;
+}
+
+void bm1880_clk_unregister_div(struct clk *clk)
+{
+	struct bm1880_div_hw_clock *div_hw;
+	struct clk_hw *hw;
+
+	hw = __clk_get_hw(clk);
+	if (!hw)
+		return;
+
+	div_hw = to_bm1880_div_clk(hw);
+
+	clk_unregister(clk);
+	kfree(div_hw);
+}
+
+int bm1880_clk_register_divs(const struct bm1880_div_clock *clks,
+			     int num_clks, struct bm1880_clock_data *data)
+{
+	struct clk *clk;
+	void __iomem *sys_base = data->sys_base;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		const struct bm1880_div_clock *bm1880_clk = &clks[i];
+
+		clk = bm1880_clk_register_div(bm1880_clk, sys_base);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, bm1880_clk->name);
+			goto err_clk;
+		}
+
+		data->clk_data.clks[clks[i].id] = clk;
+	}
+
+	return 0;
+
+err_clk:
+	while (i--)
+		bm1880_clk_unregister_div(data->clk_data.clks[clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks,
+			     int num_clks, struct bm1880_clock_data *data)
+{
+	struct clk *clk;
+	void __iomem *sys_base = data->sys_base;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		clk = clk_register_gate(NULL, clks[i].name,
+					clks[i].parent,
+					clks[i].flags,
+					sys_base + clks[i].gate_reg,
+					clks[i].gate_shift,
+					0,
+					&bm1880_clk_lock);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, clks[i].name);
+			goto err_clk;
+		}
+
+		data->clk_data.clks[clks[i].id] = clk;
+	}
+
+	return 0;
+
+err_clk:
+	while (i--)
+		clk_unregister_gate(data->clk_data.clks[clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+struct clk *bm1880_clk_register_composite(struct bm1880_composite_clock *clks,
+					  void __iomem *sys_base)
+{
+	struct clk *clk;
+	struct clk_mux *mux = NULL;
+	struct clk_gate *gate = NULL;
+	struct bm1880_div_hw_clock *div_hws = NULL;
+	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
+	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
+	const char * const *parent_names;
+	const char *parent;
+	int num_parents;
+	int ret;
+
+	if (clks->mux_shift >= 0) {
+		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+		if (!mux)
+			return ERR_PTR(-ENOMEM);
+
+		mux->reg = sys_base + clks->mux_reg;
+		mux->mask = 1;
+		mux->shift = clks->mux_shift;
+		mux_hw = &mux->hw;
+		mux_ops = &clk_mux_ops;
+		mux->lock = &bm1880_clk_lock;
+
+		parent_names = clks->parents;
+		num_parents = clks->num_parents;
+	} else {
+		parent = clks->parent;
+		parent_names = &parent;
+		num_parents = 1;
+	}
+
+	if (clks->gate_shift >= 0) {
+		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+		if (!gate) {
+			ret = -ENOMEM;
+			goto err_out;
+		}
+
+		gate->reg = sys_base + clks->gate_reg;
+		gate->bit_idx = clks->gate_shift;
+		gate->lock = &bm1880_clk_lock;
+
+		gate_hw = &gate->hw;
+		gate_ops = &clk_gate_ops;
+	}
+
+	if (clks->div_shift >= 0) {
+		div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL);
+		if (!div_hws) {
+			ret = -ENOMEM;
+			goto err_out;
+		}
+
+		div_hws->base = sys_base;
+		div_hws->div.reg = clks->div_reg;
+		div_hws->div.shift = clks->div_shift;
+		div_hws->div.width = clks->div_width;
+		div_hws->div.table = clks->table;
+		div_hws->div.initval = clks->div_initval;
+		div_hws->lock = &bm1880_clk_lock;
+		div_hws->div.flags = CLK_DIVIDER_ONE_BASED |
+				     CLK_DIVIDER_ALLOW_ZERO;
+
+		div_hw = &div_hws->hw;
+		div_ops = &bm1880_clk_div_ops;
+	}
+
+	clk = clk_register_composite(NULL, clks->name, parent_names,
+				     num_parents, mux_hw, mux_ops, div_hw,
+				     div_ops, gate_hw, gate_ops, (clks->flags));
+
+	if (IS_ERR(clk)) {
+		ret = PTR_ERR(clk);
+		goto err_out;
+	}
+
+	return clk;
+
+err_out:
+	kfree(div_hws);
+	kfree(gate);
+	kfree(mux);
+
+	return ERR_PTR(ret);
+}
+
+int bm1880_clk_register_composites(struct bm1880_composite_clock *clks,
+				   int num_clks, struct bm1880_clock_data *data)
+{
+	struct clk *clk;
+	void __iomem *sys_base = data->sys_base;
+	int i;
+
+	for (i = 0; i < num_clks; i++) {
+		struct bm1880_composite_clock *bm1880_clk = &clks[i];
+
+		clk = bm1880_clk_register_composite(bm1880_clk, sys_base);
+		if (IS_ERR(clk)) {
+			pr_err("%s: failed to register clock %s\n",
+			       __func__, bm1880_clk->name);
+			goto err_clk;
+		}
+
+		data->clk_data.clks[clks[i].id] = clk;
+	}
+
+	return 0;
+
+err_clk:
+	while (i--)
+		clk_unregister_composite(data->clk_data.clks[clks[i].id]);
+
+	return PTR_ERR(clk);
+}
+
+static void bm1880_clk_init(struct device_node *np)
+{
+	struct bm1880_clock_data *clk_data;
+	struct clk **clk_table;
+	void __iomem *pll_base, *sys_base;
+	int num_clks;
+
+	pll_base = of_iomap(np, 0);
+	if (!pll_base) {
+		pr_err("%pOFn: unable to map pll resource", np);
+		of_node_put(np);
+		return;
+	}
+
+	sys_base = of_iomap(np, 1);
+	if (!sys_base) {
+		pr_err("%pOFn: unable to map sys resource", np);
+		of_node_put(np);
+		return;
+	}
+
+	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
+	if (!clk_data)
+		return;
+
+	clk_data->pll_base = pll_base;
+	clk_data->sys_base = sys_base;
+	num_clks = ARRAY_SIZE(bm1880_gate_clks) +
+		   ARRAY_SIZE(bm1880_composite_clks);
+
+	clk_table = kcalloc(num_clks, sizeof(*clk_table), GFP_KERNEL);
+	if (!clk_table)
+		goto err_out;
+
+	clk_data->clk_data.clks = clk_table;
+	clk_data->clk_data.clk_num = num_clks;
+
+	/* Register PLL clocks */
+	bm1880_clk_register_plls(bm1880_pll_clks,
+				 ARRAY_SIZE(bm1880_pll_clks),
+				 clk_data);
+
+	/* Register Divider clocks */
+	bm1880_clk_register_divs(bm1880_div_clks,
+				 ARRAY_SIZE(bm1880_div_clks),
+				 clk_data);
+
+	/* Register Mux clocks */
+	bm1880_clk_register_mux(bm1880_mux_clks,
+				ARRAY_SIZE(bm1880_mux_clks),
+				clk_data);
+
+	/* Register Composite clocks */
+	bm1880_clk_register_composites(bm1880_composite_clks,
+				       ARRAY_SIZE(bm1880_composite_clks),
+				       clk_data);
+
+	/* Register Gate clocks */
+	bm1880_clk_register_gate(bm1880_gate_clks,
+				 ARRAY_SIZE(bm1880_gate_clks),
+				 clk_data);
+
+	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
+
+	return;
+
+err_out:
+	kfree(clk_data);
+}
+
+CLK_OF_DECLARE_DRIVER(bm1880_clk, "bitmain,bm1880-clk", bm1880_clk_init);
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* [PATCH 5/5] MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
                   ` (3 preceding siblings ...)
  2019-07-05 15:14 ` [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller Manivannan Sadhasivam
@ 2019-07-05 15:14 ` Manivannan Sadhasivam
  2019-07-22  6:20 ` [PATCH 0/5] Add Bitmain BM1880 " Manivannan Sadhasivam
  5 siblings, 0 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-05 15:14 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Add MAINTAINERS entry for Bitmain BM1880 SoC clock driver.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
---
 MAINTAINERS | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 01a52fc964da..f9259161cb5c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1464,8 +1464,10 @@ M:	Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
 L:	linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 S:	Maintained
 F:	arch/arm64/boot/dts/bitmain/
+F:	drivers/clk/clk-bm1880.c
 F:	drivers/pinctrl/pinctrl-bm1880.c
 F:	Documentation/devicetree/bindings/arm/bitmain.yaml
+F:	Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
 F:	Documentation/devicetree/bindings/pinctrl/bitmain,bm1880-pinctrl.txt
 
 ARM/CALXEDA HIGHBANK ARCHITECTURE
-- 
2.17.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 0/5] Add Bitmain BM1880 clock driver
  2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
                   ` (4 preceding siblings ...)
  2019-07-05 15:14 ` [PATCH 5/5] MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver Manivannan Sadhasivam
@ 2019-07-22  6:20 ` " Manivannan Sadhasivam
  5 siblings, 0 replies; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-07-22  6:20 UTC (permalink / raw)
  To: sboyd, mturquette, robh+dt
  Cc: devicetree, darren.tsao, linux-kernel, linux-arm-kernel,
	fisher.cheng, alec.lin, linux-clk, haitao.suo

On Fri, Jul 05, 2019 at 08:44:35PM +0530, Manivannan Sadhasivam wrote:
> Hello,
> 
> This patchset adds common clock driver for Bitmain BM1880 SoC clock
> controller. The clock controller consists of gate, divider, mux
> and pll clocks with different compositions. Hence, the driver uses
> composite clock structure in place where multiple clocking units are
> combined together.
> 
> This patchset also removes UART fixed clock and sources clocks from clock
> controller for Sophon Edge board where the driver has been validated.
> 

Ping on this series.

Thanks,
Mani

> Thanks,
> Mani
> 
> Manivannan Sadhasivam (5):
>   dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
>   arm64: dts: bitmain: Add clock controller support for BM1880 SoC
>   arm64: dts: bitmain: Source common clock for UART controllers
>   clk: Add driver for Bitmain BM1880 SoC clock controller
>   MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver
> 
>  .../bindings/clock/bitmain,bm1880-clk.txt     |  47 +
>  MAINTAINERS                                   |   2 +
>  .../boot/dts/bitmain/bm1880-sophon-edge.dts   |   9 -
>  arch/arm64/boot/dts/bitmain/bm1880.dtsi       |  27 +
>  drivers/clk/Kconfig                           |   6 +
>  drivers/clk/Makefile                          |   1 +
>  drivers/clk/clk-bm1880.c                      | 947 ++++++++++++++++++
>  include/dt-bindings/clock/bm1880-clock.h      |  82 ++
>  8 files changed, 1112 insertions(+), 9 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
>  create mode 100644 drivers/clk/clk-bm1880.c
>  create mode 100644 include/dt-bindings/clock/bm1880-clock.h
> 
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
@ 2019-07-24 16:18   ` Rob Herring
  2019-08-08  5:01   ` Stephen Boyd
  1 sibling, 0 replies; 16+ messages in thread
From: Rob Herring @ 2019-07-24 16:18 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: devicetree, sboyd, mturquette, linux-kernel, darren.tsao,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

On Fri, Jul 05, 2019 at 08:44:36PM +0530, Manivannan Sadhasivam wrote:
> Add devicetree binding for Bitmain BM1880 SoC clock controller.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
>  .../bindings/clock/bitmain,bm1880-clk.txt     | 47 +++++++++++
>  include/dt-bindings/clock/bm1880-clock.h      | 82 +++++++++++++++++++
>  2 files changed, 129 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
>  create mode 100644 include/dt-bindings/clock/bm1880-clock.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> new file mode 100644
> index 000000000000..9c967095d430
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> @@ -0,0 +1,47 @@
> +* Bitmain BM1880 Clock Controller
> +
> +The Bitmain BM1880 clock controler generates and supplies clock to

checkpatch.pl reports a spelling error...

> +various peripherals within the SoC.
> +
> +Required Properties:
> +
> +- compatible: Should be "bitmain,bm1880-clk"
> +- reg :	Register address and size of PLL and SYS control domains
> +- reg-names : Register domain names: "pll" and "sys"
> +- clocks : Phandle of the input reference clock.
> +- #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 corresponding
> +dt-bindings/clock/bm1880-clock.h header and can be used in device tree sources.
> +
> +External clocks:
> +
> +The osc clock used as the input for the plls is generated outside the SoC.
> +It is expected that it is defined using standard clock bindings as "osc".
> +
> +Example: 
> +
> +        clk: clock-controller@800 {

Usually the unit-address is from the first entry.

> +                compatible = "bitmain,bm1880-clk";
> +                reg = <0xe8 0x0c>,<0x800 0xb0>;

space                                ^

> +                reg-names = "pll", "sys";
> +                clocks = <&osc>;
> +                #clock-cells = <1>;
> +        };
> +
> +Example: UART controller node that consumes clock generated by the clock
> +controller:
> +
> +        uart0: serial@58018000 {
> +                compatible = "snps,dw-apb-uart";
> +                reg = <0x0 0x58018000 0x0 0x2000>;
> +                clocks = <&clk BM1880_CLK_UART_500M>;
> +                         <&clk BM1880_CLK_APB_UART>;
> +                clock-names = "baudclk", "apb_pclk";
> +                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
> +                reg-shift = <2>;
> +                reg-io-width = <4>;
> +        };
> diff --git a/include/dt-bindings/clock/bm1880-clock.h b/include/dt-bindings/clock/bm1880-clock.h
> new file mode 100644
> index 000000000000..764472b9a4fd
> --- /dev/null
> +++ b/include/dt-bindings/clock/bm1880-clock.h
> @@ -0,0 +1,82 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Device Tree binding constants for Bitmain BM1880 SoC
> + *
> + * Copyright (c) 2019 Linaro Ltd.
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_BM1880_H
> +#define __DT_BINDINGS_CLOCK_BM1880_H
> +
> +#define BM1880_CLK_OSC			0
> +#define BM1880_CLK_MPLL			1
> +#define BM1880_CLK_SPLL			2
> +#define BM1880_CLK_FPLL			3
> +#define BM1880_CLK_DDRPLL 		4

space before tab

> +#define BM1880_CLK_A53			5
> +#define BM1880_CLK_50M_A53		6
> +#define BM1880_CLK_AHB_ROM		7
> +#define BM1880_CLK_AXI_SRAM		8
> +#define BM1880_CLK_DDR_AXI		9
> +#define BM1880_CLK_EFUSE		10
> +#define BM1880_CLK_APB_EFUSE		11
> +#define BM1880_CLK_AXI5_EMMC		12
> +#define BM1880_CLK_EMMC			13
> +#define BM1880_CLK_100K_EMMC		14
> +#define BM1880_CLK_AXI5_SD		15
> +#define BM1880_CLK_SD			16
> +#define BM1880_CLK_100K_SD		17
> +#define BM1880_CLK_500M_ETH0		18
> +#define BM1880_CLK_AXI4_ETH0		19
> +#define BM1880_CLK_500M_ETH1		20
> +#define BM1880_CLK_AXI4_ETH1		21
> +#define BM1880_CLK_AXI1_GDMA		22
> +#define BM1880_CLK_APB_GPIO		23
> +#define BM1880_CLK_APB_GPIO_INTR	24
> +#define BM1880_CLK_GPIO_DB		25
> +#define BM1880_CLK_AXI1_MINER		26
> +#define BM1880_CLK_AHB_SF		27
> +#define BM1880_CLK_SDMA_AXI		28
> +#define BM1880_CLK_SDMA_AUD		29
> +#define BM1880_CLK_APB_I2C		30
> +#define BM1880_CLK_APB_WDT		31
> +#define BM1880_CLK_APB_JPEG		32
> +#define BM1880_CLK_JPEG_AXI		33
> +#define BM1880_CLK_AXI5_NF		34
> +#define BM1880_CLK_APB_NF		35
> +#define BM1880_CLK_NF			36
> +#define BM1880_CLK_APB_PWM		37
> +#define BM1880_CLK_DIV_0_RV		38
> +#define BM1880_CLK_DIV_1_RV		39
> +#define BM1880_CLK_MUX_RV		40
> +#define BM1880_CLK_RV			41
> +#define BM1880_CLK_APB_SPI		42
> +#define BM1880_CLK_TPU_AXI		43
> +#define BM1880_CLK_DIV_UART_500M	44
> +#define BM1880_CLK_UART_500M		45
> +#define BM1880_CLK_APB_UART		46
> +#define BM1880_CLK_APB_I2S		47
> +#define BM1880_CLK_AXI4_USB		48
> +#define BM1880_CLK_APB_USB		49
> +#define BM1880_CLK_125M_USB		50
> +#define BM1880_CLK_33K_USB		51
> +#define BM1880_CLK_DIV_12M_USB		52
> +#define BM1880_CLK_12M_USB		53
> +#define BM1880_CLK_APB_VIDEO		54
> +#define BM1880_CLK_VIDEO_AXI		55
> +#define BM1880_CLK_VPP_AXI		56
> +#define BM1880_CLK_APB_VPP		57
> +#define BM1880_CLK_DIV_0_AXI1		58
> +#define BM1880_CLK_DIV_1_AXI1		59
> +#define BM1880_CLK_AXI1			60
> +#define BM1880_CLK_AXI2			61
> +#define BM1880_CLK_AXI3			62
> +#define BM1880_CLK_AXI4			63
> +#define BM1880_CLK_AXI5			64
> +#define BM1880_CLK_DIV_0_AXI6		65
> +#define BM1880_CLK_DIV_1_AXI6		66
> +#define BM1880_CLK_MUX_AXI6		67
> +#define BM1880_CLK_AXI6			68
> +#define BM1880_NR_CLKS			69
> +
> +#endif /* __DT_BINDINGS_CLOCK_BM1880_H */
> -- 
> 2.17.1
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
  2019-07-24 16:18   ` Rob Herring
@ 2019-08-08  5:01   ` Stephen Boyd
  2019-08-17  3:34     ` Manivannan Sadhasivam
  1 sibling, 1 reply; 16+ messages in thread
From: Stephen Boyd @ 2019-08-08  5:01 UTC (permalink / raw)
  To: Manivannan Sadhasivam, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Quoting Manivannan Sadhasivam (2019-07-05 08:14:36)
> Add devicetree binding for Bitmain BM1880 SoC clock controller.
> 
> Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> ---
>  .../bindings/clock/bitmain,bm1880-clk.txt     | 47 +++++++++++

Can you convert this to YAML? It's all the rage right now.

>  include/dt-bindings/clock/bm1880-clock.h      | 82 +++++++++++++++++++
>  2 files changed, 129 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
>  create mode 100644 include/dt-bindings/clock/bm1880-clock.h
> 
> diff --git a/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> new file mode 100644
> index 000000000000..9c967095d430
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> @@ -0,0 +1,47 @@
> +* Bitmain BM1880 Clock Controller
> +
> +The Bitmain BM1880 clock controler generates and supplies clock to
> +various peripherals within the SoC.
> +
> +Required Properties:
> +
> +- compatible: Should be "bitmain,bm1880-clk"
> +- reg :        Register address and size of PLL and SYS control domains
> +- reg-names : Register domain names: "pll" and "sys"
> +- clocks : Phandle of the input reference clock.
> +- #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 corresponding
> +dt-bindings/clock/bm1880-clock.h header and can be used in device tree sources.
> +
> +External clocks:
> +
> +The osc clock used as the input for the plls is generated outside the SoC.
> +It is expected that it is defined using standard clock bindings as "osc".
> +
> +Example: 
> +
> +        clk: clock-controller@800 {
> +                compatible = "bitmain,bm1880-clk";
> +                reg = <0xe8 0x0c>,<0x800 0xb0>;

It looks weird still. What hardware module is this actually part of?
Some larger power manager block?

> +                reg-names = "pll", "sys";
> +                clocks = <&osc>;
> +                #clock-cells = <1>;
> +        };
> +

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller
  2019-07-05 15:14 ` [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller Manivannan Sadhasivam
@ 2019-08-08  5:15   ` Stephen Boyd
  2019-08-17  3:55     ` Manivannan Sadhasivam
  0 siblings, 1 reply; 16+ messages in thread
From: Stephen Boyd @ 2019-08-08  5:15 UTC (permalink / raw)
  To: Manivannan Sadhasivam, mturquette, robh+dt
  Cc: devicetree, Manivannan Sadhasivam, darren.tsao, linux-kernel,
	linux-arm-kernel, fisher.cheng, alec.lin, linux-clk, haitao.suo

Quoting Manivannan Sadhasivam (2019-07-05 08:14:39)
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index fc1e0cf44995..ffc61ed85ade 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -304,6 +304,12 @@ config COMMON_CLK_FIXED_MMIO
>         help
>           Support for Memory Mapped IO Fixed clocks
>  
> +config COMMON_CLK_BM1880
> +       bool "Clock driver for Bitmain BM1880 SoC"
> +       depends on ARCH_BITMAIN || COMPILE_TEST
> +       help
> +         This driver supports the clocks on Bitmain BM1880 SoC.

Can you add this config somewhere else besides the end? Preferably
close to alphabetically in this file.

> +
>  source "drivers/clk/actions/Kconfig"
>  source "drivers/clk/analogbits/Kconfig"
>  source "drivers/clk/bcm/Kconfig"
> diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c
> new file mode 100644
> index 000000000000..26cdb75bb936
> --- /dev/null
> +++ b/drivers/clk/clk-bm1880.c
> @@ -0,0 +1,947 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Bitmain BM1880 SoC clock driver
> + *
> + * Copyright (c) 2019 Linaro Ltd.
> + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/of_address.h>
> +#include <linux/slab.h>

Should probably add kernel.h for at least container_of()

> +
> +#include <dt-bindings/clock/bm1880-clock.h>
> +
> +#define BM1880_CLK_MPLL_CTL    0x00
> +#define BM1880_CLK_SPLL_CTL    0x04
> +#define BM1880_CLK_FPLL_CTL    0x08
> +#define BM1880_CLK_DDRPLL_CTL  0x0c
> +
> +#define BM1880_CLK_ENABLE0     0x00
> +#define BM1880_CLK_ENABLE1     0x04
> +#define BM1880_CLK_SELECT      0x20
> +#define BM1880_CLK_DIV0                0x40
> +#define BM1880_CLK_DIV1                0x44
> +#define BM1880_CLK_DIV2                0x48
> +#define BM1880_CLK_DIV3                0x4c
> +#define BM1880_CLK_DIV4                0x50
> +#define BM1880_CLK_DIV5                0x54
> +#define BM1880_CLK_DIV6                0x58
> +#define BM1880_CLK_DIV7                0x5c
> +#define BM1880_CLK_DIV8                0x60
> +#define BM1880_CLK_DIV9                0x64
> +#define BM1880_CLK_DIV10       0x68
> +#define BM1880_CLK_DIV11       0x6c
> +#define BM1880_CLK_DIV12       0x70
> +#define BM1880_CLK_DIV13       0x74
> +#define BM1880_CLK_DIV14       0x78
> +#define BM1880_CLK_DIV15       0x7c
> +#define BM1880_CLK_DIV16       0x80
> +#define BM1880_CLK_DIV17       0x84
> +#define BM1880_CLK_DIV18       0x88
> +#define BM1880_CLK_DIV19       0x8c
> +#define BM1880_CLK_DIV20       0x90
> +#define BM1880_CLK_DIV21       0x94
> +#define BM1880_CLK_DIV22       0x98
> +#define BM1880_CLK_DIV23       0x9c
> +#define BM1880_CLK_DIV24       0xa0
> +#define BM1880_CLK_DIV25       0xa4
> +#define BM1880_CLK_DIV26       0xa8
> +#define BM1880_CLK_DIV27       0xac
> +#define BM1880_CLK_DIV28       0xb0
> +
> +#define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw)
> +#define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw)
> +
> +static DEFINE_SPINLOCK(bm1880_clk_lock);
> +
> +struct bm1880_clock_data {
> +       void __iomem *pll_base;
> +       void __iomem *sys_base;
> +       struct clk_onecell_data clk_data;
> +};
> +
> +struct bm1880_gate_clock {
> +       unsigned int    id;
> +       const char      *name;
> +       const char      *parent;
> +       u32             gate_reg;
> +       s8              gate_shift;
> +       unsigned long   flags;
> +};
> +
> +struct bm1880_mux_clock {
> +       unsigned int    id;
> +       const char      *name;
> +       const char      * const * parents;
> +       s8              num_parents;
> +       u32             reg;
> +       s8              shift;
> +       unsigned long   flags;
> +};
> +
> +struct bm1880_div_clock {
> +       unsigned int    id;
> +       const char      *name;
> +       const char      *parent;
> +       u32             reg;
> +       u8              shift;
> +       u8              width;
> +       u32             initval;
> +       struct clk_div_table *table;
> +       unsigned long   flags;
> +};
> +
> +struct bm1880_div_hw_clock {
> +       struct bm1880_div_clock div;
> +       void __iomem *base;
> +       spinlock_t *lock;
> +       struct clk_hw hw;
> +};
> +
> +struct bm1880_composite_clock {
> +       unsigned int    id;
> +       const char      *name;
> +       const char      *parent;
> +       const char      * const * parents;
> +       unsigned int    num_parents;
> +       unsigned long   flags;
> +
> +       u32             gate_reg;
> +       u32             mux_reg;
> +       u32             div_reg;
> +
> +       s8              gate_shift;
> +       s8              mux_shift;
> +       s8              div_shift;
> +       s8              div_width;
> +       s16             div_initval;
> +       struct clk_div_table *table;
> +};
> +
> +struct bm1880_pll_clock {
> +       unsigned int    id;
> +       const char      *name;
> +       const char      *parent;
> +       u32             reg;
> +       unsigned long   flags;
> +};
> +
> +struct bm1880_pll_hw_clock {
> +       struct bm1880_pll_clock pll;
> +       void __iomem *base;
> +       struct clk_hw hw;
> +};
> +
> +#define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,        \
> +                       _div_shift, _div_width, _div_initval, _table,   \
> +                       _flags) {                                       \
> +               .id = _id,                                              \
> +               .parent = _parent,                                      \
> +               .name = _name,                                          \
> +               .gate_reg = _gate_reg,                                  \
> +               .gate_shift = _gate_shift,                              \
> +               .div_reg = _div_reg,                                    \
> +               .div_shift = _div_shift,                                \
> +               .div_width = _div_width,                                \
> +               .div_initval = _div_initval,                            \
> +               .table = _table,                                        \
> +               .mux_shift = -1,                                        \
> +               .flags = _flags,                                        \
> +       }
> +
> +#define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift,         \
> +                       _mux_reg, _mux_shift, _flags) {                 \
> +               .id = _id,                                              \
> +               .parents = _parents,                                    \
> +               .num_parents = ARRAY_SIZE(_parents),                    \
> +               .name = _name,                                          \
> +               .gate_reg = _gate_reg,                                  \
> +               .gate_shift = _gate_shift,                              \
> +               .div_shift = -1,                                        \
> +               .mux_reg = _mux_reg,                                    \
> +               .mux_shift = _mux_shift,                                \
> +               .flags = _flags,                                        \
> +       }
> +
> +static const struct bm1880_pll_clock bm1880_pll_clks[] = {
> +       { BM1880_CLK_MPLL, "clk_mpll", "osc", BM1880_CLK_MPLL_CTL,
> +         CLK_IS_CRITICAL },
> +       { BM1880_CLK_SPLL, "clk_spll", "osc", BM1880_CLK_SPLL_CTL,
> +         CLK_IS_CRITICAL },
> +       { BM1880_CLK_FPLL, "clk_fpll", "osc", BM1880_CLK_FPLL_CTL,
> +         CLK_IS_CRITICAL },
> +       { BM1880_CLK_DDRPLL, "clk_ddrpll", "osc", BM1880_CLK_DDRPLL_CTL,
> +         CLK_IS_CRITICAL },
> +};
> +
> +static const struct bm1880_gate_clock bm1880_gate_clks[] = {
> +       { BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 2, CLK_IS_CRITICAL },
> +       { BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1",
> +         BM1880_CLK_ENABLE0, 3, CLK_IS_CRITICAL },
> +       { BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL },
> +       { BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 6, CLK_IS_CRITICAL },
> +       { BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5",
> +         BM1880_CLK_ENABLE0, 7, 0 },
> +       { BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5",
> +         BM1880_CLK_ENABLE0, 10, 0 },
> +       { BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4",
> +         BM1880_CLK_ENABLE0, 14, 0 },
> +       { BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4",
> +         BM1880_CLK_ENABLE0, 16, 0 },
> +       { BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1",
> +         BM1880_CLK_ENABLE0, 17, 0 },
> +       /* Don't gate GPIO clocks as it is not owned by the GPIO driver */
> +       { BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED },
> +       { BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED },
> +       { BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1",
> +         BM1880_CLK_ENABLE0, 21, 0 },
> +       { BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 22, 0 },
> +       { BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5",
> +         BM1880_CLK_ENABLE0, 23, 0 },
> +       { BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 25, 0 },
> +       { BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE0, 26, 0 },
> +       { BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6",
> +         BM1880_CLK_ENABLE0, 27, 0 },
> +       { BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5",
> +         BM1880_CLK_ENABLE0, 29, 0 },
> +       { BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6",
> +         BM1880_CLK_ENABLE0, 30, 0 },
> +       { BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE1, 0, 0 },
> +       { BM1880_CLK_RV, "clk_rv", "clk_mux_rv",
> +         BM1880_CLK_ENABLE1, 1, 0 },
> +       { BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE1, 2, 0 },
> +       { BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m",
> +         BM1880_CLK_ENABLE1, 4, 0 },
> +       { BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6",
> +         BM1880_CLK_ENABLE1, 5, 0 },
> +       { BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6",
> +         BM1880_CLK_ENABLE1, 6, 0 },
> +       { BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4",
> +         BM1880_CLK_ENABLE1, 7, 0 },
> +       { BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6",
> +         BM1880_CLK_ENABLE1, 8, 0 },
> +       { BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb",
> +         BM1880_CLK_ENABLE1, 11, 0 },
> +       { BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6",
> +         BM1880_CLK_ENABLE1, 12, 0 },
> +       { BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6",
> +         BM1880_CLK_ENABLE1, 15, 0 },
> +       { BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6",
> +         BM1880_CLK_ENABLE1, 21, CLK_IS_CRITICAL },
> +};
> +
> +static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" };
> +static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" };
> +static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" };
> +static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" };
> +
> +static const struct bm1880_mux_clock bm1880_mux_clks[] = {
> +       { BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2,
> +         BM1880_CLK_SELECT, 1, 0 },
> +       { BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2,
> +         BM1880_CLK_SELECT, 3, 0 },
> +};
> +
> +static struct clk_div_table bm1880_div_table_0[] = {

Can these tables be const?

> +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> +       { 0, 0 }
> +};
> +
> +static struct clk_div_table bm1880_div_table_1[] = {
> +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> +       { 127, 128 }, { 0, 0 }
> +};
> +
> +static struct clk_div_table bm1880_div_table_2[] = {
> +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> +       { 127, 128 }, { 255, 256 }, { 0, 0 }
> +};
> +
> +static struct clk_div_table bm1880_div_table_3[] = {
> +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> +       { 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 }
> +};
> +
> +static struct clk_div_table bm1880_div_table_4[] = {
> +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> +       { 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 },
> +       { 0, 0 }
> +};
> +
> +static const struct bm1880_div_clock bm1880_div_clks[] = {
> +       { BM1880_CLK_DIV_0_RV, "clk_div_0_rv", "clk_spll",
> +         BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
> +       { BM1880_CLK_DIV_1_RV, "clk_div_1_rv", "clk_fpll",
> +         BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
> +       { BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", "clk_fpll",
> +         BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0 },
> +       { BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", "clk_mpll",
> +         BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0, CLK_IS_CRITICAL },
> +       { BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", "clk_fpll",
> +         BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0, CLK_IS_CRITICAL },
> +       { BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", "clk_fpll",
> +         BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0, CLK_IS_CRITICAL },
> +       { BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", "clk_mpll",
> +         BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0, CLK_IS_CRITICAL },
> +       { BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", "clk_fpll",
> +         BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0 },
> +};
> +
> +static struct bm1880_composite_clock bm1880_composite_clks[] = {
> +       GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents,
> +                BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0,
> +                CLK_IS_CRITICAL),

Please document why CLK_IS_CRITICAL. Maybe CPU clk so must be kept on?

> +       GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30,
> +                bm1880_div_table_0, CLK_IS_CRITICAL),
> +       GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60,
> +                bm1880_div_table_1, 0),
> +       GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb",
> +                BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120,
> +                bm1880_div_table_2, 0),
> +       GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb",
> +                BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120,
> +                bm1880_div_table_2, 0),
> +       GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3,
> +                bm1880_div_table_0, 0),
> +       /* Don't gate GPIO clocks as it is not owned by the GPIO driver */
> +       GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb",
> +                BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120,
> +                bm1880_div_table_4, CLK_IGNORE_UNUSED),
> +       GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61,
> +                bm1880_div_table_1, 0),
> +       GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll",
> +                BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll",
> +                BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb",
> +                BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363,
> +                bm1880_div_table_3, 0),
> +       GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4,
> +                bm1880_div_table_0, 0),
> +       GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4,
> +                bm1880_div_table_0, 0),
> +       GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents,
> +                BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2,
> +                CLK_IS_CRITICAL),
> +       GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3,
> +                bm1880_div_table_0, CLK_IS_CRITICAL),
> +       GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv",
> +                BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2,
> +                bm1880_div_table_0, CLK_IS_CRITICAL),
> +       GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6,
> +                bm1880_div_table_0, CLK_IS_CRITICAL),
> +       GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll",
> +                BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15,
> +                bm1880_div_table_0, CLK_IS_CRITICAL),
> +};
> +
> +static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)
> +{
> +       u32 fbdiv, fref, refdiv;
> +       u32 postdiv1, postdiv2;
> +       unsigned long rate, numerator, denominator;
> +
> +       fbdiv = (regval >> 16) & 0xfff;
> +       fref = parent_rate;
> +       refdiv = regval & 0x1f;
> +       postdiv1 = (regval >> 8) & 0x7;
> +       postdiv2 = (regval >> 12) & 0x7;
> +
> +       numerator = parent_rate * fbdiv;
> +       denominator = refdiv * postdiv1 * postdiv2;
> +       do_div(numerator, denominator);
> +       rate = numerator;
> +
> +       return rate;
> +}
> +
> +static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw,
> +                                           unsigned long parent_rate)
> +{
> +       struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);
> +       unsigned long rate;
> +       u32 regval;
> +
> +       regval = readl(pll_hw->base + pll_hw->pll.reg);
> +       rate = bm1880_pll_rate_calc(regval, parent_rate);
> +
> +       return rate;
> +}
> +
> +static const struct clk_ops bm1880_pll_ops = {
> +       .recalc_rate    = bm1880_pll_recalc_rate,
> +};
> +
> +struct clk *bm1880_clk_register_pll(const struct bm1880_pll_clock *pll_clk,
> +                                   void __iomem *sys_base)
> +{
> +       struct bm1880_pll_hw_clock *pll_hw;
> +       struct clk_init_data init;
> +       struct clk_hw *hw;
> +       int err;
> +
> +       pll_hw = kzalloc(sizeof(*pll_hw), GFP_KERNEL);
> +       if (!pll_hw)
> +               return ERR_PTR(-ENOMEM);
> +
> +       init.name = pll_clk->name;
> +       init.ops = &bm1880_pll_ops;
> +       init.flags = pll_clk->flags;
> +       init.parent_names = &pll_clk->parent;

Can you use the new way of specifying parents instead of using strings
for everything?

> +       init.num_parents = 1;
> +
> +       pll_hw->hw.init = &init;
> +       pll_hw->pll.reg = pll_clk->reg;
> +       pll_hw->base = sys_base;
> +
> +       hw = &pll_hw->hw;
> +       err = clk_hw_register(NULL, hw);
> +
> +       if (err) {
> +               kfree(pll_hw);
> +               return ERR_PTR(err);
> +       }
> +
> +       return hw->clk;

Can this return the clk_hw pointer instead?

> +}
> +
> +void bm1880_clk_unregister_pll(struct clk *clk)

Should this be static?

> +{
> +       struct bm1880_pll_hw_clock *pll_hw;
> +       struct clk_hw *hw;
> +
> +       hw = __clk_get_hw(clk);
> +       if (!hw)
> +               return;
> +
> +       pll_hw = to_bm1880_pll_clk(hw);
> +
> +       clk_unregister(clk);
> +       kfree(pll_hw);
> +}
> +
> +int bm1880_clk_register_plls(const struct bm1880_pll_clock *clks,
> +                            int num_clks, struct bm1880_clock_data *data)
> +{
> +       struct clk *clk;
> +       void __iomem *pll_base = data->pll_base;
> +       int i;
> +
> +       for (i = 0; i < num_clks; i++) {
> +               const struct bm1880_pll_clock *bm1880_clk = &clks[i];
> +
> +               clk = bm1880_clk_register_pll(bm1880_clk, pll_base);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, bm1880_clk->name);
> +                       goto err_clk;
> +               }
> +
> +               data->clk_data.clks[clks[i].id] = clk;
> +       }
> +
> +       return 0;
> +
> +err_clk:
> +       while (i--)

I guess while (--i) is more idiomatic but this works too.

> +               bm1880_clk_unregister_pll(data->clk_data.clks[clks[i].id]);
> +
> +       return PTR_ERR(clk);
> +}
> +
> +int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,
> +                           int num_clks, struct bm1880_clock_data *data)
> +{
> +       struct clk *clk;
> +       void __iomem *sys_base = data->sys_base;
> +       int i;
> +
> +       for (i = 0; i < num_clks; i++) {
> +               clk = clk_register_mux(NULL, clks[i].name,

Can you use the clk_hw based APIs for generic type clks?

> +                                      clks[i].parents,
> +                                      clks[i].num_parents,
> +                                      clks[i].flags,
> +                                      sys_base + clks[i].reg,
> +                                      clks[i].shift, 1, 0,
> +                                      &bm1880_clk_lock);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       goto err_clk;
> +               }
> +
> +               data->clk_data.clks[clks[i].id] = clk;
> +       }
> +
> +       return 0;
> +
> +err_clk:
> +       while (i--)
> +               clk_unregister_gate(data->clk_data.clks[clks[i].id]);
> +
> +       return PTR_ERR(clk);
> +}
> +
> +static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,
> +                                               unsigned long parent_rate)
> +{
> +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> +       struct bm1880_div_clock *div = &div_hw->div;
> +       void __iomem *reg_addr = div_hw->base + div->reg;
> +       unsigned int val;
> +       unsigned long rate;
> +
> +       if (!(readl(reg_addr) & BIT(3))) {
> +               val = div->initval;
> +       } else {
> +               val = readl(reg_addr) >> div->shift;
> +               val &= clk_div_mask(div->width);
> +       }
> +
> +       rate = divider_recalc_rate(hw, parent_rate, val, div->table,
> +                                  div->flags, div->width);
> +
> +       return rate;
> +}
> +
> +static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> +                                     unsigned long *prate)
> +{
> +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> +       struct bm1880_div_clock *div = &div_hw->div;
> +       void __iomem *reg_addr = div_hw->base + div->reg;
> +
> +       if (div->flags & CLK_DIVIDER_READ_ONLY) {
> +               u32 val;
> +
> +               val = readl(reg_addr) >> div->shift;
> +               val &= clk_div_mask(div->width);
> +
> +               return divider_ro_round_rate(hw, rate, prate, div->table,
> +                                            div->width, div->flags,
> +                                            val);
> +       }
> +
> +       return divider_round_rate(hw, rate, prate, div->table,
> +                                 div->width, div->flags);
> +}
> +
> +static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> +                                  unsigned long parent_rate)
> +{
> +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> +       struct bm1880_div_clock *div = &div_hw->div;
> +       void __iomem *reg_addr = div_hw->base + div->reg;
> +       unsigned long flags = 0;
> +       int value;
> +       u32 val;
> +
> +       value = divider_get_val(rate, parent_rate, div->table,
> +                               div->width, div_hw->div.flags);
> +       if (value < 0)
> +               return value;
> +
> +       if (div_hw->lock)
> +               spin_lock_irqsave(div_hw->lock, flags);
> +       else
> +               __acquire(div_hw->lock);
> +
> +       if (div->flags & CLK_DIVIDER_HIWORD_MASK) {
> +               val = clk_div_mask(div->width) << (div_hw->div.shift + 16);
> +       } else {
> +               val = readl(reg_addr);
> +               val &= ~(clk_div_mask(div->width) << div_hw->div.shift);
> +       }
> +       val |= (u32)value << div->shift;
> +       writel(val, reg_addr);
> +
> +       if (div_hw->lock)
> +               spin_unlock_irqrestore(div_hw->lock, flags);
> +       else
> +               __release(div_hw->lock);
> +
> +       return 0;
> +}
> +
> +const struct clk_ops bm1880_clk_div_ops = {

static?

> +       .recalc_rate = bm1880_clk_div_recalc_rate,
> +       .round_rate = bm1880_clk_div_round_rate,
> +       .set_rate = bm1880_clk_div_set_rate,
> +};
> +
> +struct clk *bm1880_clk_register_div(const struct bm1880_div_clock *div_clk,
> +                                   void __iomem *sys_base)
> +{
> +       struct bm1880_div_hw_clock *div_hw;
> +       struct clk_init_data init;
> +       struct clk_hw *hw;
> +       int err;
> +
> +       div_hw = kzalloc(sizeof(*div_hw), GFP_KERNEL);
> +       if (!div_hw)
> +               return ERR_PTR(-ENOMEM);
> +
> +       init.name = div_clk->name;
> +       init.ops = &bm1880_clk_div_ops;
> +       init.flags = div_clk->flags;
> +       init.parent_names = &div_clk->parent;
> +       init.num_parents = 1;
> +
> +       div_hw->hw.init = &init;
> +       div_hw->div.reg = div_clk->reg;
> +       div_hw->div.shift = div_clk->shift;
> +       div_hw->div.width = div_clk->width;
> +       div_hw->div.initval = div_clk->initval;
> +       div_hw->div.table = div_clk->table;
> +       div_hw->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
> +       div_hw->base = sys_base;
> +       div_hw->lock = &bm1880_clk_lock;
> +
> +       hw = &div_hw->hw;
> +       err = clk_hw_register(NULL, hw);
> +
> +       if (err) {
> +               kfree(div_hw);
> +               return ERR_PTR(err);
> +       }
> +
> +       return hw->clk;
> +}
> +
> +void bm1880_clk_unregister_div(struct clk *clk)
> +{
> +       struct bm1880_div_hw_clock *div_hw;
> +       struct clk_hw *hw;
> +
> +       hw = __clk_get_hw(clk);
> +       if (!hw)
> +               return;
> +
> +       div_hw = to_bm1880_div_clk(hw);
> +
> +       clk_unregister(clk);
> +       kfree(div_hw);
> +}
> +
> +int bm1880_clk_register_divs(const struct bm1880_div_clock *clks,
> +                            int num_clks, struct bm1880_clock_data *data)
> +{
> +       struct clk *clk;
> +       void __iomem *sys_base = data->sys_base;
> +       int i;
> +
> +       for (i = 0; i < num_clks; i++) {
> +               const struct bm1880_div_clock *bm1880_clk = &clks[i];
> +
> +               clk = bm1880_clk_register_div(bm1880_clk, sys_base);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, bm1880_clk->name);
> +                       goto err_clk;
> +               }
> +
> +               data->clk_data.clks[clks[i].id] = clk;
> +       }
> +
> +       return 0;
> +
> +err_clk:
> +       while (i--)
> +               bm1880_clk_unregister_div(data->clk_data.clks[clks[i].id]);
> +
> +       return PTR_ERR(clk);
> +}
> +
> +int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks,
> +                            int num_clks, struct bm1880_clock_data *data)
> +{
> +       struct clk *clk;
> +       void __iomem *sys_base = data->sys_base;
> +       int i;
> +
> +       for (i = 0; i < num_clks; i++) {
> +               clk = clk_register_gate(NULL, clks[i].name,
> +                                       clks[i].parent,
> +                                       clks[i].flags,
> +                                       sys_base + clks[i].gate_reg,
> +                                       clks[i].gate_shift,
> +                                       0,
> +                                       &bm1880_clk_lock);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, clks[i].name);
> +                       goto err_clk;
> +               }
> +
> +               data->clk_data.clks[clks[i].id] = clk;
> +       }
> +
> +       return 0;
> +
> +err_clk:
> +       while (i--)
> +               clk_unregister_gate(data->clk_data.clks[clks[i].id]);
> +
> +       return PTR_ERR(clk);
> +}
> +
> +struct clk *bm1880_clk_register_composite(struct bm1880_composite_clock *clks,
> +                                         void __iomem *sys_base)
> +{
> +       struct clk *clk;
> +       struct clk_mux *mux = NULL;
> +       struct clk_gate *gate = NULL;
> +       struct bm1880_div_hw_clock *div_hws = NULL;
> +       struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
> +       const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
> +       const char * const *parent_names;
> +       const char *parent;
> +       int num_parents;
> +       int ret;
> +
> +       if (clks->mux_shift >= 0) {
> +               mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> +               if (!mux)
> +                       return ERR_PTR(-ENOMEM);
> +
> +               mux->reg = sys_base + clks->mux_reg;
> +               mux->mask = 1;
> +               mux->shift = clks->mux_shift;
> +               mux_hw = &mux->hw;
> +               mux_ops = &clk_mux_ops;
> +               mux->lock = &bm1880_clk_lock;
> +
> +               parent_names = clks->parents;
> +               num_parents = clks->num_parents;
> +       } else {
> +               parent = clks->parent;
> +               parent_names = &parent;
> +               num_parents = 1;
> +       }
> +
> +       if (clks->gate_shift >= 0) {
> +               gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> +               if (!gate) {
> +                       ret = -ENOMEM;
> +                       goto err_out;
> +               }
> +
> +               gate->reg = sys_base + clks->gate_reg;
> +               gate->bit_idx = clks->gate_shift;
> +               gate->lock = &bm1880_clk_lock;
> +
> +               gate_hw = &gate->hw;
> +               gate_ops = &clk_gate_ops;
> +       }
> +
> +       if (clks->div_shift >= 0) {
> +               div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL);
> +               if (!div_hws) {
> +                       ret = -ENOMEM;
> +                       goto err_out;
> +               }
> +
> +               div_hws->base = sys_base;
> +               div_hws->div.reg = clks->div_reg;
> +               div_hws->div.shift = clks->div_shift;
> +               div_hws->div.width = clks->div_width;
> +               div_hws->div.table = clks->table;
> +               div_hws->div.initval = clks->div_initval;
> +               div_hws->lock = &bm1880_clk_lock;
> +               div_hws->div.flags = CLK_DIVIDER_ONE_BASED |
> +                                    CLK_DIVIDER_ALLOW_ZERO;
> +
> +               div_hw = &div_hws->hw;
> +               div_ops = &bm1880_clk_div_ops;
> +       }
> +
> +       clk = clk_register_composite(NULL, clks->name, parent_names,
> +                                    num_parents, mux_hw, mux_ops, div_hw,
> +                                    div_ops, gate_hw, gate_ops, (clks->flags));
> +
> +       if (IS_ERR(clk)) {
> +               ret = PTR_ERR(clk);
> +               goto err_out;
> +       }
> +
> +       return clk;
> +
> +err_out:
> +       kfree(div_hws);
> +       kfree(gate);
> +       kfree(mux);
> +
> +       return ERR_PTR(ret);
> +}
> +
> +int bm1880_clk_register_composites(struct bm1880_composite_clock *clks,
> +                                  int num_clks, struct bm1880_clock_data *data)
> +{
> +       struct clk *clk;
> +       void __iomem *sys_base = data->sys_base;
> +       int i;
> +
> +       for (i = 0; i < num_clks; i++) {
> +               struct bm1880_composite_clock *bm1880_clk = &clks[i];
> +
> +               clk = bm1880_clk_register_composite(bm1880_clk, sys_base);
> +               if (IS_ERR(clk)) {
> +                       pr_err("%s: failed to register clock %s\n",
> +                              __func__, bm1880_clk->name);
> +                       goto err_clk;
> +               }
> +
> +               data->clk_data.clks[clks[i].id] = clk;
> +       }
> +
> +       return 0;
> +
> +err_clk:
> +       while (i--)
> +               clk_unregister_composite(data->clk_data.clks[clks[i].id]);
> +
> +       return PTR_ERR(clk);
> +}
> +
> +static void bm1880_clk_init(struct device_node *np)
> +{
> +       struct bm1880_clock_data *clk_data;
> +       struct clk **clk_table;
> +       void __iomem *pll_base, *sys_base;
> +       int num_clks;
> +
> +       pll_base = of_iomap(np, 0);
> +       if (!pll_base) {
> +               pr_err("%pOFn: unable to map pll resource", np);
> +               of_node_put(np);
> +               return;
> +       }
> +
> +       sys_base = of_iomap(np, 1);
> +       if (!sys_base) {
> +               pr_err("%pOFn: unable to map sys resource", np);
> +               of_node_put(np);
> +               return;
> +       }
> +
> +       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
> +       if (!clk_data)
> +               return;
> +
> +       clk_data->pll_base = pll_base;
> +       clk_data->sys_base = sys_base;
> +       num_clks = ARRAY_SIZE(bm1880_gate_clks) +
> +                  ARRAY_SIZE(bm1880_composite_clks);
> +
> +       clk_table = kcalloc(num_clks, sizeof(*clk_table), GFP_KERNEL);
> +       if (!clk_table)
> +               goto err_out;
> +
> +       clk_data->clk_data.clks = clk_table;
> +       clk_data->clk_data.clk_num = num_clks;
> +
> +       /* Register PLL clocks */
> +       bm1880_clk_register_plls(bm1880_pll_clks,
> +                                ARRAY_SIZE(bm1880_pll_clks),
> +                                clk_data);
> +
> +       /* Register Divider clocks */

Please remove these comments, they provide no useful information.

> +       bm1880_clk_register_divs(bm1880_div_clks,
> +                                ARRAY_SIZE(bm1880_div_clks),
> +                                clk_data);
> +
> +       /* Register Mux clocks */
> +       bm1880_clk_register_mux(bm1880_mux_clks,
> +                               ARRAY_SIZE(bm1880_mux_clks),
> +                               clk_data);
> +
> +       /* Register Composite clocks */
> +       bm1880_clk_register_composites(bm1880_composite_clks,
> +                                      ARRAY_SIZE(bm1880_composite_clks),
> +                                      clk_data);
> +
> +       /* Register Gate clocks */
> +       bm1880_clk_register_gate(bm1880_gate_clks,
> +                                ARRAY_SIZE(bm1880_gate_clks),
> +                                clk_data);
> +
> +       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
> +
> +       return;
> +
> +err_out:
> +       kfree(clk_data);
> +}
> +
> +CLK_OF_DECLARE_DRIVER(bm1880_clk, "bitmain,bm1880-clk", bm1880_clk_init);

Is there a reason why it can't be a platform driver?


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-08-08  5:01   ` Stephen Boyd
@ 2019-08-17  3:34     ` Manivannan Sadhasivam
  2019-08-17  3:46       ` Stephen Boyd
  0 siblings, 1 reply; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-08-17  3:34 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

Hi Stephen,

On Wed, Aug 07, 2019 at 10:01:28PM -0700, Stephen Boyd wrote:
> Quoting Manivannan Sadhasivam (2019-07-05 08:14:36)
> > Add devicetree binding for Bitmain BM1880 SoC clock controller.
> > 
> > Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > ---
> >  .../bindings/clock/bitmain,bm1880-clk.txt     | 47 +++++++++++
> 
> Can you convert this to YAML? It's all the rage right now.
> 

Sure.

> >  include/dt-bindings/clock/bm1880-clock.h      | 82 +++++++++++++++++++
> >  2 files changed, 129 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> >  create mode 100644 include/dt-bindings/clock/bm1880-clock.h
> > 
> > diff --git a/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> > new file mode 100644
> > index 000000000000..9c967095d430
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/clock/bitmain,bm1880-clk.txt
> > @@ -0,0 +1,47 @@
> > +* Bitmain BM1880 Clock Controller
> > +
> > +The Bitmain BM1880 clock controler generates and supplies clock to
> > +various peripherals within the SoC.
> > +
> > +Required Properties:
> > +
> > +- compatible: Should be "bitmain,bm1880-clk"
> > +- reg :        Register address and size of PLL and SYS control domains
> > +- reg-names : Register domain names: "pll" and "sys"
> > +- clocks : Phandle of the input reference clock.
> > +- #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 corresponding
> > +dt-bindings/clock/bm1880-clock.h header and can be used in device tree sources.
> > +
> > +External clocks:
> > +
> > +The osc clock used as the input for the plls is generated outside the SoC.
> > +It is expected that it is defined using standard clock bindings as "osc".
> > +
> > +Example: 
> > +
> > +        clk: clock-controller@800 {
> > +                compatible = "bitmain,bm1880-clk";
> > +                reg = <0xe8 0x0c>,<0x800 0xb0>;
> 
> It looks weird still. What hardware module is this actually part of?
> Some larger power manager block?
> 

These are all part of the sysctrl block (clock + pinctrl + reset) and the
register domains got split between system and pll.

Thanks,
Mani

> > +                reg-names = "pll", "sys";
> > +                clocks = <&osc>;
> > +                #clock-cells = <1>;
> > +        };
> > +

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-08-17  3:34     ` Manivannan Sadhasivam
@ 2019-08-17  3:46       ` Stephen Boyd
  2019-08-17  3:58         ` Manivannan Sadhasivam
  0 siblings, 1 reply; 16+ messages in thread
From: Stephen Boyd @ 2019-08-17  3:46 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

Quoting Manivannan Sadhasivam (2019-08-16 20:34:22)
> On Wed, Aug 07, 2019 at 10:01:28PM -0700, Stephen Boyd wrote:
> > Quoting Manivannan Sadhasivam (2019-07-05 08:14:36)
> > > +It is expected that it is defined using standard clock bindings as "osc".
> > > +
> > > +Example: 
> > > +
> > > +        clk: clock-controller@800 {
> > > +                compatible = "bitmain,bm1880-clk";
> > > +                reg = <0xe8 0x0c>,<0x800 0xb0>;
> > 
> > It looks weird still. What hardware module is this actually part of?
> > Some larger power manager block?
> > 
> 
> These are all part of the sysctrl block (clock + pinctrl + reset) and the
> register domains got split between system and pll.
> 

And that can't be one node that probes the clk, pinctrl, and reset
drivers from C code?


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller
  2019-08-08  5:15   ` Stephen Boyd
@ 2019-08-17  3:55     ` Manivannan Sadhasivam
  2019-08-18  1:21       ` Stephen Boyd
  0 siblings, 1 reply; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-08-17  3:55 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

Hi Stephen,

On Wed, Aug 07, 2019 at 10:15:59PM -0700, Stephen Boyd wrote:
> Quoting Manivannan Sadhasivam (2019-07-05 08:14:39)
> > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> > index fc1e0cf44995..ffc61ed85ade 100644
> > --- a/drivers/clk/Kconfig
> > +++ b/drivers/clk/Kconfig
> > @@ -304,6 +304,12 @@ config COMMON_CLK_FIXED_MMIO
> >         help
> >           Support for Memory Mapped IO Fixed clocks
> >  
> > +config COMMON_CLK_BM1880
> > +       bool "Clock driver for Bitmain BM1880 SoC"
> > +       depends on ARCH_BITMAIN || COMPILE_TEST
> > +       help
> > +         This driver supports the clocks on Bitmain BM1880 SoC.
> 
> Can you add this config somewhere else besides the end? Preferably
> close to alphabetically in this file.
> 

Okay. I got confused by the fact that Makefile is sorted but not the
Kconfig.

> > +
> >  source "drivers/clk/actions/Kconfig"
> >  source "drivers/clk/analogbits/Kconfig"
> >  source "drivers/clk/bcm/Kconfig"
> > diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c
> > new file mode 100644
> > index 000000000000..26cdb75bb936
> > --- /dev/null
> > +++ b/drivers/clk/clk-bm1880.c
> > @@ -0,0 +1,947 @@
> > +// SPDX-License-Identifier: GPL-2.0+
> > +/*
> > + * Bitmain BM1880 SoC clock driver
> > + *
> > + * Copyright (c) 2019 Linaro Ltd.
> > + * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
> > + */
> > +
> > +#include <linux/clk-provider.h>
> > +#include <linux/of_address.h>
> > +#include <linux/slab.h>
> 
> Should probably add kernel.h for at least container_of()
> 

okay.

> > +
> > +#include <dt-bindings/clock/bm1880-clock.h>
> > +
> > +#define BM1880_CLK_MPLL_CTL    0x00
> > +#define BM1880_CLK_SPLL_CTL    0x04
> > +#define BM1880_CLK_FPLL_CTL    0x08
> > +#define BM1880_CLK_DDRPLL_CTL  0x0c
> > +
> > +#define BM1880_CLK_ENABLE0     0x00
> > +#define BM1880_CLK_ENABLE1     0x04
> > +#define BM1880_CLK_SELECT      0x20
> > +#define BM1880_CLK_DIV0                0x40
> > +#define BM1880_CLK_DIV1                0x44
> > +#define BM1880_CLK_DIV2                0x48
> > +#define BM1880_CLK_DIV3                0x4c
> > +#define BM1880_CLK_DIV4                0x50
> > +#define BM1880_CLK_DIV5                0x54
> > +#define BM1880_CLK_DIV6                0x58
> > +#define BM1880_CLK_DIV7                0x5c
> > +#define BM1880_CLK_DIV8                0x60
> > +#define BM1880_CLK_DIV9                0x64
> > +#define BM1880_CLK_DIV10       0x68
> > +#define BM1880_CLK_DIV11       0x6c
> > +#define BM1880_CLK_DIV12       0x70
> > +#define BM1880_CLK_DIV13       0x74
> > +#define BM1880_CLK_DIV14       0x78
> > +#define BM1880_CLK_DIV15       0x7c
> > +#define BM1880_CLK_DIV16       0x80
> > +#define BM1880_CLK_DIV17       0x84
> > +#define BM1880_CLK_DIV18       0x88
> > +#define BM1880_CLK_DIV19       0x8c
> > +#define BM1880_CLK_DIV20       0x90
> > +#define BM1880_CLK_DIV21       0x94
> > +#define BM1880_CLK_DIV22       0x98
> > +#define BM1880_CLK_DIV23       0x9c
> > +#define BM1880_CLK_DIV24       0xa0
> > +#define BM1880_CLK_DIV25       0xa4
> > +#define BM1880_CLK_DIV26       0xa8
> > +#define BM1880_CLK_DIV27       0xac
> > +#define BM1880_CLK_DIV28       0xb0
> > +
> > +#define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw)
> > +#define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw)
> > +
> > +static DEFINE_SPINLOCK(bm1880_clk_lock);
> > +
> > +struct bm1880_clock_data {
> > +       void __iomem *pll_base;
> > +       void __iomem *sys_base;
> > +       struct clk_onecell_data clk_data;
> > +};
> > +
> > +struct bm1880_gate_clock {
> > +       unsigned int    id;
> > +       const char      *name;
> > +       const char      *parent;
> > +       u32             gate_reg;
> > +       s8              gate_shift;
> > +       unsigned long   flags;
> > +};
> > +
> > +struct bm1880_mux_clock {
> > +       unsigned int    id;
> > +       const char      *name;
> > +       const char      * const * parents;
> > +       s8              num_parents;
> > +       u32             reg;
> > +       s8              shift;
> > +       unsigned long   flags;
> > +};
> > +
> > +struct bm1880_div_clock {
> > +       unsigned int    id;
> > +       const char      *name;
> > +       const char      *parent;
> > +       u32             reg;
> > +       u8              shift;
> > +       u8              width;
> > +       u32             initval;
> > +       struct clk_div_table *table;
> > +       unsigned long   flags;
> > +};
> > +
> > +struct bm1880_div_hw_clock {
> > +       struct bm1880_div_clock div;
> > +       void __iomem *base;
> > +       spinlock_t *lock;
> > +       struct clk_hw hw;
> > +};
> > +
> > +struct bm1880_composite_clock {
> > +       unsigned int    id;
> > +       const char      *name;
> > +       const char      *parent;
> > +       const char      * const * parents;
> > +       unsigned int    num_parents;
> > +       unsigned long   flags;
> > +
> > +       u32             gate_reg;
> > +       u32             mux_reg;
> > +       u32             div_reg;
> > +
> > +       s8              gate_shift;
> > +       s8              mux_shift;
> > +       s8              div_shift;
> > +       s8              div_width;
> > +       s16             div_initval;
> > +       struct clk_div_table *table;
> > +};
> > +
> > +struct bm1880_pll_clock {
> > +       unsigned int    id;
> > +       const char      *name;
> > +       const char      *parent;
> > +       u32             reg;
> > +       unsigned long   flags;
> > +};
> > +
> > +struct bm1880_pll_hw_clock {
> > +       struct bm1880_pll_clock pll;
> > +       void __iomem *base;
> > +       struct clk_hw hw;
> > +};
> > +
> > +#define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,        \
> > +                       _div_shift, _div_width, _div_initval, _table,   \
> > +                       _flags) {                                       \
> > +               .id = _id,                                              \
> > +               .parent = _parent,                                      \
> > +               .name = _name,                                          \
> > +               .gate_reg = _gate_reg,                                  \
> > +               .gate_shift = _gate_shift,                              \
> > +               .div_reg = _div_reg,                                    \
> > +               .div_shift = _div_shift,                                \
> > +               .div_width = _div_width,                                \
> > +               .div_initval = _div_initval,                            \
> > +               .table = _table,                                        \
> > +               .mux_shift = -1,                                        \
> > +               .flags = _flags,                                        \
> > +       }
> > +
> > +#define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift,         \
> > +                       _mux_reg, _mux_shift, _flags) {                 \
> > +               .id = _id,                                              \
> > +               .parents = _parents,                                    \
> > +               .num_parents = ARRAY_SIZE(_parents),                    \
> > +               .name = _name,                                          \
> > +               .gate_reg = _gate_reg,                                  \
> > +               .gate_shift = _gate_shift,                              \
> > +               .div_shift = -1,                                        \
> > +               .mux_reg = _mux_reg,                                    \
> > +               .mux_shift = _mux_shift,                                \
> > +               .flags = _flags,                                        \
> > +       }
> > +
> > +static const struct bm1880_pll_clock bm1880_pll_clks[] = {
> > +       { BM1880_CLK_MPLL, "clk_mpll", "osc", BM1880_CLK_MPLL_CTL,
> > +         CLK_IS_CRITICAL },
> > +       { BM1880_CLK_SPLL, "clk_spll", "osc", BM1880_CLK_SPLL_CTL,
> > +         CLK_IS_CRITICAL },
> > +       { BM1880_CLK_FPLL, "clk_fpll", "osc", BM1880_CLK_FPLL_CTL,
> > +         CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DDRPLL, "clk_ddrpll", "osc", BM1880_CLK_DDRPLL_CTL,
> > +         CLK_IS_CRITICAL },
> > +};
> > +
> > +static const struct bm1880_gate_clock bm1880_gate_clks[] = {
> > +       { BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 2, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1",
> > +         BM1880_CLK_ENABLE0, 3, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 6, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5",
> > +         BM1880_CLK_ENABLE0, 7, 0 },
> > +       { BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5",
> > +         BM1880_CLK_ENABLE0, 10, 0 },
> > +       { BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4",
> > +         BM1880_CLK_ENABLE0, 14, 0 },
> > +       { BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4",
> > +         BM1880_CLK_ENABLE0, 16, 0 },
> > +       { BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1",
> > +         BM1880_CLK_ENABLE0, 17, 0 },
> > +       /* Don't gate GPIO clocks as it is not owned by the GPIO driver */
> > +       { BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED },
> > +       { BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED },
> > +       { BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1",
> > +         BM1880_CLK_ENABLE0, 21, 0 },
> > +       { BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 22, 0 },
> > +       { BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5",
> > +         BM1880_CLK_ENABLE0, 23, 0 },
> > +       { BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 25, 0 },
> > +       { BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE0, 26, 0 },
> > +       { BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6",
> > +         BM1880_CLK_ENABLE0, 27, 0 },
> > +       { BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5",
> > +         BM1880_CLK_ENABLE0, 29, 0 },
> > +       { BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6",
> > +         BM1880_CLK_ENABLE0, 30, 0 },
> > +       { BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE1, 0, 0 },
> > +       { BM1880_CLK_RV, "clk_rv", "clk_mux_rv",
> > +         BM1880_CLK_ENABLE1, 1, 0 },
> > +       { BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE1, 2, 0 },
> > +       { BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m",
> > +         BM1880_CLK_ENABLE1, 4, 0 },
> > +       { BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6",
> > +         BM1880_CLK_ENABLE1, 5, 0 },
> > +       { BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6",
> > +         BM1880_CLK_ENABLE1, 6, 0 },
> > +       { BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4",
> > +         BM1880_CLK_ENABLE1, 7, 0 },
> > +       { BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6",
> > +         BM1880_CLK_ENABLE1, 8, 0 },
> > +       { BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb",
> > +         BM1880_CLK_ENABLE1, 11, 0 },
> > +       { BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6",
> > +         BM1880_CLK_ENABLE1, 12, 0 },
> > +       { BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6",
> > +         BM1880_CLK_ENABLE1, 15, 0 },
> > +       { BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6",
> > +         BM1880_CLK_ENABLE1, 21, CLK_IS_CRITICAL },
> > +};
> > +
> > +static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" };
> > +static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" };
> > +static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" };
> > +static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" };
> > +
> > +static const struct bm1880_mux_clock bm1880_mux_clks[] = {
> > +       { BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2,
> > +         BM1880_CLK_SELECT, 1, 0 },
> > +       { BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2,
> > +         BM1880_CLK_SELECT, 3, 0 },
> > +};
> > +
> > +static struct clk_div_table bm1880_div_table_0[] = {
> 
> Can these tables be const?
> 

Ack.

> > +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> > +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> > +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> > +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> > +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> > +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> > +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> > +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> > +       { 0, 0 }
> > +};
> > +
> > +static struct clk_div_table bm1880_div_table_1[] = {
> > +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> > +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> > +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> > +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> > +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> > +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> > +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> > +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> > +       { 127, 128 }, { 0, 0 }
> > +};
> > +
> > +static struct clk_div_table bm1880_div_table_2[] = {
> > +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> > +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> > +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> > +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> > +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> > +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> > +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> > +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> > +       { 127, 128 }, { 255, 256 }, { 0, 0 }
> > +};
> > +
> > +static struct clk_div_table bm1880_div_table_3[] = {
> > +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> > +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> > +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> > +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> > +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> > +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> > +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> > +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> > +       { 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 }
> > +};
> > +
> > +static struct clk_div_table bm1880_div_table_4[] = {
> > +       { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
> > +       { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
> > +       { 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
> > +       { 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
> > +       { 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
> > +       { 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
> > +       { 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
> > +       { 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
> > +       { 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 },
> > +       { 0, 0 }
> > +};
> > +
> > +static const struct bm1880_div_clock bm1880_div_clks[] = {
> > +       { BM1880_CLK_DIV_0_RV, "clk_div_0_rv", "clk_spll",
> > +         BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
> > +       { BM1880_CLK_DIV_1_RV, "clk_div_1_rv", "clk_fpll",
> > +         BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, CLK_IGNORE_UNUSED },
> > +       { BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", "clk_fpll",
> > +         BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0 },
> > +       { BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", "clk_mpll",
> > +         BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", "clk_fpll",
> > +         BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", "clk_fpll",
> > +         BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", "clk_mpll",
> > +         BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0, CLK_IS_CRITICAL },
> > +       { BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", "clk_fpll",
> > +         BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0 },
> > +};
> > +
> > +static struct bm1880_composite_clock bm1880_composite_clks[] = {
> > +       GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents,
> > +                BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0,
> > +                CLK_IS_CRITICAL),
> 
> Please document why CLK_IS_CRITICAL. Maybe CPU clk so must be kept on?
> 

Yeah, will add comments for all critical clocks.

> > +       GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30,
> > +                bm1880_div_table_0, CLK_IS_CRITICAL),
> > +       GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60,
> > +                bm1880_div_table_1, 0),
> > +       GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb",
> > +                BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120,
> > +                bm1880_div_table_2, 0),
> > +       GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb",
> > +                BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120,
> > +                bm1880_div_table_2, 0),
> > +       GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3,
> > +                bm1880_div_table_0, 0),
> > +       /* Don't gate GPIO clocks as it is not owned by the GPIO driver */
> > +       GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb",
> > +                BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120,
> > +                bm1880_div_table_4, CLK_IGNORE_UNUSED),
> > +       GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61,
> > +                bm1880_div_table_1, 0),
> > +       GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll",
> > +                BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll",
> > +                BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb",
> > +                BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363,
> > +                bm1880_div_table_3, 0),
> > +       GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4,
> > +                bm1880_div_table_0, 0),
> > +       GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4,
> > +                bm1880_div_table_0, 0),
> > +       GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents,
> > +                BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2,
> > +                CLK_IS_CRITICAL),
> > +       GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3,
> > +                bm1880_div_table_0, CLK_IS_CRITICAL),
> > +       GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv",
> > +                BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2,
> > +                bm1880_div_table_0, CLK_IS_CRITICAL),
> > +       GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6,
> > +                bm1880_div_table_0, CLK_IS_CRITICAL),
> > +       GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll",
> > +                BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15,
> > +                bm1880_div_table_0, CLK_IS_CRITICAL),
> > +};
> > +
> > +static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)
> > +{
> > +       u32 fbdiv, fref, refdiv;
> > +       u32 postdiv1, postdiv2;
> > +       unsigned long rate, numerator, denominator;
> > +
> > +       fbdiv = (regval >> 16) & 0xfff;
> > +       fref = parent_rate;
> > +       refdiv = regval & 0x1f;
> > +       postdiv1 = (regval >> 8) & 0x7;
> > +       postdiv2 = (regval >> 12) & 0x7;
> > +
> > +       numerator = parent_rate * fbdiv;
> > +       denominator = refdiv * postdiv1 * postdiv2;
> > +       do_div(numerator, denominator);
> > +       rate = numerator;
> > +
> > +       return rate;
> > +}
> > +
> > +static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw,
> > +                                           unsigned long parent_rate)
> > +{
> > +       struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);
> > +       unsigned long rate;
> > +       u32 regval;
> > +
> > +       regval = readl(pll_hw->base + pll_hw->pll.reg);
> > +       rate = bm1880_pll_rate_calc(regval, parent_rate);
> > +
> > +       return rate;
> > +}
> > +
> > +static const struct clk_ops bm1880_pll_ops = {
> > +       .recalc_rate    = bm1880_pll_recalc_rate,
> > +};
> > +
> > +struct clk *bm1880_clk_register_pll(const struct bm1880_pll_clock *pll_clk,
> > +                                   void __iomem *sys_base)
> > +{
> > +       struct bm1880_pll_hw_clock *pll_hw;
> > +       struct clk_init_data init;
> > +       struct clk_hw *hw;
> > +       int err;
> > +
> > +       pll_hw = kzalloc(sizeof(*pll_hw), GFP_KERNEL);
> > +       if (!pll_hw)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       init.name = pll_clk->name;
> > +       init.ops = &bm1880_pll_ops;
> > +       init.flags = pll_clk->flags;
> > +       init.parent_names = &pll_clk->parent;
> 
> Can you use the new way of specifying parents instead of using strings
> for everything?
> 

Sure, will do it for clocks which doesn't use helper APIs.

> > +       init.num_parents = 1;
> > +
> > +       pll_hw->hw.init = &init;
> > +       pll_hw->pll.reg = pll_clk->reg;
> > +       pll_hw->base = sys_base;
> > +
> > +       hw = &pll_hw->hw;
> > +       err = clk_hw_register(NULL, hw);
> > +
> > +       if (err) {
> > +               kfree(pll_hw);
> > +               return ERR_PTR(err);
> > +       }
> > +
> > +       return hw->clk;
> 
> Can this return the clk_hw pointer instead?
> 

What is the benefit? I see that only hw:init is going to be NULL in future.
So, I'll keep it as it is.

> > +}
> > +
> > +void bm1880_clk_unregister_pll(struct clk *clk)
> 
> Should this be static?
> 

Ack.

> > +{
> > +       struct bm1880_pll_hw_clock *pll_hw;
> > +       struct clk_hw *hw;
> > +
> > +       hw = __clk_get_hw(clk);
> > +       if (!hw)
> > +               return;
> > +
> > +       pll_hw = to_bm1880_pll_clk(hw);
> > +
> > +       clk_unregister(clk);
> > +       kfree(pll_hw);
> > +}
> > +
> > +int bm1880_clk_register_plls(const struct bm1880_pll_clock *clks,
> > +                            int num_clks, struct bm1880_clock_data *data)
> > +{
> > +       struct clk *clk;
> > +       void __iomem *pll_base = data->pll_base;
> > +       int i;
> > +
> > +       for (i = 0; i < num_clks; i++) {
> > +               const struct bm1880_pll_clock *bm1880_clk = &clks[i];
> > +
> > +               clk = bm1880_clk_register_pll(bm1880_clk, pll_base);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, bm1880_clk->name);
> > +                       goto err_clk;
> > +               }
> > +
> > +               data->clk_data.clks[clks[i].id] = clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_clk:
> > +       while (i--)
> 
> I guess while (--i) is more idiomatic but this works too.
> 
> > +               bm1880_clk_unregister_pll(data->clk_data.clks[clks[i].id]);
> > +
> > +       return PTR_ERR(clk);
> > +}
> > +
> > +int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,
> > +                           int num_clks, struct bm1880_clock_data *data)
> > +{
> > +       struct clk *clk;
> > +       void __iomem *sys_base = data->sys_base;
> > +       int i;
> > +
> > +       for (i = 0; i < num_clks; i++) {
> > +               clk = clk_register_mux(NULL, clks[i].name,
> 
> Can you use the clk_hw based APIs for generic type clks?
> 

IMO using helper APIs greatly reduce code size and makes the driver
look more clean. So I prefer to use the helpers wherever applicable.
When you plan to deprecate those, I'll switch over to plain clk_hw APIs.

> > +                                      clks[i].parents,
> > +                                      clks[i].num_parents,
> > +                                      clks[i].flags,
> > +                                      sys_base + clks[i].reg,
> > +                                      clks[i].shift, 1, 0,
> > +                                      &bm1880_clk_lock);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       goto err_clk;
> > +               }
> > +
> > +               data->clk_data.clks[clks[i].id] = clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_clk:
> > +       while (i--)
> > +               clk_unregister_gate(data->clk_data.clks[clks[i].id]);
> > +
> > +       return PTR_ERR(clk);
> > +}
> > +
> > +static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,
> > +                                               unsigned long parent_rate)
> > +{
> > +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> > +       struct bm1880_div_clock *div = &div_hw->div;
> > +       void __iomem *reg_addr = div_hw->base + div->reg;
> > +       unsigned int val;
> > +       unsigned long rate;
> > +
> > +       if (!(readl(reg_addr) & BIT(3))) {
> > +               val = div->initval;
> > +       } else {
> > +               val = readl(reg_addr) >> div->shift;
> > +               val &= clk_div_mask(div->width);
> > +       }
> > +
> > +       rate = divider_recalc_rate(hw, parent_rate, val, div->table,
> > +                                  div->flags, div->width);
> > +
> > +       return rate;
> > +}
> > +
> > +static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
> > +                                     unsigned long *prate)
> > +{
> > +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> > +       struct bm1880_div_clock *div = &div_hw->div;
> > +       void __iomem *reg_addr = div_hw->base + div->reg;
> > +
> > +       if (div->flags & CLK_DIVIDER_READ_ONLY) {
> > +               u32 val;
> > +
> > +               val = readl(reg_addr) >> div->shift;
> > +               val &= clk_div_mask(div->width);
> > +
> > +               return divider_ro_round_rate(hw, rate, prate, div->table,
> > +                                            div->width, div->flags,
> > +                                            val);
> > +       }
> > +
> > +       return divider_round_rate(hw, rate, prate, div->table,
> > +                                 div->width, div->flags);
> > +}
> > +
> > +static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
> > +                                  unsigned long parent_rate)
> > +{
> > +       struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
> > +       struct bm1880_div_clock *div = &div_hw->div;
> > +       void __iomem *reg_addr = div_hw->base + div->reg;
> > +       unsigned long flags = 0;
> > +       int value;
> > +       u32 val;
> > +
> > +       value = divider_get_val(rate, parent_rate, div->table,
> > +                               div->width, div_hw->div.flags);
> > +       if (value < 0)
> > +               return value;
> > +
> > +       if (div_hw->lock)
> > +               spin_lock_irqsave(div_hw->lock, flags);
> > +       else
> > +               __acquire(div_hw->lock);
> > +
> > +       if (div->flags & CLK_DIVIDER_HIWORD_MASK) {
> > +               val = clk_div_mask(div->width) << (div_hw->div.shift + 16);
> > +       } else {
> > +               val = readl(reg_addr);
> > +               val &= ~(clk_div_mask(div->width) << div_hw->div.shift);
> > +       }
> > +       val |= (u32)value << div->shift;
> > +       writel(val, reg_addr);
> > +
> > +       if (div_hw->lock)
> > +               spin_unlock_irqrestore(div_hw->lock, flags);
> > +       else
> > +               __release(div_hw->lock);
> > +
> > +       return 0;
> > +}
> > +
> > +const struct clk_ops bm1880_clk_div_ops = {
> 
> static?
> 

Ack.

> > +       .recalc_rate = bm1880_clk_div_recalc_rate,
> > +       .round_rate = bm1880_clk_div_round_rate,
> > +       .set_rate = bm1880_clk_div_set_rate,
> > +};
> > +
> > +struct clk *bm1880_clk_register_div(const struct bm1880_div_clock *div_clk,
> > +                                   void __iomem *sys_base)
> > +{
> > +       struct bm1880_div_hw_clock *div_hw;
> > +       struct clk_init_data init;
> > +       struct clk_hw *hw;
> > +       int err;
> > +
> > +       div_hw = kzalloc(sizeof(*div_hw), GFP_KERNEL);
> > +       if (!div_hw)
> > +               return ERR_PTR(-ENOMEM);
> > +
> > +       init.name = div_clk->name;
> > +       init.ops = &bm1880_clk_div_ops;
> > +       init.flags = div_clk->flags;
> > +       init.parent_names = &div_clk->parent;
> > +       init.num_parents = 1;
> > +
> > +       div_hw->hw.init = &init;
> > +       div_hw->div.reg = div_clk->reg;
> > +       div_hw->div.shift = div_clk->shift;
> > +       div_hw->div.width = div_clk->width;
> > +       div_hw->div.initval = div_clk->initval;
> > +       div_hw->div.table = div_clk->table;
> > +       div_hw->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
> > +       div_hw->base = sys_base;
> > +       div_hw->lock = &bm1880_clk_lock;
> > +
> > +       hw = &div_hw->hw;
> > +       err = clk_hw_register(NULL, hw);
> > +
> > +       if (err) {
> > +               kfree(div_hw);
> > +               return ERR_PTR(err);
> > +       }
> > +
> > +       return hw->clk;
> > +}
> > +
> > +void bm1880_clk_unregister_div(struct clk *clk)
> > +{
> > +       struct bm1880_div_hw_clock *div_hw;
> > +       struct clk_hw *hw;
> > +
> > +       hw = __clk_get_hw(clk);
> > +       if (!hw)
> > +               return;
> > +
> > +       div_hw = to_bm1880_div_clk(hw);
> > +
> > +       clk_unregister(clk);
> > +       kfree(div_hw);
> > +}
> > +
> > +int bm1880_clk_register_divs(const struct bm1880_div_clock *clks,
> > +                            int num_clks, struct bm1880_clock_data *data)
> > +{
> > +       struct clk *clk;
> > +       void __iomem *sys_base = data->sys_base;
> > +       int i;
> > +
> > +       for (i = 0; i < num_clks; i++) {
> > +               const struct bm1880_div_clock *bm1880_clk = &clks[i];
> > +
> > +               clk = bm1880_clk_register_div(bm1880_clk, sys_base);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, bm1880_clk->name);
> > +                       goto err_clk;
> > +               }
> > +
> > +               data->clk_data.clks[clks[i].id] = clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_clk:
> > +       while (i--)
> > +               bm1880_clk_unregister_div(data->clk_data.clks[clks[i].id]);
> > +
> > +       return PTR_ERR(clk);
> > +}
> > +
> > +int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks,
> > +                            int num_clks, struct bm1880_clock_data *data)
> > +{
> > +       struct clk *clk;
> > +       void __iomem *sys_base = data->sys_base;
> > +       int i;
> > +
> > +       for (i = 0; i < num_clks; i++) {
> > +               clk = clk_register_gate(NULL, clks[i].name,
> > +                                       clks[i].parent,
> > +                                       clks[i].flags,
> > +                                       sys_base + clks[i].gate_reg,
> > +                                       clks[i].gate_shift,
> > +                                       0,
> > +                                       &bm1880_clk_lock);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, clks[i].name);
> > +                       goto err_clk;
> > +               }
> > +
> > +               data->clk_data.clks[clks[i].id] = clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_clk:
> > +       while (i--)
> > +               clk_unregister_gate(data->clk_data.clks[clks[i].id]);
> > +
> > +       return PTR_ERR(clk);
> > +}
> > +
> > +struct clk *bm1880_clk_register_composite(struct bm1880_composite_clock *clks,
> > +                                         void __iomem *sys_base)
> > +{
> > +       struct clk *clk;
> > +       struct clk_mux *mux = NULL;
> > +       struct clk_gate *gate = NULL;
> > +       struct bm1880_div_hw_clock *div_hws = NULL;
> > +       struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
> > +       const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
> > +       const char * const *parent_names;
> > +       const char *parent;
> > +       int num_parents;
> > +       int ret;
> > +
> > +       if (clks->mux_shift >= 0) {
> > +               mux = kzalloc(sizeof(*mux), GFP_KERNEL);
> > +               if (!mux)
> > +                       return ERR_PTR(-ENOMEM);
> > +
> > +               mux->reg = sys_base + clks->mux_reg;
> > +               mux->mask = 1;
> > +               mux->shift = clks->mux_shift;
> > +               mux_hw = &mux->hw;
> > +               mux_ops = &clk_mux_ops;
> > +               mux->lock = &bm1880_clk_lock;
> > +
> > +               parent_names = clks->parents;
> > +               num_parents = clks->num_parents;
> > +       } else {
> > +               parent = clks->parent;
> > +               parent_names = &parent;
> > +               num_parents = 1;
> > +       }
> > +
> > +       if (clks->gate_shift >= 0) {
> > +               gate = kzalloc(sizeof(*gate), GFP_KERNEL);
> > +               if (!gate) {
> > +                       ret = -ENOMEM;
> > +                       goto err_out;
> > +               }
> > +
> > +               gate->reg = sys_base + clks->gate_reg;
> > +               gate->bit_idx = clks->gate_shift;
> > +               gate->lock = &bm1880_clk_lock;
> > +
> > +               gate_hw = &gate->hw;
> > +               gate_ops = &clk_gate_ops;
> > +       }
> > +
> > +       if (clks->div_shift >= 0) {
> > +               div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL);
> > +               if (!div_hws) {
> > +                       ret = -ENOMEM;
> > +                       goto err_out;
> > +               }
> > +
> > +               div_hws->base = sys_base;
> > +               div_hws->div.reg = clks->div_reg;
> > +               div_hws->div.shift = clks->div_shift;
> > +               div_hws->div.width = clks->div_width;
> > +               div_hws->div.table = clks->table;
> > +               div_hws->div.initval = clks->div_initval;
> > +               div_hws->lock = &bm1880_clk_lock;
> > +               div_hws->div.flags = CLK_DIVIDER_ONE_BASED |
> > +                                    CLK_DIVIDER_ALLOW_ZERO;
> > +
> > +               div_hw = &div_hws->hw;
> > +               div_ops = &bm1880_clk_div_ops;
> > +       }
> > +
> > +       clk = clk_register_composite(NULL, clks->name, parent_names,
> > +                                    num_parents, mux_hw, mux_ops, div_hw,
> > +                                    div_ops, gate_hw, gate_ops, (clks->flags));
> > +
> > +       if (IS_ERR(clk)) {
> > +               ret = PTR_ERR(clk);
> > +               goto err_out;
> > +       }
> > +
> > +       return clk;
> > +
> > +err_out:
> > +       kfree(div_hws);
> > +       kfree(gate);
> > +       kfree(mux);
> > +
> > +       return ERR_PTR(ret);
> > +}
> > +
> > +int bm1880_clk_register_composites(struct bm1880_composite_clock *clks,
> > +                                  int num_clks, struct bm1880_clock_data *data)
> > +{
> > +       struct clk *clk;
> > +       void __iomem *sys_base = data->sys_base;
> > +       int i;
> > +
> > +       for (i = 0; i < num_clks; i++) {
> > +               struct bm1880_composite_clock *bm1880_clk = &clks[i];
> > +
> > +               clk = bm1880_clk_register_composite(bm1880_clk, sys_base);
> > +               if (IS_ERR(clk)) {
> > +                       pr_err("%s: failed to register clock %s\n",
> > +                              __func__, bm1880_clk->name);
> > +                       goto err_clk;
> > +               }
> > +
> > +               data->clk_data.clks[clks[i].id] = clk;
> > +       }
> > +
> > +       return 0;
> > +
> > +err_clk:
> > +       while (i--)
> > +               clk_unregister_composite(data->clk_data.clks[clks[i].id]);
> > +
> > +       return PTR_ERR(clk);
> > +}
> > +
> > +static void bm1880_clk_init(struct device_node *np)
> > +{
> > +       struct bm1880_clock_data *clk_data;
> > +       struct clk **clk_table;
> > +       void __iomem *pll_base, *sys_base;
> > +       int num_clks;
> > +
> > +       pll_base = of_iomap(np, 0);
> > +       if (!pll_base) {
> > +               pr_err("%pOFn: unable to map pll resource", np);
> > +               of_node_put(np);
> > +               return;
> > +       }
> > +
> > +       sys_base = of_iomap(np, 1);
> > +       if (!sys_base) {
> > +               pr_err("%pOFn: unable to map sys resource", np);
> > +               of_node_put(np);
> > +               return;
> > +       }
> > +
> > +       clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
> > +       if (!clk_data)
> > +               return;
> > +
> > +       clk_data->pll_base = pll_base;
> > +       clk_data->sys_base = sys_base;
> > +       num_clks = ARRAY_SIZE(bm1880_gate_clks) +
> > +                  ARRAY_SIZE(bm1880_composite_clks);
> > +
> > +       clk_table = kcalloc(num_clks, sizeof(*clk_table), GFP_KERNEL);
> > +       if (!clk_table)
> > +               goto err_out;
> > +
> > +       clk_data->clk_data.clks = clk_table;
> > +       clk_data->clk_data.clk_num = num_clks;
> > +
> > +       /* Register PLL clocks */
> > +       bm1880_clk_register_plls(bm1880_pll_clks,
> > +                                ARRAY_SIZE(bm1880_pll_clks),
> > +                                clk_data);
> > +
> > +       /* Register Divider clocks */
> 
> Please remove these comments, they provide no useful information.
> 

Ack.

> > +       bm1880_clk_register_divs(bm1880_div_clks,
> > +                                ARRAY_SIZE(bm1880_div_clks),
> > +                                clk_data);
> > +
> > +       /* Register Mux clocks */
> > +       bm1880_clk_register_mux(bm1880_mux_clks,
> > +                               ARRAY_SIZE(bm1880_mux_clks),
> > +                               clk_data);
> > +
> > +       /* Register Composite clocks */
> > +       bm1880_clk_register_composites(bm1880_composite_clks,
> > +                                      ARRAY_SIZE(bm1880_composite_clks),
> > +                                      clk_data);
> > +
> > +       /* Register Gate clocks */
> > +       bm1880_clk_register_gate(bm1880_gate_clks,
> > +                                ARRAY_SIZE(bm1880_gate_clks),
> > +                                clk_data);
> > +
> > +       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data->clk_data);
> > +
> > +       return;
> > +
> > +err_out:
> > +       kfree(clk_data);
> > +}
> > +
> > +CLK_OF_DECLARE_DRIVER(bm1880_clk, "bitmain,bm1880-clk", bm1880_clk_init);
> 
> Is there a reason why it can't be a platform driver?
> 

Hmm, I looked into the majority of drivers which live under `driver/clk/`.
Most of them are using CLK_OF_DECLARE_DRIVER, so I thought that only drivers
which have a separate directory are preferred by the maintainers to use
platform driver way.

Anyway, I can switch over to platform driver and that's what I prefer.

Thanks,
Mani


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-08-17  3:46       ` Stephen Boyd
@ 2019-08-17  3:58         ` Manivannan Sadhasivam
  2019-08-18  1:16           ` Stephen Boyd
  0 siblings, 1 reply; 16+ messages in thread
From: Manivannan Sadhasivam @ 2019-08-17  3:58 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

On Fri, Aug 16, 2019 at 08:46:11PM -0700, Stephen Boyd wrote:
> Quoting Manivannan Sadhasivam (2019-08-16 20:34:22)
> > On Wed, Aug 07, 2019 at 10:01:28PM -0700, Stephen Boyd wrote:
> > > Quoting Manivannan Sadhasivam (2019-07-05 08:14:36)
> > > > +It is expected that it is defined using standard clock bindings as "osc".
> > > > +
> > > > +Example: 
> > > > +
> > > > +        clk: clock-controller@800 {
> > > > +                compatible = "bitmain,bm1880-clk";
> > > > +                reg = <0xe8 0x0c>,<0x800 0xb0>;
> > > 
> > > It looks weird still. What hardware module is this actually part of?
> > > Some larger power manager block?
> > > 
> > 
> > These are all part of the sysctrl block (clock + pinctrl + reset) and the
> > register domains got split between system and pll.
> > 
> 
> And that can't be one node that probes the clk, pinctrl, and reset
> drivers from C code?

It is not a MFD for sure. It's just grouping of the register domains together.

Thanks,
Mani
> 

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding
  2019-08-17  3:58         ` Manivannan Sadhasivam
@ 2019-08-18  1:16           ` Stephen Boyd
  0 siblings, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2019-08-18  1:16 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

Quoting Manivannan Sadhasivam (2019-08-16 20:58:45)
> On Fri, Aug 16, 2019 at 08:46:11PM -0700, Stephen Boyd wrote:
> > Quoting Manivannan Sadhasivam (2019-08-16 20:34:22)
> > > On Wed, Aug 07, 2019 at 10:01:28PM -0700, Stephen Boyd wrote:
> > > > Quoting Manivannan Sadhasivam (2019-07-05 08:14:36)
> > > > > +It is expected that it is defined using standard clock bindings as "osc".
> > > > > +
> > > > > +Example: 
> > > > > +
> > > > > +        clk: clock-controller@800 {
> > > > > +                compatible = "bitmain,bm1880-clk";
> > > > > +                reg = <0xe8 0x0c>,<0x800 0xb0>;
> > > > 
> > > > It looks weird still. What hardware module is this actually part of?
> > > > Some larger power manager block?
> > > > 
> > > 
> > > These are all part of the sysctrl block (clock + pinctrl + reset) and the
> > > register domains got split between system and pll.
> > > 
> > 
> > And that can't be one node that probes the clk, pinctrl, and reset
> > drivers from C code?
> 
> It is not a MFD for sure. It's just grouping of the register domains together.
> 

Are there datasheets? I'm not saying it's an "MFD", just saying that
it's one hardware IP block delivered by the SoC integrator. It's
already odd that there are two register properties.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller
  2019-08-17  3:55     ` Manivannan Sadhasivam
@ 2019-08-18  1:21       ` Stephen Boyd
  0 siblings, 0 replies; 16+ messages in thread
From: Stephen Boyd @ 2019-08-18  1:21 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: devicetree, mturquette, linux-kernel, darren.tsao, robh+dt,
	haitao.suo, fisher.cheng, alec.lin, linux-clk, linux-arm-kernel

Quoting Manivannan Sadhasivam (2019-08-16 20:55:57)
> Hi Stephen,
> 
> On Wed, Aug 07, 2019 at 10:15:59PM -0700, Stephen Boyd wrote:
> > Quoting Manivannan Sadhasivam (2019-07-05 08:14:39)
> > > diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> > > index fc1e0cf44995..ffc61ed85ade 100644
> > > --- a/drivers/clk/Kconfig
> > > +++ b/drivers/clk/Kconfig
> > > @@ -304,6 +304,12 @@ config COMMON_CLK_FIXED_MMIO
> > >         help
> > >           Support for Memory Mapped IO Fixed clocks
> > >  
> > > +config COMMON_CLK_BM1880
> > > +       bool "Clock driver for Bitmain BM1880 SoC"
> > > +       depends on ARCH_BITMAIN || COMPILE_TEST
> > > +       help
> > > +         This driver supports the clocks on Bitmain BM1880 SoC.
> > 
> > Can you add this config somewhere else besides the end? Preferably
> > close to alphabetically in this file.
> > 
> 
> Okay. I got confused by the fact that Makefile is sorted but not the
> Kconfig.

Ok. I'll make a reminder to sort the Kconfig after -rc1 next time.

> 
> > > +
> > >  source "drivers/clk/actions/Kconfig"
> > >  source "drivers/clk/analogbits/Kconfig"
> > >  source "drivers/clk/bcm/Kconfig"
> > > diff --git a/drivers/clk/clk-bm1880.c b/drivers/clk/clk-bm1880.c
> > > new file mode 100644
> > > index 000000000000..26cdb75bb936
> > > --- /dev/null
> > > +++ b/drivers/clk/clk-bm1880.c
[....]
> > > +
> > > +struct clk *bm1880_clk_register_pll(const struct bm1880_pll_clock *pll_clk,
> > > +                                   void __iomem *sys_base)
> > > +{
> > > +       struct bm1880_pll_hw_clock *pll_hw;
> > > +       struct clk_init_data init;
> > > +       struct clk_hw *hw;
> > > +       int err;
> > > +
> > > +       pll_hw = kzalloc(sizeof(*pll_hw), GFP_KERNEL);
> > > +       if (!pll_hw)
> > > +               return ERR_PTR(-ENOMEM);
> > > +
> > > +       init.name = pll_clk->name;
> > > +       init.ops = &bm1880_pll_ops;
> > > +       init.flags = pll_clk->flags;
> > > +       init.parent_names = &pll_clk->parent;
> > 
> > Can you use the new way of specifying parents instead of using strings
> > for everything?
> > 
> 
> Sure, will do it for clocks which doesn't use helper APIs.
> 
> > > +       init.num_parents = 1;
> > > +
> > > +       pll_hw->hw.init = &init;
> > > +       pll_hw->pll.reg = pll_clk->reg;
> > > +       pll_hw->base = sys_base;
> > > +
> > > +       hw = &pll_hw->hw;
> > > +       err = clk_hw_register(NULL, hw);
> > > +
> > > +       if (err) {
> > > +               kfree(pll_hw);
> > > +               return ERR_PTR(err);
> > > +       }
> > > +
> > > +       return hw->clk;
> > 
> > Can this return the clk_hw pointer instead?
> > 
> 
> What is the benefit? I see that only hw:init is going to be NULL in future.

Eventually we will remove ->clk from struct clk_hw and then this will
break. It also clearly makes this driver a clk provider driver and not a
clk consumer.

> So, I'll keep it as it is.

Please no!

> > > +               bm1880_clk_unregister_pll(data->clk_data.clks[clks[i].id]);
> > > +
> > > +       return PTR_ERR(clk);
> > > +}
> > > +
> > > +int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,
> > > +                           int num_clks, struct bm1880_clock_data *data)
> > > +{
> > > +       struct clk *clk;
> > > +       void __iomem *sys_base = data->sys_base;
> > > +       int i;
> > > +
> > > +       for (i = 0; i < num_clks; i++) {
> > > +               clk = clk_register_mux(NULL, clks[i].name,
> > 
> > Can you use the clk_hw based APIs for generic type clks?
> > 
> 
> IMO using helper APIs greatly reduce code size and makes the driver
> look more clean. So I prefer to use the helpers wherever applicable.
> When you plan to deprecate those, I'll switch over to plain clk_hw APIs.

We have clk_hw_register_mux(). Please use it. The clk based registration
APIs are deprecated.

> > > +       kfree(clk_data);
> > > +}
> > > +
> > > +CLK_OF_DECLARE_DRIVER(bm1880_clk, "bitmain,bm1880-clk", bm1880_clk_init);
> > 
> > Is there a reason why it can't be a platform driver?
> > 
> 
> Hmm, I looked into the majority of drivers which live under `driver/clk/`.
> Most of them are using CLK_OF_DECLARE_DRIVER, so I thought that only drivers
> which have a separate directory are preferred by the maintainers to use
> platform driver way.
> 
> Anyway, I can switch over to platform driver and that's what I prefer.
> 

Yes please use a platform driver unless it doesn't work for some reason.
Even then, use a platform driver and CLK_OF_DECLARE_DRIVER() in
conjunction to register the early clks from the OF_DECLARED section and
then adopt the rest to the proper device driver later on. This way we
gain the benefits of driver core.


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

end of thread, back to index

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-05 15:14 [PATCH 0/5] Add Bitmain BM1880 clock driver Manivannan Sadhasivam
2019-07-05 15:14 ` [PATCH 1/5] dt-bindings: clock: Add Bitmain BM1880 SoC clock controller binding Manivannan Sadhasivam
2019-07-24 16:18   ` Rob Herring
2019-08-08  5:01   ` Stephen Boyd
2019-08-17  3:34     ` Manivannan Sadhasivam
2019-08-17  3:46       ` Stephen Boyd
2019-08-17  3:58         ` Manivannan Sadhasivam
2019-08-18  1:16           ` Stephen Boyd
2019-07-05 15:14 ` [PATCH 2/5] arm64: dts: bitmain: Add clock controller support for BM1880 SoC Manivannan Sadhasivam
2019-07-05 15:14 ` [PATCH 3/5] arm64: dts: bitmain: Source common clock for UART controllers Manivannan Sadhasivam
2019-07-05 15:14 ` [PATCH 4/5] clk: Add driver for Bitmain BM1880 SoC clock controller Manivannan Sadhasivam
2019-08-08  5:15   ` Stephen Boyd
2019-08-17  3:55     ` Manivannan Sadhasivam
2019-08-18  1:21       ` Stephen Boyd
2019-07-05 15:14 ` [PATCH 5/5] MAINTAINERS: Add entry for Bitmain BM1880 SoC clock driver Manivannan Sadhasivam
2019-07-22  6:20 ` [PATCH 0/5] Add Bitmain BM1880 " Manivannan Sadhasivam

Linux-ARM-Kernel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/linux-arm-kernel/0 linux-arm-kernel/git/0.git
	git clone --mirror https://lore.kernel.org/linux-arm-kernel/1 linux-arm-kernel/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 linux-arm-kernel linux-arm-kernel/ https://lore.kernel.org/linux-arm-kernel \
		linux-arm-kernel@lists.infradead.org
	public-inbox-index linux-arm-kernel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.infradead.lists.linux-arm-kernel


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git