brintos

brintos / linux-shallow public Read only

0
0
Text · 12.0 KiB · f0a18d8 Raw
481 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Amlogic Meson-AXG Clock Controller Driver4 *5 * Copyright (c) 2016 Baylibre SAS.6 * Author: Michael Turquette <mturquette@baylibre.com>7 *8 * Copyright (c) 2019 Baylibre SAS.9 * Author: Neil Armstrong <narmstrong@baylibre.com>10 */11#include <linux/clk-provider.h>12#include <linux/platform_device.h>13#include <linux/reset-controller.h>14#include <linux/mfd/syscon.h>15#include <linux/module.h>16#include "meson-aoclk.h"17 18#include "clk-regmap.h"19#include "clk-dualdiv.h"20 21#include <dt-bindings/clock/g12a-aoclkc.h>22#include <dt-bindings/reset/g12a-aoclkc.h>23 24/*25 * AO Configuration Clock registers offsets26 * Register offsets from the data sheet must be multiplied by 4.27 */28#define AO_RTI_STATUS_REG3	0x0C29#define AO_RTI_PWR_CNTL_REG0	0x1030#define AO_RTI_GEN_CNTL_REG0	0x4031#define AO_CLK_GATE0		0x4c32#define AO_CLK_GATE0_SP		0x5033#define AO_OSCIN_CNTL		0x5834#define AO_CEC_CLK_CNTL_REG0	0x7435#define AO_CEC_CLK_CNTL_REG1	0x7836#define AO_SAR_CLK		0x9037#define AO_RTC_ALT_CLK_CNTL0	0x9438#define AO_RTC_ALT_CLK_CNTL1	0x9839 40/*41 * Like every other peripheral clock gate in Amlogic Clock drivers,42 * we are using CLK_IGNORE_UNUSED here, so we keep the state of the43 * bootloader. The goal is to remove this flag at some point.44 * Actually removing it will require some extensive test to be done safely.45 */46#define AXG_AO_GATE(_name, _reg, _bit)					\47static struct clk_regmap g12a_aoclk_##_name = {				\48	.data = &(struct clk_regmap_gate_data) {			\49		.offset = (_reg),					\50		.bit_idx = (_bit),					\51	},								\52	.hw.init = &(struct clk_init_data) {				\53		.name =  "g12a_ao_" #_name,				\54		.ops = &clk_regmap_gate_ops,				\55		.parent_data = &(const struct clk_parent_data) {	\56			.fw_name = "mpeg-clk",				\57		},							\58		.num_parents = 1,					\59		.flags = CLK_IGNORE_UNUSED,				\60	},								\61}62 63AXG_AO_GATE(ahb, AO_CLK_GATE0, 0);64AXG_AO_GATE(ir_in, AO_CLK_GATE0, 1);65AXG_AO_GATE(i2c_m0, AO_CLK_GATE0, 2);66AXG_AO_GATE(i2c_s0, AO_CLK_GATE0, 3);67AXG_AO_GATE(uart, AO_CLK_GATE0, 4);68AXG_AO_GATE(prod_i2c, AO_CLK_GATE0, 5);69AXG_AO_GATE(uart2, AO_CLK_GATE0, 6);70AXG_AO_GATE(ir_out, AO_CLK_GATE0, 7);71AXG_AO_GATE(saradc, AO_CLK_GATE0, 8);72AXG_AO_GATE(mailbox, AO_CLK_GATE0_SP, 0);73AXG_AO_GATE(m3, AO_CLK_GATE0_SP, 1);74AXG_AO_GATE(ahb_sram, AO_CLK_GATE0_SP, 2);75AXG_AO_GATE(rti, AO_CLK_GATE0_SP, 3);76AXG_AO_GATE(m4_fclk, AO_CLK_GATE0_SP, 4);77AXG_AO_GATE(m4_hclk, AO_CLK_GATE0_SP, 5);78 79static struct clk_regmap g12a_aoclk_cts_oscin = {80	.data = &(struct clk_regmap_gate_data){81		.offset = AO_RTI_PWR_CNTL_REG0,82		.bit_idx = 14,83	},84	.hw.init = &(struct clk_init_data){85		.name = "cts_oscin",86		.ops = &clk_regmap_gate_ro_ops,87		.parent_data = &(const struct clk_parent_data) {88			.fw_name = "xtal",89		},90		.num_parents = 1,91	},92};93 94static const struct meson_clk_dualdiv_param g12a_32k_div_table[] = {95	{96		.dual	= 1,97		.n1	= 733,98		.m1	= 8,99		.n2	= 732,100		.m2	= 11,101	}, {}102};103 104/* 32k_by_oscin clock */105 106static struct clk_regmap g12a_aoclk_32k_by_oscin_pre = {107	.data = &(struct clk_regmap_gate_data){108		.offset = AO_RTC_ALT_CLK_CNTL0,109		.bit_idx = 31,110	},111	.hw.init = &(struct clk_init_data){112		.name = "g12a_ao_32k_by_oscin_pre",113		.ops = &clk_regmap_gate_ops,114		.parent_hws = (const struct clk_hw *[]) {115			&g12a_aoclk_cts_oscin.hw116		},117		.num_parents = 1,118	},119};120 121static struct clk_regmap g12a_aoclk_32k_by_oscin_div = {122	.data = &(struct meson_clk_dualdiv_data){123		.n1 = {124			.reg_off = AO_RTC_ALT_CLK_CNTL0,125			.shift   = 0,126			.width   = 12,127		},128		.n2 = {129			.reg_off = AO_RTC_ALT_CLK_CNTL0,130			.shift   = 12,131			.width   = 12,132		},133		.m1 = {134			.reg_off = AO_RTC_ALT_CLK_CNTL1,135			.shift   = 0,136			.width   = 12,137		},138		.m2 = {139			.reg_off = AO_RTC_ALT_CLK_CNTL1,140			.shift   = 12,141			.width   = 12,142		},143		.dual = {144			.reg_off = AO_RTC_ALT_CLK_CNTL0,145			.shift   = 28,146			.width   = 1,147		},148		.table = g12a_32k_div_table,149	},150	.hw.init = &(struct clk_init_data){151		.name = "g12a_ao_32k_by_oscin_div",152		.ops = &meson_clk_dualdiv_ops,153		.parent_hws = (const struct clk_hw *[]) {154			&g12a_aoclk_32k_by_oscin_pre.hw155		},156		.num_parents = 1,157	},158};159 160static struct clk_regmap g12a_aoclk_32k_by_oscin_sel = {161	.data = &(struct clk_regmap_mux_data) {162		.offset = AO_RTC_ALT_CLK_CNTL1,163		.mask = 0x1,164		.shift = 24,165		.flags = CLK_MUX_ROUND_CLOSEST,166	},167	.hw.init = &(struct clk_init_data){168		.name = "g12a_ao_32k_by_oscin_sel",169		.ops = &clk_regmap_mux_ops,170		.parent_hws = (const struct clk_hw *[]) {171			&g12a_aoclk_32k_by_oscin_div.hw,172			&g12a_aoclk_32k_by_oscin_pre.hw,173		},174		.num_parents = 2,175		.flags = CLK_SET_RATE_PARENT,176	},177};178 179static struct clk_regmap g12a_aoclk_32k_by_oscin = {180	.data = &(struct clk_regmap_gate_data){181		.offset = AO_RTC_ALT_CLK_CNTL0,182		.bit_idx = 30,183	},184	.hw.init = &(struct clk_init_data){185		.name = "g12a_ao_32k_by_oscin",186		.ops = &clk_regmap_gate_ops,187		.parent_hws = (const struct clk_hw *[]) {188			&g12a_aoclk_32k_by_oscin_sel.hw189		},190		.num_parents = 1,191		.flags = CLK_SET_RATE_PARENT,192	},193};194 195/* cec clock */196 197static struct clk_regmap g12a_aoclk_cec_pre = {198	.data = &(struct clk_regmap_gate_data){199		.offset = AO_CEC_CLK_CNTL_REG0,200		.bit_idx = 31,201	},202	.hw.init = &(struct clk_init_data){203		.name = "g12a_ao_cec_pre",204		.ops = &clk_regmap_gate_ops,205		.parent_hws = (const struct clk_hw *[]) {206			&g12a_aoclk_cts_oscin.hw207		},208		.num_parents = 1,209	},210};211 212static struct clk_regmap g12a_aoclk_cec_div = {213	.data = &(struct meson_clk_dualdiv_data){214		.n1 = {215			.reg_off = AO_CEC_CLK_CNTL_REG0,216			.shift   = 0,217			.width   = 12,218		},219		.n2 = {220			.reg_off = AO_CEC_CLK_CNTL_REG0,221			.shift   = 12,222			.width   = 12,223		},224		.m1 = {225			.reg_off = AO_CEC_CLK_CNTL_REG1,226			.shift   = 0,227			.width   = 12,228		},229		.m2 = {230			.reg_off = AO_CEC_CLK_CNTL_REG1,231			.shift   = 12,232			.width   = 12,233		},234		.dual = {235			.reg_off = AO_CEC_CLK_CNTL_REG0,236			.shift   = 28,237			.width   = 1,238		},239		.table = g12a_32k_div_table,240	},241	.hw.init = &(struct clk_init_data){242		.name = "g12a_ao_cec_div",243		.ops = &meson_clk_dualdiv_ops,244		.parent_hws = (const struct clk_hw *[]) {245			&g12a_aoclk_cec_pre.hw246		},247		.num_parents = 1,248	},249};250 251static struct clk_regmap g12a_aoclk_cec_sel = {252	.data = &(struct clk_regmap_mux_data) {253		.offset = AO_CEC_CLK_CNTL_REG1,254		.mask = 0x1,255		.shift = 24,256		.flags = CLK_MUX_ROUND_CLOSEST,257	},258	.hw.init = &(struct clk_init_data){259		.name = "g12a_ao_cec_sel",260		.ops = &clk_regmap_mux_ops,261		.parent_hws = (const struct clk_hw *[]) {262			&g12a_aoclk_cec_div.hw,263			&g12a_aoclk_cec_pre.hw,264		},265		.num_parents = 2,266		.flags = CLK_SET_RATE_PARENT,267	},268};269 270static struct clk_regmap g12a_aoclk_cec = {271	.data = &(struct clk_regmap_gate_data){272		.offset = AO_CEC_CLK_CNTL_REG0,273		.bit_idx = 30,274	},275	.hw.init = &(struct clk_init_data){276		.name = "g12a_ao_cec",277		.ops = &clk_regmap_gate_ops,278		.parent_hws = (const struct clk_hw *[]) {279			&g12a_aoclk_cec_sel.hw280		},281		.num_parents = 1,282		.flags = CLK_SET_RATE_PARENT,283	},284};285 286static struct clk_regmap g12a_aoclk_cts_rtc_oscin = {287	.data = &(struct clk_regmap_mux_data) {288		.offset = AO_RTI_PWR_CNTL_REG0,289		.mask = 0x1,290		.shift = 10,291		.flags = CLK_MUX_ROUND_CLOSEST,292	},293	.hw.init = &(struct clk_init_data){294		.name = "g12a_ao_cts_rtc_oscin",295		.ops = &clk_regmap_mux_ops,296		.parent_data = (const struct clk_parent_data []) {297			{ .hw = &g12a_aoclk_32k_by_oscin.hw },298			{ .fw_name = "ext-32k-0", },299		},300		.num_parents = 2,301		.flags = CLK_SET_RATE_PARENT,302	},303};304 305static struct clk_regmap g12a_aoclk_clk81 = {306	.data = &(struct clk_regmap_mux_data) {307		.offset = AO_RTI_PWR_CNTL_REG0,308		.mask = 0x1,309		.shift = 8,310		.flags = CLK_MUX_ROUND_CLOSEST,311	},312	.hw.init = &(struct clk_init_data){313		.name = "g12a_ao_clk81",314		.ops = &clk_regmap_mux_ro_ops,315		.parent_data = (const struct clk_parent_data []) {316			{ .fw_name = "mpeg-clk", },317			{ .hw = &g12a_aoclk_cts_rtc_oscin.hw },318		},319		.num_parents = 2,320		.flags = CLK_SET_RATE_PARENT,321	},322};323 324static struct clk_regmap g12a_aoclk_saradc_mux = {325	.data = &(struct clk_regmap_mux_data) {326		.offset = AO_SAR_CLK,327		.mask = 0x3,328		.shift = 9,329	},330	.hw.init = &(struct clk_init_data){331		.name = "g12a_ao_saradc_mux",332		.ops = &clk_regmap_mux_ops,333		.parent_data = (const struct clk_parent_data []) {334			{ .fw_name = "xtal", },335			{ .hw = &g12a_aoclk_clk81.hw },336		},337		.num_parents = 2,338	},339};340 341static struct clk_regmap g12a_aoclk_saradc_div = {342	.data = &(struct clk_regmap_div_data) {343		.offset = AO_SAR_CLK,344		.shift = 0,345		.width = 8,346	},347	.hw.init = &(struct clk_init_data){348		.name = "g12a_ao_saradc_div",349		.ops = &clk_regmap_divider_ops,350		.parent_hws = (const struct clk_hw *[]) {351			&g12a_aoclk_saradc_mux.hw352		},353		.num_parents = 1,354		.flags = CLK_SET_RATE_PARENT,355	},356};357 358static struct clk_regmap g12a_aoclk_saradc_gate = {359	.data = &(struct clk_regmap_gate_data) {360		.offset = AO_SAR_CLK,361		.bit_idx = 8,362	},363	.hw.init = &(struct clk_init_data){364		.name = "g12a_ao_saradc_gate",365		.ops = &clk_regmap_gate_ops,366		.parent_hws = (const struct clk_hw *[]) {367			&g12a_aoclk_saradc_div.hw368		},369		.num_parents = 1,370		.flags = CLK_SET_RATE_PARENT,371	},372};373 374static const unsigned int g12a_aoclk_reset[] = {375	[RESET_AO_IR_IN]	= 16,376	[RESET_AO_UART]		= 17,377	[RESET_AO_I2C_M]	= 18,378	[RESET_AO_I2C_S]	= 19,379	[RESET_AO_SAR_ADC]	= 20,380	[RESET_AO_UART2]	= 22,381	[RESET_AO_IR_OUT]	= 23,382};383 384static struct clk_regmap *g12a_aoclk_regmap[] = {385	&g12a_aoclk_ahb,386	&g12a_aoclk_ir_in,387	&g12a_aoclk_i2c_m0,388	&g12a_aoclk_i2c_s0,389	&g12a_aoclk_uart,390	&g12a_aoclk_prod_i2c,391	&g12a_aoclk_uart2,392	&g12a_aoclk_ir_out,393	&g12a_aoclk_saradc,394	&g12a_aoclk_mailbox,395	&g12a_aoclk_m3,396	&g12a_aoclk_ahb_sram,397	&g12a_aoclk_rti,398	&g12a_aoclk_m4_fclk,399	&g12a_aoclk_m4_hclk,400	&g12a_aoclk_cts_oscin,401	&g12a_aoclk_32k_by_oscin_pre,402	&g12a_aoclk_32k_by_oscin_div,403	&g12a_aoclk_32k_by_oscin_sel,404	&g12a_aoclk_32k_by_oscin,405	&g12a_aoclk_cec_pre,406	&g12a_aoclk_cec_div,407	&g12a_aoclk_cec_sel,408	&g12a_aoclk_cec,409	&g12a_aoclk_cts_rtc_oscin,410	&g12a_aoclk_clk81,411	&g12a_aoclk_saradc_mux,412	&g12a_aoclk_saradc_div,413	&g12a_aoclk_saradc_gate,414};415 416static struct clk_hw *g12a_aoclk_hw_clks[] = {417	[CLKID_AO_AHB]		= &g12a_aoclk_ahb.hw,418	[CLKID_AO_IR_IN]	= &g12a_aoclk_ir_in.hw,419	[CLKID_AO_I2C_M0]	= &g12a_aoclk_i2c_m0.hw,420	[CLKID_AO_I2C_S0]	= &g12a_aoclk_i2c_s0.hw,421	[CLKID_AO_UART]		= &g12a_aoclk_uart.hw,422	[CLKID_AO_PROD_I2C]	= &g12a_aoclk_prod_i2c.hw,423	[CLKID_AO_UART2]	= &g12a_aoclk_uart2.hw,424	[CLKID_AO_IR_OUT]	= &g12a_aoclk_ir_out.hw,425	[CLKID_AO_SAR_ADC]	= &g12a_aoclk_saradc.hw,426	[CLKID_AO_MAILBOX]	= &g12a_aoclk_mailbox.hw,427	[CLKID_AO_M3]		= &g12a_aoclk_m3.hw,428	[CLKID_AO_AHB_SRAM]	= &g12a_aoclk_ahb_sram.hw,429	[CLKID_AO_RTI]		= &g12a_aoclk_rti.hw,430	[CLKID_AO_M4_FCLK]	= &g12a_aoclk_m4_fclk.hw,431	[CLKID_AO_M4_HCLK]	= &g12a_aoclk_m4_hclk.hw,432	[CLKID_AO_CLK81]	= &g12a_aoclk_clk81.hw,433	[CLKID_AO_SAR_ADC_SEL]	= &g12a_aoclk_saradc_mux.hw,434	[CLKID_AO_SAR_ADC_DIV]	= &g12a_aoclk_saradc_div.hw,435	[CLKID_AO_SAR_ADC_CLK]	= &g12a_aoclk_saradc_gate.hw,436	[CLKID_AO_CTS_OSCIN]	= &g12a_aoclk_cts_oscin.hw,437	[CLKID_AO_32K_PRE]	= &g12a_aoclk_32k_by_oscin_pre.hw,438	[CLKID_AO_32K_DIV]	= &g12a_aoclk_32k_by_oscin_div.hw,439	[CLKID_AO_32K_SEL]	= &g12a_aoclk_32k_by_oscin_sel.hw,440	[CLKID_AO_32K]		= &g12a_aoclk_32k_by_oscin.hw,441	[CLKID_AO_CEC_PRE]	= &g12a_aoclk_cec_pre.hw,442	[CLKID_AO_CEC_DIV]	= &g12a_aoclk_cec_div.hw,443	[CLKID_AO_CEC_SEL]	= &g12a_aoclk_cec_sel.hw,444	[CLKID_AO_CEC]		= &g12a_aoclk_cec.hw,445	[CLKID_AO_CTS_RTC_OSCIN] = &g12a_aoclk_cts_rtc_oscin.hw,446};447 448static const struct meson_aoclk_data g12a_aoclkc_data = {449	.reset_reg	= AO_RTI_GEN_CNTL_REG0,450	.num_reset	= ARRAY_SIZE(g12a_aoclk_reset),451	.reset		= g12a_aoclk_reset,452	.num_clks	= ARRAY_SIZE(g12a_aoclk_regmap),453	.clks		= g12a_aoclk_regmap,454	.hw_clks	= {455		.hws	= g12a_aoclk_hw_clks,456		.num	= ARRAY_SIZE(g12a_aoclk_hw_clks),457	},458};459 460static const struct of_device_id g12a_aoclkc_match_table[] = {461	{462		.compatible	= "amlogic,meson-g12a-aoclkc",463		.data		= &g12a_aoclkc_data,464	},465	{ }466};467MODULE_DEVICE_TABLE(of, g12a_aoclkc_match_table);468 469static struct platform_driver g12a_aoclkc_driver = {470	.probe		= meson_aoclkc_probe,471	.driver		= {472		.name	= "g12a-aoclkc",473		.of_match_table = g12a_aoclkc_match_table,474	},475};476module_platform_driver(g12a_aoclkc_driver);477 478MODULE_DESCRIPTION("Amlogic G12A Always-ON Clock Controller driver");479MODULE_LICENSE("GPL");480MODULE_IMPORT_NS(CLK_MESON);481