blob: 62e77386be7acc828fc8485f09fec679392c79d3 [file] [log] [blame]
Jagan Teki0d47bc72018-12-22 21:32:49 +05301// 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>
Simon Glassf7ae49f2020-05-10 11:40:05 -060011#include <log.h>
Andre Przywara13b08672019-01-29 15:54:08 +000012#include <reset.h>
Jagan Teki0d47bc72018-12-22 21:32:49 +053013#include <asm/io.h>
Samuel Holland21d314a2021-09-12 11:48:43 -050014#include <clk/sunxi.h>
Simon Glasscd93d622020-05-10 11:40:13 -060015#include <linux/bitops.h>
Jagan Teki0d47bc72018-12-22 21:32:49 +053016#include <linux/log2.h>
17
18static const struct ccu_clk_gate *priv_to_gate(struct ccu_priv *priv,
19 unsigned long id)
20{
Samuel Holland6827aba2022-05-09 00:29:32 -050021 if (id >= priv->desc->num_gates)
22 return NULL;
23
Jagan Teki0d47bc72018-12-22 21:32:49 +053024 return &priv->desc->gates[id];
25}
26
27static int sunxi_set_gate(struct clk *clk, bool on)
28{
29 struct ccu_priv *priv = dev_get_priv(clk->dev);
30 const struct ccu_clk_gate *gate = priv_to_gate(priv, clk->id);
31 u32 reg;
32
Samuel Holland6827aba2022-05-09 00:29:32 -050033 if (gate && (gate->flags & CCU_CLK_F_DUMMY_GATE))
Andre Przywarad6cb09d2022-05-05 01:25:43 +010034 return 0;
35
Samuel Holland6827aba2022-05-09 00:29:32 -050036 if (!gate || !(gate->flags & CCU_CLK_F_IS_VALID)) {
Jagan Teki0d47bc72018-12-22 21:32:49 +053037 printf("%s: (CLK#%ld) unhandled\n", __func__, clk->id);
38 return 0;
39 }
40
41 debug("%s: (CLK#%ld) off#0x%x, BIT(%d)\n", __func__,
42 clk->id, gate->off, ilog2(gate->bit));
43
44 reg = readl(priv->base + gate->off);
45 if (on)
46 reg |= gate->bit;
47 else
48 reg &= ~gate->bit;
49
50 writel(reg, priv->base + gate->off);
51
52 return 0;
53}
54
55static int sunxi_clk_enable(struct clk *clk)
56{
57 return sunxi_set_gate(clk, true);
58}
59
60static int sunxi_clk_disable(struct clk *clk)
61{
62 return sunxi_set_gate(clk, false);
63}
64
65struct clk_ops sunxi_clk_ops = {
66 .enable = sunxi_clk_enable,
67 .disable = sunxi_clk_disable,
68};
69
70int sunxi_clk_probe(struct udevice *dev)
71{
72 struct ccu_priv *priv = dev_get_priv(dev);
Andre Przywara13b08672019-01-29 15:54:08 +000073 struct clk_bulk clk_bulk;
74 struct reset_ctl_bulk rst_bulk;
75 int ret;
Jagan Teki0d47bc72018-12-22 21:32:49 +053076
77 priv->base = dev_read_addr_ptr(dev);
78 if (!priv->base)
79 return -ENOMEM;
80
81 priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
82 if (!priv->desc)
83 return -EINVAL;
84
Andre Przywara13b08672019-01-29 15:54:08 +000085 ret = clk_get_bulk(dev, &clk_bulk);
86 if (!ret)
87 clk_enable_bulk(&clk_bulk);
88
89 ret = reset_get_bulk(dev, &rst_bulk);
90 if (!ret)
91 reset_deassert_bulk(&rst_bulk);
92
Jagan Teki0d47bc72018-12-22 21:32:49 +053093 return 0;
94}