/** * zynq_gpio_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 zynq_gpio_set to set * the state of the pin to the value specified. * * Return: 0 always */ static int zynq_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int state) { struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); unsigned int reg, bank_num, bank_pin_num; zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); /* set the GPIO pin as output */ reg = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); reg |= 1 << bank_pin_num; zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num), reg); /* configure the output enable reg for the pin */ reg = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); reg |= 1 << bank_pin_num; zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_OUTEN_OFFSET(bank_num), reg); /* set the state of the pin */ zynq_gpio_set_value(chip, pin, state); return 0; }
/** * gpio_set_value - Modify the value of the pin with specified value * @gpio: gpio pin number within the device * @value: value used to modify the value 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 value of a * gpio pin to the specified value. The value is either 0 or non-zero. */ int gpio_set_value(unsigned gpio, int value) { unsigned int reg_offset, bank_num, bank_pin_num; if (check_gpio(gpio) < 0) return -1; zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num); if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) { /* only 16 data bits in bit maskable reg */ bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM; reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); } else { reg_offset = ZYNQ_GPIO_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 */ value = !!value; value = ~(1 << (bank_pin_num + ZYNQ_GPIO_MID_PIN_NUM)) & ((value << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK); writel(value, ZYNQ_GPIO_BASE_ADDRESS + reg_offset); return 0; }
/** * zynq_gpio_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 zynq_gpio_set_value(struct gpio_chip *chip, unsigned int pin, int state) { unsigned int reg_offset, bank_num, bank_pin_num; struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); if (bank_pin_num >= ZYNQ_GPIO_MID_PIN_NUM) { /* only 16 data bits in bit maskable reg */ bank_pin_num -= ZYNQ_GPIO_MID_PIN_NUM; reg_offset = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); } else { reg_offset = ZYNQ_GPIO_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 + ZYNQ_GPIO_MID_PIN_NUM)) & ((state << bank_pin_num) | ZYNQ_GPIO_UPPER_MASK); zynq_gpio_writereg(gpio->base_addr + reg_offset, state); }
/** * zynq_gpio_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 zynq_gpio_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 zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); zynq_gpio_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 = ZYNQ_GPIO_DATA_MSW_OFFSET(bank_num); } else { reg_offset = ZYNQ_GPIO_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); zynq_gpio_writereg(state, gpio->base_addr + reg_offset); spin_unlock_irqrestore(&gpio->gpio_lock, flags); }
/** * zynq_gpio_irq_unmask - Enable the interrupts for a gpio pin * @irq_data: irq data containing irq number of gpio pin for the interrupt * 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 zynq_gpio_irq_unmask(struct irq_data *irq_data) { struct zynq_gpio *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; zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_INTEN_OFFSET(bank_num), 1 << bank_pin_num); }
/** * zynq_gpio_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. * * Return: 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 zynq_gpio_set_irq_type(struct irq_data *irq_data, unsigned int type) { struct zynq_gpio *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; zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); int_type = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num)); int_pol = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num)); int_any = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_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; } zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_INTTYPE_OFFSET(bank_num), int_type); zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_INTPOL_OFFSET(bank_num), int_pol); zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_INTANY_OFFSET(bank_num), int_any); return 0; }
/** * zynq_gpio_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. * * Return: 0 if the pin is low, 1 if pin is high. */ static int zynq_gpio_get_value(struct gpio_chip *chip, unsigned int pin) { unsigned int bank_num, bank_pin_num, data; struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); data = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_DATA_OFFSET(bank_num)); return (data >> bank_pin_num) & ZYNQ_GPIO_PIN_HIGH; }
/** * zynq_gpio_irq_ack - Acknowledge the interrupt of a gpio pin * @irq_data: irq data containing irq number of gpio pin for the interrupt * to ack * * This function calculates gpio pin number from irq number and sets the bit * in the Interrupt Status Register of the corresponding bank, to ACK the irq. */ static void zynq_gpio_irq_ack(struct irq_data *irq_data) { struct zynq_gpio *gpio = (struct zynq_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; zynq_gpio_get_bank_pin(device_pin_num, &bank_num, &bank_pin_num); zynq_gpio_writereg(1 << bank_pin_num, gpio->base_addr + (ZYNQ_GPIO_INTSTS_OFFSET(bank_num))); }
/** * gpio_get_value - Get the state of the specified pin of GPIO device * @gpio: gpio pin number within the device * * This function reads the state of the specified pin of the GPIO device. * * Return: 0 if the pin is low, 1 if pin is high. */ int gpio_get_value(unsigned gpio) { u32 data; unsigned int bank_num, bank_pin_num; if (check_gpio(gpio) < 0) return -1; zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num); data = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DATA_RO_OFFSET(bank_num)); return (data >> bank_pin_num) & 1; }
/** * zynq_gpio_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. * * Return: 0 always */ static int zynq_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) { unsigned int reg, bank_num, bank_pin_num; struct zynq_gpio *gpio = container_of(chip, struct zynq_gpio, chip); zynq_gpio_get_bank_pin(pin, &bank_num, &bank_pin_num); /* clear the bit in direction mode reg to set the pin as input */ reg = zynq_gpio_readreg(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); reg &= ~(1 << bank_pin_num); zynq_gpio_writereg(gpio->base_addr + ZYNQ_GPIO_DIRM_OFFSET(bank_num), reg); return 0; }
/** * gpio_direction_input - Set the direction of the specified GPIO pin as input * @gpio: gpio pin number within the device * * This function uses the read-modify-write sequence to set the direction of * the gpio pin as input. * * Return: -1 if invalid gpio specified, 0 if successul */ int gpio_direction_input(unsigned gpio) { u32 reg; unsigned int bank_num, bank_pin_num; if (check_gpio(gpio) < 0) return -1; zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num); /* bank 0 pins 7 and 8 are special and cannot be used as inputs */ if (bank_num == 0 && (bank_pin_num == 7 || bank_pin_num == 8)) return -1; /* clear the bit in direction mode reg to set the pin as input */ reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); reg &= ~BIT(bank_pin_num); writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); return 0; }
/** * gpio_direction_output - Set the direction of the specified GPIO pin as output * @gpio: gpio pin number within the device * @value: 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 zynq_gpio_set to set * the value of the pin to the value specified. * * Return: 0 always */ int gpio_direction_output(unsigned gpio, int value) { u32 reg; unsigned int bank_num, bank_pin_num; if (check_gpio(gpio) < 0) return -1; zynq_gpio_get_bank_pin(gpio, &bank_num, &bank_pin_num); /* set the GPIO pin as output */ reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); reg |= BIT(bank_pin_num); writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_DIRM_OFFSET(bank_num)); /* configure the output enable reg for the pin */ reg = readl(ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); reg |= BIT(bank_pin_num); writel(reg, ZYNQ_GPIO_BASE_ADDRESS + ZYNQ_GPIO_OUTEN_OFFSET(bank_num)); /* set the state of the pin */ gpio_set_value(gpio, value); return 0; }