/** * xgpiops_set_value - Modify the state of the pin with specified value * @chip: gpio_chip instance to be worked on * @pin: gpio pin number within the device * @state: value used to modify the state of the specified pin * * This function calculates the register offset (i.e to lower 16 bits or * upper 16 bits) based on the given pin number and sets the state of a * gpio pin to the specified value. The state is either 0 or non-zero. */ static void xgpiops_set_value(struct gpio_chip *chip, unsigned int pin, int state) { unsigned long flags; unsigned int reg_offset; unsigned int bank_num, bank_pin_num; struct xgpiops *gpio = container_of(chip, struct xgpiops, chip); xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num); if (bank_pin_num >= 16) { bank_pin_num -= 16; /* only 16 data bits in bit maskable reg */ reg_offset = XGPIOPS_DATA_MSW_OFFSET(bank_num); } else { reg_offset = XGPIOPS_DATA_LSW_OFFSET(bank_num); } /* * get the 32 bit value to be written to the mask/data register where * the upper 16 bits is the mask and lower 16 bits is the data */ if (state) state = 1; state = ~(1 << (bank_pin_num + 16)) & ((state << bank_pin_num) | 0xFFFF0000); spin_lock_irqsave(&gpio->gpio_lock, flags); xgpiops_writereg(state, gpio->base_addr + reg_offset); spin_unlock_irqrestore(&gpio->gpio_lock, flags); }
/** * xgpiops_irq_unmask - Enable the interrupts for a gpio pin * @irq_data: irq data containing irq number of gpio pin for the irq to enable * * This function calculates the gpio pin number from irq number and sets the * bit in the Interrupt Enable register of the corresponding bank to enable * interrupts for that pin. */ static void xgpiops_irq_unmask(struct irq_data *irq_data) { struct xgpiops *gpio = irq_data_get_irq_chip_data(irq_data); unsigned int device_pin_num, bank_num, bank_pin_num; device_pin_num = irq_data->hwirq; xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); xgpiops_writereg(1 << bank_pin_num, gpio->base_addr + XGPIOPS_INTEN_OFFSET(bank_num)); }
/** * xgpiops_irq_mask - Disable the interrupts for a gpio pin * @irq: irq number of gpio pin for which interrupt is to be disabled * * This function calculates gpio pin number from irq number and sets the * bit in the Interrupt Disable register of the corresponding bank to disable * interrupts for that pin. */ static void xgpiops_irq_mask(struct irq_data *irq_data) { struct xgpiops *gpio = (struct xgpiops *)irq_data_get_irq_chip_data(irq_data); unsigned int device_pin_num, bank_num, bank_pin_num; device_pin_num = irq_to_gpio(irq_data->irq); /* get pin num within the device */ xgpiops_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); xgpiops_writereg(1 << bank_pin_num, gpio->base_addr + XGPIOPS_INTDIS_OFFSET(bank_num)); }
/** * 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_get_value - Get the state of the specified pin of GPIO device * @chip: gpio_chip instance to be worked on * @pin: gpio pin number within the device * * This function reads the state of the specified pin of the GPIO device. * It returns 0 if the pin is low, 1 if pin is high. */ static int xgpiops_get_value(struct gpio_chip *chip, unsigned int pin) { unsigned int bank_num, bank_pin_num; struct xgpiops *gpio = container_of(chip, struct xgpiops, chip); xgpiops_get_bank_pin(pin, &bank_num, &bank_pin_num); return (xgpiops_readreg(gpio->base_addr + XGPIOPS_DATA_OFFSET(bank_num)) >> bank_pin_num) & 1; }
/** * 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_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; }