Skip to content

Commit

Permalink
langwell_gpio: add runtime pm support
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Kristen Carlson Accardi authored and Grant Likely committed May 26, 2011
1 parent 33226ff commit 7812803
Showing 1 changed file with 65 additions and 0 deletions.
65 changes: 65 additions & 0 deletions drivers/gpio/langwell_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>

/*
* Langwell chip has 64 pins and thus there are 2 32bit registers to control
Expand Down Expand Up @@ -63,6 +64,7 @@ struct lnw_gpio {
void *reg_base;
spinlock_t lock;
unsigned irq_base;
struct pci_dev *pdev;
};

static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
Expand Down Expand Up @@ -104,11 +106,18 @@ static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
u32 value;
unsigned long flags;

if (lnw->pdev)
pm_runtime_get(&lnw->pdev->dev);

spin_lock_irqsave(&lnw->lock, flags);
value = readl(gpdr);
value &= ~BIT(offset % 32);
writel(value, gpdr);
spin_unlock_irqrestore(&lnw->lock, flags);

if (lnw->pdev)
pm_runtime_put(&lnw->pdev->dev);

return 0;
}

Expand All @@ -120,11 +129,19 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
unsigned long flags;

lnw_gpio_set(chip, offset, value);

if (lnw->pdev)
pm_runtime_get(&lnw->pdev->dev);

spin_lock_irqsave(&lnw->lock, flags);
value = readl(gpdr);
value |= BIT(offset % 32);
writel(value, gpdr);
spin_unlock_irqrestore(&lnw->lock, flags);

if (lnw->pdev)
pm_runtime_put(&lnw->pdev->dev);

return 0;
}

Expand All @@ -145,6 +162,10 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)

if (gpio >= lnw->chip.ngpio)
return -EINVAL;

if (lnw->pdev)
pm_runtime_get(&lnw->pdev->dev);

spin_lock_irqsave(&lnw->lock, flags);
if (type & IRQ_TYPE_EDGE_RISING)
value = readl(grer) | BIT(gpio % 32);
Expand All @@ -159,6 +180,9 @@ static int lnw_irq_type(struct irq_data *d, unsigned type)
writel(value, gfer);
spin_unlock_irqrestore(&lnw->lock, flags);

if (lnw->pdev)
pm_runtime_put(&lnw->pdev->dev);

return 0;
}

Expand Down Expand Up @@ -211,6 +235,39 @@ static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
chip->irq_eoi(data);
}

#ifdef CONFIG_PM
static int lnw_gpio_runtime_resume(struct device *dev)
{
return 0;
}

static int lnw_gpio_runtime_suspend(struct device *dev)
{
return 0;
}

static int lnw_gpio_runtime_idle(struct device *dev)
{
int err = pm_schedule_suspend(dev, 500);

if (!err)
return 0;

return -EBUSY;
}

#else
#define lnw_gpio_runtime_suspend NULL
#define lnw_gpio_runtime_resume NULL
#define lnw_gpio_runtime_idle NULL
#endif

static const struct dev_pm_ops lnw_gpio_pm_ops = {
.runtime_suspend = lnw_gpio_runtime_suspend,
.runtime_resume = lnw_gpio_runtime_resume,
.runtime_idle = lnw_gpio_runtime_idle,
};

static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
Expand Down Expand Up @@ -270,6 +327,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.base = gpio_base;
lnw->chip.ngpio = id->driver_data;
lnw->chip.can_sleep = 0;
lnw->pdev = pdev;
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
if (retval) {
Expand All @@ -285,6 +343,10 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
}

spin_lock_init(&lnw->lock);

pm_runtime_put_noidle(&pdev->dev);
pm_runtime_allow(&pdev->dev);

goto done;
err5:
kfree(lnw);
Expand All @@ -302,6 +364,9 @@ static struct pci_driver lnw_gpio_driver = {
.name = "langwell_gpio",
.id_table = lnw_gpio_ids,
.probe = lnw_gpio_probe,
.driver = {
.pm = &lnw_gpio_pm_ops,
},
};


Expand Down

0 comments on commit 7812803

Please sign in to comment.