Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 198709
b: refs/heads/master
c: 8081c84
h: refs/heads/master
i:
  198707: 9e85833
v: v3
  • Loading branch information
Alek Du authored and Linus Torvalds committed May 27, 2010
1 parent d7cad29 commit 725e5c0
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 35 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 8156fae26aec0285840ffa6faff6cae017abe81b
refs/heads/master: 8081c84c9ce71ef73e591e19f1f7a516cb111e1c
4 changes: 2 additions & 2 deletions trunk/drivers/gpio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,10 @@ config GPIO_BT8XX
If unsure, say N.

config GPIO_LANGWELL
bool "Intel Moorestown Platform Langwell GPIO support"
bool "Intel Langwell/Penwell GPIO support"
depends on PCI
help
Say Y here to support Intel Moorestown platform GPIO.
Say Y here to support Intel Langwell/Penwell GPIO.

config GPIO_TIMBERDALE
bool "Support for timberdale GPIO IP"
Expand Down
83 changes: 51 additions & 32 deletions trunk/drivers/gpio/langwell_gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

/* Supports:
* Moorestown platform Langwell chip.
* Medfield platform Penwell chip.
*/

#include <linux/module.h>
Expand All @@ -31,57 +32,76 @@
#include <linux/gpio.h>
#include <linux/slab.h>

struct lnw_gpio_register {
u32 GPLR[2];
u32 GPDR[2];
u32 GPSR[2];
u32 GPCR[2];
u32 GRER[2];
u32 GFER[2];
u32 GEDR[2];
/*
* Langwell chip has 64 pins and thus there are 2 32bit registers to control
* each feature, while Penwell chip has 96 pins for each block, and need 3 32bit
* registers to control them, so we only define the order here instead of a
* structure, to get a bit offset for a pin (use GPDR as an example):
*
* nreg = ngpio / 32;
* reg = offset / 32;
* bit = offset % 32;
* reg_addr = reg_base + GPDR * nreg * 4 + reg * 4;
*
* so the bit of reg_addr is to control pin offset's GPDR feature
*/

enum GPIO_REG {
GPLR = 0, /* pin level read-only */
GPDR, /* pin direction */
GPSR, /* pin set */
GPCR, /* pin clear */
GRER, /* rising edge detect */
GFER, /* falling edge detect */
GEDR, /* edge detect result */
};

struct lnw_gpio {
struct gpio_chip chip;
struct lnw_gpio_register *reg_base;
void *reg_base;
spinlock_t lock;
unsigned irq_base;
};

static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
enum GPIO_REG reg_type)
{
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
unsigned nreg = chip->ngpio / 32;
u8 reg = offset / 32;
void __iomem *gplr;
void __iomem *ptr;

ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
return ptr;
}

static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
{
void __iomem *gplr = gpio_reg(chip, offset, GPLR);

gplr = (void __iomem *)(&lnw->reg_base->GPLR[reg]);
return readl(gplr) & BIT(offset % 32);
}

static void lnw_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
u8 reg = offset / 32;
void __iomem *gpsr, *gpcr;

if (value) {
gpsr = (void __iomem *)(&lnw->reg_base->GPSR[reg]);
gpsr = gpio_reg(chip, offset, GPSR);
writel(BIT(offset % 32), gpsr);
} else {
gpcr = (void __iomem *)(&lnw->reg_base->GPCR[reg]);
gpcr = gpio_reg(chip, offset, GPCR);
writel(BIT(offset % 32), gpcr);
}
}

static int lnw_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
u8 reg = offset / 32;
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
u32 value;
unsigned long flags;
void __iomem *gpdr;

gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
spin_lock_irqsave(&lnw->lock, flags);
value = readl(gpdr);
value &= ~BIT(offset % 32);
Expand All @@ -94,12 +114,10 @@ static int lnw_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
u8 reg = offset / 32;
void __iomem *gpdr = gpio_reg(chip, offset, GPDR);
unsigned long flags;
void __iomem *gpdr;

lnw_gpio_set(chip, offset, value);
gpdr = (void __iomem *)(&lnw->reg_base->GPDR[reg]);
spin_lock_irqsave(&lnw->lock, flags);
value = readl(gpdr);
value |= BIT(offset % 32);;
Expand All @@ -118,11 +136,10 @@ static int lnw_irq_type(unsigned irq, unsigned type)
{
struct lnw_gpio *lnw = get_irq_chip_data(irq);
u32 gpio = irq - lnw->irq_base;
u8 reg = gpio / 32;
unsigned long flags;
u32 value;
void __iomem *grer = (void __iomem *)(&lnw->reg_base->GRER[reg]);
void __iomem *gfer = (void __iomem *)(&lnw->reg_base->GFER[reg]);
void __iomem *grer = gpio_reg(&lnw->chip, gpio, GRER);
void __iomem *gfer = gpio_reg(&lnw->chip, gpio, GFER);

if (gpio >= lnw->chip.ngpio)
return -EINVAL;
Expand Down Expand Up @@ -158,26 +175,28 @@ static struct irq_chip lnw_irqchip = {
.set_type = lnw_irq_type,
};

static struct pci_device_id lnw_gpio_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f) },
static DEFINE_PCI_DEVICE_TABLE(lnw_gpio_ids) = { /* pin number */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), .driver_data = 64 },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), .driver_data = 96 },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), .driver_data = 96 },
{ 0, }
};
MODULE_DEVICE_TABLE(pci, lnw_gpio_ids);

static void lnw_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct lnw_gpio *lnw = (struct lnw_gpio *)get_irq_data(irq);
u32 reg, gpio;
u32 base, gpio;
void __iomem *gedr;
u32 gedr_v;

/* check GPIO controller to check which pin triggered the interrupt */
for (reg = 0; reg < lnw->chip.ngpio / 32; reg++) {
gedr = (void __iomem *)(&lnw->reg_base->GEDR[reg]);
for (base = 0; base < lnw->chip.ngpio; base += 32) {
gedr = gpio_reg(&lnw->chip, base, GEDR);
gedr_v = readl(gedr);
if (!gedr_v)
continue;
for (gpio = reg*32; gpio < reg*32+32; gpio++)
for (gpio = base; gpio < base + 32; gpio++)
if (gedr_v & BIT(gpio % 32)) {
pr_debug("pin %d triggered\n", gpio);
generic_handle_irq(lnw->irq_base + gpio);
Expand Down Expand Up @@ -245,7 +264,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
lnw->chip.set = lnw_gpio_set;
lnw->chip.to_irq = lnw_gpio_to_irq;
lnw->chip.base = gpio_base;
lnw->chip.ngpio = 64;
lnw->chip.ngpio = id->driver_data;
lnw->chip.can_sleep = 0;
pci_set_drvdata(pdev, lnw);
retval = gpiochip_add(&lnw->chip);
Expand Down

0 comments on commit 725e5c0

Please sign in to comment.