1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2019 DENX Software Engineering 4 * Lukasz Majewski, DENX Software Engineering, lukma@denx.de 5 * 6 * Copyright (C) 2010-2011 Canonical Ltd <jeremy.kerr@canonical.com> 7 * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org> 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 * 13 * Gated clock implementation 14 * 15 */ 16 17#include <common.h> 18#include <asm/io.h> 19#include <malloc.h> 20#include <clk-uclass.h> 21#include <dm/device.h> 22#include <dm/devres.h> 23#include <linux/bug.h> 24#include <linux/clk-provider.h> 25#include <clk.h> 26#include "clk.h" 27#include <linux/err.h> 28 29#define UBOOT_DM_CLK_IMX_GATE2 "imx_clk_gate2" 30 31struct clk_gate2 { 32 struct clk clk; 33 void __iomem *reg; 34 u8 bit_idx; 35 u8 cgr_val; 36 u8 flags; 37 unsigned int *share_count; 38}; 39 40#define to_clk_gate2(_clk) container_of(_clk, struct clk_gate2, clk) 41 42static int clk_gate2_enable(struct clk *clk) 43{ 44 struct clk_gate2 *gate = to_clk_gate2(clk); 45 u32 reg; 46 47 if (gate->share_count && (*gate->share_count)++ > 0) 48 return 0; 49 50 reg = readl(gate->reg); 51 reg &= ~(3 << gate->bit_idx); 52 reg |= gate->cgr_val << gate->bit_idx; 53 writel(reg, gate->reg); 54 55 return 0; 56} 57 58static int clk_gate2_disable(struct clk *clk) 59{ 60 struct clk_gate2 *gate = to_clk_gate2(clk); 61 u32 reg; 62 63 if (gate->share_count) { 64 if (WARN_ON(*gate->share_count == 0)) 65 return 0; 66 else if (--(*gate->share_count) > 0) 67 return 0; 68 } 69 70 reg = readl(gate->reg); 71 reg &= ~(3 << gate->bit_idx); 72 writel(reg, gate->reg); 73 74 return 0; 75} 76 77static ulong clk_gate2_set_rate(struct clk *clk, ulong rate) 78{ 79 struct clk *parent = clk_get_parent(clk); 80 81 if (parent) 82 return clk_set_rate(parent, rate); 83 84 return -ENODEV; 85} 86 87static const struct clk_ops clk_gate2_ops = { 88 .set_rate = clk_gate2_set_rate, 89 .enable = clk_gate2_enable, 90 .disable = clk_gate2_disable, 91 .get_rate = clk_generic_get_rate, 92}; 93 94struct clk *clk_register_gate2(struct device *dev, const char *name, 95 const char *parent_name, unsigned long flags, 96 void __iomem *reg, u8 bit_idx, u8 cgr_val, 97 u8 clk_gate2_flags, unsigned int *share_count) 98{ 99 struct clk_gate2 *gate; 100 struct clk *clk; 101 int ret; 102 103 gate = kzalloc(sizeof(*gate), GFP_KERNEL); 104 if (!gate) 105 return ERR_PTR(-ENOMEM); 106 107 gate->reg = reg; 108 gate->bit_idx = bit_idx; 109 gate->cgr_val = cgr_val; 110 gate->flags = clk_gate2_flags; 111 gate->share_count = share_count; 112 113 clk = &gate->clk; 114 115 ret = clk_register(clk, UBOOT_DM_CLK_IMX_GATE2, name, parent_name); 116 if (ret) { 117 kfree(gate); 118 return ERR_PTR(ret); 119 } 120 121 return clk; 122} 123 124U_BOOT_DRIVER(clk_gate2) = { 125 .name = UBOOT_DM_CLK_IMX_GATE2, 126 .id = UCLASS_CLK, 127 .ops = &clk_gate2_ops, 128 .flags = DM_FLAG_PRE_RELOC, 129}; 130