aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ata
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2014-02-22 10:53:40 -0500
committerTejun Heo <tj@kernel.org>2014-02-22 15:35:43 -0500
commit21b5faeec229d4f70a7f60a7b0b065c98198f491 (patch)
tree5d85aec26355adea114e096654c4d3fb15a49086 /drivers/ata
parent42a7f53ba0f2baa2ea23cd830511cea7f8612dd2 (diff)
ata: ahci_platform: Manage SATA PHY
Some platforms have a PHY hooked up to the SATA controller. The PHY needs to be initialized and powered up for SATA to work. We do that using the PHY framework. tj: Minor comment formatting updates. CC: Balaji T K <balajitk@ti.com> Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo<tj@kernel.org>
Diffstat (limited to 'drivers/ata')
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ahci_platform.c47
2 files changed, 47 insertions, 2 deletions
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index bf8100c51142..3ab7ac9bb6a7 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/phy/phy.h>
40#include <linux/regulator/consumer.h> 41#include <linux/regulator/consumer.h>
41 42
42/* Enclosure Management Control */ 43/* Enclosure Management Control */
@@ -325,6 +326,7 @@ struct ahci_host_priv {
325 u32 em_msg_type; /* EM message type */ 326 u32 em_msg_type; /* EM message type */
326 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 327 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
327 struct regulator *target_pwr; /* Optional */ 328 struct regulator *target_pwr; /* Optional */
329 struct phy *phy; /* If platform uses phy */
328 void *plat_data; /* Other platform data */ 330 void *plat_data; /* Other platform data */
329 /* 331 /*
330 * Optional ahci_start_engine override, if not set this gets set to the 332 * 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 968e7d94af17..243dde36cd98 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -22,6 +22,7 @@
22#include <linux/platform_device.h> 22#include <linux/platform_device.h>
23#include <linux/libata.h> 23#include <linux/libata.h>
24#include <linux/ahci_platform.h> 24#include <linux/ahci_platform.h>
25#include <linux/phy/phy.h>
25#include "ahci.h" 26#include "ahci.h"
26 27
27static void ahci_host_stop(struct ata_host *host); 28static void ahci_host_stop(struct ata_host *host);
@@ -140,6 +141,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
140 * following order: 141 * following order:
141 * 1) Regulator 142 * 1) Regulator
142 * 2) Clocks (through ahci_platform_enable_clks) 143 * 2) Clocks (through ahci_platform_enable_clks)
144 * 3) Phy
143 * 145 *
144 * If resource enabling fails at any point the previous enabled resources 146 * If resource enabling fails at any point the previous enabled resources
145 * are disabled in reverse order. 147 * are disabled in reverse order.
@@ -161,8 +163,23 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
161 if (rc) 163 if (rc)
162 goto disable_regulator; 164 goto disable_regulator;
163 165
166 if (hpriv->phy) {
167 rc = phy_init(hpriv->phy);
168 if (rc)
169 goto disable_clks;
170
171 rc = phy_power_on(hpriv->phy);
172 if (rc) {
173 phy_exit(hpriv->phy);
174 goto disable_clks;
175 }
176 }
177
164 return 0; 178 return 0;
165 179
180disable_clks:
181 ahci_platform_disable_clks(hpriv);
182
166disable_regulator: 183disable_regulator:
167 if (hpriv->target_pwr) 184 if (hpriv->target_pwr)
168 regulator_disable(hpriv->target_pwr); 185 regulator_disable(hpriv->target_pwr);
@@ -176,11 +193,17 @@ EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
176 * 193 *
177 * This function disables all ahci_platform managed resources in the 194 * This function disables all ahci_platform managed resources in the
178 * following order: 195 * following order:
179 * 1) Clocks (through ahci_platform_disable_clks) 196 * 1) Phy
180 * 2) Regulator 197 * 2) Clocks (through ahci_platform_disable_clks)
198 * 3) Regulator
181 */ 199 */
182void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) 200void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
183{ 201{
202 if (hpriv->phy) {
203 phy_power_off(hpriv->phy);
204 phy_exit(hpriv->phy);
205 }
206
184 ahci_platform_disable_clks(hpriv); 207 ahci_platform_disable_clks(hpriv);
185 208
186 if (hpriv->target_pwr) 209 if (hpriv->target_pwr)
@@ -208,6 +231,7 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
208 * 2) regulator for controlling the targets power (optional) 231 * 2) regulator for controlling the targets power (optional)
209 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, 232 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node,
210 * or for non devicetree enabled platforms a single clock 233 * or for non devicetree enabled platforms a single clock
234 * 4) phy (optional)
211 * 235 *
212 * RETURNS: 236 * RETURNS:
213 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value 237 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value
@@ -266,6 +290,25 @@ struct ahci_host_priv *ahci_platform_get_resources(
266 hpriv->clks[i] = clk; 290 hpriv->clks[i] = clk;
267 } 291 }
268 292
293 hpriv->phy = devm_phy_get(dev, "sata-phy");
294 if (IS_ERR(hpriv->phy)) {
295 rc = PTR_ERR(hpriv->phy);
296 switch (rc) {
297 case -ENODEV:
298 case -ENOSYS:
299 /* continue normally */
300 hpriv->phy = NULL;
301 break;
302
303 case -EPROBE_DEFER:
304 goto err_out;
305
306 default:
307 dev_err(dev, "couldn't get sata-phy\n");
308 goto err_out;
309 }
310 }
311
269 devres_remove_group(dev, NULL); 312 devres_remove_group(dev, NULL);
270 return hpriv; 313 return hpriv;
271 314