1 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
3 * Amlogic Meson Reset Controller driver
5 * Copyright (c) 2016 BayLibre, SAS.
6 * Author: Neil Armstrong <narmstrong@baylibre.com>
9 #include <linux/init.h>
12 #include <linux/platform_device.h>
13 #include <linux/reset-controller.h>
14 #include <linux/slab.h>
15 #include <linux/types.h>
16 #include <linux/of_device.h>
18 #define BITS_PER_REG 32
20 struct meson_reset_param
{
26 void __iomem
*reg_base
;
27 const struct meson_reset_param
*param
;
28 struct reset_controller_dev rcdev
;
32 static int meson_reset_reset(struct reset_controller_dev
*rcdev
,
35 struct meson_reset
*data
=
36 container_of(rcdev
, struct meson_reset
, rcdev
);
37 unsigned int bank
= id
/ BITS_PER_REG
;
38 unsigned int offset
= id
% BITS_PER_REG
;
39 void __iomem
*reg_addr
= data
->reg_base
+ (bank
<< 2);
41 writel(BIT(offset
), reg_addr
);
46 static int meson_reset_level(struct reset_controller_dev
*rcdev
,
47 unsigned long id
, bool assert)
49 struct meson_reset
*data
=
50 container_of(rcdev
, struct meson_reset
, rcdev
);
51 unsigned int bank
= id
/ BITS_PER_REG
;
52 unsigned int offset
= id
% BITS_PER_REG
;
53 void __iomem
*reg_addr
;
57 reg_addr
= data
->reg_base
+ data
->param
->level_offset
+ (bank
<< 2);
59 spin_lock_irqsave(&data
->lock
, flags
);
61 reg
= readl(reg_addr
);
63 writel(reg
& ~BIT(offset
), reg_addr
);
65 writel(reg
| BIT(offset
), reg_addr
);
67 spin_unlock_irqrestore(&data
->lock
, flags
);
72 static int meson_reset_assert(struct reset_controller_dev
*rcdev
,
75 return meson_reset_level(rcdev
, id
, true);
78 static int meson_reset_deassert(struct reset_controller_dev
*rcdev
,
81 return meson_reset_level(rcdev
, id
, false);
84 static const struct reset_control_ops meson_reset_ops
= {
85 .reset
= meson_reset_reset
,
86 .assert = meson_reset_assert
,
87 .deassert
= meson_reset_deassert
,
90 static const struct meson_reset_param meson8b_param
= {
95 static const struct meson_reset_param meson_a1_param
= {
100 static const struct of_device_id meson_reset_dt_ids
[] = {
101 { .compatible
= "amlogic,meson8b-reset", .data
= &meson8b_param
},
102 { .compatible
= "amlogic,meson-gxbb-reset", .data
= &meson8b_param
},
103 { .compatible
= "amlogic,meson-axg-reset", .data
= &meson8b_param
},
104 { .compatible
= "amlogic,meson-a1-reset", .data
= &meson_a1_param
},
108 static int meson_reset_probe(struct platform_device
*pdev
)
110 struct meson_reset
*data
;
111 struct resource
*res
;
113 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
117 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
118 data
->reg_base
= devm_ioremap_resource(&pdev
->dev
, res
);
119 if (IS_ERR(data
->reg_base
))
120 return PTR_ERR(data
->reg_base
);
122 data
->param
= of_device_get_match_data(&pdev
->dev
);
126 platform_set_drvdata(pdev
, data
);
128 spin_lock_init(&data
->lock
);
130 data
->rcdev
.owner
= THIS_MODULE
;
131 data
->rcdev
.nr_resets
= data
->param
->reg_count
* BITS_PER_REG
;
132 data
->rcdev
.ops
= &meson_reset_ops
;
133 data
->rcdev
.of_node
= pdev
->dev
.of_node
;
135 return devm_reset_controller_register(&pdev
->dev
, &data
->rcdev
);
138 static struct platform_driver meson_reset_driver
= {
139 .probe
= meson_reset_probe
,
141 .name
= "meson_reset",
142 .of_match_table
= meson_reset_dt_ids
,
145 builtin_platform_driver(meson_reset_driver
);