]>
Commit | Line | Data |
---|---|---|
7c61ccf6 | 1 | // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause |
c7224dc3 | 2 | /* |
8290924e PG |
3 | * Amlogic Meson Reset Controller driver |
4 | * | |
c7224dc3 NA |
5 | * Copyright (c) 2016 BayLibre, SAS. |
6 | * Author: Neil Armstrong <[email protected]> | |
c7224dc3 NA |
7 | */ |
8 | #include <linux/err.h> | |
8290924e | 9 | #include <linux/init.h> |
c7224dc3 NA |
10 | #include <linux/io.h> |
11 | #include <linux/of.h> | |
12 | #include <linux/platform_device.h> | |
13 | #include <linux/reset-controller.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/types.h> | |
a5a10afe | 16 | #include <linux/of_device.h> |
c7224dc3 NA |
17 | |
18 | #define REG_COUNT 8 | |
19 | #define BITS_PER_REG 32 | |
a5a10afe | 20 | #define LEVEL_OFFSET 0x7c |
c7224dc3 NA |
21 | |
22 | struct meson_reset { | |
23 | void __iomem *reg_base; | |
24 | struct reset_controller_dev rcdev; | |
a5a10afe | 25 | spinlock_t lock; |
c7224dc3 NA |
26 | }; |
27 | ||
28 | static int meson_reset_reset(struct reset_controller_dev *rcdev, | |
29 | unsigned long id) | |
30 | { | |
31 | struct meson_reset *data = | |
32 | container_of(rcdev, struct meson_reset, rcdev); | |
33 | unsigned int bank = id / BITS_PER_REG; | |
34 | unsigned int offset = id % BITS_PER_REG; | |
35 | void __iomem *reg_addr = data->reg_base + (bank << 2); | |
36 | ||
c7224dc3 NA |
37 | writel(BIT(offset), reg_addr); |
38 | ||
39 | return 0; | |
40 | } | |
41 | ||
a5a10afe NA |
42 | static int meson_reset_level(struct reset_controller_dev *rcdev, |
43 | unsigned long id, bool assert) | |
44 | { | |
45 | struct meson_reset *data = | |
46 | container_of(rcdev, struct meson_reset, rcdev); | |
47 | unsigned int bank = id / BITS_PER_REG; | |
48 | unsigned int offset = id % BITS_PER_REG; | |
49 | void __iomem *reg_addr = data->reg_base + LEVEL_OFFSET + (bank << 2); | |
50 | unsigned long flags; | |
51 | u32 reg; | |
52 | ||
53 | spin_lock_irqsave(&data->lock, flags); | |
54 | ||
55 | reg = readl(reg_addr); | |
56 | if (assert) | |
57 | writel(reg & ~BIT(offset), reg_addr); | |
58 | else | |
59 | writel(reg | BIT(offset), reg_addr); | |
60 | ||
61 | spin_unlock_irqrestore(&data->lock, flags); | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static int meson_reset_assert(struct reset_controller_dev *rcdev, | |
67 | unsigned long id) | |
68 | { | |
69 | return meson_reset_level(rcdev, id, true); | |
70 | } | |
71 | ||
72 | static int meson_reset_deassert(struct reset_controller_dev *rcdev, | |
73 | unsigned long id) | |
74 | { | |
75 | return meson_reset_level(rcdev, id, false); | |
76 | } | |
77 | ||
320da785 | 78 | static const struct reset_control_ops meson_reset_ops = { |
a5a10afe NA |
79 | .reset = meson_reset_reset, |
80 | .assert = meson_reset_assert, | |
81 | .deassert = meson_reset_deassert, | |
82 | }; | |
83 | ||
c7224dc3 | 84 | static const struct of_device_id meson_reset_dt_ids[] = { |
320da785 MB |
85 | { .compatible = "amlogic,meson8b-reset" }, |
86 | { .compatible = "amlogic,meson-gxbb-reset" }, | |
87 | { .compatible = "amlogic,meson-axg-reset" }, | |
c7224dc3 NA |
88 | { /* sentinel */ }, |
89 | }; | |
c7224dc3 NA |
90 | |
91 | static int meson_reset_probe(struct platform_device *pdev) | |
92 | { | |
93 | struct meson_reset *data; | |
94 | struct resource *res; | |
95 | ||
96 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | |
97 | if (!data) | |
98 | return -ENOMEM; | |
99 | ||
100 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
101 | data->reg_base = devm_ioremap_resource(&pdev->dev, res); | |
102 | if (IS_ERR(data->reg_base)) | |
103 | return PTR_ERR(data->reg_base); | |
104 | ||
105 | platform_set_drvdata(pdev, data); | |
106 | ||
a5a10afe NA |
107 | spin_lock_init(&data->lock); |
108 | ||
c7224dc3 NA |
109 | data->rcdev.owner = THIS_MODULE; |
110 | data->rcdev.nr_resets = REG_COUNT * BITS_PER_REG; | |
320da785 | 111 | data->rcdev.ops = &meson_reset_ops; |
c7224dc3 NA |
112 | data->rcdev.of_node = pdev->dev.of_node; |
113 | ||
114 | return devm_reset_controller_register(&pdev->dev, &data->rcdev); | |
115 | } | |
116 | ||
117 | static struct platform_driver meson_reset_driver = { | |
118 | .probe = meson_reset_probe, | |
119 | .driver = { | |
120 | .name = "meson_reset", | |
121 | .of_match_table = meson_reset_dt_ids, | |
122 | }, | |
123 | }; | |
8290924e | 124 | builtin_platform_driver(meson_reset_driver); |