18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2016 BayLibre, SAS.
48c2ecf20Sopenharmony_ci * Author: Neil Armstrong <narmstrong@baylibre.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
78c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h>
88c2ecf20Sopenharmony_ci#include "meson-aoclk.h"
98c2ecf20Sopenharmony_ci#include "gxbb-aoclk.h"
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include "clk-regmap.h"
128c2ecf20Sopenharmony_ci#include "clk-dualdiv.h"
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci/* AO Configuration Clock registers offsets */
158c2ecf20Sopenharmony_ci#define AO_RTI_PWR_CNTL_REG1	0x0c
168c2ecf20Sopenharmony_ci#define AO_RTI_PWR_CNTL_REG0	0x10
178c2ecf20Sopenharmony_ci#define AO_RTI_GEN_CNTL_REG0	0x40
188c2ecf20Sopenharmony_ci#define AO_OSCIN_CNTL		0x58
198c2ecf20Sopenharmony_ci#define AO_CRT_CLK_CNTL1	0x68
208c2ecf20Sopenharmony_ci#define AO_RTC_ALT_CLK_CNTL0	0x94
218c2ecf20Sopenharmony_ci#define AO_RTC_ALT_CLK_CNTL1	0x98
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define GXBB_AO_GATE(_name, _bit)					\
248c2ecf20Sopenharmony_cistatic struct clk_regmap _name##_ao = {					\
258c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_gate_data) {			\
268c2ecf20Sopenharmony_ci		.offset = AO_RTI_GEN_CNTL_REG0,				\
278c2ecf20Sopenharmony_ci		.bit_idx = (_bit),					\
288c2ecf20Sopenharmony_ci	},								\
298c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data) {				\
308c2ecf20Sopenharmony_ci		.name = #_name "_ao",					\
318c2ecf20Sopenharmony_ci		.ops = &clk_regmap_gate_ops,				\
328c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data) {	\
338c2ecf20Sopenharmony_ci			.fw_name = "mpeg-clk",				\
348c2ecf20Sopenharmony_ci		},							\
358c2ecf20Sopenharmony_ci		.num_parents = 1,					\
368c2ecf20Sopenharmony_ci		.flags = CLK_IGNORE_UNUSED,				\
378c2ecf20Sopenharmony_ci	},								\
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciGXBB_AO_GATE(remote, 0);
418c2ecf20Sopenharmony_ciGXBB_AO_GATE(i2c_master, 1);
428c2ecf20Sopenharmony_ciGXBB_AO_GATE(i2c_slave, 2);
438c2ecf20Sopenharmony_ciGXBB_AO_GATE(uart1, 3);
448c2ecf20Sopenharmony_ciGXBB_AO_GATE(uart2, 5);
458c2ecf20Sopenharmony_ciGXBB_AO_GATE(ir_blaster, 6);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic struct clk_regmap ao_cts_oscin = {
488c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_gate_data){
498c2ecf20Sopenharmony_ci		.offset = AO_RTI_PWR_CNTL_REG0,
508c2ecf20Sopenharmony_ci		.bit_idx = 6,
518c2ecf20Sopenharmony_ci	},
528c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
538c2ecf20Sopenharmony_ci		.name = "ao_cts_oscin",
548c2ecf20Sopenharmony_ci		.ops = &clk_regmap_gate_ro_ops,
558c2ecf20Sopenharmony_ci		.parent_data = &(const struct clk_parent_data) {
568c2ecf20Sopenharmony_ci			.fw_name = "xtal",
578c2ecf20Sopenharmony_ci		},
588c2ecf20Sopenharmony_ci		.num_parents = 1,
598c2ecf20Sopenharmony_ci	},
608c2ecf20Sopenharmony_ci};
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_cistatic struct clk_regmap ao_32k_pre = {
638c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_gate_data){
648c2ecf20Sopenharmony_ci		.offset = AO_RTC_ALT_CLK_CNTL0,
658c2ecf20Sopenharmony_ci		.bit_idx = 31,
668c2ecf20Sopenharmony_ci	},
678c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
688c2ecf20Sopenharmony_ci		.name = "ao_32k_pre",
698c2ecf20Sopenharmony_ci		.ops = &clk_regmap_gate_ops,
708c2ecf20Sopenharmony_ci		.parent_hws = (const struct clk_hw *[]) { &ao_cts_oscin.hw },
718c2ecf20Sopenharmony_ci		.num_parents = 1,
728c2ecf20Sopenharmony_ci	},
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic const struct meson_clk_dualdiv_param gxbb_32k_div_table[] = {
768c2ecf20Sopenharmony_ci	{
778c2ecf20Sopenharmony_ci		.dual	= 1,
788c2ecf20Sopenharmony_ci		.n1	= 733,
798c2ecf20Sopenharmony_ci		.m1	= 8,
808c2ecf20Sopenharmony_ci		.n2	= 732,
818c2ecf20Sopenharmony_ci		.m2	= 11,
828c2ecf20Sopenharmony_ci	}, {}
838c2ecf20Sopenharmony_ci};
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cistatic struct clk_regmap ao_32k_div = {
868c2ecf20Sopenharmony_ci	.data = &(struct meson_clk_dualdiv_data){
878c2ecf20Sopenharmony_ci		.n1 = {
888c2ecf20Sopenharmony_ci			.reg_off = AO_RTC_ALT_CLK_CNTL0,
898c2ecf20Sopenharmony_ci			.shift   = 0,
908c2ecf20Sopenharmony_ci			.width   = 12,
918c2ecf20Sopenharmony_ci		},
928c2ecf20Sopenharmony_ci		.n2 = {
938c2ecf20Sopenharmony_ci			.reg_off = AO_RTC_ALT_CLK_CNTL0,
948c2ecf20Sopenharmony_ci			.shift   = 12,
958c2ecf20Sopenharmony_ci			.width   = 12,
968c2ecf20Sopenharmony_ci		},
978c2ecf20Sopenharmony_ci		.m1 = {
988c2ecf20Sopenharmony_ci			.reg_off = AO_RTC_ALT_CLK_CNTL1,
998c2ecf20Sopenharmony_ci			.shift   = 0,
1008c2ecf20Sopenharmony_ci			.width   = 12,
1018c2ecf20Sopenharmony_ci		},
1028c2ecf20Sopenharmony_ci		.m2 = {
1038c2ecf20Sopenharmony_ci			.reg_off = AO_RTC_ALT_CLK_CNTL1,
1048c2ecf20Sopenharmony_ci			.shift   = 12,
1058c2ecf20Sopenharmony_ci			.width   = 12,
1068c2ecf20Sopenharmony_ci		},
1078c2ecf20Sopenharmony_ci		.dual = {
1088c2ecf20Sopenharmony_ci			.reg_off = AO_RTC_ALT_CLK_CNTL0,
1098c2ecf20Sopenharmony_ci			.shift   = 28,
1108c2ecf20Sopenharmony_ci			.width   = 1,
1118c2ecf20Sopenharmony_ci		},
1128c2ecf20Sopenharmony_ci		.table = gxbb_32k_div_table,
1138c2ecf20Sopenharmony_ci	},
1148c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
1158c2ecf20Sopenharmony_ci		.name = "ao_32k_div",
1168c2ecf20Sopenharmony_ci		.ops = &meson_clk_dualdiv_ops,
1178c2ecf20Sopenharmony_ci		.parent_hws = (const struct clk_hw *[]) { &ao_32k_pre.hw },
1188c2ecf20Sopenharmony_ci		.num_parents = 1,
1198c2ecf20Sopenharmony_ci	},
1208c2ecf20Sopenharmony_ci};
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic struct clk_regmap ao_32k_sel = {
1238c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_mux_data) {
1248c2ecf20Sopenharmony_ci		.offset = AO_RTC_ALT_CLK_CNTL1,
1258c2ecf20Sopenharmony_ci		.mask = 0x1,
1268c2ecf20Sopenharmony_ci		.shift = 24,
1278c2ecf20Sopenharmony_ci		.flags = CLK_MUX_ROUND_CLOSEST,
1288c2ecf20Sopenharmony_ci	},
1298c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
1308c2ecf20Sopenharmony_ci		.name = "ao_32k_sel",
1318c2ecf20Sopenharmony_ci		.ops = &clk_regmap_mux_ops,
1328c2ecf20Sopenharmony_ci		.parent_hws = (const struct clk_hw *[]) {
1338c2ecf20Sopenharmony_ci			&ao_32k_div.hw,
1348c2ecf20Sopenharmony_ci			&ao_32k_pre.hw
1358c2ecf20Sopenharmony_ci		},
1368c2ecf20Sopenharmony_ci		.num_parents = 2,
1378c2ecf20Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT,
1388c2ecf20Sopenharmony_ci	},
1398c2ecf20Sopenharmony_ci};
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic struct clk_regmap ao_32k = {
1428c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_gate_data){
1438c2ecf20Sopenharmony_ci		.offset = AO_RTC_ALT_CLK_CNTL0,
1448c2ecf20Sopenharmony_ci		.bit_idx = 30,
1458c2ecf20Sopenharmony_ci	},
1468c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
1478c2ecf20Sopenharmony_ci		.name = "ao_32k",
1488c2ecf20Sopenharmony_ci		.ops = &clk_regmap_gate_ops,
1498c2ecf20Sopenharmony_ci		.parent_hws = (const struct clk_hw *[]) { &ao_32k_sel.hw },
1508c2ecf20Sopenharmony_ci		.num_parents = 1,
1518c2ecf20Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT,
1528c2ecf20Sopenharmony_ci	},
1538c2ecf20Sopenharmony_ci};
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic struct clk_regmap ao_cts_rtc_oscin = {
1568c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_mux_data) {
1578c2ecf20Sopenharmony_ci		.offset = AO_RTI_PWR_CNTL_REG0,
1588c2ecf20Sopenharmony_ci		.mask = 0x7,
1598c2ecf20Sopenharmony_ci		.shift = 10,
1608c2ecf20Sopenharmony_ci		.table = (u32[]){ 1, 2, 3, 4 },
1618c2ecf20Sopenharmony_ci		.flags = CLK_MUX_ROUND_CLOSEST,
1628c2ecf20Sopenharmony_ci	},
1638c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
1648c2ecf20Sopenharmony_ci		.name = "ao_cts_rtc_oscin",
1658c2ecf20Sopenharmony_ci		.ops = &clk_regmap_mux_ops,
1668c2ecf20Sopenharmony_ci		.parent_data = (const struct clk_parent_data []) {
1678c2ecf20Sopenharmony_ci			{ .fw_name = "ext-32k-0", },
1688c2ecf20Sopenharmony_ci			{ .fw_name = "ext-32k-1", },
1698c2ecf20Sopenharmony_ci			{ .fw_name = "ext-32k-2", },
1708c2ecf20Sopenharmony_ci			{ .hw = &ao_32k.hw },
1718c2ecf20Sopenharmony_ci		},
1728c2ecf20Sopenharmony_ci		.num_parents = 4,
1738c2ecf20Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT,
1748c2ecf20Sopenharmony_ci	},
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic struct clk_regmap ao_clk81 = {
1788c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_mux_data) {
1798c2ecf20Sopenharmony_ci		.offset = AO_RTI_PWR_CNTL_REG0,
1808c2ecf20Sopenharmony_ci		.mask = 0x1,
1818c2ecf20Sopenharmony_ci		.shift = 0,
1828c2ecf20Sopenharmony_ci		.flags = CLK_MUX_ROUND_CLOSEST,
1838c2ecf20Sopenharmony_ci	},
1848c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
1858c2ecf20Sopenharmony_ci		.name = "ao_clk81",
1868c2ecf20Sopenharmony_ci		.ops = &clk_regmap_mux_ro_ops,
1878c2ecf20Sopenharmony_ci		.parent_data = (const struct clk_parent_data []) {
1888c2ecf20Sopenharmony_ci			{ .fw_name = "mpeg-clk", },
1898c2ecf20Sopenharmony_ci			{ .hw = &ao_cts_rtc_oscin.hw },
1908c2ecf20Sopenharmony_ci		},
1918c2ecf20Sopenharmony_ci		.num_parents = 2,
1928c2ecf20Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT,
1938c2ecf20Sopenharmony_ci	},
1948c2ecf20Sopenharmony_ci};
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_cistatic struct clk_regmap ao_cts_cec = {
1978c2ecf20Sopenharmony_ci	.data = &(struct clk_regmap_mux_data) {
1988c2ecf20Sopenharmony_ci		.offset = AO_CRT_CLK_CNTL1,
1998c2ecf20Sopenharmony_ci		.mask = 0x1,
2008c2ecf20Sopenharmony_ci		.shift = 27,
2018c2ecf20Sopenharmony_ci		.flags = CLK_MUX_ROUND_CLOSEST,
2028c2ecf20Sopenharmony_ci	},
2038c2ecf20Sopenharmony_ci	.hw.init = &(struct clk_init_data){
2048c2ecf20Sopenharmony_ci		.name = "ao_cts_cec",
2058c2ecf20Sopenharmony_ci		.ops = &clk_regmap_mux_ops,
2068c2ecf20Sopenharmony_ci		/*
2078c2ecf20Sopenharmony_ci		 * FIXME: The 'fixme' parent obviously does not exist.
2088c2ecf20Sopenharmony_ci		 *
2098c2ecf20Sopenharmony_ci		 * ATM, CCF won't call get_parent() if num_parents is 1. It
2108c2ecf20Sopenharmony_ci		 * does not allow NULL as a parent name either.
2118c2ecf20Sopenharmony_ci		 *
2128c2ecf20Sopenharmony_ci		 * On this particular mux, we only know the input #1 parent
2138c2ecf20Sopenharmony_ci		 * but, on boot, unknown input #0 is set, so it is critical
2148c2ecf20Sopenharmony_ci		 * to call .get_parent() on it
2158c2ecf20Sopenharmony_ci		 *
2168c2ecf20Sopenharmony_ci		 * Until CCF gets fixed, adding this fake parent that won't
2178c2ecf20Sopenharmony_ci		 * ever be registered should work around the problem
2188c2ecf20Sopenharmony_ci		 */
2198c2ecf20Sopenharmony_ci		.parent_data = (const struct clk_parent_data []) {
2208c2ecf20Sopenharmony_ci			{ .name = "fixme", .index = -1, },
2218c2ecf20Sopenharmony_ci			{ .hw = &ao_cts_rtc_oscin.hw },
2228c2ecf20Sopenharmony_ci		},
2238c2ecf20Sopenharmony_ci		.num_parents = 2,
2248c2ecf20Sopenharmony_ci		.flags = CLK_SET_RATE_PARENT,
2258c2ecf20Sopenharmony_ci	},
2268c2ecf20Sopenharmony_ci};
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_cistatic const unsigned int gxbb_aoclk_reset[] = {
2298c2ecf20Sopenharmony_ci	[RESET_AO_REMOTE] = 16,
2308c2ecf20Sopenharmony_ci	[RESET_AO_I2C_MASTER] = 18,
2318c2ecf20Sopenharmony_ci	[RESET_AO_I2C_SLAVE] = 19,
2328c2ecf20Sopenharmony_ci	[RESET_AO_UART1] = 17,
2338c2ecf20Sopenharmony_ci	[RESET_AO_UART2] = 22,
2348c2ecf20Sopenharmony_ci	[RESET_AO_IR_BLASTER] = 23,
2358c2ecf20Sopenharmony_ci};
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic struct clk_regmap *gxbb_aoclk[] = {
2388c2ecf20Sopenharmony_ci	&remote_ao,
2398c2ecf20Sopenharmony_ci	&i2c_master_ao,
2408c2ecf20Sopenharmony_ci	&i2c_slave_ao,
2418c2ecf20Sopenharmony_ci	&uart1_ao,
2428c2ecf20Sopenharmony_ci	&uart2_ao,
2438c2ecf20Sopenharmony_ci	&ir_blaster_ao,
2448c2ecf20Sopenharmony_ci	&ao_cts_oscin,
2458c2ecf20Sopenharmony_ci	&ao_32k_pre,
2468c2ecf20Sopenharmony_ci	&ao_32k_div,
2478c2ecf20Sopenharmony_ci	&ao_32k_sel,
2488c2ecf20Sopenharmony_ci	&ao_32k,
2498c2ecf20Sopenharmony_ci	&ao_cts_rtc_oscin,
2508c2ecf20Sopenharmony_ci	&ao_clk81,
2518c2ecf20Sopenharmony_ci	&ao_cts_cec,
2528c2ecf20Sopenharmony_ci};
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic const struct clk_hw_onecell_data gxbb_aoclk_onecell_data = {
2558c2ecf20Sopenharmony_ci	.hws = {
2568c2ecf20Sopenharmony_ci		[CLKID_AO_REMOTE] = &remote_ao.hw,
2578c2ecf20Sopenharmony_ci		[CLKID_AO_I2C_MASTER] = &i2c_master_ao.hw,
2588c2ecf20Sopenharmony_ci		[CLKID_AO_I2C_SLAVE] = &i2c_slave_ao.hw,
2598c2ecf20Sopenharmony_ci		[CLKID_AO_UART1] = &uart1_ao.hw,
2608c2ecf20Sopenharmony_ci		[CLKID_AO_UART2] = &uart2_ao.hw,
2618c2ecf20Sopenharmony_ci		[CLKID_AO_IR_BLASTER] = &ir_blaster_ao.hw,
2628c2ecf20Sopenharmony_ci		[CLKID_AO_CEC_32K] = &ao_cts_cec.hw,
2638c2ecf20Sopenharmony_ci		[CLKID_AO_CTS_OSCIN] = &ao_cts_oscin.hw,
2648c2ecf20Sopenharmony_ci		[CLKID_AO_32K_PRE] = &ao_32k_pre.hw,
2658c2ecf20Sopenharmony_ci		[CLKID_AO_32K_DIV] = &ao_32k_div.hw,
2668c2ecf20Sopenharmony_ci		[CLKID_AO_32K_SEL] = &ao_32k_sel.hw,
2678c2ecf20Sopenharmony_ci		[CLKID_AO_32K] = &ao_32k.hw,
2688c2ecf20Sopenharmony_ci		[CLKID_AO_CTS_RTC_OSCIN] = &ao_cts_rtc_oscin.hw,
2698c2ecf20Sopenharmony_ci		[CLKID_AO_CLK81] = &ao_clk81.hw,
2708c2ecf20Sopenharmony_ci	},
2718c2ecf20Sopenharmony_ci	.num = NR_CLKS,
2728c2ecf20Sopenharmony_ci};
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cistatic const struct meson_aoclk_data gxbb_aoclkc_data = {
2758c2ecf20Sopenharmony_ci	.reset_reg	= AO_RTI_GEN_CNTL_REG0,
2768c2ecf20Sopenharmony_ci	.num_reset	= ARRAY_SIZE(gxbb_aoclk_reset),
2778c2ecf20Sopenharmony_ci	.reset		= gxbb_aoclk_reset,
2788c2ecf20Sopenharmony_ci	.num_clks	= ARRAY_SIZE(gxbb_aoclk),
2798c2ecf20Sopenharmony_ci	.clks		= gxbb_aoclk,
2808c2ecf20Sopenharmony_ci	.hw_data	= &gxbb_aoclk_onecell_data,
2818c2ecf20Sopenharmony_ci};
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_cistatic const struct of_device_id gxbb_aoclkc_match_table[] = {
2848c2ecf20Sopenharmony_ci	{
2858c2ecf20Sopenharmony_ci		.compatible	= "amlogic,meson-gx-aoclkc",
2868c2ecf20Sopenharmony_ci		.data		= &gxbb_aoclkc_data,
2878c2ecf20Sopenharmony_ci	},
2888c2ecf20Sopenharmony_ci	{ }
2898c2ecf20Sopenharmony_ci};
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_cistatic struct platform_driver gxbb_aoclkc_driver = {
2928c2ecf20Sopenharmony_ci	.probe		= meson_aoclkc_probe,
2938c2ecf20Sopenharmony_ci	.driver		= {
2948c2ecf20Sopenharmony_ci		.name	= "gxbb-aoclkc",
2958c2ecf20Sopenharmony_ci		.of_match_table = gxbb_aoclkc_match_table,
2968c2ecf20Sopenharmony_ci	},
2978c2ecf20Sopenharmony_ci};
2988c2ecf20Sopenharmony_cibuiltin_platform_driver(gxbb_aoclkc_driver);
299