| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) ST-Ericsson SA 2010 |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * License Terms: GNU General Public License, version 2 |
|---|
| 5 | 5 | * Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson |
|---|
| 6 | 6 | * Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson |
|---|
| 7 | 7 | */ |
|---|
| .. | .. |
|---|
| 19 | 19 | * These registers are modified under the irq bus lock and cached to avoid |
|---|
| 20 | 20 | * unnecessary writes in bus_sync_unlock. |
|---|
| 21 | 21 | */ |
|---|
| 22 | | -enum { REG_IBE, REG_IEV, REG_IS, REG_IE }; |
|---|
| 22 | +enum { REG_IBE, REG_IEV, REG_IS, REG_IE, REG_DIRECT }; |
|---|
| 23 | 23 | |
|---|
| 24 | | -#define CACHE_NR_REGS 4 |
|---|
| 24 | +#define CACHE_NR_REGS 5 |
|---|
| 25 | 25 | #define CACHE_NR_BANKS 3 |
|---|
| 26 | 26 | |
|---|
| 27 | 27 | struct tc3589x_gpio { |
|---|
| .. | .. |
|---|
| 97 | 97 | if (ret < 0) |
|---|
| 98 | 98 | return ret; |
|---|
| 99 | 99 | |
|---|
| 100 | | - return !(ret & BIT(pos)); |
|---|
| 100 | + if (ret & BIT(pos)) |
|---|
| 101 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 102 | + |
|---|
| 103 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 101 | 104 | } |
|---|
| 102 | 105 | |
|---|
| 103 | 106 | static int tc3589x_gpio_set_config(struct gpio_chip *chip, unsigned int offset, |
|---|
| .. | .. |
|---|
| 197 | 200 | [REG_IEV] = TC3589x_GPIOIEV0, |
|---|
| 198 | 201 | [REG_IS] = TC3589x_GPIOIS0, |
|---|
| 199 | 202 | [REG_IE] = TC3589x_GPIOIE0, |
|---|
| 203 | + [REG_DIRECT] = TC3589x_DIRECT0, |
|---|
| 200 | 204 | }; |
|---|
| 201 | 205 | int i, j; |
|---|
| 202 | 206 | |
|---|
| .. | .. |
|---|
| 225 | 229 | int mask = BIT(offset % 8); |
|---|
| 226 | 230 | |
|---|
| 227 | 231 | tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask; |
|---|
| 232 | + tc3589x_gpio->regs[REG_DIRECT][regoffset] |= mask; |
|---|
| 228 | 233 | } |
|---|
| 229 | 234 | |
|---|
| 230 | 235 | static void tc3589x_gpio_irq_unmask(struct irq_data *d) |
|---|
| .. | .. |
|---|
| 236 | 241 | int mask = BIT(offset % 8); |
|---|
| 237 | 242 | |
|---|
| 238 | 243 | tc3589x_gpio->regs[REG_IE][regoffset] |= mask; |
|---|
| 244 | + tc3589x_gpio->regs[REG_DIRECT][regoffset] &= ~mask; |
|---|
| 239 | 245 | } |
|---|
| 240 | 246 | |
|---|
| 241 | 247 | static struct irq_chip tc3589x_gpio_irq_chip = { |
|---|
| .. | .. |
|---|
| 286 | 292 | struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent); |
|---|
| 287 | 293 | struct device_node *np = pdev->dev.of_node; |
|---|
| 288 | 294 | struct tc3589x_gpio *tc3589x_gpio; |
|---|
| 295 | + struct gpio_irq_chip *girq; |
|---|
| 289 | 296 | int ret; |
|---|
| 290 | 297 | int irq; |
|---|
| 291 | 298 | |
|---|
| .. | .. |
|---|
| 314 | 321 | tc3589x_gpio->chip.base = -1; |
|---|
| 315 | 322 | tc3589x_gpio->chip.of_node = np; |
|---|
| 316 | 323 | |
|---|
| 324 | + girq = &tc3589x_gpio->chip.irq; |
|---|
| 325 | + girq->chip = &tc3589x_gpio_irq_chip; |
|---|
| 326 | + /* This will let us handle the parent IRQ in the driver */ |
|---|
| 327 | + girq->parent_handler = NULL; |
|---|
| 328 | + girq->num_parents = 0; |
|---|
| 329 | + girq->parents = NULL; |
|---|
| 330 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 331 | + girq->handler = handle_simple_irq; |
|---|
| 332 | + girq->threaded = true; |
|---|
| 333 | + |
|---|
| 317 | 334 | /* Bring the GPIO module out of reset */ |
|---|
| 318 | 335 | ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, |
|---|
| 319 | 336 | TC3589x_RSTCTRL_GPIRST, 0); |
|---|
| 337 | + if (ret < 0) |
|---|
| 338 | + return ret; |
|---|
| 339 | + |
|---|
| 340 | + /* For tc35894, have to disable Direct KBD interrupts, |
|---|
| 341 | + * else IRQST will always be 0x20, IRQN low level, can't |
|---|
| 342 | + * clear the irq status. |
|---|
| 343 | + * TODO: need more test on other tc3589x chip. |
|---|
| 344 | + * |
|---|
| 345 | + */ |
|---|
| 346 | + ret = tc3589x_reg_write(tc3589x, TC3589x_DKBDMSK, |
|---|
| 347 | + TC3589x_DKBDMSK_ELINT | TC3589x_DKBDMSK_EINT); |
|---|
| 320 | 348 | if (ret < 0) |
|---|
| 321 | 349 | return ret; |
|---|
| 322 | 350 | |
|---|
| .. | .. |
|---|
| 335 | 363 | dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret); |
|---|
| 336 | 364 | return ret; |
|---|
| 337 | 365 | } |
|---|
| 338 | | - |
|---|
| 339 | | - ret = gpiochip_irqchip_add_nested(&tc3589x_gpio->chip, |
|---|
| 340 | | - &tc3589x_gpio_irq_chip, |
|---|
| 341 | | - 0, |
|---|
| 342 | | - handle_simple_irq, |
|---|
| 343 | | - IRQ_TYPE_NONE); |
|---|
| 344 | | - if (ret) { |
|---|
| 345 | | - dev_err(&pdev->dev, |
|---|
| 346 | | - "could not connect irqchip to gpiochip\n"); |
|---|
| 347 | | - return ret; |
|---|
| 348 | | - } |
|---|
| 349 | | - |
|---|
| 350 | | - gpiochip_set_nested_irqchip(&tc3589x_gpio->chip, |
|---|
| 351 | | - &tc3589x_gpio_irq_chip, |
|---|
| 352 | | - irq); |
|---|
| 353 | 366 | |
|---|
| 354 | 367 | platform_set_drvdata(pdev, tc3589x_gpio); |
|---|
| 355 | 368 | |
|---|