summaryrefslogtreecommitdiffstats
path: root/drivers/reset/reset-uniphier-glue.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2019-02-08 08:20:32 -0500
committerTakashi Iwai <tiwai@suse.de>2019-02-08 08:20:32 -0500
commitd02cac152c97dffcb0cdd91e09b54fd6e2cca63d (patch)
tree68e4c6bd842703009f3edbf8f0e0e9326e4b2fad /drivers/reset/reset-uniphier-glue.c
parent36e4617c01153757cde9e5fcd375a75a8f8425c3 (diff)
parenta50e32694fbcdbf55875095258b9398e2eabd71f (diff)
Merge tag 'asoc-v5.1' of https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound into for-next
ASoC: Updates for v5.1 Lots and lots of new drivers so far, a highlight being the MediaTek BTCVSD which is a driver for a Bluetooth radio chip - the first such driver we've had upstream. Hopefully we will soon also see a baseband with an upstream driver! - Support for only powering up channels that are actively being used. - Quite a few improvements to simplify the generic card drivers, especially the merge of the SCU cards into the main generic drivers. - Lots of fixes for probing on Intel systems, trying to rationalize things to look more standard from a framework point of view. - New drivers for Asahi Kasei Microdevices AK4497, Cirrus Logic CS4341, Google ChromeOS embedded controllers, Ingenic JZ4725B, MediaTek BTCVSD, MT8183 and MT6358, NXP MICFIL, Rockchip RK3328, Spreadtrum DMA controllers, Qualcomm WCD9335, Xilinx S/PDIF and PCM formatters.
Diffstat (limited to 'drivers/reset/reset-uniphier-glue.c')
-rw-r--r--drivers/reset/reset-uniphier-glue.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/drivers/reset/reset-uniphier-glue.c b/drivers/reset/reset-uniphier-glue.c
new file mode 100644
index 000000000000..a45923f4df6d
--- /dev/null
+++ b/drivers/reset/reset-uniphier-glue.c
@@ -0,0 +1,183 @@
1// SPDX-License-Identifier: GPL-2.0
2//
3// reset-uniphier-glue.c - Glue layer reset driver for UniPhier
4// Copyright 2018 Socionext Inc.
5// Author: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
6
7#include <linux/clk.h>
8#include <linux/module.h>
9#include <linux/of_device.h>
10#include <linux/platform_device.h>
11#include <linux/reset.h>
12
13#include "reset-simple.h"
14
15#define MAX_CLKS 2
16#define MAX_RSTS 2
17
18struct uniphier_glue_reset_soc_data {
19 int nclks;
20 const char * const *clock_names;
21 int nrsts;
22 const char * const *reset_names;
23};
24
25struct 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;
30};
31
32static int uniphier_glue_reset_probe(struct platform_device *pdev)
33{
34 struct device *dev = &pdev->dev;
35 struct uniphier_glue_reset_priv *priv;
36 struct resource *res;
37 resource_size_t size;
38 const char *name;
39 int i, ret, nr;
40
41 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
42 if (!priv)
43 return -ENOMEM;
44
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))
48 return -EINVAL;
49
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);
55
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);
59 if (ret)
60 return ret;
61
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]);
67 }
68
69 ret = clk_bulk_prepare_enable(priv->data->nclks, priv->clk);
70 if (ret)
71 return ret;
72
73 for (nr = 0; nr < priv->data->nrsts; nr++) {
74 ret = reset_control_deassert(priv->rst[nr]);
75 if (ret)
76 goto out_rst_assert;
77 }
78
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;
85
86 platform_set_drvdata(pdev, priv);
87
88 ret = devm_reset_controller_register(dev, &priv->rdata.rcdev);
89 if (ret)
90 goto out_rst_assert;
91
92 return 0;
93
94out_rst_assert:
95 while (nr--)
96 reset_control_assert(priv->rst[nr]);
97
98 clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
99
100 return ret;
101}
102
103static int uniphier_glue_reset_remove(struct platform_device *pdev)
104{
105 struct uniphier_glue_reset_priv *priv = platform_get_drvdata(pdev);
106 int i;
107
108 for (i = 0; i < priv->data->nrsts; i++)
109 reset_control_assert(priv->rst[i]);
110
111 clk_bulk_disable_unprepare(priv->data->nclks, priv->clk);
112
113 return 0;
114}
115
116static const char * const uniphier_pro4_clock_reset_names[] = {
117 "gio", "link",
118};
119
120static 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,
125};
126
127static const char * const uniphier_pxs2_clock_reset_names[] = {
128 "link",
129};
130
131static 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,
136};
137
138static const struct of_device_id uniphier_glue_reset_match[] = {
139 {
140 .compatible = "socionext,uniphier-pro4-usb3-reset",
141 .data = &uniphier_pro4_data,
142 },
143 {
144 .compatible = "socionext,uniphier-pxs2-usb3-reset",
145 .data = &uniphier_pxs2_data,
146 },
147 {
148 .compatible = "socionext,uniphier-ld20-usb3-reset",
149 .data = &uniphier_pxs2_data,
150 },
151 {
152 .compatible = "socionext,uniphier-pxs3-usb3-reset",
153 .data = &uniphier_pxs2_data,
154 },
155 {
156 .compatible = "socionext,uniphier-pro4-ahci-reset",
157 .data = &uniphier_pro4_data,
158 },
159 {
160 .compatible = "socionext,uniphier-pxs2-ahci-reset",
161 .data = &uniphier_pxs2_data,
162 },
163 {
164 .compatible = "socionext,uniphier-pxs3-ahci-reset",
165 .data = &uniphier_pxs2_data,
166 },
167 { /* Sentinel */ }
168};
169MODULE_DEVICE_TABLE(of, uniphier_glue_reset_match);
170
171static struct platform_driver uniphier_glue_reset_driver = {
172 .probe = uniphier_glue_reset_probe,
173 .remove = uniphier_glue_reset_remove,
174 .driver = {
175 .name = "uniphier-glue-reset",
176 .of_match_table = uniphier_glue_reset_match,
177 },
178};
179module_platform_driver(uniphier_glue_reset_driver);
180
181MODULE_AUTHOR("Kunihiko Hayashi <hayashi.kunihiko@socionext.com>");
182MODULE_DESCRIPTION("UniPhier Glue layer reset driver");
183MODULE_LICENSE("GPL");