xref: /openbmc/u-boot/drivers/clk/sunxi/clk_sunxi.c (revision 29e1a64c)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2018 Amarula Solutions.
4  * Author: Jagan Teki <jagan@amarulasolutions.com>
5  */
6 
7 #include <common.h>
8 #include <clk-uclass.h>
9 #include <dm.h>
10 #include <errno.h>
11 #include <asm/io.h>
12 #include <asm/arch/ccu.h>
13 #include <linux/log2.h>
14 
15 static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv,
16 					       unsigned long id)
17 {
18 	return &priv->desc->gates[id];
19 }
20 
21 static int sunxi_set_gate(struct clk *clk, bool on)
22 {
23 	struct ccu_priv *priv = dev_get_priv(clk->dev);
24 	const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id);
25 	u32 reg;
26 
27 	if (!(gate->flags & CCU_CLK_F_IS_VALID)) {
28 		printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id);
29 		return 0;
30 	}
31 
32 	debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__,
33 	      clk->id, gate->off, ilog2(gate->bit));
34 
35 	reg = readl(priv->base + gate->off);
36 	if (on)
37 		reg |= gate->bit;
38 	else
39 		reg &= ~gate->bit;
40 
41 	writel(reg, priv->base + gate->off);
42 
43 	return 0;
44 }
45 
46 static int sunxi_clk_enable(struct clk *clk)
47 {
48 	return sunxi_set_gate(clk, true);
49 }
50 
51 static int sunxi_clk_disable(struct clk *clk)
52 {
53 	return sunxi_set_gate(clk, false);
54 }
55 
56 struct clk_ops sunxi_clk_ops = {
57 	.enable = sunxi_clk_enable,
58 	.disable = sunxi_clk_disable,
59 };
60 
61 int sunxi_clk_probe(struct udevice *dev)
62 {
63 	struct ccu_priv *priv = dev_get_priv(dev);
64 
65 	priv->base = dev_read_addr_ptr(dev);
66 	if (!priv->base)
67 		return -ENOMEM;
68 
69 	priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
70 	if (!priv->desc)
71 		return -EINVAL;
72 
73 	return 0;
74 }
75