Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Gregory CLEMENT and committed by
Tejun Heo
c7d7ddee 6bd15996

+173 -75
+1 -1
drivers/ata/ahci.h
··· 333 333 u32 em_msg_type; /* EM message type */ 334 334 bool got_runtime_pm; /* Did we do pm_runtime_get? */ 335 335 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 336 - struct regulator *target_pwr; /* Optional */ 336 + struct regulator **target_pwrs; /* Optional */ 337 337 /* 338 338 * If platform uses PHYs. There is a 1:1 relation between the port number and 339 339 * the PHY position in this array.
+5 -9
drivers/ata/ahci_imx.c
··· 221 221 if (imxpriv->no_device) 222 222 return 0; 223 223 224 - if (hpriv->target_pwr) { 225 - ret = regulator_enable(hpriv->target_pwr); 226 - if (ret) 227 - return ret; 228 - } 224 + ret = ahci_platform_enable_regulators(hpriv); 225 + if (ret) 226 + return ret; 229 227 230 228 ret = clk_prepare_enable(imxpriv->sata_ref_clk); 231 229 if (ret < 0) ··· 268 270 disable_clk: 269 271 clk_disable_unprepare(imxpriv->sata_ref_clk); 270 272 disable_regulator: 271 - if (hpriv->target_pwr) 272 - regulator_disable(hpriv->target_pwr); 273 + ahci_platform_disable_regulators(hpriv); 273 274 274 275 return ret; 275 276 } ··· 288 291 289 292 clk_disable_unprepare(imxpriv->sata_ref_clk); 290 293 291 - if (hpriv->target_pwr) 292 - regulator_disable(hpriv->target_pwr); 294 + ahci_platform_disable_regulators(hpriv); 293 295 } 294 296 295 297 static void ahci_imx_error_handler(struct ata_port *ap)
+165 -65
drivers/ata/libahci_platform.c
··· 24 24 #include <linux/ahci_platform.h> 25 25 #include <linux/phy/phy.h> 26 26 #include <linux/pm_runtime.h> 27 + #include <linux/of_platform.h> 27 28 #include "ahci.h" 28 29 29 30 static void ahci_host_stop(struct ata_host *host); ··· 139 138 EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); 140 139 141 140 /** 141 + * ahci_platform_enable_regulators - Enable regulators 142 + * @hpriv: host private area to store config values 143 + * 144 + * This function enables all the regulators found in 145 + * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it 146 + * disables all the regulators already enabled in reverse order and 147 + * returns an error. 148 + * 149 + * RETURNS: 150 + * 0 on success otherwise a negative error code 151 + */ 152 + int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv) 153 + { 154 + int rc, i; 155 + 156 + for (i = 0; i < hpriv->nports; i++) { 157 + if (!hpriv->target_pwrs[i]) 158 + continue; 159 + 160 + rc = regulator_enable(hpriv->target_pwrs[i]); 161 + if (rc) 162 + goto disable_target_pwrs; 163 + } 164 + 165 + return 0; 166 + 167 + disable_target_pwrs: 168 + while (--i >= 0) 169 + if (hpriv->target_pwrs[i]) 170 + regulator_disable(hpriv->target_pwrs[i]); 171 + 172 + return rc; 173 + } 174 + EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators); 175 + 176 + /** 177 + * ahci_platform_disable_regulators - Disable regulators 178 + * @hpriv: host private area to store config values 179 + * 180 + * This function disables all regulators found in hpriv->target_pwrs. 181 + */ 182 + void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv) 183 + { 184 + int i; 185 + 186 + for (i = 0; i < hpriv->nports; i++) { 187 + if (!hpriv->target_pwrs[i]) 188 + continue; 189 + regulator_disable(hpriv->target_pwrs[i]); 190 + } 191 + } 192 + EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators); 193 + /** 142 194 * ahci_platform_enable_resources - Enable platform resources 143 195 * @hpriv: host private area to store config values 144 196 * ··· 211 157 { 212 158 int rc; 213 159 214 - if (hpriv->target_pwr) { 215 - rc = regulator_enable(hpriv->target_pwr); 216 - if (rc) 217 - return rc; 218 - } 160 + rc = ahci_platform_enable_regulators(hpriv); 161 + if (rc) 162 + return rc; 219 163 220 164 rc = ahci_platform_enable_clks(hpriv); 221 165 if (rc) ··· 229 177 ahci_platform_disable_clks(hpriv); 230 178 231 179 disable_regulator: 232 - if (hpriv->target_pwr) 233 - regulator_disable(hpriv->target_pwr); 180 + ahci_platform_disable_regulators(hpriv); 181 + 234 182 return rc; 235 183 } 236 184 EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); ··· 251 199 252 200 ahci_platform_disable_clks(hpriv); 253 201 254 - if (hpriv->target_pwr) 255 - regulator_disable(hpriv->target_pwr); 202 + ahci_platform_disable_regulators(hpriv); 256 203 } 257 204 EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); 258 205 ··· 267 216 268 217 for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) 269 218 clk_put(hpriv->clks[c]); 219 + /* 220 + * The regulators are tied to child node device and not to the 221 + * SATA device itself. So we can't use devm for automatically 222 + * releasing them. We have to do it manually here. 223 + */ 224 + for (c = 0; c < hpriv->nports; c++) 225 + if (hpriv->target_pwrs && hpriv->target_pwrs[c]) 226 + regulator_put(hpriv->target_pwrs[c]); 227 + 228 + } 229 + 230 + static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port, 231 + struct device *dev, struct device_node *node) 232 + { 233 + int rc; 234 + 235 + hpriv->phys[port] = devm_of_phy_get(dev, node, NULL); 236 + 237 + if (!IS_ERR(hpriv->phys[port])) 238 + return 0; 239 + 240 + rc = PTR_ERR(hpriv->phys[port]); 241 + switch (rc) { 242 + case -ENOSYS: 243 + /* No PHY support. Check if PHY is required. */ 244 + if (of_find_property(node, "phys", NULL)) { 245 + dev_err(dev, 246 + "couldn't get PHY in node %s: ENOSYS\n", 247 + node->name); 248 + break; 249 + } 250 + case -ENODEV: 251 + /* continue normally */ 252 + hpriv->phys[port] = NULL; 253 + rc = 0; 254 + break; 255 + 256 + default: 257 + dev_err(dev, 258 + "couldn't get PHY in node %s: %d\n", 259 + node->name, rc); 260 + 261 + break; 262 + } 263 + 264 + return rc; 265 + } 266 + 267 + static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port, 268 + struct device *dev) 269 + { 270 + struct regulator *target_pwr; 271 + int rc = 0; 272 + 273 + target_pwr = regulator_get_optional(dev, "target"); 274 + 275 + if (!IS_ERR(target_pwr)) 276 + hpriv->target_pwrs[port] = target_pwr; 277 + else 278 + rc = PTR_ERR(target_pwr); 279 + 280 + return rc; 270 281 } 271 282 272 283 /** ··· 353 240 struct ahci_host_priv *hpriv; 354 241 struct clk *clk; 355 242 struct device_node *child; 356 - int i, enabled_ports = 0, rc = -ENOMEM; 243 + int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes; 357 244 u32 mask_port_map = 0; 358 245 359 246 if (!devres_open_group(dev, NULL, GFP_KERNEL)) ··· 372 259 dev_err(dev, "no mmio space\n"); 373 260 rc = PTR_ERR(hpriv->mmio); 374 261 goto err_out; 375 - } 376 - 377 - hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); 378 - if (IS_ERR(hpriv->target_pwr)) { 379 - rc = PTR_ERR(hpriv->target_pwr); 380 - if (rc == -EPROBE_DEFER) 381 - goto err_out; 382 - hpriv->target_pwr = NULL; 383 262 } 384 263 385 264 for (i = 0; i < AHCI_MAX_CLKS; i++) { ··· 395 290 hpriv->clks[i] = clk; 396 291 } 397 292 398 - hpriv->nports = of_get_child_count(dev->of_node); 293 + hpriv->nports = child_nodes = of_get_child_count(dev->of_node); 399 294 400 - if (hpriv->nports) { 401 - hpriv->phys = devm_kzalloc(dev, 402 - hpriv->nports * sizeof(*hpriv->phys), 403 - GFP_KERNEL); 404 - if (!hpriv->phys) { 405 - rc = -ENOMEM; 406 - goto err_out; 407 - } 295 + /* 296 + * If no sub-node was found, we still need to set nports to 297 + * one in order to be able to use the 298 + * ahci_platform_[en|dis]able_[phys|regulators] functions. 299 + */ 300 + if (!child_nodes) 301 + hpriv->nports = 1; 408 302 303 + sz = hpriv->nports * sizeof(*hpriv->phys); 304 + hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL); 305 + if (!hpriv->phys) { 306 + rc = -ENOMEM; 307 + goto err_out; 308 + } 309 + sz = hpriv->nports * sizeof(*hpriv->target_pwrs); 310 + hpriv->target_pwrs = devm_kzalloc(dev, sz, GFP_KERNEL); 311 + if (!hpriv->target_pwrs) { 312 + rc = -ENOMEM; 313 + goto err_out; 314 + } 315 + 316 + if (child_nodes) { 409 317 for_each_child_of_node(dev->of_node, child) { 410 318 u32 port; 319 + struct platform_device *port_dev; 411 320 412 321 if (!of_device_is_available(child)) 413 322 continue; ··· 435 316 dev_warn(dev, "invalid port number %d\n", port); 436 317 continue; 437 318 } 438 - 439 319 mask_port_map |= BIT(port); 440 320 441 - hpriv->phys[port] = devm_of_phy_get(dev, child, NULL); 442 - if (IS_ERR(hpriv->phys[port])) { 443 - rc = PTR_ERR(hpriv->phys[port]); 444 - dev_err(dev, 445 - "couldn't get PHY in node %s: %d\n", 446 - child->name, rc); 447 - goto err_out; 321 + of_platform_device_create(child, NULL, NULL); 322 + 323 + port_dev = of_find_device_by_node(child); 324 + 325 + if (port_dev) { 326 + rc = ahci_platform_get_regulator(hpriv, port, 327 + &port_dev->dev); 328 + if (rc == -EPROBE_DEFER) 329 + goto err_out; 448 330 } 331 + 332 + rc = ahci_platform_get_phy(hpriv, port, dev, child); 333 + if (rc) 334 + goto err_out; 449 335 450 336 enabled_ports++; 451 337 } ··· 467 343 * If no sub-node was found, keep this for device tree 468 344 * compatibility 469 345 */ 470 - struct phy *phy = devm_phy_get(dev, "sata-phy"); 471 - if (!IS_ERR(phy)) { 472 - hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys), 473 - GFP_KERNEL); 474 - if (!hpriv->phys) { 475 - rc = -ENOMEM; 476 - goto err_out; 477 - } 346 + rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node); 347 + if (rc) 348 + goto err_out; 478 349 479 - hpriv->phys[0] = phy; 480 - hpriv->nports = 1; 481 - } else { 482 - rc = PTR_ERR(phy); 483 - switch (rc) { 484 - case -ENOSYS: 485 - /* No PHY support. Check if PHY is required. */ 486 - if (of_find_property(dev->of_node, "phys", NULL)) { 487 - dev_err(dev, "couldn't get sata-phy: ENOSYS\n"); 488 - goto err_out; 489 - } 490 - case -ENODEV: 491 - /* continue normally */ 492 - hpriv->phys = NULL; 493 - break; 494 - 495 - default: 496 - goto err_out; 497 - 498 - } 499 - } 350 + rc = ahci_platform_get_regulator(hpriv, 0, dev); 351 + if (rc == -EPROBE_DEFER) 352 + goto err_out; 500 353 } 501 - 502 354 pm_runtime_enable(dev); 503 355 pm_runtime_get_sync(dev); 504 356 hpriv->got_runtime_pm = true;
+2
include/linux/ahci_platform.h
··· 24 24 25 25 int ahci_platform_enable_clks(struct ahci_host_priv *hpriv); 26 26 void ahci_platform_disable_clks(struct ahci_host_priv *hpriv); 27 + int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv); 28 + void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv); 27 29 int ahci_platform_enable_resources(struct ahci_host_priv *hpriv); 28 30 void ahci_platform_disable_resources(struct ahci_host_priv *hpriv); 29 31 struct ahci_host_priv *ahci_platform_get_resources(