1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Support for Atmel/Microchip Reset Controller.
4  *
5  * Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries
6  *
7  * Author: Sergiu Moga <sergiu.moga@microchip.com>
8  */
9 
10 #include <clk.h>
11 #include <asm/io.h>
12 #include <dm.h>
13 #include <dm/lists.h>
14 #include <reset-uclass.h>
15 #include <asm/arch/at91_rstc.h>
16 #include <dt-bindings/reset/sama7g5-reset.h>
17 
18 struct at91_reset {
19 	void __iomem *dev_base;
20 	struct at91_reset_data *data;
21 };
22 
23 struct at91_reset_data {
24 	u32 n_device_reset;
25 	u8 device_reset_min_id;
26 	u8 device_reset_max_id;
27 };
28 
29 static const struct at91_reset_data sama7g5_data = {
30 	.n_device_reset = 3,
31 	.device_reset_min_id = SAMA7G5_RESET_USB_PHY1,
32 	.device_reset_max_id = SAMA7G5_RESET_USB_PHY3,
33 };
34 
at91_rst_update(struct at91_reset * reset,unsigned long id,bool assert)35 static int at91_rst_update(struct at91_reset *reset, unsigned long id,
36 			   bool assert)
37 {
38 	u32 val;
39 
40 	if (!reset->dev_base)
41 		return 0;
42 
43 	val = readl(reset->dev_base);
44 	if (assert)
45 		val |= BIT(id);
46 	else
47 		val &= ~BIT(id);
48 	writel(val, reset->dev_base);
49 
50 	return 0;
51 }
52 
at91_reset_of_xlate(struct reset_ctl * reset_ctl,struct ofnode_phandle_args * args)53 static int at91_reset_of_xlate(struct reset_ctl *reset_ctl,
54 			       struct ofnode_phandle_args *args)
55 {
56 	struct at91_reset *reset = dev_get_priv(reset_ctl->dev);
57 
58 	if (!reset->data->n_device_reset ||
59 	    args->args[0] < reset->data->device_reset_min_id ||
60 	    args->args[0] > reset->data->device_reset_max_id)
61 		return -EINVAL;
62 
63 	reset_ctl->id = args->args[0];
64 
65 	return 0;
66 }
67 
at91_rst_assert(struct reset_ctl * reset_ctl)68 static int at91_rst_assert(struct reset_ctl *reset_ctl)
69 {
70 	struct at91_reset *reset = dev_get_priv(reset_ctl->dev);
71 
72 	return at91_rst_update(reset, reset_ctl->id, true);
73 }
74 
at91_rst_deassert(struct reset_ctl * reset_ctl)75 static int at91_rst_deassert(struct reset_ctl *reset_ctl)
76 {
77 	struct at91_reset *reset = dev_get_priv(reset_ctl->dev);
78 
79 	return at91_rst_update(reset, reset_ctl->id, false);
80 }
81 
82 struct reset_ops at91_reset_ops = {
83 	.of_xlate = at91_reset_of_xlate,
84 	.rst_assert = at91_rst_assert,
85 	.rst_deassert = at91_rst_deassert,
86 };
87 
at91_reset_probe(struct udevice * dev)88 static int at91_reset_probe(struct udevice *dev)
89 {
90 	struct at91_reset *reset = dev_get_priv(dev);
91 	struct clk sclk;
92 	int ret;
93 
94 	reset->data = (struct at91_reset_data *)dev_get_driver_data(dev);
95 	reset->dev_base = dev_remap_addr_index(dev, 1);
96 	if (reset->data && reset->data->n_device_reset && !reset->dev_base)
97 		return -EINVAL;
98 
99 	ret = clk_get_by_index(dev, 0, &sclk);
100 	if (ret)
101 		return ret;
102 
103 	return clk_prepare_enable(&sclk);
104 }
105 
at91_reset_bind(struct udevice * dev)106 static int at91_reset_bind(struct udevice *dev)
107 {
108 	struct udevice *at91_sysreset;
109 
110 	if (CONFIG_IS_ENABLED(SYSRESET_AT91))
111 		return device_bind_driver_to_node(dev, "at91_sysreset",
112 						  "at91_sysreset",
113 						  dev_ofnode(dev),
114 						  &at91_sysreset);
115 
116 	return 0;
117 }
118 
119 static const struct udevice_id at91_reset_ids[] = {
120 	{
121 		.compatible = "microchip,sama7g5-rstc",
122 		.data = (ulong)&sama7g5_data,
123 	},
124 	{
125 		.compatible = "atmel,sama5d3-rstc",
126 	},
127 	{
128 		.compatible = "microchip,sam9x60-rstc",
129 	},
130 	{ }
131 };
132 
133 U_BOOT_DRIVER(at91_reset) = {
134 	.name = "at91_reset",
135 	.id = UCLASS_RESET,
136 	.of_match = at91_reset_ids,
137 	.bind = at91_reset_bind,
138 	.probe = at91_reset_probe,
139 	.priv_auto = sizeof(struct at91_reset),
140 	.ops = &at91_reset_ops,
141 };
142