static int giu_get_irq(unsigned int irq) { uint16_t pendl, pendh, maskl, maskh; int i; pendl = giu_read(GIUINTSTATL); pendh = giu_read(GIUINTSTATH); maskl = giu_read(GIUINTENL); maskh = giu_read(GIUINTENH); maskl &= pendl; maskh &= pendh; if (maskl) { for (i = 0; i < 16; i++) { if (maskl & (1 << i)) return GIU_IRQ(i); } } else if (maskh) { for (i = 0; i < 16; i++) { if (maskh & (1 << i)) return GIU_IRQ(i + GIUINT_HIGH_OFFSET); } } printk(KERN_ERR "spurious GIU interrupt: %04x(%04x),%04x(%04x)\n", maskl, pendl, maskh, pendh); atomic_inc(&irq_err_count); return -EINVAL; }
gpio_data_t vr41xx_gpio_get_pin(unsigned int pin) { uint16_t reg, mask; if (pin >= giu_nr_pins) return GPIO_DATA_INVAL; if (pin < 16) { reg = giu_read(GIUPIODL); mask = (uint16_t)1 << pin; } else if (pin < 32) { reg = giu_read(GIUPIODH); mask = (uint16_t)1 << (pin - 16); } else if (pin < 48) { reg = giu_read(GIUPODATL); mask = (uint16_t)1 << (pin - 32); } else { reg = giu_read(GIUPODATH); mask = (uint16_t)1 << (pin - 48); } if (reg & mask) return GPIO_DATA_HIGH; return GPIO_DATA_LOW; }
static int vr41xx_gpio_get(struct gpio_chip *chip, unsigned pin) { u16 reg, mask; if (pin >= chip->ngpio) return -EINVAL; if (pin < 16) { reg = giu_read(GIUPIODL); mask = 1 << pin; } else if (pin < 32) { reg = giu_read(GIUPIODH); mask = 1 << (pin - 16); } else if (pin < 48) { reg = giu_read(GIUPODATL); mask = 1 << (pin - 32); } else { reg = giu_read(GIUPODATH); mask = 1 << (pin - 48); } if (reg & mask) return 1; return 0; }
int vr41xx_gpio_set_pin(unsigned int pin, gpio_data_t data) { uint16_t offset, mask, reg; unsigned long flags; if (pin >= giu_nr_pins) return -EINVAL; if (pin < 16) { offset = GIUPIODL; mask = (uint16_t)1 << pin; } else if (pin < 32) { offset = GIUPIODH; mask = (uint16_t)1 << (pin - 16); } else if (pin < 48) { offset = GIUPODATL; mask = (uint16_t)1 << (pin - 32); } else { offset = GIUPODATH; mask = (uint16_t)1 << (pin - 48); } spin_lock_irqsave(&giu_lock, flags); reg = giu_read(offset); if (data == GPIO_DATA_HIGH) reg |= mask; else reg &= ~mask; giu_write(offset, reg); spin_unlock_irqrestore(&giu_lock, flags); return 0; }
static void vr41xx_gpio_set(struct gpio_chip *chip, unsigned pin, int value) { u16 offset, mask, reg; unsigned long flags; if (pin >= chip->ngpio) return; if (pin < 16) { offset = GIUPIODL; mask = 1 << pin; } else if (pin < 32) { offset = GIUPIODH; mask = 1 << (pin - 16); } else if (pin < 48) { offset = GIUPODATL; mask = 1 << (pin - 32); } else { offset = GIUPODATH; mask = 1 << (pin - 48); } spin_lock_irqsave(&giu_lock, flags); reg = giu_read(offset); if (value) reg |= mask; else reg &= ~mask; giu_write(offset, reg); spin_unlock_irqrestore(&giu_lock, flags); }
static inline uint16_t giu_set(uint16_t offset, uint16_t set) { uint16_t data; data = giu_read(offset); data |= set; giu_write(offset, data); return data; }
static inline uint16_t giu_clear(uint16_t offset, uint16_t clear) { uint16_t data; data = giu_read(offset); data &= ~clear; giu_write(offset, data); return data; }
static inline u16 giu_set(u16 offset, u16 set) { u16 data; data = giu_read(offset); data |= set; giu_write(offset, data); return data; }
static inline u16 giu_clear(u16 offset, u16 clear) { u16 data; data = giu_read(offset); data &= ~clear; giu_write(offset, data); return data; }
int vr41xx_gpio_pullupdown(unsigned int pin, gpio_pull_t pull) { uint16_t reg, mask; unsigned long flags; if ((giu_flags & GPIO_HAS_PULLUPDOWN_IO) != GPIO_HAS_PULLUPDOWN_IO) return -EPERM; if (pin >= 15) return -EINVAL; mask = (uint16_t)1 << pin; spin_lock_irqsave(&giu_lock, flags); if (pull == GPIO_PULL_UP || pull == GPIO_PULL_DOWN) { reg = giu_read(GIUTERMUPDN); if (pull == GPIO_PULL_UP) reg |= mask; else reg &= ~mask; giu_write(GIUTERMUPDN, reg); reg = giu_read(GIUUSEUPDN); reg |= mask; giu_write(GIUUSEUPDN, reg); } else { reg = giu_read(GIUUSEUPDN); reg &= ~mask; giu_write(GIUUSEUPDN, reg); } spin_unlock_irqrestore(&giu_lock, flags); return 0; }
int vr41xx_gpio_set_direction(unsigned int pin, gpio_direction_t dir) { uint16_t offset, mask, reg; unsigned long flags; if (pin >= giu_nr_pins) return -EINVAL; if (pin < 16) { offset = GIUIOSELL; mask = (uint16_t)1 << pin; } else if (pin < 32) { offset = GIUIOSELH; mask = (uint16_t)1 << (pin - 16); } else { if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { offset = GIUPODATEN; mask = (uint16_t)1 << (pin - 32); } else { switch (pin) { case 48: offset = GIUPODATH; mask = PIOEN0; break; case 49: offset = GIUPODATH; mask = PIOEN1; break; default: return -EINVAL; } } } spin_lock_irqsave(&giu_lock, flags); reg = giu_read(offset); if (dir == GPIO_OUTPUT) reg |= mask; else reg &= ~mask; giu_write(offset, reg); spin_unlock_irqrestore(&giu_lock, flags); return 0; }
static int giu_set_direction(struct gpio_chip *chip, unsigned pin, int dir) { u16 offset, mask, reg; unsigned long flags; if (pin >= chip->ngpio) return -EINVAL; if (pin < 16) { offset = GIUIOSELL; mask = 1 << pin; } else if (pin < 32) { offset = GIUIOSELH; mask = 1 << (pin - 16); } else { if (giu_flags & GPIO_HAS_OUTPUT_ENABLE) { offset = GIUPODATEN; mask = 1 << (pin - 32); } else { switch (pin) { case 48: offset = GIUPODATH; mask = PIOEN0; break; case 49: offset = GIUPODATH; mask = PIOEN1; break; default: return -EINVAL; } } } spin_lock_irqsave(&giu_lock, flags); reg = giu_read(offset); if (dir == GPIO_OUTPUT) reg |= mask; else reg &= ~mask; giu_write(offset, reg); spin_unlock_irqrestore(&giu_lock, flags); return 0; }
static int __devinit giu_probe(struct platform_device *dev) { struct resource *res; unsigned int trigger, i, pin; struct irq_chip *chip; int irq, retval; switch (dev->id) { case GPIO_50PINS_PULLUPDOWN: giu_flags = GPIO_HAS_PULLUPDOWN_IO; giu_nr_pins = 50; break; case GPIO_36PINS: giu_nr_pins = 36; break; case GPIO_48PINS_EDGE_SELECT: giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; giu_nr_pins = 48; break; default: printk(KERN_ERR "GIU: unknown ID %d\n", dev->id); return -ENODEV; } res = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!res) return -EBUSY; giu_base = ioremap(res->start, res->end - res->start + 1); if (!giu_base) return -ENOMEM; retval = register_chrdev(major, "GIU", &gpio_fops); if (retval < 0) { iounmap(giu_base); giu_base = NULL; return retval; } if (major == 0) { major = retval; printk(KERN_INFO "GIU: major number %d\n", major); } spin_lock_init(&giu_lock); giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); trigger = giu_read(GIUINTTYPH) << 16; trigger |= giu_read(GIUINTTYPL); for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { pin = GPIO_PIN_OF_IRQ(i); if (pin < GIUINT_HIGH_OFFSET) chip = &giuint_low_irq_chip; else chip = &giuint_high_irq_chip; if (trigger & (1 << pin)) set_irq_chip_and_handler(i, chip, handle_edge_irq); else set_irq_chip_and_handler(i, chip, handle_level_irq); } irq = platform_get_irq(dev, 0); if (irq < 0 || irq >= NR_IRQS) return -EBUSY; return cascade_irq(irq, giu_get_irq); }
static int giu_probe(struct platform_device *pdev) { struct resource *res; unsigned int trigger, i, pin; struct irq_chip *chip; int irq, ret; switch (pdev->id) { case GPIO_50PINS_PULLUPDOWN: giu_flags = GPIO_HAS_PULLUPDOWN_IO; vr41xx_gpio_chip.ngpio = 50; break; case GPIO_36PINS: vr41xx_gpio_chip.ngpio = 36; break; case GPIO_48PINS_EDGE_SELECT: giu_flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; vr41xx_gpio_chip.ngpio = 48; break; default: dev_err(&pdev->dev, "GIU: unknown ID %d\n", pdev->id); return -ENODEV; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) return -EBUSY; giu_base = ioremap(res->start, resource_size(res)); if (!giu_base) return -ENOMEM; vr41xx_gpio_chip.dev = &pdev->dev; ret = gpiochip_add(&vr41xx_gpio_chip); if (!ret) { iounmap(giu_base); return -ENODEV; } giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); trigger = giu_read(GIUINTTYPH) << 16; trigger |= giu_read(GIUINTTYPL); for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { pin = GPIO_PIN_OF_IRQ(i); if (pin < GIUINT_HIGH_OFFSET) chip = &giuint_low_irq_chip; else chip = &giuint_high_irq_chip; if (trigger & (1 << pin)) irq_set_chip_and_handler(i, chip, handle_edge_irq); else irq_set_chip_and_handler(i, chip, handle_level_irq); } irq = platform_get_irq(pdev, 0); if (irq < 0 || irq >= nr_irqs) return -EBUSY; return cascade_irq(irq, giu_get_irq); }