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

ata: libahci_platform: add reset control support

Add support to get and control a list of resets for the device
as optional and shared. These resets must be kept de-asserted until
the device is enabled.

This is specified as shared because some SoCs like UniPhier series
have common reset controls with all ahci controller instances.

However, according to Thierry's view,
https://www.spinics.net/lists/linux-ide/msg55357.html
some hardware-specific drivers already use their own resets,
and the common reset make a path to occur double controls of resets.

The ahci_platform_get_resources() can get and control the reset
only when the second argument includes AHCI_PLATFORM_GET_RESETS bit.

Suggested-by: Hans de Goede <hdegoede@redhat.com>
Cc: Thierry Reding <thierry.reding@gmail.com>
Signed-off-by: Kunihiko Hayashi <hayashi.kunihiko@socionext.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Kunihiko Hayashi and committed by
Tejun Heo
9d2ab995 16af2d65

+30 -5
+1
Documentation/devicetree/bindings/ata/ahci-platform.txt
··· 30 30 Optional properties: 31 31 - dma-coherent : Present if dma operations are coherent 32 32 - clocks : a list of phandle + clock specifier pairs 33 + - resets : a list of phandle + reset specifier pairs 33 34 - target-supply : regulator for SATA target power 34 35 - phys : reference to the SATA PHY node 35 36 - phy-names : must be "sata-phy"
+1
drivers/ata/ahci.h
··· 350 350 u32 em_msg_type; /* EM message type */ 351 351 bool got_runtime_pm; /* Did we do pm_runtime_get? */ 352 352 struct clk *clks[AHCI_MAX_CLKS]; /* Optional */ 353 + struct reset_control *rsts; /* Optional */ 353 354 struct regulator **target_pwrs; /* Optional */ 354 355 /* 355 356 * If platform uses PHYs. There is a 1:1 relation between the port number and
+26 -5
drivers/ata/libahci_platform.c
··· 25 25 #include <linux/phy/phy.h> 26 26 #include <linux/pm_runtime.h> 27 27 #include <linux/of_platform.h> 28 + #include <linux/reset.h> 28 29 #include "ahci.h" 29 30 30 31 static void ahci_host_stop(struct ata_host *host); ··· 196 195 * following order: 197 196 * 1) Regulator 198 197 * 2) Clocks (through ahci_platform_enable_clks) 199 - * 3) Phys 198 + * 3) Resets 199 + * 4) Phys 200 200 * 201 201 * If resource enabling fails at any point the previous enabled resources 202 202 * are disabled in reverse order. ··· 217 215 if (rc) 218 216 goto disable_regulator; 219 217 220 - rc = ahci_platform_enable_phys(hpriv); 218 + rc = reset_control_deassert(hpriv->rsts); 221 219 if (rc) 222 220 goto disable_clks; 223 221 222 + rc = ahci_platform_enable_phys(hpriv); 223 + if (rc) 224 + goto disable_resets; 225 + 224 226 return 0; 227 + 228 + disable_resets: 229 + reset_control_assert(hpriv->rsts); 225 230 226 231 disable_clks: 227 232 ahci_platform_disable_clks(hpriv); ··· 247 238 * This function disables all ahci_platform managed resources in the 248 239 * following order: 249 240 * 1) Phys 250 - * 2) Clocks (through ahci_platform_disable_clks) 251 - * 3) Regulator 241 + * 2) Resets 242 + * 3) Clocks (through ahci_platform_disable_clks) 243 + * 4) Regulator 252 244 */ 253 245 void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) 254 246 { 255 247 ahci_platform_disable_phys(hpriv); 248 + 249 + reset_control_assert(hpriv->rsts); 256 250 257 251 ahci_platform_disable_clks(hpriv); 258 252 ··· 353 341 * 2) regulator for controlling the targets power (optional) 354 342 * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, 355 343 * or for non devicetree enabled platforms a single clock 356 - * 4) phys (optional) 344 + * 4) resets, if flags has AHCI_PLATFORM_GET_RESETS (optional) 345 + * 5) phys (optional) 357 346 * 358 347 * RETURNS: 359 348 * The allocated ahci_host_priv on success, otherwise an ERR_PTR value ··· 406 393 break; 407 394 } 408 395 hpriv->clks[i] = clk; 396 + } 397 + 398 + if (flags & AHCI_PLATFORM_GET_RESETS) { 399 + hpriv->rsts = devm_reset_control_array_get_optional_shared(dev); 400 + if (IS_ERR(hpriv->rsts)) { 401 + rc = PTR_ERR(hpriv->rsts); 402 + goto err_out; 403 + } 409 404 } 410 405 411 406 hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
+2
include/linux/ahci_platform.h
··· 43 43 int ahci_platform_suspend(struct device *dev); 44 44 int ahci_platform_resume(struct device *dev); 45 45 46 + #define AHCI_PLATFORM_GET_RESETS 0x01 47 + 46 48 #endif /* _AHCI_PLATFORM_H */