xref: /openbmc/linux/drivers/clk/rockchip/softrst.c (revision ada8f95b)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2014 MundoReader S.L.
4  * Author: Heiko Stuebner <heiko@sntech.de>
5  */
6 
7 #include <linux/slab.h>
8 #include <linux/io.h>
9 #include <linux/reset-controller.h>
10 #include <linux/spinlock.h>
11 #include "clk.h"
12 
13 struct rockchip_softrst {
14 	struct reset_controller_dev	rcdev;
15 	const int			*lut;
16 	void __iomem			*reg_base;
17 	int				num_regs;
18 	int				num_per_reg;
19 	u8				flags;
20 	spinlock_t			lock;
21 };
22 
rockchip_softrst_assert(struct reset_controller_dev * rcdev,unsigned long id)23 static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
24 			      unsigned long id)
25 {
26 	struct rockchip_softrst *softrst = container_of(rcdev,
27 						     struct rockchip_softrst,
28 						     rcdev);
29 	int bank, offset;
30 
31 	if (softrst->lut)
32 		id = softrst->lut[id];
33 
34 	bank = id / softrst->num_per_reg;
35 	offset = id % softrst->num_per_reg;
36 
37 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
38 		writel(BIT(offset) | (BIT(offset) << 16),
39 		       softrst->reg_base + (bank * 4));
40 	} else {
41 		unsigned long flags;
42 		u32 reg;
43 
44 		spin_lock_irqsave(&softrst->lock, flags);
45 
46 		reg = readl(softrst->reg_base + (bank * 4));
47 		writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
48 
49 		spin_unlock_irqrestore(&softrst->lock, flags);
50 	}
51 
52 	return 0;
53 }
54 
rockchip_softrst_deassert(struct reset_controller_dev * rcdev,unsigned long id)55 static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
56 				unsigned long id)
57 {
58 	struct rockchip_softrst *softrst = container_of(rcdev,
59 						     struct rockchip_softrst,
60 						     rcdev);
61 	int bank, offset;
62 
63 	if (softrst->lut)
64 		id = softrst->lut[id];
65 
66 	bank = id / softrst->num_per_reg;
67 	offset = id % softrst->num_per_reg;
68 
69 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
70 		writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
71 	} else {
72 		unsigned long flags;
73 		u32 reg;
74 
75 		spin_lock_irqsave(&softrst->lock, flags);
76 
77 		reg = readl(softrst->reg_base + (bank * 4));
78 		writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
79 
80 		spin_unlock_irqrestore(&softrst->lock, flags);
81 	}
82 
83 	return 0;
84 }
85 
86 static const struct reset_control_ops rockchip_softrst_ops = {
87 	.assert		= rockchip_softrst_assert,
88 	.deassert	= rockchip_softrst_deassert,
89 };
90 
rockchip_register_softrst_lut(struct device_node * np,const int * lookup_table,unsigned int num_regs,void __iomem * base,u8 flags)91 void rockchip_register_softrst_lut(struct device_node *np,
92 				   const int *lookup_table,
93 				   unsigned int num_regs,
94 				   void __iomem *base, u8 flags)
95 {
96 	struct rockchip_softrst *softrst;
97 	int ret;
98 
99 	softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
100 	if (!softrst)
101 		return;
102 
103 	spin_lock_init(&softrst->lock);
104 
105 	softrst->reg_base = base;
106 	softrst->lut = lookup_table;
107 	softrst->flags = flags;
108 	softrst->num_regs = num_regs;
109 	softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
110 								      : 32;
111 
112 	softrst->rcdev.owner = THIS_MODULE;
113 	if (lookup_table)
114 		softrst->rcdev.nr_resets = num_regs;
115 	else
116 		softrst->rcdev.nr_resets = num_regs * softrst->num_per_reg;
117 	softrst->rcdev.ops = &rockchip_softrst_ops;
118 	softrst->rcdev.of_node = np;
119 	ret = reset_controller_register(&softrst->rcdev);
120 	if (ret) {
121 		pr_err("%s: could not register reset controller, %d\n",
122 		       __func__, ret);
123 		kfree(softrst);
124 	}
125 };
126 EXPORT_SYMBOL_GPL(rockchip_register_softrst_lut);
127