|
11 | 11 | #include <linux/of.h>
|
12 | 12 | #include <linux/module.h>
|
13 | 13 | #include <linux/platform_device.h>
|
| 14 | +#include <linux/regmap.h> |
14 | 15 | #include <linux/reset-controller.h>
|
15 | 16 | #include <linux/slab.h>
|
16 | 17 | #include <linux/types.h>
|
17 | 18 |
|
18 |
| -#define BITS_PER_REG 32 |
19 |
| - |
20 | 19 | struct meson_reset_param {
|
21 | 20 | int reg_count;
|
22 | 21 | int level_offset;
|
23 | 22 | };
|
24 | 23 |
|
25 | 24 | struct meson_reset {
|
26 |
| - void __iomem *reg_base; |
27 | 25 | const struct meson_reset_param *param;
|
28 | 26 | struct reset_controller_dev rcdev;
|
29 |
| - spinlock_t lock; |
| 27 | + struct regmap *map; |
30 | 28 | };
|
31 | 29 |
|
| 30 | +static void meson_reset_offset_and_bit(struct meson_reset *data, |
| 31 | + unsigned long id, |
| 32 | + unsigned int *offset, |
| 33 | + unsigned int *bit) |
| 34 | +{ |
| 35 | + unsigned int stride = regmap_get_reg_stride(data->map); |
| 36 | + |
| 37 | + *offset = (id / (stride * BITS_PER_BYTE)) * stride; |
| 38 | + *bit = id % (stride * BITS_PER_BYTE); |
| 39 | +} |
| 40 | + |
32 | 41 | static int meson_reset_reset(struct reset_controller_dev *rcdev,
|
33 |
| - unsigned long id) |
| 42 | + unsigned long id) |
34 | 43 | {
|
35 | 44 | struct meson_reset *data =
|
36 | 45 | 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); |
| 46 | + unsigned int offset, bit; |
40 | 47 |
|
41 |
| - writel(BIT(offset), reg_addr); |
| 48 | + meson_reset_offset_and_bit(data, id, &offset, &bit); |
42 | 49 |
|
43 |
| - return 0; |
| 50 | + return regmap_write(data->map, offset, BIT(bit)); |
44 | 51 | }
|
45 | 52 |
|
46 | 53 | static int meson_reset_level(struct reset_controller_dev *rcdev,
|
47 | 54 | unsigned long id, bool assert)
|
48 | 55 | {
|
49 | 56 | struct meson_reset *data =
|
50 | 57 | 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; |
54 |
| - unsigned long flags; |
55 |
| - u32 reg; |
| 58 | + unsigned int offset, bit; |
56 | 59 |
|
57 |
| - reg_addr = data->reg_base + data->param->level_offset + (bank << 2); |
| 60 | + meson_reset_offset_and_bit(data, id, &offset, &bit); |
| 61 | + offset += data->param->level_offset; |
58 | 62 |
|
59 |
| - spin_lock_irqsave(&data->lock, flags); |
60 |
| - |
61 |
| - reg = readl(reg_addr); |
62 |
| - if (assert) |
63 |
| - writel(reg & ~BIT(offset), reg_addr); |
64 |
| - else |
65 |
| - writel(reg | BIT(offset), reg_addr); |
66 |
| - |
67 |
| - spin_unlock_irqrestore(&data->lock, flags); |
68 |
| - |
69 |
| - return 0; |
| 63 | + return regmap_update_bits(data->map, offset, |
| 64 | + BIT(bit), assert ? 0 : BIT(bit)); |
70 | 65 | }
|
71 | 66 |
|
72 | 67 | static int meson_reset_assert(struct reset_controller_dev *rcdev,
|
@@ -119,30 +114,42 @@ static const struct of_device_id meson_reset_dt_ids[] = {
|
119 | 114 | };
|
120 | 115 | MODULE_DEVICE_TABLE(of, meson_reset_dt_ids);
|
121 | 116 |
|
| 117 | +static const struct regmap_config regmap_config = { |
| 118 | + .reg_bits = 32, |
| 119 | + .val_bits = 32, |
| 120 | + .reg_stride = 4, |
| 121 | +}; |
| 122 | + |
122 | 123 | static int meson_reset_probe(struct platform_device *pdev)
|
123 | 124 | {
|
| 125 | + struct device *dev = &pdev->dev; |
124 | 126 | struct meson_reset *data;
|
| 127 | + void __iomem *base; |
125 | 128 |
|
126 |
| - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
| 129 | + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); |
127 | 130 | if (!data)
|
128 | 131 | return -ENOMEM;
|
129 | 132 |
|
130 |
| - data->reg_base = devm_platform_ioremap_resource(pdev, 0); |
131 |
| - if (IS_ERR(data->reg_base)) |
132 |
| - return PTR_ERR(data->reg_base); |
| 133 | + base = devm_platform_ioremap_resource(pdev, 0); |
| 134 | + if (IS_ERR(base)) |
| 135 | + return PTR_ERR(base); |
133 | 136 |
|
134 |
| - data->param = of_device_get_match_data(&pdev->dev); |
| 137 | + data->param = of_device_get_match_data(dev); |
135 | 138 | if (!data->param)
|
136 | 139 | return -ENODEV;
|
137 | 140 |
|
138 |
| - spin_lock_init(&data->lock); |
| 141 | + data->map = devm_regmap_init_mmio(dev, base, ®map_config); |
| 142 | + if (IS_ERR(data->map)) |
| 143 | + return dev_err_probe(dev, PTR_ERR(data->map), |
| 144 | + "can't init regmap mmio region\n"); |
139 | 145 |
|
140 | 146 | data->rcdev.owner = THIS_MODULE;
|
141 |
| - data->rcdev.nr_resets = data->param->reg_count * BITS_PER_REG; |
| 147 | + data->rcdev.nr_resets = data->param->reg_count * BITS_PER_BYTE |
| 148 | + * regmap_config.reg_stride; |
142 | 149 | data->rcdev.ops = &meson_reset_ops;
|
143 |
| - data->rcdev.of_node = pdev->dev.of_node; |
| 150 | + data->rcdev.of_node = dev->of_node; |
144 | 151 |
|
145 |
| - return devm_reset_controller_register(&pdev->dev, &data->rcdev); |
| 152 | + return devm_reset_controller_register(dev, &data->rcdev); |
146 | 153 | }
|
147 | 154 |
|
148 | 155 | static struct platform_driver meson_reset_driver = {
|
|
0 commit comments