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

ata: move library code from ahci_platform.c to libahci_platform.c

Move AHCI platform library code from ahci_platform.c to
libahci_platform.c and fix dependencies for ahci_st,
ahci_imx and ahci_sunxi drivers.

Acked-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
Signed-off-by: Tejun Heo <tj@kernel.org>

authored by

Bartlomiej Zolnierkiewicz and committed by
Tejun Heo
fd990556 83b03fd6

+549 -524
+3 -4
drivers/ata/Kconfig
··· 99 99 100 100 config AHCI_ST 101 101 tristate "ST AHCI SATA support" 102 - depends on SATA_AHCI_PLATFORM 103 102 depends on ARCH_STI 104 103 help 105 104 This option enables support for ST AHCI SATA controller. ··· 107 108 108 109 config AHCI_IMX 109 110 tristate "Freescale i.MX AHCI SATA support" 110 - depends on SATA_AHCI_PLATFORM && MFD_SYSCON 111 + depends on MFD_SYSCON 111 112 help 112 113 This option enables support for the Freescale i.MX SoC's 113 114 onboard AHCI SATA. ··· 116 117 117 118 config AHCI_SUNXI 118 119 tristate "Allwinner sunxi AHCI SATA support" 119 - depends on ARCH_SUNXI && SATA_AHCI_PLATFORM 120 + depends on ARCH_SUNXI 120 121 help 121 122 This option enables support for the Allwinner sunxi SoC's 122 123 onboard AHCI SATA. ··· 125 126 126 127 config AHCI_XGENE 127 128 tristate "APM X-Gene 6.0Gbps AHCI SATA host controller support" 128 - depends on SATA_AHCI_PLATFORM && (ARM64 || COMPILE_TEST) 129 + depends on ARM64 || COMPILE_TEST 129 130 select PHY_XGENE 130 131 help 131 132 This option enables support for APM X-Gene SoC SATA host controller.
+5 -5
drivers/ata/Makefile
··· 4 4 # non-SFF interface 5 5 obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o 6 6 obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o 7 - obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o 7 + obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o 8 8 obj-$(CONFIG_SATA_FSL) += sata_fsl.o 9 9 obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o 10 10 obj-$(CONFIG_SATA_SIL24) += sata_sil24.o 11 11 obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o 12 12 obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o 13 - obj-$(CONFIG_AHCI_IMX) += ahci_imx.o 14 - obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o 15 - obj-$(CONFIG_AHCI_ST) += ahci_st.o 16 - obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o 13 + obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o 14 + obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o 15 + obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o 16 + obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o 17 17 18 18 # SFF w/ custom DMA 19 19 obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
-515
drivers/ata/ahci_platform.c
··· 12 12 * any later version. 13 13 */ 14 14 15 - #include <linux/clk.h> 16 15 #include <linux/kernel.h> 17 - #include <linux/gfp.h> 18 16 #include <linux/module.h> 19 17 #include <linux/pm.h> 20 - #include <linux/interrupt.h> 21 18 #include <linux/device.h> 22 19 #include <linux/platform_device.h> 23 20 #include <linux/libata.h> 24 21 #include <linux/ahci_platform.h> 25 - #include <linux/phy/phy.h> 26 - #include <linux/pm_runtime.h> 27 22 #include "ahci.h" 28 - 29 - static void ahci_host_stop(struct ata_host *host); 30 - 31 - struct ata_port_operations ahci_platform_ops = { 32 - .inherits = &ahci_ops, 33 - .host_stop = ahci_host_stop, 34 - }; 35 - EXPORT_SYMBOL_GPL(ahci_platform_ops); 36 23 37 24 static const struct ata_port_info ahci_port_info = { 38 25 .flags = AHCI_FLAG_COMMON, ··· 27 40 .udma_mask = ATA_UDMA6, 28 41 .port_ops = &ahci_platform_ops, 29 42 }; 30 - 31 - static struct scsi_host_template ahci_platform_sht = { 32 - AHCI_SHT("ahci_platform"), 33 - }; 34 - 35 - /** 36 - * ahci_platform_enable_clks - Enable platform clocks 37 - * @hpriv: host private area to store config values 38 - * 39 - * This function enables all the clks found in hpriv->clks, starting at 40 - * index 0. If any clk fails to enable it disables all the clks already 41 - * enabled in reverse order, and then returns an error. 42 - * 43 - * RETURNS: 44 - * 0 on success otherwise a negative error code 45 - */ 46 - int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) 47 - { 48 - int c, rc; 49 - 50 - for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) { 51 - rc = clk_prepare_enable(hpriv->clks[c]); 52 - if (rc) 53 - goto disable_unprepare_clk; 54 - } 55 - return 0; 56 - 57 - disable_unprepare_clk: 58 - while (--c >= 0) 59 - clk_disable_unprepare(hpriv->clks[c]); 60 - return rc; 61 - } 62 - EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); 63 - 64 - /** 65 - * ahci_platform_disable_clks - Disable platform clocks 66 - * @hpriv: host private area to store config values 67 - * 68 - * This function disables all the clks found in hpriv->clks, in reverse 69 - * order of ahci_platform_enable_clks (starting at the end of the array). 70 - */ 71 - void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) 72 - { 73 - int c; 74 - 75 - for (c = AHCI_MAX_CLKS - 1; c >= 0; c--) 76 - if (hpriv->clks[c]) 77 - clk_disable_unprepare(hpriv->clks[c]); 78 - } 79 - EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); 80 - 81 - /** 82 - * ahci_platform_enable_resources - Enable platform resources 83 - * @hpriv: host private area to store config values 84 - * 85 - * This function enables all ahci_platform managed resources in the 86 - * following order: 87 - * 1) Regulator 88 - * 2) Clocks (through ahci_platform_enable_clks) 89 - * 3) Phy 90 - * 91 - * If resource enabling fails at any point the previous enabled resources 92 - * are disabled in reverse order. 93 - * 94 - * RETURNS: 95 - * 0 on success otherwise a negative error code 96 - */ 97 - int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) 98 - { 99 - int rc; 100 - 101 - if (hpriv->target_pwr) { 102 - rc = regulator_enable(hpriv->target_pwr); 103 - if (rc) 104 - return rc; 105 - } 106 - 107 - rc = ahci_platform_enable_clks(hpriv); 108 - if (rc) 109 - goto disable_regulator; 110 - 111 - if (hpriv->phy) { 112 - rc = phy_init(hpriv->phy); 113 - if (rc) 114 - goto disable_clks; 115 - 116 - rc = phy_power_on(hpriv->phy); 117 - if (rc) { 118 - phy_exit(hpriv->phy); 119 - goto disable_clks; 120 - } 121 - } 122 - 123 - return 0; 124 - 125 - disable_clks: 126 - ahci_platform_disable_clks(hpriv); 127 - 128 - disable_regulator: 129 - if (hpriv->target_pwr) 130 - regulator_disable(hpriv->target_pwr); 131 - return rc; 132 - } 133 - EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); 134 - 135 - /** 136 - * ahci_platform_disable_resources - Disable platform resources 137 - * @hpriv: host private area to store config values 138 - * 139 - * This function disables all ahci_platform managed resources in the 140 - * following order: 141 - * 1) Phy 142 - * 2) Clocks (through ahci_platform_disable_clks) 143 - * 3) Regulator 144 - */ 145 - void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) 146 - { 147 - if (hpriv->phy) { 148 - phy_power_off(hpriv->phy); 149 - phy_exit(hpriv->phy); 150 - } 151 - 152 - ahci_platform_disable_clks(hpriv); 153 - 154 - if (hpriv->target_pwr) 155 - regulator_disable(hpriv->target_pwr); 156 - } 157 - EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); 158 - 159 - static void ahci_platform_put_resources(struct device *dev, void *res) 160 - { 161 - struct ahci_host_priv *hpriv = res; 162 - int c; 163 - 164 - if (hpriv->got_runtime_pm) { 165 - pm_runtime_put_sync(dev); 166 - pm_runtime_disable(dev); 167 - } 168 - 169 - for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) 170 - clk_put(hpriv->clks[c]); 171 - } 172 - 173 - /** 174 - * ahci_platform_get_resources - Get platform resources 175 - * @pdev: platform device to get resources for 176 - * 177 - * This function allocates an ahci_host_priv struct, and gets the following 178 - * resources, storing a reference to them inside the returned struct: 179 - * 180 - * 1) mmio registers (IORESOURCE_MEM 0, mandatory) 181 - * 2) regulator for controlling the targets power (optional) 182 - * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, 183 - * or for non devicetree enabled platforms a single clock 184 - * 4) phy (optional) 185 - * 186 - * RETURNS: 187 - * The allocated ahci_host_priv on success, otherwise an ERR_PTR value 188 - */ 189 - struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) 190 - { 191 - struct device *dev = &pdev->dev; 192 - struct ahci_host_priv *hpriv; 193 - struct clk *clk; 194 - int i, rc = -ENOMEM; 195 - 196 - if (!devres_open_group(dev, NULL, GFP_KERNEL)) 197 - return ERR_PTR(-ENOMEM); 198 - 199 - hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), 200 - GFP_KERNEL); 201 - if (!hpriv) 202 - goto err_out; 203 - 204 - devres_add(dev, hpriv); 205 - 206 - hpriv->mmio = devm_ioremap_resource(dev, 207 - platform_get_resource(pdev, IORESOURCE_MEM, 0)); 208 - if (IS_ERR(hpriv->mmio)) { 209 - dev_err(dev, "no mmio space\n"); 210 - rc = PTR_ERR(hpriv->mmio); 211 - goto err_out; 212 - } 213 - 214 - hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); 215 - if (IS_ERR(hpriv->target_pwr)) { 216 - rc = PTR_ERR(hpriv->target_pwr); 217 - if (rc == -EPROBE_DEFER) 218 - goto err_out; 219 - hpriv->target_pwr = NULL; 220 - } 221 - 222 - for (i = 0; i < AHCI_MAX_CLKS; i++) { 223 - /* 224 - * For now we must use clk_get(dev, NULL) for the first clock, 225 - * because some platforms (da850, spear13xx) are not yet 226 - * converted to use devicetree for clocks. For new platforms 227 - * this is equivalent to of_clk_get(dev->of_node, 0). 228 - */ 229 - if (i == 0) 230 - clk = clk_get(dev, NULL); 231 - else 232 - clk = of_clk_get(dev->of_node, i); 233 - 234 - if (IS_ERR(clk)) { 235 - rc = PTR_ERR(clk); 236 - if (rc == -EPROBE_DEFER) 237 - goto err_out; 238 - break; 239 - } 240 - hpriv->clks[i] = clk; 241 - } 242 - 243 - hpriv->phy = devm_phy_get(dev, "sata-phy"); 244 - if (IS_ERR(hpriv->phy)) { 245 - rc = PTR_ERR(hpriv->phy); 246 - switch (rc) { 247 - case -ENODEV: 248 - case -ENOSYS: 249 - /* continue normally */ 250 - hpriv->phy = NULL; 251 - break; 252 - 253 - case -EPROBE_DEFER: 254 - goto err_out; 255 - 256 - default: 257 - dev_err(dev, "couldn't get sata-phy\n"); 258 - goto err_out; 259 - } 260 - } 261 - 262 - pm_runtime_enable(dev); 263 - pm_runtime_get_sync(dev); 264 - hpriv->got_runtime_pm = true; 265 - 266 - devres_remove_group(dev, NULL); 267 - return hpriv; 268 - 269 - err_out: 270 - devres_release_group(dev, NULL); 271 - return ERR_PTR(rc); 272 - } 273 - EXPORT_SYMBOL_GPL(ahci_platform_get_resources); 274 - 275 - /** 276 - * ahci_platform_init_host - Bring up an ahci-platform host 277 - * @pdev: platform device pointer for the host 278 - * @hpriv: ahci-host private data for the host 279 - * @pi_template: template for the ata_port_info to use 280 - * @force_port_map: param passed to ahci_save_initial_config 281 - * @mask_port_map: param passed to ahci_save_initial_config 282 - * 283 - * This function does all the usual steps needed to bring up an 284 - * ahci-platform host, note any necessary resources (ie clks, phy, etc.) 285 - * must be initialized / enabled before calling this. 286 - * 287 - * RETURNS: 288 - * 0 on success otherwise a negative error code 289 - */ 290 - int ahci_platform_init_host(struct platform_device *pdev, 291 - struct ahci_host_priv *hpriv, 292 - const struct ata_port_info *pi_template, 293 - unsigned int force_port_map, 294 - unsigned int mask_port_map) 295 - { 296 - struct device *dev = &pdev->dev; 297 - struct ata_port_info pi = *pi_template; 298 - const struct ata_port_info *ppi[] = { &pi, NULL }; 299 - struct ata_host *host; 300 - int i, irq, n_ports, rc; 301 - 302 - irq = platform_get_irq(pdev, 0); 303 - if (irq <= 0) { 304 - dev_err(dev, "no irq\n"); 305 - return -EINVAL; 306 - } 307 - 308 - /* prepare host */ 309 - hpriv->flags |= (unsigned long)pi.private_data; 310 - 311 - ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); 312 - 313 - if (hpriv->cap & HOST_CAP_NCQ) 314 - pi.flags |= ATA_FLAG_NCQ; 315 - 316 - if (hpriv->cap & HOST_CAP_PMP) 317 - pi.flags |= ATA_FLAG_PMP; 318 - 319 - ahci_set_em_messages(hpriv, &pi); 320 - 321 - /* CAP.NP sometimes indicate the index of the last enabled 322 - * port, at other times, that of the last possible port, so 323 - * determining the maximum port number requires looking at 324 - * both CAP.NP and port_map. 325 - */ 326 - n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 327 - 328 - host = ata_host_alloc_pinfo(dev, ppi, n_ports); 329 - if (!host) 330 - return -ENOMEM; 331 - 332 - host->private_data = hpriv; 333 - 334 - if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) 335 - host->flags |= ATA_HOST_PARALLEL_SCAN; 336 - else 337 - dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); 338 - 339 - if (pi.flags & ATA_FLAG_EM) 340 - ahci_reset_em(host); 341 - 342 - for (i = 0; i < host->n_ports; i++) { 343 - struct ata_port *ap = host->ports[i]; 344 - 345 - ata_port_desc(ap, "mmio %pR", 346 - platform_get_resource(pdev, IORESOURCE_MEM, 0)); 347 - ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); 348 - 349 - /* set enclosure management message type */ 350 - if (ap->flags & ATA_FLAG_EM) 351 - ap->em_message_type = hpriv->em_msg_type; 352 - 353 - /* disabled/not-implemented port */ 354 - if (!(hpriv->port_map & (1 << i))) 355 - ap->ops = &ata_dummy_port_ops; 356 - } 357 - 358 - rc = ahci_reset_controller(host); 359 - if (rc) 360 - return rc; 361 - 362 - ahci_init_controller(host); 363 - ahci_print_info(host, "platform"); 364 - 365 - return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, 366 - &ahci_platform_sht); 367 - } 368 - EXPORT_SYMBOL_GPL(ahci_platform_init_host); 369 43 370 44 static int ahci_probe(struct platform_device *pdev) 371 45 { ··· 67 419 ahci_platform_disable_resources(hpriv); 68 420 return rc; 69 421 } 70 - 71 - static void ahci_host_stop(struct ata_host *host) 72 - { 73 - struct device *dev = host->dev; 74 - struct ahci_platform_data *pdata = dev_get_platdata(dev); 75 - struct ahci_host_priv *hpriv = host->private_data; 76 - 77 - if (pdata && pdata->exit) 78 - pdata->exit(dev); 79 - 80 - ahci_platform_disable_resources(hpriv); 81 - } 82 - 83 - #ifdef CONFIG_PM_SLEEP 84 - /** 85 - * ahci_platform_suspend_host - Suspend an ahci-platform host 86 - * @dev: device pointer for the host 87 - * 88 - * This function does all the usual steps needed to suspend an 89 - * ahci-platform host, note any necessary resources (ie clks, phy, etc.) 90 - * must be disabled after calling this. 91 - * 92 - * RETURNS: 93 - * 0 on success otherwise a negative error code 94 - */ 95 - int ahci_platform_suspend_host(struct device *dev) 96 - { 97 - struct ata_host *host = dev_get_drvdata(dev); 98 - struct ahci_host_priv *hpriv = host->private_data; 99 - void __iomem *mmio = hpriv->mmio; 100 - u32 ctl; 101 - 102 - if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { 103 - dev_err(dev, "firmware update required for suspend/resume\n"); 104 - return -EIO; 105 - } 106 - 107 - /* 108 - * AHCI spec rev1.1 section 8.3.3: 109 - * Software must disable interrupts prior to requesting a 110 - * transition of the HBA to D3 state. 111 - */ 112 - ctl = readl(mmio + HOST_CTL); 113 - ctl &= ~HOST_IRQ_EN; 114 - writel(ctl, mmio + HOST_CTL); 115 - readl(mmio + HOST_CTL); /* flush */ 116 - 117 - return ata_host_suspend(host, PMSG_SUSPEND); 118 - } 119 - EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); 120 - 121 - /** 122 - * ahci_platform_resume_host - Resume an ahci-platform host 123 - * @dev: device pointer for the host 124 - * 125 - * This function does all the usual steps needed to resume an ahci-platform 126 - * host, note any necessary resources (ie clks, phy, etc.) must be 127 - * initialized / enabled before calling this. 128 - * 129 - * RETURNS: 130 - * 0 on success otherwise a negative error code 131 - */ 132 - int ahci_platform_resume_host(struct device *dev) 133 - { 134 - struct ata_host *host = dev_get_drvdata(dev); 135 - int rc; 136 - 137 - if (dev->power.power_state.event == PM_EVENT_SUSPEND) { 138 - rc = ahci_reset_controller(host); 139 - if (rc) 140 - return rc; 141 - 142 - ahci_init_controller(host); 143 - } 144 - 145 - ata_host_resume(host); 146 - 147 - return 0; 148 - } 149 - EXPORT_SYMBOL_GPL(ahci_platform_resume_host); 150 - 151 - /** 152 - * ahci_platform_suspend - Suspend an ahci-platform device 153 - * @dev: the platform device to suspend 154 - * 155 - * This function suspends the host associated with the device, followed by 156 - * disabling all the resources of the device. 157 - * 158 - * RETURNS: 159 - * 0 on success otherwise a negative error code 160 - */ 161 - int ahci_platform_suspend(struct device *dev) 162 - { 163 - struct ahci_platform_data *pdata = dev_get_platdata(dev); 164 - struct ata_host *host = dev_get_drvdata(dev); 165 - struct ahci_host_priv *hpriv = host->private_data; 166 - int rc; 167 - 168 - rc = ahci_platform_suspend_host(dev); 169 - if (rc) 170 - return rc; 171 - 172 - if (pdata && pdata->suspend) { 173 - rc = pdata->suspend(dev); 174 - if (rc) 175 - goto resume_host; 176 - } 177 - 178 - ahci_platform_disable_resources(hpriv); 179 - 180 - return 0; 181 - 182 - resume_host: 183 - ahci_platform_resume_host(dev); 184 - return rc; 185 - } 186 - EXPORT_SYMBOL_GPL(ahci_platform_suspend); 187 - 188 - /** 189 - * ahci_platform_resume - Resume an ahci-platform device 190 - * @dev: the platform device to resume 191 - * 192 - * This function enables all the resources of the device followed by 193 - * resuming the host associated with the device. 194 - * 195 - * RETURNS: 196 - * 0 on success otherwise a negative error code 197 - */ 198 - int ahci_platform_resume(struct device *dev) 199 - { 200 - struct ahci_platform_data *pdata = dev_get_platdata(dev); 201 - struct ata_host *host = dev_get_drvdata(dev); 202 - struct ahci_host_priv *hpriv = host->private_data; 203 - int rc; 204 - 205 - rc = ahci_platform_enable_resources(hpriv); 206 - if (rc) 207 - return rc; 208 - 209 - if (pdata && pdata->resume) { 210 - rc = pdata->resume(dev); 211 - if (rc) 212 - goto disable_resources; 213 - } 214 - 215 - rc = ahci_platform_resume_host(dev); 216 - if (rc) 217 - goto disable_resources; 218 - 219 - /* We resumed so update PM runtime state */ 220 - pm_runtime_disable(dev); 221 - pm_runtime_set_active(dev); 222 - pm_runtime_enable(dev); 223 - 224 - return 0; 225 - 226 - disable_resources: 227 - ahci_platform_disable_resources(hpriv); 228 - 229 - return rc; 230 - } 231 - EXPORT_SYMBOL_GPL(ahci_platform_resume); 232 - #endif 233 422 234 423 static SIMPLE_DEV_PM_OPS(ahci_pm_ops, ahci_platform_suspend, 235 424 ahci_platform_resume);
+541
drivers/ata/libahci_platform.c
··· 1 + /* 2 + * AHCI SATA platform library 3 + * 4 + * Copyright 2004-2005 Red Hat, Inc. 5 + * Jeff Garzik <jgarzik@pobox.com> 6 + * Copyright 2010 MontaVista Software, LLC. 7 + * Anton Vorontsov <avorontsov@ru.mvista.com> 8 + * 9 + * This program is free software; you can redistribute it and/or modify 10 + * it under the terms of the GNU General Public License as published by 11 + * the Free Software Foundation; either version 2, or (at your option) 12 + * any later version. 13 + */ 14 + 15 + #include <linux/clk.h> 16 + #include <linux/kernel.h> 17 + #include <linux/gfp.h> 18 + #include <linux/module.h> 19 + #include <linux/pm.h> 20 + #include <linux/interrupt.h> 21 + #include <linux/device.h> 22 + #include <linux/platform_device.h> 23 + #include <linux/libata.h> 24 + #include <linux/ahci_platform.h> 25 + #include <linux/phy/phy.h> 26 + #include <linux/pm_runtime.h> 27 + #include "ahci.h" 28 + 29 + static void ahci_host_stop(struct ata_host *host); 30 + 31 + struct ata_port_operations ahci_platform_ops = { 32 + .inherits = &ahci_ops, 33 + .host_stop = ahci_host_stop, 34 + }; 35 + EXPORT_SYMBOL_GPL(ahci_platform_ops); 36 + 37 + static struct scsi_host_template ahci_platform_sht = { 38 + AHCI_SHT("ahci_platform"), 39 + }; 40 + 41 + /** 42 + * ahci_platform_enable_clks - Enable platform clocks 43 + * @hpriv: host private area to store config values 44 + * 45 + * This function enables all the clks found in hpriv->clks, starting at 46 + * index 0. If any clk fails to enable it disables all the clks already 47 + * enabled in reverse order, and then returns an error. 48 + * 49 + * RETURNS: 50 + * 0 on success otherwise a negative error code 51 + */ 52 + int ahci_platform_enable_clks(struct ahci_host_priv *hpriv) 53 + { 54 + int c, rc; 55 + 56 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) { 57 + rc = clk_prepare_enable(hpriv->clks[c]); 58 + if (rc) 59 + goto disable_unprepare_clk; 60 + } 61 + return 0; 62 + 63 + disable_unprepare_clk: 64 + while (--c >= 0) 65 + clk_disable_unprepare(hpriv->clks[c]); 66 + return rc; 67 + } 68 + EXPORT_SYMBOL_GPL(ahci_platform_enable_clks); 69 + 70 + /** 71 + * ahci_platform_disable_clks - Disable platform clocks 72 + * @hpriv: host private area to store config values 73 + * 74 + * This function disables all the clks found in hpriv->clks, in reverse 75 + * order of ahci_platform_enable_clks (starting at the end of the array). 76 + */ 77 + void ahci_platform_disable_clks(struct ahci_host_priv *hpriv) 78 + { 79 + int c; 80 + 81 + for (c = AHCI_MAX_CLKS - 1; c >= 0; c--) 82 + if (hpriv->clks[c]) 83 + clk_disable_unprepare(hpriv->clks[c]); 84 + } 85 + EXPORT_SYMBOL_GPL(ahci_platform_disable_clks); 86 + 87 + /** 88 + * ahci_platform_enable_resources - Enable platform resources 89 + * @hpriv: host private area to store config values 90 + * 91 + * This function enables all ahci_platform managed resources in the 92 + * following order: 93 + * 1) Regulator 94 + * 2) Clocks (through ahci_platform_enable_clks) 95 + * 3) Phy 96 + * 97 + * If resource enabling fails at any point the previous enabled resources 98 + * are disabled in reverse order. 99 + * 100 + * RETURNS: 101 + * 0 on success otherwise a negative error code 102 + */ 103 + int ahci_platform_enable_resources(struct ahci_host_priv *hpriv) 104 + { 105 + int rc; 106 + 107 + if (hpriv->target_pwr) { 108 + rc = regulator_enable(hpriv->target_pwr); 109 + if (rc) 110 + return rc; 111 + } 112 + 113 + rc = ahci_platform_enable_clks(hpriv); 114 + if (rc) 115 + goto disable_regulator; 116 + 117 + if (hpriv->phy) { 118 + rc = phy_init(hpriv->phy); 119 + if (rc) 120 + goto disable_clks; 121 + 122 + rc = phy_power_on(hpriv->phy); 123 + if (rc) { 124 + phy_exit(hpriv->phy); 125 + goto disable_clks; 126 + } 127 + } 128 + 129 + return 0; 130 + 131 + disable_clks: 132 + ahci_platform_disable_clks(hpriv); 133 + 134 + disable_regulator: 135 + if (hpriv->target_pwr) 136 + regulator_disable(hpriv->target_pwr); 137 + return rc; 138 + } 139 + EXPORT_SYMBOL_GPL(ahci_platform_enable_resources); 140 + 141 + /** 142 + * ahci_platform_disable_resources - Disable platform resources 143 + * @hpriv: host private area to store config values 144 + * 145 + * This function disables all ahci_platform managed resources in the 146 + * following order: 147 + * 1) Phy 148 + * 2) Clocks (through ahci_platform_disable_clks) 149 + * 3) Regulator 150 + */ 151 + void ahci_platform_disable_resources(struct ahci_host_priv *hpriv) 152 + { 153 + if (hpriv->phy) { 154 + phy_power_off(hpriv->phy); 155 + phy_exit(hpriv->phy); 156 + } 157 + 158 + ahci_platform_disable_clks(hpriv); 159 + 160 + if (hpriv->target_pwr) 161 + regulator_disable(hpriv->target_pwr); 162 + } 163 + EXPORT_SYMBOL_GPL(ahci_platform_disable_resources); 164 + 165 + static void ahci_platform_put_resources(struct device *dev, void *res) 166 + { 167 + struct ahci_host_priv *hpriv = res; 168 + int c; 169 + 170 + if (hpriv->got_runtime_pm) { 171 + pm_runtime_put_sync(dev); 172 + pm_runtime_disable(dev); 173 + } 174 + 175 + for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++) 176 + clk_put(hpriv->clks[c]); 177 + } 178 + 179 + /** 180 + * ahci_platform_get_resources - Get platform resources 181 + * @pdev: platform device to get resources for 182 + * 183 + * This function allocates an ahci_host_priv struct, and gets the following 184 + * resources, storing a reference to them inside the returned struct: 185 + * 186 + * 1) mmio registers (IORESOURCE_MEM 0, mandatory) 187 + * 2) regulator for controlling the targets power (optional) 188 + * 3) 0 - AHCI_MAX_CLKS clocks, as specified in the devs devicetree node, 189 + * or for non devicetree enabled platforms a single clock 190 + * 4) phy (optional) 191 + * 192 + * RETURNS: 193 + * The allocated ahci_host_priv on success, otherwise an ERR_PTR value 194 + */ 195 + struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev) 196 + { 197 + struct device *dev = &pdev->dev; 198 + struct ahci_host_priv *hpriv; 199 + struct clk *clk; 200 + int i, rc = -ENOMEM; 201 + 202 + if (!devres_open_group(dev, NULL, GFP_KERNEL)) 203 + return ERR_PTR(-ENOMEM); 204 + 205 + hpriv = devres_alloc(ahci_platform_put_resources, sizeof(*hpriv), 206 + GFP_KERNEL); 207 + if (!hpriv) 208 + goto err_out; 209 + 210 + devres_add(dev, hpriv); 211 + 212 + hpriv->mmio = devm_ioremap_resource(dev, 213 + platform_get_resource(pdev, IORESOURCE_MEM, 0)); 214 + if (IS_ERR(hpriv->mmio)) { 215 + dev_err(dev, "no mmio space\n"); 216 + rc = PTR_ERR(hpriv->mmio); 217 + goto err_out; 218 + } 219 + 220 + hpriv->target_pwr = devm_regulator_get_optional(dev, "target"); 221 + if (IS_ERR(hpriv->target_pwr)) { 222 + rc = PTR_ERR(hpriv->target_pwr); 223 + if (rc == -EPROBE_DEFER) 224 + goto err_out; 225 + hpriv->target_pwr = NULL; 226 + } 227 + 228 + for (i = 0; i < AHCI_MAX_CLKS; i++) { 229 + /* 230 + * For now we must use clk_get(dev, NULL) for the first clock, 231 + * because some platforms (da850, spear13xx) are not yet 232 + * converted to use devicetree for clocks. For new platforms 233 + * this is equivalent to of_clk_get(dev->of_node, 0). 234 + */ 235 + if (i == 0) 236 + clk = clk_get(dev, NULL); 237 + else 238 + clk = of_clk_get(dev->of_node, i); 239 + 240 + if (IS_ERR(clk)) { 241 + rc = PTR_ERR(clk); 242 + if (rc == -EPROBE_DEFER) 243 + goto err_out; 244 + break; 245 + } 246 + hpriv->clks[i] = clk; 247 + } 248 + 249 + hpriv->phy = devm_phy_get(dev, "sata-phy"); 250 + if (IS_ERR(hpriv->phy)) { 251 + rc = PTR_ERR(hpriv->phy); 252 + switch (rc) { 253 + case -ENODEV: 254 + case -ENOSYS: 255 + /* continue normally */ 256 + hpriv->phy = NULL; 257 + break; 258 + 259 + case -EPROBE_DEFER: 260 + goto err_out; 261 + 262 + default: 263 + dev_err(dev, "couldn't get sata-phy\n"); 264 + goto err_out; 265 + } 266 + } 267 + 268 + pm_runtime_enable(dev); 269 + pm_runtime_get_sync(dev); 270 + hpriv->got_runtime_pm = true; 271 + 272 + devres_remove_group(dev, NULL); 273 + return hpriv; 274 + 275 + err_out: 276 + devres_release_group(dev, NULL); 277 + return ERR_PTR(rc); 278 + } 279 + EXPORT_SYMBOL_GPL(ahci_platform_get_resources); 280 + 281 + /** 282 + * ahci_platform_init_host - Bring up an ahci-platform host 283 + * @pdev: platform device pointer for the host 284 + * @hpriv: ahci-host private data for the host 285 + * @pi_template: template for the ata_port_info to use 286 + * @force_port_map: param passed to ahci_save_initial_config 287 + * @mask_port_map: param passed to ahci_save_initial_config 288 + * 289 + * This function does all the usual steps needed to bring up an 290 + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) 291 + * must be initialized / enabled before calling this. 292 + * 293 + * RETURNS: 294 + * 0 on success otherwise a negative error code 295 + */ 296 + int ahci_platform_init_host(struct platform_device *pdev, 297 + struct ahci_host_priv *hpriv, 298 + const struct ata_port_info *pi_template, 299 + unsigned int force_port_map, 300 + unsigned int mask_port_map) 301 + { 302 + struct device *dev = &pdev->dev; 303 + struct ata_port_info pi = *pi_template; 304 + const struct ata_port_info *ppi[] = { &pi, NULL }; 305 + struct ata_host *host; 306 + int i, irq, n_ports, rc; 307 + 308 + irq = platform_get_irq(pdev, 0); 309 + if (irq <= 0) { 310 + dev_err(dev, "no irq\n"); 311 + return -EINVAL; 312 + } 313 + 314 + /* prepare host */ 315 + hpriv->flags |= (unsigned long)pi.private_data; 316 + 317 + ahci_save_initial_config(dev, hpriv, force_port_map, mask_port_map); 318 + 319 + if (hpriv->cap & HOST_CAP_NCQ) 320 + pi.flags |= ATA_FLAG_NCQ; 321 + 322 + if (hpriv->cap & HOST_CAP_PMP) 323 + pi.flags |= ATA_FLAG_PMP; 324 + 325 + ahci_set_em_messages(hpriv, &pi); 326 + 327 + /* CAP.NP sometimes indicate the index of the last enabled 328 + * port, at other times, that of the last possible port, so 329 + * determining the maximum port number requires looking at 330 + * both CAP.NP and port_map. 331 + */ 332 + n_ports = max(ahci_nr_ports(hpriv->cap), fls(hpriv->port_map)); 333 + 334 + host = ata_host_alloc_pinfo(dev, ppi, n_ports); 335 + if (!host) 336 + return -ENOMEM; 337 + 338 + host->private_data = hpriv; 339 + 340 + if (!(hpriv->cap & HOST_CAP_SSS) || ahci_ignore_sss) 341 + host->flags |= ATA_HOST_PARALLEL_SCAN; 342 + else 343 + dev_info(dev, "SSS flag set, parallel bus scan disabled\n"); 344 + 345 + if (pi.flags & ATA_FLAG_EM) 346 + ahci_reset_em(host); 347 + 348 + for (i = 0; i < host->n_ports; i++) { 349 + struct ata_port *ap = host->ports[i]; 350 + 351 + ata_port_desc(ap, "mmio %pR", 352 + platform_get_resource(pdev, IORESOURCE_MEM, 0)); 353 + ata_port_desc(ap, "port 0x%x", 0x100 + ap->port_no * 0x80); 354 + 355 + /* set enclosure management message type */ 356 + if (ap->flags & ATA_FLAG_EM) 357 + ap->em_message_type = hpriv->em_msg_type; 358 + 359 + /* disabled/not-implemented port */ 360 + if (!(hpriv->port_map & (1 << i))) 361 + ap->ops = &ata_dummy_port_ops; 362 + } 363 + 364 + rc = ahci_reset_controller(host); 365 + if (rc) 366 + return rc; 367 + 368 + ahci_init_controller(host); 369 + ahci_print_info(host, "platform"); 370 + 371 + return ata_host_activate(host, irq, ahci_interrupt, IRQF_SHARED, 372 + &ahci_platform_sht); 373 + } 374 + EXPORT_SYMBOL_GPL(ahci_platform_init_host); 375 + 376 + static void ahci_host_stop(struct ata_host *host) 377 + { 378 + struct device *dev = host->dev; 379 + struct ahci_platform_data *pdata = dev_get_platdata(dev); 380 + struct ahci_host_priv *hpriv = host->private_data; 381 + 382 + if (pdata && pdata->exit) 383 + pdata->exit(dev); 384 + 385 + ahci_platform_disable_resources(hpriv); 386 + } 387 + 388 + #ifdef CONFIG_PM_SLEEP 389 + /** 390 + * ahci_platform_suspend_host - Suspend an ahci-platform host 391 + * @dev: device pointer for the host 392 + * 393 + * This function does all the usual steps needed to suspend an 394 + * ahci-platform host, note any necessary resources (ie clks, phy, etc.) 395 + * must be disabled after calling this. 396 + * 397 + * RETURNS: 398 + * 0 on success otherwise a negative error code 399 + */ 400 + int ahci_platform_suspend_host(struct device *dev) 401 + { 402 + struct ata_host *host = dev_get_drvdata(dev); 403 + struct ahci_host_priv *hpriv = host->private_data; 404 + void __iomem *mmio = hpriv->mmio; 405 + u32 ctl; 406 + 407 + if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { 408 + dev_err(dev, "firmware update required for suspend/resume\n"); 409 + return -EIO; 410 + } 411 + 412 + /* 413 + * AHCI spec rev1.1 section 8.3.3: 414 + * Software must disable interrupts prior to requesting a 415 + * transition of the HBA to D3 state. 416 + */ 417 + ctl = readl(mmio + HOST_CTL); 418 + ctl &= ~HOST_IRQ_EN; 419 + writel(ctl, mmio + HOST_CTL); 420 + readl(mmio + HOST_CTL); /* flush */ 421 + 422 + return ata_host_suspend(host, PMSG_SUSPEND); 423 + } 424 + EXPORT_SYMBOL_GPL(ahci_platform_suspend_host); 425 + 426 + /** 427 + * ahci_platform_resume_host - Resume an ahci-platform host 428 + * @dev: device pointer for the host 429 + * 430 + * This function does all the usual steps needed to resume an ahci-platform 431 + * host, note any necessary resources (ie clks, phy, etc.) must be 432 + * initialized / enabled before calling this. 433 + * 434 + * RETURNS: 435 + * 0 on success otherwise a negative error code 436 + */ 437 + int ahci_platform_resume_host(struct device *dev) 438 + { 439 + struct ata_host *host = dev_get_drvdata(dev); 440 + int rc; 441 + 442 + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { 443 + rc = ahci_reset_controller(host); 444 + if (rc) 445 + return rc; 446 + 447 + ahci_init_controller(host); 448 + } 449 + 450 + ata_host_resume(host); 451 + 452 + return 0; 453 + } 454 + EXPORT_SYMBOL_GPL(ahci_platform_resume_host); 455 + 456 + /** 457 + * ahci_platform_suspend - Suspend an ahci-platform device 458 + * @dev: the platform device to suspend 459 + * 460 + * This function suspends the host associated with the device, followed by 461 + * disabling all the resources of the device. 462 + * 463 + * RETURNS: 464 + * 0 on success otherwise a negative error code 465 + */ 466 + int ahci_platform_suspend(struct device *dev) 467 + { 468 + struct ahci_platform_data *pdata = dev_get_platdata(dev); 469 + struct ata_host *host = dev_get_drvdata(dev); 470 + struct ahci_host_priv *hpriv = host->private_data; 471 + int rc; 472 + 473 + rc = ahci_platform_suspend_host(dev); 474 + if (rc) 475 + return rc; 476 + 477 + if (pdata && pdata->suspend) { 478 + rc = pdata->suspend(dev); 479 + if (rc) 480 + goto resume_host; 481 + } 482 + 483 + ahci_platform_disable_resources(hpriv); 484 + 485 + return 0; 486 + 487 + resume_host: 488 + ahci_platform_resume_host(dev); 489 + return rc; 490 + } 491 + EXPORT_SYMBOL_GPL(ahci_platform_suspend); 492 + 493 + /** 494 + * ahci_platform_resume - Resume an ahci-platform device 495 + * @dev: the platform device to resume 496 + * 497 + * This function enables all the resources of the device followed by 498 + * resuming the host associated with the device. 499 + * 500 + * RETURNS: 501 + * 0 on success otherwise a negative error code 502 + */ 503 + int ahci_platform_resume(struct device *dev) 504 + { 505 + struct ahci_platform_data *pdata = dev_get_platdata(dev); 506 + struct ata_host *host = dev_get_drvdata(dev); 507 + struct ahci_host_priv *hpriv = host->private_data; 508 + int rc; 509 + 510 + rc = ahci_platform_enable_resources(hpriv); 511 + if (rc) 512 + return rc; 513 + 514 + if (pdata && pdata->resume) { 515 + rc = pdata->resume(dev); 516 + if (rc) 517 + goto disable_resources; 518 + } 519 + 520 + rc = ahci_platform_resume_host(dev); 521 + if (rc) 522 + goto disable_resources; 523 + 524 + /* We resumed so update PM runtime state */ 525 + pm_runtime_disable(dev); 526 + pm_runtime_set_active(dev); 527 + pm_runtime_enable(dev); 528 + 529 + return 0; 530 + 531 + disable_resources: 532 + ahci_platform_disable_resources(hpriv); 533 + 534 + return rc; 535 + } 536 + EXPORT_SYMBOL_GPL(ahci_platform_resume); 537 + #endif 538 + 539 + MODULE_DESCRIPTION("AHCI SATA platform library"); 540 + MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>"); 541 + MODULE_LICENSE("GPL");