| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Intel Whiskey Cove PMIC GPIO Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * This driver is written based on gpio-crystalcove.c |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2016 Intel Corporation. All rights reserved. |
|---|
| 7 | | - * |
|---|
| 8 | | - * This program is free software; you can redistribute it and/or |
|---|
| 9 | | - * modify it under the terms of the GNU General Public License version |
|---|
| 10 | | - * 2 as published by the Free Software Foundation. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 13 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 14 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 15 | | - * GNU General Public License for more details. |
|---|
| 16 | 8 | */ |
|---|
| 17 | 9 | |
|---|
| 18 | 10 | #include <linux/bitops.h> |
|---|
| 19 | | -#include <linux/module.h> |
|---|
| 20 | | -#include <linux/interrupt.h> |
|---|
| 21 | 11 | #include <linux/gpio/driver.h> |
|---|
| 12 | +#include <linux/interrupt.h> |
|---|
| 22 | 13 | #include <linux/mfd/intel_soc_pmic.h> |
|---|
| 14 | +#include <linux/module.h> |
|---|
| 23 | 15 | #include <linux/platform_device.h> |
|---|
| 24 | 16 | #include <linux/regmap.h> |
|---|
| 25 | 17 | #include <linux/seq_file.h> |
|---|
| 26 | 18 | |
|---|
| 27 | 19 | /* |
|---|
| 28 | 20 | * Whiskey Cove PMIC has 13 physical GPIO pins divided into 3 banks: |
|---|
| 29 | | - * Bank 0: Pin 0 - 6 |
|---|
| 30 | | - * Bank 1: Pin 7 - 10 |
|---|
| 31 | | - * Bank 2: Pin 11 -12 |
|---|
| 21 | + * Bank 0: Pin 0 - 6 |
|---|
| 22 | + * Bank 1: Pin 7 - 10 |
|---|
| 23 | + * Bank 2: Pin 11 - 12 |
|---|
| 32 | 24 | * Each pin has one output control register and one input control register. |
|---|
| 33 | 25 | */ |
|---|
| 34 | 26 | #define BANK0_NR_PINS 7 |
|---|
| .. | .. |
|---|
| 75 | 67 | #define CTLO_RVAL_50KDOWN (2 << 1) |
|---|
| 76 | 68 | #define CTLO_RVAL_50KUP (3 << 1) |
|---|
| 77 | 69 | |
|---|
| 78 | | -#define CTLO_INPUT_SET (CTLO_DRV_CMOS | CTLO_DRV_REN | CTLO_RVAL_2KUP) |
|---|
| 79 | | -#define CTLO_OUTPUT_SET (CTLO_DIR_OUT | CTLO_INPUT_SET) |
|---|
| 70 | +#define CTLO_INPUT_SET (CTLO_DRV_CMOS | CTLO_DRV_REN | CTLO_RVAL_2KUP) |
|---|
| 71 | +#define CTLO_OUTPUT_SET (CTLO_DIR_OUT | CTLO_INPUT_SET) |
|---|
| 80 | 72 | |
|---|
| 81 | 73 | enum ctrl_register { |
|---|
| 82 | 74 | CTRL_IN, |
|---|
| .. | .. |
|---|
| 105 | 97 | bool set_irq_mask; |
|---|
| 106 | 98 | }; |
|---|
| 107 | 99 | |
|---|
| 108 | | -static inline unsigned int to_reg(int gpio, enum ctrl_register reg_type) |
|---|
| 100 | +static inline int to_reg(int gpio, enum ctrl_register reg_type) |
|---|
| 109 | 101 | { |
|---|
| 110 | 102 | unsigned int reg; |
|---|
| 111 | 103 | |
|---|
| .. | .. |
|---|
| 178 | 170 | int ret, reg = to_reg(gpio, CTRL_OUT); |
|---|
| 179 | 171 | |
|---|
| 180 | 172 | if (reg < 0) |
|---|
| 181 | | - return 0; |
|---|
| 173 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 182 | 174 | |
|---|
| 183 | 175 | ret = regmap_read(wg->regmap, reg, &val); |
|---|
| 184 | 176 | if (ret) |
|---|
| 185 | 177 | return ret; |
|---|
| 186 | 178 | |
|---|
| 187 | | - return !(val & CTLO_DIR_OUT); |
|---|
| 179 | + if (val & CTLO_DIR_OUT) |
|---|
| 180 | + return GPIO_LINE_DIRECTION_OUT; |
|---|
| 181 | + |
|---|
| 182 | + return GPIO_LINE_DIRECTION_IN; |
|---|
| 188 | 183 | } |
|---|
| 189 | 184 | |
|---|
| 190 | 185 | static int wcove_gpio_get(struct gpio_chip *chip, unsigned int gpio) |
|---|
| .. | .. |
|---|
| 203 | 198 | return val & 0x1; |
|---|
| 204 | 199 | } |
|---|
| 205 | 200 | |
|---|
| 206 | | -static void wcove_gpio_set(struct gpio_chip *chip, |
|---|
| 207 | | - unsigned int gpio, int value) |
|---|
| 201 | +static void wcove_gpio_set(struct gpio_chip *chip, unsigned int gpio, int value) |
|---|
| 208 | 202 | { |
|---|
| 209 | 203 | struct wcove_gpio *wg = gpiochip_get_data(chip); |
|---|
| 210 | 204 | int reg = to_reg(gpio, CTRL_OUT); |
|---|
| .. | .. |
|---|
| 406 | 400 | struct wcove_gpio *wg; |
|---|
| 407 | 401 | int virq, ret, irq; |
|---|
| 408 | 402 | struct device *dev; |
|---|
| 403 | + struct gpio_irq_chip *girq; |
|---|
| 409 | 404 | |
|---|
| 410 | 405 | /* |
|---|
| 411 | 406 | * This gpio platform device is created by a mfd device (see |
|---|
| .. | .. |
|---|
| 448 | 443 | wg->dev = dev; |
|---|
| 449 | 444 | wg->regmap = pmic->regmap; |
|---|
| 450 | 445 | |
|---|
| 451 | | - ret = devm_gpiochip_add_data(dev, &wg->chip, wg); |
|---|
| 452 | | - if (ret) { |
|---|
| 453 | | - dev_err(dev, "Failed to add gpiochip: %d\n", ret); |
|---|
| 454 | | - return ret; |
|---|
| 455 | | - } |
|---|
| 456 | | - |
|---|
| 457 | | - ret = gpiochip_irqchip_add_nested(&wg->chip, &wcove_irqchip, 0, |
|---|
| 458 | | - handle_simple_irq, IRQ_TYPE_NONE); |
|---|
| 459 | | - if (ret) { |
|---|
| 460 | | - dev_err(dev, "Failed to add irqchip: %d\n", ret); |
|---|
| 461 | | - return ret; |
|---|
| 462 | | - } |
|---|
| 463 | | - |
|---|
| 464 | 446 | virq = regmap_irq_get_virq(wg->regmap_irq_chip, irq); |
|---|
| 465 | 447 | if (virq < 0) { |
|---|
| 466 | 448 | dev_err(dev, "Failed to get virq by irq %d\n", irq); |
|---|
| 467 | 449 | return virq; |
|---|
| 468 | 450 | } |
|---|
| 469 | 451 | |
|---|
| 470 | | - ret = devm_request_threaded_irq(dev, virq, NULL, |
|---|
| 471 | | - wcove_gpio_irq_handler, IRQF_ONESHOT, pdev->name, wg); |
|---|
| 452 | + girq = &wg->chip.irq; |
|---|
| 453 | + girq->chip = &wcove_irqchip; |
|---|
| 454 | + /* This will let us handle the parent IRQ in the driver */ |
|---|
| 455 | + girq->parent_handler = NULL; |
|---|
| 456 | + girq->num_parents = 0; |
|---|
| 457 | + girq->parents = NULL; |
|---|
| 458 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 459 | + girq->handler = handle_simple_irq; |
|---|
| 460 | + girq->threaded = true; |
|---|
| 461 | + |
|---|
| 462 | + ret = devm_request_threaded_irq(dev, virq, NULL, wcove_gpio_irq_handler, |
|---|
| 463 | + IRQF_ONESHOT, pdev->name, wg); |
|---|
| 472 | 464 | if (ret) { |
|---|
| 473 | 465 | dev_err(dev, "Failed to request irq %d\n", virq); |
|---|
| 474 | 466 | return ret; |
|---|
| 475 | 467 | } |
|---|
| 476 | 468 | |
|---|
| 477 | | - gpiochip_set_nested_irqchip(&wg->chip, &wcove_irqchip, virq); |
|---|
| 469 | + ret = devm_gpiochip_add_data(dev, &wg->chip, wg); |
|---|
| 470 | + if (ret) { |
|---|
| 471 | + dev_err(dev, "Failed to add gpiochip: %d\n", ret); |
|---|
| 472 | + return ret; |
|---|
| 473 | + } |
|---|
| 478 | 474 | |
|---|
| 479 | 475 | /* Enable GPIO0 interrupts */ |
|---|
| 480 | 476 | ret = regmap_update_bits(wg->regmap, IRQ_MASK_BASE, GPIO_IRQ0_MASK, |
|---|