blob: 23d81f68c5c0c5eaa929a2219ceac6987fb88b69 [file] [log] [blame]
Jagan Teki1d150b42018-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 Glass0f2af882020-05-10 11:40:05 -060011#include <log.h>
Andre Przywara030bab82019-01-29 15:54:08 +000012#include <reset.h>
Jagan Teki1d150b42018-12-22 21:32:49 +053013#include <asm/io.h>
Samuel Holland12e3faa2021-09-12 11:48:43 -050014#include <clk/sunxi.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060015#include <linux/bitops.h>
Jagan Teki1d150b42018-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 Hollanda4969072022-05-09 00:29:32 -050021 if (id >= priv->desc->num_gates)
22 return NULL;
23
Jagan Teki1d150b42018-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 Hollanda4969072022-05-09 00:29:32 -050033 if (gate && (gate->flags & CCU_CLK_F_DUMMY_GATE))
Andre Przywara2d1864f2022-05-05 01:25:43 +010034 return 0;
35
Samuel Hollanda4969072022-05-09 00:29:32 -050036 if (!gate || !(gate->flags & CCU_CLK_F_IS_VALID)) {
Jagan Teki1d150b42018-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
Samuel Holland1567fdf2022-05-09 00:29:33 -050070int sunxi_clk_bind(struct udevice *dev)
71{
72 return sunxi_reset_bind(dev);
73}
74
Jagan Teki1d150b42018-12-22 21:32:49 +053075int sunxi_clk_probe(struct udevice *dev)
76{
77 struct ccu_priv *priv = dev_get_priv(dev);
Andre Przywara030bab82019-01-29 15:54:08 +000078 struct clk_bulk clk_bulk;
79 struct reset_ctl_bulk rst_bulk;
80 int ret;
Jagan Teki1d150b42018-12-22 21:32:49 +053081
82 priv->base = dev_read_addr_ptr(dev);
83 if (!priv->base)
84 return -ENOMEM;
85
86 priv->desc = (const struct ccu_desc *)dev_get_driver_data(dev);
87 if (!priv->desc)
88 return -EINVAL;
89
Andre Przywara030bab82019-01-29 15:54:08 +000090 ret = clk_get_bulk(dev, &clk_bulk);
91 if (!ret)
92 clk_enable_bulk(&clk_bulk);
93
94 ret = reset_get_bulk(dev, &rst_bulk);
95 if (!ret)
96 reset_deassert_bulk(&rst_bulk);
97
Jagan Teki1d150b42018-12-22 21:32:49 +053098 return 0;
99}