041717c2991654000496c9132b8bd0cad7940abb
[openwrt/openwrt.git] / target / linux / gemini / patches-4.19 / 0013-usb-host-fotg2-add-silicon-clock-handling.patch
1 From e76906e8e9dfaeeb22a37706aca493b86e4367bd Mon Sep 17 00:00:00 2001
2 From: Linus Walleij <linus.walleij@linaro.org>
3 Date: Fri, 21 Apr 2017 20:46:12 +0200
4 Subject: [PATCH 13/18] usb: host: fotg2: add silicon clock handling
5
6 When used in a system with software-controlled silicon clocks,
7 the FOTG210 needs to grab, prepare and enable the clock.
8
9 This is needed on for example the Cortina Gemini, where the
10 platform will by default gate off the clock unless the
11 peripheral (in this case the USB driver) grabs and enables
12 the clock.
13
14 If there is no clock available on the platform, we live
15 without it. Make sure to percolate probe deferrals.
16
17 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
18 ---
19 ChangeLog v1->v2:
20 - Handle probe deferrals on the clock controller, no matter
21 how unlikely they are.
22 - Send the patch to get Gemini USB rolling and try to get some
23 stuff upstream, this patch should be fine on its own.
24 ---
25 drivers/usb/host/fotg210-hcd.c | 33 +++++++++++++++++++++++++++++----
26 drivers/usb/host/fotg210.h | 3 +++
27 2 files changed, 32 insertions(+), 4 deletions(-)
28
29 diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
30 index e64eb47770c8..058ff82ea789 100644
31 --- a/drivers/usb/host/fotg210-hcd.c
32 +++ b/drivers/usb/host/fotg210-hcd.c
33 @@ -31,6 +31,7 @@
34 #include <linux/uaccess.h>
35 #include <linux/platform_device.h>
36 #include <linux/io.h>
37 +#include <linux/clk.h>
38
39 #include <asm/byteorder.h>
40 #include <asm/irq.h>
41 @@ -5596,7 +5597,7 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
42 hcd->regs = devm_ioremap_resource(&pdev->dev, res);
43 if (IS_ERR(hcd->regs)) {
44 retval = PTR_ERR(hcd->regs);
45 - goto failed;
46 + goto failed_put_hcd;
47 }
48
49 hcd->rsrc_start = res->start;
50 @@ -5606,22 +5607,42 @@ static int fotg210_hcd_probe(struct platform_device *pdev)
51
52 fotg210->caps = hcd->regs;
53
54 + /* It's OK not to supply this clock */
55 + fotg210->pclk = clk_get(dev, "PCLK");
56 + if (!IS_ERR(fotg210->pclk)) {
57 + retval = clk_prepare_enable(fotg210->pclk);
58 + if (retval) {
59 + dev_err(dev, "failed to enable PCLK\n");
60 + goto failed_put_hcd;
61 + }
62 + } else if (PTR_ERR(fotg210->pclk) == -EPROBE_DEFER) {
63 + /*
64 + * Percolate deferrals, for anything else,
65 + * just live without the clocking.
66 + */
67 + retval = PTR_ERR(fotg210->pclk);
68 + goto failed_dis_clk;
69 + }
70 +
71 retval = fotg210_setup(hcd);
72 if (retval)
73 - goto failed;
74 + goto failed_dis_clk;
75
76 fotg210_init(fotg210);
77
78 retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
79 if (retval) {
80 dev_err(dev, "failed to add hcd with err %d\n", retval);
81 - goto failed;
82 + goto failed_dis_clk;
83 }
84 device_wakeup_enable(hcd->self.controller);
85
86 return retval;
87
88 -failed:
89 +failed_dis_clk:
90 + if (!IS_ERR(fotg210->pclk))
91 + clk_disable_unprepare(fotg210->pclk);
92 +failed_put_hcd:
93 usb_put_hcd(hcd);
94 fail_create_hcd:
95 dev_err(dev, "init %s fail, %d\n", dev_name(dev), retval);
96 @@ -5637,6 +5658,10 @@ static int fotg210_hcd_remove(struct platform_device *pdev)
97 {
98 struct device *dev = &pdev->dev;
99 struct usb_hcd *hcd = dev_get_drvdata(dev);
100 + struct fotg210_hcd *fotg210 = hcd_to_fotg210(hcd);
101 +
102 + if (!IS_ERR(fotg210->pclk))
103 + clk_disable_unprepare(fotg210->pclk);
104
105 if (!hcd)
106 return 0;
107 diff --git a/drivers/usb/host/fotg210.h b/drivers/usb/host/fotg210.h
108 index 7fcd785c7bc8..28f6467c0cbf 100644
109 --- a/drivers/usb/host/fotg210.h
110 +++ b/drivers/usb/host/fotg210.h
111 @@ -182,6 +182,9 @@ struct fotg210_hcd { /* one per controller */
112 # define COUNT(x)
113 #endif
114
115 + /* silicon clock */
116 + struct clk *pclk;
117 +
118 /* debug files */
119 struct dentry *debug_dir;
120 };
121 --
122 2.19.2
123