xref: /openbmc/linux/drivers/clk/clk-fsl-flexspi.c (revision fcf77be8)
1*fcf77be8SMichael Walle // SPDX-License-Identifier: GPL-2.0-only
2*fcf77be8SMichael Walle /*
3*fcf77be8SMichael Walle  * Layerscape FlexSPI clock driver
4*fcf77be8SMichael Walle  *
5*fcf77be8SMichael Walle  * Copyright 2020 Michael Walle <michael@walle.cc>
6*fcf77be8SMichael Walle  */
7*fcf77be8SMichael Walle 
8*fcf77be8SMichael Walle #include <linux/clk-provider.h>
9*fcf77be8SMichael Walle #include <linux/io.h>
10*fcf77be8SMichael Walle #include <linux/module.h>
11*fcf77be8SMichael Walle #include <linux/platform_device.h>
12*fcf77be8SMichael Walle 
13*fcf77be8SMichael Walle static const struct clk_div_table ls1028a_flexspi_divs[] = {
14*fcf77be8SMichael Walle 	{ .val = 0, .div = 1, },
15*fcf77be8SMichael Walle 	{ .val = 1, .div = 2, },
16*fcf77be8SMichael Walle 	{ .val = 2, .div = 3, },
17*fcf77be8SMichael Walle 	{ .val = 3, .div = 4, },
18*fcf77be8SMichael Walle 	{ .val = 4, .div = 5, },
19*fcf77be8SMichael Walle 	{ .val = 5, .div = 6, },
20*fcf77be8SMichael Walle 	{ .val = 6, .div = 7, },
21*fcf77be8SMichael Walle 	{ .val = 7, .div = 8, },
22*fcf77be8SMichael Walle 	{ .val = 11, .div = 12, },
23*fcf77be8SMichael Walle 	{ .val = 15, .div = 16, },
24*fcf77be8SMichael Walle 	{ .val = 16, .div = 20, },
25*fcf77be8SMichael Walle 	{ .val = 17, .div = 24, },
26*fcf77be8SMichael Walle 	{ .val = 18, .div = 28, },
27*fcf77be8SMichael Walle 	{ .val = 19, .div = 32, },
28*fcf77be8SMichael Walle 	{ .val = 20, .div = 80, },
29*fcf77be8SMichael Walle 	{}
30*fcf77be8SMichael Walle };
31*fcf77be8SMichael Walle 
32*fcf77be8SMichael Walle static const struct clk_div_table lx2160a_flexspi_divs[] = {
33*fcf77be8SMichael Walle 	{ .val = 1, .div = 2, },
34*fcf77be8SMichael Walle 	{ .val = 3, .div = 4, },
35*fcf77be8SMichael Walle 	{ .val = 5, .div = 6, },
36*fcf77be8SMichael Walle 	{ .val = 7, .div = 8, },
37*fcf77be8SMichael Walle 	{ .val = 11, .div = 12, },
38*fcf77be8SMichael Walle 	{ .val = 15, .div = 16, },
39*fcf77be8SMichael Walle 	{ .val = 16, .div = 20, },
40*fcf77be8SMichael Walle 	{ .val = 17, .div = 24, },
41*fcf77be8SMichael Walle 	{ .val = 18, .div = 28, },
42*fcf77be8SMichael Walle 	{ .val = 19, .div = 32, },
43*fcf77be8SMichael Walle 	{ .val = 20, .div = 80, },
44*fcf77be8SMichael Walle 	{}
45*fcf77be8SMichael Walle };
46*fcf77be8SMichael Walle 
fsl_flexspi_clk_probe(struct platform_device * pdev)47*fcf77be8SMichael Walle static int fsl_flexspi_clk_probe(struct platform_device *pdev)
48*fcf77be8SMichael Walle {
49*fcf77be8SMichael Walle 	struct device *dev = &pdev->dev;
50*fcf77be8SMichael Walle 	struct device_node *np = dev->of_node;
51*fcf77be8SMichael Walle 	const char *clk_name = np->name;
52*fcf77be8SMichael Walle 	const char *clk_parent;
53*fcf77be8SMichael Walle 	struct resource *res;
54*fcf77be8SMichael Walle 	void __iomem *reg;
55*fcf77be8SMichael Walle 	struct clk_hw *hw;
56*fcf77be8SMichael Walle 	const struct clk_div_table *divs;
57*fcf77be8SMichael Walle 
58*fcf77be8SMichael Walle 	divs = device_get_match_data(dev);
59*fcf77be8SMichael Walle 	if (!divs)
60*fcf77be8SMichael Walle 		return -ENOENT;
61*fcf77be8SMichael Walle 
62*fcf77be8SMichael Walle 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
63*fcf77be8SMichael Walle 	if (!res)
64*fcf77be8SMichael Walle 		return -ENOENT;
65*fcf77be8SMichael Walle 
66*fcf77be8SMichael Walle 	/*
67*fcf77be8SMichael Walle 	 * Can't use devm_ioremap_resource() or devm_of_iomap() because the
68*fcf77be8SMichael Walle 	 * resource might already be taken by the parent device.
69*fcf77be8SMichael Walle 	 */
70*fcf77be8SMichael Walle 	reg = devm_ioremap(dev, res->start, resource_size(res));
71*fcf77be8SMichael Walle 	if (!reg)
72*fcf77be8SMichael Walle 		return -ENOMEM;
73*fcf77be8SMichael Walle 
74*fcf77be8SMichael Walle 	clk_parent = of_clk_get_parent_name(np, 0);
75*fcf77be8SMichael Walle 	if (!clk_parent)
76*fcf77be8SMichael Walle 		return -EINVAL;
77*fcf77be8SMichael Walle 
78*fcf77be8SMichael Walle 	of_property_read_string(np, "clock-output-names", &clk_name);
79*fcf77be8SMichael Walle 
80*fcf77be8SMichael Walle 	hw = devm_clk_hw_register_divider_table(dev, clk_name, clk_parent, 0,
81*fcf77be8SMichael Walle 						reg, 0, 5, 0, divs, NULL);
82*fcf77be8SMichael Walle 	if (IS_ERR(hw))
83*fcf77be8SMichael Walle 		return PTR_ERR(hw);
84*fcf77be8SMichael Walle 
85*fcf77be8SMichael Walle 	return devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, hw);
86*fcf77be8SMichael Walle }
87*fcf77be8SMichael Walle 
88*fcf77be8SMichael Walle static const struct of_device_id fsl_flexspi_clk_dt_ids[] = {
89*fcf77be8SMichael Walle 	{ .compatible = "fsl,ls1028a-flexspi-clk", .data = &ls1028a_flexspi_divs },
90*fcf77be8SMichael Walle 	{ .compatible = "fsl,lx2160a-flexspi-clk", .data = &lx2160a_flexspi_divs },
91*fcf77be8SMichael Walle 	{}
92*fcf77be8SMichael Walle };
93*fcf77be8SMichael Walle MODULE_DEVICE_TABLE(of, fsl_flexspi_clk_dt_ids);
94*fcf77be8SMichael Walle 
95*fcf77be8SMichael Walle static struct platform_driver fsl_flexspi_clk_driver = {
96*fcf77be8SMichael Walle 	.driver = {
97*fcf77be8SMichael Walle 		.name = "fsl-flexspi-clk",
98*fcf77be8SMichael Walle 		.of_match_table = fsl_flexspi_clk_dt_ids,
99*fcf77be8SMichael Walle 	},
100*fcf77be8SMichael Walle 	.probe = fsl_flexspi_clk_probe,
101*fcf77be8SMichael Walle };
102*fcf77be8SMichael Walle module_platform_driver(fsl_flexspi_clk_driver);
103*fcf77be8SMichael Walle 
104*fcf77be8SMichael Walle MODULE_DESCRIPTION("FlexSPI clock driver for Layerscape SoCs");
105*fcf77be8SMichael Walle MODULE_AUTHOR("Michael Walle <michael@walle.cc>");
106*fcf77be8SMichael Walle MODULE_LICENSE("GPL");
107