]> Git Repo - linux.git/blob - drivers/usb/chipidea/ci_hdrc_msm.c
ARM: dts: imx7s: Enable SNVS power key according to board design
[linux.git] / drivers / usb / chipidea / ci_hdrc_msm.c
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2010, Code Aurora Forum. All rights reserved. */
3
4 #include <linux/module.h>
5 #include <linux/platform_device.h>
6 #include <linux/pm_runtime.h>
7 #include <linux/usb/chipidea.h>
8 #include <linux/clk.h>
9 #include <linux/reset.h>
10 #include <linux/mfd/syscon.h>
11 #include <linux/regmap.h>
12 #include <linux/io.h>
13 #include <linux/reset-controller.h>
14 #include <linux/extcon.h>
15 #include <linux/of.h>
16
17 #include "ci.h"
18
19 #define HS_PHY_AHB_MODE                 0x0098
20
21 #define HS_PHY_GENCONFIG                0x009c
22 #define HS_PHY_TXFIFO_IDLE_FORCE_DIS    BIT(4)
23
24 #define HS_PHY_GENCONFIG_2              0x00a0
25 #define HS_PHY_SESS_VLD_CTRL_EN         BIT(7)
26 #define HS_PHY_ULPI_TX_PKT_EN_CLR_FIX   BIT(19)
27
28 #define HSPHY_SESS_VLD_CTRL             BIT(25)
29
30 /* Vendor base starts at 0x200 beyond CI base */
31 #define HS_PHY_CTRL                     0x0040
32 #define HS_PHY_SEC_CTRL                 0x0078
33 #define HS_PHY_DIG_CLAMP_N              BIT(16)
34 #define HS_PHY_POR_ASSERT               BIT(0)
35
36 struct ci_hdrc_msm {
37         struct platform_device *ci;
38         struct clk *core_clk;
39         struct clk *iface_clk;
40         struct clk *fs_clk;
41         struct ci_hdrc_platform_data pdata;
42         struct reset_controller_dev rcdev;
43         bool secondary_phy;
44         bool hsic;
45         void __iomem *base;
46 };
47
48 static int
49 ci_hdrc_msm_por_reset(struct reset_controller_dev *r, unsigned long id)
50 {
51         struct ci_hdrc_msm *ci_msm = container_of(r, struct ci_hdrc_msm, rcdev);
52         void __iomem *addr = ci_msm->base;
53         u32 val;
54
55         if (id)
56                 addr += HS_PHY_SEC_CTRL;
57         else
58                 addr += HS_PHY_CTRL;
59
60         val = readl_relaxed(addr);
61         val |= HS_PHY_POR_ASSERT;
62         writel(val, addr);
63         /*
64          * wait for minimum 10 microseconds as suggested by manual.
65          * Use a slightly larger value since the exact value didn't
66          * work 100% of the time.
67          */
68         udelay(12);
69         val &= ~HS_PHY_POR_ASSERT;
70         writel(val, addr);
71
72         return 0;
73 }
74
75 static const struct reset_control_ops ci_hdrc_msm_reset_ops = {
76         .reset = ci_hdrc_msm_por_reset,
77 };
78
79 static int ci_hdrc_msm_notify_event(struct ci_hdrc *ci, unsigned event)
80 {
81         struct device *dev = ci->dev->parent;
82         struct ci_hdrc_msm *msm_ci = dev_get_drvdata(dev);
83         int ret;
84
85         switch (event) {
86         case CI_HDRC_CONTROLLER_RESET_EVENT:
87                 dev_dbg(dev, "CI_HDRC_CONTROLLER_RESET_EVENT received\n");
88
89                 hw_phymode_configure(ci);
90                 if (msm_ci->secondary_phy) {
91                         u32 val = readl_relaxed(msm_ci->base + HS_PHY_SEC_CTRL);
92                         val |= HS_PHY_DIG_CLAMP_N;
93                         writel_relaxed(val, msm_ci->base + HS_PHY_SEC_CTRL);
94                 }
95
96                 ret = phy_init(ci->phy);
97                 if (ret)
98                         return ret;
99
100                 ret = phy_power_on(ci->phy);
101                 if (ret) {
102                         phy_exit(ci->phy);
103                         return ret;
104                 }
105
106                 /* use AHB transactor, allow posted data writes */
107                 hw_write_id_reg(ci, HS_PHY_AHB_MODE, 0xffffffff, 0x8);
108
109                 /* workaround for rx buffer collision issue */
110                 hw_write_id_reg(ci, HS_PHY_GENCONFIG,
111                                 HS_PHY_TXFIFO_IDLE_FORCE_DIS, 0);
112
113                 if (!msm_ci->hsic)
114                         hw_write_id_reg(ci, HS_PHY_GENCONFIG_2,
115                                         HS_PHY_ULPI_TX_PKT_EN_CLR_FIX, 0);
116
117                 if (!IS_ERR(ci->platdata->vbus_extcon.edev)) {
118                         hw_write_id_reg(ci, HS_PHY_GENCONFIG_2,
119                                         HS_PHY_SESS_VLD_CTRL_EN,
120                                         HS_PHY_SESS_VLD_CTRL_EN);
121                         hw_write(ci, OP_USBCMD, HSPHY_SESS_VLD_CTRL,
122                                  HSPHY_SESS_VLD_CTRL);
123
124                 }
125                 break;
126         case CI_HDRC_CONTROLLER_STOPPED_EVENT:
127                 dev_dbg(dev, "CI_HDRC_CONTROLLER_STOPPED_EVENT received\n");
128                 phy_power_off(ci->phy);
129                 phy_exit(ci->phy);
130                 break;
131         default:
132                 dev_dbg(dev, "unknown ci_hdrc event\n");
133                 break;
134         }
135
136         return 0;
137 }
138
139 static int ci_hdrc_msm_mux_phy(struct ci_hdrc_msm *ci,
140                                struct platform_device *pdev)
141 {
142         struct regmap *regmap;
143         struct device *dev = &pdev->dev;
144         struct of_phandle_args args;
145         u32 val;
146         int ret;
147
148         ret = of_parse_phandle_with_fixed_args(dev->of_node, "phy-select", 2, 0,
149                                                &args);
150         if (ret)
151                 return 0;
152
153         regmap = syscon_node_to_regmap(args.np);
154         of_node_put(args.np);
155         if (IS_ERR(regmap))
156                 return PTR_ERR(regmap);
157
158         ret = regmap_write(regmap, args.args[0], args.args[1]);
159         if (ret)
160                 return ret;
161
162         ci->secondary_phy = !!args.args[1];
163         if (ci->secondary_phy) {
164                 val = readl_relaxed(ci->base + HS_PHY_SEC_CTRL);
165                 val |= HS_PHY_DIG_CLAMP_N;
166                 writel_relaxed(val, ci->base + HS_PHY_SEC_CTRL);
167         }
168
169         return 0;
170 }
171
172 static int ci_hdrc_msm_probe(struct platform_device *pdev)
173 {
174         struct ci_hdrc_msm *ci;
175         struct platform_device *plat_ci;
176         struct clk *clk;
177         struct reset_control *reset;
178         struct resource *res;
179         int ret;
180         struct device_node *ulpi_node, *phy_node;
181
182         dev_dbg(&pdev->dev, "ci_hdrc_msm_probe\n");
183
184         ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
185         if (!ci)
186                 return -ENOMEM;
187         platform_set_drvdata(pdev, ci);
188
189         ci->pdata.name = "ci_hdrc_msm";
190         ci->pdata.capoffset = DEF_CAPOFFSET;
191         ci->pdata.flags = CI_HDRC_REGS_SHARED | CI_HDRC_DISABLE_STREAMING |
192                           CI_HDRC_OVERRIDE_AHB_BURST |
193                           CI_HDRC_OVERRIDE_PHY_CONTROL;
194         ci->pdata.notify_event = ci_hdrc_msm_notify_event;
195
196         reset = devm_reset_control_get(&pdev->dev, "core");
197         if (IS_ERR(reset))
198                 return PTR_ERR(reset);
199
200         ci->core_clk = clk = devm_clk_get(&pdev->dev, "core");
201         if (IS_ERR(clk))
202                 return PTR_ERR(clk);
203
204         ci->iface_clk = clk = devm_clk_get(&pdev->dev, "iface");
205         if (IS_ERR(clk))
206                 return PTR_ERR(clk);
207
208         ci->fs_clk = clk = devm_clk_get_optional(&pdev->dev, "fs");
209         if (IS_ERR(clk))
210                 return PTR_ERR(clk);
211
212         res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
213         ci->base = devm_ioremap_resource(&pdev->dev, res);
214         if (IS_ERR(ci->base))
215                 return PTR_ERR(ci->base);
216
217         ci->rcdev.owner = THIS_MODULE;
218         ci->rcdev.ops = &ci_hdrc_msm_reset_ops;
219         ci->rcdev.of_node = pdev->dev.of_node;
220         ci->rcdev.nr_resets = 2;
221         ret = reset_controller_register(&ci->rcdev);
222         if (ret)
223                 return ret;
224
225         ret = clk_prepare_enable(ci->fs_clk);
226         if (ret)
227                 goto err_fs;
228
229         reset_control_assert(reset);
230         usleep_range(10000, 12000);
231         reset_control_deassert(reset);
232
233         clk_disable_unprepare(ci->fs_clk);
234
235         ret = clk_prepare_enable(ci->core_clk);
236         if (ret)
237                 goto err_fs;
238
239         ret = clk_prepare_enable(ci->iface_clk);
240         if (ret)
241                 goto err_iface;
242
243         ret = ci_hdrc_msm_mux_phy(ci, pdev);
244         if (ret)
245                 goto err_mux;
246
247         ulpi_node = of_get_child_by_name(pdev->dev.of_node, "ulpi");
248         if (ulpi_node) {
249                 phy_node = of_get_next_available_child(ulpi_node, NULL);
250                 ci->hsic = of_device_is_compatible(phy_node, "qcom,usb-hsic-phy");
251                 of_node_put(phy_node);
252         }
253         of_node_put(ulpi_node);
254
255         plat_ci = ci_hdrc_add_device(&pdev->dev, pdev->resource,
256                                      pdev->num_resources, &ci->pdata);
257         if (IS_ERR(plat_ci)) {
258                 ret = PTR_ERR(plat_ci);
259                 if (ret != -EPROBE_DEFER)
260                         dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
261                 goto err_mux;
262         }
263
264         ci->ci = plat_ci;
265
266         pm_runtime_set_active(&pdev->dev);
267         pm_runtime_no_callbacks(&pdev->dev);
268         pm_runtime_enable(&pdev->dev);
269
270         return 0;
271
272 err_mux:
273         clk_disable_unprepare(ci->iface_clk);
274 err_iface:
275         clk_disable_unprepare(ci->core_clk);
276 err_fs:
277         reset_controller_unregister(&ci->rcdev);
278         return ret;
279 }
280
281 static int ci_hdrc_msm_remove(struct platform_device *pdev)
282 {
283         struct ci_hdrc_msm *ci = platform_get_drvdata(pdev);
284
285         pm_runtime_disable(&pdev->dev);
286         ci_hdrc_remove_device(ci->ci);
287         clk_disable_unprepare(ci->iface_clk);
288         clk_disable_unprepare(ci->core_clk);
289         reset_controller_unregister(&ci->rcdev);
290
291         return 0;
292 }
293
294 static const struct of_device_id msm_ci_dt_match[] = {
295         { .compatible = "qcom,ci-hdrc", },
296         { }
297 };
298 MODULE_DEVICE_TABLE(of, msm_ci_dt_match);
299
300 static struct platform_driver ci_hdrc_msm_driver = {
301         .probe = ci_hdrc_msm_probe,
302         .remove = ci_hdrc_msm_remove,
303         .driver = {
304                 .name = "msm_hsusb",
305                 .of_match_table = msm_ci_dt_match,
306         },
307 };
308
309 module_platform_driver(ci_hdrc_msm_driver);
310
311 MODULE_ALIAS("platform:msm_hsusb");
312 MODULE_ALIAS("platform:ci13xxx_msm");
313 MODULE_LICENSE("GPL v2");
This page took 0.048102 seconds and 4 git commands to generate.