xref: /rk3399_rockchip-uboot/drivers/clk/at91/clk-peripheral.c (revision 6cadaa046b196bebebd7acb13edd840bcfef98e2)
19e5935c0SWenyou Yang /*
29e5935c0SWenyou Yang  * Copyright (C) 2016 Atmel Corporation
39e5935c0SWenyou Yang  *               Wenyou.Yang <wenyou.yang@atmel.com>
49e5935c0SWenyou Yang  *
59e5935c0SWenyou Yang  * SPDX-License-Identifier:	GPL-2.0+
69e5935c0SWenyou Yang  */
79e5935c0SWenyou Yang 
89e5935c0SWenyou Yang #include <common.h>
99e5935c0SWenyou Yang #include <clk-uclass.h>
109e5935c0SWenyou Yang #include <dm/device.h>
119e5935c0SWenyou Yang #include <linux/io.h>
129e5935c0SWenyou Yang #include <mach/at91_pmc.h>
139e5935c0SWenyou Yang #include "pmc.h"
149e5935c0SWenyou Yang 
159e5935c0SWenyou Yang #define PERIPHERAL_ID_MIN	2
169e5935c0SWenyou Yang #define PERIPHERAL_ID_MAX	31
179e5935c0SWenyou Yang #define PERIPHERAL_MASK(id)	(1 << ((id) & PERIPHERAL_ID_MAX))
189e5935c0SWenyou Yang 
19*6cadaa04SWenyou Yang /**
20*6cadaa04SWenyou Yang  * sam9x5_periph_clk_bind() - for the periph clock driver
21*6cadaa04SWenyou Yang  * Recursively bind its children as clk devices.
22*6cadaa04SWenyou Yang  *
23*6cadaa04SWenyou Yang  * @return: 0 on success, or negative error code on failure
24*6cadaa04SWenyou Yang  */
25*6cadaa04SWenyou Yang static int sam9x5_periph_clk_bind(struct udevice *dev)
26*6cadaa04SWenyou Yang {
27*6cadaa04SWenyou Yang 	return at91_clk_sub_device_bind(dev, "periph-clk");
28*6cadaa04SWenyou Yang }
29*6cadaa04SWenyou Yang 
30*6cadaa04SWenyou Yang static const struct udevice_id sam9x5_periph_clk_match[] = {
31*6cadaa04SWenyou Yang 	{ .compatible = "atmel,at91sam9x5-clk-peripheral" },
32*6cadaa04SWenyou Yang 	{}
33*6cadaa04SWenyou Yang };
34*6cadaa04SWenyou Yang 
35*6cadaa04SWenyou Yang U_BOOT_DRIVER(sam9x5_periph_clk) = {
36*6cadaa04SWenyou Yang 	.name = "sam9x5-periph-clk",
37*6cadaa04SWenyou Yang 	.id = UCLASS_MISC,
38*6cadaa04SWenyou Yang 	.of_match = sam9x5_periph_clk_match,
39*6cadaa04SWenyou Yang 	.bind = sam9x5_periph_clk_bind,
40*6cadaa04SWenyou Yang };
41*6cadaa04SWenyou Yang 
42*6cadaa04SWenyou Yang /*---------------------------------------------------------*/
43*6cadaa04SWenyou Yang 
44*6cadaa04SWenyou Yang static int periph_clk_enable(struct clk *clk)
459e5935c0SWenyou Yang {
469e5935c0SWenyou Yang 	struct pmc_platdata *plat = dev_get_platdata(clk->dev);
479e5935c0SWenyou Yang 	struct at91_pmc *pmc = plat->reg_base;
489e5935c0SWenyou Yang 
499e5935c0SWenyou Yang 	if (clk->id < PERIPHERAL_ID_MIN)
509e5935c0SWenyou Yang 		return -1;
519e5935c0SWenyou Yang 
529e5935c0SWenyou Yang 	writel(clk->id & AT91_PMC_PCR_PID_MASK, &pmc->pcr);
539e5935c0SWenyou Yang 	setbits_le32(&pmc->pcr, AT91_PMC_PCR_CMD_WRITE | AT91_PMC_PCR_EN);
549e5935c0SWenyou Yang 
559e5935c0SWenyou Yang 	return 0;
569e5935c0SWenyou Yang }
579e5935c0SWenyou Yang 
58*6cadaa04SWenyou Yang static ulong periph_get_rate(struct clk *clk)
599e5935c0SWenyou Yang {
60*6cadaa04SWenyou Yang 	struct udevice *dev;
61*6cadaa04SWenyou Yang 	struct clk clk_dev;
62*6cadaa04SWenyou Yang 	ulong clk_rate;
63*6cadaa04SWenyou Yang 	int ret;
64*6cadaa04SWenyou Yang 
65*6cadaa04SWenyou Yang 	dev = dev_get_parent(clk->dev);
66*6cadaa04SWenyou Yang 
67*6cadaa04SWenyou Yang 	ret = clk_get_by_index(dev, 0, &clk_dev);
68*6cadaa04SWenyou Yang 	if (ret)
69*6cadaa04SWenyou Yang 		return ret;
70*6cadaa04SWenyou Yang 
71*6cadaa04SWenyou Yang 	clk_rate = clk_get_rate(&clk_dev);
72*6cadaa04SWenyou Yang 
73*6cadaa04SWenyou Yang 	clk_free(&clk_dev);
74*6cadaa04SWenyou Yang 
75*6cadaa04SWenyou Yang 	return clk_rate;
769e5935c0SWenyou Yang }
779e5935c0SWenyou Yang 
78*6cadaa04SWenyou Yang static struct clk_ops periph_clk_ops = {
79*6cadaa04SWenyou Yang 	.of_xlate = at91_clk_of_xlate,
80*6cadaa04SWenyou Yang 	.enable = periph_clk_enable,
81*6cadaa04SWenyou Yang 	.get_rate = periph_get_rate,
829e5935c0SWenyou Yang };
839e5935c0SWenyou Yang 
84*6cadaa04SWenyou Yang U_BOOT_DRIVER(clk_periph) = {
85*6cadaa04SWenyou Yang 	.name	= "periph-clk",
869e5935c0SWenyou Yang 	.id	= UCLASS_CLK,
879e5935c0SWenyou Yang 	.platdata_auto_alloc_size = sizeof(struct pmc_platdata),
88*6cadaa04SWenyou Yang 	.probe = at91_clk_probe,
89*6cadaa04SWenyou Yang 	.ops	= &periph_clk_ops,
909e5935c0SWenyou Yang };
91