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; }
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; }
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); }
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; }
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); }
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; }
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); }
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; }
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); }