xref: /openbmc/linux/drivers/clk/rockchip/softrst.c (revision 1c2dd16a)
1 /*
2  * Copyright (c) 2014 MundoReader S.L.
3  * Author: Heiko Stuebner <heiko@sntech.de>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  */
15 
16 #include <linux/slab.h>
17 #include <linux/io.h>
18 #include <linux/reset-controller.h>
19 #include <linux/spinlock.h>
20 #include "clk.h"
21 
22 struct rockchip_softrst {
23 	struct reset_controller_dev	rcdev;
24 	void __iomem			*reg_base;
25 	int				num_regs;
26 	int				num_per_reg;
27 	u8				flags;
28 	spinlock_t			lock;
29 };
30 
31 static int rockchip_softrst_assert(struct reset_controller_dev *rcdev,
32 			      unsigned long id)
33 {
34 	struct rockchip_softrst *softrst = container_of(rcdev,
35 						     struct rockchip_softrst,
36 						     rcdev);
37 	int bank = id / softrst->num_per_reg;
38 	int offset = id % softrst->num_per_reg;
39 
40 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
41 		writel(BIT(offset) | (BIT(offset) << 16),
42 		       softrst->reg_base + (bank * 4));
43 	} else {
44 		unsigned long flags;
45 		u32 reg;
46 
47 		spin_lock_irqsave(&softrst->lock, flags);
48 
49 		reg = readl(softrst->reg_base + (bank * 4));
50 		writel(reg | BIT(offset), softrst->reg_base + (bank * 4));
51 
52 		spin_unlock_irqrestore(&softrst->lock, flags);
53 	}
54 
55 	return 0;
56 }
57 
58 static int rockchip_softrst_deassert(struct reset_controller_dev *rcdev,
59 				unsigned long id)
60 {
61 	struct rockchip_softrst *softrst = container_of(rcdev,
62 						     struct rockchip_softrst,
63 						     rcdev);
64 	int bank = id / softrst->num_per_reg;
65 	int offset = id % softrst->num_per_reg;
66 
67 	if (softrst->flags & ROCKCHIP_SOFTRST_HIWORD_MASK) {
68 		writel((BIT(offset) << 16), softrst->reg_base + (bank * 4));
69 	} else {
70 		unsigned long flags;
71 		u32 reg;
72 
73 		spin_lock_irqsave(&softrst->lock, flags);
74 
75 		reg = readl(softrst->reg_base + (bank * 4));
76 		writel(reg & ~BIT(offset), softrst->reg_base + (bank * 4));
77 
78 		spin_unlock_irqrestore(&softrst->lock, flags);
79 	}
80 
81 	return 0;
82 }
83 
84 static const struct reset_control_ops rockchip_softrst_ops = {
85 	.assert		= rockchip_softrst_assert,
86 	.deassert	= rockchip_softrst_deassert,
87 };
88 
89 void __init rockchip_register_softrst(struct device_node *np,
90 				      unsigned int num_regs,
91 				      void __iomem *base, u8 flags)
92 {
93 	struct rockchip_softrst *softrst;
94 	int ret;
95 
96 	softrst = kzalloc(sizeof(*softrst), GFP_KERNEL);
97 	if (!softrst)
98 		return;
99 
100 	spin_lock_init(&softrst->lock);
101 
102 	softrst->reg_base = base;
103 	softrst->flags = flags;
104 	softrst->num_regs = num_regs;
105 	softrst->num_per_reg = (flags & ROCKCHIP_SOFTRST_HIWORD_MASK) ? 16
106 								      : 32;
107 
108 	softrst->rcdev.owner = THIS_MODULE;
109 	softrst->rcdev.nr_resets =  num_regs * softrst->num_per_reg;
110 	softrst->rcdev.ops = &rockchip_softrst_ops;
111 	softrst->rcdev.of_node = np;
112 	ret = reset_controller_register(&softrst->rcdev);
113 	if (ret) {
114 		pr_err("%s: could not register reset controller, %d\n",
115 		       __func__, ret);
116 		kfree(softrst);
117 	}
118 };
119