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 <log.h>
12 #include <reset.h>
13 #include <asm/io.h>
14 #include <asm/arch/ccu.h>
15 #include <linux/bitops.h>
16 #include <linux/log2.h>
17 
priv_to_gate(struct ccu_priv * priv,unsigned long id)18 static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv,
19 					       unsigned long id)
20 {
21 	return &priv->desc->gates[id];
22 }
23 
sunxi_set_gate(struct clk * clk,bool on)24 static int sunxi_set_gate(struct clk *clk, bool on)
25 {
26 	struct ccu_priv *priv = dev_get_priv(clk->dev);
27 	const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id);
28 	u32 reg;
29 
30 	if (!(gate->flags & CCU_CLK_F_IS_VALID)) {
31 		printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id);
32 		return 0;
33 	}
34 
35 	debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__,
36 	      clk->id, gate->off, ilog2(gate->bit));
37 
38 	reg = readl(priv->base + gate->off);
39 	if (on)
40 		reg |= gate->bit;
41 	else
42 		reg &= ~gate->bit;
43 
44 	writel(reg, priv->base + gate->off);
45 
46 	return 0;
47 }
48 
sunxi_clk_enable(struct clk * clk)49 static int sunxi_clk_enable(struct clk *clk)
50 {
51 	return sunxi_set_gate(clk, true);
52 }
53 
sunxi_clk_disable(struct clk * clk)54 static int sunxi_clk_disable(struct clk *clk)
55 {
56 	return sunxi_set_gate(clk, false);
57 }
58 
59 struct clk_ops sunxi_clk_ops = {
60 	.enable = sunxi_clk_enable,
61 	.disable = sunxi_clk_disable,
62 };
63 
sunxi_clk_probe(struct udevice * dev)64 int sunxi_clk_probe(struct udevice *dev)
65 {
66 	struct ccu_priv *priv = dev_get_priv(dev);
67 	struct clk_bulk clk_bulk;
68 	struct reset_ctl_bulk rst_bulk;
69 	int ret;
70 
71 	priv->base = dev_read_addr_ptr(dev);
72 	if (!priv->base)
73 		return -ENOMEM;
74 
75 	priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
76 	if (!priv->desc)
77 		return -EINVAL;
78 
79 	ret = clk_get_bulk(dev, &clk_bulk);
80 	if (!ret)
81 		clk_enable_bulk(&clk_bulk);
82 
83 	ret = reset_get_bulk(dev, &rst_bulk);
84 	if (!ret)
85 		reset_deassert_bulk(&rst_bulk);
86 
87 	return 0;
88 }
89