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/module.h>
13 #include <linux/platform_device.h>
14 #include <linux/reset-controller.h>
15 #include <linux/slab.h>
16 #include <linux/types.h>
17 #include <linux/of_device.h>
19 #define BITS_PER_REG 32
21 struct meson_reset_param
{
27 void __iomem
*reg_base
;
28 const struct meson_reset_param
*param
;
29 struct reset_controller_dev rcdev
;
33 static int meson_reset_reset(struct reset_controller_dev
*rcdev
,
36 struct meson_reset
*data
=
37 container_of(rcdev
, struct meson_reset
, rcdev
);
38 unsigned int bank
= id
/ BITS_PER_REG
;
39 unsigned int offset
= id
% BITS_PER_REG
;
40 void __iomem
*reg_addr
= data
->reg_base
+ (bank
<< 2);
42 writel(BIT(offset
), reg_addr
);
47 static int meson_reset_level(struct reset_controller_dev
*rcdev
,
48 unsigned long id
, bool assert)
50 struct meson_reset
*data
=
51 container_of(rcdev
, struct meson_reset
, rcdev
);
52 unsigned int bank
= id
/ BITS_PER_REG
;
53 unsigned int offset
= id
% BITS_PER_REG
;
54 void __iomem
*reg_addr
;
58 reg_addr
= data
->reg_base
+ data
->param
->level_offset
+ (bank
<< 2);
60 spin_lock_irqsave(&data
->lock
, flags
);
62 reg
= readl(reg_addr
);
64 writel(reg
& ~BIT(offset
), reg_addr
);
66 writel(reg
| BIT(offset
), reg_addr
);
68 spin_unlock_irqrestore(&data
->lock
, flags
);
73 static int meson_reset_assert(struct reset_controller_dev
*rcdev
,
76 return meson_reset_level(rcdev
, id
, true);
79 static int meson_reset_deassert(struct reset_controller_dev
*rcdev
,
82 return meson_reset_level(rcdev
, id
, false);
85 static const struct reset_control_ops meson_reset_ops
= {
86 .reset
= meson_reset_reset
,
87 .assert = meson_reset_assert
,
88 .deassert
= meson_reset_deassert
,
91 static const struct meson_reset_param meson8b_param
= {
96 static const struct meson_reset_param meson_a1_param
= {
101 static const struct of_device_id meson_reset_dt_ids
[] = {
102 { .compatible
= "amlogic,meson8b-reset", .data
= &meson8b_param
},
103 { .compatible
= "amlogic,meson-gxbb-reset", .data
= &meson8b_param
},
104 { .compatible
= "amlogic,meson-axg-reset", .data
= &meson8b_param
},
105 { .compatible
= "amlogic,meson-a1-reset", .data
= &meson_a1_param
},
108 MODULE_DEVICE_TABLE(of
, meson_reset_dt_ids
);
110 static int meson_reset_probe(struct platform_device
*pdev
)
112 struct meson_reset
*data
;
113 struct resource
*res
;
115 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
119 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
120 data
->reg_base
= devm_ioremap_resource(&pdev
->dev
, res
);
121 if (IS_ERR(data
->reg_base
))
122 return PTR_ERR(data
->reg_base
);
124 data
->param
= of_device_get_match_data(&pdev
->dev
);
128 platform_set_drvdata(pdev
, data
);
130 spin_lock_init(&data
->lock
);
132 data
->rcdev
.owner
= THIS_MODULE
;
133 data
->rcdev
.nr_resets
= data
->param
->reg_count
* BITS_PER_REG
;
134 data
->rcdev
.ops
= &meson_reset_ops
;
135 data
->rcdev
.of_node
= pdev
->dev
.of_node
;
137 return devm_reset_controller_register(&pdev
->dev
, &data
->rcdev
);
140 static struct platform_driver meson_reset_driver
= {
141 .probe
= meson_reset_probe
,
143 .name
= "meson_reset",
144 .of_match_table
= meson_reset_dt_ids
,
147 module_platform_driver(meson_reset_driver
);
149 MODULE_DESCRIPTION("Amlogic Meson Reset Controller driver");
150 MODULE_AUTHOR("Neil Armstrong <narmstrong@baylibre.com>");
151 MODULE_LICENSE("Dual BSD/GPL");