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 void mask_ack_giuint_low(struct irq_data *d) { unsigned int pin; pin = GPIO_PIN_OF_IRQ(d->irq); giu_clear(GIUINTENL, 1 << pin); giu_write(GIUINTSTATL, 1 << pin); }
static void mask_ack_giuint_low(unsigned int irq) { unsigned int pin; pin = GPIO_PIN_OF_IRQ(irq); giu_clear(GIUINTENL, 1 << pin); giu_write(GIUINTSTATL, 1 << pin); }
static void mask_ack_giuint_high(unsigned int irq) { unsigned int pin; pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; giu_clear(GIUINTENH, 1 << pin); giu_write(GIUINTSTATH, 1 << pin); }
static inline u16 giu_clear(u16 offset, u16 clear) { u16 data; data = giu_read(offset); data &= ~clear; 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 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 unsigned int startup_giuint_low_irq(unsigned int irq) { unsigned int pin; pin = GPIO_PIN_OF_IRQ(irq); giu_write(GIUINTSTATL, 1 << pin); giu_set(GIUINTENL, 1 << pin); return 0; }
static unsigned int startup_giuint_high_irq(unsigned int irq) { unsigned int pin; pin = GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET; giu_write(GIUINTSTATH, 1 << pin); giu_set(GIUINTENH, 1 << pin); return 0; }
static inline u16 giu_set(u16 offset, u16 set) { u16 data; data = giu_read(offset); data |= set; giu_write(offset, data); return data; }
void vr41xx_set_irq_level(unsigned int pin, irq_level_t level) { uint16_t mask; if (pin < GIUINT_HIGH_OFFSET) { mask = 1 << pin; if (level == IRQ_LEVEL_HIGH) giu_set(GIUINTALSELL, mask); else giu_clear(GIUINTALSELL, mask); giu_write(GIUINTSTATL, mask); } else if (pin < GIUINT_HIGH_MAX) { mask = 1 << (pin - GIUINT_HIGH_OFFSET); if (level == IRQ_LEVEL_HIGH) giu_set(GIUINTALSELH, mask); else giu_clear(GIUINTALSELH, mask); giu_write(GIUINTSTATH, mask); } }
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); }
void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) { uint16_t mask; if (pin < GIUINT_HIGH_OFFSET) { mask = 1 << pin; if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPL, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELL, mask); else giu_clear(GIUINTHTSELL, mask); if (current_cpu_data.cputype == CPU_VR4133) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHL, mask); giu_clear(GIUREDGEINHL, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; default: giu_set(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; } } } else { giu_clear(GIUINTTYPL, mask); giu_clear(GIUINTHTSELL, mask); } giu_write(GIUINTSTATL, mask); } else if (pin < GIUINT_HIGH_MAX) { mask = 1 << (pin - GIUINT_HIGH_OFFSET); if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPH, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELH, mask); else giu_clear(GIUINTHTSELH, mask); if (current_cpu_data.cputype == CPU_VR4133) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHH, mask); giu_clear(GIUREDGEINHH, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; default: giu_set(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; } } } else { giu_clear(GIUINTTYPH, mask); giu_clear(GIUINTHTSELH, mask); } giu_write(GIUINTSTATH, mask); } }
void vr41xx_set_irq_trigger(unsigned int pin, irq_trigger_t trigger, irq_signal_t signal) { uint16_t mask; if (pin < GIUINT_HIGH_OFFSET) { mask = 1 << pin; if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPL, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELL, mask); else giu_clear(GIUINTHTSELL, mask); if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHL, mask); giu_clear(GIUREDGEINHL, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; default: giu_set(GIUFEDGEINHL, mask); giu_set(GIUREDGEINHL, mask); break; } } set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPL, mask); giu_clear(GIUINTHTSELL, mask); set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_low_irq_chip, handle_level_irq); } giu_write(GIUINTSTATL, mask); } else if (pin < GIUINT_HIGH_MAX) { mask = 1 << (pin - GIUINT_HIGH_OFFSET); if (trigger != IRQ_TRIGGER_LEVEL) { giu_set(GIUINTTYPH, mask); if (signal == IRQ_SIGNAL_HOLD) giu_set(GIUINTHTSELH, mask); else giu_clear(GIUINTHTSELH, mask); if (giu_flags & GPIO_HAS_INTERRUPT_EDGE_SELECT) { switch (trigger) { case IRQ_TRIGGER_EDGE_FALLING: giu_set(GIUFEDGEINHH, mask); giu_clear(GIUREDGEINHH, mask); break; case IRQ_TRIGGER_EDGE_RISING: giu_clear(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; default: giu_set(GIUFEDGEINHH, mask); giu_set(GIUREDGEINHH, mask); break; } } set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_edge_irq); } else { giu_clear(GIUINTTYPH, mask); giu_clear(GIUINTHTSELH, mask); set_irq_chip_and_handler(GIU_IRQ(pin), &giuint_high_irq_chip, handle_level_irq); } giu_write(GIUINTSTATH, mask); } }
static int __devinit giu_probe(struct platform_device *dev) { unsigned long start, size, flags = 0; unsigned int nr_pins = 0; struct resource *res1, *res2 = NULL; void *base; int retval, i; switch (current_cpu_data.cputype) { case CPU_VR4111: case CPU_VR4121: start = GIU_TYPE1_START; size = GIU_TYPE1_SIZE; flags = GPIO_HAS_PULLUPDOWN_IO; nr_pins = 50; break; case CPU_VR4122: case CPU_VR4131: start = GIU_TYPE2_START; size = GIU_TYPE2_SIZE; nr_pins = 36; break; case CPU_VR4133: start = GIU_TYPE3_START; size = GIU_TYPE3_SIZE; flags = GPIO_HAS_INTERRUPT_EDGE_SELECT; nr_pins = 48; break; default: return -ENODEV; } res1 = request_mem_region(start, size, "GIU"); if (res1 == NULL) return -EBUSY; base = ioremap(start, size); if (base == NULL) { release_resource(res1); return -ENOMEM; } if (flags & GPIO_HAS_PULLUPDOWN_IO) { res2 = request_mem_region(GIU_PULLUPDOWN_START, GIU_PULLUPDOWN_SIZE, "GIU"); if (res2 == NULL) { iounmap(base); release_resource(res1); return -EBUSY; } } retval = register_chrdev(major, "GIU", &gpio_fops); if (retval < 0) { iounmap(base); release_resource(res1); release_resource(res2); return retval; } if (major == 0) { major = retval; printk(KERN_INFO "GIU: major number %d\n", major); } spin_lock_init(&giu_lock); giu_base = base; giu_resource1 = res1; giu_resource2 = res2; giu_flags = flags; giu_nr_pins = nr_pins; giu_write(GIUINTENL, 0); giu_write(GIUINTENH, 0); for (i = GIU_IRQ_BASE; i <= GIU_IRQ_LAST; i++) { if (i < GIU_IRQ(GIUINT_HIGH_OFFSET)) irq_desc[i].handler = &giuint_low_irq_type; else irq_desc[i].handler = &giuint_high_irq_type; } return cascade_irq(GIUINT_IRQ, giu_get_irq); }
static void ack_giuint_high(unsigned int irq) { giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(irq) - GIUINT_HIGH_OFFSET)); }
static void ack_giuint_low(struct irq_data *d) { giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(d->irq)); }
static void ack_giuint_low(unsigned int irq) { giu_write(GIUINTSTATL, 1 << GPIO_PIN_OF_IRQ(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); }
static void ack_giuint_high(struct irq_data *d) { giu_write(GIUINTSTATH, 1 << (GPIO_PIN_OF_IRQ(d->irq) - GIUINT_HIGH_OFFSET)); }