sunxi: initial 3.14 patchset
[openwrt/staging/stintel.git] / target / linux / sunxi / patches-3.14 / 190-ahci-libahci-changes.patch
1 From 3b5db9d024f173c30ef4060c31bb8e9fbd194cc1 Mon Sep 17 00:00:00 2001
2 From: Hans de Goede <hdegoede@redhat.com>
3 Date: Mon, 2 Dec 2013 16:13:32 +0100
4 Subject: [PATCH] libahci: Allow drivers to override start_engine
5
6 Allwinner A10 and A20 ARM SoCs have an AHCI sata controller which needs a
7 special register to be poked before starting the DMA engine.
8
9 This register gets reset on an ahci_stop_engine call, so there is no other
10 place then ahci_start_engine where this poking can be done.
11
12 This commit allows drivers to override ahci_start_engine behavior for use by
13 the Allwinner AHCI driver (and potentially other drivers in the future).
14
15 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
16 ---
17 drivers/ata/ahci.c | 6 ++++--
18 drivers/ata/ahci.h | 6 ++++++
19 drivers/ata/libahci.c | 26 +++++++++++++++++++-------
20 drivers/ata/sata_highbank.c | 3 ++-
21 4 files changed, 31 insertions(+), 10 deletions(-)
22
23 diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
24 index c81d809..8bfc477 100644
25 --- a/drivers/ata/ahci.c
26 +++ b/drivers/ata/ahci.c
27 @@ -578,6 +578,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
28 unsigned long deadline)
29 {
30 struct ata_port *ap = link->ap;
31 + struct ahci_host_priv *hpriv = ap->host->private_data;
32 bool online;
33 int rc;
34
35 @@ -588,7 +589,7 @@ static int ahci_vt8251_hardreset(struct ata_link *link, unsigned int *class,
36 rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
37 deadline, &online, NULL);
38
39 - ahci_start_engine(ap);
40 + hpriv->start_engine(ap);
41
42 DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
43
44 @@ -603,6 +604,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
45 {
46 struct ata_port *ap = link->ap;
47 struct ahci_port_priv *pp = ap->private_data;
48 + struct ahci_host_priv *hpriv = ap->host->private_data;
49 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
50 struct ata_taskfile tf;
51 bool online;
52 @@ -618,7 +620,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
53 rc = sata_link_hardreset(link, sata_ehc_deb_timing(&link->eh_context),
54 deadline, &online, NULL);
55
56 - ahci_start_engine(ap);
57 + hpriv->start_engine(ap);
58
59 /* The pseudo configuration device on SIMG4726 attached to
60 * ASUS P5W-DH Deluxe doesn't send signature FIS after
61 diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
62 index 2289efd..64d1a99d 100644
63 --- a/drivers/ata/ahci.h
64 +++ b/drivers/ata/ahci.h
65 @@ -323,6 +323,12 @@ struct ahci_host_priv {
66 u32 em_msg_type; /* EM message type */
67 struct clk *clk; /* Only for platforms supporting clk */
68 void *plat_data; /* Other platform data */
69 + /*
70 + * Optional ahci_start_engine override, if not set this gets set to the
71 + * default ahci_start_engine during ahci_save_initial_config, this can
72 + * be overridden anytime before the host is activated.
73 + */
74 + void (*start_engine)(struct ata_port *ap);
75 };
76
77 extern int ahci_ignore_sss;
78 diff --git a/drivers/ata/libahci.c b/drivers/ata/libahci.c
79 index 36605ab..f839bb3 100644
80 --- a/drivers/ata/libahci.c
81 +++ b/drivers/ata/libahci.c
82 @@ -394,6 +394,9 @@ static ssize_t ahci_show_em_supported(struct device *dev,
83 *
84 * If inconsistent, config values are fixed up by this function.
85 *
86 + * If it is not set already this function sets hpriv->start_engine to
87 + * ahci_start_engine.
88 + *
89 * LOCKING:
90 * None.
91 */
92 @@ -500,6 +503,9 @@ void ahci_save_initial_config(struct device *dev,
93 hpriv->cap = cap;
94 hpriv->cap2 = cap2;
95 hpriv->port_map = port_map;
96 +
97 + if (!hpriv->start_engine)
98 + hpriv->start_engine = ahci_start_engine;
99 }
100 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
101
102 @@ -766,7 +772,7 @@ static void ahci_start_port(struct ata_port *ap)
103
104 /* enable DMA */
105 if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
106 - ahci_start_engine(ap);
107 + hpriv->start_engine(ap);
108
109 /* turn on LEDs */
110 if (ap->flags & ATA_FLAG_EM) {
111 @@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
112
113 /* restart engine */
114 out_restart:
115 - ahci_start_engine(ap);
116 + hpriv->start_engine(ap);
117 return rc;
118 }
119 EXPORT_SYMBOL_GPL(ahci_kick_engine);
120 @@ -1426,6 +1432,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
121 const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
122 struct ata_port *ap = link->ap;
123 struct ahci_port_priv *pp = ap->private_data;
124 + struct ahci_host_priv *hpriv = ap->host->private_data;
125 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
126 struct ata_taskfile tf;
127 bool online;
128 @@ -1443,7 +1450,7 @@ static int ahci_hardreset(struct ata_link *link, unsigned int *class,
129 rc = sata_link_hardreset(link, timing, deadline, &online,
130 ahci_check_ready);
131
132 - ahci_start_engine(ap);
133 + hpriv->start_engine(ap);
134
135 if (online)
136 *class = ahci_dev_classify(ap);
137 @@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
138
139 void ahci_error_handler(struct ata_port *ap)
140 {
141 + struct ahci_host_priv *hpriv = ap->host->private_data;
142 +
143 if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
144 /* restart engine */
145 ahci_stop_engine(ap);
146 - ahci_start_engine(ap);
147 + hpriv->start_engine(ap);
148 }
149
150 sata_pmp_error_handler(ap);
151 @@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
152
153 static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
154 {
155 + struct ahci_host_priv *hpriv = ap->host->private_data;
156 void __iomem *port_mmio = ahci_port_base(ap);
157 struct ata_device *dev = ap->link.device;
158 u32 devslp, dm, dito, mdat, deto;
159 @@ -2094,7 +2104,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
160 PORT_DEVSLP_ADSE);
161 writel(devslp, port_mmio + PORT_DEVSLP);
162
163 - ahci_start_engine(ap);
164 + hpriv->start_engine(ap);
165
166 /* enable device sleep feature for the drive */
167 err_mask = ata_dev_set_feature(dev,
168 @@ -2106,6 +2116,7 @@ static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
169
170 static void ahci_enable_fbs(struct ata_port *ap)
171 {
172 + struct ahci_host_priv *hpriv = ap->host->private_data;
173 struct ahci_port_priv *pp = ap->private_data;
174 void __iomem *port_mmio = ahci_port_base(ap);
175 u32 fbs;
176 @@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
177 } else
178 dev_err(ap->host->dev, "Failed to enable FBS\n");
179
180 - ahci_start_engine(ap);
181 + hpriv->start_engine(ap);
182 }
183
184 static void ahci_disable_fbs(struct ata_port *ap)
185 {
186 + struct ahci_host_priv *hpriv = ap->host->private_data;
187 struct ahci_port_priv *pp = ap->private_data;
188 void __iomem *port_mmio = ahci_port_base(ap);
189 u32 fbs;
190 @@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
191 pp->fbs_enabled = false;
192 }
193
194 - ahci_start_engine(ap);
195 + hpriv->start_engine(ap);
196 }
197
198 static void ahci_pmp_attach(struct ata_port *ap)
199 diff --git a/drivers/ata/sata_highbank.c b/drivers/ata/sata_highbank.c
200 index 870b11e..b3b18d1 100644
201 --- a/drivers/ata/sata_highbank.c
202 +++ b/drivers/ata/sata_highbank.c
203 @@ -403,6 +403,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
204 static const unsigned long timing[] = { 5, 100, 500};
205 struct ata_port *ap = link->ap;
206 struct ahci_port_priv *pp = ap->private_data;
207 + struct ahci_host_priv *hpriv = ap->host->private_data;
208 u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
209 struct ata_taskfile tf;
210 bool online;
211 @@ -431,7 +432,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
212 break;
213 } while (!online && retry--);
214
215 - ahci_start_engine(ap);
216 + hpriv->start_engine(ap);
217
218 if (online)
219 *class = ahci_dev_classify(ap);
220 --
221 2.0.3
222
223 From fcc3a79f048480e6723b0cfd294f9eecbf73dfd9 Mon Sep 17 00:00:00 2001
224 From: Hans de Goede <hdegoede@redhat.com>
225 Date: Thu, 16 Jan 2014 14:32:35 +0100
226 Subject: [PATCH] ahci-platform: Add support for devices with more then 1 clock
227
228 The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
229 imx AHCI controller needs 3 clocks to be enabled.
230
231 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
232 ---
233 .../devicetree/bindings/ata/ahci-platform.txt | 1 +
234 drivers/ata/ahci.h | 3 +-
235 drivers/ata/ahci_platform.c | 119 ++++++++++++++++-----
236 include/linux/ahci_platform.h | 4 +
237 4 files changed, 99 insertions(+), 28 deletions(-)
238
239 diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
240 index 89de156..3ced07d 100644
241 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
242 +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
243 @@ -10,6 +10,7 @@ Required properties:
244
245 Optional properties:
246 - dma-coherent : Present if dma operations are coherent
247 +- clocks : a list of phandle + clock specifier pairs
248
249 Example:
250 sata@ffe08000 {
251 diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
252 index 64d1a99d..c12862b 100644
253 --- a/drivers/ata/ahci.h
254 +++ b/drivers/ata/ahci.h
255 @@ -51,6 +51,7 @@
256
257 enum {
258 AHCI_MAX_PORTS = 32,
259 + AHCI_MAX_CLKS = 3,
260 AHCI_MAX_SG = 168, /* hardware max is 64K */
261 AHCI_DMA_BOUNDARY = 0xffffffff,
262 AHCI_MAX_CMDS = 32,
263 @@ -321,7 +322,7 @@ struct ahci_host_priv {
264 u32 em_loc; /* enclosure management location */
265 u32 em_buf_sz; /* EM buffer size in byte */
266 u32 em_msg_type; /* EM message type */
267 - struct clk *clk; /* Only for platforms supporting clk */
268 + struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
269 void *plat_data; /* Other platform data */
270 /*
271 * Optional ahci_start_engine override, if not set this gets set to the
272 diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
273 index 4b231ba..609975d 100644
274 --- a/drivers/ata/ahci_platform.c
275 +++ b/drivers/ata/ahci_platform.c
276 @@ -87,6 +87,66 @@ static struct scsi_host_template ahci_platform_sht = {
277 AHCI_SHT("ahci_platform"),
278 };
279
280 +/**
281 + * ahci_platform_enable_clks - Enable platform clocks
282 + * @hpriv: host private area to store config values
283 + *
284 + * This function enables all the clks found in hpriv->clks, starting
285 + * at index 0. If any clk fails to enable it disables all the clks
286 + * already enabled in reverse order, and then returns an error.
287 + *
288 + * LOCKING:
289 + * None.
290 + *
291 + * RETURNS:
292 + * 0 on success otherwise a negative error code
293 + */
294 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
295 +{
296 + int c, rc;
297 +
298 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
299 + rc = clk_prepare_enable(hpriv->clks[c]);
300 + if (rc)
301 + goto disable_unprepare_clk;
302 + }
303 + return 0;
304 +
305 +disable_unprepare_clk:
306 + while (--c >= 0)
307 + clk_disable_unprepare(hpriv->clks[c]);
308 + return rc;
309 +}
310 +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
311 +
312 +/**
313 + * ahci_platform_disable_clks - Disable platform clocks
314 + * @hpriv: host private area to store config values
315 + *
316 + * This function disables all the clks found in hpriv->clks, in reverse
317 + * order of ahci_platform_enable_clks (starting at the end of the array).
318 + *
319 + * LOCKING:
320 + * None.
321 + */
322 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
323 +{
324 + int c;
325 +
326 + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
327 + if (hpriv->clks[c])
328 + clk_disable_unprepare(hpriv->clks[c]);
329 +}
330 +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
331 +
332 +static void ahci_put_clks(struct ahci_host_priv *hpriv)
333 +{
334 + int c;
335 +
336 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
337 + clk_put(hpriv->clks[c]);
338 +}
339 +
340 static int ahci_probe(struct platform_device *pdev)
341 {
342 struct device *dev = &pdev->dev;
343 @@ -97,6 +157,7 @@ static int ahci_probe(struct platform_device *pdev)
344 struct ahci_host_priv *hpriv;
345 struct ata_host *host;
346 struct resource *mem;
347 + struct clk *clk;
348 int irq;
349 int n_ports;
350 int i;
351 @@ -131,17 +192,31 @@ static int ahci_probe(struct platform_device *pdev)
352 return -ENOMEM;
353 }
354
355 - hpriv->clk = clk_get(dev, NULL);
356 - if (IS_ERR(hpriv->clk)) {
357 - dev_err(dev, "can't get clock\n");
358 - } else {
359 - rc = clk_prepare_enable(hpriv->clk);
360 - if (rc) {
361 - dev_err(dev, "clock prepare enable failed");
362 - goto free_clk;
363 + for (i = 0; i < AHCI_MAX_CLKS; i++) {
364 + /*
365 + * For now we must use clk_get(dev, NULL) for the first clock,
366 + * because some platforms (da850, spear13xx) are not yet
367 + * converted to use devicetree for clocks. For new platforms
368 + * this is equivalent to of_clk_get(dev->of_node, 0).
369 + */
370 + if (i == 0)
371 + clk = clk_get(dev, NULL);
372 + else
373 + clk = of_clk_get(dev->of_node, i);
374 +
375 + if (IS_ERR(clk)) {
376 + rc = PTR_ERR(clk);
377 + if (rc == -EPROBE_DEFER)
378 + goto free_clk;
379 + break;
380 }
381 + hpriv->clks[i] = clk;
382 }
383
384 + rc = ahci_enable_clks(dev, hpriv);
385 + if (rc)
386 + goto free_clk;
387 +
388 /*
389 * Some platforms might need to prepare for mmio region access,
390 * which could be done in the following init call. So, the mmio
391 @@ -222,11 +297,9 @@ static int ahci_probe(struct platform_device *pdev)
392 if (pdata && pdata->exit)
393 pdata->exit(dev);
394 disable_unprepare_clk:
395 - if (!IS_ERR(hpriv->clk))
396 - clk_disable_unprepare(hpriv->clk);
397 + ahci_disable_clks(hpriv);
398 free_clk:
399 - if (!IS_ERR(hpriv->clk))
400 - clk_put(hpriv->clk);
401 + ahci_put_clks(hpriv);
402 return rc;
403 }
404
405 @@ -239,10 +312,8 @@ static void ahci_host_stop(struct ata_host *host)
406 if (pdata && pdata->exit)
407 pdata->exit(dev);
408
409 - if (!IS_ERR(hpriv->clk)) {
410 - clk_disable_unprepare(hpriv->clk);
411 - clk_put(hpriv->clk);
412 - }
413 + ahci_disable_clks(hpriv);
414 + ahci_put_clks(hpriv);
415 }
416
417 #ifdef CONFIG_PM_SLEEP
418 @@ -277,8 +348,7 @@ static int ahci_suspend(struct device *dev)
419 if (pdata && pdata->suspend)
420 return pdata->suspend(dev);
421
422 - if (!IS_ERR(hpriv->clk))
423 - clk_disable_unprepare(hpriv->clk);
424 + ahci_disable_clks(hpriv);
425
426 return 0;
427 }
428 @@ -290,13 +360,9 @@ static int ahci_resume(struct device *dev)
429 struct ahci_host_priv *hpriv = host->private_data;
430 int rc;
431
432 - if (!IS_ERR(hpriv->clk)) {
433 - rc = clk_prepare_enable(hpriv->clk);
434 - if (rc) {
435 - dev_err(dev, "clock prepare enable failed");
436 - return rc;
437 - }
438 - }
439 + rc = ahci_enable_clks(dev, hpriv);
440 + if (rc)
441 + return rc;
442
443 if (pdata && pdata->resume) {
444 rc = pdata->resume(dev);
445 @@ -317,8 +383,7 @@ static int ahci_resume(struct device *dev)
446 return 0;
447
448 disable_unprepare_clk:
449 - if (!IS_ERR(hpriv->clk))
450 - clk_disable_unprepare(hpriv->clk);
451 + ahci_disable_clks(hpriv);
452
453 return rc;
454 }
455 diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
456 index 73a2500..769d065 100644
457 --- a/include/linux/ahci_platform.h
458 +++ b/include/linux/ahci_platform.h
459 @@ -19,6 +19,7 @@
460
461 struct device;
462 struct ata_port_info;
463 +struct ahci_host_priv;
464
465 struct ahci_platform_data {
466 int (*init)(struct device *dev, void __iomem *addr);
467 @@ -30,4 +31,7 @@ struct ahci_platform_data {
468 unsigned int mask_port_map;
469 };
470
471 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
472 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
473 +
474 #endif /* _AHCI_PLATFORM_H */
475 --
476 2.0.3
477
478 From 3dc53b267843b6dfeb2eb67e52e17915dc2347ab Mon Sep 17 00:00:00 2001
479 From: Hans de Goede <hdegoede@redhat.com>
480 Date: Fri, 17 Jan 2014 13:23:21 +0100
481 Subject: [PATCH] ahci-platform: Add support for an optional regulator for
482 sata-target power
483
484 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
485 ---
486 .../devicetree/bindings/ata/ahci-platform.txt | 1 +
487 drivers/ata/ahci.h | 2 ++
488 drivers/ata/ahci_platform.c | 36 ++++++++++++++++++++--
489 3 files changed, 37 insertions(+), 2 deletions(-)
490
491 diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
492 index 3ced07d..1ac807f 100644
493 --- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
494 +++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
495 @@ -11,6 +11,7 @@ Required properties:
496 Optional properties:
497 - dma-coherent : Present if dma operations are coherent
498 - clocks : a list of phandle + clock specifier pairs
499 +- target-supply : regulator for SATA target power
500
501 Example:
502 sata@ffe08000 {
503 diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
504 index c12862b..bf8100c 100644
505 --- a/drivers/ata/ahci.h
506 +++ b/drivers/ata/ahci.h
507 @@ -37,6 +37,7 @@
508
509 #include <linux/clk.h>
510 #include <linux/libata.h>
511 +#include <linux/regulator/consumer.h>
512
513 /* Enclosure Management Control */
514 #define EM_CTRL_MSG_TYPE 0x000f0000
515 @@ -323,6 +324,7 @@ struct ahci_host_priv {
516 u32 em_buf_sz; /* EM buffer size in byte */
517 u32 em_msg_type; /* EM message type */
518 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
519 + struct regulator *target_pwr; /* Optional */
520 void *plat_data; /* Other platform data */
521 /*
522 * Optional ahci_start_engine override, if not set this gets set to the
523 diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
524 index 609975d..907c076 100644
525 --- a/drivers/ata/ahci_platform.c
526 +++ b/drivers/ata/ahci_platform.c
527 @@ -192,6 +192,14 @@ static int ahci_probe(struct platform_device *pdev)
528 return -ENOMEM;
529 }
530
531 + hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
532 + if (IS_ERR(hpriv->target_pwr)) {
533 + rc = PTR_ERR(hpriv->target_pwr);
534 + if (rc == -EPROBE_DEFER)
535 + return -EPROBE_DEFER;
536 + hpriv->target_pwr = NULL;
537 + }
538 +
539 for (i = 0; i < AHCI_MAX_CLKS; i++) {
540 /*
541 * For now we must use clk_get(dev, NULL) for the first clock,
542 @@ -213,9 +221,15 @@ static int ahci_probe(struct platform_device *pdev)
543 hpriv->clks[i] = clk;
544 }
545
546 + if (hpriv->target_pwr) {
547 + rc = regulator_enable(hpriv->target_pwr);
548 + if (rc)
549 + goto free_clk;
550 + }
551 +
552 rc = ahci_enable_clks(dev, hpriv);
553 if (rc)
554 - goto free_clk;
555 + goto disable_regulator;
556
557 /*
558 * Some platforms might need to prepare for mmio region access,
559 @@ -298,6 +312,9 @@ static int ahci_probe(struct platform_device *pdev)
560 pdata->exit(dev);
561 disable_unprepare_clk:
562 ahci_disable_clks(hpriv);
563 +disable_regulator:
564 + if (hpriv->target_pwr)
565 + regulator_disable(hpriv->target_pwr);
566 free_clk:
567 ahci_put_clks(hpriv);
568 return rc;
569 @@ -314,6 +331,9 @@ static void ahci_host_stop(struct ata_host *host)
570
571 ahci_disable_clks(hpriv);
572 ahci_put_clks(hpriv);
573 +
574 + if (hpriv->target_pwr)
575 + regulator_disable(hpriv->target_pwr);
576 }
577
578 #ifdef CONFIG_PM_SLEEP
579 @@ -350,6 +370,9 @@ static int ahci_suspend(struct device *dev)
580
581 ahci_disable_clks(hpriv);
582
583 + if (hpriv->target_pwr)
584 + regulator_disable(hpriv->target_pwr);
585 +
586 return 0;
587 }
588
589 @@ -360,9 +383,15 @@ static int ahci_resume(struct device *dev)
590 struct ahci_host_priv *hpriv = host->private_data;
591 int rc;
592
593 + if (hpriv->target_pwr) {
594 + rc = regulator_enable(hpriv->target_pwr);
595 + if (rc)
596 + return rc;
597 + }
598 +
599 rc = ahci_enable_clks(dev, hpriv);
600 if (rc)
601 - return rc;
602 + goto disable_regulator;
603
604 if (pdata && pdata->resume) {
605 rc = pdata->resume(dev);
606 @@ -384,6 +413,9 @@ static int ahci_resume(struct device *dev)
607
608 disable_unprepare_clk:
609 ahci_disable_clks(hpriv);
610 +disable_regulator:
611 + if (hpriv->target_pwr)
612 + regulator_disable(hpriv->target_pwr);
613
614 return rc;
615 }
616 --
617 2.0.3
618
619 From 74f54552b061865ff46d43aa68d0c6e8852dc592 Mon Sep 17 00:00:00 2001
620 From: Hans de Goede <hdegoede@redhat.com>
621 Date: Mon, 20 Jan 2014 14:54:40 +0100
622 Subject: [PATCH] ahci-platform: Add enable_ / disable_resources helper
623 functions
624
625 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
626 ---
627 drivers/ata/ahci_platform.c | 112 ++++++++++++++++++++++++++++--------------
628 include/linux/ahci_platform.h | 2 +
629 2 files changed, 77 insertions(+), 37 deletions(-)
630
631 diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
632 index 907c076..6ebbc17 100644
633 --- a/drivers/ata/ahci_platform.c
634 +++ b/drivers/ata/ahci_platform.c
635 @@ -139,6 +139,68 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
636 }
637 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
638
639 +/**
640 + * ahci_platform_enable_resources - Enable platform resources
641 + * @hpriv: host private area to store config values
642 + *
643 + * This function enables all ahci_platform managed resources in
644 + * the following order:
645 + * 1) Regulator
646 + * 2) Clocks (through ahci_platform_enable_clks)
647 + *
648 + * If resource enabling fails at any point the previous enabled
649 + * resources are disabled in reverse order.
650 + *
651 + * LOCKING:
652 + * None.
653 + *
654 + * RETURNS:
655 + * 0 on success otherwise a negative error code
656 + */
657 +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
658 +{
659 + int rc;
660 +
661 + if (hpriv->target_pwr) {
662 + rc = regulator_enable(hpriv->target_pwr);
663 + if (rc)
664 + return rc;
665 + }
666 +
667 + rc = ahci_platform_enable_clks(hpriv);
668 + if (rc)
669 + goto disable_regulator;
670 +
671 + return 0;
672 +
673 +disable_regulator:
674 + if (hpriv->target_pwr)
675 + regulator_disable(hpriv->target_pwr);
676 + return rc;
677 +}
678 +EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
679 +
680 +/**
681 + * ahci_platform_disable_resources - Disable platform resources
682 + * @hpriv: host private area to store config values
683 + *
684 + * This function disables all ahci_platform managed resources in
685 + * the following order:
686 + * 1) Clocks (through ahci_platform_disable_clks)
687 + * 2) Regulator
688 + *
689 + * LOCKING:
690 + * None.
691 + */
692 +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
693 +{
694 + ahci_platform_disable_clks(hpriv);
695 +
696 + if (hpriv->target_pwr)
697 + regulator_disable(hpriv->target_pwr);
698 +}
699 +EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
700 +
701 static void ahci_put_clks(struct ahci_host_priv *hpriv)
702 {
703 int c;
704 @@ -221,15 +283,9 @@ static int ahci_probe(struct platform_device *pdev)
705 hpriv->clks[i] = clk;
706 }
707
708 - if (hpriv->target_pwr) {
709 - rc = regulator_enable(hpriv->target_pwr);
710 - if (rc)
711 - goto free_clk;
712 - }
713 -
714 - rc = ahci_enable_clks(dev, hpriv);
715 + rc = ahci_platform_enable_resources(hpriv);
716 if (rc)
717 - goto disable_regulator;
718 + goto free_clk;
719
720 /*
721 * Some platforms might need to prepare for mmio region access,
722 @@ -240,7 +296,7 @@ static int ahci_probe(struct platform_device *pdev)
723 if (pdata && pdata->init) {
724 rc = pdata->init(dev, hpriv->mmio);
725 if (rc)
726 - goto disable_unprepare_clk;
727 + goto disable_resources;
728 }
729
730 ahci_save_initial_config(dev, hpriv,
731 @@ -310,11 +366,8 @@ static int ahci_probe(struct platform_device *pdev)
732 pdata_exit:
733 if (pdata && pdata->exit)
734 pdata->exit(dev);
735 -disable_unprepare_clk:
736 - ahci_disable_clks(hpriv);
737 -disable_regulator:
738 - if (hpriv->target_pwr)
739 - regulator_disable(hpriv->target_pwr);
740 +disable_resources:
741 + ahci_platform_disable_resources(hpriv);
742 free_clk:
743 ahci_put_clks(hpriv);
744 return rc;
745 @@ -329,11 +382,8 @@ static void ahci_host_stop(struct ata_host *host)
746 if (pdata && pdata->exit)
747 pdata->exit(dev);
748
749 - ahci_disable_clks(hpriv);
750 + ahci_platform_disable_resources(hpriv);
751 ahci_put_clks(hpriv);
752 -
753 - if (hpriv->target_pwr)
754 - regulator_disable(hpriv->target_pwr);
755 }
756
757 #ifdef CONFIG_PM_SLEEP
758 @@ -368,10 +418,7 @@ static int ahci_suspend(struct device *dev)
759 if (pdata && pdata->suspend)
760 return pdata->suspend(dev);
761
762 - ahci_disable_clks(hpriv);
763 -
764 - if (hpriv->target_pwr)
765 - regulator_disable(hpriv->target_pwr);
766 + ahci_platform_disable_resources(hpriv);
767
768 return 0;
769 }
770 @@ -383,26 +430,20 @@ static int ahci_resume(struct device *dev)
771 struct ahci_host_priv *hpriv = host->private_data;
772 int rc;
773
774 - if (hpriv->target_pwr) {
775 - rc = regulator_enable(hpriv->target_pwr);
776 - if (rc)
777 - return rc;
778 - }
779 -
780 - rc = ahci_enable_clks(dev, hpriv);
781 + rc = ahci_platform_enable_resources(hpriv);
782 if (rc)
783 - goto disable_regulator;
784 + return rc;
785
786 if (pdata && pdata->resume) {
787 rc = pdata->resume(dev);
788 if (rc)
789 - goto disable_unprepare_clk;
790 + goto disable_resources;
791 }
792
793 if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
794 rc = ahci_reset_controller(host);
795 if (rc)
796 - goto disable_unprepare_clk;
797 + goto disable_resources;
798
799 ahci_init_controller(host);
800 }
801 @@ -411,11 +452,8 @@ static int ahci_resume(struct device *dev)
802
803 return 0;
804
805 -disable_unprepare_clk:
806 - ahci_disable_clks(hpriv);
807 -disable_regulator:
808 - if (hpriv->target_pwr)
809 - regulator_disable(hpriv->target_pwr);
810 +disable_resources:
811 + ahci_platform_disable_resources(hpriv);
812
813 return rc;
814 }
815 diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
816 index 769d065..b674b01 100644
817 --- a/include/linux/ahci_platform.h
818 +++ b/include/linux/ahci_platform.h
819 @@ -33,5 +33,7 @@ struct ahci_platform_data {
820
821 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
822 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
823 +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
824 +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
825
826 #endif /* _AHCI_PLATFORM_H */
827 --
828 2.0.3
829
830 From 88972833cba7a6dad8e9a1c9b43ab02fc274e4fd Mon Sep 17 00:00:00 2001
831 From: Hans de Goede <hdegoede@redhat.com>
832 Date: Mon, 20 Jan 2014 14:58:04 +0100
833 Subject: [PATCH] ahci-platform: "Library-ise" ahci_probe functionality
834
835 ahci_probe consists of 3 steps:
836 1) Get resources (get mmio, clks, regulator)
837 2) Enable resources, handled by ahci_platform_enable_resouces
838 3) The more or less standard ahci-host controller init sequence
839
840 This commit refactors step 1 and 3 into separate functions, so the platform
841 drivers for AHCI implementations which need a specific order in step 2,
842 and / or need to do some custom register poking at some time, can re-use
843 ahci-platform.c code without needing to copy and paste it.
844
845 Note that ahci_platform_init_host's prototype takes the 3 non function
846 members of ahci_platform_data as arguments, the idea is that drivers using
847 the new exported utility functions will not use ahci_platform_data at all,
848 and hopefully in the future ahci_platform_data can go away entirely.
849
850 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
851 ---
852 drivers/ata/ahci_platform.c | 195 ++++++++++++++++++++++++++++--------------
853 include/linux/ahci_platform.h | 14 +++
854 2 files changed, 144 insertions(+), 65 deletions(-)
855
856 diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
857 index 6ebbc17..7f3f2ac 100644
858 --- a/drivers/ata/ahci_platform.c
859 +++ b/drivers/ata/ahci_platform.c
860 @@ -201,64 +201,64 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
861 }
862 EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
863
864 -static void ahci_put_clks(struct ahci_host_priv *hpriv)
865 +static void ahci_platform_put_resources(struct device *dev, void *res)
866 {
867 + struct ahci_host_priv *hpriv = res;
868 int c;
869
870 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
871 clk_put(hpriv->clks[c]);
872 }
873
874 -static int ahci_probe(struct platform_device *pdev)
875 +/**
876 + * ahci_platform_get_resources - Get platform resources
877 + * @pdev: platform device to get resources for
878 + *
879 + * This function allocates an ahci_host_priv struct, and gets the
880 + * following resources, storing a reference to them inside the returned
881 + * struct:
882 + *
883 + * 1) mmio registers (IORESOURCE_MEM 0, mandatory)
884 + * 2) regulator for controlling the targets power (optional)
885 + * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
886 + * or for non devicetree enabled platforms a single clock
887 + *
888 + * LOCKING:
889 + * None.
890 + *
891 + * RETURNS:
892 + * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
893 + */
894 +struct ahci_host_priv *ahci_platform_get_resources(
895 + struct platform_device *pdev)
896 {
897 struct device *dev = &pdev->dev;
898 - struct ahci_platform_data *pdata = dev_get_platdata(dev);
899 - const struct platform_device_id *id = platform_get_device_id(pdev);
900 - struct ata_port_info pi = ahci_port_info[id ? id->driver_data : 0];
901 - const struct ata_port_info *ppi[] = { &pi, NULL };
902 struct ahci_host_priv *hpriv;
903 - struct ata_host *host;
904 - struct resource *mem;
905 struct clk *clk;
906 - int irq;
907 - int n_ports;
908 - int i;
909 - int rc;
910 + int i, rc = -ENOMEM;
911
912 - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
913 - if (!mem) {
914 - dev_err(dev, "no mmio space\n");
915 - return -EINVAL;
916 - }
917 + if (!devres_open_group(dev, NULL, GFP_KERNEL))
918 + return ERR_PTR(-ENOMEM);
919
920 - irq = platform_get_irq(pdev, 0);
921 - if (irq <= 0) {
922 - dev_err(dev, "no irq\n");
923 - return -EINVAL;
924 - }
925 + hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
926 + GFP_KERNEL);
927 + if (!hpriv)
928 + goto err_out;
929
930 - if (pdata && pdata->ata_port_info)
931 - pi = *pdata->ata_port_info;
932 + devres_add(dev, hpriv);
933
934 - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
935 - if (!hpriv) {
936 - dev_err(dev, "can't alloc ahci_host_priv\n");
937 - return -ENOMEM;
938 - }
939 -
940 - hpriv->flags |= (unsigned long)pi.private_data;
941 -
942 - hpriv->mmio = devm_ioremap(dev, mem->start, resource_size(mem));
943 + hpriv->mmio = devm_ioremap_resource(dev,
944 + platform_get_resource(pdev, IORESOURCE_MEM, 0));
945 if (!hpriv->mmio) {
946 - dev_err(dev, "can't map %pR\n", mem);
947 - return -ENOMEM;
948 + dev_err(dev, "no mmio space\n");
949 + goto err_out;
950 }
951
952 hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
953 if (IS_ERR(hpriv->target_pwr)) {
954 rc = PTR_ERR(hpriv->target_pwr);
955 if (rc == -EPROBE_DEFER)
956 - return -EPROBE_DEFER;
957 + goto err_out;
958 hpriv->target_pwr = NULL;
959 }
960
961 @@ -277,33 +277,62 @@ static int ahci_probe(struct platform_device *pdev)
962 if (IS_ERR(clk)) {
963 rc = PTR_ERR(clk);
964 if (rc == -EPROBE_DEFER)
965 - goto free_clk;
966 + goto err_out;
967 break;
968 }
969 hpriv->clks[i] = clk;
970 }
971
972 - rc = ahci_platform_enable_resources(hpriv);
973 - if (rc)
974 - goto free_clk;
975 + devres_remove_group(dev, NULL);
976 + return hpriv;
977
978 - /*
979 - * Some platforms might need to prepare for mmio region access,
980 - * which could be done in the following init call. So, the mmio
981 - * region shouldn't be accessed before init (if provided) has
982 - * returned successfully.
983 - */
984 - if (pdata && pdata->init) {
985 - rc = pdata->init(dev, hpriv->mmio);
986 - if (rc)
987 - goto disable_resources;
988 - }
989 +err_out:
990 + devres_release_group(dev, NULL);
991 + return ERR_PTR(rc);
992 +}
993 +EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
994 +
995 +/**
996 + * ahci_platform_init_host - Bring up an ahci-platform host
997 + * @pdev: platform device pointer for the host
998 + * @hpriv: ahci-host private data for the host
999 + * @pi_template: template for the ata_port_info to use
1000 + * @force_port_map: param passed to ahci_save_initial_config
1001 + * @mask_port_map: param passed to ahci_save_initial_config
1002 + *
1003 + * This function does all the usual steps needed to bring up an
1004 + * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
1005 + * must be initialized / enabled before calling this.
1006 + *
1007 + * LOCKING:
1008 + * None.
1009 + *
1010 + * RETURNS:
1011 + * 0 on success otherwise a negative error code
1012 + */
1013 +int ahci_platform_init_host(struct platform_device *pdev,
1014 + struct ahci_host_priv *hpriv,
1015 + const struct ata_port_info *pi_template,
1016 + unsigned int force_port_map,
1017 + unsigned int mask_port_map)
1018 +{
1019 + struct device *dev = &pdev->dev;
1020 + struct ata_port_info pi = *pi_template;
1021 + const struct ata_port_info *ppi[] = { &pi, NULL };
1022 + struct ata_host *host;
1023 + int i, irq, n_ports, rc;
1024
1025 - ahci_save_initial_config(dev, hpriv,
1026 - pdata ? pdata->force_port_map : 0,
1027 - pdata ? pdata->mask_port_map : 0);
1028 + irq = platform_get_irq(pdev, 0);
1029 + if (irq <= 0) {
1030 + dev_err(dev, "no irq\n");
1031 + return -EINVAL;
1032 + }
1033
1034 /* prepare host */
1035 + hpriv->flags |= (unsigned long)pi.private_data;
1036 +
1037 + ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
1038 +
1039 if (hpriv->cap & HOST_CAP_NCQ)
1040 pi.flags |= ATA_FLAG_NCQ;
1041
1042 @@ -320,10 +349,8 @@ static int ahci_probe(struct platform_device *pdev)
1043 n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map));
1044
1045 host = ata_host_alloc_pinfo(dev, ppi, n_ports);
1046 - if (!host) {
1047 - rc = -ENOMEM;
1048 - goto pdata_exit;
1049 - }
1050 + if (!host)
1051 + return -ENOMEM;
1052
1053 host->private_data = hpriv;
1054
1055 @@ -338,7 +365,8 @@ static int ahci_probe(struct platform_device *pdev)
1056 for (i = 0; i < host->n_ports; i++) {
1057 struct ata_port *ap = host->ports[i];
1058
1059 - ata_port_desc(ap, "mmio %pR", mem);
1060 + ata_port_desc(ap, "mmio %pR",
1061 + platform_get_resource(pdev, IORESOURCE_MEM, 0));
1062 ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80);
1063
1064 /* set enclosure management message type */
1065 @@ -352,13 +380,53 @@ static int ahci_probe(struct platform_device *pdev)
1066
1067 rc = ahci_reset_controller(host);
1068 if (rc)
1069 - goto pdata_exit;
1070 + return rc;
1071
1072 ahci_init_controller(host);
1073 ahci_print_info(host, "platform");
1074
1075 - rc = ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
1076 - &ahci_platform_sht);
1077 + return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED,
1078 + &ahci_platform_sht);
1079 +}
1080 +EXPORT_SYMBOL_GPL(ahci_platform_init_host);
1081 +
1082 +static int ahci_probe(struct platform_device *pdev)
1083 +{
1084 + struct device *dev = &pdev->dev;
1085 + struct ahci_platform_data *pdata = dev_get_platdata(dev);
1086 + const struct platform_device_id *id = platform_get_device_id(pdev);
1087 + const struct ata_port_info *pi_template;
1088 + struct ahci_host_priv *hpriv;
1089 + int rc;
1090 +
1091 + hpriv = ahci_platform_get_resources(pdev);
1092 + if (IS_ERR(hpriv))
1093 + return PTR_ERR(hpriv);
1094 +
1095 + rc = ahci_platform_enable_resources(hpriv);
1096 + if (rc)
1097 + return rc;
1098 +
1099 + /*
1100 + * Some platforms might need to prepare for mmio region access,
1101 + * which could be done in the following init call. So, the mmio
1102 + * region shouldn't be accessed before init (if provided) has
1103 + * returned successfully.
1104 + */
1105 + if (pdata && pdata->init) {
1106 + rc = pdata->init(dev, hpriv->mmio);
1107 + if (rc)
1108 + goto disable_resources;
1109 + }
1110 +
1111 + if (pdata && pdata->ata_port_info)
1112 + pi_template = pdata->ata_port_info;
1113 + else
1114 + pi_template = &ahci_port_info[id ? id->driver_data : 0];
1115 +
1116 + rc = ahci_platform_init_host(pdev, hpriv, pi_template,
1117 + pdata ? pdata->force_port_map : 0,
1118 + pdata ? pdata->mask_port_map : 0);
1119 if (rc)
1120 goto pdata_exit;
1121
1122 @@ -368,8 +436,6 @@ static int ahci_probe(struct platform_device *pdev)
1123 pdata->exit(dev);
1124 disable_resources:
1125 ahci_platform_disable_resources(hpriv);
1126 -free_clk:
1127 - ahci_put_clks(hpriv);
1128 return rc;
1129 }
1130
1131 @@ -383,7 +449,6 @@ static void ahci_host_stop(struct ata_host *host)
1132 pdata->exit(dev);
1133
1134 ahci_platform_disable_resources(hpriv);
1135 - ahci_put_clks(hpriv);
1136 }
1137
1138 #ifdef CONFIG_PM_SLEEP
1139 diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
1140 index b674b01..b80c51c 100644
1141 --- a/include/linux/ahci_platform.h
1142 +++ b/include/linux/ahci_platform.h
1143 @@ -20,7 +20,14 @@
1144 struct device;
1145 struct ata_port_info;
1146 struct ahci_host_priv;
1147 +struct platform_device;
1148
1149 +/*
1150 + * Note ahci_platform_data is deprecated, it is only kept around for use
1151 + * by the old da850 and spear13xx ahci code.
1152 + * New drivers should instead declare their own platform_driver struct, and
1153 + * use ahci_platform* functions in their own probe, suspend and resume methods.
1154 + */
1155 struct ahci_platform_data {
1156 int (*init)(struct device *dev, void __iomem *addr);
1157 void (*exit)(struct device *dev);
1158 @@ -35,5 +42,12 @@ int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
1159 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
1160 int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
1161 void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
1162 +struct ahci_host_priv *ahci_platform_get_resources(
1163 + struct platform_device *pdev);
1164 +int ahci_platform_init_host(struct platform_device *pdev,
1165 + struct ahci_host_priv *hpriv,
1166 + const struct ata_port_info *pi_template,
1167 + unsigned int force_port_map,
1168 + unsigned int mask_port_map);
1169
1170 #endif /* _AHCI_PLATFORM_H */
1171 --
1172 2.0.3
1173
1174 From dffde1e107b4360a4ff6b3aec3693e8b3b4a1bd0 Mon Sep 17 00:00:00 2001
1175 From: Hans de Goede <hdegoede@redhat.com>
1176 Date: Mon, 20 Jan 2014 15:52:07 +0100
1177 Subject: [PATCH] ahci-platform: "Library-ise" suspend / resume functionality
1178
1179 Split suspend / resume code into host suspend / resume functionality and
1180 resource enable / disabling phases, and export the new suspend_ / resume_host
1181 functions.
1182
1183 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1184 ---
1185 drivers/ata/ahci_platform.c | 109 ++++++++++++++++++++++++++++++++++++------
1186 include/linux/ahci_platform.h | 5 ++
1187 2 files changed, 99 insertions(+), 15 deletions(-)
1188
1189 diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
1190 index 7f3f2ac..bdadec1 100644
1191 --- a/drivers/ata/ahci_platform.c
1192 +++ b/drivers/ata/ahci_platform.c
1193 @@ -452,14 +452,26 @@ static void ahci_host_stop(struct ata_host *host)
1194 }
1195
1196 #ifdef CONFIG_PM_SLEEP
1197 -static int ahci_suspend(struct device *dev)
1198 +/**
1199 + * ahci_platform_suspend_host - Suspend an ahci-platform host
1200 + * @dev: device pointer for the host
1201 + *
1202 + * This function does all the usual steps needed to suspend an
1203 + * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
1204 + * must be disabled after calling this.
1205 + *
1206 + * LOCKING:
1207 + * None.
1208 + *
1209 + * RETURNS:
1210 + * 0 on success otherwise a negative error code
1211 + */
1212 +int ahci_platform_suspend_host(struct device *dev)
1213 {
1214 - struct ahci_platform_data *pdata = dev_get_platdata(dev);
1215 struct ata_host *host = dev_get_drvdata(dev);
1216 struct ahci_host_priv *hpriv = host->private_data;
1217 void __iomem *mmio = hpriv->mmio;
1218 u32 ctl;
1219 - int rc;
1220
1221 if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) {
1222 dev_err(dev, "firmware update required for suspend/resume\n");
1223 @@ -476,7 +488,64 @@ static int ahci_suspend(struct device *dev)
1224 writel(ctl, mmio + HOST_CTL);
1225 readl(mmio + HOST_CTL); /* flush */
1226
1227 - rc = ata_host_suspend(host, PMSG_SUSPEND);
1228 + return ata_host_suspend(host, PMSG_SUSPEND);
1229 +}
1230 +EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
1231 +
1232 +/**
1233 + * ahci_platform_resume_host - Resume an ahci-platform host
1234 + * @dev: device pointer for the host
1235 + *
1236 + * This function does all the usual steps needed to resume an
1237 + * ahci-platform host, note any necessary resources (ie clks, phy, etc.)
1238 + * must be initialized / enabled before calling this.
1239 + *
1240 + * LOCKING:
1241 + * None.
1242 + *
1243 + * RETURNS:
1244 + * 0 on success otherwise a negative error code
1245 + */
1246 +int ahci_platform_resume_host(struct device *dev)
1247 +{
1248 + struct ata_host *host = dev_get_drvdata(dev);
1249 + int rc;
1250 +
1251 + if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
1252 + rc = ahci_reset_controller(host);
1253 + if (rc)
1254 + return rc;
1255 +
1256 + ahci_init_controller(host);
1257 + }
1258 +
1259 + ata_host_resume(host);
1260 +
1261 + return 0;
1262 +}
1263 +EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
1264 +
1265 +/**
1266 + * ahci_platform_suspend - Suspend an ahci-platform device
1267 + * @dev: the platform device to suspend
1268 + *
1269 + * This function suspends the host associated with the device, followed
1270 + * by disabling all the resources of the device.
1271 + *
1272 + * LOCKING:
1273 + * None.
1274 + *
1275 + * RETURNS:
1276 + * 0 on success otherwise a negative error code
1277 + */
1278 +int ahci_platform_suspend(struct device *dev)
1279 +{
1280 + struct ahci_platform_data *pdata = dev_get_platdata(dev);
1281 + struct ata_host *host = dev_get_drvdata(dev);
1282 + struct ahci_host_priv *hpriv = host->private_data;
1283 + int rc;
1284 +
1285 + rc = ahci_platform_suspend_host(dev);
1286 if (rc)
1287 return rc;
1288
1289 @@ -487,8 +556,22 @@ static int ahci_suspend(struct device *dev)
1290
1291 return 0;
1292 }
1293 +EXPORT_SYMBOL_GPL(ahci_platform_suspend);
1294
1295 -static int ahci_resume(struct device *dev)
1296 +/**
1297 + * ahci_platform_resume - Resume an ahci-platform device
1298 + * @dev: the platform device to resume
1299 + *
1300 + * This function enables all the resources of the device followed by
1301 + * resuming the host associated with the device.
1302 + *
1303 + * LOCKING:
1304 + * None.
1305 + *
1306 + * RETURNS:
1307 + * 0 on success otherwise a negative error code
1308 + */
1309 +int ahci_platform_resume(struct device *dev)
1310 {
1311 struct ahci_platform_data *pdata = dev_get_platdata(dev);
1312 struct ata_host *host = dev_get_drvdata(dev);
1313 @@ -505,15 +588,9 @@ static int ahci_resume(struct device *dev)
1314 goto disable_resources;
1315 }
1316
1317 - if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
1318 - rc = ahci_reset_controller(host);
1319 - if (rc)
1320 - goto disable_resources;
1321 -
1322 - ahci_init_controller(host);
1323 - }
1324 -
1325 - ata_host_resume(host);
1326 + rc = ahci_platform_resume_host(dev);
1327 + if (rc)
1328 + goto disable_resources;
1329
1330 return 0;
1331
1332 @@ -522,9 +599,11 @@ static int ahci_resume(struct device *dev)
1333
1334 return rc;
1335 }
1336 +EXPORT_SYMBOL_GPL(ahci_platform_resume);
1337 #endif
1338
1339 -static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_suspend, ahci_resume);
1340 +static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend,
1341 + ahci_platform_resume);
1342
1343 static const struct of_device_id ahci_of_match[] = {
1344 { .compatible = "snps,spear-ahci", },
1345 diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
1346 index b80c51c..542f268 100644
1347 --- a/include/linux/ahci_platform.h
1348 +++ b/include/linux/ahci_platform.h
1349 @@ -50,4 +50,9 @@ int ahci_platform_init_host(struct platform_device *pdev,
1350 unsigned int force_port_map,
1351 unsigned int mask_port_map);
1352
1353 +int ahci_platform_suspend_host(struct device *dev);
1354 +int ahci_platform_resume_host(struct device *dev);
1355 +int ahci_platform_suspend(struct device *dev);
1356 +int ahci_platform_resume(struct device *dev);
1357 +
1358 #endif /* _AHCI_PLATFORM_H */
1359 --
1360 2.0.3
1361