forked from mirrors/linux
		
	 8b9844d7e8
			
		
	
	
		8b9844d7e8
		
	
	
	
	
		
			
			Based on 1 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details you should have received a copy of the gnu general public license along with this program if not write to the free software foundation extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 2 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Steve Winslow <swinslow@gmail.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Reviewed-by: Jilayne Lovejoy <opensource@jilayne.com> Reviewed-by: Allison Randal <allison@lohutok.net> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190519154042.615184352@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
		
			
				
	
	
		
			233 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			233 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (C) 2012 Sascha Hauer <kernel@pengutronix.de>
 | |
|  */
 | |
| 
 | |
| #include <linux/module.h>
 | |
| #include <linux/clk.h>
 | |
| #include <linux/clkdev.h>
 | |
| #include <linux/io.h>
 | |
| #include <linux/err.h>
 | |
| #include <linux/of.h>
 | |
| #include <linux/of_address.h>
 | |
| #include <soc/imx/revision.h>
 | |
| #include <soc/imx/timer.h>
 | |
| #include <asm/irq.h>
 | |
| 
 | |
| #include "clk.h"
 | |
| 
 | |
| #define MX31_CCM_BASE_ADDR	0x53f80000
 | |
| #define MX31_GPT1_BASE_ADDR	0x53f90000
 | |
| #define MX31_INT_GPT		(NR_IRQS_LEGACY + 29)
 | |
| 
 | |
| #define MXC_CCM_CCMR		0x00
 | |
| #define MXC_CCM_PDR0		0x04
 | |
| #define MXC_CCM_PDR1		0x08
 | |
| #define MXC_CCM_MPCTL		0x10
 | |
| #define MXC_CCM_UPCTL		0x14
 | |
| #define MXC_CCM_SRPCTL		0x18
 | |
| #define MXC_CCM_CGR0		0x20
 | |
| #define MXC_CCM_CGR1		0x24
 | |
| #define MXC_CCM_CGR2		0x28
 | |
| #define MXC_CCM_PMCR0		0x5c
 | |
| 
 | |
| static const char *mcu_main_sel[] = { "spll", "mpll", };
 | |
| static const char *per_sel[] = { "per_div", "ipg", };
 | |
| static const char *csi_sel[] = { "upll", "spll", };
 | |
| static const char *fir_sel[] = { "mcu_main", "upll", "spll" };
 | |
| 
 | |
| enum mx31_clks {
 | |
| 	dummy, ckih, ckil, mpll, spll, upll, mcu_main, hsp, ahb, nfc, ipg,
 | |
| 	per_div, per, csi, fir, csi_div, usb_div_pre, usb_div_post, fir_div_pre,
 | |
| 	fir_div_post, sdhc1_gate, sdhc2_gate, gpt_gate, epit1_gate, epit2_gate,
 | |
| 	iim_gate, ata_gate, sdma_gate, cspi3_gate, rng_gate, uart1_gate,
 | |
| 	uart2_gate, ssi1_gate, i2c1_gate, i2c2_gate, i2c3_gate, hantro_gate,
 | |
| 	mstick1_gate, mstick2_gate, csi_gate, rtc_gate, wdog_gate, pwm_gate,
 | |
| 	sim_gate, ect_gate, usb_gate, kpp_gate, ipu_gate, uart3_gate,
 | |
| 	uart4_gate, uart5_gate, owire_gate, ssi2_gate, cspi1_gate, cspi2_gate,
 | |
| 	gacc_gate, emi_gate, rtic_gate, firi_gate, clk_max
 | |
| };
 | |
| 
 | |
| static struct clk *clk[clk_max];
 | |
| static struct clk_onecell_data clk_data;
 | |
| 
 | |
| static struct clk ** const uart_clks[] __initconst = {
 | |
| 	&clk[ipg],
 | |
| 	&clk[uart1_gate],
 | |
| 	&clk[uart2_gate],
 | |
| 	&clk[uart3_gate],
 | |
| 	&clk[uart4_gate],
 | |
| 	&clk[uart5_gate],
 | |
| 	NULL
 | |
| };
 | |
| 
 | |
| static void __init _mx31_clocks_init(void __iomem *base, unsigned long fref)
 | |
| {
 | |
| 	clk[dummy] = imx_clk_fixed("dummy", 0);
 | |
| 	clk[ckih] = imx_clk_fixed("ckih", fref);
 | |
| 	clk[ckil] = imx_clk_fixed("ckil", 32768);
 | |
| 	clk[mpll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "mpll", "ckih", base + MXC_CCM_MPCTL);
 | |
| 	clk[spll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "spll", "ckih", base + MXC_CCM_SRPCTL);
 | |
| 	clk[upll] = imx_clk_pllv1(IMX_PLLV1_IMX31, "upll", "ckih", base + MXC_CCM_UPCTL);
 | |
| 	clk[mcu_main] = imx_clk_mux("mcu_main", base + MXC_CCM_PMCR0, 31, 1, mcu_main_sel, ARRAY_SIZE(mcu_main_sel));
 | |
| 	clk[hsp] = imx_clk_divider("hsp", "mcu_main", base + MXC_CCM_PDR0, 11, 3);
 | |
| 	clk[ahb] = imx_clk_divider("ahb", "mcu_main", base + MXC_CCM_PDR0, 3, 3);
 | |
| 	clk[nfc] = imx_clk_divider("nfc", "ahb", base + MXC_CCM_PDR0, 8, 3);
 | |
| 	clk[ipg] = imx_clk_divider("ipg", "ahb", base + MXC_CCM_PDR0, 6, 2);
 | |
| 	clk[per_div] = imx_clk_divider("per_div", "upll", base + MXC_CCM_PDR0, 16, 5);
 | |
| 	clk[per] = imx_clk_mux("per", base + MXC_CCM_CCMR, 24, 1, per_sel, ARRAY_SIZE(per_sel));
 | |
| 	clk[csi] = imx_clk_mux("csi_sel", base + MXC_CCM_CCMR, 25, 1, csi_sel, ARRAY_SIZE(csi_sel));
 | |
| 	clk[fir] = imx_clk_mux("fir_sel", base + MXC_CCM_CCMR, 11, 2, fir_sel, ARRAY_SIZE(fir_sel));
 | |
| 	clk[csi_div] = imx_clk_divider("csi_div", "csi_sel", base + MXC_CCM_PDR0, 23, 9);
 | |
| 	clk[usb_div_pre] = imx_clk_divider("usb_div_pre", "upll", base + MXC_CCM_PDR1, 30, 2);
 | |
| 	clk[usb_div_post] = imx_clk_divider("usb_div_post", "usb_div_pre", base + MXC_CCM_PDR1, 27, 3);
 | |
| 	clk[fir_div_pre] = imx_clk_divider("fir_div_pre", "fir_sel", base + MXC_CCM_PDR1, 24, 3);
 | |
| 	clk[fir_div_post] = imx_clk_divider("fir_div_post", "fir_div_pre", base + MXC_CCM_PDR1, 23, 6);
 | |
| 	clk[sdhc1_gate] = imx_clk_gate2("sdhc1_gate", "per", base + MXC_CCM_CGR0, 0);
 | |
| 	clk[sdhc2_gate] = imx_clk_gate2("sdhc2_gate", "per", base + MXC_CCM_CGR0, 2);
 | |
| 	clk[gpt_gate] = imx_clk_gate2("gpt_gate", "per", base + MXC_CCM_CGR0, 4);
 | |
| 	clk[epit1_gate] = imx_clk_gate2("epit1_gate", "per", base + MXC_CCM_CGR0, 6);
 | |
| 	clk[epit2_gate] = imx_clk_gate2("epit2_gate", "per", base + MXC_CCM_CGR0, 8);
 | |
| 	clk[iim_gate] = imx_clk_gate2("iim_gate", "ipg", base + MXC_CCM_CGR0, 10);
 | |
| 	clk[ata_gate] = imx_clk_gate2("ata_gate", "ipg", base + MXC_CCM_CGR0, 12);
 | |
| 	clk[sdma_gate] = imx_clk_gate2("sdma_gate", "ahb", base + MXC_CCM_CGR0, 14);
 | |
| 	clk[cspi3_gate] = imx_clk_gate2("cspi3_gate", "ipg", base + MXC_CCM_CGR0, 16);
 | |
| 	clk[rng_gate] = imx_clk_gate2("rng_gate", "ipg", base + MXC_CCM_CGR0, 18);
 | |
| 	clk[uart1_gate] = imx_clk_gate2("uart1_gate", "per", base + MXC_CCM_CGR0, 20);
 | |
| 	clk[uart2_gate] = imx_clk_gate2("uart2_gate", "per", base + MXC_CCM_CGR0, 22);
 | |
| 	clk[ssi1_gate] = imx_clk_gate2("ssi1_gate", "spll", base + MXC_CCM_CGR0, 24);
 | |
| 	clk[i2c1_gate] = imx_clk_gate2("i2c1_gate", "per", base + MXC_CCM_CGR0, 26);
 | |
| 	clk[i2c2_gate] = imx_clk_gate2("i2c2_gate", "per", base + MXC_CCM_CGR0, 28);
 | |
| 	clk[i2c3_gate] = imx_clk_gate2("i2c3_gate", "per", base + MXC_CCM_CGR0, 30);
 | |
| 	clk[hantro_gate] = imx_clk_gate2("hantro_gate", "per", base + MXC_CCM_CGR1, 0);
 | |
| 	clk[mstick1_gate] = imx_clk_gate2("mstick1_gate", "per", base + MXC_CCM_CGR1, 2);
 | |
| 	clk[mstick2_gate] = imx_clk_gate2("mstick2_gate", "per", base + MXC_CCM_CGR1, 4);
 | |
| 	clk[csi_gate] = imx_clk_gate2("csi_gate", "csi_div", base + MXC_CCM_CGR1, 6);
 | |
| 	clk[rtc_gate] = imx_clk_gate2("rtc_gate", "ipg", base + MXC_CCM_CGR1, 8);
 | |
| 	clk[wdog_gate] = imx_clk_gate2("wdog_gate", "ipg", base + MXC_CCM_CGR1, 10);
 | |
| 	clk[pwm_gate] = imx_clk_gate2("pwm_gate", "per", base + MXC_CCM_CGR1, 12);
 | |
| 	clk[sim_gate] = imx_clk_gate2("sim_gate", "per", base + MXC_CCM_CGR1, 14);
 | |
| 	clk[ect_gate] = imx_clk_gate2("ect_gate", "per", base + MXC_CCM_CGR1, 16);
 | |
| 	clk[usb_gate] = imx_clk_gate2("usb_gate", "ahb", base + MXC_CCM_CGR1, 18);
 | |
| 	clk[kpp_gate] = imx_clk_gate2("kpp_gate", "ipg", base + MXC_CCM_CGR1, 20);
 | |
| 	clk[ipu_gate] = imx_clk_gate2("ipu_gate", "hsp", base + MXC_CCM_CGR1, 22);
 | |
| 	clk[uart3_gate] = imx_clk_gate2("uart3_gate", "per", base + MXC_CCM_CGR1, 24);
 | |
| 	clk[uart4_gate] = imx_clk_gate2("uart4_gate", "per", base + MXC_CCM_CGR1, 26);
 | |
| 	clk[uart5_gate] = imx_clk_gate2("uart5_gate", "per", base + MXC_CCM_CGR1, 28);
 | |
| 	clk[owire_gate] = imx_clk_gate2("owire_gate", "per", base + MXC_CCM_CGR1, 30);
 | |
| 	clk[ssi2_gate] = imx_clk_gate2("ssi2_gate", "spll", base + MXC_CCM_CGR2, 0);
 | |
| 	clk[cspi1_gate] = imx_clk_gate2("cspi1_gate", "ipg", base + MXC_CCM_CGR2, 2);
 | |
| 	clk[cspi2_gate] = imx_clk_gate2("cspi2_gate", "ipg", base + MXC_CCM_CGR2, 4);
 | |
| 	clk[gacc_gate] = imx_clk_gate2("gacc_gate", "per", base + MXC_CCM_CGR2, 6);
 | |
| 	clk[emi_gate] = imx_clk_gate2("emi_gate", "ahb", base + MXC_CCM_CGR2, 8);
 | |
| 	clk[rtic_gate] = imx_clk_gate2("rtic_gate", "ahb", base + MXC_CCM_CGR2, 10);
 | |
| 	clk[firi_gate] = imx_clk_gate2("firi_gate", "upll", base+MXC_CCM_CGR2, 12);
 | |
| 
 | |
| 	imx_check_clocks(clk, ARRAY_SIZE(clk));
 | |
| 
 | |
| 	clk_set_parent(clk[csi], clk[upll]);
 | |
| 	clk_prepare_enable(clk[emi_gate]);
 | |
| 	clk_prepare_enable(clk[iim_gate]);
 | |
| 	mx31_revision();
 | |
| 	clk_disable_unprepare(clk[iim_gate]);
 | |
| }
 | |
| 
 | |
| int __init mx31_clocks_init(unsigned long fref)
 | |
| {
 | |
| 	void __iomem *base;
 | |
| 
 | |
| 	base = ioremap(MX31_CCM_BASE_ADDR, SZ_4K);
 | |
| 	if (!base)
 | |
| 		panic("%s: failed to map registers\n", __func__);
 | |
| 
 | |
| 	_mx31_clocks_init(base, fref);
 | |
| 
 | |
| 	clk_register_clkdev(clk[gpt_gate], "per", "imx-gpt.0");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx-gpt.0");
 | |
| 	clk_register_clkdev(clk[cspi1_gate], NULL, "imx31-cspi.0");
 | |
| 	clk_register_clkdev(clk[cspi2_gate], NULL, "imx31-cspi.1");
 | |
| 	clk_register_clkdev(clk[cspi3_gate], NULL, "imx31-cspi.2");
 | |
| 	clk_register_clkdev(clk[pwm_gate], "pwm", NULL);
 | |
| 	clk_register_clkdev(clk[wdog_gate], NULL, "imx2-wdt.0");
 | |
| 	clk_register_clkdev(clk[ckil], "ref", "imx21-rtc");
 | |
| 	clk_register_clkdev(clk[rtc_gate], "ipg", "imx21-rtc");
 | |
| 	clk_register_clkdev(clk[epit1_gate], "epit", NULL);
 | |
| 	clk_register_clkdev(clk[epit2_gate], "epit", NULL);
 | |
| 	clk_register_clkdev(clk[nfc], NULL, "imx27-nand.0");
 | |
| 	clk_register_clkdev(clk[ipu_gate], NULL, "ipu-core");
 | |
| 	clk_register_clkdev(clk[ipu_gate], NULL, "mx3_sdc_fb");
 | |
| 	clk_register_clkdev(clk[kpp_gate], NULL, "imx-keypad");
 | |
| 	clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.0");
 | |
| 	clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.0");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.0");
 | |
| 	clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.1");
 | |
| 	clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.1");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.1");
 | |
| 	clk_register_clkdev(clk[usb_div_post], "per", "mxc-ehci.2");
 | |
| 	clk_register_clkdev(clk[usb_gate], "ahb", "mxc-ehci.2");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "mxc-ehci.2");
 | |
| 	clk_register_clkdev(clk[usb_div_post], "per", "imx-udc-mx27");
 | |
| 	clk_register_clkdev(clk[usb_gate], "ahb", "imx-udc-mx27");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx-udc-mx27");
 | |
| 	clk_register_clkdev(clk[csi_gate], NULL, "mx3-camera.0");
 | |
| 	/* i.mx31 has the i.mx21 type uart */
 | |
| 	clk_register_clkdev(clk[uart1_gate], "per", "imx21-uart.0");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.0");
 | |
| 	clk_register_clkdev(clk[uart2_gate], "per", "imx21-uart.1");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.1");
 | |
| 	clk_register_clkdev(clk[uart3_gate], "per", "imx21-uart.2");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.2");
 | |
| 	clk_register_clkdev(clk[uart4_gate], "per", "imx21-uart.3");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.3");
 | |
| 	clk_register_clkdev(clk[uart5_gate], "per", "imx21-uart.4");
 | |
| 	clk_register_clkdev(clk[ipg], "ipg", "imx21-uart.4");
 | |
| 	clk_register_clkdev(clk[i2c1_gate], NULL, "imx21-i2c.0");
 | |
| 	clk_register_clkdev(clk[i2c2_gate], NULL, "imx21-i2c.1");
 | |
| 	clk_register_clkdev(clk[i2c3_gate], NULL, "imx21-i2c.2");
 | |
| 	clk_register_clkdev(clk[owire_gate], NULL, "mxc_w1.0");
 | |
| 	clk_register_clkdev(clk[sdhc1_gate], NULL, "imx31-mmc.0");
 | |
| 	clk_register_clkdev(clk[sdhc2_gate], NULL, "imx31-mmc.1");
 | |
| 	clk_register_clkdev(clk[ssi1_gate], NULL, "imx-ssi.0");
 | |
| 	clk_register_clkdev(clk[ssi2_gate], NULL, "imx-ssi.1");
 | |
| 	clk_register_clkdev(clk[firi_gate], "firi", NULL);
 | |
| 	clk_register_clkdev(clk[ata_gate], NULL, "pata_imx");
 | |
| 	clk_register_clkdev(clk[rtic_gate], "rtic", NULL);
 | |
| 	clk_register_clkdev(clk[rng_gate], NULL, "mxc_rnga");
 | |
| 	clk_register_clkdev(clk[sdma_gate], NULL, "imx31-sdma");
 | |
| 	clk_register_clkdev(clk[iim_gate], "iim", NULL);
 | |
| 
 | |
| 
 | |
| 	imx_register_uart_clocks(uart_clks);
 | |
| 	mxc_timer_init(MX31_GPT1_BASE_ADDR, MX31_INT_GPT, GPT_TYPE_IMX31);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void __init mx31_clocks_init_dt(struct device_node *np)
 | |
| {
 | |
| 	struct device_node *osc_np;
 | |
| 	u32 fref = 26000000; /* default */
 | |
| 	void __iomem *ccm;
 | |
| 
 | |
| 	for_each_compatible_node(osc_np, NULL, "fixed-clock") {
 | |
| 		if (!of_device_is_compatible(osc_np, "fsl,imx-osc26m"))
 | |
| 			continue;
 | |
| 
 | |
| 		if (!of_property_read_u32(osc_np, "clock-frequency", &fref)) {
 | |
| 			of_node_put(osc_np);
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	ccm = of_iomap(np, 0);
 | |
| 	if (!ccm)
 | |
| 		panic("%s: failed to map registers\n", __func__);
 | |
| 
 | |
| 	_mx31_clocks_init(ccm, fref);
 | |
| 
 | |
| 	clk_data.clks = clk;
 | |
| 	clk_data.clk_num = ARRAY_SIZE(clk);
 | |
| 	of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 | |
| }
 | |
| 
 | |
| CLK_OF_DECLARE(imx31_ccm, "fsl,imx31-ccm", mx31_clocks_init_dt);
 |