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

langwell_gpio: add runtime pm support

While this is essentially a no-op for this driver, it has the
side effect of letting the PMU driver snoop D3 requests from
the PCI core for this driver.

This is only for langwell, not for whitney point.

Signed-off-by: Kristen Carlson Accardi <kristen@linux.intel.com>
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dirk Brandewie <dirk.brandewie@gmail.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>

authored by

Kristen Carlson Accardi and committed by
Grant Likely
7812803a 33226ffd

+65
+65
drivers/gpio/langwell_gpio.c
··· 33 33 #include <linux/io.h> 34 34 #include <linux/gpio.h> 35 35 #include <linux/slab.h> 36 + #include <linux/pm_runtime.h> 36 37 37 38 /* 38 39 * Langwell chip has 64 pins and thus there are 2 32bit registers to control ··· 64 63 void *reg_base; 65 64 spinlock_t lock; 66 65 unsigned irq_base; 66 + struct pci_dev *pdev; 67 67 }; 68 68 69 69 static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, ··· 106 104 u32 value; 107 105 unsigned long flags; 108 106 107 + if (lnw->pdev) 108 + pm_runtime_get(&lnw->pdev->dev); 109 + 109 110 spin_lock_irqsave(&lnw->lock, flags); 110 111 value = readl(gpdr); 111 112 value &= ~BIT(offset % 32); 112 113 writel(value, gpdr); 113 114 spin_unlock_irqrestore(&lnw->lock, flags); 115 + 116 + if (lnw->pdev) 117 + pm_runtime_put(&lnw->pdev->dev); 118 + 114 119 return 0; 115 120 } 116 121 ··· 129 120 unsigned long flags; 130 121 131 122 lnw_gpio_set(chip, offset, value); 123 + 124 + if (lnw->pdev) 125 + pm_runtime_get(&lnw->pdev->dev); 126 + 132 127 spin_lock_irqsave(&lnw->lock, flags); 133 128 value = readl(gpdr); 134 129 value |= BIT(offset % 32); 135 130 writel(value, gpdr); 136 131 spin_unlock_irqrestore(&lnw->lock, flags); 132 + 133 + if (lnw->pdev) 134 + pm_runtime_put(&lnw->pdev->dev); 135 + 137 136 return 0; 138 137 } 139 138 ··· 162 145 163 146 if (gpio >= lnw->chip.ngpio) 164 147 return -EINVAL; 148 + 149 + if (lnw->pdev) 150 + pm_runtime_get(&lnw->pdev->dev); 151 + 165 152 spin_lock_irqsave(&lnw->lock, flags); 166 153 if (type & IRQ_TYPE_EDGE_RISING) 167 154 value = readl(grer) | BIT(gpio % 32); ··· 179 158 value = readl(gfer) & (~BIT(gpio % 32)); 180 159 writel(value, gfer); 181 160 spin_unlock_irqrestore(&lnw->lock, flags); 161 + 162 + if (lnw->pdev) 163 + pm_runtime_put(&lnw->pdev->dev); 182 164 183 165 return 0; 184 166 } ··· 234 210 235 211 chip->irq_eoi(data); 236 212 } 213 + 214 + #ifdef CONFIG_PM 215 + static int lnw_gpio_runtime_resume(struct device *dev) 216 + { 217 + return 0; 218 + } 219 + 220 + static int lnw_gpio_runtime_suspend(struct device *dev) 221 + { 222 + return 0; 223 + } 224 + 225 + static int lnw_gpio_runtime_idle(struct device *dev) 226 + { 227 + int err = pm_schedule_suspend(dev, 500); 228 + 229 + if (!err) 230 + return 0; 231 + 232 + return -EBUSY; 233 + } 234 + 235 + #else 236 + #define lnw_gpio_runtime_suspend NULL 237 + #define lnw_gpio_runtime_resume NULL 238 + #define lnw_gpio_runtime_idle NULL 239 + #endif 240 + 241 + static const struct dev_pm_ops lnw_gpio_pm_ops = { 242 + .runtime_suspend = lnw_gpio_runtime_suspend, 243 + .runtime_resume = lnw_gpio_runtime_resume, 244 + .runtime_idle = lnw_gpio_runtime_idle, 245 + }; 237 246 238 247 static int __devinit lnw_gpio_probe(struct pci_dev *pdev, 239 248 const struct pci_device_id *id) ··· 327 270 lnw->chip.base = gpio_base; 328 271 lnw->chip.ngpio = id->driver_data; 329 272 lnw->chip.can_sleep = 0; 273 + lnw->pdev = pdev; 330 274 pci_set_drvdata(pdev, lnw); 331 275 retval = gpiochip_add(&lnw->chip); 332 276 if (retval) { ··· 343 285 } 344 286 345 287 spin_lock_init(&lnw->lock); 288 + 289 + pm_runtime_put_noidle(&pdev->dev); 290 + pm_runtime_allow(&pdev->dev); 291 + 346 292 goto done; 347 293 err5: 348 294 kfree(lnw); ··· 364 302 .name = "langwell_gpio", 365 303 .id_table = lnw_gpio_ids, 366 304 .probe = lnw_gpio_probe, 305 + .driver = { 306 + .pm = &lnw_gpio_pm_ops, 307 + }, 367 308 }; 368 309 369 310