brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · a3f349d Raw
240 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * ARTPEC-6 clock initialization4 *5 * Copyright 2015-2016 Axis Communications AB.6 */7 8#include <linux/clk-provider.h>9#include <linux/device.h>10#include <linux/io.h>11#include <linux/of.h>12#include <linux/of_address.h>13#include <linux/platform_device.h>14#include <linux/slab.h>15#include <dt-bindings/clock/axis,artpec6-clkctrl.h>16 17#define NUM_I2S_CLOCKS 218 19struct artpec6_clkctrl_drvdata {20	struct clk *clk_table[ARTPEC6_CLK_NUMCLOCKS];21	void __iomem *syscon_base;22	struct clk_onecell_data clk_data;23	spinlock_t i2scfg_lock;24};25 26static struct artpec6_clkctrl_drvdata *clkdata;27 28static const char *const i2s_clk_names[NUM_I2S_CLOCKS] = {29	"i2s0",30	"i2s1",31};32 33static const int i2s_clk_indexes[NUM_I2S_CLOCKS] = {34	ARTPEC6_CLK_I2S0_CLK,35	ARTPEC6_CLK_I2S1_CLK,36};37 38static void of_artpec6_clkctrl_setup(struct device_node *np)39{40	int i;41	const char *sys_refclk_name;42	u32 pll_mode, pll_m, pll_n;43	struct clk **clks;44 45	/* Mandatory parent clock. */46	i = of_property_match_string(np, "clock-names", "sys_refclk");47	if (i < 0)48		return;49 50	sys_refclk_name = of_clk_get_parent_name(np, i);51 52	clkdata = kzalloc(sizeof(*clkdata), GFP_KERNEL);53	if (!clkdata)54		return;55 56	clks = clkdata->clk_table;57 58	for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i)59		clks[i] = ERR_PTR(-EPROBE_DEFER);60 61	clkdata->syscon_base = of_iomap(np, 0);62	BUG_ON(clkdata->syscon_base == NULL);63 64	/* Read PLL1 factors configured by boot strap pins. */65	pll_mode = (readl(clkdata->syscon_base) >> 6) & 3;66	switch (pll_mode) {67	case 0:		/* DDR3-2133 mode */68		pll_m = 4;69		pll_n = 85;70		break;71	case 1:		/* DDR3-1866 mode */72		pll_m = 6;73		pll_n = 112;74		break;75	case 2:		/* DDR3-1600 mode */76		pll_m = 4;77		pll_n = 64;78		break;79	case 3:		/* DDR3-1333 mode */80		pll_m = 8;81		pll_n = 106;82		break;83	}84 85	clks[ARTPEC6_CLK_CPU] =86	    clk_register_fixed_factor(NULL, "cpu", sys_refclk_name, 0, pll_n,87				      pll_m);88	clks[ARTPEC6_CLK_CPU_PERIPH] =89	    clk_register_fixed_factor(NULL, "cpu_periph", "cpu", 0, 1, 2);90 91	/* EPROBE_DEFER on the apb_clock is not handled in amba devices. */92	clks[ARTPEC6_CLK_UART_PCLK] =93	    clk_register_fixed_factor(NULL, "uart_pclk", "cpu", 0, 1, 8);94	clks[ARTPEC6_CLK_UART_REFCLK] =95	    clk_register_fixed_rate(NULL, "uart_ref", sys_refclk_name, 0,96				    50000000);97 98	clks[ARTPEC6_CLK_SPI_PCLK] =99	    clk_register_fixed_factor(NULL, "spi_pclk", "cpu", 0, 1, 8);100	clks[ARTPEC6_CLK_SPI_SSPCLK] =101	    clk_register_fixed_rate(NULL, "spi_sspclk", sys_refclk_name, 0,102				    50000000);103 104	clks[ARTPEC6_CLK_DBG_PCLK] =105	    clk_register_fixed_factor(NULL, "dbg_pclk", "cpu", 0, 1, 8);106 107	clkdata->clk_data.clks = clkdata->clk_table;108	clkdata->clk_data.clk_num = ARTPEC6_CLK_NUMCLOCKS;109 110	of_clk_add_provider(np, of_clk_src_onecell_get, &clkdata->clk_data);111}112 113CLK_OF_DECLARE_DRIVER(artpec6_clkctrl, "axis,artpec6-clkctrl",114		      of_artpec6_clkctrl_setup);115 116static int artpec6_clkctrl_probe(struct platform_device *pdev)117{118	int propidx;119	struct device_node *np = pdev->dev.of_node;120	struct device *dev = &pdev->dev;121	struct clk **clks = clkdata->clk_table;122	const char *sys_refclk_name;123	const char *i2s_refclk_name = NULL;124	const char *frac_clk_name[2] = { NULL, NULL };125	const char *i2s_mux_parents[2];126	u32 muxreg;127	int i;128	int err = 0;129 130	/* Mandatory parent clock. */131	propidx = of_property_match_string(np, "clock-names", "sys_refclk");132	if (propidx < 0)133		return -EINVAL;134 135	sys_refclk_name = of_clk_get_parent_name(np, propidx);136 137	/* Find clock names of optional parent clocks. */138	propidx = of_property_match_string(np, "clock-names", "i2s_refclk");139	if (propidx >= 0)140		i2s_refclk_name = of_clk_get_parent_name(np, propidx);141 142	propidx = of_property_match_string(np, "clock-names", "frac_clk0");143	if (propidx >= 0)144		frac_clk_name[0] = of_clk_get_parent_name(np, propidx);145	propidx = of_property_match_string(np, "clock-names", "frac_clk1");146	if (propidx >= 0)147		frac_clk_name[1] = of_clk_get_parent_name(np, propidx);148 149	spin_lock_init(&clkdata->i2scfg_lock);150 151	clks[ARTPEC6_CLK_NAND_CLKA] =152	    clk_register_fixed_factor(dev, "nand_clka", "cpu", 0, 1, 8);153	clks[ARTPEC6_CLK_NAND_CLKB] =154	    clk_register_fixed_rate(dev, "nand_clkb", sys_refclk_name, 0,155				    100000000);156	clks[ARTPEC6_CLK_ETH_ACLK] =157	    clk_register_fixed_factor(dev, "eth_aclk", "cpu", 0, 1, 4);158	clks[ARTPEC6_CLK_DMA_ACLK] =159	    clk_register_fixed_factor(dev, "dma_aclk", "cpu", 0, 1, 4);160	clks[ARTPEC6_CLK_PTP_REF] =161	    clk_register_fixed_rate(dev, "ptp_ref", sys_refclk_name, 0,162				    100000000);163	clks[ARTPEC6_CLK_SD_PCLK] =164	    clk_register_fixed_rate(dev, "sd_pclk", sys_refclk_name, 0,165				    100000000);166	clks[ARTPEC6_CLK_SD_IMCLK] =167	    clk_register_fixed_rate(dev, "sd_imclk", sys_refclk_name, 0,168				    100000000);169	clks[ARTPEC6_CLK_I2S_HST] =170	    clk_register_fixed_factor(dev, "i2s_hst", "cpu", 0, 1, 8);171 172	for (i = 0; i < NUM_I2S_CLOCKS; ++i) {173		if (i2s_refclk_name && frac_clk_name[i]) {174			i2s_mux_parents[0] = frac_clk_name[i];175			i2s_mux_parents[1] = i2s_refclk_name;176 177			clks[i2s_clk_indexes[i]] =178			    clk_register_mux(dev, i2s_clk_names[i],179					     i2s_mux_parents, 2,180					     CLK_SET_RATE_NO_REPARENT |181					     CLK_SET_RATE_PARENT,182					     clkdata->syscon_base + 0x14, i, 1,183					     0, &clkdata->i2scfg_lock);184		} else if (frac_clk_name[i]) {185			/* Lock the mux for internal clock reference. */186			muxreg = readl(clkdata->syscon_base + 0x14);187			muxreg &= ~BIT(i);188			writel(muxreg, clkdata->syscon_base + 0x14);189			clks[i2s_clk_indexes[i]] =190			    clk_register_fixed_factor(dev, i2s_clk_names[i],191						      frac_clk_name[i], 0, 1,192						      1);193		} else if (i2s_refclk_name) {194			/* Lock the mux for external clock reference. */195			muxreg = readl(clkdata->syscon_base + 0x14);196			muxreg |= BIT(i);197			writel(muxreg, clkdata->syscon_base + 0x14);198			clks[i2s_clk_indexes[i]] =199			    clk_register_fixed_factor(dev, i2s_clk_names[i],200						      i2s_refclk_name, 0, 1, 1);201		}202	}203 204	clks[ARTPEC6_CLK_I2C] =205	    clk_register_fixed_rate(dev, "i2c", sys_refclk_name, 0, 100000000);206 207	clks[ARTPEC6_CLK_SYS_TIMER] =208	    clk_register_fixed_rate(dev, "timer", sys_refclk_name, 0,209				    100000000);210	clks[ARTPEC6_CLK_FRACDIV_IN] =211	    clk_register_fixed_rate(dev, "fracdiv_in", sys_refclk_name, 0,212				    600000000);213 214	for (i = 0; i < ARTPEC6_CLK_NUMCLOCKS; ++i) {215		if (IS_ERR(clks[i]) && PTR_ERR(clks[i]) != -EPROBE_DEFER) {216			dev_err(dev,217				"Failed to register clock at index %d err=%ld\n",218				i, PTR_ERR(clks[i]));219			err = PTR_ERR(clks[i]);220		}221	}222 223	return err;224}225 226static const struct of_device_id artpec_clkctrl_of_match[] = {227	{ .compatible = "axis,artpec6-clkctrl" },228	{}229};230 231static struct platform_driver artpec6_clkctrl_driver = {232	.probe = artpec6_clkctrl_probe,233	.driver = {234		   .name = "artpec6_clkctrl",235		   .of_match_table = artpec_clkctrl_of_match,236	},237};238 239builtin_platform_driver(artpec6_clkctrl_driver);240