xref: /openbmc/linux/drivers/clk/clk-bm1880.c (revision 3b392629)
11ab4601dSManivannan Sadhasivam // SPDX-License-Identifier: GPL-2.0+
21ab4601dSManivannan Sadhasivam /*
31ab4601dSManivannan Sadhasivam  * Bitmain BM1880 SoC clock driver
41ab4601dSManivannan Sadhasivam  *
51ab4601dSManivannan Sadhasivam  * Copyright (c) 2019 Linaro Ltd.
61ab4601dSManivannan Sadhasivam  * Author: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
71ab4601dSManivannan Sadhasivam  */
81ab4601dSManivannan Sadhasivam 
91ab4601dSManivannan Sadhasivam #include <linux/clk-provider.h>
10a96cbb14SRob Herring #include <linux/io.h>
111ab4601dSManivannan Sadhasivam #include <linux/kernel.h>
12a96cbb14SRob Herring #include <linux/mod_devicetable.h>
131ab4601dSManivannan Sadhasivam #include <linux/module.h>
141ab4601dSManivannan Sadhasivam #include <linux/platform_device.h>
151ab4601dSManivannan Sadhasivam #include <linux/slab.h>
161ab4601dSManivannan Sadhasivam 
171ab4601dSManivannan Sadhasivam #include <dt-bindings/clock/bm1880-clock.h>
181ab4601dSManivannan Sadhasivam 
191ab4601dSManivannan Sadhasivam #define BM1880_CLK_MPLL_CTL	0x00
201ab4601dSManivannan Sadhasivam #define BM1880_CLK_SPLL_CTL	0x04
211ab4601dSManivannan Sadhasivam #define BM1880_CLK_FPLL_CTL	0x08
221ab4601dSManivannan Sadhasivam #define BM1880_CLK_DDRPLL_CTL	0x0c
231ab4601dSManivannan Sadhasivam 
241ab4601dSManivannan Sadhasivam #define BM1880_CLK_ENABLE0	0x00
251ab4601dSManivannan Sadhasivam #define BM1880_CLK_ENABLE1	0x04
261ab4601dSManivannan Sadhasivam #define BM1880_CLK_SELECT	0x20
271ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV0		0x40
281ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV1		0x44
291ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV2		0x48
301ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV3		0x4c
311ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV4		0x50
321ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV5		0x54
331ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV6		0x58
341ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV7		0x5c
351ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV8		0x60
361ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV9		0x64
371ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV10	0x68
381ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV11	0x6c
391ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV12	0x70
401ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV13	0x74
411ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV14	0x78
421ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV15	0x7c
431ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV16	0x80
441ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV17	0x84
451ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV18	0x88
461ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV19	0x8c
471ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV20	0x90
481ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV21	0x94
491ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV22	0x98
501ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV23	0x9c
511ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV24	0xa0
521ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV25	0xa4
531ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV26	0xa8
541ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV27	0xac
551ab4601dSManivannan Sadhasivam #define BM1880_CLK_DIV28	0xb0
561ab4601dSManivannan Sadhasivam 
571ab4601dSManivannan Sadhasivam #define to_bm1880_pll_clk(_hw) container_of(_hw, struct bm1880_pll_hw_clock, hw)
581ab4601dSManivannan Sadhasivam #define to_bm1880_div_clk(_hw) container_of(_hw, struct bm1880_div_hw_clock, hw)
591ab4601dSManivannan Sadhasivam 
601ab4601dSManivannan Sadhasivam static DEFINE_SPINLOCK(bm1880_clk_lock);
611ab4601dSManivannan Sadhasivam 
621ab4601dSManivannan Sadhasivam struct bm1880_clock_data {
631ab4601dSManivannan Sadhasivam 	void __iomem *pll_base;
641ab4601dSManivannan Sadhasivam 	void __iomem *sys_base;
651ab4601dSManivannan Sadhasivam 	struct clk_hw_onecell_data hw_data;
661ab4601dSManivannan Sadhasivam };
671ab4601dSManivannan Sadhasivam 
681ab4601dSManivannan Sadhasivam struct bm1880_gate_clock {
691ab4601dSManivannan Sadhasivam 	unsigned int	id;
701ab4601dSManivannan Sadhasivam 	const char	*name;
711ab4601dSManivannan Sadhasivam 	const char      *parent;
721ab4601dSManivannan Sadhasivam 	u32		gate_reg;
731ab4601dSManivannan Sadhasivam 	s8		gate_shift;
741ab4601dSManivannan Sadhasivam 	unsigned long	flags;
751ab4601dSManivannan Sadhasivam };
761ab4601dSManivannan Sadhasivam 
771ab4601dSManivannan Sadhasivam struct bm1880_mux_clock {
781ab4601dSManivannan Sadhasivam 	unsigned int	id;
791ab4601dSManivannan Sadhasivam 	const char	*name;
801ab4601dSManivannan Sadhasivam 	const char      * const *parents;
811ab4601dSManivannan Sadhasivam 	s8		num_parents;
821ab4601dSManivannan Sadhasivam 	u32		reg;
831ab4601dSManivannan Sadhasivam 	s8		shift;
841ab4601dSManivannan Sadhasivam 	unsigned long	flags;
851ab4601dSManivannan Sadhasivam };
861ab4601dSManivannan Sadhasivam 
871ab4601dSManivannan Sadhasivam struct bm1880_div_clock {
881ab4601dSManivannan Sadhasivam 	unsigned int	id;
891ab4601dSManivannan Sadhasivam 	const char	*name;
901ab4601dSManivannan Sadhasivam 	u32		reg;
911ab4601dSManivannan Sadhasivam 	u8		shift;
921ab4601dSManivannan Sadhasivam 	u8		width;
931ab4601dSManivannan Sadhasivam 	u32		initval;
941ab4601dSManivannan Sadhasivam 	const struct clk_div_table *table;
951ab4601dSManivannan Sadhasivam 	unsigned long flags;
961ab4601dSManivannan Sadhasivam };
971ab4601dSManivannan Sadhasivam 
981ab4601dSManivannan Sadhasivam struct bm1880_div_hw_clock {
991ab4601dSManivannan Sadhasivam 	struct bm1880_div_clock div;
1001ab4601dSManivannan Sadhasivam 	void __iomem *base;
1011ab4601dSManivannan Sadhasivam 	spinlock_t *lock;
1021ab4601dSManivannan Sadhasivam 	struct clk_hw hw;
1031ab4601dSManivannan Sadhasivam 	struct clk_init_data init;
1041ab4601dSManivannan Sadhasivam };
1051ab4601dSManivannan Sadhasivam 
1061ab4601dSManivannan Sadhasivam struct bm1880_composite_clock {
1071ab4601dSManivannan Sadhasivam 	unsigned int	id;
1081ab4601dSManivannan Sadhasivam 	const char	*name;
1091ab4601dSManivannan Sadhasivam 	const char	*parent;
1101ab4601dSManivannan Sadhasivam 	const char      * const *parents;
1111ab4601dSManivannan Sadhasivam 	unsigned int	num_parents;
1121ab4601dSManivannan Sadhasivam 	unsigned long	flags;
1131ab4601dSManivannan Sadhasivam 
1141ab4601dSManivannan Sadhasivam 	u32		gate_reg;
1151ab4601dSManivannan Sadhasivam 	u32		mux_reg;
1161ab4601dSManivannan Sadhasivam 	u32		div_reg;
1171ab4601dSManivannan Sadhasivam 
1181ab4601dSManivannan Sadhasivam 	s8		gate_shift;
1191ab4601dSManivannan Sadhasivam 	s8		mux_shift;
1201ab4601dSManivannan Sadhasivam 	s8		div_shift;
1211ab4601dSManivannan Sadhasivam 	s8		div_width;
1221ab4601dSManivannan Sadhasivam 	s16		div_initval;
1231ab4601dSManivannan Sadhasivam 	const struct clk_div_table *table;
1241ab4601dSManivannan Sadhasivam };
1251ab4601dSManivannan Sadhasivam 
1261ab4601dSManivannan Sadhasivam struct bm1880_pll_clock {
1271ab4601dSManivannan Sadhasivam 	unsigned int	id;
1281ab4601dSManivannan Sadhasivam 	const char	*name;
1291ab4601dSManivannan Sadhasivam 	u32		reg;
1301ab4601dSManivannan Sadhasivam 	unsigned long	flags;
1311ab4601dSManivannan Sadhasivam };
1321ab4601dSManivannan Sadhasivam 
1331ab4601dSManivannan Sadhasivam struct bm1880_pll_hw_clock {
1341ab4601dSManivannan Sadhasivam 	struct bm1880_pll_clock pll;
1351ab4601dSManivannan Sadhasivam 	void __iomem *base;
1361ab4601dSManivannan Sadhasivam 	struct clk_hw hw;
1371ab4601dSManivannan Sadhasivam 	struct clk_init_data init;
1381ab4601dSManivannan Sadhasivam };
1391ab4601dSManivannan Sadhasivam 
1401ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_pll_ops;
1411ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_clk_div_ops;
1421ab4601dSManivannan Sadhasivam 
1431ab4601dSManivannan Sadhasivam #define GATE_DIV(_id, _name, _parent, _gate_reg, _gate_shift, _div_reg,	\
1441ab4601dSManivannan Sadhasivam 			_div_shift, _div_width, _div_initval, _table,	\
1451ab4601dSManivannan Sadhasivam 			_flags) {					\
1461ab4601dSManivannan Sadhasivam 		.id = _id,						\
1471ab4601dSManivannan Sadhasivam 		.parent = _parent,					\
1481ab4601dSManivannan Sadhasivam 		.name = _name,						\
1491ab4601dSManivannan Sadhasivam 		.gate_reg = _gate_reg,					\
1501ab4601dSManivannan Sadhasivam 		.gate_shift = _gate_shift,				\
1511ab4601dSManivannan Sadhasivam 		.div_reg = _div_reg,					\
1521ab4601dSManivannan Sadhasivam 		.div_shift = _div_shift,				\
1531ab4601dSManivannan Sadhasivam 		.div_width = _div_width,				\
1541ab4601dSManivannan Sadhasivam 		.div_initval = _div_initval,				\
1551ab4601dSManivannan Sadhasivam 		.table = _table,					\
1561ab4601dSManivannan Sadhasivam 		.mux_shift = -1,					\
1571ab4601dSManivannan Sadhasivam 		.flags = _flags,					\
1581ab4601dSManivannan Sadhasivam 	}
1591ab4601dSManivannan Sadhasivam 
1601ab4601dSManivannan Sadhasivam #define GATE_MUX(_id, _name, _parents, _gate_reg, _gate_shift,		\
1611ab4601dSManivannan Sadhasivam 			_mux_reg, _mux_shift, _flags) {			\
1621ab4601dSManivannan Sadhasivam 		.id = _id,						\
1631ab4601dSManivannan Sadhasivam 		.parents = _parents,					\
1641ab4601dSManivannan Sadhasivam 		.num_parents = ARRAY_SIZE(_parents),			\
1651ab4601dSManivannan Sadhasivam 		.name = _name,						\
1661ab4601dSManivannan Sadhasivam 		.gate_reg = _gate_reg,					\
1671ab4601dSManivannan Sadhasivam 		.gate_shift = _gate_shift,				\
1681ab4601dSManivannan Sadhasivam 		.div_shift = -1,					\
1691ab4601dSManivannan Sadhasivam 		.mux_reg = _mux_reg,					\
1701ab4601dSManivannan Sadhasivam 		.mux_shift = _mux_shift,				\
1711ab4601dSManivannan Sadhasivam 		.flags = _flags,					\
1721ab4601dSManivannan Sadhasivam 	}
1731ab4601dSManivannan Sadhasivam 
1741ab4601dSManivannan Sadhasivam #define CLK_PLL(_id, _name, _parent, _reg, _flags) {			\
1751ab4601dSManivannan Sadhasivam 		.pll.id = _id,						\
1761ab4601dSManivannan Sadhasivam 		.pll.name = _name,					\
1771ab4601dSManivannan Sadhasivam 		.pll.reg = _reg,					\
1781ab4601dSManivannan Sadhasivam 		.hw.init = CLK_HW_INIT_PARENTS_DATA(_name, _parent,	\
1791ab4601dSManivannan Sadhasivam 						    &bm1880_pll_ops,	\
1801ab4601dSManivannan Sadhasivam 						    _flags),		\
1811ab4601dSManivannan Sadhasivam 	}
1821ab4601dSManivannan Sadhasivam 
1831ab4601dSManivannan Sadhasivam #define CLK_DIV(_id, _name, _parent, _reg, _shift, _width, _initval,	\
1841ab4601dSManivannan Sadhasivam 				_table,	_flags) {			\
1851ab4601dSManivannan Sadhasivam 		.div.id = _id,						\
1861ab4601dSManivannan Sadhasivam 		.div.name = _name,					\
1871ab4601dSManivannan Sadhasivam 		.div.reg = _reg,					\
1881ab4601dSManivannan Sadhasivam 		.div.shift = _shift,					\
1891ab4601dSManivannan Sadhasivam 		.div.width = _width,					\
1901ab4601dSManivannan Sadhasivam 		.div.initval = _initval,				\
1911ab4601dSManivannan Sadhasivam 		.div.table = _table,					\
1921ab4601dSManivannan Sadhasivam 		.hw.init = CLK_HW_INIT_HW(_name, _parent,		\
1931ab4601dSManivannan Sadhasivam 					  &bm1880_clk_div_ops,		\
1941ab4601dSManivannan Sadhasivam 					  _flags),			\
1951ab4601dSManivannan Sadhasivam 	}
1961ab4601dSManivannan Sadhasivam 
1971ab4601dSManivannan Sadhasivam static struct clk_parent_data bm1880_pll_parent[] = {
1981ab4601dSManivannan Sadhasivam 	{ .fw_name = "osc", .name = "osc" },
1991ab4601dSManivannan Sadhasivam };
2001ab4601dSManivannan Sadhasivam 
2011ab4601dSManivannan Sadhasivam /*
2021ab4601dSManivannan Sadhasivam  * All PLL clocks are marked as CRITICAL, hence they are very crucial
2031ab4601dSManivannan Sadhasivam  * for the functioning of the SoC
2041ab4601dSManivannan Sadhasivam  */
2051ab4601dSManivannan Sadhasivam static struct bm1880_pll_hw_clock bm1880_pll_clks[] = {
2061ab4601dSManivannan Sadhasivam 	CLK_PLL(BM1880_CLK_MPLL, "clk_mpll", bm1880_pll_parent,
2071ab4601dSManivannan Sadhasivam 		BM1880_CLK_MPLL_CTL, 0),
2081ab4601dSManivannan Sadhasivam 	CLK_PLL(BM1880_CLK_SPLL, "clk_spll", bm1880_pll_parent,
2091ab4601dSManivannan Sadhasivam 		BM1880_CLK_SPLL_CTL, 0),
2101ab4601dSManivannan Sadhasivam 	CLK_PLL(BM1880_CLK_FPLL, "clk_fpll", bm1880_pll_parent,
2111ab4601dSManivannan Sadhasivam 		BM1880_CLK_FPLL_CTL, 0),
2121ab4601dSManivannan Sadhasivam 	CLK_PLL(BM1880_CLK_DDRPLL, "clk_ddrpll", bm1880_pll_parent,
2131ab4601dSManivannan Sadhasivam 		BM1880_CLK_DDRPLL_CTL, 0),
2141ab4601dSManivannan Sadhasivam };
2151ab4601dSManivannan Sadhasivam 
2161ab4601dSManivannan Sadhasivam /*
2171ab4601dSManivannan Sadhasivam  * Clocks marked as CRITICAL are needed for the proper functioning
2181ab4601dSManivannan Sadhasivam  * of the SoC.
2191ab4601dSManivannan Sadhasivam  */
2201ab4601dSManivannan Sadhasivam static const struct bm1880_gate_clock bm1880_gate_clks[] = {
2211ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AHB_ROM, "clk_ahb_rom", "clk_mux_axi6",
2221ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 2, 0 },
2231ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI_SRAM, "clk_axi_sram", "clk_axi1",
2241ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 3, 0 },
2251ab4601dSManivannan Sadhasivam 	/*
2261ab4601dSManivannan Sadhasivam 	 * Since this clock is sourcing the DDR memory, let's mark it as
2271ab4601dSManivannan Sadhasivam 	 * critical to avoid gating.
2281ab4601dSManivannan Sadhasivam 	 */
2291ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_DDR_AXI, "clk_ddr_axi", "clk_mux_axi6",
2301ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 4, CLK_IS_CRITICAL },
2311ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_EFUSE, "clk_apb_efuse", "clk_mux_axi6",
2321ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 6, 0 },
2331ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI5_EMMC, "clk_axi5_emmc", "clk_axi5",
2341ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 7, 0 },
2351ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI5_SD, "clk_axi5_sd", "clk_axi5",
2361ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 10, 0 },
2371ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI4_ETH0, "clk_axi4_eth0", "clk_axi4",
2381ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 14, 0 },
2391ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI4_ETH1, "clk_axi4_eth1", "clk_axi4",
2401ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 16, 0 },
2411ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI1_GDMA, "clk_axi1_gdma", "clk_axi1",
2421ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 17, 0 },
2431ab4601dSManivannan Sadhasivam 	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */
2441ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_GPIO, "clk_apb_gpio", "clk_mux_axi6",
2451ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 18, CLK_IGNORE_UNUSED },
2461ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_GPIO_INTR, "clk_apb_gpio_intr", "clk_mux_axi6",
2471ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 19, CLK_IGNORE_UNUSED },
2481ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI1_MINER, "clk_axi1_miner", "clk_axi1",
2491ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 21, 0 },
2501ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AHB_SF, "clk_ahb_sf", "clk_mux_axi6",
2511ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 22, 0 },
2521ab4601dSManivannan Sadhasivam 	/*
2531ab4601dSManivannan Sadhasivam 	 * Not sure which module this clock is sourcing but gating this clock
2541ab4601dSManivannan Sadhasivam 	 * prevents the system from booting. So, let's mark it as critical.
2551ab4601dSManivannan Sadhasivam 	 */
2561ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_SDMA_AXI, "clk_sdma_axi", "clk_axi5",
2571ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 23, CLK_IS_CRITICAL },
2581ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_I2C, "clk_apb_i2c", "clk_mux_axi6",
2591ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 25, 0 },
2601ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_WDT, "clk_apb_wdt", "clk_mux_axi6",
2611ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 26, 0 },
2621ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_JPEG, "clk_apb_jpeg", "clk_axi6",
2631ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 27, 0 },
2641ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI5_NF, "clk_axi5_nf", "clk_axi5",
2651ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 29, 0 },
2661ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_NF, "clk_apb_nf", "clk_axi6",
2671ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE0, 30, 0 },
2681ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_PWM, "clk_apb_pwm", "clk_mux_axi6",
2691ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 0, 0 },
2701ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_RV, "clk_rv", "clk_mux_rv",
2711ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 1, 0 },
2721ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_SPI, "clk_apb_spi", "clk_mux_axi6",
2731ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 2, 0 },
2741ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_UART_500M, "clk_uart_500m", "clk_div_uart_500m",
2751ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 4, 0 },
2761ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_UART, "clk_apb_uart", "clk_axi6",
2771ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 5, 0 },
2781ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_I2S, "clk_apb_i2s", "clk_axi6",
2791ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 6, 0 },
2801ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI4_USB, "clk_axi4_usb", "clk_axi4",
2811ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 7, 0 },
2821ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_USB, "clk_apb_usb", "clk_axi6",
2831ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 8, 0 },
2841ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_12M_USB, "clk_12m_usb", "clk_div_12m_usb",
2851ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 11, 0 },
2861ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_VIDEO, "clk_apb_video", "clk_axi6",
2871ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 12, 0 },
2881ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_APB_VPP, "clk_apb_vpp", "clk_axi6",
2891ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 15, 0 },
2901ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_AXI6, "clk_axi6", "clk_mux_axi6",
2911ab4601dSManivannan Sadhasivam 	  BM1880_CLK_ENABLE1, 21, 0 },
2921ab4601dSManivannan Sadhasivam };
2931ab4601dSManivannan Sadhasivam 
2941ab4601dSManivannan Sadhasivam static const char * const clk_a53_parents[] = { "clk_spll", "clk_mpll" };
2951ab4601dSManivannan Sadhasivam static const char * const clk_rv_parents[] = { "clk_div_1_rv", "clk_div_0_rv" };
2961ab4601dSManivannan Sadhasivam static const char * const clk_axi1_parents[] = { "clk_div_1_axi1", "clk_div_0_axi1" };
2971ab4601dSManivannan Sadhasivam static const char * const clk_axi6_parents[] = { "clk_div_1_axi6", "clk_div_0_axi6" };
2981ab4601dSManivannan Sadhasivam 
2991ab4601dSManivannan Sadhasivam static const struct bm1880_mux_clock bm1880_mux_clks[] = {
3001ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_MUX_RV, "clk_mux_rv", clk_rv_parents, 2,
3011ab4601dSManivannan Sadhasivam 	  BM1880_CLK_SELECT, 1, 0 },
3021ab4601dSManivannan Sadhasivam 	{ BM1880_CLK_MUX_AXI6, "clk_mux_axi6", clk_axi6_parents, 2,
3031ab4601dSManivannan Sadhasivam 	  BM1880_CLK_SELECT, 3, 0 },
3041ab4601dSManivannan Sadhasivam };
3051ab4601dSManivannan Sadhasivam 
3061ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_0[] = {
3071ab4601dSManivannan Sadhasivam 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
3081ab4601dSManivannan Sadhasivam 	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
3091ab4601dSManivannan Sadhasivam 	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
3101ab4601dSManivannan Sadhasivam 	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
3111ab4601dSManivannan Sadhasivam 	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
3121ab4601dSManivannan Sadhasivam 	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
3131ab4601dSManivannan Sadhasivam 	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
3141ab4601dSManivannan Sadhasivam 	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
3151ab4601dSManivannan Sadhasivam 	{ 0, 0 }
3161ab4601dSManivannan Sadhasivam };
3171ab4601dSManivannan Sadhasivam 
3181ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_1[] = {
3191ab4601dSManivannan Sadhasivam 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
3201ab4601dSManivannan Sadhasivam 	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
3211ab4601dSManivannan Sadhasivam 	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
3221ab4601dSManivannan Sadhasivam 	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
3231ab4601dSManivannan Sadhasivam 	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
3241ab4601dSManivannan Sadhasivam 	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
3251ab4601dSManivannan Sadhasivam 	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
3261ab4601dSManivannan Sadhasivam 	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
3271ab4601dSManivannan Sadhasivam 	{ 127, 128 }, { 0, 0 }
3281ab4601dSManivannan Sadhasivam };
3291ab4601dSManivannan Sadhasivam 
3301ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_2[] = {
3311ab4601dSManivannan Sadhasivam 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
3321ab4601dSManivannan Sadhasivam 	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
3331ab4601dSManivannan Sadhasivam 	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
3341ab4601dSManivannan Sadhasivam 	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
3351ab4601dSManivannan Sadhasivam 	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
3361ab4601dSManivannan Sadhasivam 	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
3371ab4601dSManivannan Sadhasivam 	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
3381ab4601dSManivannan Sadhasivam 	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
3391ab4601dSManivannan Sadhasivam 	{ 127, 128 }, { 255, 256 }, { 0, 0 }
3401ab4601dSManivannan Sadhasivam };
3411ab4601dSManivannan Sadhasivam 
3421ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_3[] = {
3431ab4601dSManivannan Sadhasivam 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
3441ab4601dSManivannan Sadhasivam 	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
3451ab4601dSManivannan Sadhasivam 	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
3461ab4601dSManivannan Sadhasivam 	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
3471ab4601dSManivannan Sadhasivam 	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
3481ab4601dSManivannan Sadhasivam 	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
3491ab4601dSManivannan Sadhasivam 	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
3501ab4601dSManivannan Sadhasivam 	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
3511ab4601dSManivannan Sadhasivam 	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 0, 0 }
3521ab4601dSManivannan Sadhasivam };
3531ab4601dSManivannan Sadhasivam 
3541ab4601dSManivannan Sadhasivam static const struct clk_div_table bm1880_div_table_4[] = {
3551ab4601dSManivannan Sadhasivam 	{ 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 4 },
3561ab4601dSManivannan Sadhasivam 	{ 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 8 },
3571ab4601dSManivannan Sadhasivam 	{ 8, 9 }, { 9, 10 }, { 10, 11 }, { 11, 12 },
3581ab4601dSManivannan Sadhasivam 	{ 12, 13 }, { 13, 14 }, { 14, 15 }, { 15, 16 },
3591ab4601dSManivannan Sadhasivam 	{ 16, 17 }, { 17, 18 }, { 18, 19 }, { 19, 20 },
3601ab4601dSManivannan Sadhasivam 	{ 20, 21 }, { 21, 22 }, { 22, 23 }, { 23, 24 },
3611ab4601dSManivannan Sadhasivam 	{ 24, 25 }, { 25, 26 }, { 26, 27 }, { 27, 28 },
3621ab4601dSManivannan Sadhasivam 	{ 28, 29 }, { 29, 30 }, { 30, 31 }, { 31, 32 },
3631ab4601dSManivannan Sadhasivam 	{ 127, 128 }, { 255, 256 }, { 511, 512 }, { 65535, 65536 },
3641ab4601dSManivannan Sadhasivam 	{ 0, 0 }
3651ab4601dSManivannan Sadhasivam };
3661ab4601dSManivannan Sadhasivam 
3671ab4601dSManivannan Sadhasivam /*
3681ab4601dSManivannan Sadhasivam  * Clocks marked as CRITICAL are needed for the proper functioning
3691ab4601dSManivannan Sadhasivam  * of the SoC.
3701ab4601dSManivannan Sadhasivam  */
3711ab4601dSManivannan Sadhasivam static struct bm1880_div_hw_clock bm1880_div_clks[] = {
3721ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_0_RV, "clk_div_0_rv", &bm1880_pll_clks[1].hw,
3731ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV12, 16, 5, 1, bm1880_div_table_0, 0),
3741ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_1_RV, "clk_div_1_rv", &bm1880_pll_clks[2].hw,
3751ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV13, 16, 5, 1, bm1880_div_table_0, 0),
3761ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_UART_500M, "clk_div_uart_500m", &bm1880_pll_clks[2].hw,
3771ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV15, 16, 7, 3, bm1880_div_table_1, 0),
3781ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_0_AXI1, "clk_div_0_axi1", &bm1880_pll_clks[0].hw,
3791ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV21, 16, 5, 2, bm1880_div_table_0,
3801ab4601dSManivannan Sadhasivam 		0),
3811ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_1_AXI1, "clk_div_1_axi1", &bm1880_pll_clks[2].hw,
3821ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV22, 16, 5, 3, bm1880_div_table_0,
3831ab4601dSManivannan Sadhasivam 		0),
3841ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_0_AXI6, "clk_div_0_axi6", &bm1880_pll_clks[2].hw,
3851ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV27, 16, 5, 15, bm1880_div_table_0,
3861ab4601dSManivannan Sadhasivam 		0),
3871ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_1_AXI6, "clk_div_1_axi6", &bm1880_pll_clks[0].hw,
3881ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV28, 16, 5, 11, bm1880_div_table_0,
3891ab4601dSManivannan Sadhasivam 		0),
3901ab4601dSManivannan Sadhasivam 	CLK_DIV(BM1880_CLK_DIV_12M_USB, "clk_div_12m_usb", &bm1880_pll_clks[2].hw,
3911ab4601dSManivannan Sadhasivam 		BM1880_CLK_DIV18, 16, 7, 125, bm1880_div_table_1, 0),
3921ab4601dSManivannan Sadhasivam };
3931ab4601dSManivannan Sadhasivam 
3941ab4601dSManivannan Sadhasivam /*
3951ab4601dSManivannan Sadhasivam  * Clocks marked as CRITICAL are all needed for the proper functioning
3961ab4601dSManivannan Sadhasivam  * of the SoC.
3971ab4601dSManivannan Sadhasivam  */
3981ab4601dSManivannan Sadhasivam static struct bm1880_composite_clock bm1880_composite_clks[] = {
3991ab4601dSManivannan Sadhasivam 	/*
4001ab4601dSManivannan Sadhasivam 	 * Since clk_a53 and clk_50m_a53 clocks are sourcing the CPU core,
4011ab4601dSManivannan Sadhasivam 	 * let's mark them as critical to avoid gating.
4021ab4601dSManivannan Sadhasivam 	 */
4031ab4601dSManivannan Sadhasivam 	GATE_MUX(BM1880_CLK_A53, "clk_a53", clk_a53_parents,
4041ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 0, BM1880_CLK_SELECT, 0,
4051ab4601dSManivannan Sadhasivam 		 CLK_IS_CRITICAL),
4061ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_50M_A53, "clk_50m_a53", "clk_fpll",
4071ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 1, BM1880_CLK_DIV0, 16, 5, 30,
4081ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, CLK_IS_CRITICAL),
4091ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_EFUSE, "clk_efuse", "clk_fpll",
4101ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 5, BM1880_CLK_DIV1, 16, 7, 60,
4111ab4601dSManivannan Sadhasivam 		 bm1880_div_table_1, 0),
4121ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_EMMC, "clk_emmc", "clk_fpll",
4131ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 8, BM1880_CLK_DIV2, 16, 5, 15,
4141ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4151ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_100K_EMMC, "clk_100k_emmc", "clk_div_12m_usb",
4161ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 9, BM1880_CLK_DIV3, 16, 8, 120,
4171ab4601dSManivannan Sadhasivam 		 bm1880_div_table_2, 0),
4181ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_SD, "clk_sd", "clk_fpll",
4191ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 11, BM1880_CLK_DIV4, 16, 5, 15,
4201ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4211ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_100K_SD, "clk_100k_sd", "clk_div_12m_usb",
4221ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 12, BM1880_CLK_DIV5, 16, 8, 120,
4231ab4601dSManivannan Sadhasivam 		 bm1880_div_table_2, 0),
4241ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_500M_ETH0, "clk_500m_eth0", "clk_fpll",
4251ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 13, BM1880_CLK_DIV6, 16, 5, 3,
4261ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4271ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_500M_ETH1, "clk_500m_eth1", "clk_fpll",
4281ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 15, BM1880_CLK_DIV7, 16, 5, 3,
4291ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4301ab4601dSManivannan Sadhasivam 	/* Don't gate GPIO clocks as it is not owned by the GPIO driver */
4311ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_GPIO_DB, "clk_gpio_db", "clk_div_12m_usb",
4321ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 20, BM1880_CLK_DIV8, 16, 16, 120,
4331ab4601dSManivannan Sadhasivam 		 bm1880_div_table_4, CLK_IGNORE_UNUSED),
4341ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_SDMA_AUD, "clk_sdma_aud", "clk_fpll",
4351ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 24, BM1880_CLK_DIV9, 16, 7, 61,
4361ab4601dSManivannan Sadhasivam 		 bm1880_div_table_1, 0),
4371ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_JPEG_AXI, "clk_jpeg_axi", "clk_fpll",
4381ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 28, BM1880_CLK_DIV10, 16, 5, 4,
4391ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4401ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_NF, "clk_nf", "clk_fpll",
4411ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE0, 31, BM1880_CLK_DIV11, 16, 5, 30,
4421ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4431ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_TPU_AXI, "clk_tpu_axi", "clk_spll",
4441ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 3, BM1880_CLK_DIV14, 16, 5, 1,
4451ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4461ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_125M_USB, "clk_125m_usb", "clk_fpll",
4471ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 9, BM1880_CLK_DIV16, 16, 5, 12,
4481ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4491ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_33K_USB, "clk_33k_usb", "clk_div_12m_usb",
4501ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 10, BM1880_CLK_DIV17, 16, 9, 363,
4511ab4601dSManivannan Sadhasivam 		 bm1880_div_table_3, 0),
4521ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_VIDEO_AXI, "clk_video_axi", "clk_fpll",
4531ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 13, BM1880_CLK_DIV19, 16, 5, 4,
4541ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4551ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_VPP_AXI, "clk_vpp_axi", "clk_fpll",
4561ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 14, BM1880_CLK_DIV20, 16, 5, 4,
4571ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4581ab4601dSManivannan Sadhasivam 	GATE_MUX(BM1880_CLK_AXI1, "clk_axi1", clk_axi1_parents,
4591ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 15, BM1880_CLK_SELECT, 2, 0),
4601ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_AXI2, "clk_axi2", "clk_fpll",
4611ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 17, BM1880_CLK_DIV23, 16, 5, 3,
4621ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4631ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_AXI3, "clk_axi3", "clk_mux_rv",
4641ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 18, BM1880_CLK_DIV24, 16, 5, 2,
4651ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4661ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_AXI4, "clk_axi4", "clk_fpll",
4671ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 19, BM1880_CLK_DIV25, 16, 5, 6,
4681ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4691ab4601dSManivannan Sadhasivam 	GATE_DIV(BM1880_CLK_AXI5, "clk_axi5", "clk_fpll",
4701ab4601dSManivannan Sadhasivam 		 BM1880_CLK_ENABLE1, 20, BM1880_CLK_DIV26, 16, 5, 15,
4711ab4601dSManivannan Sadhasivam 		 bm1880_div_table_0, 0),
4721ab4601dSManivannan Sadhasivam };
4731ab4601dSManivannan Sadhasivam 
bm1880_pll_rate_calc(u32 regval,unsigned long parent_rate)4741ab4601dSManivannan Sadhasivam static unsigned long bm1880_pll_rate_calc(u32 regval, unsigned long parent_rate)
4751ab4601dSManivannan Sadhasivam {
4761ab4601dSManivannan Sadhasivam 	u64 numerator;
47759ef4da4SYueHaibing 	u32 fbdiv, refdiv;
4781ab4601dSManivannan Sadhasivam 	u32 postdiv1, postdiv2, denominator;
4791ab4601dSManivannan Sadhasivam 
4801ab4601dSManivannan Sadhasivam 	fbdiv = (regval >> 16) & 0xfff;
4811ab4601dSManivannan Sadhasivam 	refdiv = regval & 0x1f;
4821ab4601dSManivannan Sadhasivam 	postdiv1 = (regval >> 8) & 0x7;
4831ab4601dSManivannan Sadhasivam 	postdiv2 = (regval >> 12) & 0x7;
4841ab4601dSManivannan Sadhasivam 
4851ab4601dSManivannan Sadhasivam 	numerator = parent_rate * fbdiv;
4861ab4601dSManivannan Sadhasivam 	denominator = refdiv * postdiv1 * postdiv2;
4871ab4601dSManivannan Sadhasivam 	do_div(numerator, denominator);
4881ab4601dSManivannan Sadhasivam 
4891ab4601dSManivannan Sadhasivam 	return (unsigned long)numerator;
4901ab4601dSManivannan Sadhasivam }
4911ab4601dSManivannan Sadhasivam 
bm1880_pll_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)4921ab4601dSManivannan Sadhasivam static unsigned long bm1880_pll_recalc_rate(struct clk_hw *hw,
4931ab4601dSManivannan Sadhasivam 					    unsigned long parent_rate)
4941ab4601dSManivannan Sadhasivam {
4951ab4601dSManivannan Sadhasivam 	struct bm1880_pll_hw_clock *pll_hw = to_bm1880_pll_clk(hw);
4961ab4601dSManivannan Sadhasivam 	unsigned long rate;
4971ab4601dSManivannan Sadhasivam 	u32 regval;
4981ab4601dSManivannan Sadhasivam 
4991ab4601dSManivannan Sadhasivam 	regval = readl(pll_hw->base + pll_hw->pll.reg);
5001ab4601dSManivannan Sadhasivam 	rate = bm1880_pll_rate_calc(regval, parent_rate);
5011ab4601dSManivannan Sadhasivam 
5021ab4601dSManivannan Sadhasivam 	return rate;
5031ab4601dSManivannan Sadhasivam }
5041ab4601dSManivannan Sadhasivam 
5051ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_pll_ops = {
5061ab4601dSManivannan Sadhasivam 	.recalc_rate	= bm1880_pll_recalc_rate,
5071ab4601dSManivannan Sadhasivam };
5081ab4601dSManivannan Sadhasivam 
bm1880_clk_register_pll(struct bm1880_pll_hw_clock * pll_clk,void __iomem * sys_base)5091ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_pll(struct bm1880_pll_hw_clock *pll_clk,
5101ab4601dSManivannan Sadhasivam 					      void __iomem *sys_base)
5111ab4601dSManivannan Sadhasivam {
5121ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
5131ab4601dSManivannan Sadhasivam 	int err;
5141ab4601dSManivannan Sadhasivam 
5151ab4601dSManivannan Sadhasivam 	pll_clk->base = sys_base;
5161ab4601dSManivannan Sadhasivam 	hw = &pll_clk->hw;
5171ab4601dSManivannan Sadhasivam 
5181ab4601dSManivannan Sadhasivam 	err = clk_hw_register(NULL, hw);
5191ab4601dSManivannan Sadhasivam 	if (err)
5201ab4601dSManivannan Sadhasivam 		return ERR_PTR(err);
5211ab4601dSManivannan Sadhasivam 
5221ab4601dSManivannan Sadhasivam 	return hw;
5231ab4601dSManivannan Sadhasivam }
5241ab4601dSManivannan Sadhasivam 
bm1880_clk_register_plls(struct bm1880_pll_hw_clock * clks,int num_clks,struct bm1880_clock_data * data)5251ab4601dSManivannan Sadhasivam static int bm1880_clk_register_plls(struct bm1880_pll_hw_clock *clks,
5261ab4601dSManivannan Sadhasivam 				    int num_clks,
5271ab4601dSManivannan Sadhasivam 				    struct bm1880_clock_data *data)
5281ab4601dSManivannan Sadhasivam {
5291ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
5301ab4601dSManivannan Sadhasivam 	void __iomem *pll_base = data->pll_base;
5311ab4601dSManivannan Sadhasivam 	int i;
5321ab4601dSManivannan Sadhasivam 
5331ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++) {
5341ab4601dSManivannan Sadhasivam 		struct bm1880_pll_hw_clock *bm1880_clk = &clks[i];
5351ab4601dSManivannan Sadhasivam 
5361ab4601dSManivannan Sadhasivam 		hw = bm1880_clk_register_pll(bm1880_clk, pll_base);
5371ab4601dSManivannan Sadhasivam 		if (IS_ERR(hw)) {
5381ab4601dSManivannan Sadhasivam 			pr_err("%s: failed to register clock %s\n",
5391ab4601dSManivannan Sadhasivam 			       __func__, bm1880_clk->pll.name);
5401ab4601dSManivannan Sadhasivam 			goto err_clk;
5411ab4601dSManivannan Sadhasivam 		}
5421ab4601dSManivannan Sadhasivam 
5431ab4601dSManivannan Sadhasivam 		data->hw_data.hws[clks[i].pll.id] = hw;
5441ab4601dSManivannan Sadhasivam 	}
5451ab4601dSManivannan Sadhasivam 
5461ab4601dSManivannan Sadhasivam 	return 0;
5471ab4601dSManivannan Sadhasivam 
5481ab4601dSManivannan Sadhasivam err_clk:
5491ab4601dSManivannan Sadhasivam 	while (i--)
550c861c1beSConor Dooley 		clk_hw_unregister(data->hw_data.hws[clks[i].pll.id]);
5511ab4601dSManivannan Sadhasivam 
5521ab4601dSManivannan Sadhasivam 	return PTR_ERR(hw);
5531ab4601dSManivannan Sadhasivam }
5541ab4601dSManivannan Sadhasivam 
bm1880_clk_register_mux(const struct bm1880_mux_clock * clks,int num_clks,struct bm1880_clock_data * data)5551ab4601dSManivannan Sadhasivam static int bm1880_clk_register_mux(const struct bm1880_mux_clock *clks,
5561ab4601dSManivannan Sadhasivam 				   int num_clks,
5571ab4601dSManivannan Sadhasivam 				   struct bm1880_clock_data *data)
5581ab4601dSManivannan Sadhasivam {
5591ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
5601ab4601dSManivannan Sadhasivam 	void __iomem *sys_base = data->sys_base;
5611ab4601dSManivannan Sadhasivam 	int i;
5621ab4601dSManivannan Sadhasivam 
5631ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++) {
5641ab4601dSManivannan Sadhasivam 		hw = clk_hw_register_mux(NULL, clks[i].name,
5651ab4601dSManivannan Sadhasivam 					 clks[i].parents,
5661ab4601dSManivannan Sadhasivam 					 clks[i].num_parents,
5671ab4601dSManivannan Sadhasivam 					 clks[i].flags,
5681ab4601dSManivannan Sadhasivam 					 sys_base + clks[i].reg,
5691ab4601dSManivannan Sadhasivam 					 clks[i].shift, 1, 0,
5701ab4601dSManivannan Sadhasivam 					 &bm1880_clk_lock);
5711ab4601dSManivannan Sadhasivam 		if (IS_ERR(hw)) {
5721ab4601dSManivannan Sadhasivam 			pr_err("%s: failed to register clock %s\n",
5731ab4601dSManivannan Sadhasivam 			       __func__, clks[i].name);
5741ab4601dSManivannan Sadhasivam 			goto err_clk;
5751ab4601dSManivannan Sadhasivam 		}
5761ab4601dSManivannan Sadhasivam 
5771ab4601dSManivannan Sadhasivam 		data->hw_data.hws[clks[i].id] = hw;
5781ab4601dSManivannan Sadhasivam 	}
5791ab4601dSManivannan Sadhasivam 
5801ab4601dSManivannan Sadhasivam 	return 0;
5811ab4601dSManivannan Sadhasivam 
5821ab4601dSManivannan Sadhasivam err_clk:
5831ab4601dSManivannan Sadhasivam 	while (i--)
5841ab4601dSManivannan Sadhasivam 		clk_hw_unregister_mux(data->hw_data.hws[clks[i].id]);
5851ab4601dSManivannan Sadhasivam 
5861ab4601dSManivannan Sadhasivam 	return PTR_ERR(hw);
5871ab4601dSManivannan Sadhasivam }
5881ab4601dSManivannan Sadhasivam 
bm1880_clk_div_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)5891ab4601dSManivannan Sadhasivam static unsigned long bm1880_clk_div_recalc_rate(struct clk_hw *hw,
5901ab4601dSManivannan Sadhasivam 						unsigned long parent_rate)
5911ab4601dSManivannan Sadhasivam {
5921ab4601dSManivannan Sadhasivam 	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
5931ab4601dSManivannan Sadhasivam 	struct bm1880_div_clock *div = &div_hw->div;
5941ab4601dSManivannan Sadhasivam 	void __iomem *reg_addr = div_hw->base + div->reg;
5951ab4601dSManivannan Sadhasivam 	unsigned int val;
5961ab4601dSManivannan Sadhasivam 	unsigned long rate;
5971ab4601dSManivannan Sadhasivam 
5981ab4601dSManivannan Sadhasivam 	if (!(readl(reg_addr) & BIT(3))) {
5991ab4601dSManivannan Sadhasivam 		val = div->initval;
6001ab4601dSManivannan Sadhasivam 	} else {
6011ab4601dSManivannan Sadhasivam 		val = readl(reg_addr) >> div->shift;
6021ab4601dSManivannan Sadhasivam 		val &= clk_div_mask(div->width);
6031ab4601dSManivannan Sadhasivam 	}
6041ab4601dSManivannan Sadhasivam 
6051ab4601dSManivannan Sadhasivam 	rate = divider_recalc_rate(hw, parent_rate, val, div->table,
6061ab4601dSManivannan Sadhasivam 				   div->flags, div->width);
6071ab4601dSManivannan Sadhasivam 
6081ab4601dSManivannan Sadhasivam 	return rate;
6091ab4601dSManivannan Sadhasivam }
6101ab4601dSManivannan Sadhasivam 
bm1880_clk_div_round_rate(struct clk_hw * hw,unsigned long rate,unsigned long * prate)6111ab4601dSManivannan Sadhasivam static long bm1880_clk_div_round_rate(struct clk_hw *hw, unsigned long rate,
6121ab4601dSManivannan Sadhasivam 				      unsigned long *prate)
6131ab4601dSManivannan Sadhasivam {
6141ab4601dSManivannan Sadhasivam 	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
6151ab4601dSManivannan Sadhasivam 	struct bm1880_div_clock *div = &div_hw->div;
6161ab4601dSManivannan Sadhasivam 	void __iomem *reg_addr = div_hw->base + div->reg;
6171ab4601dSManivannan Sadhasivam 
6181ab4601dSManivannan Sadhasivam 	if (div->flags & CLK_DIVIDER_READ_ONLY) {
6191ab4601dSManivannan Sadhasivam 		u32 val;
6201ab4601dSManivannan Sadhasivam 
6211ab4601dSManivannan Sadhasivam 		val = readl(reg_addr) >> div->shift;
6221ab4601dSManivannan Sadhasivam 		val &= clk_div_mask(div->width);
6231ab4601dSManivannan Sadhasivam 
6241ab4601dSManivannan Sadhasivam 		return divider_ro_round_rate(hw, rate, prate, div->table,
6251ab4601dSManivannan Sadhasivam 					     div->width, div->flags,
6261ab4601dSManivannan Sadhasivam 					     val);
6271ab4601dSManivannan Sadhasivam 	}
6281ab4601dSManivannan Sadhasivam 
6291ab4601dSManivannan Sadhasivam 	return divider_round_rate(hw, rate, prate, div->table,
6301ab4601dSManivannan Sadhasivam 				  div->width, div->flags);
6311ab4601dSManivannan Sadhasivam }
6321ab4601dSManivannan Sadhasivam 
bm1880_clk_div_set_rate(struct clk_hw * hw,unsigned long rate,unsigned long parent_rate)6331ab4601dSManivannan Sadhasivam static int bm1880_clk_div_set_rate(struct clk_hw *hw, unsigned long rate,
6341ab4601dSManivannan Sadhasivam 				   unsigned long parent_rate)
6351ab4601dSManivannan Sadhasivam {
6361ab4601dSManivannan Sadhasivam 	struct bm1880_div_hw_clock *div_hw = to_bm1880_div_clk(hw);
6371ab4601dSManivannan Sadhasivam 	struct bm1880_div_clock *div = &div_hw->div;
6381ab4601dSManivannan Sadhasivam 	void __iomem *reg_addr = div_hw->base + div->reg;
6391ab4601dSManivannan Sadhasivam 	unsigned long flags = 0;
6401ab4601dSManivannan Sadhasivam 	int value;
6411ab4601dSManivannan Sadhasivam 	u32 val;
6421ab4601dSManivannan Sadhasivam 
6431ab4601dSManivannan Sadhasivam 	value = divider_get_val(rate, parent_rate, div->table,
6441ab4601dSManivannan Sadhasivam 				div->width, div_hw->div.flags);
6451ab4601dSManivannan Sadhasivam 	if (value < 0)
6461ab4601dSManivannan Sadhasivam 		return value;
6471ab4601dSManivannan Sadhasivam 
6481ab4601dSManivannan Sadhasivam 	if (div_hw->lock)
6491ab4601dSManivannan Sadhasivam 		spin_lock_irqsave(div_hw->lock, flags);
6501ab4601dSManivannan Sadhasivam 	else
6511ab4601dSManivannan Sadhasivam 		__acquire(div_hw->lock);
6521ab4601dSManivannan Sadhasivam 
6531ab4601dSManivannan Sadhasivam 	val = readl(reg_addr);
6541ab4601dSManivannan Sadhasivam 	val &= ~(clk_div_mask(div->width) << div_hw->div.shift);
6551ab4601dSManivannan Sadhasivam 	val |= (u32)value << div->shift;
6561ab4601dSManivannan Sadhasivam 	writel(val, reg_addr);
6571ab4601dSManivannan Sadhasivam 
6581ab4601dSManivannan Sadhasivam 	if (div_hw->lock)
6591ab4601dSManivannan Sadhasivam 		spin_unlock_irqrestore(div_hw->lock, flags);
6601ab4601dSManivannan Sadhasivam 	else
6611ab4601dSManivannan Sadhasivam 		__release(div_hw->lock);
6621ab4601dSManivannan Sadhasivam 
6631ab4601dSManivannan Sadhasivam 	return 0;
6641ab4601dSManivannan Sadhasivam }
6651ab4601dSManivannan Sadhasivam 
6661ab4601dSManivannan Sadhasivam static const struct clk_ops bm1880_clk_div_ops = {
6671ab4601dSManivannan Sadhasivam 	.recalc_rate = bm1880_clk_div_recalc_rate,
6681ab4601dSManivannan Sadhasivam 	.round_rate = bm1880_clk_div_round_rate,
6691ab4601dSManivannan Sadhasivam 	.set_rate = bm1880_clk_div_set_rate,
6701ab4601dSManivannan Sadhasivam };
6711ab4601dSManivannan Sadhasivam 
bm1880_clk_register_div(struct bm1880_div_hw_clock * div_clk,void __iomem * sys_base)6721ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_div(struct bm1880_div_hw_clock *div_clk,
6731ab4601dSManivannan Sadhasivam 					      void __iomem *sys_base)
6741ab4601dSManivannan Sadhasivam {
6751ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
6761ab4601dSManivannan Sadhasivam 	int err;
6771ab4601dSManivannan Sadhasivam 
6781ab4601dSManivannan Sadhasivam 	div_clk->div.flags = CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO;
6791ab4601dSManivannan Sadhasivam 	div_clk->base = sys_base;
6801ab4601dSManivannan Sadhasivam 	div_clk->lock = &bm1880_clk_lock;
6811ab4601dSManivannan Sadhasivam 
6821ab4601dSManivannan Sadhasivam 	hw = &div_clk->hw;
6831ab4601dSManivannan Sadhasivam 	err = clk_hw_register(NULL, hw);
6841ab4601dSManivannan Sadhasivam 	if (err)
6851ab4601dSManivannan Sadhasivam 		return ERR_PTR(err);
6861ab4601dSManivannan Sadhasivam 
6871ab4601dSManivannan Sadhasivam 	return hw;
6881ab4601dSManivannan Sadhasivam }
6891ab4601dSManivannan Sadhasivam 
bm1880_clk_register_divs(struct bm1880_div_hw_clock * clks,int num_clks,struct bm1880_clock_data * data)6901ab4601dSManivannan Sadhasivam static int bm1880_clk_register_divs(struct bm1880_div_hw_clock *clks,
6911ab4601dSManivannan Sadhasivam 				    int num_clks,
6921ab4601dSManivannan Sadhasivam 				    struct bm1880_clock_data *data)
6931ab4601dSManivannan Sadhasivam {
6941ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
6951ab4601dSManivannan Sadhasivam 	void __iomem *sys_base = data->sys_base;
6961ab4601dSManivannan Sadhasivam 	unsigned int i, id;
6971ab4601dSManivannan Sadhasivam 
6981ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++) {
6991ab4601dSManivannan Sadhasivam 		struct bm1880_div_hw_clock *bm1880_clk = &clks[i];
7001ab4601dSManivannan Sadhasivam 
7011ab4601dSManivannan Sadhasivam 		hw = bm1880_clk_register_div(bm1880_clk, sys_base);
7021ab4601dSManivannan Sadhasivam 		if (IS_ERR(hw)) {
7031ab4601dSManivannan Sadhasivam 			pr_err("%s: failed to register clock %s\n",
7041ab4601dSManivannan Sadhasivam 			       __func__, bm1880_clk->div.name);
7051ab4601dSManivannan Sadhasivam 			goto err_clk;
7061ab4601dSManivannan Sadhasivam 		}
7071ab4601dSManivannan Sadhasivam 
7081ab4601dSManivannan Sadhasivam 		id = clks[i].div.id;
7091ab4601dSManivannan Sadhasivam 		data->hw_data.hws[id] = hw;
7101ab4601dSManivannan Sadhasivam 	}
7111ab4601dSManivannan Sadhasivam 
7121ab4601dSManivannan Sadhasivam 	return 0;
7131ab4601dSManivannan Sadhasivam 
7141ab4601dSManivannan Sadhasivam err_clk:
7151ab4601dSManivannan Sadhasivam 	while (i--)
716c861c1beSConor Dooley 		clk_hw_unregister(data->hw_data.hws[clks[i].div.id]);
7171ab4601dSManivannan Sadhasivam 
7181ab4601dSManivannan Sadhasivam 	return PTR_ERR(hw);
7191ab4601dSManivannan Sadhasivam }
7201ab4601dSManivannan Sadhasivam 
bm1880_clk_register_gate(const struct bm1880_gate_clock * clks,int num_clks,struct bm1880_clock_data * data)7211ab4601dSManivannan Sadhasivam static int bm1880_clk_register_gate(const struct bm1880_gate_clock *clks,
7221ab4601dSManivannan Sadhasivam 				    int num_clks,
7231ab4601dSManivannan Sadhasivam 				    struct bm1880_clock_data *data)
7241ab4601dSManivannan Sadhasivam {
7251ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
7261ab4601dSManivannan Sadhasivam 	void __iomem *sys_base = data->sys_base;
7271ab4601dSManivannan Sadhasivam 	int i;
7281ab4601dSManivannan Sadhasivam 
7291ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++) {
7301ab4601dSManivannan Sadhasivam 		hw = clk_hw_register_gate(NULL, clks[i].name,
7311ab4601dSManivannan Sadhasivam 					  clks[i].parent,
7321ab4601dSManivannan Sadhasivam 					  clks[i].flags,
7331ab4601dSManivannan Sadhasivam 					  sys_base + clks[i].gate_reg,
7341ab4601dSManivannan Sadhasivam 					  clks[i].gate_shift, 0,
7351ab4601dSManivannan Sadhasivam 					  &bm1880_clk_lock);
7361ab4601dSManivannan Sadhasivam 		if (IS_ERR(hw)) {
7371ab4601dSManivannan Sadhasivam 			pr_err("%s: failed to register clock %s\n",
7381ab4601dSManivannan Sadhasivam 			       __func__, clks[i].name);
7391ab4601dSManivannan Sadhasivam 			goto err_clk;
7401ab4601dSManivannan Sadhasivam 		}
7411ab4601dSManivannan Sadhasivam 
7421ab4601dSManivannan Sadhasivam 		data->hw_data.hws[clks[i].id] = hw;
7431ab4601dSManivannan Sadhasivam 	}
7441ab4601dSManivannan Sadhasivam 
7451ab4601dSManivannan Sadhasivam 	return 0;
7461ab4601dSManivannan Sadhasivam 
7471ab4601dSManivannan Sadhasivam err_clk:
7481ab4601dSManivannan Sadhasivam 	while (i--)
7491ab4601dSManivannan Sadhasivam 		clk_hw_unregister_gate(data->hw_data.hws[clks[i].id]);
7501ab4601dSManivannan Sadhasivam 
7511ab4601dSManivannan Sadhasivam 	return PTR_ERR(hw);
7521ab4601dSManivannan Sadhasivam }
7531ab4601dSManivannan Sadhasivam 
bm1880_clk_register_composite(struct bm1880_composite_clock * clks,void __iomem * sys_base)7541ab4601dSManivannan Sadhasivam static struct clk_hw *bm1880_clk_register_composite(struct bm1880_composite_clock *clks,
7551ab4601dSManivannan Sadhasivam 						    void __iomem *sys_base)
7561ab4601dSManivannan Sadhasivam {
7571ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
7581ab4601dSManivannan Sadhasivam 	struct clk_mux *mux = NULL;
7591ab4601dSManivannan Sadhasivam 	struct clk_gate *gate = NULL;
7601ab4601dSManivannan Sadhasivam 	struct bm1880_div_hw_clock *div_hws = NULL;
7611ab4601dSManivannan Sadhasivam 	struct clk_hw *mux_hw = NULL, *gate_hw = NULL, *div_hw = NULL;
7621ab4601dSManivannan Sadhasivam 	const struct clk_ops *mux_ops = NULL, *gate_ops = NULL, *div_ops = NULL;
7631ab4601dSManivannan Sadhasivam 	const char * const *parent_names;
7641ab4601dSManivannan Sadhasivam 	const char *parent;
7651ab4601dSManivannan Sadhasivam 	int num_parents;
7661ab4601dSManivannan Sadhasivam 	int ret;
7671ab4601dSManivannan Sadhasivam 
7681ab4601dSManivannan Sadhasivam 	if (clks->mux_shift >= 0) {
7691ab4601dSManivannan Sadhasivam 		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
7701ab4601dSManivannan Sadhasivam 		if (!mux)
7711ab4601dSManivannan Sadhasivam 			return ERR_PTR(-ENOMEM);
7721ab4601dSManivannan Sadhasivam 
7731ab4601dSManivannan Sadhasivam 		mux->reg = sys_base + clks->mux_reg;
7741ab4601dSManivannan Sadhasivam 		mux->mask = 1;
7751ab4601dSManivannan Sadhasivam 		mux->shift = clks->mux_shift;
7761ab4601dSManivannan Sadhasivam 		mux_hw = &mux->hw;
7771ab4601dSManivannan Sadhasivam 		mux_ops = &clk_mux_ops;
7781ab4601dSManivannan Sadhasivam 		mux->lock = &bm1880_clk_lock;
7791ab4601dSManivannan Sadhasivam 
7801ab4601dSManivannan Sadhasivam 		parent_names = clks->parents;
7811ab4601dSManivannan Sadhasivam 		num_parents = clks->num_parents;
7821ab4601dSManivannan Sadhasivam 	} else {
7831ab4601dSManivannan Sadhasivam 		parent = clks->parent;
7841ab4601dSManivannan Sadhasivam 		parent_names = &parent;
7851ab4601dSManivannan Sadhasivam 		num_parents = 1;
7861ab4601dSManivannan Sadhasivam 	}
7871ab4601dSManivannan Sadhasivam 
7881ab4601dSManivannan Sadhasivam 	if (clks->gate_shift >= 0) {
7891ab4601dSManivannan Sadhasivam 		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
7901ab4601dSManivannan Sadhasivam 		if (!gate) {
7911ab4601dSManivannan Sadhasivam 			ret = -ENOMEM;
7921ab4601dSManivannan Sadhasivam 			goto err_out;
7931ab4601dSManivannan Sadhasivam 		}
7941ab4601dSManivannan Sadhasivam 
7951ab4601dSManivannan Sadhasivam 		gate->reg = sys_base + clks->gate_reg;
7961ab4601dSManivannan Sadhasivam 		gate->bit_idx = clks->gate_shift;
7971ab4601dSManivannan Sadhasivam 		gate->lock = &bm1880_clk_lock;
7981ab4601dSManivannan Sadhasivam 
7991ab4601dSManivannan Sadhasivam 		gate_hw = &gate->hw;
8001ab4601dSManivannan Sadhasivam 		gate_ops = &clk_gate_ops;
8011ab4601dSManivannan Sadhasivam 	}
8021ab4601dSManivannan Sadhasivam 
8031ab4601dSManivannan Sadhasivam 	if (clks->div_shift >= 0) {
8041ab4601dSManivannan Sadhasivam 		div_hws = kzalloc(sizeof(*div_hws), GFP_KERNEL);
8051ab4601dSManivannan Sadhasivam 		if (!div_hws) {
8061ab4601dSManivannan Sadhasivam 			ret = -ENOMEM;
8071ab4601dSManivannan Sadhasivam 			goto err_out;
8081ab4601dSManivannan Sadhasivam 		}
8091ab4601dSManivannan Sadhasivam 
8101ab4601dSManivannan Sadhasivam 		div_hws->base = sys_base;
8111ab4601dSManivannan Sadhasivam 		div_hws->div.reg = clks->div_reg;
8121ab4601dSManivannan Sadhasivam 		div_hws->div.shift = clks->div_shift;
8131ab4601dSManivannan Sadhasivam 		div_hws->div.width = clks->div_width;
8141ab4601dSManivannan Sadhasivam 		div_hws->div.table = clks->table;
8151ab4601dSManivannan Sadhasivam 		div_hws->div.initval = clks->div_initval;
8161ab4601dSManivannan Sadhasivam 		div_hws->lock = &bm1880_clk_lock;
8171ab4601dSManivannan Sadhasivam 		div_hws->div.flags = CLK_DIVIDER_ONE_BASED |
8181ab4601dSManivannan Sadhasivam 				     CLK_DIVIDER_ALLOW_ZERO;
8191ab4601dSManivannan Sadhasivam 
8201ab4601dSManivannan Sadhasivam 		div_hw = &div_hws->hw;
8211ab4601dSManivannan Sadhasivam 		div_ops = &bm1880_clk_div_ops;
8221ab4601dSManivannan Sadhasivam 	}
8231ab4601dSManivannan Sadhasivam 
8241ab4601dSManivannan Sadhasivam 	hw = clk_hw_register_composite(NULL, clks->name, parent_names,
8251ab4601dSManivannan Sadhasivam 				       num_parents, mux_hw, mux_ops, div_hw,
8261ab4601dSManivannan Sadhasivam 				       div_ops, gate_hw, gate_ops,
8271ab4601dSManivannan Sadhasivam 				       clks->flags);
8281ab4601dSManivannan Sadhasivam 
8291ab4601dSManivannan Sadhasivam 	if (IS_ERR(hw)) {
8301ab4601dSManivannan Sadhasivam 		ret = PTR_ERR(hw);
8311ab4601dSManivannan Sadhasivam 		goto err_out;
8321ab4601dSManivannan Sadhasivam 	}
8331ab4601dSManivannan Sadhasivam 
8341ab4601dSManivannan Sadhasivam 	return hw;
8351ab4601dSManivannan Sadhasivam 
8361ab4601dSManivannan Sadhasivam err_out:
8371ab4601dSManivannan Sadhasivam 	kfree(div_hws);
8381ab4601dSManivannan Sadhasivam 	kfree(gate);
8391ab4601dSManivannan Sadhasivam 	kfree(mux);
8401ab4601dSManivannan Sadhasivam 
8411ab4601dSManivannan Sadhasivam 	return ERR_PTR(ret);
8421ab4601dSManivannan Sadhasivam }
8431ab4601dSManivannan Sadhasivam 
bm1880_clk_register_composites(struct bm1880_composite_clock * clks,int num_clks,struct bm1880_clock_data * data)8441ab4601dSManivannan Sadhasivam static int bm1880_clk_register_composites(struct bm1880_composite_clock *clks,
8451ab4601dSManivannan Sadhasivam 					  int num_clks,
8461ab4601dSManivannan Sadhasivam 					  struct bm1880_clock_data *data)
8471ab4601dSManivannan Sadhasivam {
8481ab4601dSManivannan Sadhasivam 	struct clk_hw *hw;
8491ab4601dSManivannan Sadhasivam 	void __iomem *sys_base = data->sys_base;
8501ab4601dSManivannan Sadhasivam 	int i;
8511ab4601dSManivannan Sadhasivam 
8521ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++) {
8531ab4601dSManivannan Sadhasivam 		struct bm1880_composite_clock *bm1880_clk = &clks[i];
8541ab4601dSManivannan Sadhasivam 
8551ab4601dSManivannan Sadhasivam 		hw = bm1880_clk_register_composite(bm1880_clk, sys_base);
8561ab4601dSManivannan Sadhasivam 		if (IS_ERR(hw)) {
8571ab4601dSManivannan Sadhasivam 			pr_err("%s: failed to register clock %s\n",
8581ab4601dSManivannan Sadhasivam 			       __func__, bm1880_clk->name);
8591ab4601dSManivannan Sadhasivam 			goto err_clk;
8601ab4601dSManivannan Sadhasivam 		}
8611ab4601dSManivannan Sadhasivam 
8621ab4601dSManivannan Sadhasivam 		data->hw_data.hws[clks[i].id] = hw;
8631ab4601dSManivannan Sadhasivam 	}
8641ab4601dSManivannan Sadhasivam 
8651ab4601dSManivannan Sadhasivam 	return 0;
8661ab4601dSManivannan Sadhasivam 
8671ab4601dSManivannan Sadhasivam err_clk:
8681ab4601dSManivannan Sadhasivam 	while (i--)
8691ab4601dSManivannan Sadhasivam 		clk_hw_unregister_composite(data->hw_data.hws[clks[i].id]);
8701ab4601dSManivannan Sadhasivam 
8711ab4601dSManivannan Sadhasivam 	return PTR_ERR(hw);
8721ab4601dSManivannan Sadhasivam }
8731ab4601dSManivannan Sadhasivam 
bm1880_clk_probe(struct platform_device * pdev)8741ab4601dSManivannan Sadhasivam static int bm1880_clk_probe(struct platform_device *pdev)
8751ab4601dSManivannan Sadhasivam {
8761ab4601dSManivannan Sadhasivam 	struct bm1880_clock_data *clk_data;
8771ab4601dSManivannan Sadhasivam 	void __iomem *pll_base, *sys_base;
8781ab4601dSManivannan Sadhasivam 	struct device *dev = &pdev->dev;
8791ab4601dSManivannan Sadhasivam 	int num_clks, i;
8801ab4601dSManivannan Sadhasivam 
881*3b392629SYangtao Li 	pll_base = devm_platform_ioremap_resource(pdev, 0);
8821ab4601dSManivannan Sadhasivam 	if (IS_ERR(pll_base))
8831ab4601dSManivannan Sadhasivam 		return PTR_ERR(pll_base);
8841ab4601dSManivannan Sadhasivam 
885*3b392629SYangtao Li 	sys_base = devm_platform_ioremap_resource(pdev, 1);
8861ab4601dSManivannan Sadhasivam 	if (IS_ERR(sys_base))
8871ab4601dSManivannan Sadhasivam 		return PTR_ERR(sys_base);
8881ab4601dSManivannan Sadhasivam 
8891ab4601dSManivannan Sadhasivam 	num_clks = ARRAY_SIZE(bm1880_pll_clks) +
8901ab4601dSManivannan Sadhasivam 		   ARRAY_SIZE(bm1880_div_clks) +
8911ab4601dSManivannan Sadhasivam 		   ARRAY_SIZE(bm1880_mux_clks) +
8921ab4601dSManivannan Sadhasivam 		   ARRAY_SIZE(bm1880_composite_clks) +
8931ab4601dSManivannan Sadhasivam 		   ARRAY_SIZE(bm1880_gate_clks);
8941ab4601dSManivannan Sadhasivam 
8951ab4601dSManivannan Sadhasivam 	clk_data = devm_kzalloc(dev, struct_size(clk_data, hw_data.hws,
8961ab4601dSManivannan Sadhasivam 						 num_clks), GFP_KERNEL);
8971ab4601dSManivannan Sadhasivam 	if (!clk_data)
8981ab4601dSManivannan Sadhasivam 		return -ENOMEM;
8991ab4601dSManivannan Sadhasivam 
9001ab4601dSManivannan Sadhasivam 	clk_data->pll_base = pll_base;
9011ab4601dSManivannan Sadhasivam 	clk_data->sys_base = sys_base;
9021ab4601dSManivannan Sadhasivam 
9031ab4601dSManivannan Sadhasivam 	for (i = 0; i < num_clks; i++)
9041ab4601dSManivannan Sadhasivam 		clk_data->hw_data.hws[i] = ERR_PTR(-ENOENT);
9051ab4601dSManivannan Sadhasivam 
9061ab4601dSManivannan Sadhasivam 	clk_data->hw_data.num = num_clks;
9071ab4601dSManivannan Sadhasivam 
9081ab4601dSManivannan Sadhasivam 	bm1880_clk_register_plls(bm1880_pll_clks,
9091ab4601dSManivannan Sadhasivam 				 ARRAY_SIZE(bm1880_pll_clks),
9101ab4601dSManivannan Sadhasivam 				 clk_data);
9111ab4601dSManivannan Sadhasivam 
9121ab4601dSManivannan Sadhasivam 	bm1880_clk_register_divs(bm1880_div_clks,
9131ab4601dSManivannan Sadhasivam 				 ARRAY_SIZE(bm1880_div_clks),
9141ab4601dSManivannan Sadhasivam 				 clk_data);
9151ab4601dSManivannan Sadhasivam 
9161ab4601dSManivannan Sadhasivam 	bm1880_clk_register_mux(bm1880_mux_clks,
9171ab4601dSManivannan Sadhasivam 				ARRAY_SIZE(bm1880_mux_clks),
9181ab4601dSManivannan Sadhasivam 				clk_data);
9191ab4601dSManivannan Sadhasivam 
9201ab4601dSManivannan Sadhasivam 	bm1880_clk_register_composites(bm1880_composite_clks,
9211ab4601dSManivannan Sadhasivam 				       ARRAY_SIZE(bm1880_composite_clks),
9221ab4601dSManivannan Sadhasivam 				       clk_data);
9231ab4601dSManivannan Sadhasivam 
9241ab4601dSManivannan Sadhasivam 	bm1880_clk_register_gate(bm1880_gate_clks,
9251ab4601dSManivannan Sadhasivam 				 ARRAY_SIZE(bm1880_gate_clks),
9261ab4601dSManivannan Sadhasivam 				 clk_data);
9271ab4601dSManivannan Sadhasivam 
9281ab4601dSManivannan Sadhasivam 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
9291ab4601dSManivannan Sadhasivam 				      &clk_data->hw_data);
9301ab4601dSManivannan Sadhasivam }
9311ab4601dSManivannan Sadhasivam 
9321ab4601dSManivannan Sadhasivam static const struct of_device_id bm1880_of_match[] = {
9331ab4601dSManivannan Sadhasivam 	{ .compatible = "bitmain,bm1880-clk", },
9341ab4601dSManivannan Sadhasivam 	{}
9351ab4601dSManivannan Sadhasivam };
9361ab4601dSManivannan Sadhasivam MODULE_DEVICE_TABLE(of, bm1880_of_match);
9371ab4601dSManivannan Sadhasivam 
9381ab4601dSManivannan Sadhasivam static struct platform_driver bm1880_clk_driver = {
9391ab4601dSManivannan Sadhasivam 	.driver = {
9401ab4601dSManivannan Sadhasivam 		.name = "bm1880-clk",
9411ab4601dSManivannan Sadhasivam 		.of_match_table = bm1880_of_match,
9421ab4601dSManivannan Sadhasivam 	},
9431ab4601dSManivannan Sadhasivam 	.probe = bm1880_clk_probe,
9441ab4601dSManivannan Sadhasivam };
9451ab4601dSManivannan Sadhasivam module_platform_driver(bm1880_clk_driver);
9461ab4601dSManivannan Sadhasivam 
9471ab4601dSManivannan Sadhasivam MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>");
9481ab4601dSManivannan Sadhasivam MODULE_DESCRIPTION("Clock driver for Bitmain BM1880 SoC");
949