gpio updates for v6.7-rc1

GPIOLIB core:
 - provide interfaces allowing users to retrieve, manage and query the
   reference counted GPIO device instead of accessing the private gpio_chip
   structure
 - replace gpiochip_find() with gpio_device_find()
 - remove unused acpi_get_and_request_gpiod()
 - improve the ignore_interrupt functionality in GPIO ACPI
 - correct notifier return codes in gpiolib-of
 - unexport gpiod_set_transitory() as it's unused outside of core GPIO code
 - while there are still external users accessing struct gpio_chip, let's
   make gpiochip_get_desc() public so that they at least use the preferred
   helper
 - improve locking for lookup tables
 - annotate struct linereq with __counted_by
 - improve GPIOLIB docs
 - add an OF quirk for LED trigger sources
 
 Driver improvements:
 - convert all GPIO drivers with .remove() callbacks to using the new
   variant returning void instead of int
 - stop accessing the GPIOLIB private structures in gpio-mockup,
   i2c-mux-gpio, hte-tegra194, gpio-sim
 - use the recommended pattern for autofree variables in gpio-sim
 - add support for more models to gpio-loongson
 - use a notifier chain to notify other blocks about interrupts in
   gpio-eic-sprd instead of looking up GPIO devices on every interrupt
 - convert gpio-pca953x and gpio-fx6408 to using the maple tree regmap
   cache
 - don't include GPIOLIB internal headers in drivers which don't need them
 - move the ingenic NAND quirk into gpiolib-of
 - add an ignore interrupt quirk for Peaq C1010
 - drop static GPIO base from gpio-omap, gpio-f7188x
 - use the preferred device_get_match_data() function in drivers that still
   don't
 - refactor gpio-pca953x: switch to using DEFINE_SIMPLE_DEV_PM_OPS(), use
   cleanup helpers, use dev_err_probe() where it makes sense, fully convert
   to using devres and some other minor tweaks
 
 DT bindings:
 - add support for a new model to gpio-vf610 and update existing properties
 - add support for more loongson models
 - add missing support for imx models that are used but undocumented
 - convert bindings for Intel IXP4xx to schema
 
 Minor stuff:
 - deprecate gpio-mockup in favor of gpio-sim
 - include missing headers here and there
 - stop using gpiochip_find() in OMAP1 board files
 - minor tweaks in gpio-vf610, gpio-hisi
 - remove unneeded 'extern' specifiers from headers
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmU7ixgACgkQEacuoBRx
 13JwfxAA4CeZdXdUpx6EMUw+6ST4EWb5JanrPjNcQbyBxNFrHx+6yJJL4AOQJStQ
 WkG+Zi8Li9uV3wZQixBDs0WN8xVwJU+4QLSwwtNhEjl2x9MkVjghh4la6TqBrMj8
 e/iJufTyKUgcm2P4MRTDXFarAin4doBQUPKWfCgL18VvlKxLXG0KMndUl3jAd/Rm
 YZLm4Z/iqWaxjfrm+E9LfWFmWS5T7t/g+7TYzMp2AHQ9dHFiwoodpiHTkdWH4dfL
 zxF8Ek2132Up0BYC1lQlwz1aoLIlHcr9xVOqOrIxZI/B5xRcUfoXnQQmCCfH2UYr
 wtfwKMI7IO2d5E+F7anFC67d9wm7tWacKEifw9lWUAD6xr6yv/13ZOU6aoWXj1Vq
 xOMe6gEeZSboF/XiqlmrpZYH+ljDp/mYWkGcOJrUg7WYUgvUCFWu6l6DmuUFMr7m
 ACtOUqwbTuWTXN28QtMOpjiQRqlAWyrY6PqhBCllhmcjsoVaZNgWEfriPlSOyoBg
 EBRBcURXLs7/h86nEsK/8BIsC0myHbpNiNpG5qaMjrrYJxMh4qS4MIG83MWAy1dZ
 8ZtYrxx4XClyaYwYomsIkseLaSCrBTIoYws7wmyTjYfKC7P/t6/XXPS1suyMnf9I
 /n5tN8Rv1pDrnS3iQflHQVl9H5m4yezHOOBJUiWW+gs5MUr4vK0=
 =1QF8
 -----END PGP SIGNATURE-----

Merge tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio updates from Bartosz Golaszewski:
 "We don't have any new drivers. The loongson driver is getting extended
  with support for new models. There's a big refactor of gpio-pca953x
  and many small improvements to others.

  The GPIO code in the kernel has acquired a lot of cruft over the years
  as well as many abusers of the API across the kernel tree. This
  release cycle we have started a major cleanup and improvement effort
  that will most likely span several releases. We have started by
  converting external users of struct gpio_chip to accessing the wrapper
  around it - struct gpio_device. This is because the latter is
  reference counted while the former is removed when the provider is
  unbound. We also removed several instances of drivers accessing
  private GPIOLIB structures and including the private header from
  drivers/gpio/.

  To that end you'll see several commits aimed at different subsystems
  (acked by relevant maintainers) as well as two merges from the
  x86/platform tree.

  We'll then rework the locking in GPIOLIB which currently uses a big
  spinlock for many different things and could use becoming more
  fine-grained, especially as it doesn't even get the locking right.
  We'll also use SRCU for protecting the gpio_chip pointer against
  in-kernel hot-unplug crashes similar to what we saw triggered from
  user-space and fixed with semaphores in gpiolib-cdev. The core GPIOLIB
  is still vulnerable to these use-cases. I'm just mentioning the plans
  here, this is not part of this PR.

  You'll see some new instances of using __free(). We've added a
  gpio_device_put cleanup helper similar to the put_device one
  introduced by Peter Zijlstra and used it according to the preferred
  pattern except where it didn't make sense.

  GPIOLIB core:
   - provide interfaces allowing users to retrieve, manage and query the
     reference counted GPIO device instead of accessing the private
     gpio_chip structure
   - replace gpiochip_find() with gpio_device_find()
   - remove unused acpi_get_and_request_gpiod()
   - improve the ignore_interrupt functionality in GPIO ACPI
   - correct notifier return codes in gpiolib-of
   - unexport gpiod_set_transitory() as it's unused outside of core GPIO
     code
   - while there are still external users accessing struct gpio_chip,
     let's make gpiochip_get_desc() public so that they at least use the
     preferred helper
   - improve locking for lookup tables
   - annotate struct linereq with __counted_by
   - improve GPIOLIB docs
   - add an OF quirk for LED trigger sources

  Driver improvements:
   - convert all GPIO drivers with .remove() callbacks to using the new
     variant returning void instead of int
   - stop accessing the GPIOLIB private structures in gpio-mockup,
     i2c-mux-gpio, hte-tegra194, gpio-sim
   - use the recommended pattern for autofree variables in gpio-sim
   - add support for more models to gpio-loongson
   - use a notifier chain to notify other blocks about interrupts in
     gpio-eic-sprd instead of looking up GPIO devices on every interrupt
   - convert gpio-pca953x and gpio-fx6408 to using the maple tree regmap
     cache
   - don't include GPIOLIB internal headers in drivers which don't need
     them
   - move the ingenic NAND quirk into gpiolib-of
   - add an ignore interrupt quirk for Peaq C1010
   - drop static GPIO base from gpio-omap, gpio-f7188x
   - use the preferred device_get_match_data() function in drivers that
     still don't
   - refactor gpio-pca953x: switch to using DEFINE_SIMPLE_DEV_PM_OPS(),
     use cleanup helpers, use dev_err_probe() where it makes sense,
     fully convert to using devres and some other minor tweaks

  DT bindings:
   - add support for a new model to gpio-vf610 and update existing
     properties
   - add support for more loongson models
   - add missing support for imx models that are used but undocumented
   - convert bindings for Intel IXP4xx to schema

  Minor stuff:
   - deprecate gpio-mockup in favor of gpio-sim
   - include missing headers here and there
   - stop using gpiochip_find() in OMAP1 board files
   - minor tweaks in gpio-vf610, gpio-hisi
   - remove unneeded 'extern' specifiers from headers"

* tag 'gpio-updates-for-v6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (108 commits)
  hte: tegra194: add GPIOLIB dependency
  hte: tegra194: don't access struct gpio_chip
  gpiolib: provide gpio_device_get_base()
  i2c: mux: gpio: don't fiddle with GPIOLIB internals
  gpiolib: provide gpiod_to_gpio_device()
  gpiolib: provide gpio_device_to_device()
  gpio: hisi: Fix format specifier
  gpiolib: provide gpio_device_find_by_fwnode()
  gpio: acpi: remove acpi_get_and_request_gpiod()
  gpio: Use device_get_match_data()
  gpio: vf610: update comment for i.MX8ULP and i.MX93 legacy compatibles
  platform/x86: int3472: Switch to devm_get_gpiod()
  platform/x86: int3472: Stop using gpiod_toggle_active_low()
  platform/x86: int3472: Add new skl_int3472_gpiod_get_from_temp_lookup() helper
  platform/x86: int3472: Add new skl_int3472_fill_gpiod_lookup() helper
  gpio: vf610: simplify code by dropping data check
  gpio: vf610: add i.MX8ULP of_device_id entry
  dt-bindings: gpio: vf610: add i.MX95 compatible
  dt-bindings: gpio: vf610: correct i.MX8ULP and i.MX93
  dt-bindings: gpio: vf610: update gpio-ranges
  ...
This commit is contained in:
Linus Torvalds 2023-10-31 17:21:54 -10:00
commit b05ddad009
71 changed files with 1336 additions and 927 deletions

View File

@ -18,9 +18,17 @@ properties:
- fsl,imx31-gpio
- fsl,imx35-gpio
- fsl,imx7d-gpio
- items:
- enum:
- fsl,imx27-gpio
- const: fsl,imx21-gpio
- items:
- const: fsl,imx35-gpio
- const: fsl,imx31-gpio
- items:
- enum:
- fsl,imx25-gpio
- const: fsl,imx35-gpio
- items:
- enum:
- fsl,imx50-gpio

View File

@ -20,6 +20,7 @@ description: |
properties:
compatible:
oneOf:
- const: fsl,imx8ulp-gpio
- const: fsl,vf610-gpio
- items:
- const: fsl,imx7ulp-gpio
@ -27,16 +28,18 @@ properties:
- items:
- enum:
- fsl,imx93-gpio
- fsl,imx8ulp-gpio
- const: fsl,imx7ulp-gpio
- fsl,imx95-gpio
- const: fsl,imx8ulp-gpio
reg:
description: The first reg tuple represents the PORT module, the second tuple
represents the GPIO module.
minItems: 1
maxItems: 2
interrupts:
maxItems: 1
items:
- description: GPIO Trustzone non-secure interrupt number
- description: GPIO Trustzone secure interrupt number
minItems: 1
interrupt-controller: true
@ -59,7 +62,8 @@ properties:
- const: port
gpio-ranges:
maxItems: 1
minItems: 1
maxItems: 4
patternProperties:
"^.+-hog(-[0-9]+)?$":
@ -77,6 +81,30 @@ required:
- "#gpio-cells"
- gpio-controller
allOf:
- if:
properties:
compatible:
contains:
enum:
- fsl,vf610-gpio
- fsl,imx7ulp-gpio
then:
properties:
interrupts:
maxItems: 1
reg:
items:
- description: PORT register base address
- description: GPIO register base address
else:
properties:
interrupts:
minItems: 2
reg:
items:
- description: GPIO register base address
additionalProperties: false
examples:

View File

@ -1,38 +0,0 @@
Intel IXP4xx XScale Networking Processors GPIO
This GPIO controller is found in the Intel IXP4xx processors.
It supports 16 GPIO lines.
The interrupt portions of the GPIO controller is hierarchical:
the synchronous edge detector is part of the GPIO block, but the
actual enabling/disabling of the interrupt line is done in the
main IXP4xx interrupt controller which has a 1:1 mapping for
the first 12 GPIO lines to 12 system interrupts.
The remaining 4 GPIO lines can not be used for receiving
interrupts.
The interrupt parent of this GPIO controller must be the
IXP4xx interrupt controller.
Required properties:
- compatible : Should be
"intel,ixp4xx-gpio"
- reg : Should contain registers location and length
- gpio-controller : marks this as a GPIO controller
- #gpio-cells : Should be 2, see gpio/gpio.txt
- interrupt-controller : marks this as an interrupt controller
- #interrupt-cells : a standard two-cell interrupt, see
interrupt-controller/interrupts.txt
Example:
gpio0: gpio@c8004000 {
compatible = "intel,ixp4xx-gpio";
reg = <0xc8004000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};

View File

@ -0,0 +1,73 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/intel,ixp4xx-gpio.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Intel IXP4xx XScale Networking Processors GPIO Controller
description: |
This GPIO controller is found in the Intel IXP4xx
processors. It supports 16 GPIO lines.
The interrupt portions of the GPIO controller is hierarchical.
The synchronous edge detector is part of the GPIO block, but the
actual enabling/disabling of the interrupt line is done in the
main IXP4xx interrupt controller which has a 1-to-1 mapping for
the first 12 GPIO lines to 12 system interrupts.
The remaining 4 GPIO lines can not be used for receiving
interrupts.
The interrupt parent of this GPIO controller must be the
IXP4xx interrupt controller.
GPIO 14 and 15 can be used as clock outputs rather than GPIO,
and this can be enabled by a special flag.
maintainers:
- Linus Walleij <linus.walleij@linaro.org>
properties:
compatible:
const: intel,ixp4xx-gpio
reg:
maxItems: 1
gpio-controller: true
"#gpio-cells":
const: 2
interrupt-controller: true
"#interrupt-cells":
const: 2
intel,ixp4xx-gpio14-clkout:
description: If defined, enables clock output on GPIO 14
instead of GPIO.
type: boolean
intel,ixp4xx-gpio15-clkout:
description: If defined, enables clock output on GPIO 15
instead of GPIO.
type: boolean
required:
- compatible
- reg
- "#gpio-cells"
- interrupt-controller
- "#interrupt-cells"
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
gpio@c8004000 {
compatible = "intel,ixp4xx-gpio";
reg = <0xc8004000 0x1000>;
gpio-controller;
#gpio-cells = <2>;
interrupt-controller;
#interrupt-cells = <2>;
};

View File

@ -11,9 +11,22 @@ maintainers:
properties:
compatible:
enum:
- loongson,ls2k-gpio
- loongson,ls7a-gpio
oneOf:
- enum:
- loongson,ls2k-gpio
- loongson,ls2k0500-gpio0
- loongson,ls2k0500-gpio1
- loongson,ls2k2000-gpio0
- loongson,ls2k2000-gpio1
- loongson,ls2k2000-gpio2
- loongson,ls3a5000-gpio
- loongson,ls7a-gpio
- items:
- const: loongson,ls2k1000-gpio
- const: loongson,ls2k-gpio
- items:
- const: loongson,ls7a1000-gpio
- const: loongson,ls7a-gpio
reg:
maxItems: 1
@ -49,7 +62,7 @@ examples:
#include <dt-bindings/interrupt-controller/irq.h>
gpio0: gpio@1fe00500 {
compatible = "loongson,ls2k-gpio";
compatible = "loongson,ls2k1000-gpio", "loongson,ls2k-gpio";
reg = <0x1fe00500 0x38>;
ngpios = <64>;
#gpio-cells = <2>;

View File

@ -29,6 +29,10 @@ warnings. These stubs are used for two use cases:
will use it under other compile-time configurations. In this case the
consumer must make sure not to call into these functions, or the user will
be met with console warnings that may be perceived as intimidating.
Combining truly optional GPIOLIB usage with calls to
``[devm_]gpiod_get_optional()`` is a *bad idea*, and will result in weird
error messages. Use the ordinary getter functions with optional GPIOLIB:
some open coding of error handling should be expected when you do this.
All the functions that work with the descriptor-based GPIO interface are
prefixed with ``gpiod_``. The ``gpio_`` prefix is used for the legacy

View File

@ -2224,7 +2224,7 @@ M: Imre Kaloz <kaloz@openwrt.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/arm/intel-ixp4xx.yaml
F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.txt
F: Documentation/devicetree/bindings/gpio/intel,ixp4xx-gpio.yaml
F: Documentation/devicetree/bindings/interrupt-controller/intel,ixp4xx-interrupt.yaml
F: Documentation/devicetree/bindings/memory-controllers/intel,ixp4xx-expansion*
F: Documentation/devicetree/bindings/rng/intel,ixp46x-rng.yaml

View File

@ -561,22 +561,6 @@ static struct gpiod_lookup_table *ams_delta_gpio_tables[] __initdata = {
&ams_delta_nand_gpio_table,
};
/*
* Some drivers may not use GPIO lookup tables but need to be provided
* with GPIO numbers. The same applies to GPIO based IRQ lines - some
* drivers may even not use GPIO layer but expect just IRQ numbers.
* We could either define GPIO lookup tables then use them on behalf
* of those devices, or we can use GPIO driver level methods for
* identification of GPIO and IRQ numbers. For the purpose of the latter,
* defina a helper function which identifies GPIO chips by their labels.
*/
static int gpiochip_match_by_label(struct gpio_chip *chip, void *data)
{
char *label = data;
return !strcmp(label, chip->label);
}
static struct gpiod_hog ams_delta_gpio_hogs[] = {
GPIO_HOG(LATCH2_LABEL, LATCH2_PIN_KEYBRD_DATAOUT, "keybrd_dataout",
GPIO_ACTIVE_HIGH, GPIOD_OUT_LOW),
@ -616,14 +600,28 @@ static void __init modem_assign_irq(struct gpio_chip *chip)
*/
static void __init omap_gpio_deps_init(void)
{
struct gpio_device *gdev;
struct gpio_chip *chip;
chip = gpiochip_find(OMAP_GPIO_LABEL, gpiochip_match_by_label);
if (!chip) {
pr_err("%s: OMAP GPIO chip not found\n", __func__);
/*
* Some drivers may not use GPIO lookup tables but need to be provided
* with GPIO numbers. The same applies to GPIO based IRQ lines - some
* drivers may even not use GPIO layer but expect just IRQ numbers.
* We could either define GPIO lookup tables then use them on behalf
* of those devices, or we can use GPIO driver level methods for
* identification of GPIO and IRQ numbers.
*
* This reference will be leaked but that's alright as this device
* never goes down.
*/
gdev = gpio_device_find_by_label(OMAP_GPIO_LABEL);
if (!gdev) {
pr_err("%s: OMAP GPIO device not found\n", __func__);
return;
}
chip = gpio_device_get_chip(gdev);
/*
* Start with FIQ initialization as it may have to request
* and release successfully each OMAP GPIO pin in turn.

View File

@ -51,11 +51,6 @@
#define PALMTE_HDQ_GPIO 11
#define PALMTE_HEADPHONES_GPIO 14
#define PALMTE_SPEAKER_GPIO 15
#define PALMTE_DC_GPIO OMAP_MPUIO(2)
#define PALMTE_MMC_SWITCH_GPIO OMAP_MPUIO(4)
#define PALMTE_MMC1_GPIO OMAP_MPUIO(6)
#define PALMTE_MMC2_GPIO OMAP_MPUIO(7)
#define PALMTE_MMC3_GPIO OMAP_MPUIO(11)
static const unsigned int palmte_keymap[] = {
KEY(0, 0, KEY_F1), /* Calendar */

View File

@ -1790,9 +1790,11 @@ config GPIO_LATCH
connected to other GPIOs.
config GPIO_MOCKUP
tristate "GPIO Testing Driver"
tristate "GPIO Testing Driver (DEPRECATED)"
select IRQ_SIM
help
This module is DEPRECATED. Please consider using gpio-sim instead.
This enables GPIO Testing driver, which provides a way to test GPIO
subsystem through sysfs (or char device) and debugfs.
User could use it through the script in

View File

@ -317,13 +317,11 @@ static int altera_gpio_probe(struct platform_device *pdev)
return 0;
}
static int altera_gpio_remove(struct platform_device *pdev)
static void altera_gpio_remove(struct platform_device *pdev)
{
struct altera_gpio_chip *altera_gc = platform_get_drvdata(pdev);
of_mm_gpiochip_remove(&altera_gc->mmchip);
return 0;
}
static const struct of_device_id altera_gpio_of_match[] = {
@ -338,7 +336,7 @@ static struct platform_driver altera_gpio_driver = {
.of_match_table = altera_gpio_of_match,
},
.probe = altera_gpio_probe,
.remove = altera_gpio_remove,
.remove_new = altera_gpio_remove,
};
static int __init altera_gpio_init(void)

View File

@ -122,13 +122,11 @@ static int pt_gpio_probe(struct platform_device *pdev)
return ret;
}
static int pt_gpio_remove(struct platform_device *pdev)
static void pt_gpio_remove(struct platform_device *pdev)
{
struct pt_gpio_chip *pt_gpio = platform_get_drvdata(pdev);
gpiochip_remove(&pt_gpio->gc);
return 0;
}
static const struct acpi_device_id pt_gpio_acpi_match[] = {
@ -145,7 +143,7 @@ static struct platform_driver pt_gpio_driver = {
.acpi_match_table = ACPI_PTR(pt_gpio_acpi_match),
},
.probe = pt_gpio_probe,
.remove = pt_gpio_remove,
.remove_new = pt_gpio_remove,
};
module_platform_driver(pt_gpio_driver);

View File

@ -371,7 +371,7 @@ static int brcmstb_gpio_sanity_check_banks(struct device *dev,
}
}
static int brcmstb_gpio_remove(struct platform_device *pdev)
static void brcmstb_gpio_remove(struct platform_device *pdev)
{
struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev);
struct brcmstb_gpio_bank *bank;
@ -395,8 +395,6 @@ static int brcmstb_gpio_remove(struct platform_device *pdev)
*/
list_for_each_entry(bank, &priv->bank_list, node)
gpiochip_remove(&bank->gc);
return 0;
}
static int brcmstb_gpio_of_xlate(struct gpio_chip *gc,
@ -757,7 +755,7 @@ static struct platform_driver brcmstb_gpio_driver = {
.pm = &brcmstb_gpio_pm_ops,
},
.probe = brcmstb_gpio_probe,
.remove = brcmstb_gpio_remove,
.remove_new = brcmstb_gpio_remove,
.shutdown = brcmstb_gpio_shutdown,
};
module_platform_driver(brcmstb_gpio_driver);

View File

@ -268,14 +268,12 @@ static int cdns_gpio_probe(struct platform_device *pdev)
return ret;
}
static int cdns_gpio_remove(struct platform_device *pdev)
static void cdns_gpio_remove(struct platform_device *pdev)
{
struct cdns_gpio_chip *cgpio = platform_get_drvdata(pdev);
iowrite32(cgpio->bypass_orig, cgpio->regs + CDNS_GPIO_BYPASS_MODE);
clk_disable_unprepare(cgpio->pclk);
return 0;
}
static const struct of_device_id cdns_of_ids[] = {
@ -290,7 +288,7 @@ static struct platform_driver cdns_gpio_driver = {
.of_match_table = cdns_of_ids,
},
.probe = cdns_gpio_probe,
.remove = cdns_gpio_remove,
.remove_new = cdns_gpio_remove,
};
module_platform_driver(cdns_gpio_driver);

View File

@ -16,10 +16,10 @@
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/platform_data/gpio-davinci.h>
#include <linux/property.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/spinlock.h>
#include <linux/pm_runtime.h>
@ -486,7 +486,6 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
struct davinci_gpio_platform_data *pdata = dev->platform_data;
struct davinci_gpio_regs __iomem *g;
struct irq_domain *irq_domain = NULL;
const struct of_device_id *match;
struct irq_chip *irq_chip;
struct davinci_gpio_irq_data *irqdata;
gpio_get_irq_chip_cb_t gpio_get_irq_chip;
@ -495,10 +494,8 @@ static int davinci_gpio_irq_setup(struct platform_device *pdev)
* Use davinci_gpio_get_irq_chip by default to handle non DT cases
*/
gpio_get_irq_chip = davinci_gpio_get_irq_chip;
match = of_match_device(of_match_ptr(davinci_gpio_ids),
dev);
if (match)
gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)match->data;
if (dev->of_node)
gpio_get_irq_chip = (gpio_get_irq_chip_cb_t)device_get_match_data(dev);
ngpio = pdata->ngpio;

View File

@ -504,17 +504,15 @@ static int dln2_gpio_probe(struct platform_device *pdev)
return 0;
}
static int dln2_gpio_remove(struct platform_device *pdev)
static void dln2_gpio_remove(struct platform_device *pdev)
{
dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV);
return 0;
}
static struct platform_driver dln2_gpio_driver = {
.driver.name = "dln2-gpio",
.probe = dln2_gpio_probe,
.remove = dln2_gpio_remove,
.remove_new = dln2_gpio_remove,
};
module_platform_driver(dln2_gpio_driver);

View File

@ -21,7 +21,6 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include "gpiolib.h"
#include "gpiolib-acpi.h"
#define GPIO_SWPORTA_DR 0x00

View File

@ -9,6 +9,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/notifier.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@ -91,12 +92,20 @@ enum sprd_eic_type {
struct sprd_eic {
struct gpio_chip chip;
struct notifier_block irq_nb;
void __iomem *base[SPRD_EIC_MAX_BANK];
enum sprd_eic_type type;
spinlock_t lock;
int irq;
};
static ATOMIC_NOTIFIER_HEAD(sprd_eic_irq_notifier);
static struct sprd_eic *to_sprd_eic(struct notifier_block *nb)
{
return container_of(nb, struct sprd_eic, irq_nb);
}
struct sprd_eic_variant_data {
enum sprd_eic_type type;
u32 num_eics;
@ -494,13 +503,6 @@ static void sprd_eic_toggle_trigger(struct gpio_chip *chip, unsigned int irq,
sprd_eic_irq_unmask(data);
}
static int sprd_eic_match_chip_by_type(struct gpio_chip *chip, void *data)
{
enum sprd_eic_type type = *(enum sprd_eic_type *)data;
return !strcmp(chip->label, sprd_eic_label_name[type]);
}
static void sprd_eic_handle_one_type(struct gpio_chip *chip)
{
struct sprd_eic *sprd_eic = gpiochip_get_data(chip);
@ -546,27 +548,29 @@ static void sprd_eic_handle_one_type(struct gpio_chip *chip)
static void sprd_eic_irq_handler(struct irq_desc *desc)
{
struct irq_chip *ic = irq_desc_get_chip(desc);
struct gpio_chip *chip;
enum sprd_eic_type type;
chained_irq_enter(ic, desc);
/*
* Since the digital-chip EIC 4 sub-modules (debounce, latch, async
* and sync) share one same interrupt line, we should iterate each
* EIC module to check if there are EIC interrupts were triggered.
* and sync) share one same interrupt line, we should notify all of
* them to let them check if there are EIC interrupts were triggered.
*/
for (type = SPRD_EIC_DEBOUNCE; type < SPRD_EIC_MAX; type++) {
chip = gpiochip_find(&type, sprd_eic_match_chip_by_type);
if (!chip)
continue;
sprd_eic_handle_one_type(chip);
}
atomic_notifier_call_chain(&sprd_eic_irq_notifier, 0, NULL);
chained_irq_exit(ic, desc);
}
static int sprd_eic_irq_notify(struct notifier_block *nb, unsigned long action,
void *data)
{
struct sprd_eic *sprd_eic = to_sprd_eic(nb);
sprd_eic_handle_one_type(&sprd_eic->chip);
return NOTIFY_OK;
}
static const struct irq_chip sprd_eic_irq = {
.name = "sprd-eic",
.irq_ack = sprd_eic_irq_ack,
@ -576,21 +580,30 @@ static const struct irq_chip sprd_eic_irq = {
.flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_IMMUTABLE,
GPIOCHIP_IRQ_RESOURCE_HELPERS,
};
static void sprd_eic_unregister_notifier(void *data)
{
struct notifier_block *nb = data;
atomic_notifier_chain_unregister(&sprd_eic_irq_notifier, nb);
}
static int sprd_eic_probe(struct platform_device *pdev)
{
const struct sprd_eic_variant_data *pdata;
struct device *dev = &pdev->dev;
struct gpio_irq_chip *irq;
struct sprd_eic *sprd_eic;
struct resource *res;
int ret, i;
pdata = of_device_get_match_data(&pdev->dev);
pdata = of_device_get_match_data(dev);
if (!pdata) {
dev_err(&pdev->dev, "No matching driver data found.\n");
dev_err(dev, "No matching driver data found.\n");
return -EINVAL;
}
sprd_eic = devm_kzalloc(&pdev->dev, sizeof(*sprd_eic), GFP_KERNEL);
sprd_eic = devm_kzalloc(dev, sizeof(*sprd_eic), GFP_KERNEL);
if (!sprd_eic)
return -ENOMEM;
@ -612,7 +625,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
if (!res)
break;
sprd_eic->base[i] = devm_ioremap_resource(&pdev->dev, res);
sprd_eic->base[i] = devm_ioremap_resource(dev, res);
if (IS_ERR(sprd_eic->base[i]))
return PTR_ERR(sprd_eic->base[i]);
}
@ -620,7 +633,7 @@ static int sprd_eic_probe(struct platform_device *pdev)
sprd_eic->chip.label = sprd_eic_label_name[sprd_eic->type];
sprd_eic->chip.ngpio = pdata->num_eics;
sprd_eic->chip.base = -1;
sprd_eic->chip.parent = &pdev->dev;
sprd_eic->chip.parent = dev;
sprd_eic->chip.direction_input = sprd_eic_direction_input;
switch (sprd_eic->type) {
case SPRD_EIC_DEBOUNCE:
@ -647,13 +660,21 @@ static int sprd_eic_probe(struct platform_device *pdev)
irq->num_parents = 1;
irq->parents = &sprd_eic->irq;
ret = devm_gpiochip_add_data(&pdev->dev, &sprd_eic->chip, sprd_eic);
ret = devm_gpiochip_add_data(dev, &sprd_eic->chip, sprd_eic);
if (ret < 0) {
dev_err(&pdev->dev, "Could not register gpiochip %d.\n", ret);
dev_err(dev, "Could not register gpiochip %d.\n", ret);
return ret;
}
return 0;
sprd_eic->irq_nb.notifier_call = sprd_eic_irq_notify;
ret = atomic_notifier_chain_register(&sprd_eic_irq_notifier,
&sprd_eic->irq_nb);
if (ret)
return dev_err_probe(dev, ret,
"Failed to register with the interrupt notifier");
return devm_add_action_or_reset(dev, sprd_eic_unregister_notifier,
&sprd_eic->irq_nb);
}
static const struct of_device_id sprd_eic_of_match[] = {

View File

@ -163,7 +163,7 @@ static void f7188x_gpio_set(struct gpio_chip *chip, unsigned offset, int value);
static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
unsigned long config);
#define F7188X_GPIO_BANK(_base, _ngpio, _regbase, _label) \
#define F7188X_GPIO_BANK(_ngpio, _regbase, _label) \
{ \
.chip = { \
.label = _label, \
@ -174,7 +174,7 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
.direction_output = f7188x_gpio_direction_out, \
.set = f7188x_gpio_set, \
.set_config = f7188x_gpio_set_config, \
.base = _base, \
.base = -1, \
.ngpio = _ngpio, \
.can_sleep = true, \
}, \
@ -191,98 +191,98 @@ static int f7188x_gpio_set_config(struct gpio_chip *chip, unsigned offset,
#define f7188x_gpio_data_single(type) ((type) == nct6126d)
static struct f7188x_gpio_bank f71869_gpio_bank[] = {
F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 6, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(6, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(6, 0x90, DRVNAME "-6"),
};
static struct f7188x_gpio_bank f71869a_gpio_bank[] = {
F7188X_GPIO_BANK(0, 6, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
F7188X_GPIO_BANK(6, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"),
};
static struct f7188x_gpio_bank f71882_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 4, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 4, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(4, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(4, 0xB0, DRVNAME "-4"),
};
static struct f7188x_gpio_bank f71889a_gpio_bank[] = {
F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
F7188X_GPIO_BANK(7, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(7, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"),
};
static struct f7188x_gpio_bank f71889_gpio_bank[] = {
F7188X_GPIO_BANK(0, 7, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 7, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
F7188X_GPIO_BANK(7, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(7, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(5, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"),
};
static struct f7188x_gpio_bank f81866_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-7"),
F7188X_GPIO_BANK(80, 8, 0x88, DRVNAME "-8"),
F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0x80, DRVNAME "-7"),
F7188X_GPIO_BANK(8, 0x88, DRVNAME "-8"),
};
static struct f7188x_gpio_bank f81804_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-3"),
F7188X_GPIO_BANK(60, 8, 0x90, DRVNAME "-4"),
F7188X_GPIO_BANK(70, 8, 0x80, DRVNAME "-5"),
F7188X_GPIO_BANK(90, 8, 0x98, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0x90, DRVNAME "-4"),
F7188X_GPIO_BANK(8, 0x80, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0x98, DRVNAME "-6"),
};
static struct f7188x_gpio_bank f81865_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 8, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 5, 0x90, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xD0, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xC0, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xB0, DRVNAME "-4"),
F7188X_GPIO_BANK(8, 0xA0, DRVNAME "-5"),
F7188X_GPIO_BANK(5, 0x90, DRVNAME "-6"),
};
static struct f7188x_gpio_bank nct6126d_gpio_bank[] = {
F7188X_GPIO_BANK(0, 8, 0xE0, DRVNAME "-0"),
F7188X_GPIO_BANK(10, 8, 0xE4, DRVNAME "-1"),
F7188X_GPIO_BANK(20, 8, 0xE8, DRVNAME "-2"),
F7188X_GPIO_BANK(30, 8, 0xEC, DRVNAME "-3"),
F7188X_GPIO_BANK(40, 8, 0xF0, DRVNAME "-4"),
F7188X_GPIO_BANK(50, 8, 0xF4, DRVNAME "-5"),
F7188X_GPIO_BANK(60, 8, 0xF8, DRVNAME "-6"),
F7188X_GPIO_BANK(70, 8, 0xFC, DRVNAME "-7"),
F7188X_GPIO_BANK(8, 0xE0, DRVNAME "-0"),
F7188X_GPIO_BANK(8, 0xE4, DRVNAME "-1"),
F7188X_GPIO_BANK(8, 0xE8, DRVNAME "-2"),
F7188X_GPIO_BANK(8, 0xEC, DRVNAME "-3"),
F7188X_GPIO_BANK(8, 0xF0, DRVNAME "-4"),
F7188X_GPIO_BANK(8, 0xF4, DRVNAME "-5"),
F7188X_GPIO_BANK(8, 0xF8, DRVNAME "-6"),
F7188X_GPIO_BANK(8, 0xFC, DRVNAME "-7"),
};
static int f7188x_gpio_get_direction(struct gpio_chip *chip, unsigned offset)

View File

@ -324,13 +324,11 @@ static int ftgpio_gpio_probe(struct platform_device *pdev)
return ret;
}
static int ftgpio_gpio_remove(struct platform_device *pdev)
static void ftgpio_gpio_remove(struct platform_device *pdev)
{
struct ftgpio_gpio *g = platform_get_drvdata(pdev);
clk_disable_unprepare(g->clk);
return 0;
}
static const struct of_device_id ftgpio_gpio_of_match[] = {
@ -352,6 +350,6 @@ static struct platform_driver ftgpio_gpio_driver = {
.of_match_table = ftgpio_gpio_of_match,
},
.probe = ftgpio_gpio_probe,
.remove = ftgpio_gpio_remove,
.remove_new = ftgpio_gpio_remove,
};
builtin_platform_driver(ftgpio_gpio_driver);

View File

@ -84,7 +84,7 @@ static const struct regmap_config regmap = {
.rd_table = &rd_table,
.volatile_table = &volatile_table,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_MAPLE,
.num_reg_defaults_raw = FXL6408_REG_INT_STS + 1,
};

View File

@ -431,7 +431,7 @@ static int grgpio_probe(struct platform_device *ofdev)
return 0;
}
static int grgpio_remove(struct platform_device *ofdev)
static void grgpio_remove(struct platform_device *ofdev)
{
struct grgpio_priv *priv = platform_get_drvdata(ofdev);
@ -439,8 +439,6 @@ static int grgpio_remove(struct platform_device *ofdev)
if (priv->domain)
irq_domain_remove(priv->domain);
return 0;
}
static const struct of_device_id grgpio_match[] = {
@ -457,7 +455,7 @@ static struct platform_driver grgpio_driver = {
.of_match_table = grgpio_match,
},
.probe = grgpio_probe,
.remove = grgpio_remove,
.remove_new = grgpio_remove,
};
module_platform_driver(grgpio_driver);

View File

@ -255,7 +255,7 @@ static void hisi_gpio_get_pdata(struct device *dev,
hisi_gpio->irq = platform_get_irq(pdev, idx);
dev_info(dev,
"get hisi_gpio[%d] with %d lines\n", idx,
"get hisi_gpio[%d] with %u lines\n", idx,
hisi_gpio->line_num);
idx++;

View File

@ -421,7 +421,7 @@ static int ljca_gpio_probe(struct platform_device *pdev)
return ret;
}
static int ljca_gpio_remove(struct platform_device *pdev)
static void ljca_gpio_remove(struct platform_device *pdev)
{
struct ljca_gpio_dev *ljca_gpio = platform_get_drvdata(pdev);
@ -429,7 +429,6 @@ static int ljca_gpio_remove(struct platform_device *pdev)
ljca_unregister_event_cb(ljca_gpio->gpio_info->ljca);
mutex_destroy(&ljca_gpio->irq_lock);
mutex_destroy(&ljca_gpio->trans_lock);
return 0;
}
#define LJCA_GPIO_DRV_NAME "ljca-gpio"
@ -442,7 +441,7 @@ MODULE_DEVICE_TABLE(platform, ljca_gpio_id);
static struct platform_driver ljca_gpio_driver = {
.driver.name = LJCA_GPIO_DRV_NAME,
.probe = ljca_gpio_probe,
.remove = ljca_gpio_remove,
.remove_new = ljca_gpio_remove,
};
module_platform_driver(ljca_gpio_driver);

View File

@ -26,6 +26,7 @@ struct loongson_gpio_chip_data {
unsigned int conf_offset;
unsigned int out_offset;
unsigned int in_offset;
unsigned int inten_offset;
};
struct loongson_gpio_chip {
@ -117,19 +118,29 @@ static void loongson_gpio_set(struct gpio_chip *chip, unsigned int pin, int valu
static int loongson_gpio_to_irq(struct gpio_chip *chip, unsigned int offset)
{
unsigned int u;
struct platform_device *pdev = to_platform_device(chip->parent);
struct loongson_gpio_chip *lgpio = to_loongson_gpio_chip(chip);
if (lgpio->chip_data->mode == BIT_CTRL_MODE) {
/* Get the register index from offset then multiply by bytes per register */
u = readl(lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4);
u |= BIT(offset % 32);
writel(u, lgpio->reg_base + lgpio->chip_data->inten_offset + (offset / 32) * 4);
} else {
writeb(1, lgpio->reg_base + lgpio->chip_data->inten_offset + offset);
}
return platform_get_irq(pdev, offset);
}
static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgpio,
struct device_node *np, void __iomem *reg_base)
void __iomem *reg_base)
{
int ret;
u32 ngpios;
lgpio->reg_base = reg_base;
if (lgpio->chip_data->mode == BIT_CTRL_MODE) {
ret = bgpio_init(&lgpio->chip, dev, 8,
lgpio->reg_base + lgpio->chip_data->in_offset,
@ -148,15 +159,15 @@ static int loongson_gpio_init(struct device *dev, struct loongson_gpio_chip *lgp
lgpio->chip.direction_output = loongson_gpio_direction_output;
lgpio->chip.set = loongson_gpio_set;
lgpio->chip.parent = dev;
device_property_read_u32(dev, "ngpios", &ngpios);
lgpio->chip.ngpio = ngpios;
spin_lock_init(&lgpio->lock);
}
device_property_read_u32(dev, "ngpios", &ngpios);
lgpio->chip.can_sleep = 0;
lgpio->chip.ngpio = ngpios;
lgpio->chip.label = lgpio->chip_data->label;
lgpio->chip.to_irq = loongson_gpio_to_irq;
lgpio->chip.can_sleep = false;
if (lgpio->chip_data->inten_offset)
lgpio->chip.to_irq = loongson_gpio_to_irq;
return devm_gpiochip_add_data(dev, &lgpio->chip, lgpio);
}
@ -165,7 +176,6 @@ static int loongson_gpio_probe(struct platform_device *pdev)
{
void __iomem *reg_base;
struct loongson_gpio_chip *lgpio;
struct device_node *np = pdev->dev.of_node;
struct device *dev = &pdev->dev;
lgpio = devm_kzalloc(dev, sizeof(*lgpio), GFP_KERNEL);
@ -178,7 +188,7 @@ static int loongson_gpio_probe(struct platform_device *pdev)
if (IS_ERR(reg_base))
return PTR_ERR(reg_base);
return loongson_gpio_init(dev, lgpio, np, reg_base);
return loongson_gpio_init(dev, lgpio, reg_base);
}
static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
@ -187,6 +197,57 @@ static const struct loongson_gpio_chip_data loongson_gpio_ls2k_data = {
.conf_offset = 0x0,
.in_offset = 0x20,
.out_offset = 0x10,
.inten_offset = 0x30,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data0 = {
.label = "ls2k0500_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x0,
.in_offset = 0x8,
.out_offset = 0x10,
.inten_offset = 0xb0,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls2k0500_data1 = {
.label = "ls2k0500_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x0,
.in_offset = 0x8,
.out_offset = 0x10,
.inten_offset = 0x98,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data0 = {
.label = "ls2k2000_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x0,
.in_offset = 0xc,
.out_offset = 0x8,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data1 = {
.label = "ls2k2000_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x0,
.in_offset = 0x20,
.out_offset = 0x10,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls2k2000_data2 = {
.label = "ls2k2000_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x84,
.in_offset = 0x88,
.out_offset = 0x80,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls3a5000_data = {
.label = "ls3a5000_gpio",
.mode = BIT_CTRL_MODE,
.conf_offset = 0x0,
.in_offset = 0xc,
.out_offset = 0x8,
};
static const struct loongson_gpio_chip_data loongson_gpio_ls7a_data = {
@ -202,6 +263,30 @@ static const struct of_device_id loongson_gpio_of_match[] = {
.compatible = "loongson,ls2k-gpio",
.data = &loongson_gpio_ls2k_data,
},
{
.compatible = "loongson,ls2k0500-gpio0",
.data = &loongson_gpio_ls2k0500_data0,
},
{
.compatible = "loongson,ls2k0500-gpio1",
.data = &loongson_gpio_ls2k0500_data1,
},
{
.compatible = "loongson,ls2k2000-gpio0",
.data = &loongson_gpio_ls2k2000_data0,
},
{
.compatible = "loongson,ls2k2000-gpio1",
.data = &loongson_gpio_ls2k2000_data1,
},
{
.compatible = "loongson,ls2k2000-gpio2",
.data = &loongson_gpio_ls2k2000_data2,
},
{
.compatible = "loongson,ls3a5000-gpio",
.data = &loongson_gpio_ls3a5000_data,
},
{
.compatible = "loongson,ls7a-gpio",
.data = &loongson_gpio_ls7a_data,
@ -215,6 +300,22 @@ static const struct acpi_device_id loongson_gpio_acpi_match[] = {
.id = "LOON0002",
.driver_data = (kernel_ulong_t)&loongson_gpio_ls7a_data,
},
{
.id = "LOON0007",
.driver_data = (kernel_ulong_t)&loongson_gpio_ls3a5000_data,
},
{
.id = "LOON000A",
.driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data0,
},
{
.id = "LOON000B",
.driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data1,
},
{
.id = "LOON000C",
.driver_data = (kernel_ulong_t)&loongson_gpio_ls2k2000_data2,
},
{}
};
MODULE_DEVICE_TABLE(acpi, loongson_gpio_acpi_match);

View File

@ -381,7 +381,7 @@ static int lpc18xx_gpio_probe(struct platform_device *pdev)
return 0;
}
static int lpc18xx_gpio_remove(struct platform_device *pdev)
static void lpc18xx_gpio_remove(struct platform_device *pdev)
{
struct lpc18xx_gpio_chip *gc = platform_get_drvdata(pdev);
@ -389,8 +389,6 @@ static int lpc18xx_gpio_remove(struct platform_device *pdev)
irq_domain_remove(gc->pin_ic->domain);
clk_disable_unprepare(gc->clk);
return 0;
}
static const struct of_device_id lpc18xx_gpio_match[] = {
@ -401,7 +399,7 @@ MODULE_DEVICE_TABLE(of, lpc18xx_gpio_match);
static struct platform_driver lpc18xx_gpio_driver = {
.probe = lpc18xx_gpio_probe,
.remove = lpc18xx_gpio_remove,
.remove_new = lpc18xx_gpio_remove,
.driver = {
.name = "lpc18xx-gpio",
.of_match_table = lpc18xx_gpio_match,

View File

@ -20,7 +20,6 @@
#include <linux/spinlock.h>
#include <linux/slab.h>
#include "gpiolib.h"
#include "gpiolib-acpi.h"
/*
@ -205,15 +204,13 @@ static int mb86s70_gpio_probe(struct platform_device *pdev)
return 0;
}
static int mb86s70_gpio_remove(struct platform_device *pdev)
static void mb86s70_gpio_remove(struct platform_device *pdev)
{
struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
acpi_gpiochip_free_interrupts(&gchip->gc);
gpiochip_remove(&gchip->gc);
clk_disable_unprepare(gchip->clk);
return 0;
}
static const struct of_device_id mb86s70_gpio_dt_ids[] = {
@ -237,7 +234,7 @@ static struct platform_driver mb86s70_gpio_driver = {
.acpi_match_table = ACPI_PTR(mb86s70_gpio_acpi_ids),
},
.probe = mb86s70_gpio_probe,
.remove = mb86s70_gpio_remove,
.remove_new = mb86s70_gpio_remove,
};
module_platform_driver(mb86s70_gpio_driver);

View File

@ -121,13 +121,11 @@ static int ltq_mm_probe(struct platform_device *pdev)
return of_mm_gpiochip_add_data(pdev->dev.of_node, &chip->mmchip, chip);
}
static int ltq_mm_remove(struct platform_device *pdev)
static void ltq_mm_remove(struct platform_device *pdev)
{
struct ltq_mm *chip = platform_get_drvdata(pdev);
of_mm_gpiochip_remove(&chip->mmchip);
return 0;
}
static const struct of_device_id ltq_mm_match[] = {
@ -138,7 +136,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match);
static struct platform_driver ltq_mm_driver = {
.probe = ltq_mm_probe,
.remove = ltq_mm_remove,
.remove_new = ltq_mm_remove,
.driver = {
.name = "gpio-mm-ltq",
.of_match_table = ltq_mm_match,

View File

@ -56,9 +56,9 @@ o ` ~~~~\___/~~~~ ` controller in FPGA is ,.`
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include "gpiolib.h"
@ -702,7 +702,7 @@ static struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev,
{
struct bgpio_pdata *pdata;
if (!of_match_device(bgpio_of_match, &pdev->dev))
if (!pdev->dev.of_node)
return NULL;
pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata),

View File

@ -9,7 +9,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/cleanup.h>
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/gpio/driver.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
@ -24,8 +26,6 @@
#include <linux/string_helpers.h>
#include <linux/uaccess.h>
#include "gpiolib.h"
#define GPIO_MOCKUP_MAX_GC 10
/*
* We're storing two values per chip: the GPIO base and the number
@ -39,11 +39,15 @@
* struct gpio_pin_status - structure describing a GPIO status
* @dir: Configures direction of gpio as "in" or "out"
* @value: Configures status of the gpio as 0(low) or 1(high)
* @pull: Configures the current pull of the GPIO as 0 (pull-down) or
* 1 (pull-up)
* @requested: Request status of this GPIO
*/
struct gpio_mockup_line_status {
int dir;
int value;
int pull;
bool requested;
};
struct gpio_mockup_chip {
@ -56,7 +60,6 @@ struct gpio_mockup_chip {
struct gpio_mockup_dbgfs_private {
struct gpio_mockup_chip *chip;
struct gpio_desc *desc;
unsigned int offset;
};
@ -91,9 +94,8 @@ static int gpio_mockup_get(struct gpio_chip *gc, unsigned int offset)
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
int val;
mutex_lock(&chip->lock);
val = __gpio_mockup_get(chip, offset);
mutex_unlock(&chip->lock);
scoped_guard(mutex, &chip->lock)
val = __gpio_mockup_get(chip, offset);
return val;
}
@ -104,12 +106,12 @@ static int gpio_mockup_get_multiple(struct gpio_chip *gc,
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
unsigned int bit, val;
mutex_lock(&chip->lock);
for_each_set_bit(bit, mask, gc->ngpio) {
val = __gpio_mockup_get(chip, bit);
__assign_bit(bit, bits, val);
scoped_guard(mutex, &chip->lock) {
for_each_set_bit(bit, mask, gc->ngpio) {
val = __gpio_mockup_get(chip, bit);
__assign_bit(bit, bits, val);
}
}
mutex_unlock(&chip->lock);
return 0;
}
@ -125,9 +127,9 @@ static void gpio_mockup_set(struct gpio_chip *gc,
{
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock);
guard(mutex)(&chip->lock);
__gpio_mockup_set(chip, offset, value);
mutex_unlock(&chip->lock);
}
static void gpio_mockup_set_multiple(struct gpio_chip *gc,
@ -136,23 +138,21 @@ static void gpio_mockup_set_multiple(struct gpio_chip *gc,
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
unsigned int bit;
mutex_lock(&chip->lock);
guard(mutex)(&chip->lock);
for_each_set_bit(bit, mask, gc->ngpio)
__gpio_mockup_set(chip, bit, test_bit(bit, bits));
mutex_unlock(&chip->lock);
}
static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
unsigned int offset, int value)
{
struct gpio_chip *gc = &chip->gc;
struct gpio_desc *desc = gpiochip_get_desc(gc, offset);
struct gpio_mockup_line_status *line = &chip->lines[offset];
int curr, irq, irq_type, ret = 0;
mutex_lock(&chip->lock);
guard(mutex)(&chip->lock);
if (test_bit(FLAG_REQUESTED, &desc->flags) &&
!test_bit(FLAG_IS_OUT, &desc->flags)) {
if (line->requested && line->dir == GPIO_LINE_DIRECTION_IN) {
curr = __gpio_mockup_get(chip, offset);
if (curr == value)
goto out;
@ -180,13 +180,11 @@ static int gpio_mockup_apply_pull(struct gpio_mockup_chip *chip,
set_value:
/* Change the value unless we're actively driving the line. */
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
!test_bit(FLAG_IS_OUT, &desc->flags))
if (!line->requested || line->dir == GPIO_LINE_DIRECTION_IN)
__gpio_mockup_set(chip, offset, value);
out:
chip->lines[offset].pull = value;
mutex_unlock(&chip->lock);
return ret;
}
@ -211,10 +209,10 @@ static int gpio_mockup_dirout(struct gpio_chip *gc,
{
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock);
chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT;
__gpio_mockup_set(chip, offset, value);
mutex_unlock(&chip->lock);
scoped_guard(mutex, &chip->lock) {
chip->lines[offset].dir = GPIO_LINE_DIRECTION_OUT;
__gpio_mockup_set(chip, offset, value);
}
return 0;
}
@ -223,9 +221,8 @@ static int gpio_mockup_dirin(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
mutex_lock(&chip->lock);
chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN;
mutex_unlock(&chip->lock);
scoped_guard(mutex, &chip->lock)
chip->lines[offset].dir = GPIO_LINE_DIRECTION_IN;
return 0;
}
@ -235,9 +232,8 @@ static int gpio_mockup_get_direction(struct gpio_chip *gc, unsigned int offset)
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
int direction;
mutex_lock(&chip->lock);
direction = chip->lines[offset].dir;
mutex_unlock(&chip->lock);
scoped_guard(mutex, &chip->lock)
direction = chip->lines[offset].dir;
return direction;
}
@ -249,10 +245,23 @@ static int gpio_mockup_to_irq(struct gpio_chip *gc, unsigned int offset)
return irq_create_mapping(chip->irq_sim_domain, offset);
}
static int gpio_mockup_request(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
scoped_guard(mutex, &chip->lock)
chip->lines[offset].requested = true;
return 0;
}
static void gpio_mockup_free(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_mockup_chip *chip = gpiochip_get_data(gc);
guard(mutex)(&chip->lock);
chip->lines[offset].requested = false;
__gpio_mockup_set(chip, offset, chip->lines[offset].pull);
}
@ -345,6 +354,7 @@ static const struct file_operations gpio_mockup_debugfs_ops = {
static void gpio_mockup_debugfs_setup(struct device *dev,
struct gpio_mockup_chip *chip)
{
struct device *child __free(put_device) = NULL;
struct gpio_mockup_dbgfs_private *priv;
struct gpio_chip *gc;
const char *devname;
@ -352,8 +362,16 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
int i;
gc = &chip->gc;
devname = dev_name(&gc->gpiodev->dev);
/*
* There can only be a single GPIO device per platform device in
* gpio-mockup so using device_find_any_child() is OK.
*/
child = device_find_any_child(dev);
if (!child)
return;
devname = dev_name(child);
chip->dbg_dir = debugfs_create_dir(devname, gpio_mockup_dbg_dir);
for (i = 0; i < gc->ngpio; i++) {
@ -367,7 +385,6 @@ static void gpio_mockup_debugfs_setup(struct device *dev,
priv->chip = chip;
priv->offset = i;
priv->desc = gpiochip_get_desc(gc, i);
debugfs_create_file(name, 0600, chip->dbg_dir, priv,
&gpio_mockup_debugfs_ops);
@ -438,6 +455,7 @@ static int gpio_mockup_probe(struct platform_device *pdev)
gc->get_direction = gpio_mockup_get_direction;
gc->set_config = gpio_mockup_set_config;
gc->to_irq = gpio_mockup_to_irq;
gc->request = gpio_mockup_request;
gc->free = gpio_mockup_free;
chip->lines = devm_kcalloc(dev, gc->ngpio,

View File

@ -165,13 +165,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
return 0;
}
static int mpc52xx_gpiochip_remove(struct platform_device *ofdev)
static void mpc52xx_gpiochip_remove(struct platform_device *ofdev)
{
struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev);
of_mm_gpiochip_remove(&chip->mmchip);
return 0;
}
static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = {
@ -185,7 +183,7 @@ static struct platform_driver mpc52xx_wkup_gpiochip_driver = {
.of_match_table = mpc52xx_wkup_gpiochip_match,
},
.probe = mpc52xx_wkup_gpiochip_probe,
.remove = mpc52xx_gpiochip_remove,
.remove_new = mpc52xx_gpiochip_remove,
};
/*
@ -338,7 +336,7 @@ static struct platform_driver mpc52xx_simple_gpiochip_driver = {
.of_match_table = mpc52xx_simple_gpiochip_match,
},
.probe = mpc52xx_simple_gpiochip_probe,
.remove = mpc52xx_gpiochip_remove,
.remove_new = mpc52xx_gpiochip_remove,
};
static struct platform_driver * const drivers[] = {

View File

@ -419,7 +419,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
return ret;
}
static int mpc8xxx_remove(struct platform_device *pdev)
static void mpc8xxx_remove(struct platform_device *pdev)
{
struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev);
@ -427,8 +427,6 @@ static int mpc8xxx_remove(struct platform_device *pdev)
irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL);
irq_domain_remove(mpc8xxx_gc->irq);
}
return 0;
}
#ifdef CONFIG_ACPI
@ -441,7 +439,7 @@ MODULE_DEVICE_TABLE(acpi, gpio_acpi_ids);
static struct platform_driver mpc8xxx_plat_driver = {
.probe = mpc8xxx_probe,
.remove = mpc8xxx_remove,
.remove_new = mpc8xxx_remove,
.driver = {
.name = "gpio-mpc8xxx",
.of_match_table = mpc8xxx_gpio_ids,

View File

@ -42,9 +42,10 @@
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/mfd/syscon.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/pwm.h>
#include <linux/regmap.h>
#include <linux/slab.h>
@ -1122,7 +1123,6 @@ static void mvebu_gpio_remove_irq_domain(void *data)
static int mvebu_gpio_probe(struct platform_device *pdev)
{
struct mvebu_gpio_chip *mvchip;
const struct of_device_id *match;
struct device_node *np = pdev->dev.of_node;
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
@ -1132,11 +1132,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
int i, cpu, id;
int err;
match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match)
soc_variant = (unsigned long) match->data;
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
soc_variant = (unsigned long)device_get_match_data(&pdev->dev);
/* Some gpio controllers do not provide irq support */
err = platform_irq_count(pdev);

View File

@ -1048,15 +1048,14 @@ static int omap_gpio_chip_init(struct gpio_bank *bank, struct device *pm_dev)
bank->chip.label = "mpuio";
if (bank->regs->wkup_en)
bank->chip.parent = &omap_mpuio_device.dev;
bank->chip.base = OMAP_MPUIO(0);
} else {
label = devm_kasprintf(bank->chip.parent, GFP_KERNEL, "gpio-%d-%d",
gpio, gpio + bank->width - 1);
if (!label)
return -ENOMEM;
bank->chip.label = label;
bank->chip.base = -1;
}
bank->chip.base = -1;
bank->chip.ngpio = bank->width;
irq = &bank->chip.irq;
@ -1489,7 +1488,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
return 0;
}
static int omap_gpio_remove(struct platform_device *pdev)
static void omap_gpio_remove(struct platform_device *pdev)
{
struct gpio_bank *bank = platform_get_drvdata(pdev);
@ -1498,8 +1497,6 @@ static int omap_gpio_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
if (bank->dbck_flag)
clk_unprepare(bank->dbck);
return 0;
}
static int __maybe_unused omap_gpio_runtime_suspend(struct device *dev)
@ -1560,7 +1557,7 @@ static const struct dev_pm_ops gpio_pm_ops = {
static struct platform_driver omap_gpio_driver = {
.probe = omap_gpio_probe,
.remove = omap_gpio_remove,
.remove_new = omap_gpio_remove,
.driver = {
.name = "omap_gpio",
.pm = &gpio_pm_ops,

View File

@ -8,22 +8,30 @@
* Derived from drivers/i2c/chips/pca9539.c
*/
#include <linux/acpi.h>
#include <linux/atomic.h>
#include <linux/bitmap.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/platform_data/pca953x.h>
#include <linux/mutex.h>
#include <linux/pm.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/platform_data/pca953x.h>
#define PCA953X_INPUT 0x00
#define PCA953X_OUTPUT 0x01
@ -118,6 +126,7 @@ MODULE_DEVICE_TABLE(i2c, pca953x_id);
#ifdef CONFIG_GPIO_PCA953X_IRQ
#include <linux/acpi.h>
#include <linux/dmi.h>
static const struct acpi_gpio_params pca953x_irq_gpios = { 0, 0, true };
@ -211,7 +220,6 @@ struct pca953x_chip {
struct i2c_client *client;
struct gpio_chip gpio_chip;
const char *const *names;
unsigned long driver_data;
struct regulator *regulator;
@ -414,7 +422,7 @@ static const struct regmap_config pca953x_i2c_regmap = {
.volatile_reg = pca953x_volatile_register,
.disable_locking = true,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_MAPLE,
.max_register = 0x7f,
};
@ -430,7 +438,7 @@ static const struct regmap_config pca953x_ai_i2c_regmap = {
.volatile_reg = pca953x_volatile_register,
.disable_locking = true,
.cache_type = REGCACHE_RBTREE,
.cache_type = REGCACHE_MAPLE,
.max_register = 0x7f,
};
@ -520,12 +528,10 @@ static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
struct pca953x_chip *chip = gpiochip_get_data(gc);
u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off);
u8 bit = BIT(off % BANK_SZ);
int ret;
mutex_lock(&chip->i2c_lock);
ret = regmap_write_bits(chip->regmap, dirreg, bit, bit);
mutex_unlock(&chip->i2c_lock);
return ret;
guard(mutex)(&chip->i2c_lock);
return regmap_write_bits(chip->regmap, dirreg, bit, bit);
}
static int pca953x_gpio_direction_output(struct gpio_chip *gc,
@ -537,17 +543,15 @@ static int pca953x_gpio_direction_output(struct gpio_chip *gc,
u8 bit = BIT(off % BANK_SZ);
int ret;
mutex_lock(&chip->i2c_lock);
guard(mutex)(&chip->i2c_lock);
/* set output level */
ret = regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
if (ret)
goto exit;
return ret;
/* then direction */
ret = regmap_write_bits(chip->regmap, dirreg, bit, 0);
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
return regmap_write_bits(chip->regmap, dirreg, bit, 0);
}
static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
@ -558,9 +562,8 @@ static int pca953x_gpio_get_value(struct gpio_chip *gc, unsigned off)
u32 reg_val;
int ret;
mutex_lock(&chip->i2c_lock);
ret = regmap_read(chip->regmap, inreg, &reg_val);
mutex_unlock(&chip->i2c_lock);
scoped_guard(mutex, &chip->i2c_lock)
ret = regmap_read(chip->regmap, inreg, &reg_val);
if (ret < 0)
return ret;
@ -573,9 +576,9 @@ static void pca953x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
u8 outreg = chip->recalc_addr(chip, chip->regs->output, off);
u8 bit = BIT(off % BANK_SZ);
mutex_lock(&chip->i2c_lock);
guard(mutex)(&chip->i2c_lock);
regmap_write_bits(chip->regmap, outreg, bit, val ? bit : 0);
mutex_unlock(&chip->i2c_lock);
}
static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
@ -586,9 +589,8 @@ static int pca953x_gpio_get_direction(struct gpio_chip *gc, unsigned off)
u32 reg_val;
int ret;
mutex_lock(&chip->i2c_lock);
ret = regmap_read(chip->regmap, dirreg, &reg_val);
mutex_unlock(&chip->i2c_lock);
scoped_guard(mutex, &chip->i2c_lock)
ret = regmap_read(chip->regmap, dirreg, &reg_val);
if (ret < 0)
return ret;
@ -605,9 +607,8 @@ static int pca953x_gpio_get_multiple(struct gpio_chip *gc,
DECLARE_BITMAP(reg_val, MAX_LINE);
int ret;
mutex_lock(&chip->i2c_lock);
ret = pca953x_read_regs(chip, chip->regs->input, reg_val);
mutex_unlock(&chip->i2c_lock);
scoped_guard(mutex, &chip->i2c_lock)
ret = pca953x_read_regs(chip, chip->regs->input, reg_val);
if (ret)
return ret;
@ -622,16 +623,15 @@ static void pca953x_gpio_set_multiple(struct gpio_chip *gc,
DECLARE_BITMAP(reg_val, MAX_LINE);
int ret;
mutex_lock(&chip->i2c_lock);
guard(mutex)(&chip->i2c_lock);
ret = pca953x_read_regs(chip, chip->regs->output, reg_val);
if (ret)
goto exit;
return;
bitmap_replace(reg_val, reg_val, bits, mask, gc->ngpio);
pca953x_write_regs(chip, chip->regs->output, reg_val);
exit:
mutex_unlock(&chip->i2c_lock);
}
static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
@ -639,7 +639,6 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
unsigned long config)
{
enum pin_config_param param = pinconf_to_config_param(config);
u8 pull_en_reg = chip->recalc_addr(chip, PCAL953X_PULL_EN, offset);
u8 pull_sel_reg = chip->recalc_addr(chip, PCAL953X_PULL_SEL, offset);
u8 bit = BIT(offset % BANK_SZ);
@ -652,7 +651,7 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
if (!(chip->driver_data & PCA_PCAL))
return -ENOTSUPP;
mutex_lock(&chip->i2c_lock);
guard(mutex)(&chip->i2c_lock);
/* Configure pull-up/pull-down */
if (param == PIN_CONFIG_BIAS_PULL_UP)
@ -662,17 +661,13 @@ static int pca953x_gpio_set_pull_up_down(struct pca953x_chip *chip,
else
ret = 0;
if (ret)
goto exit;
return ret;
/* Disable/Enable pull-up/pull-down */
if (param == PIN_CONFIG_BIAS_DISABLE)
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
return regmap_write_bits(chip->regmap, pull_en_reg, bit, 0);
else
ret = regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
exit:
mutex_unlock(&chip->i2c_lock);
return ret;
return regmap_write_bits(chip->regmap, pull_en_reg, bit, bit);
}
static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
@ -693,9 +688,7 @@ static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset,
static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
{
struct gpio_chip *gc;
gc = &chip->gpio_chip;
struct gpio_chip *gc = &chip->gpio_chip;
gc->direction_input = pca953x_gpio_direction_input;
gc->direction_output = pca953x_gpio_direction_output;
@ -712,7 +705,6 @@ static void pca953x_setup_gpio(struct pca953x_chip *chip, int gpios)
gc->label = dev_name(&chip->client->dev);
gc->parent = &chip->client->dev;
gc->owner = THIS_MODULE;
gc->names = chip->names;
}
#ifdef CONFIG_GPIO_PCA953X_IRQ
@ -793,11 +785,11 @@ static int pca953x_irq_set_type(struct irq_data *d, unsigned int type)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
struct pca953x_chip *chip = gpiochip_get_data(gc);
struct device *dev = &chip->client->dev;
irq_hw_number_t hwirq = irqd_to_hwirq(d);
if (!(type & IRQ_TYPE_EDGE_BOTH)) {
dev_err(&chip->client->dev, "irq %d: unsupported type %d\n",
d->irq, type);
dev_err(dev, "irq %d: unsupported type %d\n", d->irq, type);
return -EINVAL;
}
@ -902,10 +894,8 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
bitmap_zero(pending, MAX_LINE);
mutex_lock(&chip->i2c_lock);
ret = pca953x_irq_pending(chip, pending);
mutex_unlock(&chip->i2c_lock);
scoped_guard(mutex, &chip->i2c_lock)
ret = pca953x_irq_pending(chip, pending);
if (ret) {
ret = 0;
@ -928,13 +918,15 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
{
struct i2c_client *client = chip->client;
struct device *dev = &client->dev;
DECLARE_BITMAP(reg_direction, MAX_LINE);
DECLARE_BITMAP(irq_stat, MAX_LINE);
struct gpio_chip *gc = &chip->gpio_chip;
struct gpio_irq_chip *girq;
int ret;
if (dmi_first_match(pca953x_dmi_acpi_irq_info)) {
ret = pca953x_acpi_get_irq(&client->dev);
ret = pca953x_acpi_get_irq(dev);
if (ret > 0)
client->irq = ret;
}
@ -958,7 +950,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
* this purpose.
*/
pca953x_read_regs(chip, chip->regs->direction, reg_direction);
bitmap_and(chip->irq_stat, irq_stat, reg_direction, chip->gpio_chip.ngpio);
bitmap_and(chip->irq_stat, irq_stat, reg_direction, gc->ngpio);
mutex_init(&chip->irq_lock);
girq = &chip->gpio_chip.irq;
@ -972,33 +964,29 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
girq->threaded = true;
girq->first = irq_base; /* FIXME: get rid of this */
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pca953x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
return ret;
}
ret = devm_request_threaded_irq(dev, client->irq, NULL, pca953x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED, dev_name(dev),
chip);
if (ret)
return dev_err_probe(dev, client->irq, "failed to request irq\n");
return 0;
}
#else /* CONFIG_GPIO_PCA953X_IRQ */
static int pca953x_irq_setup(struct pca953x_chip *chip,
int irq_base)
static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
{
struct i2c_client *client = chip->client;
struct device *dev = &client->dev;
if (client->irq && irq_base != -1 && (chip->driver_data & PCA_INT))
dev_warn(&client->dev, "interrupt support not compiled in\n");
dev_warn(dev, "interrupt support not compiled in\n");
return 0;
}
#endif
static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
static int device_pca95xx_init(struct pca953x_chip *chip)
{
DECLARE_BITMAP(val, MAX_LINE);
u8 regaddr;
@ -1008,68 +996,81 @@ static int device_pca95xx_init(struct pca953x_chip *chip, u32 invert)
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret)
goto out;
return ret;
regaddr = chip->recalc_addr(chip, chip->regs->direction, 0);
ret = regcache_sync_region(chip->regmap, regaddr,
regaddr + NBANK(chip) - 1);
if (ret)
goto out;
return ret;
/* set platform specific polarity inversion */
if (invert)
bitmap_fill(val, MAX_LINE);
else
bitmap_zero(val, MAX_LINE);
/* clear polarity inversion */
bitmap_zero(val, MAX_LINE);
ret = pca953x_write_regs(chip, chip->regs->invert, val);
out:
return ret;
return pca953x_write_regs(chip, chip->regs->invert, val);
}
static int device_pca957x_init(struct pca953x_chip *chip, u32 invert)
static int device_pca957x_init(struct pca953x_chip *chip)
{
DECLARE_BITMAP(val, MAX_LINE);
unsigned int i;
int ret;
ret = device_pca95xx_init(chip, invert);
ret = device_pca95xx_init(chip);
if (ret)
goto out;
return ret;
/* To enable register 6, 7 to control pull up and pull down */
for (i = 0; i < NBANK(chip); i++)
bitmap_set_value8(val, 0x02, i * BANK_SZ);
ret = pca953x_write_regs(chip, PCA957X_BKEN, val);
if (ret)
goto out;
return pca953x_write_regs(chip, PCA957X_BKEN, val);
}
static void pca953x_disable_regulator(void *reg)
{
regulator_disable(reg);
}
static int pca953x_get_and_enable_regulator(struct pca953x_chip *chip)
{
struct device *dev = &chip->client->dev;
struct regulator *reg = chip->regulator;
int ret;
reg = devm_regulator_get(dev, "vcc");
if (IS_ERR(reg))
return dev_err_probe(dev, PTR_ERR(reg), "reg get err\n");
ret = regulator_enable(reg);
if (ret)
return dev_err_probe(dev, ret, "reg en err\n");
ret = devm_add_action_or_reset(dev, pca953x_disable_regulator, reg);
if (ret)
return ret;
chip->regulator = reg;
return 0;
out:
return ret;
}
static int pca953x_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct pca953x_platform_data *pdata;
struct pca953x_chip *chip;
int irq_base = 0;
int irq_base;
int ret;
u32 invert = 0;
struct regulator *reg;
const struct regmap_config *regmap_config;
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
pdata = dev_get_platdata(&client->dev);
pdata = dev_get_platdata(dev);
if (pdata) {
irq_base = pdata->irq_base;
chip->gpio_start = pdata->gpio_base;
invert = pdata->invert;
chip->names = pdata->names;
} else {
struct gpio_desc *reset_gpio;
@ -1083,8 +1084,7 @@ static int pca953x_probe(struct i2c_client *client)
* using "reset" GPIO. Otherwise any of those platform
* must use _DSD method with corresponding property.
*/
reset_gpio = devm_gpiod_get_optional(&client->dev, "reset",
GPIOD_OUT_LOW);
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
if (IS_ERR(reset_gpio))
return PTR_ERR(reset_gpio);
}
@ -1094,26 +1094,19 @@ static int pca953x_probe(struct i2c_client *client)
if (!chip->driver_data)
return -ENODEV;
reg = devm_regulator_get(&client->dev, "vcc");
if (IS_ERR(reg))
return dev_err_probe(&client->dev, PTR_ERR(reg), "reg get err\n");
ret = regulator_enable(reg);
if (ret) {
dev_err(&client->dev, "reg en err: %d\n", ret);
ret = pca953x_get_and_enable_regulator(chip);
if (ret)
return ret;
}
chip->regulator = reg;
i2c_set_clientdata(client, chip);
pca953x_setup_gpio(chip, chip->driver_data & PCA_GPIO_MASK);
if (NBANK(chip) > 2 || PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
dev_info(&client->dev, "using AI\n");
dev_info(dev, "using AI\n");
regmap_config = &pca953x_ai_i2c_regmap;
} else {
dev_info(&client->dev, "using no AI\n");
dev_info(dev, "using no AI\n");
regmap_config = &pca953x_i2c_regmap;
}
@ -1126,10 +1119,8 @@ static int pca953x_probe(struct i2c_client *client)
}
chip->regmap = devm_regmap_init_i2c(client, regmap_config);
if (IS_ERR(chip->regmap)) {
ret = PTR_ERR(chip->regmap);
goto err_exit;
}
if (IS_ERR(chip->regmap))
return PTR_ERR(chip->regmap);
regcache_mark_dirty(chip->regmap);
@ -1158,53 +1149,24 @@ static int pca953x_probe(struct i2c_client *client)
*/
if (PCA_CHIP_TYPE(chip->driver_data) == PCA957X_TYPE) {
chip->regs = &pca957x_regs;
ret = device_pca957x_init(chip, invert);
ret = device_pca957x_init(chip);
} else {
chip->regs = &pca953x_regs;
ret = device_pca95xx_init(chip, invert);
ret = device_pca95xx_init(chip);
}
if (ret)
goto err_exit;
return ret;
ret = pca953x_irq_setup(chip, irq_base);
if (ret)
goto err_exit;
return ret;
ret = devm_gpiochip_add_data(&client->dev, &chip->gpio_chip, chip);
if (ret)
goto err_exit;
if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
if (ret < 0)
dev_warn(&client->dev, "setup failed, %d\n", ret);
}
return 0;
err_exit:
regulator_disable(chip->regulator);
return ret;
return devm_gpiochip_add_data(dev, &chip->gpio_chip, chip);
}
static void pca953x_remove(struct i2c_client *client)
static int pca953x_regcache_sync(struct pca953x_chip *chip)
{
struct pca953x_platform_data *pdata = dev_get_platdata(&client->dev);
struct pca953x_chip *chip = i2c_get_clientdata(client);
if (pdata && pdata->teardown) {
pdata->teardown(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
}
regulator_disable(chip->regulator);
}
#ifdef CONFIG_PM_SLEEP
static int pca953x_regcache_sync(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
struct device *dev = &chip->client->dev;
int ret;
u8 regaddr;
@ -1251,13 +1213,32 @@ static int pca953x_regcache_sync(struct device *dev)
return 0;
}
static int pca953x_restore_context(struct pca953x_chip *chip)
{
int ret;
guard(mutex)(&chip->i2c_lock);
regcache_cache_only(chip->regmap, false);
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(chip);
if (ret)
return ret;
return regcache_sync(chip->regmap);
}
static void pca953x_save_context(struct pca953x_chip *chip)
{
guard(mutex)(&chip->i2c_lock);
regcache_cache_only(chip->regmap, true);
}
static int pca953x_suspend(struct device *dev)
{
struct pca953x_chip *chip = dev_get_drvdata(dev);
mutex_lock(&chip->i2c_lock);
regcache_cache_only(chip->regmap, true);
mutex_unlock(&chip->i2c_lock);
pca953x_save_context(chip);
if (atomic_read(&chip->wakeup_path))
device_set_wakeup_path(dev);
@ -1280,25 +1261,14 @@ static int pca953x_resume(struct device *dev)
}
}
mutex_lock(&chip->i2c_lock);
regcache_cache_only(chip->regmap, false);
regcache_mark_dirty(chip->regmap);
ret = pca953x_regcache_sync(dev);
if (ret) {
mutex_unlock(&chip->i2c_lock);
return ret;
}
ret = regcache_sync(chip->regmap);
mutex_unlock(&chip->i2c_lock);
if (ret) {
ret = pca953x_restore_context(chip);
if (ret)
dev_err(dev, "Failed to restore register map: %d\n", ret);
return ret;
}
return 0;
return ret;
}
#endif
static DEFINE_SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume);
/* convenience to stop overlong match-table lines */
#define OF_653X(__nrgpio, __int) ((void *)(__nrgpio | PCAL653X_TYPE | __int))
@ -1356,17 +1326,14 @@ static const struct of_device_id pca953x_dt_ids[] = {
MODULE_DEVICE_TABLE(of, pca953x_dt_ids);
static SIMPLE_DEV_PM_OPS(pca953x_pm_ops, pca953x_suspend, pca953x_resume);
static struct i2c_driver pca953x_driver = {
.driver = {
.name = "pca953x",
.pm = &pca953x_pm_ops,
.pm = pm_sleep_ptr(&pca953x_pm_ops),
.of_match_table = pca953x_dt_ids,
.acpi_match_table = pca953x_acpi_ids,
},
.probe = pca953x_probe,
.remove = pca953x_remove,
.id_table = pca953x_id,
};

View File

@ -583,14 +583,13 @@ static int gpio_rcar_probe(struct platform_device *pdev)
return ret;
}
static int gpio_rcar_remove(struct platform_device *pdev)
static void gpio_rcar_remove(struct platform_device *pdev)
{
struct gpio_rcar_priv *p = platform_get_drvdata(pdev);
gpiochip_remove(&p->gpio_chip);
pm_runtime_disable(&pdev->dev);
return 0;
}
#ifdef CONFIG_PM_SLEEP
@ -658,7 +657,7 @@ static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume);
static struct platform_driver gpio_rcar_device_driver = {
.probe = gpio_rcar_probe,
.remove = gpio_rcar_remove,
.remove_new = gpio_rcar_remove,
.driver = {
.name = "gpio_rcar",
.pm = &gpio_rcar_pm_ops,

View File

@ -778,14 +778,12 @@ static int rockchip_gpio_probe(struct platform_device *pdev)
return 0;
}
static int rockchip_gpio_remove(struct platform_device *pdev)
static void rockchip_gpio_remove(struct platform_device *pdev)
{
struct rockchip_pin_bank *bank = platform_get_drvdata(pdev);
clk_disable_unprepare(bank->clk);
gpiochip_remove(&bank->gpio_chip);
return 0;
}
static const struct of_device_id rockchip_gpio_match[] = {
@ -796,7 +794,7 @@ static const struct of_device_id rockchip_gpio_match[] = {
static struct platform_driver rockchip_gpio_driver = {
.probe = rockchip_gpio_probe,
.remove = rockchip_gpio_remove,
.remove_new = rockchip_gpio_remove,
.driver = {
.name = "rockchip-gpio",
.of_match_table = rockchip_gpio_match,

View File

@ -12,6 +12,8 @@
#include <linux/completion.h>
#include <linux/configfs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
#include <linux/idr.h>
@ -30,8 +32,7 @@
#include <linux/string.h>
#include <linux/string_helpers.h>
#include <linux/sysfs.h>
#include "gpiolib.h"
#include <linux/types.h>
#define GPIO_SIM_NGPIO_MAX 1024
#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */
@ -41,6 +42,8 @@ static DEFINE_IDA(gpio_sim_ida);
struct gpio_sim_chip {
struct gpio_chip gc;
struct device *dev;
unsigned long *request_map;
unsigned long *direction_map;
unsigned long *value_map;
unsigned long *pull_map;
@ -64,16 +67,11 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip,
unsigned int offset, int value)
{
int irq, irq_type, ret;
struct gpio_desc *desc;
struct gpio_chip *gc;
gc = &chip->gc;
desc = &gc->gpiodev->descs[offset];
guard(mutex)(&chip->lock);
if (test_bit(FLAG_REQUESTED, &desc->flags) &&
!test_bit(FLAG_IS_OUT, &desc->flags)) {
if (test_bit(offset, chip->request_map) &&
test_bit(offset, chip->direction_map)) {
if (value == !!test_bit(offset, chip->value_map))
goto set_pull;
@ -100,8 +98,8 @@ static int gpio_sim_apply_pull(struct gpio_sim_chip *chip,
set_value:
/* Change the value unless we're actively driving the line. */
if (!test_bit(FLAG_REQUESTED, &desc->flags) ||
!test_bit(FLAG_IS_OUT, &desc->flags))
if (!test_bit(offset, chip->request_map) ||
test_bit(offset, chip->direction_map))
__assign_bit(offset, chip->value_map, value);
set_pull:
@ -181,8 +179,8 @@ static int gpio_sim_get_direction(struct gpio_chip *gc, unsigned int offset)
return direction ? GPIO_LINE_DIRECTION_IN : GPIO_LINE_DIRECTION_OUT;
}
static int gpio_sim_set_config(struct gpio_chip *gc,
unsigned int offset, unsigned long config)
static int gpio_sim_set_config(struct gpio_chip *gc, unsigned int offset,
unsigned long config)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
@ -205,13 +203,25 @@ static int gpio_sim_to_irq(struct gpio_chip *gc, unsigned int offset)
return irq_create_mapping(chip->irq_sim, offset);
}
static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset)
static int gpio_sim_request(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
scoped_guard(mutex, &chip->lock)
__set_bit(offset, chip->request_map);
return 0;
}
static void gpio_sim_free(struct gpio_chip *gc, unsigned int offset)
{
struct gpio_sim_chip *chip = gpiochip_get_data(gc);
scoped_guard(mutex, &chip->lock) {
__assign_bit(offset, chip->value_map,
!!test_bit(offset, chip->pull_map));
__clear_bit(offset, chip->request_map);
}
}
static ssize_t gpio_sim_sysfs_val_show(struct device *dev,
@ -283,6 +293,13 @@ static void gpio_sim_mutex_destroy(void *data)
mutex_destroy(lock);
}
static void gpio_sim_put_device(void *data)
{
struct device *dev = data;
put_device(dev);
}
static void gpio_sim_dispose_mappings(void *data)
{
struct gpio_sim_chip *chip = data;
@ -296,7 +313,7 @@ static void gpio_sim_sysfs_remove(void *data)
{
struct gpio_sim_chip *chip = data;
sysfs_remove_groups(&chip->gc.gpiodev->dev.kobj, chip->attr_groups);
sysfs_remove_groups(&chip->dev->kobj, chip->attr_groups);
}
static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip)
@ -353,14 +370,18 @@ static int gpio_sim_setup_sysfs(struct gpio_sim_chip *chip)
chip->attr_groups[i] = attr_group;
}
ret = sysfs_create_groups(&chip->gc.gpiodev->dev.kobj,
chip->attr_groups);
ret = sysfs_create_groups(&chip->dev->kobj, chip->attr_groups);
if (ret)
return ret;
return devm_add_action_or_reset(dev, gpio_sim_sysfs_remove, chip);
}
static int gpio_sim_dev_match_fwnode(struct device *dev, void *data)
{
return device_match_fwnode(dev, data);
}
static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
{
struct gpio_sim_chip *chip;
@ -388,6 +409,10 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
if (!chip)
return -ENOMEM;
chip->request_map = devm_bitmap_zalloc(dev, num_lines, GFP_KERNEL);
if (!chip->request_map)
return -ENOMEM;
chip->direction_map = devm_bitmap_alloc(dev, num_lines, GFP_KERNEL);
if (!chip->direction_map)
return -ENOMEM;
@ -433,6 +458,7 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
gc->get_direction = gpio_sim_get_direction;
gc->set_config = gpio_sim_set_config;
gc->to_irq = gpio_sim_to_irq;
gc->request = gpio_sim_request;
gc->free = gpio_sim_free;
gc->can_sleep = true;
@ -440,8 +466,16 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)
if (ret)
return ret;
/* Used by sysfs and configfs callbacks. */
dev_set_drvdata(&gc->gpiodev->dev, chip);
chip->dev = device_find_child(dev, swnode, gpio_sim_dev_match_fwnode);
if (!chip->dev)
return -ENODEV;
ret = devm_add_action_or_reset(dev, gpio_sim_put_device, chip->dev);
if (ret)
return ret;
/* Used by sysfs callbacks. */
dev_set_drvdata(chip->dev, chip);
return gpio_sim_setup_sysfs(chip);
}
@ -1438,10 +1472,10 @@ static const struct config_item_type gpio_sim_device_config_group_type = {
static struct config_group *
gpio_sim_config_make_device_group(struct config_group *group, const char *name)
{
struct gpio_sim_device *dev __free(kfree) = NULL;
int id;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
struct gpio_sim_device *dev __free(kfree) = kzalloc(sizeof(*dev),
GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);

View File

@ -215,7 +215,7 @@ static int tb10x_gpio_probe(struct platform_device *pdev)
return ret;
}
static int tb10x_gpio_remove(struct platform_device *pdev)
static void tb10x_gpio_remove(struct platform_device *pdev)
{
struct tb10x_gpio *tb10x_gpio = platform_get_drvdata(pdev);
@ -225,8 +225,6 @@ static int tb10x_gpio_remove(struct platform_device *pdev)
kfree(tb10x_gpio->domain->gc);
irq_domain_remove(tb10x_gpio->domain);
}
return 0;
}
static const struct of_device_id tb10x_gpio_dt_ids[] = {
@ -237,7 +235,7 @@ MODULE_DEVICE_TABLE(of, tb10x_gpio_dt_ids);
static struct platform_driver tb10x_gpio_driver = {
.probe = tb10x_gpio_probe,
.remove = tb10x_gpio_remove,
.remove_new = tb10x_gpio_remove,
.driver = {
.name = "tb10x-gpio",
.of_match_table = tb10x_gpio_dt_ids,

View File

@ -412,13 +412,11 @@ static int ts5500_dio_probe(struct platform_device *pdev)
return 0;
}
static int ts5500_dio_remove(struct platform_device *pdev)
static void ts5500_dio_remove(struct platform_device *pdev)
{
struct ts5500_priv *priv = platform_get_drvdata(pdev);
ts5500_disable_irq(priv);
return 0;
}
static const struct platform_device_id ts5500_dio_ids[] = {
@ -435,7 +433,7 @@ static struct platform_driver ts5500_dio_driver = {
.name = "ts5500-dio",
},
.probe = ts5500_dio_probe,
.remove = ts5500_dio_remove,
.remove_new = ts5500_dio_remove,
.id_table = ts5500_dio_ids,
};

View File

@ -414,13 +414,11 @@ static int uniphier_gpio_probe(struct platform_device *pdev)
return 0;
}
static int uniphier_gpio_remove(struct platform_device *pdev)
static void uniphier_gpio_remove(struct platform_device *pdev)
{
struct uniphier_gpio_priv *priv = platform_get_drvdata(pdev);
irq_domain_remove(priv->domain);
return 0;
}
static int __maybe_unused uniphier_gpio_suspend(struct device *dev)
@ -482,7 +480,7 @@ MODULE_DEVICE_TABLE(of, uniphier_gpio_match);
static struct platform_driver uniphier_gpio_driver = {
.probe = uniphier_gpio_probe,
.remove = uniphier_gpio_remove,
.remove_new = uniphier_gpio_remove,
.driver = {
.name = "uniphier-gpio",
.of_match_table = uniphier_gpio_match,

View File

@ -25,6 +25,7 @@
struct fsl_gpio_soc_data {
/* SoCs has a Port Data Direction Register (PDDR) */
bool have_paddr;
bool have_dual_base;
};
struct vf610_gpio_port {
@ -60,13 +61,26 @@ struct vf610_gpio_port {
#define PORT_INT_EITHER_EDGE 0xb
#define PORT_INT_LOGIC_ONE 0xc
#define IMX8ULP_GPIO_BASE_OFF 0x40
#define IMX8ULP_BASE_OFF 0x80
static const struct fsl_gpio_soc_data vf610_data = {
.have_dual_base = true,
};
static const struct fsl_gpio_soc_data imx_data = {
.have_paddr = true,
.have_dual_base = true,
};
static const struct fsl_gpio_soc_data imx8ulp_data = {
.have_paddr = true,
};
static const struct of_device_id vf610_gpio_dt_ids[] = {
{ .compatible = "fsl,vf610-gpio", .data = NULL, },
{ .compatible = "fsl,vf610-gpio", .data = &vf610_data },
{ .compatible = "fsl,imx7ulp-gpio", .data = &imx_data, },
{ .compatible = "fsl,imx8ulp-gpio", .data = &imx8ulp_data, },
{ /* sentinel */ }
};
@ -86,7 +100,7 @@ static int vf610_gpio_get(struct gpio_chip *gc, unsigned int gpio)
unsigned long mask = BIT(gpio);
unsigned long offset = GPIO_PDIR;
if (port->sdata && port->sdata->have_paddr) {
if (port->sdata->have_paddr) {
mask &= vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
if (mask)
offset = GPIO_PDOR;
@ -110,7 +124,7 @@ static int vf610_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
unsigned long mask = BIT(gpio);
u32 val;
if (port->sdata && port->sdata->have_paddr) {
if (port->sdata->have_paddr) {
val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
val &= ~mask;
vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
@ -128,7 +142,7 @@ static int vf610_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
vf610_gpio_set(chip, gpio, value);
if (port->sdata && port->sdata->have_paddr) {
if (port->sdata->have_paddr) {
val = vf610_gpio_readl(port->gpio_base + GPIO_PDDR);
val |= mask;
vf610_gpio_writel(val, port->gpio_base + GPIO_PDDR);
@ -264,19 +278,41 @@ static int vf610_gpio_probe(struct platform_device *pdev)
struct gpio_irq_chip *girq;
int i;
int ret;
bool dual_base;
port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
port->sdata = of_device_get_match_data(dev);
port->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
port->gpio_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(port->gpio_base))
return PTR_ERR(port->gpio_base);
dual_base = port->sdata->have_dual_base;
/*
* Handle legacy compatible combinations which used two reg values
* for the i.MX8ULP and i.MX93.
*/
if (device_is_compatible(dev, "fsl,imx7ulp-gpio") &&
(device_is_compatible(dev, "fsl,imx93-gpio") ||
(device_is_compatible(dev, "fsl,imx8ulp-gpio"))))
dual_base = true;
if (dual_base) {
port->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
port->gpio_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(port->gpio_base))
return PTR_ERR(port->gpio_base);
} else {
port->base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(port->base))
return PTR_ERR(port->base);
port->gpio_base = port->base + IMX8ULP_GPIO_BASE_OFF;
port->base = port->base + IMX8ULP_BASE_OFF;
}
port->irq = platform_get_irq(pdev, 0);
if (port->irq < 0)

View File

@ -15,7 +15,6 @@
#include <linux/gpio/driver.h>
#include <linux/acpi.h>
#include "gpiolib.h"
#include "gpiolib-acpi.h"
/* Common property names */
@ -296,15 +295,13 @@ static int xgene_gpio_sb_probe(struct platform_device *pdev)
return ret;
}
static int xgene_gpio_sb_remove(struct platform_device *pdev)
static void xgene_gpio_sb_remove(struct platform_device *pdev)
{
struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
acpi_gpiochip_free_interrupts(&priv->gc);
irq_domain_remove(priv->irq_domain);
return 0;
}
static const struct of_device_id xgene_gpio_sb_of_match[] = {
@ -328,7 +325,7 @@ static struct platform_driver xgene_gpio_sb_driver = {
.acpi_match_table = ACPI_PTR(xgene_gpio_sb_acpi_match),
},
.probe = xgene_gpio_sb_probe,
.remove = xgene_gpio_sb_remove,
.remove_new = xgene_gpio_sb_remove,
};
module_platform_driver(xgene_gpio_sb_driver);

View File

@ -291,7 +291,7 @@ static int iproc_gpio_probe(struct platform_device *pdev)
return 0;
}
static int iproc_gpio_remove(struct platform_device *pdev)
static void iproc_gpio_remove(struct platform_device *pdev)
{
struct iproc_gpio_chip *chip = platform_get_drvdata(pdev);
@ -302,8 +302,6 @@ static int iproc_gpio_remove(struct platform_device *pdev)
val &= ~IPROC_CCA_INT_F_GPIOINT;
writel_relaxed(val, chip->intr + IPROC_CCA_INT_MASK);
}
return 0;
}
static const struct of_device_id bcm_iproc_gpio_of_match[] = {
@ -318,7 +316,7 @@ static struct platform_driver bcm_iproc_gpio_driver = {
.of_match_table = bcm_iproc_gpio_of_match,
},
.probe = iproc_gpio_probe,
.remove = iproc_gpio_remove,
.remove_new = iproc_gpio_remove,
};
module_platform_driver(bcm_iproc_gpio_driver);

View File

@ -332,7 +332,7 @@ static int __maybe_unused xgpio_suspend(struct device *dev)
*
* Return: 0 always
*/
static int xgpio_remove(struct platform_device *pdev)
static void xgpio_remove(struct platform_device *pdev)
{
struct xgpio_instance *gpio = platform_get_drvdata(pdev);
@ -340,8 +340,6 @@ static int xgpio_remove(struct platform_device *pdev)
pm_runtime_put_noidle(&pdev->dev);
pm_runtime_disable(&pdev->dev);
clk_disable_unprepare(gpio->clk);
return 0;
}
/**
@ -715,7 +713,7 @@ MODULE_DEVICE_TABLE(of, xgpio_of_match);
static struct platform_driver xgpio_plat_driver = {
.probe = xgpio_probe,
.remove = xgpio_remove,
.remove_new = xgpio_remove,
.driver = {
.name = "gpio-xilinx",
.of_match_table = xgpio_of_match,

View File

@ -1010,7 +1010,7 @@ static int zynq_gpio_probe(struct platform_device *pdev)
*
* Return: 0 always
*/
static int zynq_gpio_remove(struct platform_device *pdev)
static void zynq_gpio_remove(struct platform_device *pdev)
{
struct zynq_gpio *gpio = platform_get_drvdata(pdev);
int ret;
@ -1022,7 +1022,6 @@ static int zynq_gpio_remove(struct platform_device *pdev)
clk_disable_unprepare(gpio->clk);
device_set_wakeup_capable(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
return 0;
}
static struct platform_driver zynq_gpio_driver = {
@ -1032,7 +1031,7 @@ static struct platform_driver zynq_gpio_driver = {
.of_match_table = zynq_gpio_of_match,
},
.probe = zynq_gpio_probe,
.remove = zynq_gpio_remove,
.remove_new = zynq_gpio_remove,
};
module_platform_driver(zynq_gpio_driver);

View File

@ -143,7 +143,6 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
*/
static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
{
struct gpio_chip *chip;
acpi_handle handle;
acpi_status status;
@ -151,41 +150,18 @@ static struct gpio_desc *acpi_get_gpiod(char *path, unsigned int pin)
if (ACPI_FAILURE(status))
return ERR_PTR(-ENODEV);
chip = gpiochip_find(handle, acpi_gpiochip_find);
if (!chip)
struct gpio_device *gdev __free(gpio_device_put) =
gpio_device_find(handle, acpi_gpiochip_find);
if (!gdev)
return ERR_PTR(-EPROBE_DEFER);
return gpiochip_get_desc(chip, pin);
/*
* FIXME: keep track of the reference to the GPIO device somehow
* instead of putting it here.
*/
return gpio_device_get_desc(gdev, pin);
}
/**
* acpi_get_and_request_gpiod - Translate ACPI GPIO pin to GPIO descriptor and
* hold a refcount to the GPIO device.
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
* @pin: ACPI GPIO pin number (0-based, controller-relative)
* @label: Label to pass to gpiod_request()
*
* This function is a simple pass-through to acpi_get_gpiod(), except that
* as it is intended for use outside of the GPIO layer (in a similar fashion to
* gpiod_get_index() for example) it also holds a reference to the GPIO device.
*/
struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label)
{
struct gpio_desc *gpio;
int ret;
gpio = acpi_get_gpiod(path, pin);
if (IS_ERR(gpio))
return gpio;
ret = gpiod_request(gpio, label);
if (ret)
return ERR_PTR(ret);
return gpio;
}
EXPORT_SYMBOL_GPL(acpi_get_and_request_gpiod);
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
{
struct acpi_gpio_event *event = data;
@ -437,6 +413,11 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
if (!handler)
return AE_OK;
if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) {
dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
return AE_OK;
}
desc = acpi_request_own_gpiod(chip, agpio, 0, "ACPI:Event");
if (IS_ERR(desc)) {
dev_err(chip->parent,
@ -461,11 +442,6 @@ static acpi_status acpi_gpiochip_alloc_event(struct acpi_resource *ares,
goto fail_unlock_irq;
}
if (acpi_gpio_in_ignore_list(ignore_interrupt, dev_name(chip->parent), pin)) {
dev_info(chip->parent, "Ignoring interrupt on pin %u\n", pin);
return AE_OK;
}
event = kzalloc(sizeof(*event), GFP_KERNEL);
if (!event)
goto fail_unlock_irq;
@ -1655,6 +1631,26 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
.ignore_wake = "SYNA1202:00@16",
},
},
{
/*
* On the Peaq C1010 2-in-1 INT33FC:00 pin 3 is connected to
* a "dolby" button. At the ACPI level an _AEI event-handler
* is connected which sets an ACPI variable to 1 on both
* edges. This variable can be polled + cleared to 0 using
* WMI. But since the variable is set on both edges the WMI
* interface is pretty useless even when polling.
* So instead the x86-android-tablets code instantiates
* a gpio-keys platform device for it.
* Ignore the _AEI handler for the pin, so that it is not busy.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "PEAQ"),
DMI_MATCH(DMI_PRODUCT_NAME, "PEAQ PMM C1010 MD99187"),
},
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
.ignore_interrupt = "INT33FC:00@3",
},
},
{} /* Terminating entry */
};

View File

@ -572,7 +572,7 @@ struct linereq {
DECLARE_KFIFO_PTR(events, struct gpio_v2_line_event);
atomic_t seqno;
struct mutex config_mutex;
struct line lines[];
struct line lines[] __counted_by(num_lines);
};
#define GPIO_V2_LINE_BIAS_FLAGS \
@ -1656,6 +1656,7 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
lr = kzalloc(struct_size(lr, lines, ulr.num_lines), GFP_KERNEL);
if (!lr)
return -ENOMEM;
lr->num_lines = ulr.num_lines;
lr->gdev = gpio_device_get(gdev);
@ -1684,7 +1685,6 @@ static int linereq_create(struct gpio_device *gdev, void __user *ip)
lr->event_buffer_size = GPIO_V2_LINES_MAX * 16;
atomic_set(&lr->seqno, 0);
lr->num_lines = ulr.num_lines;
/* Request each GPIO */
for (i = 0; i < ulr.num_lines; i++) {

View File

@ -127,10 +127,10 @@ static int of_gpiochip_match_node_and_xlate(struct gpio_chip *chip, void *data)
chip->of_xlate(chip, gpiospec, NULL) >= 0;
}
static struct gpio_chip *of_find_gpiochip_by_xlate(
struct of_phandle_args *gpiospec)
static struct gpio_device *
of_find_gpio_device_by_xlate(struct of_phandle_args *gpiospec)
{
return gpiochip_find(gpiospec, of_gpiochip_match_node_and_xlate);
return gpio_device_find(gpiospec, of_gpiochip_match_node_and_xlate);
}
static struct gpio_desc *of_xlate_and_get_gpiod_flags(struct gpio_chip *chip,
@ -192,6 +192,15 @@ static void of_gpio_try_fixup_polarity(const struct device_node *np,
*/
{ "himax,hx8357", "gpios-reset", false },
{ "himax,hx8369", "gpios-reset", false },
/*
* The rb-gpios semantics was undocumented and qi,lb60 (along with
* the ingenic driver) got it wrong. The active state encodes the
* NAND ready state, which is high level. Since there's no signal
* inverter on this board, it should be active-high. Let's fix that
* here for older DTs so we can re-use the generic nand_gpio_waitrdy()
* helper, and be consistent with what other drivers do.
*/
{ "qi,lb60", "rb-gpios", true },
#endif
};
unsigned int i;
@ -363,7 +372,6 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
const char *propname, int index, enum of_gpio_flags *flags)
{
struct of_phandle_args gpiospec;
struct gpio_chip *chip;
struct gpio_desc *desc;
int ret;
@ -375,13 +383,15 @@ static struct gpio_desc *of_get_named_gpiod_flags(const struct device_node *np,
return ERR_PTR(ret);
}
chip = of_find_gpiochip_by_xlate(&gpiospec);
if (!chip) {
struct gpio_device *gdev __free(gpio_device_put) =
of_find_gpio_device_by_xlate(&gpiospec);
if (!gdev) {
desc = ERR_PTR(-EPROBE_DEFER);
goto out;
}
desc = of_xlate_and_get_gpiod_flags(chip, &gpiospec, flags);
desc = of_xlate_and_get_gpiod_flags(gpio_device_get_chip(gdev),
&gpiospec, flags);
if (IS_ERR(desc))
goto out;
@ -611,6 +621,33 @@ static struct gpio_desc *of_find_mt2701_gpio(struct device_node *np,
return desc;
}
/*
* Trigger sources are special, they allow us to use any GPIO as a LED trigger
* and have the name "trigger-sources" no matter which kind of phandle it is
* pointing to, whether to a GPIO, a USB host, a network PHY etc. So in this case
* we allow looking something up that is not named "foo-gpios".
*/
static struct gpio_desc *of_find_trigger_gpio(struct device_node *np,
const char *con_id,
unsigned int idx,
enum of_gpio_flags *of_flags)
{
struct gpio_desc *desc;
if (!IS_ENABLED(CONFIG_LEDS_TRIGGER_GPIO))
return ERR_PTR(-ENOENT);
if (!con_id || strcmp(con_id, "trigger-sources"))
return ERR_PTR(-ENOENT);
desc = of_get_named_gpiod_flags(np, con_id, idx, of_flags);
if (!gpiod_not_found(desc))
pr_debug("%s is used as a trigger\n", of_node_full_name(np));
return desc;
}
typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
const char *con_id,
unsigned int idx,
@ -618,6 +655,7 @@ typedef struct gpio_desc *(*of_find_gpio_quirk)(struct device_node *np,
static const of_find_gpio_quirk of_find_gpio_quirks[] = {
of_find_gpio_rename,
of_find_mt2701_gpio,
of_find_trigger_gpio,
NULL
};
@ -813,16 +851,16 @@ static int of_gpiochip_match_node(struct gpio_chip *chip, void *data)
return device_match_of_node(&chip->gpiodev->dev, data);
}
static struct gpio_chip *of_find_gpiochip_by_node(struct device_node *np)
static struct gpio_device *of_find_gpio_device_by_node(struct device_node *np)
{
return gpiochip_find(np, of_gpiochip_match_node);
return gpio_device_find(np, of_gpiochip_match_node);
}
static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
void *arg)
{
struct gpio_device *gdev __free(gpio_device_put) = NULL;
struct of_reconfig_data *rd = arg;
struct gpio_chip *chip;
int ret;
/*
@ -834,38 +872,38 @@ static int of_gpio_notify(struct notifier_block *nb, unsigned long action,
switch (of_reconfig_get_state_change(action, arg)) {
case OF_RECONFIG_CHANGE_ADD:
if (!of_property_read_bool(rd->dn, "gpio-hog"))
return NOTIFY_OK; /* not for us */
return NOTIFY_DONE; /* not for us */
if (of_node_test_and_set_flag(rd->dn, OF_POPULATED))
return NOTIFY_OK;
return NOTIFY_DONE;
chip = of_find_gpiochip_by_node(rd->dn->parent);
if (chip == NULL)
return NOTIFY_OK; /* not for us */
gdev = of_find_gpio_device_by_node(rd->dn->parent);
if (!gdev)
return NOTIFY_DONE; /* not for us */
ret = of_gpiochip_add_hog(chip, rd->dn);
ret = of_gpiochip_add_hog(gpio_device_get_chip(gdev), rd->dn);
if (ret < 0) {
pr_err("%s: failed to add hogs for %pOF\n", __func__,
rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
return notifier_from_errno(ret);
}
break;
return NOTIFY_OK;
case OF_RECONFIG_CHANGE_REMOVE:
if (!of_node_check_flag(rd->dn, OF_POPULATED))
return NOTIFY_OK; /* already depopulated */
return NOTIFY_DONE; /* already depopulated */
chip = of_find_gpiochip_by_node(rd->dn->parent);
if (chip == NULL)
return NOTIFY_OK; /* not for us */
gdev = of_find_gpio_device_by_node(rd->dn->parent);
if (!gdev)
return NOTIFY_DONE; /* not for us */
of_gpiochip_remove_hog(chip, rd->dn);
of_gpiochip_remove_hog(gpio_device_get_chip(gdev), rd->dn);
of_node_clear_flag(rd->dn, OF_POPULATED);
break;
return NOTIFY_OK;
}
return NOTIFY_OK;
return NOTIFY_DONE;
}
struct notifier_block gpio_of_notifier = {

View File

@ -31,22 +31,17 @@ static void swnode_format_propname(const char *con_id, char *propname,
strscpy(propname, "gpios", max_size);
}
static int swnode_gpiochip_match_name(struct gpio_chip *chip, void *data)
static struct gpio_device *swnode_get_gpio_device(struct fwnode_handle *fwnode)
{
return !strcmp(chip->label, data);
}
const struct software_node *gdev_node;
struct gpio_device *gdev;
static struct gpio_chip *swnode_get_chip(struct fwnode_handle *fwnode)
{
const struct software_node *chip_node;
struct gpio_chip *chip;
chip_node = to_software_node(fwnode);
if (!chip_node || !chip_node->name)
gdev_node = to_software_node(fwnode);
if (!gdev_node || !gdev_node->name)
return ERR_PTR(-EINVAL);
chip = gpiochip_find((void *)chip_node->name, swnode_gpiochip_match_name);
return chip ?: ERR_PTR(-EPROBE_DEFER);
gdev = gpio_device_find_by_label(gdev_node->name);
return gdev ?: ERR_PTR(-EPROBE_DEFER);
}
struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
@ -55,7 +50,6 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
{
const struct software_node *swnode;
struct fwnode_reference_args args;
struct gpio_chip *chip;
struct gpio_desc *desc;
char propname[32]; /* 32 is max size of property name */
int error;
@ -77,12 +71,17 @@ struct gpio_desc *swnode_find_gpio(struct fwnode_handle *fwnode,
return ERR_PTR(error);
}
chip = swnode_get_chip(args.fwnode);
struct gpio_device *gdev __free(gpio_device_put) =
swnode_get_gpio_device(args.fwnode);
fwnode_handle_put(args.fwnode);
if (IS_ERR(chip))
return ERR_CAST(chip);
if (IS_ERR(gdev))
return ERR_CAST(gdev);
desc = gpiochip_get_desc(chip, args.args[0]);
/*
* FIXME: The GPIO device reference is put at return but the descriptor
* is passed on. Find a proper solution.
*/
desc = gpio_device_get_desc(gdev, args.args[0]);
*flags = args.args[1]; /* We expect native GPIO flags */
pr_debug("%s: parsed '%s' property of node '%pfwP[%d]' - status (%d)\n",

View File

@ -814,7 +814,7 @@ static int __init gpiolib_sysfs_init(void)
* gpiochip_sysfs_register() acquires a mutex. This is unsafe
* and needs to be fixed.
*
* Also it would be nice to use gpiochip_find() here so we
* Also it would be nice to use gpio_device_find() here so we
* can keep gpio_chips local to gpiolib.c, but the yield of
* gpio_lock prevents us from doing this.
*/

View File

@ -20,6 +20,7 @@
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/gpio.h>
#include <linux/gpio/driver.h>
@ -146,27 +147,49 @@ struct gpio_desc *gpio_to_desc(unsigned gpio)
}
EXPORT_SYMBOL_GPL(gpio_to_desc);
/**
* gpiochip_get_desc - get the GPIO descriptor corresponding to the given
* hardware number for this chip
* @gc: GPIO chip
* @hwnum: hardware number of the GPIO for this chip
*
* Returns:
* A pointer to the GPIO descriptor or ``ERR_PTR(-EINVAL)`` if no GPIO exists
* in the given chip for the specified hardware number.
*/
/* This function is deprecated and will be removed soon, don't use. */
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc,
unsigned int hwnum)
{
struct gpio_device *gdev = gc->gpiodev;
return gpio_device_get_desc(gc->gpiodev, hwnum);
}
EXPORT_SYMBOL_GPL(gpiochip_get_desc);
/**
* gpio_device_get_desc() - get the GPIO descriptor corresponding to the given
* hardware number for this GPIO device
* @gdev: GPIO device to get the descriptor from
* @hwnum: hardware number of the GPIO for this chip
*
* Returns:
* A pointer to the GPIO descriptor or %EINVAL if no GPIO exists in the given
* chip for the specified hardware number or %ENODEV if the underlying chip
* already vanished.
*
* The reference count of struct gpio_device is *NOT* increased like when the
* GPIO is being requested for exclusive usage. It's up to the caller to make
* sure the GPIO device will stay alive together with the descriptor returned
* by this function.
*/
struct gpio_desc *
gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum)
{
struct gpio_chip *gc;
/*
* FIXME: This will be locked once we protect gdev->chip everywhere
* with SRCU.
*/
gc = gdev->chip;
if (!gc)
return ERR_PTR(-ENODEV);
if (hwnum >= gdev->ngpio)
return ERR_PTR(-EINVAL);
return &gdev->descs[hwnum];
}
EXPORT_SYMBOL_GPL(gpiochip_get_desc);
EXPORT_SYMBOL_GPL(gpio_device_get_desc);
/**
* desc_to_gpio - convert a GPIO descriptor to the integer namespace
@ -197,6 +220,61 @@ struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc)
}
EXPORT_SYMBOL_GPL(gpiod_to_chip);
/**
* gpiod_to_gpio_device() - Return the GPIO device to which this descriptor
* belongs.
* @desc: Descriptor for which to return the GPIO device.
*
* This *DOES NOT* increase the reference count of the GPIO device as it's
* expected that the descriptor is requested and the users already holds a
* reference to the device.
*
* Returns:
* Address of the GPIO device owning this descriptor.
*/
struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc)
{
if (!desc)
return NULL;
return desc->gdev;
}
EXPORT_SYMBOL_GPL(gpiod_to_gpio_device);
/**
* gpio_device_get_base() - Get the base GPIO number allocated by this device
* @gdev: GPIO device
*
* Returns:
* First GPIO number in the global GPIO numberspace for this device.
*/
int gpio_device_get_base(struct gpio_device *gdev)
{
return gdev->base;
}
EXPORT_SYMBOL_GPL(gpio_device_get_base);
/**
* gpio_device_get_chip() - Get the gpio_chip implementation of this GPIO device
* @gdev: GPIO device
*
* Returns:
* Address of the GPIO chip backing this device.
*
* Until we can get rid of all non-driver users of struct gpio_chip, we must
* provide a way of retrieving the pointer to it from struct gpio_device. This
* is *NOT* safe as the GPIO API is considered to be hot-unpluggable and the
* chip can dissapear at any moment (unlike reference-counted struct
* gpio_device).
*
* Use at your own risk.
*/
struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev)
{
return gdev->chip;
}
EXPORT_SYMBOL_GPL(gpio_device_get_chip);
/* dynamic allocation of GPIOs, e.g. on a hotplugged device */
static int gpiochip_find_base(int ngpio)
{
@ -1014,16 +1092,10 @@ void gpiochip_remove(struct gpio_chip *gc)
}
EXPORT_SYMBOL_GPL(gpiochip_remove);
/**
* gpiochip_find() - iterator for locating a specific gpio_chip
* @data: data to pass to match function
* @match: Callback function to check gpio_chip
/*
* FIXME: This will be removed soon.
*
* Similar to bus_find_device. It returns a reference to a gpio_chip as
* determined by a user supplied @match callback. The callback should return
* 0 if the device doesn't match and non-zero if it does. If the callback is
* non-zero, this function will return to the caller and not iterate over any
* more gpio_chips.
* This function is depracated, don't use.
*/
struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *gc,
@ -1031,32 +1103,142 @@ struct gpio_chip *gpiochip_find(void *data,
{
struct gpio_device *gdev;
struct gpio_chip *gc = NULL;
unsigned long flags;
spin_lock_irqsave(&gpio_lock, flags);
list_for_each_entry(gdev, &gpio_devices, list)
if (gdev->chip && match(gdev->chip, data)) {
gc = gdev->chip;
break;
}
spin_unlock_irqrestore(&gpio_lock, flags);
gdev = gpio_device_find(data, match);
if (gdev) {
gc = gdev->chip;
gpio_device_put(gdev);
}
return gc;
}
EXPORT_SYMBOL_GPL(gpiochip_find);
static int gpiochip_match_name(struct gpio_chip *gc, void *data)
/**
* gpio_device_find() - find a specific GPIO device
* @data: data to pass to match function
* @match: Callback function to check gpio_chip
*
* Returns:
* New reference to struct gpio_device.
*
* Similar to bus_find_device(). It returns a reference to a gpio_device as
* determined by a user supplied @match callback. The callback should return
* 0 if the device doesn't match and non-zero if it does. If the callback
* returns non-zero, this function will return to the caller and not iterate
* over any more gpio_devices.
*
* The callback takes the GPIO chip structure as argument. During the execution
* of the callback function the chip is protected from being freed. TODO: This
* actually has yet to be implemented.
*
* If the function returns non-NULL, the returned reference must be freed by
* the caller using gpio_device_put().
*/
struct gpio_device *gpio_device_find(void *data,
int (*match)(struct gpio_chip *gc,
void *data))
{
const char *name = data;
struct gpio_device *gdev;
return !strcmp(gc->label, name);
/*
* Not yet but in the future the spinlock below will become a mutex.
* Annotate this function before anyone tries to use it in interrupt
* context like it happened with gpiochip_find().
*/
might_sleep();
guard(spinlock_irqsave)(&gpio_lock);
list_for_each_entry(gdev, &gpio_devices, list) {
if (gdev->chip && match(gdev->chip, data))
return gpio_device_get(gdev);
}
return NULL;
}
EXPORT_SYMBOL_GPL(gpio_device_find);
static int gpio_chip_match_by_label(struct gpio_chip *gc, void *label)
{
return gc->label && !strcmp(gc->label, label);
}
static struct gpio_chip *find_chip_by_name(const char *name)
/**
* gpio_device_find_by_label() - wrapper around gpio_device_find() finding the
* GPIO device by its backing chip's label
* @label: Label to lookup
*
* Returns:
* Reference to the GPIO device or NULL. Reference must be released with
* gpio_device_put().
*/
struct gpio_device *gpio_device_find_by_label(const char *label)
{
return gpiochip_find((void *)name, gpiochip_match_name);
return gpio_device_find((void *)label, gpio_chip_match_by_label);
}
EXPORT_SYMBOL_GPL(gpio_device_find_by_label);
static int gpio_chip_match_by_fwnode(struct gpio_chip *gc, void *fwnode)
{
return device_match_fwnode(&gc->gpiodev->dev, fwnode);
}
/**
* gpio_device_find_by_fwnode() - wrapper around gpio_device_find() finding
* the GPIO device by its fwnode
* @fwnode: Firmware node to lookup
*
* Returns:
* Reference to the GPIO device or NULL. Reference must be released with
* gpio_device_put().
*/
struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode)
{
return gpio_device_find((void *)fwnode, gpio_chip_match_by_fwnode);
}
EXPORT_SYMBOL_GPL(gpio_device_find_by_fwnode);
/**
* gpio_device_get() - Increase the reference count of this GPIO device
* @gdev: GPIO device to increase the refcount for
*
* Returns:
* Pointer to @gdev.
*/
struct gpio_device *gpio_device_get(struct gpio_device *gdev)
{
return to_gpio_device(get_device(&gdev->dev));
}
EXPORT_SYMBOL_GPL(gpio_device_get);
/**
* gpio_device_put() - Decrease the reference count of this GPIO device and
* possibly free all resources associated with it.
* @gdev: GPIO device to decrease the reference count for
*/
void gpio_device_put(struct gpio_device *gdev)
{
put_device(&gdev->dev);
}
EXPORT_SYMBOL_GPL(gpio_device_put);
/**
* gpio_device_to_device() - Retrieve the address of the underlying struct
* device.
* @gdev: GPIO device for which to return the address.
*
* This does not increase the reference count of the GPIO device nor the
* underlying struct device.
*
* Returns:
* Address of struct device backing this GPIO device.
*/
struct device *gpio_device_to_device(struct gpio_device *gdev)
{
return &gdev->dev;
}
EXPORT_SYMBOL_GPL(gpio_device_to_device);
#ifdef CONFIG_GPIOLIB_IRQCHIP
@ -2700,7 +2882,6 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
PIN_CONFIG_PERSIST_STATE,
!transitory);
}
EXPORT_SYMBOL_GPL(gpiod_set_transitory);
/**
* gpiod_is_active_low - test whether a GPIO is active-low or not
@ -3786,7 +3967,6 @@ EXPORT_SYMBOL_GPL(gpiod_remove_lookup_table);
*/
void gpiod_add_hogs(struct gpiod_hog *hogs)
{
struct gpio_chip *gc;
struct gpiod_hog *hog;
mutex_lock(&gpio_machine_hogs_mutex);
@ -3798,9 +3978,10 @@ void gpiod_add_hogs(struct gpiod_hog *hogs)
* The chip may have been registered earlier, so check if it
* exists and, if so, try to hog the line now.
*/
gc = find_chip_by_name(hog->chip_label);
if (gc)
gpiochip_machine_hog(gc, hog);
struct gpio_device *gdev __free(gpio_device_put) =
gpio_device_find_by_label(hog->chip_label);
if (gdev)
gpiochip_machine_hog(gpio_device_get_chip(gdev), hog);
}
mutex_unlock(&gpio_machine_hogs_mutex);
@ -3823,8 +4004,6 @@ static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
const char *dev_id = dev ? dev_name(dev) : NULL;
struct gpiod_lookup_table *table;
mutex_lock(&gpio_lookup_lock);
list_for_each_entry(table, &gpio_lookup_list, list) {
if (table->dev_id && dev_id) {
/*
@ -3832,21 +4011,18 @@ static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
* a match
*/
if (!strcmp(table->dev_id, dev_id))
goto found;
return table;
} else {
/*
* One of the pointers is NULL, so both must be to have
* a match
*/
if (dev_id == table->dev_id)
goto found;
return table;
}
}
table = NULL;
found:
mutex_unlock(&gpio_lookup_lock);
return table;
return NULL;
}
static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
@ -3855,14 +4031,15 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
struct gpio_desc *desc = ERR_PTR(-ENOENT);
struct gpiod_lookup_table *table;
struct gpiod_lookup *p;
struct gpio_chip *gc;
guard(mutex)(&gpio_lookup_lock);
table = gpiod_find_lookup_table(dev);
if (!table)
return desc;
for (p = &table->table[0]; p->key; p++) {
struct gpio_chip *gc;
/* idx must always match exactly */
if (p->idx != idx)
continue;
@ -3883,9 +4060,9 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return ERR_PTR(-EPROBE_DEFER);
}
gc = find_chip_by_name(p->key);
if (!gc) {
struct gpio_device *gdev __free(gpio_device_put) =
gpio_device_find_by_label(p->key);
if (!gdev) {
/*
* As the lookup table indicates a chip with
* p->key should exist, assume it may
@ -3898,6 +4075,8 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return ERR_PTR(-EPROBE_DEFER);
}
gc = gpio_device_get_chip(gdev);
if (gc->ngpio <= p->chip_hwnum) {
dev_err(dev,
"requested GPIO %u (%u) is out of range [0..%u] for chip %s\n",
@ -3906,7 +4085,7 @@ static struct gpio_desc *gpiod_find(struct device *dev, const char *con_id,
return ERR_PTR(-EINVAL);
}
desc = gpiochip_get_desc(gc, p->chip_hwnum);
desc = gpio_device_get_desc(gdev, p->chip_hwnum);
*flags = p->flags;
return desc;
@ -3921,15 +4100,18 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
struct gpiod_lookup *p;
unsigned int count = 0;
table = gpiod_find_lookup_table(dev);
if (!table)
return -ENOENT;
scoped_guard(mutex, &gpio_lookup_lock) {
table = gpiod_find_lookup_table(dev);
if (!table)
return -ENOENT;
for (p = &table->table[0]; p->key; p++) {
if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) ||
(!con_id && !p->con_id))
count++;
for (p = &table->table[0]; p->key; p++) {
if ((con_id && p->con_id && !strcmp(con_id, p->con_id)) ||
(!con_id && !p->con_id))
count++;
}
}
if (!count)
return -ENOENT;

View File

@ -86,16 +86,6 @@ static inline struct gpio_device *to_gpio_device(struct device *dev)
return container_of(dev, struct gpio_device, dev);
}
static inline struct gpio_device *gpio_device_get(struct gpio_device *gdev)
{
return to_gpio_device(get_device(&gdev->dev));
}
static inline void gpio_device_put(struct gpio_device *gdev)
{
put_device(&gdev->dev);
}
/* gpio suffixes used for ACPI and device tree lookup */
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
@ -122,8 +112,6 @@ struct gpio_array {
unsigned long invert_mask[];
};
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
#define for_each_gpio_desc(gc, desc) \
for (unsigned int __i = 0; \
__i < gc->ngpio && (desc = gpiochip_get_desc(gc, __i)); \
@ -144,6 +132,8 @@ int gpiod_set_array_value_complex(bool raw, bool can_sleep,
struct gpio_array *array_info,
unsigned long *value_bitmap);
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
extern spinlock_t gpio_lock;
extern struct list_head gpio_devices;

View File

@ -17,6 +17,7 @@ if HTE
config HTE_TEGRA194
tristate "NVIDIA Tegra194 HTE Support"
depends on ARCH_TEGRA_194_SOC
depends on GPIOLIB
help
Enable this option for integrated hardware timestamping engine also
known as generic timestamping engine (GTE) support on NVIDIA Tegra194

View File

@ -132,7 +132,7 @@ struct tegra_hte_soc {
const struct tegra_hte_data *prov_data;
struct tegra_hte_line_data *line_data;
struct hte_chip *chip;
struct gpio_chip *c;
struct gpio_device *gdev;
void __iomem *regs;
};
@ -418,7 +418,7 @@ static int tegra_hte_line_xlate(struct hte_chip *gc,
* HTE/GTE namespace.
*/
if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO && !args) {
line_id = desc->attr.line_id - gs->c->base;
line_id = desc->attr.line_id - gpio_device_get_base(gs->gdev);
map = gs->prov_data->map;
map_sz = gs->prov_data->map_sz;
} else if (gs->prov_data->type == HTE_TEGRA_TYPE_GPIO && args) {
@ -645,7 +645,7 @@ static bool tegra_hte_match_from_linedata(const struct hte_chip *chip,
if (!hte_dev || (hte_dev->prov_data->type != HTE_TEGRA_TYPE_GPIO))
return false;
return hte_dev->c == gpiod_to_chip(hdesc->attr.line_data);
return hte_dev->gdev == gpiod_to_gpio_device(hdesc->attr.line_data);
}
static const struct of_device_id tegra_hte_of_match[] = {
@ -673,14 +673,11 @@ static void tegra_gte_disable(void *data)
tegra_hte_writel(gs, HTE_TECTRL, 0);
}
static int tegra_get_gpiochip_from_name(struct gpio_chip *chip, void *data)
static void tegra_hte_put_gpio_device(void *data)
{
return !strcmp(chip->label, data);
}
struct gpio_device *gdev = data;
static int tegra_gpiochip_match(struct gpio_chip *chip, void *data)
{
return chip->fwnode == of_node_to_fwnode(data);
gpio_device_put(gdev);
}
static int tegra_hte_probe(struct platform_device *pdev)
@ -760,8 +757,8 @@ static int tegra_hte_probe(struct platform_device *pdev)
if (of_device_is_compatible(dev->of_node,
"nvidia,tegra194-gte-aon")) {
hte_dev->c = gpiochip_find("tegra194-gpio-aon",
tegra_get_gpiochip_from_name);
hte_dev->gdev =
gpio_device_find_by_label("tegra194-gpio-aon");
} else {
gpio_ctrl = of_parse_phandle(dev->of_node,
"nvidia,gpio-controller",
@ -772,14 +769,19 @@ static int tegra_hte_probe(struct platform_device *pdev)
return -ENODEV;
}
hte_dev->c = gpiochip_find(gpio_ctrl,
tegra_gpiochip_match);
hte_dev->gdev =
gpio_device_find_by_fwnode(of_fwnode_handle(gpio_ctrl));
of_node_put(gpio_ctrl);
}
if (!hte_dev->c)
if (!hte_dev->gdev)
return dev_err_probe(dev, -EPROBE_DEFER,
"wait for gpio controller\n");
ret = devm_add_action_or_reset(dev, tegra_hte_put_gpio_device,
hte_dev->gdev);
if (ret)
return ret;
}
hte_dev->chip = gc;

View File

@ -14,8 +14,7 @@
#include <linux/slab.h>
#include <linux/bits.h>
#include <linux/gpio/consumer.h>
/* FIXME: stop poking around inside gpiolib */
#include "../../gpio/gpiolib.h"
#include <linux/gpio/driver.h>
struct gpiomux {
struct i2c_mux_gpio_platform_data data;
@ -178,7 +177,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
}
for (i = 0; i < ngpios; i++) {
struct device *gpio_dev;
struct gpio_device *gdev;
struct device *dev;
struct gpio_desc *gpiod;
enum gpiod_flags flag;
@ -197,9 +197,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev)
if (!muxc->mux_locked)
continue;
/* FIXME: find a proper way to access the GPIO device */
gpio_dev = &gpiod->gdev->dev;
muxc->mux_locked = i2c_root_adapter(gpio_dev) == root;
gdev = gpiod_to_gpio_device(gpiod);
dev = gpio_device_to_device(gdev);
muxc->mux_locked = i2c_root_adapter(dev) == root;
}
if (muxc->mux_locked)

View File

@ -380,18 +380,6 @@ static int ingenic_nand_init_chip(struct platform_device *pdev,
return ret;
}
/*
* The rb-gpios semantics was undocumented and qi,lb60 (along with
* the ingenic driver) got it wrong. The active state encodes the
* NAND ready state, which is high level. Since there's no signal
* inverter on this board, it should be active-high. Let's fix that
* here for older DTs so we can re-use the generic nand_gpio_waitrdy()
* helper, and be consistent with what other drivers do.
*/
if (of_machine_is_compatible("qi,lb60") &&
gpiod_is_active_low(nand->busy_gpio))
gpiod_toggle_active_low(nand->busy_gpio);
nand->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_LOW);
if (IS_ERR(nand->wp_gpio)) {

View File

@ -17,17 +17,12 @@
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/mfd/da9062/core.h>
#include <linux/mfd/da9062/registers.h>
/*
* We need this get the gpio_desc from a <gpio_chip,offset> tuple to decide if
* the gpio is active low without a vendor specific dt-binding.
*/
#include "../gpio/gpiolib.h"
#define DA9062_TYPE(offset) (4 * (offset % 2))
#define DA9062_PIN_SHIFT(offset) (4 * (offset % 2))
#define DA9062_PIN_ALTERNATE 0x00 /* gpio alternate mode */

View File

@ -162,9 +162,8 @@ int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472)
}
int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity)
struct gpio_desc *gpio)
{
char *path = agpio->resource_source.string_ptr;
struct clk_init_data init = {
.ops = &skl_int3472_clock_ops,
.flags = CLK_GET_RATE_NOCACHE,
@ -174,26 +173,12 @@ int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
if (int3472->clock.cl)
return -EBUSY;
int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
"int3472,clk-enable");
if (IS_ERR(int3472->clock.ena_gpio)) {
ret = PTR_ERR(int3472->clock.ena_gpio);
int3472->clock.ena_gpio = NULL;
return dev_err_probe(int3472->dev, ret, "getting clk-enable GPIO\n");
}
if (polarity == GPIO_ACTIVE_LOW)
gpiod_toggle_active_low(int3472->clock.ena_gpio);
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->clock.ena_gpio, 0);
int3472->clock.ena_gpio = gpio;
init.name = kasprintf(GFP_KERNEL, "%s-clk",
acpi_dev_name(int3472->adev));
if (!init.name) {
ret = -ENOMEM;
goto out_put_gpio;
}
if (!init.name)
return -ENOMEM;
int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
@ -219,8 +204,6 @@ int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
clk_unregister(int3472->clock.clk);
out_free_init_name:
kfree(init.name);
out_put_gpio:
gpiod_put(int3472->clock.ena_gpio);
return ret;
}
@ -232,7 +215,6 @@ void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
clkdev_drop(int3472->clock.cl);
clk_unregister(int3472->clock.clk);
gpiod_put(int3472->clock.ena_gpio);
}
/*
@ -273,14 +255,13 @@ static const struct dmi_system_id skl_int3472_regulator_second_sensor[] = {
};
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio)
struct gpio_desc *gpio)
{
char *path = agpio->resource_source.string_ptr;
struct regulator_init_data init_data = { };
struct regulator_config cfg = { };
const char *second_sensor = NULL;
const struct dmi_system_id *id;
int i, j, ret;
int i, j;
id = dmi_first_match(skl_int3472_regulator_second_sensor);
if (id)
@ -314,16 +295,7 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
int3472->regulator.supply_name,
&int3472_gpio_regulator_ops);
int3472->regulator.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
"int3472,regulator");
if (IS_ERR(int3472->regulator.gpio)) {
ret = PTR_ERR(int3472->regulator.gpio);
int3472->regulator.gpio = NULL;
return dev_err_probe(int3472->dev, ret, "getting regulator GPIO\n");
}
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->regulator.gpio, 0);
int3472->regulator.gpio = gpio;
cfg.dev = &int3472->adev->dev;
cfg.init_data = &init_data;
@ -332,21 +304,11 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
int3472->regulator.rdev = regulator_register(int3472->dev,
&int3472->regulator.rdesc,
&cfg);
if (IS_ERR(int3472->regulator.rdev)) {
ret = PTR_ERR(int3472->regulator.rdev);
goto err_free_gpio;
}
return 0;
err_free_gpio:
gpiod_put(int3472->regulator.gpio);
return ret;
return PTR_ERR_OR_ZERO(int3472->regulator.rdev);
}
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472)
{
regulator_unregister(int3472->regulator.rdev);
gpiod_put(int3472->regulator.gpio);
}

View File

@ -117,16 +117,15 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
const char **name_ret);
int skl_int3472_register_gpio_clock(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity);
struct gpio_desc *gpio);
int skl_int3472_register_dsm_clock(struct int3472_discrete_device *int3472);
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio);
struct gpio_desc *gpio);
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity);
int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio);
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
#endif

View File

@ -52,21 +52,15 @@ static void skl_int3472_log_sensor_module_name(struct int3472_discrete_device *i
}
}
static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio,
const char *func, u32 polarity)
static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
struct acpi_resource_gpio *agpio,
const char *func, u32 polarity)
{
char *path = agpio->resource_source.string_ptr;
struct gpiod_lookup *table_entry;
struct acpi_device *adev;
acpi_handle handle;
acpi_status status;
if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
dev_warn(int3472->dev, "Too many GPIOs mapped\n");
return -EINVAL;
}
status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status))
return -EINVAL;
@ -75,18 +69,62 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
if (!adev)
return -ENODEV;
table_entry = &int3472->gpios.table[int3472->n_sensor_gpios];
table_entry->key = acpi_dev_name(adev);
table_entry->chip_hwnum = agpio->pin_table[0];
table_entry->con_id = func;
table_entry->idx = 0;
table_entry->flags = polarity;
return 0;
}
static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio,
const char *func, u32 polarity)
{
int ret;
if (int3472->n_sensor_gpios >= INT3472_MAX_SENSOR_GPIOS) {
dev_warn(int3472->dev, "Too many GPIOs mapped\n");
return -EINVAL;
}
ret = skl_int3472_fill_gpiod_lookup(&int3472->gpios.table[int3472->n_sensor_gpios],
agpio, func, polarity);
if (ret)
return ret;
int3472->n_sensor_gpios++;
return 0;
}
/* This should *really* only be used when there's no other way... */
static struct gpio_desc *
skl_int3472_gpiod_get_from_temp_lookup(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio,
const char *func, u32 polarity)
{
struct gpio_desc *desc;
int ret;
struct gpiod_lookup_table *lookup __free(kfree) =
kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
if (!lookup)
return ERR_PTR(-ENOMEM);
lookup->dev_id = dev_name(int3472->dev);
ret = skl_int3472_fill_gpiod_lookup(&lookup->table[0], agpio, func, polarity);
if (ret)
return ERR_PTR(ret);
gpiod_add_lookup_table(lookup);
desc = devm_gpiod_get(int3472->dev, func, GPIOD_OUT_LOW);
gpiod_remove_lookup_table(lookup);
return desc;
}
static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
{
switch (type) {
@ -156,6 +194,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
struct acpi_resource_gpio *agpio;
u8 active_value, pin, type;
union acpi_object *obj;
struct gpio_desc *gpio;
const char *err_msg;
const char *func;
u32 polarity;
@ -206,22 +245,38 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
ret = skl_int3472_register_gpio_clock(int3472, agpio, polarity);
if (ret)
err_msg = "Failed to register clock\n";
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
ret = skl_int3472_register_pled(int3472, agpio, polarity);
if (ret)
err_msg = "Failed to register LED\n";
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
ret = skl_int3472_register_regulator(int3472, agpio);
if (ret)
err_msg = "Failed to map regulator to sensor\n";
gpio = skl_int3472_gpiod_get_from_temp_lookup(int3472, agpio, func, polarity);
if (IS_ERR(gpio)) {
ret = PTR_ERR(gpio);
err_msg = "Failed to get GPIO\n";
break;
}
switch (type) {
case INT3472_GPIO_TYPE_CLK_ENABLE:
ret = skl_int3472_register_gpio_clock(int3472, gpio);
if (ret)
err_msg = "Failed to register clock\n";
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
ret = skl_int3472_register_pled(int3472, gpio);
if (ret)
err_msg = "Failed to register LED\n";
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
ret = skl_int3472_register_regulator(int3472, gpio);
if (ret)
err_msg = "Failed to map regulator to sensor\n";
break;
default: /* Never reached */
ret = -EINVAL;
break;
}
break;
default:
dev_warn(int3472->dev,

View File

@ -16,26 +16,15 @@ static int int3472_pled_set(struct led_classdev *led_cdev,
return 0;
}
int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio, u32 polarity)
int skl_int3472_register_pled(struct int3472_discrete_device *int3472, struct gpio_desc *gpio)
{
char *p, *path = agpio->resource_source.string_ptr;
char *p;
int ret;
if (int3472->pled.classdev.dev)
return -EBUSY;
int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
"int3472,privacy-led");
if (IS_ERR(int3472->pled.gpio))
return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio),
"getting privacy LED GPIO\n");
if (polarity == GPIO_ACTIVE_LOW)
gpiod_toggle_active_low(int3472->pled.gpio);
/* Ensure the pin is in output mode and non-active state */
gpiod_direction_output(int3472->pled.gpio, 0);
int3472->pled.gpio = gpio;
/* Generate the name, replacing the ':' in the ACPI devname with '_' */
snprintf(int3472->pled.name, sizeof(int3472->pled.name),
@ -50,7 +39,7 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
if (ret)
goto err_free_gpio;
return ret;
int3472->pled.lookup.provider = int3472->pled.name;
int3472->pled.lookup.dev_id = int3472->sensor_name;
@ -58,10 +47,6 @@ int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
led_add_lookup(&int3472->pled.lookup);
return 0;
err_free_gpio:
gpiod_put(int3472->pled.gpio);
return ret;
}
void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
@ -71,5 +56,4 @@ void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
led_remove_lookup(&int3472->pled.lookup);
led_classdev_unregister(&int3472->pled.classdev);
gpiod_put(int3472->pled.gpio);
}

View File

@ -303,6 +303,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
.index = 28,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "atmel_mxt_ts_irq",
},
},
};

View File

@ -12,7 +12,7 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
#include <linux/irq.h>
#include <linux/module.h>
@ -21,33 +21,39 @@
#include <linux/string.h>
#include "x86-android-tablets.h"
/* For gpiochip_get_desc() which is EXPORT_SYMBOL_GPL() */
#include "../../../gpio/gpiolib.h"
#include "../../../gpio/gpiolib-acpi.h"
static int gpiochip_find_match_label(struct gpio_chip *gc, void *data)
{
return gc->label && !strcmp(gc->label, data);
}
static struct platform_device *x86_android_tablet_device;
int x86_android_tablet_get_gpiod(const char *label, int pin, struct gpio_desc **desc)
int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
bool active_low, enum gpiod_flags dflags,
struct gpio_desc **desc)
{
struct gpiod_lookup_table *lookup;
struct gpio_desc *gpiod;
struct gpio_chip *chip;
chip = gpiochip_find((void *)label, gpiochip_find_match_label);
if (!chip) {
pr_err("error cannot find GPIO chip %s\n", label);
return -ENODEV;
}
lookup = kzalloc(struct_size(lookup, table, 2), GFP_KERNEL);
if (!lookup)
return -ENOMEM;
lookup->dev_id = KBUILD_MODNAME;
lookup->table[0].key = chip;
lookup->table[0].chip_hwnum = pin;
lookup->table[0].con_id = con_id;
lookup->table[0].flags = active_low ? GPIO_ACTIVE_LOW : GPIO_ACTIVE_HIGH;
gpiod_add_lookup_table(lookup);
gpiod = devm_gpiod_get(&x86_android_tablet_device->dev, con_id, dflags);
gpiod_remove_lookup_table(lookup);
kfree(lookup);
gpiod = gpiochip_get_desc(chip, pin);
if (IS_ERR(gpiod)) {
pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), label, pin);
pr_err("error %ld getting GPIO %s %d\n", PTR_ERR(gpiod), chip, pin);
return PTR_ERR(gpiod);
}
*desc = gpiod;
if (desc)
*desc = gpiod;
return 0;
}
@ -77,7 +83,8 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
return irq;
case X86_ACPI_IRQ_TYPE_GPIOINT:
/* Like acpi_dev_gpio_irq_get(), but without parsing ACPI resources */
ret = x86_android_tablet_get_gpiod(data->chip, data->index, &gpiod);
ret = x86_android_tablet_get_gpiod(data->chip, data->index, data->con_id,
false, GPIOD_ASIS, &gpiod);
if (ret)
return ret;
@ -224,7 +231,7 @@ static __init int x86_instantiate_serdev(const struct x86_serdev_info *info, int
return ret;
}
static void x86_android_tablet_cleanup(void)
static void x86_android_tablet_remove(struct platform_device *pdev)
{
int i;
@ -255,11 +262,10 @@ static void x86_android_tablet_cleanup(void)
software_node_unregister(bat_swnode);
}
static __init int x86_android_tablet_init(void)
static __init int x86_android_tablet_probe(struct platform_device *pdev)
{
const struct x86_dev_info *dev_info;
const struct dmi_system_id *id;
struct gpio_chip *chip;
int i, ret = 0;
id = dmi_first_match(x86_android_tablet_ids);
@ -267,20 +273,8 @@ static __init int x86_android_tablet_init(void)
return -ENODEV;
dev_info = id->driver_data;
/*
* The broken DSDTs on these devices often also include broken
* _AEI (ACPI Event Interrupt) handlers, disable these.
*/
if (dev_info->invalid_aei_gpiochip) {
chip = gpiochip_find(dev_info->invalid_aei_gpiochip,
gpiochip_find_match_label);
if (!chip) {
pr_err("error cannot find GPIO chip %s\n", dev_info->invalid_aei_gpiochip);
return -ENODEV;
}
acpi_gpiochip_free_interrupts(chip);
}
/* Allow x86_android_tablet_device use before probe() exits */
x86_android_tablet_device = pdev;
/*
* Since this runs from module_init() it cannot use -EPROBE_DEFER,
@ -303,7 +297,7 @@ static __init int x86_android_tablet_init(void)
if (dev_info->init) {
ret = dev_info->init();
if (ret < 0) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return ret;
}
exit_handler = dev_info->exit;
@ -311,7 +305,7 @@ static __init int x86_android_tablet_init(void)
i2c_clients = kcalloc(dev_info->i2c_client_count, sizeof(*i2c_clients), GFP_KERNEL);
if (!i2c_clients) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@ -319,7 +313,7 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < i2c_client_count; i++) {
ret = x86_instantiate_i2c_client(dev_info, i);
if (ret < 0) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return ret;
}
}
@ -327,7 +321,7 @@ static __init int x86_android_tablet_init(void)
/* + 1 to make space for (optional) gpio_keys_button pdev */
pdevs = kcalloc(dev_info->pdev_count + 1, sizeof(*pdevs), GFP_KERNEL);
if (!pdevs) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@ -335,14 +329,14 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < pdev_count; i++) {
pdevs[i] = platform_device_register_full(&dev_info->pdev_info[i]);
if (IS_ERR(pdevs[i])) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return PTR_ERR(pdevs[i]);
}
}
serdevs = kcalloc(dev_info->serdev_count, sizeof(*serdevs), GFP_KERNEL);
if (!serdevs) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return -ENOMEM;
}
@ -350,7 +344,7 @@ static __init int x86_android_tablet_init(void)
for (i = 0; i < serdev_count; i++) {
ret = x86_instantiate_serdev(&dev_info->serdev_info[i], i);
if (ret < 0) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return ret;
}
}
@ -361,30 +355,34 @@ static __init int x86_android_tablet_init(void)
buttons = kcalloc(dev_info->gpio_button_count, sizeof(*buttons), GFP_KERNEL);
if (!buttons) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return -ENOMEM;
}
for (i = 0; i < dev_info->gpio_button_count; i++) {
ret = x86_android_tablet_get_gpiod(dev_info->gpio_button[i].chip,
dev_info->gpio_button[i].pin, &gpiod);
dev_info->gpio_button[i].pin,
dev_info->gpio_button[i].button.desc,
false, GPIOD_IN, &gpiod);
if (ret < 0) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return ret;
}
buttons[i] = dev_info->gpio_button[i].button;
buttons[i].gpio = desc_to_gpio(gpiod);
/* Release gpiod so that gpio-keys can request it */
devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
}
pdata.buttons = buttons;
pdata.nbuttons = dev_info->gpio_button_count;
pdevs[pdev_count] = platform_device_register_data(NULL, "gpio-keys",
pdevs[pdev_count] = platform_device_register_data(&pdev->dev, "gpio-keys",
PLATFORM_DEVID_AUTO,
&pdata, sizeof(pdata));
if (IS_ERR(pdevs[pdev_count])) {
x86_android_tablet_cleanup();
x86_android_tablet_remove(pdev);
return PTR_ERR(pdevs[pdev_count]);
}
pdev_count++;
@ -393,8 +391,29 @@ static __init int x86_android_tablet_init(void)
return 0;
}
static struct platform_driver x86_android_tablet_driver = {
.driver = {
.name = KBUILD_MODNAME,
},
.remove_new = x86_android_tablet_remove,
};
static int __init x86_android_tablet_init(void)
{
x86_android_tablet_device = platform_create_bundle(&x86_android_tablet_driver,
x86_android_tablet_probe,
NULL, 0, NULL, 0);
return PTR_ERR_OR_ZERO(x86_android_tablet_device);
}
module_init(x86_android_tablet_init);
module_exit(x86_android_tablet_cleanup);
static void __exit x86_android_tablet_exit(void)
{
platform_device_unregister(x86_android_tablet_device);
platform_driver_unregister(&x86_android_tablet_driver);
}
module_exit(x86_android_tablet_exit);
MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("X86 Android tablets DSDT fixups driver");

View File

@ -95,6 +95,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 56,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "goodix_ts_irq",
},
}, {
/* Wacom Digitizer in keyboard half */
@ -111,6 +112,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 49,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "wacom_irq",
},
}, {
/* LP8557 Backlight controller */
@ -136,6 +138,7 @@ static const struct x86_i2c_client_info lenovo_yb1_x90_i2c_clients[] __initconst
.index = 77,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "hideep_ts_irq",
},
},
};
@ -321,6 +324,7 @@ static struct x86_i2c_client_info lenovo_yoga_tab2_830_1050_i2c_clients[] __init
.index = 2,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
.con_id = "bq24292i_irq",
},
}, {
/* BQ27541 fuel-gauge */
@ -431,7 +435,8 @@ static int __init lenovo_yoga_tab2_830_1050_init_touchscreen(void)
int ret;
/* Use PMIC GPIO 10 bootstrap pin to differentiate 830 vs 1050 */
ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, &gpiod);
ret = x86_android_tablet_get_gpiod("gpio_crystalcove", 10, "yoga_bootstrap",
false, GPIOD_IN, &gpiod);
if (ret)
return ret;
@ -560,7 +565,6 @@ static const struct software_node fg_bq25890_1_supply_node = {
/* bq25892 charger settings for the flat lipo battery behind the screen */
static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
PROPERTY_ENTRY_STRING("linux,power-supply-name", "bq25892-second-chrg"),
PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
PROPERTY_ENTRY_BOOL("linux,skip-reset"),
/* Values taken from Android Factory Image */
@ -615,6 +619,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
.index = 5,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "bq25892_0_irq",
},
}, {
/* bq27500 fuel-gauge for the round li-ion cells in the hinge */
@ -640,6 +645,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
.index = 77,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "hideep_ts_irq",
},
}, {
/* LP8557 Backlight controller */
@ -655,7 +661,6 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
static int __init lenovo_yt3_init(void)
{
struct gpio_desc *gpiod;
int ret;
/*
@ -665,31 +670,23 @@ static int __init lenovo_yt3_init(void)
*
* The bq25890_charger driver controls these through I2C, but this only
* works if not overridden by the pins. Set these pins here:
* 1. Set /CE to 0 to allow charging.
* 1. Set /CE to 1 to allow charging.
* 2. Set OTG to 0 disable V5 boost output since the 5V boost output of
* the main "bq25892_1" charger is used when necessary.
*/
/* /CE pin */
ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, &gpiod);
ret = x86_android_tablet_get_gpiod("INT33FF:02", 22, "bq25892_0_ce",
true, GPIOD_OUT_HIGH, NULL);
if (ret < 0)
return ret;
/*
* The gpio_desc returned by x86_android_tablet_get_gpiod() is a "raw"
* gpio_desc, that is there is no way to pass lookup-flags like
* GPIO_ACTIVE_LOW. Set the GPIO to 0 here to enable charging since
* the /CE pin is active-low, but not marked as such in the gpio_desc.
*/
gpiod_set_value(gpiod, 0);
/* OTG pin */
ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, &gpiod);
ret = x86_android_tablet_get_gpiod("INT33FF:03", 19, "bq25892_0_otg",
false, GPIOD_OUT_LOW, NULL);
if (ret < 0)
return ret;
gpiod_set_value(gpiod, 0);
/* Enable the regulators used by the touchscreen */
intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0x9b, 0x02, 0xff);
intel_soc_pmic_exec_mipi_pmic_seq_element(0x6e, 0xa0, 0x02, 0xff);

View File

@ -47,6 +47,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst =
.index = 3,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "NVT-ts_irq",
},
}, {
/* BMA250E accelerometer */
@ -62,6 +63,7 @@ static const struct x86_i2c_client_info acer_b1_750_i2c_clients[] __initconst =
.index = 25,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
.con_id = "bma250e_irq",
},
},
};
@ -174,6 +176,7 @@ static const struct x86_i2c_client_info chuwi_hi8_i2c_clients[] __initconst = {
.index = 23,
.trigger = ACPI_LEVEL_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
.con_id = "bma250e_irq",
},
},
};
@ -312,6 +315,7 @@ static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __in
.index = 23,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_HIGH,
.con_id = "kxtj21009_irq",
},
}, {
/* goodix touchscreen */
@ -402,6 +406,7 @@ static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst
.index = 3,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "ft5416_irq",
},
},
};
@ -460,6 +465,7 @@ static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initcons
.index = 17,
.trigger = ACPI_EDGE_SENSITIVE,
.polarity = ACPI_ACTIVE_LOW,
.con_id = "ft5416_irq",
},
},
};
@ -505,11 +511,6 @@ static const struct x86_gpio_button peaq_c1010_button __initconst = {
const struct x86_dev_info peaq_c1010_info __initconst = {
.gpio_button = &peaq_c1010_button,
.gpio_button_count = 1,
/*
* Move the ACPI event handler used by the broken WMI interface out of
* the way. This is the only event handler on INT33FC:00.
*/
.invalid_aei_gpiochip = "INT33FC:00",
};
/*

View File

@ -10,6 +10,7 @@
#ifndef __PDX86_X86_ANDROID_TABLETS_H
#define __PDX86_X86_ANDROID_TABLETS_H
#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
#include <linux/i2c.h>
#include <linux/irqdomain_defs.h>
@ -37,6 +38,7 @@ struct x86_acpi_irq_data {
int index;
int trigger; /* ACPI_EDGE_SENSITIVE / ACPI_LEVEL_SENSITIVE */
int polarity; /* ACPI_ACTIVE_HIGH / ACPI_ACTIVE_LOW / ACPI_ACTIVE_BOTH */
const char *con_id;
};
/* Structs to describe devices to instantiate */
@ -66,7 +68,6 @@ struct x86_gpio_button {
};
struct x86_dev_info {
char *invalid_aei_gpiochip;
const char * const *modules;
const struct software_node *bat_swnode;
struct gpiod_lookup_table * const *gpiod_lookup_tables;
@ -82,7 +83,9 @@ struct x86_dev_info {
void (*exit)(void);
};
int x86_android_tablet_get_gpiod(const char *label, int pin, struct gpio_desc **desc);
int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
bool active_low, enum gpiod_flags dflags,
struct gpio_desc **desc);
int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data);
/*

View File

@ -159,7 +159,6 @@ int gpiod_set_raw_array_value_cansleep(unsigned int array_size,
int gpiod_set_config(struct gpio_desc *desc, unsigned long config);
int gpiod_set_debounce(struct gpio_desc *desc, unsigned int debounce);
int gpiod_set_transitory(struct gpio_desc *desc, bool transitory);
void gpiod_toggle_active_low(struct gpio_desc *desc);
int gpiod_is_active_low(const struct gpio_desc *desc);
@ -494,13 +493,6 @@ static inline int gpiod_set_debounce(struct gpio_desc *desc, unsigned int deboun
return -ENOSYS;
}
static inline int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
{
/* GPIO can never have been requested */
WARN_ON(desc);
return -ENOSYS;
}
static inline void gpiod_toggle_active_low(struct gpio_desc *desc)
{
/* GPIO can never have been requested */
@ -614,8 +606,6 @@ void acpi_dev_remove_driver_gpios(struct acpi_device *adev);
int devm_acpi_dev_add_driver_gpios(struct device *dev,
const struct acpi_gpio_mapping *gpios);
struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin, char *label);
#else /* CONFIG_GPIOLIB && CONFIG_ACPI */
#include <linux/err.h>
@ -633,12 +623,6 @@ static inline int devm_acpi_dev_add_driver_gpios(struct device *dev,
return -ENXIO;
}
static inline struct gpio_desc *acpi_get_and_request_gpiod(char *path, unsigned int pin,
char *label)
{
return ERR_PTR(-ENOSYS);
}
#endif /* CONFIG_GPIOLIB && CONFIG_ACPI */

View File

@ -3,6 +3,8 @@
#define __LINUX_GPIO_DRIVER_H
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/err.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/irqdomain.h>
#include <linux/irqhandler.h>
@ -529,8 +531,7 @@ struct gpio_chip {
#endif /* CONFIG_OF_GPIO */
};
extern const char *gpiochip_is_requested(struct gpio_chip *gc,
unsigned int offset);
const char *gpiochip_is_requested(struct gpio_chip *gc, unsigned int offset);
/**
* for_each_requested_gpio_in_range - iterates over requested GPIOs in a given range
@ -549,9 +550,9 @@ extern const char *gpiochip_is_requested(struct gpio_chip *gc,
for_each_requested_gpio_in_range(chip, i, 0, chip->ngpio, label)
/* add/remove chips */
extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
/**
* gpiochip_add_data() - register a gpio_chip
@ -599,13 +600,26 @@ static inline int gpiochip_add(struct gpio_chip *gc)
{
return gpiochip_add_data(gc, NULL);
}
extern void gpiochip_remove(struct gpio_chip *gc);
extern int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc, void *data,
struct lock_class_key *lock_key,
struct lock_class_key *request_key);
void gpiochip_remove(struct gpio_chip *gc);
int devm_gpiochip_add_data_with_key(struct device *dev, struct gpio_chip *gc,
void *data, struct lock_class_key *lock_key,
struct lock_class_key *request_key);
extern struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *gc, void *data));
struct gpio_chip *gpiochip_find(void *data,
int (*match)(struct gpio_chip *gc, void *data));
struct gpio_device *gpio_device_find(void *data,
int (*match)(struct gpio_chip *gc, void *data));
struct gpio_device *gpio_device_find_by_label(const char *label);
struct gpio_device *gpio_device_find_by_fwnode(const struct fwnode_handle *fwnode);
struct gpio_device *gpio_device_get(struct gpio_device *gdev);
void gpio_device_put(struct gpio_device *gdev);
DEFINE_FREE(gpio_device_put, struct gpio_device *,
if (IS_ERR_OR_NULL(_T)) gpio_device_put(_T));
struct device *gpio_device_to_device(struct gpio_device *gdev);
bool gpiochip_line_is_irq(struct gpio_chip *gc, unsigned int offset);
int gpiochip_reqres_irq(struct gpio_chip *gc, unsigned int offset);
@ -758,14 +772,23 @@ struct gpio_desc *gpiochip_request_own_desc(struct gpio_chip *gc,
enum gpiod_flags dflags);
void gpiochip_free_own_desc(struct gpio_desc *desc);
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
struct gpio_desc *
gpio_device_get_desc(struct gpio_device *gdev, unsigned int hwnum);
struct gpio_chip *gpio_device_get_chip(struct gpio_device *gdev);
#ifdef CONFIG_GPIOLIB
/* lock/unlock as IRQ */
int gpiochip_lock_as_irq(struct gpio_chip *gc, unsigned int offset);
void gpiochip_unlock_as_irq(struct gpio_chip *gc, unsigned int offset);
struct gpio_chip *gpiod_to_chip(const struct gpio_desc *desc);
struct gpio_device *gpiod_to_gpio_device(struct gpio_desc *desc);
/* struct gpio_device getters */
int gpio_device_get_base(struct gpio_device *gdev);
#else /* CONFIG_GPIOLIB */

View File

@ -144,9 +144,6 @@
#define OMAP_MAX_GPIO_LINES 192
#define OMAP_MPUIO(nr) (OMAP_MAX_GPIO_LINES + (nr))
#define OMAP_GPIO_IS_MPUIO(nr) ((nr) >= OMAP_MAX_GPIO_LINES)
#ifndef __ASSEMBLER__
struct omap_gpio_reg_offs {
u16 revision;

View File

@ -11,21 +11,8 @@ struct pca953x_platform_data {
/* number of the first GPIO */
unsigned gpio_base;
/* initial polarity inversion setting */
u32 invert;
/* interrupt base */
int irq_base;
void *context; /* param to setup/teardown */
int (*setup)(struct i2c_client *client,
unsigned gpio, unsigned ngpio,
void *context);
void (*teardown)(struct i2c_client *client,
unsigned gpio, unsigned ngpio,
void *context);
const char *const *names;
};
#endif /* _LINUX_PCA953X_H */