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

ahci: platform support for suspend/resume

Add platform hooks for custom suspend() and resume() functions. The
generic suspend/resume code in drivers/ata/ahci_platform.c is adapted
from the PCI version in drivers/ata/ahci.c.

Signed-off-by: Brian Norris <computersforpeace@gmail.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>

authored by

Brian Norris and committed by
Jeff Garzik
17ab594f 80a9c430

+70
+68
drivers/ata/ahci_platform.c
··· 202 202 return 0; 203 203 } 204 204 205 + #ifdef CONFIG_PM 206 + static int ahci_suspend(struct device *dev) 207 + { 208 + struct ahci_platform_data *pdata = dev_get_platdata(dev); 209 + struct ata_host *host = dev_get_drvdata(dev); 210 + struct ahci_host_priv *hpriv = host->private_data; 211 + void __iomem *mmio = hpriv->mmio; 212 + u32 ctl; 213 + int rc; 214 + 215 + if (hpriv->flags & AHCI_HFLAG_NO_SUSPEND) { 216 + dev_err(dev, "firmware update required for suspend/resume\n"); 217 + return -EIO; 218 + } 219 + 220 + /* 221 + * AHCI spec rev1.1 section 8.3.3: 222 + * Software must disable interrupts prior to requesting a 223 + * transition of the HBA to D3 state. 224 + */ 225 + ctl = readl(mmio + HOST_CTL); 226 + ctl &= ~HOST_IRQ_EN; 227 + writel(ctl, mmio + HOST_CTL); 228 + readl(mmio + HOST_CTL); /* flush */ 229 + 230 + rc = ata_host_suspend(host, PMSG_SUSPEND); 231 + if (rc) 232 + return rc; 233 + 234 + if (pdata && pdata->suspend) 235 + return pdata->suspend(dev); 236 + return 0; 237 + } 238 + 239 + static int ahci_resume(struct device *dev) 240 + { 241 + struct ahci_platform_data *pdata = dev_get_platdata(dev); 242 + struct ata_host *host = dev_get_drvdata(dev); 243 + int rc; 244 + 245 + if (pdata && pdata->resume) { 246 + rc = pdata->resume(dev); 247 + if (rc) 248 + return rc; 249 + } 250 + 251 + if (dev->power.power_state.event == PM_EVENT_SUSPEND) { 252 + rc = ahci_reset_controller(host); 253 + if (rc) 254 + return rc; 255 + 256 + ahci_init_controller(host); 257 + } 258 + 259 + ata_host_resume(host); 260 + 261 + return 0; 262 + } 263 + 264 + static struct dev_pm_ops ahci_pm_ops = { 265 + .suspend = &ahci_suspend, 266 + .resume = &ahci_resume, 267 + }; 268 + #endif 269 + 205 270 static const struct of_device_id ahci_of_match[] = { 206 271 { .compatible = "calxeda,hb-ahci", }, 207 272 {}, ··· 279 214 .name = "ahci", 280 215 .owner = THIS_MODULE, 281 216 .of_match_table = ahci_of_match, 217 + #ifdef CONFIG_PM 218 + .pm = &ahci_pm_ops, 219 + #endif 282 220 }, 283 221 .id_table = ahci_devtype, 284 222 };
+2
include/linux/ahci_platform.h
··· 23 23 struct ahci_platform_data { 24 24 int (*init)(struct device *dev, void __iomem *addr); 25 25 void (*exit)(struct device *dev); 26 + int (*suspend)(struct device *dev); 27 + int (*resume)(struct device *dev); 26 28 const struct ata_port_info *ata_port_info; 27 29 unsigned int force_port_map; 28 30 unsigned int mask_port_map;