コード例 #1
0
ファイル: gpio-xilinxps.c プロジェクト: bjayesh/chandra
/**
 * 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;
}
コード例 #2
0
ファイル: gpio-xilinxps.c プロジェクト: bjayesh/chandra
/**
 * 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;
}
コード例 #3
0
ファイル: gpio-xilinxps.c プロジェクト: bjayesh/chandra
/**
 * 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;
}
コード例 #4
0
ファイル: gpio-xilinxps.c プロジェクト: Analias/SNOWLeo-SDR-1
/**
 * 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);
}