diff options
author | Hans de Goede <hdegoede@redhat.com> | 2014-02-22 10:53:32 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-02-22 15:35:42 -0500 |
commit | 4b3e603a298db26c6c37e8b08adcce24d014df13 (patch) | |
tree | ee83e07b60a9fc55e3882c826ee9804223ebaf3a | |
parent | 156c5887948cd191417f18026aab9ce26e5a95da (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.txt | 1 | ||||
-rw-r--r-- | drivers/ata/ahci.h | 2 | ||||
-rw-r--r-- | drivers/ata/ahci_platform.c | 36 |
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: | |||
11 | Optional properties: | 11 | Optional 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 | ||
15 | Example: | 16 | Example: |
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); |
292 | disable_unprepare_clk: | 306 | disable_unprepare_clk: |
293 | ahci_disable_clks(hpriv); | 307 | ahci_disable_clks(hpriv); |
308 | disable_regulator: | ||
309 | if (hpriv->target_pwr) | ||
310 | regulator_disable(hpriv->target_pwr); | ||
294 | free_clk: | 311 | free_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 | ||
378 | disable_unprepare_clk: | 407 | disable_unprepare_clk: |
379 | ahci_disable_clks(hpriv); | 408 | ahci_disable_clks(hpriv); |
409 | disable_regulator: | ||
410 | if (hpriv->target_pwr) | ||
411 | regulator_disable(hpriv->target_pwr); | ||
380 | 412 | ||
381 | return rc; | 413 | return rc; |
382 | } | 414 | } |