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