--- zzzz-none-000/linux-3.10.107/drivers/gpio/gpio-stmpe.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/gpio/gpio-stmpe.c 2021-02-04 17:41:59.000000000 +0000 @@ -10,11 +10,10 @@ #include #include #include -#include -#include #include #include #include +#include /* * These registers are modified under the irq bus lock and cached to avoid @@ -23,18 +22,15 @@ enum { REG_RE, REG_FE, REG_IE }; #define CACHE_NR_REGS 3 -#define CACHE_NR_BANKS (STMPE_NR_GPIOS / 8) +/* No variant has more than 24 GPIOs */ +#define CACHE_NR_BANKS (24 / 8) struct stmpe_gpio { struct gpio_chip chip; struct stmpe *stmpe; struct device *dev; struct mutex irq_lock; - struct irq_domain *domain; - - int irq_base; - unsigned norequest_mask; - + u32 norequest_mask; /* Caches of interrupt control registers for bus_lock */ u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS]; u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS]; @@ -102,13 +98,6 @@ return stmpe_set_bits(stmpe, reg, mask, 0); } -static int stmpe_gpio_to_irq(struct gpio_chip *chip, unsigned offset) -{ - struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); - - return irq_create_mapping(stmpe_gpio->domain, offset); -} - static int stmpe_gpio_request(struct gpio_chip *chip, unsigned offset) { struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(chip); @@ -127,31 +116,31 @@ .get = stmpe_gpio_get, .direction_output = stmpe_gpio_direction_output, .set = stmpe_gpio_set, - .to_irq = stmpe_gpio_to_irq, .request = stmpe_gpio_request, - .can_sleep = 1, + .can_sleep = true, }; static int stmpe_gpio_irq_set_type(struct irq_data *d, unsigned int type) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); - if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH) + if (type & IRQ_TYPE_LEVEL_LOW || type & IRQ_TYPE_LEVEL_HIGH) return -EINVAL; /* STMPE801 doesn't have RE and FE registers */ if (stmpe_gpio->stmpe->partnum == STMPE801) return 0; - if (type == IRQ_TYPE_EDGE_RISING) + if (type & IRQ_TYPE_EDGE_RISING) stmpe_gpio->regs[REG_RE][regoffset] |= mask; else stmpe_gpio->regs[REG_RE][regoffset] &= ~mask; - if (type == IRQ_TYPE_EDGE_FALLING) + if (type & IRQ_TYPE_EDGE_FALLING) stmpe_gpio->regs[REG_FE][regoffset] |= mask; else stmpe_gpio->regs[REG_FE][regoffset] &= ~mask; @@ -161,14 +150,16 @@ static void stmpe_gpio_irq_lock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); mutex_lock(&stmpe_gpio->irq_lock); } static void stmpe_gpio_irq_sync_unlock(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); struct stmpe *stmpe = stmpe_gpio->stmpe; int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); static const u8 regmap[] = { @@ -201,7 +192,8 @@ static void stmpe_gpio_irq_mask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -211,7 +203,8 @@ static void stmpe_gpio_irq_unmask(struct irq_data *d) { - struct stmpe_gpio *stmpe_gpio = irq_data_get_irq_chip_data(d); + struct gpio_chip *gc = irq_data_get_irq_chip_data(d); + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); int offset = d->hwirq; int regoffset = offset / 8; int mask = 1 << (offset % 8); @@ -219,6 +212,77 @@ stmpe_gpio->regs[REG_IE][regoffset] |= mask; } +static void stmpe_dbg_show_one(struct seq_file *s, + struct gpio_chip *gc, + unsigned offset, unsigned gpio) +{ + struct stmpe_gpio *stmpe_gpio = to_stmpe_gpio(gc); + struct stmpe *stmpe = stmpe_gpio->stmpe; + const char *label = gpiochip_is_requested(gc, offset); + int num_banks = DIV_ROUND_UP(stmpe->num_gpios, 8); + bool val = !!stmpe_gpio_get(gc, offset); + u8 dir_reg = stmpe->regs[STMPE_IDX_GPDR_LSB] - (offset / 8); + u8 mask = 1 << (offset % 8); + int ret; + u8 dir; + + ret = stmpe_reg_read(stmpe, dir_reg); + if (ret < 0) + return; + dir = !!(ret & mask); + + if (dir) { + seq_printf(s, " gpio-%-3d (%-20.20s) out %s", + gpio, label ?: "(none)", + val ? "hi" : "lo"); + } else { + u8 edge_det_reg = stmpe->regs[STMPE_IDX_GPEDR_MSB] + num_banks - 1 - (offset / 8); + u8 rise_reg = stmpe->regs[STMPE_IDX_GPRER_LSB] - (offset / 8); + u8 fall_reg = stmpe->regs[STMPE_IDX_GPFER_LSB] - (offset / 8); + u8 irqen_reg = stmpe->regs[STMPE_IDX_IEGPIOR_LSB] - (offset / 8); + bool edge_det; + bool rise; + bool fall; + bool irqen; + + ret = stmpe_reg_read(stmpe, edge_det_reg); + if (ret < 0) + return; + edge_det = !!(ret & mask); + ret = stmpe_reg_read(stmpe, rise_reg); + if (ret < 0) + return; + rise = !!(ret & mask); + ret = stmpe_reg_read(stmpe, fall_reg); + if (ret < 0) + return; + fall = !!(ret & mask); + ret = stmpe_reg_read(stmpe, irqen_reg); + if (ret < 0) + return; + irqen = !!(ret & mask); + + seq_printf(s, " gpio-%-3d (%-20.20s) in %s %s %s%s%s", + gpio, label ?: "(none)", + val ? "hi" : "lo", + edge_det ? "edge-asserted" : "edge-inactive", + irqen ? "IRQ-enabled" : "", + rise ? " rising-edge-detection" : "", + fall ? " falling-edge-detection" : ""); + } +} + +static void stmpe_dbg_show(struct seq_file *s, struct gpio_chip *gc) +{ + unsigned i; + unsigned gpio = gc->base; + + for (i = 0; i < gc->ngpio; i++, gpio++) { + stmpe_dbg_show_one(s, gc, i, gpio); + seq_printf(s, "\n"); + } +} + static struct irq_chip stmpe_gpio_irq_chip = { .name = "stmpe-gpio", .irq_bus_lock = stmpe_gpio_irq_lock, @@ -254,9 +318,10 @@ while (stat) { int bit = __ffs(stat); int line = bank * 8 + bit; - int virq = irq_find_mapping(stmpe_gpio->domain, line); + int child_irq = irq_find_mapping(stmpe_gpio->chip.irqdomain, + line); - handle_nested_irq(virq); + handle_nested_irq(child_irq); stat &= ~(1 << bit); } @@ -271,72 +336,14 @@ return IRQ_HANDLED; } -int stmpe_gpio_irq_map(struct irq_domain *d, unsigned int virq, - irq_hw_number_t hwirq) -{ - struct stmpe_gpio *stmpe_gpio = d->host_data; - - if (!stmpe_gpio) - return -EINVAL; - - irq_set_chip_data(hwirq, stmpe_gpio); - irq_set_chip_and_handler(hwirq, &stmpe_gpio_irq_chip, - handle_simple_irq); - irq_set_nested_thread(hwirq, 1); -#ifdef CONFIG_ARM - set_irq_flags(hwirq, IRQF_VALID); -#else - irq_set_noprobe(hwirq); -#endif - - return 0; -} - -void stmpe_gpio_irq_unmap(struct irq_domain *d, unsigned int virq) -{ -#ifdef CONFIG_ARM - set_irq_flags(virq, 0); -#endif - irq_set_chip_and_handler(virq, NULL, NULL); - irq_set_chip_data(virq, NULL); -} - -static const struct irq_domain_ops stmpe_gpio_irq_simple_ops = { - .unmap = stmpe_gpio_irq_unmap, - .map = stmpe_gpio_irq_map, - .xlate = irq_domain_xlate_twocell, -}; - -static int stmpe_gpio_irq_init(struct stmpe_gpio *stmpe_gpio, - struct device_node *np) -{ - int base = 0; - - if (!np) - base = stmpe_gpio->irq_base; - - stmpe_gpio->domain = irq_domain_add_simple(np, - stmpe_gpio->chip.ngpio, base, - &stmpe_gpio_irq_simple_ops, stmpe_gpio); - if (!stmpe_gpio->domain) { - dev_err(stmpe_gpio->dev, "failed to create irqdomain\n"); - return -ENOSYS; - } - - return 0; -} - static int stmpe_gpio_probe(struct platform_device *pdev) { struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent); struct device_node *np = pdev->dev.of_node; - struct stmpe_gpio_platform_data *pdata; struct stmpe_gpio *stmpe_gpio; int ret; int irq = 0; - pdata = stmpe->pdata->gpio; - irq = platform_get_irq(pdev, 0); stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL); @@ -350,59 +357,62 @@ stmpe_gpio->chip = template_chip; stmpe_gpio->chip.ngpio = stmpe->num_gpios; stmpe_gpio->chip.dev = &pdev->dev; -#ifdef CONFIG_OF stmpe_gpio->chip.of_node = np; -#endif - stmpe_gpio->chip.base = pdata ? pdata->gpio_base : -1; + stmpe_gpio->chip.base = -1; - if (pdata) - stmpe_gpio->norequest_mask = pdata->norequest_mask; - else if (np) - of_property_read_u32(np, "st,norequest-mask", - &stmpe_gpio->norequest_mask); + if (IS_ENABLED(CONFIG_DEBUG_FS)) + stmpe_gpio->chip.dbg_show = stmpe_dbg_show; - if (irq >= 0) - stmpe_gpio->irq_base = stmpe->irq_base + STMPE_INT_GPIO(0); - else + of_property_read_u32(np, "st,norequest-mask", + &stmpe_gpio->norequest_mask); + + if (irq < 0) dev_info(&pdev->dev, - "device configured in no-irq mode; " + "device configured in no-irq mode: " "irqs are not available\n"); ret = stmpe_enable(stmpe, STMPE_BLOCK_GPIO); if (ret) goto out_free; - if (irq >= 0) { - ret = stmpe_gpio_irq_init(stmpe_gpio, np); - if (ret) - goto out_disable; + ret = gpiochip_add(&stmpe_gpio->chip); + if (ret) { + dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); + goto out_disable; + } - ret = request_threaded_irq(irq, NULL, stmpe_gpio_irq, - IRQF_ONESHOT, "stmpe-gpio", stmpe_gpio); + if (irq > 0) { + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, + stmpe_gpio_irq, IRQF_ONESHOT, + "stmpe-gpio", stmpe_gpio); if (ret) { dev_err(&pdev->dev, "unable to get irq: %d\n", ret); goto out_disable; } - } + ret = gpiochip_irqchip_add(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + 0, + handle_simple_irq, + IRQ_TYPE_NONE); + if (ret) { + dev_err(&pdev->dev, + "could not connect irqchip to gpiochip\n"); + goto out_disable; + } - ret = gpiochip_add(&stmpe_gpio->chip); - if (ret) { - dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); - goto out_freeirq; + gpiochip_set_chained_irqchip(&stmpe_gpio->chip, + &stmpe_gpio_irq_chip, + irq, + NULL); } - if (pdata && pdata->setup) - pdata->setup(stmpe, stmpe_gpio->chip.base); - platform_set_drvdata(pdev, stmpe_gpio); return 0; -out_freeirq: - if (irq >= 0) - free_irq(irq, stmpe_gpio); out_disable: stmpe_disable(stmpe, STMPE_BLOCK_GPIO); + gpiochip_remove(&stmpe_gpio->chip); out_free: kfree(stmpe_gpio); return ret; @@ -412,26 +422,9 @@ { struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev); struct stmpe *stmpe = stmpe_gpio->stmpe; - struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio; - int irq = platform_get_irq(pdev, 0); - int ret; - - if (pdata && pdata->remove) - pdata->remove(stmpe, stmpe_gpio->chip.base); - - ret = gpiochip_remove(&stmpe_gpio->chip); - if (ret < 0) { - dev_err(stmpe_gpio->dev, - "unable to remove gpiochip: %d\n", ret); - return ret; - } + gpiochip_remove(&stmpe_gpio->chip); stmpe_disable(stmpe, STMPE_BLOCK_GPIO); - - if (irq >= 0) - free_irq(irq, stmpe_gpio); - - platform_set_drvdata(pdev, NULL); kfree(stmpe_gpio); return 0;