| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0 |
|---|
| 1 | 2 | /* |
|---|
| 2 | | - * gpio-crystalcove.c - Intel Crystal Cove GPIO Driver |
|---|
| 3 | + * Intel Crystal Cove GPIO Driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2012, 2014 Intel Corporation. All rights reserved. |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License version |
|---|
| 8 | | - * 2 as published by the Free Software Foundation. |
|---|
| 9 | | - * |
|---|
| 10 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 11 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | | - * GNU General Public License for more details. |
|---|
| 14 | 6 | * |
|---|
| 15 | 7 | * Author: Yang, Bin <bin.yang@intel.com> |
|---|
| 16 | 8 | */ |
|---|
| 17 | 9 | |
|---|
| 10 | +#include <linux/bitops.h> |
|---|
| 11 | +#include <linux/gpio/driver.h> |
|---|
| 18 | 12 | #include <linux/interrupt.h> |
|---|
| 13 | +#include <linux/mfd/intel_soc_pmic.h> |
|---|
| 19 | 14 | #include <linux/module.h> |
|---|
| 20 | 15 | #include <linux/platform_device.h> |
|---|
| 21 | | -#include <linux/gpio/driver.h> |
|---|
| 22 | | -#include <linux/seq_file.h> |
|---|
| 23 | | -#include <linux/bitops.h> |
|---|
| 24 | 16 | #include <linux/regmap.h> |
|---|
| 25 | | -#include <linux/mfd/intel_soc_pmic.h> |
|---|
| 17 | +#include <linux/seq_file.h> |
|---|
| 26 | 18 | |
|---|
| 27 | 19 | #define CRYSTALCOVE_GPIO_NUM 16 |
|---|
| 28 | 20 | #define CRYSTALCOVE_VGPIO_NUM 95 |
|---|
| .. | .. |
|---|
| 137 | 129 | regmap_update_bits(cg->regmap, reg, CTLI_INTCNT_BE, cg->intcnt_value); |
|---|
| 138 | 130 | } |
|---|
| 139 | 131 | |
|---|
| 140 | | -static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned gpio) |
|---|
| 132 | +static int crystalcove_gpio_dir_in(struct gpio_chip *chip, unsigned int gpio) |
|---|
| 141 | 133 | { |
|---|
| 142 | 134 | struct crystalcove_gpio *cg = gpiochip_get_data(chip); |
|---|
| 143 | 135 | int reg = to_reg(gpio, CTRL_OUT); |
|---|
| .. | .. |
|---|
| 148 | 140 | return regmap_write(cg->regmap, reg, CTLO_INPUT_SET); |
|---|
| 149 | 141 | } |
|---|
| 150 | 142 | |
|---|
| 151 | | -static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned gpio, |
|---|
| 143 | +static int crystalcove_gpio_dir_out(struct gpio_chip *chip, unsigned int gpio, |
|---|
| 152 | 144 | int value) |
|---|
| 153 | 145 | { |
|---|
| 154 | 146 | struct crystalcove_gpio *cg = gpiochip_get_data(chip); |
|---|
| .. | .. |
|---|
| 160 | 152 | return regmap_write(cg->regmap, reg, CTLO_OUTPUT_SET | value); |
|---|
| 161 | 153 | } |
|---|
| 162 | 154 | |
|---|
| 163 | | -static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned gpio) |
|---|
| 155 | +static int crystalcove_gpio_get(struct gpio_chip *chip, unsigned int gpio) |
|---|
| 164 | 156 | { |
|---|
| 165 | 157 | struct crystalcove_gpio *cg = gpiochip_get_data(chip); |
|---|
| 166 | 158 | unsigned int val; |
|---|
| .. | .. |
|---|
| 177 | 169 | } |
|---|
| 178 | 170 | |
|---|
| 179 | 171 | static void crystalcove_gpio_set(struct gpio_chip *chip, |
|---|
| 180 | | - unsigned gpio, int value) |
|---|
| 172 | + unsigned int gpio, int value) |
|---|
| 181 | 173 | { |
|---|
| 182 | 174 | struct crystalcove_gpio *cg = gpiochip_get_data(chip); |
|---|
| 183 | 175 | int reg = to_reg(gpio, CTRL_OUT); |
|---|
| .. | .. |
|---|
| 191 | 183 | regmap_update_bits(cg->regmap, reg, 1, 0); |
|---|
| 192 | 184 | } |
|---|
| 193 | 185 | |
|---|
| 194 | | -static int crystalcove_irq_type(struct irq_data *data, unsigned type) |
|---|
| 186 | +static int crystalcove_irq_type(struct irq_data *data, unsigned int type) |
|---|
| 195 | 187 | { |
|---|
| 196 | 188 | struct crystalcove_gpio *cg = |
|---|
| 197 | 189 | gpiochip_get_data(irq_data_get_irq_chip_data(data)); |
|---|
| .. | .. |
|---|
| 279 | 271 | static irqreturn_t crystalcove_gpio_irq_handler(int irq, void *data) |
|---|
| 280 | 272 | { |
|---|
| 281 | 273 | struct crystalcove_gpio *cg = data; |
|---|
| 274 | + unsigned long pending; |
|---|
| 282 | 275 | unsigned int p0, p1; |
|---|
| 283 | | - int pending; |
|---|
| 284 | 276 | int gpio; |
|---|
| 285 | 277 | unsigned int virq; |
|---|
| 286 | 278 | |
|---|
| .. | .. |
|---|
| 293 | 285 | |
|---|
| 294 | 286 | pending = p0 | p1 << 8; |
|---|
| 295 | 287 | |
|---|
| 296 | | - for (gpio = 0; gpio < CRYSTALCOVE_GPIO_NUM; gpio++) { |
|---|
| 297 | | - if (pending & BIT(gpio)) { |
|---|
| 298 | | - virq = irq_find_mapping(cg->chip.irq.domain, gpio); |
|---|
| 299 | | - handle_nested_irq(virq); |
|---|
| 300 | | - } |
|---|
| 288 | + for_each_set_bit(gpio, &pending, CRYSTALCOVE_GPIO_NUM) { |
|---|
| 289 | + virq = irq_find_mapping(cg->chip.irq.domain, gpio); |
|---|
| 290 | + handle_nested_irq(virq); |
|---|
| 301 | 291 | } |
|---|
| 302 | 292 | |
|---|
| 303 | 293 | return IRQ_HANDLED; |
|---|
| .. | .. |
|---|
| 340 | 330 | int retval; |
|---|
| 341 | 331 | struct device *dev = pdev->dev.parent; |
|---|
| 342 | 332 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); |
|---|
| 333 | + struct gpio_irq_chip *girq; |
|---|
| 343 | 334 | |
|---|
| 344 | 335 | if (irq < 0) |
|---|
| 345 | 336 | return irq; |
|---|
| .. | .. |
|---|
| 363 | 354 | cg->chip.dbg_show = crystalcove_gpio_dbg_show; |
|---|
| 364 | 355 | cg->regmap = pmic->regmap; |
|---|
| 365 | 356 | |
|---|
| 357 | + girq = &cg->chip.irq; |
|---|
| 358 | + girq->chip = &crystalcove_irqchip; |
|---|
| 359 | + /* This will let us handle the parent IRQ in the driver */ |
|---|
| 360 | + girq->parent_handler = NULL; |
|---|
| 361 | + girq->num_parents = 0; |
|---|
| 362 | + girq->parents = NULL; |
|---|
| 363 | + girq->default_type = IRQ_TYPE_NONE; |
|---|
| 364 | + girq->handler = handle_simple_irq; |
|---|
| 365 | + girq->threaded = true; |
|---|
| 366 | + |
|---|
| 367 | + retval = devm_request_threaded_irq(&pdev->dev, irq, NULL, |
|---|
| 368 | + crystalcove_gpio_irq_handler, |
|---|
| 369 | + IRQF_ONESHOT, KBUILD_MODNAME, cg); |
|---|
| 370 | + if (retval) { |
|---|
| 371 | + dev_warn(&pdev->dev, "request irq failed: %d\n", retval); |
|---|
| 372 | + return retval; |
|---|
| 373 | + } |
|---|
| 374 | + |
|---|
| 366 | 375 | retval = devm_gpiochip_add_data(&pdev->dev, &cg->chip, cg); |
|---|
| 367 | 376 | if (retval) { |
|---|
| 368 | 377 | dev_warn(&pdev->dev, "add gpio chip error: %d\n", retval); |
|---|
| 369 | 378 | return retval; |
|---|
| 370 | 379 | } |
|---|
| 371 | 380 | |
|---|
| 372 | | - gpiochip_irqchip_add_nested(&cg->chip, &crystalcove_irqchip, 0, |
|---|
| 373 | | - handle_simple_irq, IRQ_TYPE_NONE); |
|---|
| 374 | | - |
|---|
| 375 | | - retval = request_threaded_irq(irq, NULL, crystalcove_gpio_irq_handler, |
|---|
| 376 | | - IRQF_ONESHOT, KBUILD_MODNAME, cg); |
|---|
| 377 | | - |
|---|
| 378 | | - if (retval) { |
|---|
| 379 | | - dev_warn(&pdev->dev, "request irq failed: %d\n", retval); |
|---|
| 380 | | - return retval; |
|---|
| 381 | | - } |
|---|
| 382 | | - |
|---|
| 383 | | - gpiochip_set_nested_irqchip(&cg->chip, &crystalcove_irqchip, irq); |
|---|
| 384 | | - |
|---|
| 385 | | - return 0; |
|---|
| 386 | | -} |
|---|
| 387 | | - |
|---|
| 388 | | -static int crystalcove_gpio_remove(struct platform_device *pdev) |
|---|
| 389 | | -{ |
|---|
| 390 | | - struct crystalcove_gpio *cg = platform_get_drvdata(pdev); |
|---|
| 391 | | - int irq = platform_get_irq(pdev, 0); |
|---|
| 392 | | - |
|---|
| 393 | | - if (irq >= 0) |
|---|
| 394 | | - free_irq(irq, cg); |
|---|
| 395 | 381 | return 0; |
|---|
| 396 | 382 | } |
|---|
| 397 | 383 | |
|---|
| 398 | 384 | static struct platform_driver crystalcove_gpio_driver = { |
|---|
| 399 | 385 | .probe = crystalcove_gpio_probe, |
|---|
| 400 | | - .remove = crystalcove_gpio_remove, |
|---|
| 401 | 386 | .driver = { |
|---|
| 402 | 387 | .name = "crystal_cove_gpio", |
|---|
| 403 | 388 | }, |
|---|
| 404 | 389 | }; |
|---|
| 405 | | - |
|---|
| 406 | 390 | module_platform_driver(crystalcove_gpio_driver); |
|---|
| 407 | 391 | |
|---|
| 408 | 392 | MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>"); |
|---|