aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2015-01-15 09:09:37 -0500
committerTejun Heo <tj@kernel.org>2015-01-19 09:53:26 -0500
commitc7d7ddee7e24eedde6149eefbcfbfbc7125b9ff0 (patch)
treea2b9b1404322dc69e75752f4da8a8aece5b73ac3
parent6bd15996071096456578871b286d3e2185bd91e6 (diff)
ata: libahci: Allow using multiple regulators
The current implementation of the libahci allows using multiple PHYs but not multiple regulators. This patch adds the support of multiple regulators. Until now it was mandatory to have a PHY under a subnode, now a port subnode can contain either a regulator or a PHY (or both). In order to be able to asociate a port with a regulator the port are now a platform device in the device tree case. There was only one driver which used directly the regulator field of the ahci_host_priv structure. To preserve the bisectability the change in the ahci_imx driver was done in the same patch. Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Acked-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
-rw-r--r--drivers/ata/ahci.h2
-rw-r--r--drivers/ata/ahci_imx.c14
-rw-r--r--drivers/ata/libahci_platform.c230
-rw-r--r--include/linux/ahci_platform.h2
4 files changed, 173 insertions, 75 deletions
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 40f0e34f17af..275358ae0b3f 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -333,7 +333,7 @@ struct ahci_host_priv {
333 u32 em_msg_type; /* EM message type */ 333 u32 em_msg_type; /* EM message type */
334 bool got_runtime_pm; /* Did we do pm_runtime_get? */ 334 bool got_runtime_pm; /* Did we do pm_runtime_get? */
335 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 335 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
336 struct regulator *target_pwr; /* Optional */ 336 struct regulator **target_pwrs; /* Optional */
337 /* 337 /*
338 * If platform uses PHYs. There is a 1:1 relation between the port number and 338 * If platform uses PHYs. There is a 1:1 relation between the port number and
339 * the PHY position in this array. 339 * the PHY position in this array.
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 35d51c59a370..41632e57d46f 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -221,11 +221,9 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
221 if (imxpriv->no_device) 221 if (imxpriv->no_device)
222 return 0; 222 return 0;
223 223
224 if (hpriv->target_pwr) { 224 ret = ahci_platform_enable_regulators(hpriv);
225 ret = regulator_enable(hpriv->target_pwr); 225 if (ret)
226 if (ret) 226 return ret;
227 return ret;
228 }
229 227
230 ret = clk_prepare_enable(imxpriv->sata_ref_clk); 228 ret = clk_prepare_enable(imxpriv->sata_ref_clk);
231 if (ret < 0) 229 if (ret < 0)
@@ -270,8 +268,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
270disable_clk: 268disable_clk:
271 clk_disable_unprepare(imxpriv->sata_ref_clk); 269 clk_disable_unprepare(imxpriv->sata_ref_clk);
272disable_regulator: 270disable_regulator:
273 if (hpriv->target_pwr) 271 ahci_platform_disable_regulators(hpriv);
274 regulator_disable(hpriv->target_pwr);
275 272
276 return ret; 273 return ret;
277} 274}
@@ -291,8 +288,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
291 288
292 clk_disable_unprepare(imxpriv->sata_ref_clk); 289 clk_disable_unprepare(imxpriv->sata_ref_clk);
293 290
294 if (hpriv->target_pwr) 291 ahci_platform_disable_regulators(hpriv);
295 regulator_disable(hpriv->target_pwr);
296} 292}
297 293
298static void ahci_imx_error_handler(struct ata_port *ap) 294static void ahci_imx_error_handler(struct ata_port *ap)
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index a147aaadca85..73a086664ee7 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -24,6 +24,7 @@
24#include <linux/ahci_platform.h> 24#include <linux/ahci_platform.h>
25#include <linux/phy/phy.h> 25#include <linux/phy/phy.h>
26#include <linux/pm_runtime.h> 26#include <linux/pm_runtime.h>
27#include <linux/of_platform.h>
27#include "ahci.h" 28#include "ahci.h"
28 29
29static void ahci_host_stop(struct ata_host *host); 30static void ahci_host_stop(struct ata_host *host);
@@ -138,6 +139,59 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
138EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); 139EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
139 140
140/** 141/**
142 * ahci_platform_enable_regulators - Enable regulators
143 * @hpriv: host private area to store config values
144 *
145 * This function enables all the regulators found in
146 * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it
147 * disables all the regulators already enabled in reverse order and
148 * returns an error.
149 *
150 * RETURNS:
151 * 0 on success otherwise a negative error code
152 */
153int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
154{
155 int rc, i;
156
157 for (i = 0; i < hpriv->nports; i++) {
158 if (!hpriv->target_pwrs[i])
159 continue;
160
161 rc = regulator_enable(hpriv->target_pwrs[i]);
162 if (rc)
163 goto disable_target_pwrs;
164 }
165
166 return 0;
167
168disable_target_pwrs:
169 while (--i >= 0)
170 if (hpriv->target_pwrs[i])
171 regulator_disable(hpriv->target_pwrs[i]);
172
173 return rc;
174}
175EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
176
177/**
178 * ahci_platform_disable_regulators - Disable regulators
179 * @hpriv: host private area to store config values
180 *
181 * This function disables all regulators found in hpriv->target_pwrs.
182 */
183void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
184{
185 int i;
186
187 for (i = 0; i < hpriv->nports; i++) {
188 if (!hpriv->target_pwrs[i])
189 continue;
190 regulator_disable(hpriv->target_pwrs[i]);
191 }
192}
193EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
194/**
141 * ahci_platform_enable_resources - Enable platform resources 195 * ahci_platform_enable_resources - Enable platform resources
142 * @hpriv: host private area to store config values 196 * @hpriv: host private area to store config values
143 * 197 *
@@ -157,11 +211,9 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
157{ 211{
158 int rc; 212 int rc;
159 213
160 if (hpriv->target_pwr) { 214 rc = ahci_platform_enable_regulators(hpriv);
161 rc = regulator_enable(hpriv->target_pwr); 215 if (rc)
162 if (rc) 216 return rc;
163 return rc;
164 }
165 217
166 rc = ahci_platform_enable_clks(hpriv); 218 rc = ahci_platform_enable_clks(hpriv);
167 if (rc) 219 if (rc)
@@ -177,8 +229,8 @@ disable_clks:
177 ahci_platform_disable_clks(hpriv); 229 ahci_platform_disable_clks(hpriv);
178 230
179disable_regulator: 231disable_regulator:
180 if (hpriv->target_pwr) 232 ahci_platform_disable_regulators(hpriv);
181 regulator_disable(hpriv->target_pwr); 233
182 return rc; 234 return rc;
183} 235}
184EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); 236EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
@@ -199,8 +251,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
199 251
200 ahci_platform_disable_clks(hpriv); 252 ahci_platform_disable_clks(hpriv);
201 253
202 if (hpriv->target_pwr) 254 ahci_platform_disable_regulators(hpriv);
203 regulator_disable(hpriv->target_pwr);
204} 255}
205EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); 256EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
206 257
@@ -216,6 +267,68 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
216 267
217 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) 268 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
218 clk_put(hpriv->clks[c]); 269 clk_put(hpriv->clks[c]);
270 /*
271 * The regulators are tied to child node device and not to the
272 * SATA device itself. So we can't use devm for automatically
273 * releasing them. We have to do it manually here.
274 */
275 for (c = 0; c < hpriv->nports; c++)
276 if (hpriv->target_pwrs && hpriv->target_pwrs[c])
277 regulator_put(hpriv->target_pwrs[c]);
278
279}
280
281static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
282 struct device *dev, struct device_node *node)
283{
284 int rc;
285
286 hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
287
288 if (!IS_ERR(hpriv->phys[port]))
289 return 0;
290
291 rc = PTR_ERR(hpriv->phys[port]);
292 switch (rc) {
293 case -ENOSYS:
294 /* No PHY support. Check if PHY is required. */
295 if (of_find_property(node, "phys", NULL)) {
296 dev_err(dev,
297 "couldn't get PHY in node %s: ENOSYS\n",
298 node->name);
299 break;
300 }
301 case -ENODEV:
302 /* continue normally */
303 hpriv->phys[port] = NULL;
304 rc = 0;
305 break;
306
307 default:
308 dev_err(dev,
309 "couldn't get PHY in node %s: %d\n",
310 node->name, rc);
311
312 break;
313 }
314
315 return rc;
316}
317
318static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
319 struct device *dev)
320{
321 struct regulator *target_pwr;
322 int rc = 0;
323
324 target_pwr = regulator_get_optional(dev, "target");
325
326 if (!IS_ERR(target_pwr))
327 hpriv->target_pwrs[port] = target_pwr;
328 else
329 rc = PTR_ERR(target_pwr);
330
331 return rc;
219} 332}
220 333
221/** 334/**
@@ -240,7 +353,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
240 struct ahci_host_priv *hpriv; 353 struct ahci_host_priv *hpriv;
241 struct clk *clk; 354 struct clk *clk;
242 struct device_node *child; 355 struct device_node *child;
243 int i, enabled_ports = 0, rc = -ENOMEM; 356 int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes;
244 u32 mask_port_map = 0; 357 u32 mask_port_map = 0;
245 358
246 if (!devres_open_group(dev, NULL, GFP_KERNEL)) 359 if (!devres_open_group(dev, NULL, GFP_KERNEL))
@@ -261,14 +374,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
261 goto err_out; 374 goto err_out;
262 } 375 }
263 376
264 hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
265 if (IS_ERR(hpriv->target_pwr)) {
266 rc = PTR_ERR(hpriv->target_pwr);
267 if (rc == -EPROBE_DEFER)
268 goto err_out;
269 hpriv->target_pwr = NULL;
270 }
271
272 for (i = 0; i < AHCI_MAX_CLKS; i++) { 377 for (i = 0; i < AHCI_MAX_CLKS; i++) {
273 /* 378 /*
274 * For now we must use clk_get(dev, NULL) for the first clock, 379 * For now we must use clk_get(dev, NULL) for the first clock,
@@ -290,19 +395,33 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
290 hpriv->clks[i] = clk; 395 hpriv->clks[i] = clk;
291 } 396 }
292 397
293 hpriv->nports = of_get_child_count(dev->of_node); 398 hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
294 399
295 if (hpriv->nports) { 400 /*
296 hpriv->phys = devm_kzalloc(dev, 401 * If no sub-node was found, we still need to set nports to
297 hpriv->nports * sizeof(*hpriv->phys), 402 * one in order to be able to use the
298 GFP_KERNEL); 403 * ahci_platform_[en|dis]able_[phys|regulators] functions.
299 if (!hpriv->phys) { 404 */
300 rc = -ENOMEM; 405 if (!child_nodes)
301 goto err_out; 406 hpriv->nports = 1;
302 }
303 407
408 sz = hpriv->nports * sizeof(*hpriv->phys);
409 hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL);
410 if (!hpriv->phys) {
411 rc = -ENOMEM;
412 goto err_out;
413 }
414 sz = hpriv->nports * sizeof(*hpriv->target_pwrs);
415 hpriv->target_pwrs = devm_kzalloc(dev, sz, GFP_KERNEL);
416 if (!hpriv->target_pwrs) {
417 rc = -ENOMEM;
418 goto err_out;
419 }
420
421 if (child_nodes) {
304 for_each_child_of_node(dev->of_node, child) { 422 for_each_child_of_node(dev->of_node, child) {
305 u32 port; 423 u32 port;
424 struct platform_device *port_dev;
306 425
307 if (!of_device_is_available(child)) 426 if (!of_device_is_available(child))
308 continue; 427 continue;
@@ -316,18 +435,23 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
316 dev_warn(dev, "invalid port number %d\n", port); 435 dev_warn(dev, "invalid port number %d\n", port);
317 continue; 436 continue;
318 } 437 }
319
320 mask_port_map |= BIT(port); 438 mask_port_map |= BIT(port);
321 439
322 hpriv->phys[port] = devm_of_phy_get(dev, child, NULL); 440 of_platform_device_create(child, NULL, NULL);
323 if (IS_ERR(hpriv->phys[port])) { 441
324 rc = PTR_ERR(hpriv->phys[port]); 442 port_dev = of_find_device_by_node(child);
325 dev_err(dev, 443
326 "couldn't get PHY in node %s: %d\n", 444 if (port_dev) {
327 child->name, rc); 445 rc = ahci_platform_get_regulator(hpriv, port,
328 goto err_out; 446 &port_dev->dev);
447 if (rc == -EPROBE_DEFER)
448 goto err_out;
329 } 449 }
330 450
451 rc = ahci_platform_get_phy(hpriv, port, dev, child);
452 if (rc)
453 goto err_out;
454
331 enabled_ports++; 455 enabled_ports++;
332 } 456 }
333 if (!enabled_ports) { 457 if (!enabled_ports) {
@@ -343,38 +467,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
343 * If no sub-node was found, keep this for device tree 467 * If no sub-node was found, keep this for device tree
344 * compatibility 468 * compatibility
345 */ 469 */
346 struct phy *phy = devm_phy_get(dev, "sata-phy"); 470 rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
347 if (!IS_ERR(phy)) { 471 if (rc)
348 hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys), 472 goto err_out;
349 GFP_KERNEL);
350 if (!hpriv->phys) {
351 rc = -ENOMEM;
352 goto err_out;
353 }
354
355 hpriv->phys[0] = phy;
356 hpriv->nports = 1;
357 } else {
358 rc = PTR_ERR(phy);
359 switch (rc) {
360 case -ENOSYS:
361 /* No PHY support. Check if PHY is required. */
362 if (of_find_property(dev->of_node, "phys", NULL)) {
363 dev_err(dev, "couldn't get sata-phy: ENOSYS\n");
364 goto err_out;
365 }
366 case -ENODEV:
367 /* continue normally */
368 hpriv->phys = NULL;
369 break;
370
371 default:
372 goto err_out;
373 473
374 } 474 rc = ahci_platform_get_regulator(hpriv, 0, dev);
375 } 475 if (rc == -EPROBE_DEFER)
476 goto err_out;
376 } 477 }
377
378 pm_runtime_enable(dev); 478 pm_runtime_enable(dev);
379 pm_runtime_get_sync(dev); 479 pm_runtime_get_sync(dev);
380 hpriv->got_runtime_pm = true; 480 hpriv->got_runtime_pm = true;
diff --git a/include/linux/ahci_platform.h b/include/linux/ahci_platform.h
index 642d6ae4030c..f65b33809170 100644
--- a/include/linux/ahci_platform.h
+++ b/include/linux/ahci_platform.h
@@ -24,6 +24,8 @@ struct platform_device;
24 24
25int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); 25int ahci_platform_enable_clks(struct ahci_host_priv *hpriv);
26void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); 26void ahci_platform_disable_clks(struct ahci_host_priv *hpriv);
27int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv);
28void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv);
27int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); 29int ahci_platform_enable_resources(struct ahci_host_priv *hpriv);
28void ahci_platform_disable_resources(struct ahci_host_priv *hpriv); 30void ahci_platform_disable_resources(struct ahci_host_priv *hpriv);
29struct ahci_host_priv *ahci_platform_get_resources( 31struct ahci_host_priv *ahci_platform_get_resources(