1 // SPDX-License-Identifier: GPL-2.0
3 // reset-uniphier-glue.c - Glue layer reset driver for UniPhier
4 // Copyright 2018 Socionext Inc.
5 // Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
8 #include <linux/module.h>
9 #include <linux/of_device.h>
10 #include <linux/platform_device.h>
11 #include <linux/reset.h>
13 #include "reset-simple.h"
18 struct uniphier_glue_reset_soc_data
{
20 const char * const *clock_names
;
22 const char * const *reset_names
;
25 struct uniphier_glue_reset_priv
{
26 struct clk_bulk_data clk
[MAX_CLKS
];
27 struct reset_control
*rst
[MAX_RSTS
];
28 struct reset_simple_data rdata
;
29 const struct uniphier_glue_reset_soc_data
*data
;
32 static int uniphier_glue_reset_probe(struct platform_device
*pdev
)
34 struct device
*dev
= &pdev
->dev
;
35 struct uniphier_glue_reset_priv
*priv
;
41 priv
= devm_kzalloc(dev
, sizeof(*priv
), GFP_KERNEL
);
45 priv
->data
= of_device_get_match_data(dev
);
46 if (WARN_ON(!priv
->data
|| priv
->data
->nclks
> MAX_CLKS
||
47 priv
->data
->nrsts
> MAX_RSTS
))
50 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
51 size
= resource_size(res
);
52 priv
->rdata
.membase
= devm_ioremap_resource(dev
, res
);
53 if (IS_ERR(priv
->rdata
.membase
))
54 return PTR_ERR(priv
->rdata
.membase
);
56 for (i
= 0; i
< priv
->data
->nclks
; i
++)
57 priv
->clk
[i
].id
= priv
->data
->clock_names
[i
];
58 ret
= devm_clk_bulk_get(dev
, priv
->data
->nclks
, priv
->clk
);
62 for (i
= 0; i
< priv
->data
->nrsts
; i
++) {
63 name
= priv
->data
->reset_names
[i
];
64 priv
->rst
[i
] = devm_reset_control_get_shared(dev
, name
);
65 if (IS_ERR(priv
->rst
[i
]))
66 return PTR_ERR(priv
->rst
[i
]);
69 ret
= clk_bulk_prepare_enable(priv
->data
->nclks
, priv
->clk
);
73 for (nr
= 0; nr
< priv
->data
->nrsts
; nr
++) {
74 ret
= reset_control_deassert(priv
->rst
[nr
]);
79 spin_lock_init(&priv
->rdata
.lock
);
80 priv
->rdata
.rcdev
.owner
= THIS_MODULE
;
81 priv
->rdata
.rcdev
.nr_resets
= size
* BITS_PER_BYTE
;
82 priv
->rdata
.rcdev
.ops
= &reset_simple_ops
;
83 priv
->rdata
.rcdev
.of_node
= dev
->of_node
;
84 priv
->rdata
.active_low
= true;
86 platform_set_drvdata(pdev
, priv
);
88 ret
= devm_reset_controller_register(dev
, &priv
->rdata
.rcdev
);
96 reset_control_assert(priv
->rst
[nr
]);
98 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
103 static int uniphier_glue_reset_remove(struct platform_device
*pdev
)
105 struct uniphier_glue_reset_priv
*priv
= platform_get_drvdata(pdev
);
108 for (i
= 0; i
< priv
->data
->nrsts
; i
++)
109 reset_control_assert(priv
->rst
[i
]);
111 clk_bulk_disable_unprepare(priv
->data
->nclks
, priv
->clk
);
116 static const char * const uniphier_pro4_clock_reset_names
[] = {
120 static const struct uniphier_glue_reset_soc_data uniphier_pro4_data
= {
121 .nclks
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
122 .clock_names
= uniphier_pro4_clock_reset_names
,
123 .nrsts
= ARRAY_SIZE(uniphier_pro4_clock_reset_names
),
124 .reset_names
= uniphier_pro4_clock_reset_names
,
127 static const char * const uniphier_pxs2_clock_reset_names
[] = {
131 static const struct uniphier_glue_reset_soc_data uniphier_pxs2_data
= {
132 .nclks
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
133 .clock_names
= uniphier_pxs2_clock_reset_names
,
134 .nrsts
= ARRAY_SIZE(uniphier_pxs2_clock_reset_names
),
135 .reset_names
= uniphier_pxs2_clock_reset_names
,
138 static const struct of_device_id uniphier_glue_reset_match
[] = {
140 .compatible
= "socionext,uniphier-pro4-usb3-reset",
141 .data
= &uniphier_pro4_data
,
144 .compatible
= "socionext,uniphier-pxs2-usb3-reset",
145 .data
= &uniphier_pxs2_data
,
148 .compatible
= "socionext,uniphier-ld20-usb3-reset",
149 .data
= &uniphier_pxs2_data
,
152 .compatible
= "socionext,uniphier-pxs3-usb3-reset",
153 .data
= &uniphier_pxs2_data
,
156 .compatible
= "socionext,uniphier-pro4-ahci-reset",
157 .data
= &uniphier_pro4_data
,
160 .compatible
= "socionext,uniphier-pxs2-ahci-reset",
161 .data
= &uniphier_pxs2_data
,
164 .compatible
= "socionext,uniphier-pxs3-ahci-reset",
165 .data
= &uniphier_pxs2_data
,
169 MODULE_DEVICE_TABLE(of
, uniphier_glue_reset_match
);
171 static struct platform_driver uniphier_glue_reset_driver
= {
172 .probe
= uniphier_glue_reset_probe
,
173 .remove
= uniphier_glue_reset_remove
,
175 .name
= "uniphier-glue-reset",
176 .of_match_table
= uniphier_glue_reset_match
,
179 module_platform_driver(uniphier_glue_reset_driver
);
181 MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
182 MODULE_DESCRIPTION("UniPhier Glue layer reset driver");
183 MODULE_LICENSE("GPL");