diff options
author | Roger Quadros <rogerq@ti.com> | 2014-02-22 10:53:40 -0500 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2014-02-22 15:35:43 -0500 |
commit | 21b5faeec229d4f70a7f60a7b0b065c98198f491 (patch) | |
tree | 5d85aec26355adea114e096654c4d3fb15a49086 /drivers/ata | |
parent | 42a7f53ba0f2baa2ea23cd830511cea7f8612dd2 (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.h | 2 | ||||
-rw-r--r-- | drivers/ata/ahci_platform.c | 47 |
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 | ||
27 | static void ahci_host_stop(struct ata_host *host); | 28 | static 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 | ||
180 | disable_clks: | ||
181 | ahci_platform_disable_clks(hpriv); | ||
182 | |||
166 | disable_regulator: | 183 | disable_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 | */ |
182 | void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) | 200 | void 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 | ||