/** * xgpiops_set_irq_type - Set the irq type for a gpio pin * @irq_data: irq data containing irq number of gpio pin * @type: interrupt type that is to be set for the gpio pin * * This function gets the gpio pin number and its bank from the gpio pin number * and configures the INT_TYPE, INT_POLARITY and INT_ANY registers. Returns 0, * negative error otherwise. * TYPE-EDGE_RISING, INT_TYPE - 1, INT_POLARITY - 1, INT_ANY - 0; * TYPE-EDGE_FALLING, INT_TYPE - 1, INT_POLARITY - 0, INT_ANY - 0; * TYPE-EDGE_BOTH, INT_TYPE - 1, INT_POLARITY - NA, INT_ANY - 1; * TYPE-LEVEL_HIGH, INT_TYPE - 0, INT_POLARITY - 1, INT_ANY - NA; * TYPE-LEVEL_LOW, INT_TYPE - 0, INT_POLARITY - 0, INT_ANY - NA */ static int xgpiops_set_irq_type(struct irq_data *irq_data, unsigned int type) { struct xgpiops *gpio = irq_data_get_irq_chip_data(irq_data); unsigned int device_pin_num, bank_num, bank_pin_num; unsigned int int_type, int_pol, int_any; device_pin_num = irq_data->hwirq; xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); int_type = xgpiops_readreg(gpio->base_addr + XGPIOPS_INTTYPE_OFFSET(bank_num)); int_pol = xgpiops_readreg(gpio->base_addr + XGPIOPS_INTPOL_OFFSET(bank_num)); int_any = xgpiops_readreg(gpio->base_addr + XGPIOPS_INTANY_OFFSET(bank_num)); /* * based on the type requested, configure the INT_TYPE, INT_POLARITY * and INT_ANY registers */ switch (type) { case IRQ_TYPE_EDGE_RISING: int_type |= (1 << bank_pin_num); int_pol |= (1 << bank_pin_num); int_any &= ~(1 << bank_pin_num); break; case IRQ_TYPE_EDGE_FALLING: int_type |= (1 << bank_pin_num); int_pol &= ~(1 << bank_pin_num); int_any &= ~(1 << bank_pin_num); break; case IRQ_TYPE_EDGE_BOTH: int_type |= (1 << bank_pin_num); int_any |= (1 << bank_pin_num); break; case IRQ_TYPE_LEVEL_HIGH: int_type &= ~(1 << bank_pin_num); int_pol |= (1 << bank_pin_num); break; case IRQ_TYPE_LEVEL_LOW: int_type &= ~(1 << bank_pin_num); int_pol &= ~(1 << bank_pin_num); break; default: return -EINVAL; } xgpiops_writereg(int_type, gpio->base_addr + XGPIOPS_INTTYPE_OFFSET(bank_num)); xgpiops_writereg(int_pol, gpio->base_addr + XGPIOPS_INTPOL_OFFSET(bank_num)); xgpiops_writereg(int_any, gpio->base_addr + XGPIOPS_INTANY_OFFSET(bank_num)); return 0; }
/** * xgpiops_dir_out - Set the direction of the specified GPIO pin as output * @chip: gpio_chip instance to be worked on * @pin: gpio pin number within the device * @state: value to be written to specified pin * * This function sets the direction of specified GPIO pin as output, configures * the Output Enable register for the pin and uses xgpiops_set to set the state * of the pin to the value specified. Returns 0 always. */ static int xgpiops_dir_out(struct gpio_chip *chip, unsigned int pin, int state) { struct xgpiops *gpio = container_of(chip, struct xgpiops, chip); unsigned int reg, bank_num, bank_pin_num; xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num); /* set the GPIO pin as output */ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num)); reg |= 1 << bank_pin_num; xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num)); /* configure the output enable reg for the pin */ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_OUTEN_OFFSET(bank_num)); reg |= 1 << bank_pin_num; xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_OUTEN_OFFSET(bank_num)); /* set the state of the pin */ xgpiops_set_value(chip, pin, state); return 0; }
/** * xgpiops_dir_in - Set the direction of the specified GPIO pin as input * @chip: gpio_chip instance to be worked on * @pin: gpio pin number within the device * * This function uses the read-modify-write sequence to set the direction of * the gpio pin as input. Returns 0 always. */ static int xgpiops_dir_in(struct gpio_chip *chip, unsigned int pin) { unsigned int reg, bank_num, bank_pin_num; struct xgpiops *gpio = container_of(chip, struct xgpiops, chip); xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num); /* clear the bit in direction mode reg to set the pin as input */ reg = xgpiops_readreg(gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num)); reg &= ~(1 << bank_pin_num); xgpiops_writereg(reg, gpio->base_addr + XGPIOPS_DIRM_OFFSET(bank_num)); return 0; }
/** * xgpiops_irqhandler - IRQ handler for the gpio banks of a gpio device * @irq: irq number of the gpio bank where interrupt has occurred * @desc: irq descriptor instance of the 'irq' * * This function reads the Interrupt Status Register of each bank to get the * gpio pin number which has triggered an interrupt. It then acks the triggered * interrupt and calls the pin specific handler set by the higher layer * application for that pin. * Note: A bug is reported if no handler is set for the gpio pin. */ void xgpiops_irqhandler(unsigned int irq, struct irq_desc *desc) { int gpio_irq = (int)irq_get_handler_data(irq); struct xgpiops *gpio = (struct xgpiops *)irq_get_chip_data(gpio_irq); unsigned int int_sts, int_enb, bank_num; struct irq_desc *gpio_irq_desc; struct irq_chip *chip = irq_desc_get_chip(desc); chained_irq_enter(chip, desc); for (bank_num = 0; bank_num < 4; bank_num++) { int_sts = xgpiops_readreg(gpio->base_addr + XGPIOPS_INTSTS_OFFSET(bank_num)); int_enb = xgpiops_readreg(gpio->base_addr + XGPIOPS_INTMASK_OFFSET(bank_num)); int_sts &= ~int_enb; for (; int_sts != 0; int_sts >>= 1, gpio_irq++) { if ((int_sts & 1) == 0) continue; gpio_irq_desc = irq_to_desc(gpio_irq); BUG_ON(!gpio_irq_desc); chip = irq_desc_get_chip(gpio_irq_desc); BUG_ON(!chip); chip->irq_ack(&gpio_irq_desc->irq_data); /* call the pin specific handler */ generic_handle_irq(gpio_irq); } /* shift to first virtual irq of next bank */ gpio_irq = (int)irq_get_handler_data(irq) + (xgpiops_pin_table[bank_num] + 1); } chip = irq_desc_get_chip(desc); chained_irq_exit(chip, desc); }