예제 #1
0
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_CONF0_REG);
	u32 value;
	bool special;

	/*
	 * In most cases, func pin mux 000 means GPIO function.
	 * But, some pins may have func pin mux 001 represents
	 * GPIO function. Only allow user to export pin with
	 * func pin mux preset as GPIO function by BIOS/FW.
	 */
	value = readl(reg) & BYT_PIN_MUX;
	special = is_special_pin(vg, offset);
	if ((special && value != 1) || (!special && value)) {
		dev_err(&vg->pdev->dev,
			"pin %u cannot be used as GPIO.\n", offset);
		return -EINVAL;
	}

	pm_runtime_get(&vg->pdev->dev);

	return 0;
}
예제 #2
0
static int byt_gpio_direction_output(struct gpio_chip *chip,
				     unsigned gpio, int value)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *conf_reg = byt_gpio_reg(chip, gpio, BYT_CONF0_REG);
	void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
	unsigned long flags;
	u32 reg_val;

	spin_lock_irqsave(&vg->lock, flags);

	/*
	 * Before making any direction modifications, do a check if gpio
	 * is set for direct IRQ.  On baytrail, setting GPIO to output does
	 * not make sense, so let's at least warn the caller before they shoot
	 * themselves in the foot.
	 */
	WARN(readl(conf_reg) & BYT_DIRECT_IRQ_EN,
		"Potential Error: Setting GPIO with direct_irq_en to output");

	reg_val = readl(reg) | BYT_DIR_MASK;
	reg_val &= ~BYT_OUTPUT_EN;

	if (value)
		writel(reg_val | BYT_LEVEL, reg);
	else
		writel(reg_val & ~BYT_LEVEL, reg);

	spin_unlock_irqrestore(&vg->lock, flags);

	return 0;
}
static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	int i;
	unsigned long flags;
	u32 conf0, val, offs;

	spin_lock_irqsave(&vg->lock, flags);

	for (i = 0; i < vg->chip.ngpio; i++) {
		const char *label;
		offs = vg->range->pins[i] * 16;
		conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
		val = readl(vg->reg_base + offs + BYT_VAL_REG);

		label = gpiochip_is_requested(chip, i);
		if (!label)
			label = "Unrequested";

		seq_printf(s,
			   " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s\n",
			   i,
			   label,
			   val & BYT_INPUT_EN ? "  " : "in",
			   val & BYT_OUTPUT_EN ? "   " : "out",
			   val & BYT_LEVEL ? "hi" : "lo",
			   vg->range->pins[i], offs,
			   conf0 & 0x7,
			   conf0 & BYT_TRIG_NEG ? " fall" : "",
			   conf0 & BYT_TRIG_POS ? " rise" : "",
			   conf0 & BYT_TRIG_LVL ? " level" : "");
	}
	spin_unlock_irqrestore(&vg->lock, flags);
}
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
	struct byt_gpio *vg = to_byt_gpio(chip);

	pm_runtime_get(&vg->pdev->dev);

	return 0;
}
예제 #5
0
static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
	u32 value;

	/* clear interrupt triggering */
	value = readl(reg);
	value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
	writel(value, reg);

	pm_runtime_put(&vg->pdev->dev);
}
예제 #6
0
static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
				 int reg)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	u32 reg_offset;

	if (reg == BYT_INT_STAT_REG)
		reg_offset = (offset / 32) * 4;
	else
		reg_offset = vg->range->pins[offset] * 16;

	return vg->reg_base + reg_offset + reg;
}
예제 #7
0
static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
	struct irq_data *data = irq_desc_get_irq_data(desc);
	struct byt_gpio *vg = to_byt_gpio(irq_desc_get_handler_data(desc));
	struct irq_chip *chip = irq_data_get_irq_chip(data);
	u32 base, pin, mask;
	void __iomem *reg;
	u32 pending;
	unsigned virq;
	int looplimit = 0;

	/* check from GPIO controller which pin triggered the interrupt */
	for (base = 0; base < vg->chip.ngpio; base += 32) {

		reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);

		while ((pending = readl(reg))) {
			pin = __ffs(pending);
			mask = BIT(pin);
			/* Clear before handling so we can't lose an edge */
			writel(mask, reg);

			virq = irq_find_mapping(vg->chip.irqdomain, base + pin);
			generic_handle_irq(virq);

			/* In case bios or user sets triggering incorretly a pin
			 * might remain in "interrupt triggered" state.
			 */
			if (looplimit++ > 32) {
				dev_err(&vg->pdev->dev,
					"Gpio %d interrupt flood, disabling\n",
					base + pin);

				reg = byt_gpio_reg(&vg->chip, base + pin,
						   BYT_CONF0_REG);
				mask = readl(reg);
				mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
					  BYT_TRIG_LVL);
				writel(mask, reg);
				mask = readl(reg); /* flush */
				break;
			}
		}
	}
	chip->irq_eoi(data);
}
예제 #8
0
static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
	unsigned long flags;
	u32 value;

	spin_lock_irqsave(&vg->lock, flags);

	value = readl(reg) | BYT_DIR_MASK;
	value &= ~BYT_INPUT_EN;		/* active low */
	writel(value, reg);

	spin_unlock_irqrestore(&vg->lock, flags);

	return 0;
}
예제 #9
0
static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
	unsigned long flags;
	u32 old_val;

	spin_lock_irqsave(&vg->lock, flags);

	old_val = readl(reg);

	if (value)
		writel(old_val | BYT_LEVEL, reg);
	else
		writel(old_val & ~BYT_LEVEL, reg);

	spin_unlock_irqrestore(&vg->lock, flags);
}
예제 #10
0
static int byt_irq_type(struct irq_data *d, unsigned type)
{
	struct byt_gpio *vg = to_byt_gpio(irq_data_get_irq_chip_data(d));
	u32 offset = irqd_to_hwirq(d);
	u32 value;
	unsigned long flags;
	void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);

	if (offset >= vg->chip.ngpio)
		return -EINVAL;

	spin_lock_irqsave(&vg->lock, flags);
	value = readl(reg);

	/* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits
	 * are used to indicate high and low level triggering
	 */
	value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);

	switch (type) {
	case IRQ_TYPE_LEVEL_HIGH:
		value |= BYT_TRIG_LVL;
	case IRQ_TYPE_EDGE_RISING:
		value |= BYT_TRIG_POS;
		break;
	case IRQ_TYPE_LEVEL_LOW:
		value |= BYT_TRIG_LVL;
	case IRQ_TYPE_EDGE_FALLING:
		value |= BYT_TRIG_NEG;
		break;
	case IRQ_TYPE_EDGE_BOTH:
		value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
		break;
	}
	writel(value, reg);

	spin_unlock_irqrestore(&vg->lock, flags);

	return 0;
}
static int byt_gpio_direction_output(struct gpio_chip *chip,
				     unsigned gpio, int value)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
	unsigned long flags;
	u32 reg_val;

	spin_lock_irqsave(&vg->lock, flags);

	reg_val = readl(reg) | BYT_DIR_MASK;
	reg_val &= ~(BYT_OUTPUT_EN | BYT_INPUT_EN);

	if (value)
		writel(reg_val | BYT_LEVEL, reg);
	else
		writel(reg_val & ~BYT_LEVEL, reg);

	spin_unlock_irqrestore(&vg->lock, flags);

	return 0;
}
예제 #12
0
static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	int i;
	unsigned long flags;
	u32 conf0, val, offs;

	spin_lock_irqsave(&vg->lock, flags);

	for (i = 0; i < vg->chip.ngpio; i++) {
		const char *pull_str = NULL;
		const char *pull = NULL;
		const char *label;
		offs = vg->range->pins[i] * 16;
		conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
		val = readl(vg->reg_base + offs + BYT_VAL_REG);

		label = gpiochip_is_requested(chip, i);
		if (!label)
			label = "Unrequested";

		switch (conf0 & BYT_PULL_ASSIGN_MASK) {
		case BYT_PULL_ASSIGN_UP:
			pull = "up";
			break;
		case BYT_PULL_ASSIGN_DOWN:
			pull = "down";
			break;
		}

		switch (conf0 & BYT_PULL_STR_MASK) {
		case BYT_PULL_STR_2K:
			pull_str = "2k";
			break;
		case BYT_PULL_STR_10K:
			pull_str = "10k";
			break;
		case BYT_PULL_STR_20K:
			pull_str = "20k";
			break;
		case BYT_PULL_STR_40K:
			pull_str = "40k";
			break;
		}

		seq_printf(s,
			   " gpio-%-3d (%-20.20s) %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s",
			   i,
			   label,
			   val & BYT_INPUT_EN ? "  " : "in",
			   val & BYT_OUTPUT_EN ? "   " : "out",
			   val & BYT_LEVEL ? "hi" : "lo",
			   vg->range->pins[i], offs,
			   conf0 & 0x7,
			   conf0 & BYT_TRIG_NEG ? " fall" : "     ",
			   conf0 & BYT_TRIG_POS ? " rise" : "     ",
			   conf0 & BYT_TRIG_LVL ? " level" : "      ");

		if (pull && pull_str)
			seq_printf(s, " %-4s %-3s", pull, pull_str);
		else
			seq_puts(s, "          ");

		if (conf0 & BYT_IODEN)
			seq_puts(s, " open-drain");

		seq_puts(s, "\n");
	}
	spin_unlock_irqrestore(&vg->lock, flags);
}
static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
	struct byt_gpio *vg = to_byt_gpio(chip);
	return irq_create_mapping(vg->domain, offset);
}