aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2014-02-22 10:53:32 -0500
committerTejun Heo <tj@kernel.org>2014-02-22 15:35:42 -0500
commit4b3e603a298db26c6c37e8b08adcce24d014df13 (patch)
treeee83e07b60a9fc55e3882c826ee9804223ebaf3a
parent156c5887948cd191417f18026aab9ce26e5a95da (diff)
ahci-platform: Add support for an optional regulator for sata-target power
Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--Documentation/devicetree/bindings/ata/ahci-platform.txt1
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ahci_platform.c36
3 files changed, 37 insertions, 2 deletions
diff --git a/Documentation/devicetree/bindings/ata/ahci-platform.txt b/Documentation/devicetree/bindings/ata/ahci-platform.txt
index 3ced07dc8f56..1ac807fd34e6 100644
--- a/Documentation/devicetree/bindings/ata/ahci-platform.txt
+++ b/Documentation/devicetree/bindings/ata/ahci-platform.txt
@@ -11,6 +11,7 @@ Required properties:
11Optional properties: 11Optional properties:
12- dma-coherent : Present if dma operations are coherent 12- dma-coherent : Present if dma operations are coherent
13- clocks : a list of phandle + clock specifier pairs 13- clocks : a list of phandle + clock specifier pairs
14- target-supply : regulator for SATA target power
14 15
15Example: 16Example:
16 sata@ffe08000 { 17 sata@ffe08000 {
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index c12862bd48ee..bf8100c51142 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -37,6 +37,7 @@
37 37
38#include <linux/clk.h> 38#include <linux/clk.h>
39#include <linux/libata.h> 39#include <linux/libata.h>
40#include <linux/regulator/consumer.h>
40 41
41/* Enclosure Management Control */ 42/* Enclosure Management Control */
42#define EM_CTRL_MSG_TYPE 0x000f0000 43#define EM_CTRL_MSG_TYPE 0x000f0000
@@ -323,6 +324,7 @@ struct ahci_host_priv {
323 u32 em_buf_sz; /* EM buffer size in byte */ 324 u32 em_buf_sz; /* EM buffer size in byte */
324 u32 em_msg_type; /* EM message type */ 325 u32 em_msg_type; /* EM message type */
325 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 326 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
327 struct regulator *target_pwr; /* Optional */
326 void *plat_data; /* Other platform data */ 328 void *plat_data; /* Other platform data */
327 /* 329 /*
328 * Optional ahci_start_engine override, if not set this gets set to the 330 * Optional ahci_start_engine override, if not set this gets set to the
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 8d5a9a7ce958..4befd78133ad 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -185,6 +185,14 @@ static int ahci_probe(struct platform_device *pdev)
185 return -ENOMEM; 185 return -ENOMEM;
186 } 186 }
187 187
188 hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
189 if (IS_ERR(hpriv->target_pwr)) {
190 rc = PTR_ERR(hpriv->target_pwr);
191 if (rc == -EPROBE_DEFER)
192 return -EPROBE_DEFER;
193 hpriv->target_pwr = NULL;
194 }
195
188 for (i = 0; i < AHCI_MAX_CLKS; i++) { 196 for (i = 0; i < AHCI_MAX_CLKS; i++) {
189 /* 197 /*
190 * For now we must use clk_get(dev, NULL) for the first clock, 198 * For now we must use clk_get(dev, NULL) for the first clock,
@@ -206,9 +214,15 @@ static int ahci_probe(struct platform_device *pdev)
206 hpriv->clks[i] = clk; 214 hpriv->clks[i] = clk;
207 } 215 }
208 216
217 if (hpriv->target_pwr) {
218 rc = regulator_enable(hpriv->target_pwr);
219 if (rc)
220 goto free_clk;
221 }
222
209 rc = ahci_enable_clks(dev, hpriv); 223 rc = ahci_enable_clks(dev, hpriv);
210 if (rc) 224 if (rc)
211 goto free_clk; 225 goto disable_regulator;
212 226
213 /* 227 /*
214 * Some platforms might need to prepare for mmio region access, 228 * Some platforms might need to prepare for mmio region access,
@@ -291,6 +305,9 @@ pdata_exit:
291 pdata->exit(dev); 305 pdata->exit(dev);
292disable_unprepare_clk: 306disable_unprepare_clk:
293 ahci_disable_clks(hpriv); 307 ahci_disable_clks(hpriv);
308disable_regulator:
309 if (hpriv->target_pwr)
310 regulator_disable(hpriv->target_pwr);
294free_clk: 311free_clk:
295 ahci_put_clks(hpriv); 312 ahci_put_clks(hpriv);
296 return rc; 313 return rc;
@@ -307,6 +324,9 @@ static void ahci_host_stop(struct ata_host *host)
307 324
308 ahci_disable_clks(hpriv); 325 ahci_disable_clks(hpriv);
309 ahci_put_clks(hpriv); 326 ahci_put_clks(hpriv);
327
328 if (hpriv->target_pwr)
329 regulator_disable(hpriv->target_pwr);
310} 330}
311 331
312#ifdef CONFIG_PM_SLEEP 332#ifdef CONFIG_PM_SLEEP
@@ -343,6 +363,9 @@ static int ahci_suspend(struct device *dev)
343 363
344 ahci_disable_clks(hpriv); 364 ahci_disable_clks(hpriv);
345 365
366 if (hpriv->target_pwr)
367 regulator_disable(hpriv->target_pwr);
368
346 return 0; 369 return 0;
347} 370}
348 371
@@ -353,9 +376,15 @@ static int ahci_resume(struct device *dev)
353 struct ahci_host_priv *hpriv = host->private_data; 376 struct ahci_host_priv *hpriv = host->private_data;
354 int rc; 377 int rc;
355 378
379 if (hpriv->target_pwr) {
380 rc = regulator_enable(hpriv->target_pwr);
381 if (rc)
382 return rc;
383 }
384
356 rc = ahci_enable_clks(dev, hpriv); 385 rc = ahci_enable_clks(dev, hpriv);
357 if (rc) 386 if (rc)
358 return rc; 387 goto disable_regulator;
359 388
360 if (pdata && pdata->resume) { 389 if (pdata && pdata->resume) {
361 rc = pdata->resume(dev); 390 rc = pdata->resume(dev);
@@ -377,6 +406,9 @@ static int ahci_resume(struct device *dev)
377 406
378disable_unprepare_clk: 407disable_unprepare_clk:
379 ahci_disable_clks(hpriv); 408 ahci_disable_clks(hpriv);
409disable_regulator:
410 if (hpriv->target_pwr)
411 regulator_disable(hpriv->target_pwr);
380 412
381 return rc; 413 return rc;
382} 414}