kernel: backport bcma patches queued for 3.20
[openwrt/svn-archive/archive.git] / target / linux / ipq806x / patches / 0110-ahci-platform-Add-support-for-devices-with-more-then.patch
1 From b7ad421c184b827806c7f65be3a980cfc855b589 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Sat, 22 Feb 2014 16:53:31 +0100
4 Subject: [PATCH 110/182] ahci-platform: Add support for devices with more
5 then 1 clock
6
7 The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
8 imx AHCI controller needs 3 clocks to be enabled.
9
10 tj: Minor comment formatting updates.
11
12 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
13 Signed-off-by: Tejun Heo <tj@kernel.org>
14 ---
15 .../devicetree/bindings/ata/ahci-platform.txt | 1 +
16 drivers/ata/ahci.h | 3 +-
17 drivers/ata/ahci_platform.c | 113 +++++++++++++++-----
18 include/linux/ahci_platform.h | 4 +
19 4 files changed, 93 insertions(+), 28 deletions(-)
20
21 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
22 +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
23 @@ -10,6 +10,7 @@ Required properties:
24
25 Optional properties:
26 - dma-coherent : Present if dma operations are coherent
27 +- clocks : a list of phandle + clock specifier pairs
28
29 Example:
30 sata@ffe08000 {
31 --- a/drivers/ata/ahci.h
32 +++ b/drivers/ata/ahci.h
33 @@ -51,6 +51,7 @@
34
35 enum {
36 AHCI_MAX_PORTS = 32,
37 + AHCI_MAX_CLKS = 3,
38 AHCI_MAX_SG = 168, /* hardware max is 64K */
39 AHCI_DMA_BOUNDARY = 0xffffffff,
40 AHCI_MAX_CMDS = 32,
41 @@ -322,7 +323,7 @@ struct ahci_host_priv {
42 u32 em_loc; /* enclosure management location */
43 u32 em_buf_sz; /* EM buffer size in byte */
44 u32 em_msg_type; /* EM message type */
45 - struct clk *clk; /* Only for platforms supporting clk */
46 + struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
47 void *plat_data; /* Other platform data */
48 /*
49 * Optional ahci_start_engine override, if not set this gets set to the
50 --- a/drivers/ata/ahci_platform.c
51 +++ b/drivers/ata/ahci_platform.c
52 @@ -87,6 +87,60 @@ static struct scsi_host_template ahci_pl
53 AHCI_SHT("ahci_platform"),
54 };
55
56 +/**
57 + * ahci_platform_enable_clks - Enable platform clocks
58 + * @hpriv: host private area to store config values
59 + *
60 + * This function enables all the clks found in hpriv->clks, starting at
61 + * index 0. If any clk fails to enable it disables all the clks already
62 + * enabled in reverse order, and then returns an error.
63 + *
64 + * RETURNS:
65 + * 0 on success otherwise a negative error code
66 + */
67 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
68 +{
69 + int c, rc;
70 +
71 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
72 + rc = clk_prepare_enable(hpriv->clks[c]);
73 + if (rc)
74 + goto disable_unprepare_clk;
75 + }
76 + return 0;
77 +
78 +disable_unprepare_clk:
79 + while (--c >= 0)
80 + clk_disable_unprepare(hpriv->clks[c]);
81 + return rc;
82 +}
83 +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
84 +
85 +/**
86 + * ahci_platform_disable_clks - Disable platform clocks
87 + * @hpriv: host private area to store config values
88 + *
89 + * This function disables all the clks found in hpriv->clks, in reverse
90 + * order of ahci_platform_enable_clks (starting at the end of the array).
91 + */
92 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
93 +{
94 + int c;
95 +
96 + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
97 + if (hpriv->clks[c])
98 + clk_disable_unprepare(hpriv->clks[c]);
99 +}
100 +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
101 +
102 +static void ahci_put_clks(struct ahci_host_priv *hpriv)
103 +{
104 + int c;
105 +
106 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
107 + clk_put(hpriv->clks[c]);
108 +}
109 +
110 static int ahci_probe(struct platform_device *pdev)
111 {
112 struct device *dev = &pdev->dev;
113 @@ -97,6 +151,7 @@ static int ahci_probe(struct platform_de
114 struct ahci_host_priv *hpriv;
115 struct ata_host *host;
116 struct resource *mem;
117 + struct clk *clk;
118 int irq;
119 int n_ports;
120 int i;
121 @@ -131,17 +186,31 @@ static int ahci_probe(struct platform_de
122 return -ENOMEM;
123 }
124
125 - hpriv->clk = clk_get(dev, NULL);
126 - if (IS_ERR(hpriv->clk)) {
127 - dev_err(dev, "can't get clock\n");
128 - } else {
129 - rc = clk_prepare_enable(hpriv->clk);
130 - if (rc) {
131 - dev_err(dev, "clock prepare enable failed");
132 - goto free_clk;
133 + for (i = 0; i < AHCI_MAX_CLKS; i++) {
134 + /*
135 + * For now we must use clk_get(dev, NULL) for the first clock,
136 + * because some platforms (da850, spear13xx) are not yet
137 + * converted to use devicetree for clocks. For new platforms
138 + * this is equivalent to of_clk_get(dev->of_node, 0).
139 + */
140 + if (i == 0)
141 + clk = clk_get(dev, NULL);
142 + else
143 + clk = of_clk_get(dev->of_node, i);
144 +
145 + if (IS_ERR(clk)) {
146 + rc = PTR_ERR(clk);
147 + if (rc == -EPROBE_DEFER)
148 + goto free_clk;
149 + break;
150 }
151 + hpriv->clks[i] = clk;
152 }
153
154 + rc = ahci_enable_clks(dev, hpriv);
155 + if (rc)
156 + goto free_clk;
157 +
158 /*
159 * Some platforms might need to prepare for mmio region access,
160 * which could be done in the following init call. So, the mmio
161 @@ -222,11 +291,9 @@ pdata_exit:
162 if (pdata && pdata->exit)
163 pdata->exit(dev);
164 disable_unprepare_clk:
165 - if (!IS_ERR(hpriv->clk))
166 - clk_disable_unprepare(hpriv->clk);
167 + ahci_disable_clks(hpriv);
168 free_clk:
169 - if (!IS_ERR(hpriv->clk))
170 - clk_put(hpriv->clk);
171 + ahci_put_clks(hpriv);
172 return rc;
173 }
174
175 @@ -239,10 +306,8 @@ static void ahci_host_stop(struct ata_ho
176 if (pdata && pdata->exit)
177 pdata->exit(dev);
178
179 - if (!IS_ERR(hpriv->clk)) {
180 - clk_disable_unprepare(hpriv->clk);
181 - clk_put(hpriv->clk);
182 - }
183 + ahci_disable_clks(hpriv);
184 + ahci_put_clks(hpriv);
185 }
186
187 #ifdef CONFIG_PM_SLEEP
188 @@ -277,8 +342,7 @@ static int ahci_suspend(struct device *d
189 if (pdata && pdata->suspend)
190 return pdata->suspend(dev);
191
192 - if (!IS_ERR(hpriv->clk))
193 - clk_disable_unprepare(hpriv->clk);
194 + ahci_disable_clks(hpriv);
195
196 return 0;
197 }
198 @@ -290,13 +354,9 @@ static int ahci_resume(struct device *de
199 struct ahci_host_priv *hpriv = host->private_data;
200 int rc;
201
202 - if (!IS_ERR(hpriv->clk)) {
203 - rc = clk_prepare_enable(hpriv->clk);
204 - if (rc) {
205 - dev_err(dev, "clock prepare enable failed");
206 - return rc;
207 - }
208 - }
209 + rc = ahci_enable_clks(dev, hpriv);
210 + if (rc)
211 + return rc;
212
213 if (pdata && pdata->resume) {
214 rc = pdata->resume(dev);
215 @@ -317,8 +377,7 @@ static int ahci_resume(struct device *de
216 return 0;
217
218 disable_unprepare_clk:
219 - if (!IS_ERR(hpriv->clk))
220 - clk_disable_unprepare(hpriv->clk);
221 + ahci_disable_clks(hpriv);
222
223 return rc;
224 }
225 --- a/include/linux/ahci_platform.h
226 +++ b/include/linux/ahci_platform.h
227 @@ -19,6 +19,7 @@
228
229 struct device;
230 struct ata_port_info;
231 +struct ahci_host_priv;
232
233 struct ahci_platform_data {
234 int (*init)(struct device *dev, void __iomem *addr);
235 @@ -30,4 +31,7 @@ struct ahci_platform_data {
236 unsigned int mask_port_map;
237 };
238
239 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
240 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
241 +
242 #endif /* _AHCI_PLATFORM_H */