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
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.
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.
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).
15 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
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(-)
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)
30 struct ata_port *ap = link->ap;
31 + struct ahci_host_priv *hpriv = ap->host->private_data;
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);
39 - ahci_start_engine(ap);
40 + hpriv->start_engine(ap);
42 DPRINTK("EXIT, rc=%d, class=%u\n", rc, *class);
44 @@ -603,6 +604,7 @@ static int ahci_p5wdh_hardreset(struct ata_link *link, unsigned int *class,
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;
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);
56 - ahci_start_engine(ap);
57 + hpriv->start_engine(ap);
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 */
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.
74 + void (*start_engine)(struct ata_port *ap);
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,
84 * If inconsistent, config values are fixed up by this function.
86 + * If it is not set already this function sets hpriv->start_engine to
87 + * ahci_start_engine.
92 @@ -500,6 +503,9 @@ void ahci_save_initial_config(struct device *dev,
95 hpriv->port_map = port_map;
97 + if (!hpriv->start_engine)
98 + hpriv->start_engine = ahci_start_engine;
100 EXPORT_SYMBOL_GPL(ahci_save_initial_config);
102 @@ -766,7 +772,7 @@ static void ahci_start_port(struct ata_port *ap)
105 if (!(hpriv->flags & AHCI_HFLAG_DELAY_ENGINE))
106 - ahci_start_engine(ap);
107 + hpriv->start_engine(ap);
110 if (ap->flags & ATA_FLAG_EM) {
111 @@ -1234,7 +1240,7 @@ int ahci_kick_engine(struct ata_port *ap)
115 - ahci_start_engine(ap);
116 + hpriv->start_engine(ap);
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;
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,
132 - ahci_start_engine(ap);
133 + hpriv->start_engine(ap);
136 *class = ahci_dev_classify(ap);
137 @@ -2007,10 +2014,12 @@ static void ahci_thaw(struct ata_port *ap)
139 void ahci_error_handler(struct ata_port *ap)
141 + struct ahci_host_priv *hpriv = ap->host->private_data;
143 if (!(ap->pflags & ATA_PFLAG_FROZEN)) {
145 ahci_stop_engine(ap);
146 - ahci_start_engine(ap);
147 + hpriv->start_engine(ap);
150 sata_pmp_error_handler(ap);
151 @@ -2031,6 +2040,7 @@ static void ahci_post_internal_cmd(struct ata_queued_cmd *qc)
153 static void ahci_set_aggressive_devslp(struct ata_port *ap, bool sleep)
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)
161 writel(devslp, port_mmio + PORT_DEVSLP);
163 - ahci_start_engine(ap);
164 + hpriv->start_engine(ap);
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)
170 static void ahci_enable_fbs(struct ata_port *ap)
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);
176 @@ -2134,11 +2145,12 @@ static void ahci_enable_fbs(struct ata_port *ap)
178 dev_err(ap->host->dev, "Failed to enable FBS\n");
180 - ahci_start_engine(ap);
181 + hpriv->start_engine(ap);
184 static void ahci_disable_fbs(struct ata_port *ap)
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);
190 @@ -2166,7 +2178,7 @@ static void ahci_disable_fbs(struct ata_port *ap)
191 pp->fbs_enabled = false;
194 - ahci_start_engine(ap);
195 + hpriv->start_engine(ap);
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;
211 @@ -431,7 +432,7 @@ static int ahci_highbank_hardreset(struct ata_link *link, unsigned int *class,
213 } while (!online && retry--);
215 - ahci_start_engine(ap);
216 + hpriv->start_engine(ap);
219 *class = ahci_dev_classify(ap);
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
228 The allwinner-sun4i AHCI controller needs 2 clocks to be enabled and the
229 imx AHCI controller needs 3 clocks to be enabled.
231 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
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(-)
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:
246 - dma-coherent : Present if dma operations are coherent
247 +- clocks : a list of phandle + clock specifier pairs
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
260 AHCI_MAX_SG = 168, /* hardware max is 64K */
261 AHCI_DMA_BOUNDARY = 0xffffffff,
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 */
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"),
281 + * ahci_platform_enable_clks - Enable platform clocks
282 + * @hpriv: host private area to store config values
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.
292 + * 0 on success otherwise a negative error code
294 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv)
298 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) {
299 + rc = clk_prepare_enable(hpriv->clks[c]);
301 + goto disable_unprepare_clk;
305 +disable_unprepare_clk:
307 + clk_disable_unprepare(hpriv->clks[c]);
310 +EXPORT_SYMBOL_GPL(ahci_platform_enable_clks);
313 + * ahci_platform_disable_clks - Disable platform clocks
314 + * @hpriv: host private area to store config values
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).
322 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
326 + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--)
327 + if (hpriv->clks[c])
328 + clk_disable_unprepare(hpriv->clks[c]);
330 +EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
332 +static void ahci_put_clks(struct ahci_host_priv *hpriv)
336 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
337 + clk_put(hpriv->clks[c]);
340 static int ahci_probe(struct platform_device *pdev)
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;
351 @@ -131,17 +192,31 @@ static int ahci_probe(struct platform_device *pdev)
355 - hpriv->clk = clk_get(dev, NULL);
356 - if (IS_ERR(hpriv->clk)) {
357 - dev_err(dev, "can't get clock\n");
359 - rc = clk_prepare_enable(hpriv->clk);
361 - dev_err(dev, "clock prepare enable failed");
363 + for (i = 0; i < AHCI_MAX_CLKS; i++) {
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).
371 + clk = clk_get(dev, NULL);
373 + clk = of_clk_get(dev->of_node, i);
377 + if (rc == -EPROBE_DEFER)
381 + hpriv->clks[i] = clk;
384 + rc = ahci_enable_clks(dev, hpriv);
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)
394 disable_unprepare_clk:
395 - if (!IS_ERR(hpriv->clk))
396 - clk_disable_unprepare(hpriv->clk);
397 + ahci_disable_clks(hpriv);
399 - if (!IS_ERR(hpriv->clk))
400 - clk_put(hpriv->clk);
401 + ahci_put_clks(hpriv);
405 @@ -239,10 +312,8 @@ static void ahci_host_stop(struct ata_host *host)
406 if (pdata && pdata->exit)
409 - if (!IS_ERR(hpriv->clk)) {
410 - clk_disable_unprepare(hpriv->clk);
411 - clk_put(hpriv->clk);
413 + ahci_disable_clks(hpriv);
414 + ahci_put_clks(hpriv);
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);
422 - if (!IS_ERR(hpriv->clk))
423 - clk_disable_unprepare(hpriv->clk);
424 + ahci_disable_clks(hpriv);
428 @@ -290,13 +360,9 @@ static int ahci_resume(struct device *dev)
429 struct ahci_host_priv *hpriv = host->private_data;
432 - if (!IS_ERR(hpriv->clk)) {
433 - rc = clk_prepare_enable(hpriv->clk);
435 - dev_err(dev, "clock prepare enable failed");
439 + rc = ahci_enable_clks(dev, hpriv);
443 if (pdata && pdata->resume) {
444 rc = pdata->resume(dev);
445 @@ -317,8 +383,7 @@ static int ahci_resume(struct device *dev)
448 disable_unprepare_clk:
449 - if (!IS_ERR(hpriv->clk))
450 - clk_disable_unprepare(hpriv->clk);
451 + ahci_disable_clks(hpriv);
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
462 struct ata_port_info;
463 +struct ahci_host_priv;
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;
471 +int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
472 +void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
474 #endif /* _AHCI_PLATFORM_H */
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
484 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
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(-)
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:
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
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
509 #include <linux/clk.h>
510 #include <linux/libata.h>
511 +#include <linux/regulator/consumer.h>
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 */
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)
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;
539 for (i = 0; i < AHCI_MAX_CLKS; i++) {
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;
546 + if (hpriv->target_pwr) {
547 + rc = regulator_enable(hpriv->target_pwr);
552 rc = ahci_enable_clks(dev, hpriv);
555 + goto disable_regulator;
558 * Some platforms might need to prepare for mmio region access,
559 @@ -298,6 +312,9 @@ static int ahci_probe(struct platform_device *pdev)
561 disable_unprepare_clk:
562 ahci_disable_clks(hpriv);
564 + if (hpriv->target_pwr)
565 + regulator_disable(hpriv->target_pwr);
567 ahci_put_clks(hpriv);
569 @@ -314,6 +331,9 @@ static void ahci_host_stop(struct ata_host *host)
571 ahci_disable_clks(hpriv);
572 ahci_put_clks(hpriv);
574 + if (hpriv->target_pwr)
575 + regulator_disable(hpriv->target_pwr);
578 #ifdef CONFIG_PM_SLEEP
579 @@ -350,6 +370,9 @@ static int ahci_suspend(struct device *dev)
581 ahci_disable_clks(hpriv);
583 + if (hpriv->target_pwr)
584 + regulator_disable(hpriv->target_pwr);
589 @@ -360,9 +383,15 @@ static int ahci_resume(struct device *dev)
590 struct ahci_host_priv *hpriv = host->private_data;
593 + if (hpriv->target_pwr) {
594 + rc = regulator_enable(hpriv->target_pwr);
599 rc = ahci_enable_clks(dev, hpriv);
602 + goto disable_regulator;
604 if (pdata && pdata->resume) {
605 rc = pdata->resume(dev);
606 @@ -384,6 +413,9 @@ static int ahci_resume(struct device *dev)
608 disable_unprepare_clk:
609 ahci_disable_clks(hpriv);
611 + if (hpriv->target_pwr)
612 + regulator_disable(hpriv->target_pwr);
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
625 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
627 drivers/ata/ahci_platform.c | 112 ++++++++++++++++++++++++++++--------------
628 include/linux/ahci_platform.h | 2 +
629 2 files changed, 77 insertions(+), 37 deletions(-)
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)
637 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
640 + * ahci_platform_enable_resources - Enable platform resources
641 + * @hpriv: host private area to store config values
643 + * This function enables all ahci_platform managed resources in
644 + * the following order:
646 + * 2) Clocks (through ahci_platform_enable_clks)
648 + * If resource enabling fails at any point the previous enabled
649 + * resources are disabled in reverse order.
655 + * 0 on success otherwise a negative error code
657 +int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
661 + if (hpriv->target_pwr) {
662 + rc = regulator_enable(hpriv->target_pwr);
667 + rc = ahci_platform_enable_clks(hpriv);
669 + goto disable_regulator;
674 + if (hpriv->target_pwr)
675 + regulator_disable(hpriv->target_pwr);
678 +EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
681 + * ahci_platform_disable_resources - Disable platform resources
682 + * @hpriv: host private area to store config values
684 + * This function disables all ahci_platform managed resources in
685 + * the following order:
686 + * 1) Clocks (through ahci_platform_disable_clks)
692 +void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
694 + ahci_platform_disable_clks(hpriv);
696 + if (hpriv->target_pwr)
697 + regulator_disable(hpriv->target_pwr);
699 +EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
701 static void ahci_put_clks(struct ahci_host_priv *hpriv)
704 @@ -221,15 +283,9 @@ static int ahci_probe(struct platform_device *pdev)
705 hpriv->clks[i] = clk;
708 - if (hpriv->target_pwr) {
709 - rc = regulator_enable(hpriv->target_pwr);
714 - rc = ahci_enable_clks(dev, hpriv);
715 + rc = ahci_platform_enable_resources(hpriv);
717 - goto disable_regulator;
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);
726 - goto disable_unprepare_clk;
727 + goto disable_resources;
730 ahci_save_initial_config(dev, hpriv,
731 @@ -310,11 +366,8 @@ static int ahci_probe(struct platform_device *pdev)
733 if (pdata && pdata->exit)
735 -disable_unprepare_clk:
736 - ahci_disable_clks(hpriv);
738 - if (hpriv->target_pwr)
739 - regulator_disable(hpriv->target_pwr);
741 + ahci_platform_disable_resources(hpriv);
743 ahci_put_clks(hpriv);
745 @@ -329,11 +382,8 @@ static void ahci_host_stop(struct ata_host *host)
746 if (pdata && pdata->exit)
749 - ahci_disable_clks(hpriv);
750 + ahci_platform_disable_resources(hpriv);
751 ahci_put_clks(hpriv);
753 - if (hpriv->target_pwr)
754 - regulator_disable(hpriv->target_pwr);
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);
762 - ahci_disable_clks(hpriv);
764 - if (hpriv->target_pwr)
765 - regulator_disable(hpriv->target_pwr);
766 + ahci_platform_disable_resources(hpriv);
770 @@ -383,26 +430,20 @@ static int ahci_resume(struct device *dev)
771 struct ahci_host_priv *hpriv = host->private_data;
774 - if (hpriv->target_pwr) {
775 - rc = regulator_enable(hpriv->target_pwr);
780 - rc = ahci_enable_clks(dev, hpriv);
781 + rc = ahci_platform_enable_resources(hpriv);
783 - goto disable_regulator;
786 if (pdata && pdata->resume) {
787 rc = pdata->resume(dev);
789 - goto disable_unprepare_clk;
790 + goto disable_resources;
793 if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
794 rc = ahci_reset_controller(host);
796 - goto disable_unprepare_clk;
797 + goto disable_resources;
799 ahci_init_controller(host);
801 @@ -411,11 +452,8 @@ static int ahci_resume(struct device *dev)
805 -disable_unprepare_clk:
806 - ahci_disable_clks(hpriv);
808 - if (hpriv->target_pwr)
809 - regulator_disable(hpriv->target_pwr);
811 + ahci_platform_disable_resources(hpriv);
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 {
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);
826 #endif /* _AHCI_PLATFORM_H */
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
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
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.
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.
850 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
852 drivers/ata/ahci_platform.c | 195 ++++++++++++++++++++++++++++--------------
853 include/linux/ahci_platform.h | 14 +++
854 2 files changed, 144 insertions(+), 65 deletions(-)
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)
862 EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
864 -static void ahci_put_clks(struct ahci_host_priv *hpriv)
865 +static void ahci_platform_put_resources(struct device *dev, void *res)
867 + struct ahci_host_priv *hpriv = res;
870 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
871 clk_put(hpriv->clks[c]);
874 -static int ahci_probe(struct platform_device *pdev)
876 + * ahci_platform_get_resources - Get platform resources
877 + * @pdev: platform device to get resources for
879 + * This function allocates an ahci_host_priv struct, and gets the
880 + * following resources, storing a reference to them inside the returned
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
892 + * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
894 +struct ahci_host_priv *ahci_platform_get_resources(
895 + struct platform_device *pdev)
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;
910 + int i, rc = -ENOMEM;
912 - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
914 - dev_err(dev, "no mmio space\n");
917 + if (!devres_open_group(dev, NULL, GFP_KERNEL))
918 + return ERR_PTR(-ENOMEM);
920 - irq = platform_get_irq(pdev, 0);
922 - dev_err(dev, "no irq\n");
925 + hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv),
930 - if (pdata && pdata->ata_port_info)
931 - pi = *pdata->ata_port_info;
932 + devres_add(dev, hpriv);
934 - hpriv = devm_kzalloc(dev, sizeof(*hpriv), GFP_KERNEL);
936 - dev_err(dev, "can't alloc ahci_host_priv\n");
940 - hpriv->flags |= (unsigned long)pi.private_data;
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));
946 - dev_err(dev, "can't map %pR\n", mem);
948 + dev_err(dev, "no mmio space\n");
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;
958 hpriv->target_pwr = NULL;
961 @@ -277,33 +277,62 @@ static int ahci_probe(struct platform_device *pdev)
964 if (rc == -EPROBE_DEFER)
969 hpriv->clks[i] = clk;
972 - rc = ahci_platform_enable_resources(hpriv);
975 + devres_remove_group(dev, NULL);
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.
984 - if (pdata && pdata->init) {
985 - rc = pdata->init(dev, hpriv->mmio);
987 - goto disable_resources;
990 + devres_release_group(dev, NULL);
991 + return ERR_PTR(rc);
993 +EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
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
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.
1011 + * 0 on success otherwise a negative error code
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)
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;
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);
1030 + dev_err(dev, "no irq\n");
1035 + hpriv->flags |= (unsigned long)pi.private_data;
1037 + ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map);
1039 if (hpriv->cap & HOST_CAP_NCQ)
1040 pi.flags |= ATA_FLAG_NCQ;
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));
1045 host = ata_host_alloc_pinfo(dev, ppi, n_ports);
1053 host->private_data = hpriv;
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];
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);
1064 /* set enclosure management message type */
1065 @@ -352,13 +380,53 @@ static int ahci_probe(struct platform_device *pdev)
1067 rc = ahci_reset_controller(host);
1072 ahci_init_controller(host);
1073 ahci_print_info(host, "platform");
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);
1080 +EXPORT_SYMBOL_GPL(ahci_platform_init_host);
1082 +static int ahci_probe(struct platform_device *pdev)
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;
1091 + hpriv = ahci_platform_get_resources(pdev);
1092 + if (IS_ERR(hpriv))
1093 + return PTR_ERR(hpriv);
1095 + rc = ahci_platform_enable_resources(hpriv);
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.
1105 + if (pdata && pdata->init) {
1106 + rc = pdata->init(dev, hpriv->mmio);
1108 + goto disable_resources;
1111 + if (pdata && pdata->ata_port_info)
1112 + pi_template = pdata->ata_port_info;
1114 + pi_template = &ahci_port_info[id ? id->driver_data : 0];
1116 + rc = ahci_platform_init_host(pdev, hpriv, pi_template,
1117 + pdata ? pdata->force_port_map : 0,
1118 + pdata ? pdata->mask_port_map : 0);
1122 @@ -368,8 +436,6 @@ static int ahci_probe(struct platform_device *pdev)
1125 ahci_platform_disable_resources(hpriv);
1127 - ahci_put_clks(hpriv);
1131 @@ -383,7 +449,6 @@ static void ahci_host_stop(struct ata_host *host)
1134 ahci_platform_disable_resources(hpriv);
1135 - ahci_put_clks(hpriv);
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
1145 struct ata_port_info;
1146 struct ahci_host_priv;
1147 +struct platform_device;
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.
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);
1170 #endif /* _AHCI_PLATFORM_H */
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
1179 Split suspend / resume code into host suspend / resume functionality and
1180 resource enable / disabling phases, and export the new suspend_ / resume_host
1183 Signed-off-by: Hans de Goede <hdegoede@redhat.com>
1185 drivers/ata/ahci_platform.c | 109 ++++++++++++++++++++++++++++++++++++------
1186 include/linux/ahci_platform.h | 5 ++
1187 2 files changed, 99 insertions(+), 15 deletions(-)
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)
1196 #ifdef CONFIG_PM_SLEEP
1197 -static int ahci_suspend(struct device *dev)
1199 + * ahci_platform_suspend_host - Suspend an ahci-platform host
1200 + * @dev: device pointer for the host
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.
1210 + * 0 on success otherwise a negative error code
1212 +int ahci_platform_suspend_host(struct device *dev)
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;
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 */
1227 - rc = ata_host_suspend(host, PMSG_SUSPEND);
1228 + return ata_host_suspend(host, PMSG_SUSPEND);
1230 +EXPORT_SYMBOL_GPL(ahci_platform_suspend_host);
1233 + * ahci_platform_resume_host - Resume an ahci-platform host
1234 + * @dev: device pointer for the host
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.
1244 + * 0 on success otherwise a negative error code
1246 +int ahci_platform_resume_host(struct device *dev)
1248 + struct ata_host *host = dev_get_drvdata(dev);
1251 + if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
1252 + rc = ahci_reset_controller(host);
1256 + ahci_init_controller(host);
1259 + ata_host_resume(host);
1263 +EXPORT_SYMBOL_GPL(ahci_platform_resume_host);
1266 + * ahci_platform_suspend - Suspend an ahci-platform device
1267 + * @dev: the platform device to suspend
1269 + * This function suspends the host associated with the device, followed
1270 + * by disabling all the resources of the device.
1276 + * 0 on success otherwise a negative error code
1278 +int ahci_platform_suspend(struct device *dev)
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;
1285 + rc = ahci_platform_suspend_host(dev);
1289 @@ -487,8 +556,22 @@ static int ahci_suspend(struct device *dev)
1293 +EXPORT_SYMBOL_GPL(ahci_platform_suspend);
1295 -static int ahci_resume(struct device *dev)
1297 + * ahci_platform_resume - Resume an ahci-platform device
1298 + * @dev: the platform device to resume
1300 + * This function enables all the resources of the device followed by
1301 + * resuming the host associated with the device.
1307 + * 0 on success otherwise a negative error code
1309 +int ahci_platform_resume(struct device *dev)
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;
1317 - if (dev->power.power_state.event == PM_EVENT_SUSPEND) {
1318 - rc = ahci_reset_controller(host);
1320 - goto disable_resources;
1322 - ahci_init_controller(host);
1325 - ata_host_resume(host);
1326 + rc = ahci_platform_resume_host(dev);
1328 + goto disable_resources;
1332 @@ -522,9 +599,11 @@ static int ahci_resume(struct device *dev)
1336 +EXPORT_SYMBOL_GPL(ahci_platform_resume);
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);
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);
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);
1358 #endif /* _AHCI_PLATFORM_H */