forked from Minki/linux
gpio updates for v5.13
- new driver for the Realtek Otto GPIO controller - ACPI support for gpio-mpc8xxx - edge event support for gpio-sch (+ Kconfig fixes) - Kconfig improvements in gpio-ich - fixes to older issues in gpio-mockup - ACPI quirk for ignoring EC wakeups on Dell Venue 10 Pro 5055 - improve the GPIO aggregator code by using more generic interfaces instead of reimplementing them in the driver - convert the DT bindings for gpio-74x164 to yaml - documentation improvements - a slew of other minor fixes and improvements to GPIO drivers -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEFp3rbAvDxGAT0sefEacuoBRx13IFAmCSptQACgkQEacuoBRx 13KFDQ/+NOkRQuJarKAvGuR5LJ81CbBfH72/m9gJMB9gwNBS7g+esNWrZG/riWVM BVs2fxlC52+ppN1rV7iMEaXSyREULrcidgoZ0H7X2vsI9MRkk/fjzpTRwbJbSLPo C+IXBAHHfuUC1FQNtQk1cuZXl7PToHd/A14KZIkLOBxLjQddpSo7TTkv23Ub1BA7 Se13EaDrBJxzfmLR900kAKCFDyM8VRnIt7/euhmlTcXCxOg/lCbGZ4eBpEZasUs5 UA9PQX0dnnwtMER4b4TQPIdQ345A0l+xqALr8X2leqQ0AqsWQ7kveMwfSRlXI5Hr zyuXRiA0e84h6HXIHE59kXqoa4LJVnW59hgjYx0D+fcZ5gNVnaRg/4LsztJmMd/f uVAZazE4jd81Cr/kbtpEu5mfGPjOVBeUCeDnKtRovnaSMi24HwqvHqIauI9sM8fN locTCYOdLfvxucAJHZ/BWe8yl301/+IlwiHiN+7+/3ljYB+HjAH42rdPwFpP1BWJ bpgd90KxLHezeqsv83U9CTTrVK9ZM2yisVunQUo3bVi6Ztxl2Juv16P5Qs0IJW2F mly+KNTa4M6NKCdP6luEnazmifFIsnreCzTMfPoa9w+eu/vpIw6lZDFpDAbePV+A 8XJ99TxV1Bk9kUjvKiEi2qx6uW7f5k8JIwvRvJWhRXkEzufJyUI= =5vLN -----END PGP SIGNATURE----- Merge tag 'gpio-updates-for-v5.13-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux Pull gpio updates from Bartosz Golaszewski: - new driver for the Realtek Otto GPIO controller - ACPI support for gpio-mpc8xxx - edge event support for gpio-sch (+ Kconfig fixes) - Kconfig improvements in gpio-ich - fixes to older issues in gpio-mockup - ACPI quirk for ignoring EC wakeups on Dell Venue 10 Pro 5055 - improve the GPIO aggregator code by using more generic interfaces instead of reimplementing them in the driver - convert the DT bindings for gpio-74x164 to yaml - documentation improvements - a slew of other minor fixes and improvements to GPIO drivers * tag 'gpio-updates-for-v5.13-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux: (34 commits) dt-bindings: gpio: add YAML description for rockchip,gpio-bank gpio: mxs: remove useless function dt-bindings: gpio: fairchild,74hc595: Convert to json-schema gpio: it87: remove unused code gpio: 104-dio-48e: Fix coding style issues gpio: mpc8xxx: Add ACPI support gpio: ich: Switch to be dependent on LPC_ICH gpio: sch: Drop MFD_CORE selection gpio: sch: depends on LPC_SCH gpiolib: acpi: Add quirk to ignore EC wakeups on Dell Venue 10 Pro 5055 gpio: sch: Hook into ACPI GPE handler to catch GPIO edge events gpio: sch: Add edge event support gpio: aggregator: Replace custom get_arg() with a generic next_arg() lib/cmdline: Export next_arg() for being used in modules gpio: omap: Use device_get_match_data() helper gpio: Add Realtek Otto GPIO support dt-bindings: gpio: Binding for Realtek Otto GPIO docs: kernel-parameters: Add gpio_mockup_named_lines docs: kernel-parameters: Move gpio-mockup for alphabetic order lib: bitmap: provide devm_bitmap_alloc() and devm_bitmap_zalloc() ...
This commit is contained in:
commit
5d6a1b84e0
@ -17,17 +17,18 @@ module.
|
||||
gpio_mockup_ranges
|
||||
|
||||
This parameter takes an argument in the form of an array of integer
|
||||
pairs. Each pair defines the base GPIO number (if any) and the number
|
||||
of lines exposed by the chip. If the base GPIO is -1, the gpiolib
|
||||
will assign it automatically.
|
||||
pairs. Each pair defines the base GPIO number (non-negative integer)
|
||||
and the first number after the last of this chip. If the base GPIO
|
||||
is -1, the gpiolib will assign it automatically. while the following
|
||||
parameter is the number of lines exposed by the chip.
|
||||
|
||||
Example: gpio_mockup_ranges=-1,8,-1,16,405,4
|
||||
Example: gpio_mockup_ranges=-1,8,-1,16,405,409
|
||||
|
||||
The line above creates three chips. The first one will expose 8 lines,
|
||||
the second 16 and the third 4. The base GPIO for the third chip is set
|
||||
to 405 while for two first chips it will be assigned automatically.
|
||||
|
||||
gpio_named_lines
|
||||
gpio_mockup_named_lines
|
||||
|
||||
This parameter doesn't take any arguments. It lets the driver know that
|
||||
GPIO lines exposed by it should be named.
|
||||
|
@ -1469,6 +1469,12 @@
|
||||
Don't use this when you are not running on the
|
||||
android emulator
|
||||
|
||||
gpio-mockup.gpio_mockup_ranges
|
||||
[HW] Sets the ranges of gpiochip of for this device.
|
||||
Format: <start1>,<end1>,<start2>,<end2>...
|
||||
gpio-mockup.gpio_mockup_named_lines
|
||||
[HW] Let the driver know GPIO lines should be named.
|
||||
|
||||
gpt [EFI] Forces disk with valid GPT signature but
|
||||
invalid Protective MBR to be treated as GPT. If the
|
||||
primary GPT is corrupted, it enables the backup/alternate
|
||||
@ -1492,10 +1498,6 @@
|
||||
Format: <unsigned int> such that (rxsize & ~0x1fffc0) == 0.
|
||||
Default: 1024
|
||||
|
||||
gpio-mockup.gpio_mockup_ranges
|
||||
[HW] Sets the ranges of gpiochip of for this device.
|
||||
Format: <start1>,<end1>,<start2>,<end2>...
|
||||
|
||||
hardlockup_all_cpu_backtrace=
|
||||
[KNL] Should the hard-lockup detector generate
|
||||
backtraces on all cpus.
|
||||
|
@ -42,10 +42,10 @@ irq_domain usage
|
||||
================
|
||||
|
||||
An interrupt controller driver creates and registers an irq_domain by
|
||||
calling one of the irq_domain_add_*() functions (each mapping method
|
||||
has a different allocator function, more on that later). The function
|
||||
will return a pointer to the irq_domain on success. The caller must
|
||||
provide the allocator function with an irq_domain_ops structure.
|
||||
calling one of the irq_domain_add_*() or irq_domain_create_*() functions
|
||||
(each mapping method has a different allocator function, more on that later).
|
||||
The function will return a pointer to the irq_domain on success. The caller
|
||||
must provide the allocator function with an irq_domain_ops structure.
|
||||
|
||||
In most cases, the irq_domain will begin empty without any mappings
|
||||
between hwirq and IRQ numbers. Mappings are added to the irq_domain
|
||||
@ -147,6 +147,7 @@ Legacy
|
||||
irq_domain_add_simple()
|
||||
irq_domain_add_legacy()
|
||||
irq_domain_add_legacy_isa()
|
||||
irq_domain_create_simple()
|
||||
irq_domain_create_legacy()
|
||||
|
||||
The Legacy mapping is a special case for drivers that already have a
|
||||
@ -169,13 +170,13 @@ supported. For example, ISA controllers would use the legacy map for
|
||||
mapping Linux IRQs 0-15 so that existing ISA drivers get the correct IRQ
|
||||
numbers.
|
||||
|
||||
Most users of legacy mappings should use irq_domain_add_simple() which
|
||||
will use a legacy domain only if an IRQ range is supplied by the
|
||||
system and will otherwise use a linear domain mapping. The semantics
|
||||
of this call are such that if an IRQ range is specified then
|
||||
Most users of legacy mappings should use irq_domain_add_simple() or
|
||||
irq_domain_create_simple() which will use a legacy domain only if an IRQ range
|
||||
is supplied by the system and will otherwise use a linear domain mapping.
|
||||
The semantics of this call are such that if an IRQ range is specified then
|
||||
descriptors will be allocated on-the-fly for it, and if no range is
|
||||
specified it will fall through to irq_domain_add_linear() which means
|
||||
*no* irq descriptors will be allocated.
|
||||
specified it will fall through to irq_domain_add_linear() or
|
||||
irq_domain_create_linear() which means *no* irq descriptors will be allocated.
|
||||
|
||||
A typical use case for simple domains is where an irqchip provider
|
||||
is supporting both dynamic and static IRQ assignments.
|
||||
@ -186,6 +187,7 @@ that the driver using the simple domain call irq_create_mapping()
|
||||
before any irq_find_mapping() since the latter will actually work
|
||||
for the static IRQ assignment case.
|
||||
|
||||
irq_domain_add_simple() and irq_domain_create_simple() as well as
|
||||
irq_domain_add_legacy() and irq_domain_create_legacy() are functionally
|
||||
equivalent, except for the first argument is different - the former
|
||||
accepts an Open Firmware specific 'struct device_node', while the latter
|
||||
|
@ -0,0 +1,77 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/fairchild,74hc595.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Generic 8-bit shift register
|
||||
|
||||
maintainers:
|
||||
- Maxime Ripard <mripard@kernel.org>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- fairchild,74hc595
|
||||
- nxp,74lvc594
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
'#gpio-cells':
|
||||
description:
|
||||
The second cell is only used to specify the GPIO polarity.
|
||||
const: 2
|
||||
|
||||
registers-number:
|
||||
description: Number of daisy-chained shift registers
|
||||
|
||||
enable-gpios:
|
||||
description: GPIO connected to the OE (Output Enable) pin.
|
||||
maxItems: 1
|
||||
|
||||
spi-max-frequency: true
|
||||
|
||||
patternProperties:
|
||||
"^(hog-[0-9]+|.+-hog(-[0-9]+)?)$":
|
||||
type: object
|
||||
|
||||
properties:
|
||||
gpio-hog: true
|
||||
gpios: true
|
||||
output-high: true
|
||||
output-low: true
|
||||
line-name: true
|
||||
|
||||
required:
|
||||
- gpio-hog
|
||||
- gpios
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- gpio-controller
|
||||
- '#gpio-cells'
|
||||
- registers-number
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
gpio5: gpio5@0 {
|
||||
compatible = "fairchild,74hc595";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
registers-number = <4>;
|
||||
spi-max-frequency = <100000>;
|
||||
};
|
||||
};
|
@ -1,27 +0,0 @@
|
||||
* Generic 8-bits shift register GPIO driver
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain one of the following:
|
||||
"fairchild,74hc595"
|
||||
"nxp,74lvc594"
|
||||
- reg : chip select number
|
||||
- gpio-controller : Marks the device node as a gpio controller.
|
||||
- #gpio-cells : Should be two. The first cell is the pin number and
|
||||
the second cell is used to specify the gpio polarity:
|
||||
0 = active high
|
||||
1 = active low
|
||||
- registers-number: Number of daisy-chained shift registers
|
||||
|
||||
Optional properties:
|
||||
- enable-gpios: GPIO connected to the OE (Output Enable) pin.
|
||||
|
||||
Example:
|
||||
|
||||
gpio5: gpio5@0 {
|
||||
compatible = "fairchild,74hc595";
|
||||
reg = <0>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
registers-number = <4>;
|
||||
spi-max-frequency = <100000>;
|
||||
};
|
@ -0,0 +1,78 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/realtek,otto-gpio.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Realtek Otto GPIO controller
|
||||
|
||||
maintainers:
|
||||
- Sander Vanheule <sander@svanheule.net>
|
||||
- Bert Vermeulen <bert@biot.com>
|
||||
|
||||
description: |
|
||||
Realtek's GPIO controller on their MIPS switch SoCs (Otto platform) consists
|
||||
of two banks of 32 GPIOs. These GPIOs can generate edge-triggered interrupts.
|
||||
Each bank's interrupts are cascased into one interrupt line on the parent
|
||||
interrupt controller, if provided.
|
||||
This binding allows defining a single bank in the devicetree. The interrupt
|
||||
controller is not supported on the fallback compatible name, which only
|
||||
allows for GPIO port use.
|
||||
|
||||
properties:
|
||||
$nodename:
|
||||
pattern: "^gpio@[0-9a-f]+$"
|
||||
|
||||
compatible:
|
||||
items:
|
||||
- enum:
|
||||
- realtek,rtl8380-gpio
|
||||
- realtek,rtl8390-gpio
|
||||
- const: realtek,otto-gpio
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
ngpios:
|
||||
minimum: 1
|
||||
maximum: 32
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- "#gpio-cells"
|
||||
- gpio-controller
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
dependencies:
|
||||
interrupt-controller: [ interrupts ]
|
||||
|
||||
examples:
|
||||
- |
|
||||
gpio@3500 {
|
||||
compatible = "realtek,rtl8380-gpio", "realtek,otto-gpio";
|
||||
reg = <0x3500 0x1c>;
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
ngpios = <24>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
interrupt-parent = <&rtlintc>;
|
||||
interrupts = <23>;
|
||||
};
|
||||
|
||||
...
|
@ -0,0 +1,82 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/gpio/rockchip,gpio-bank.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Rockchip GPIO bank
|
||||
|
||||
maintainers:
|
||||
- Heiko Stuebner <heiko@sntech.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- rockchip,gpio-bank
|
||||
- rockchip,rk3188-gpio-bank0
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
gpio-controller: true
|
||||
|
||||
"#gpio-cells":
|
||||
const: 2
|
||||
|
||||
interrupt-controller: true
|
||||
|
||||
"#interrupt-cells":
|
||||
const: 2
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- gpio-controller
|
||||
- "#gpio-cells"
|
||||
- interrupt-controller
|
||||
- "#interrupt-cells"
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
pinctrl: pinctrl {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
gpio0: gpio@2000a000 {
|
||||
compatible = "rockchip,rk3188-gpio-bank0";
|
||||
reg = <0x2000a000 0x100>;
|
||||
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_gates8 9>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
gpio1: gpio@2003c000 {
|
||||
compatible = "rockchip,gpio-bank";
|
||||
reg = <0x2003c000 0x100>;
|
||||
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_gates8 10>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
};
|
@ -51,23 +51,7 @@ Deprecated properties for iomux controller:
|
||||
Use rockchip,grf and rockchip,pmu described above instead.
|
||||
|
||||
Required properties for gpio sub nodes:
|
||||
- compatible: "rockchip,gpio-bank"
|
||||
- reg: register of the gpio bank (different than the iomux registerset)
|
||||
- interrupts: base interrupt of the gpio bank in the interrupt controller
|
||||
- clocks: clock that drives this bank
|
||||
- gpio-controller: identifies the node as a gpio controller and pin bank.
|
||||
- #gpio-cells: number of cells in GPIO specifier. Since the generic GPIO
|
||||
binding is used, the amount of cells must be specified as 2. See generic
|
||||
GPIO binding documentation for description of particular cells.
|
||||
- interrupt-controller: identifies the controller node as interrupt-parent.
|
||||
- #interrupt-cells: the value of this property should be 2 and the interrupt
|
||||
cells should use the standard two-cell scheme described in
|
||||
bindings/interrupt-controller/interrupts.txt
|
||||
|
||||
Deprecated properties for gpio sub nodes:
|
||||
- compatible: "rockchip,rk3188-gpio-bank0"
|
||||
- reg: second element: separate pull register for rk3188 bank0, use
|
||||
rockchip,pmu described above instead
|
||||
See rockchip,gpio-bank.yaml
|
||||
|
||||
Required properties for pin configuration node:
|
||||
- rockchip,pins: 3 integers array, represents a group of pins mux and config
|
||||
@ -128,43 +112,3 @@ uart2: serial@20064000 {
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&uart2_xfer>;
|
||||
};
|
||||
|
||||
Example for rk3188:
|
||||
|
||||
pinctrl@20008000 {
|
||||
compatible = "rockchip,rk3188-pinctrl";
|
||||
rockchip,grf = <&grf>;
|
||||
rockchip,pmu = <&pmu>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
ranges;
|
||||
|
||||
gpio0: gpio0@2000a000 {
|
||||
compatible = "rockchip,rk3188-gpio-bank0";
|
||||
reg = <0x2000a000 0x100>;
|
||||
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_gates8 9>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
gpio1: gpio1@2003c000 {
|
||||
compatible = "rockchip,gpio-bank";
|
||||
reg = <0x2003c000 0x100>;
|
||||
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&clk_gates8 10>;
|
||||
|
||||
gpio-controller;
|
||||
#gpio-cells = <2>;
|
||||
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
};
|
||||
|
||||
...
|
||||
|
||||
};
|
||||
|
@ -12,7 +12,7 @@ Guidelines for GPIOs consumers
|
||||
|
||||
Drivers that can't work without standard GPIO calls should have Kconfig entries
|
||||
that depend on GPIOLIB or select GPIOLIB. The functions that allow a driver to
|
||||
obtain and use GPIOs are available by including the following file:
|
||||
obtain and use GPIOs are available by including the following file::
|
||||
|
||||
#include <linux/gpio/consumer.h>
|
||||
|
||||
|
@ -96,6 +96,12 @@ hardware descriptions such as device tree or ACPI:
|
||||
way to pass the charging parameters from hardware descriptions such as the
|
||||
device tree.
|
||||
|
||||
- gpio-mux: drivers/mux/gpio.c is used for controlling a multiplexer using
|
||||
n GPIO lines such that you can mux in 2^n different devices by activating
|
||||
different GPIO lines. Often the GPIOs are on a SoC and the devices are
|
||||
some SoC-external entities, such as different components on a PCB that
|
||||
can be selectively enabled.
|
||||
|
||||
Apart from this there are special GPIO drivers in subsystems like MMC/SD to
|
||||
read card detect and write protect GPIO lines, and in the TTY serial subsystem
|
||||
to emulate MCTRL (modem control) signals CTS/RTS by using two GPIO lines. The
|
||||
|
@ -321,9 +321,8 @@ config GPIO_HLWD
|
||||
|
||||
config GPIO_ICH
|
||||
tristate "Intel ICH GPIO"
|
||||
depends on PCI && X86
|
||||
select MFD_CORE
|
||||
select LPC_ICH
|
||||
depends on X86
|
||||
depends on LPC_ICH
|
||||
help
|
||||
Say yes here to support the GPIO functionality of a number of Intel
|
||||
ICH-based chipsets. Currently supported devices: ICH6, ICH7, ICH8
|
||||
@ -502,6 +501,19 @@ config GPIO_RDA
|
||||
help
|
||||
Say Y here to support RDA Micro GPIO controller.
|
||||
|
||||
config GPIO_REALTEK_OTTO
|
||||
tristate "Realtek Otto GPIO support"
|
||||
depends on MACH_REALTEK_RTL
|
||||
default MACH_REALTEK_RTL
|
||||
select GPIO_GENERIC
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
The GPIO controller on the Otto MIPS platform supports up to two
|
||||
banks of 32 GPIOs, with edge triggered interrupts. The 32 GPIOs
|
||||
are grouped in four 8-bit wide ports.
|
||||
|
||||
When built as a module, the module will be called realtek_otto_gpio.
|
||||
|
||||
config GPIO_REG
|
||||
bool
|
||||
help
|
||||
@ -847,9 +859,9 @@ config GPIO_IT87
|
||||
|
||||
config GPIO_SCH
|
||||
tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
|
||||
depends on (X86 || COMPILE_TEST) && PCI
|
||||
select MFD_CORE
|
||||
select LPC_SCH
|
||||
depends on (X86 || COMPILE_TEST) && ACPI
|
||||
depends on LPC_SCH
|
||||
select GPIOLIB_IRQCHIP
|
||||
help
|
||||
Say yes here to support GPIO interface on Intel Poulsbo SCH,
|
||||
Intel Tunnel Creek processor, Intel Centerton processor or
|
||||
|
@ -125,6 +125,7 @@ obj-$(CONFIG_GPIO_RC5T583) += gpio-rc5t583.o
|
||||
obj-$(CONFIG_GPIO_RCAR) += gpio-rcar.o
|
||||
obj-$(CONFIG_GPIO_RDA) += gpio-rda.o
|
||||
obj-$(CONFIG_GPIO_RDC321X) += gpio-rdc321x.o
|
||||
obj-$(CONFIG_GPIO_REALTEK_OTTO) += gpio-realtek-otto.o
|
||||
obj-$(CONFIG_GPIO_REG) += gpio-reg.o
|
||||
obj-$(CONFIG_ARCH_SA1100) += gpio-sa1100.o
|
||||
obj-$(CONFIG_GPIO_SAMA5D2_PIOBU) += gpio-sama5d2-piobu.o
|
||||
|
@ -49,15 +49,15 @@ struct dio48e_gpio {
|
||||
unsigned char out_state[6];
|
||||
unsigned char control[2];
|
||||
raw_spinlock_t lock;
|
||||
unsigned base;
|
||||
unsigned int base;
|
||||
unsigned char irq_mask;
|
||||
};
|
||||
|
||||
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned port = offset / 8;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
const unsigned int port = offset / 8;
|
||||
const unsigned int mask = BIT(offset % 8);
|
||||
|
||||
if (dio48egpio->io_state[port] & mask)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
@ -65,14 +65,14 @@ static int dio48e_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned io_port = offset / 8;
|
||||
const unsigned int io_port = offset / 8;
|
||||
const unsigned int control_port = io_port / 3;
|
||||
const unsigned control_addr = dio48egpio->base + 3 + control_port*4;
|
||||
const unsigned int control_addr = dio48egpio->base + 3 + control_port * 4;
|
||||
unsigned long flags;
|
||||
unsigned control;
|
||||
unsigned int control;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
@ -104,17 +104,17 @@ static int dio48e_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
int value)
|
||||
static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
|
||||
int value)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned io_port = offset / 8;
|
||||
const unsigned int io_port = offset / 8;
|
||||
const unsigned int control_port = io_port / 3;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
const unsigned control_addr = dio48egpio->base + 3 + control_port*4;
|
||||
const unsigned out_port = (io_port > 2) ? io_port + 1 : io_port;
|
||||
const unsigned int mask = BIT(offset % 8);
|
||||
const unsigned int control_addr = dio48egpio->base + 3 + control_port * 4;
|
||||
const unsigned int out_port = (io_port > 2) ? io_port + 1 : io_port;
|
||||
unsigned long flags;
|
||||
unsigned control;
|
||||
unsigned int control;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
@ -154,14 +154,14 @@ static int dio48e_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
static int dio48e_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned port = offset / 8;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
const unsigned in_port = (port > 2) ? port + 1 : port;
|
||||
const unsigned int port = offset / 8;
|
||||
const unsigned int mask = BIT(offset % 8);
|
||||
const unsigned int in_port = (port > 2) ? port + 1 : port;
|
||||
unsigned long flags;
|
||||
unsigned port_state;
|
||||
unsigned int port_state;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
|
||||
@ -202,12 +202,12 @@ static int dio48e_gpio_get_multiple(struct gpio_chip *chip, unsigned long *mask,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||
static void dio48e_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
||||
{
|
||||
struct dio48e_gpio *const dio48egpio = gpiochip_get_data(chip);
|
||||
const unsigned port = offset / 8;
|
||||
const unsigned mask = BIT(offset % 8);
|
||||
const unsigned out_port = (port > 2) ? port + 1 : port;
|
||||
const unsigned int port = offset / 8;
|
||||
const unsigned int mask = BIT(offset % 8);
|
||||
const unsigned int out_port = (port > 2) ? port + 1 : port;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&dio48egpio->lock, flags);
|
||||
@ -306,7 +306,7 @@ static void dio48e_irq_unmask(struct irq_data *data)
|
||||
raw_spin_unlock_irqrestore(&dio48egpio->lock, flags);
|
||||
}
|
||||
|
||||
static int dio48e_irq_set_type(struct irq_data *data, unsigned flow_type)
|
||||
static int dio48e_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
const unsigned long offset = irqd_to_hwirq(data);
|
||||
|
||||
|
@ -37,31 +37,6 @@ struct gpio_aggregator {
|
||||
static DEFINE_MUTEX(gpio_aggregator_lock); /* protects idr */
|
||||
static DEFINE_IDR(gpio_aggregator_idr);
|
||||
|
||||
static char *get_arg(char **args)
|
||||
{
|
||||
char *start, *end;
|
||||
|
||||
start = skip_spaces(*args);
|
||||
if (!*start)
|
||||
return NULL;
|
||||
|
||||
if (*start == '"') {
|
||||
/* Quoted arg */
|
||||
end = strchr(++start, '"');
|
||||
if (!end)
|
||||
return ERR_PTR(-EINVAL);
|
||||
} else {
|
||||
/* Unquoted arg */
|
||||
for (end = start; *end && !isspace(*end); end++) ;
|
||||
}
|
||||
|
||||
if (*end)
|
||||
*end++ = '\0';
|
||||
|
||||
*args = end;
|
||||
return start;
|
||||
}
|
||||
|
||||
static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
|
||||
int hwnum, unsigned int *n)
|
||||
{
|
||||
@ -83,8 +58,8 @@ static int aggr_add_gpio(struct gpio_aggregator *aggr, const char *key,
|
||||
|
||||
static int aggr_parse(struct gpio_aggregator *aggr)
|
||||
{
|
||||
char *args = skip_spaces(aggr->args);
|
||||
char *name, *offsets, *p;
|
||||
char *args = aggr->args;
|
||||
unsigned long *bitmap;
|
||||
unsigned int i, n = 0;
|
||||
int error = 0;
|
||||
@ -93,13 +68,9 @@ static int aggr_parse(struct gpio_aggregator *aggr)
|
||||
if (!bitmap)
|
||||
return -ENOMEM;
|
||||
|
||||
for (name = get_arg(&args), offsets = get_arg(&args); name;
|
||||
offsets = get_arg(&args)) {
|
||||
if (IS_ERR(name)) {
|
||||
pr_err("Cannot get GPIO specifier: %pe\n", name);
|
||||
error = PTR_ERR(name);
|
||||
goto free_bitmap;
|
||||
}
|
||||
args = next_arg(args, &name, &p);
|
||||
while (*args) {
|
||||
args = next_arg(args, &offsets, &p);
|
||||
|
||||
p = get_options(offsets, 0, &error);
|
||||
if (error == 0 || *p) {
|
||||
@ -125,7 +96,7 @@ static int aggr_parse(struct gpio_aggregator *aggr)
|
||||
goto free_bitmap;
|
||||
}
|
||||
|
||||
name = get_arg(&args);
|
||||
args = next_arg(args, &name, &p);
|
||||
}
|
||||
|
||||
if (!n) {
|
||||
|
@ -5,13 +5,11 @@
|
||||
* Copyright (C) 2010 Extreme Engineering Solutions.
|
||||
*/
|
||||
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/mfd/lpc_ich.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#define DRV_NAME "gpio_ich"
|
||||
|
@ -125,14 +125,6 @@ static inline int superio_inw(int reg)
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void superio_outw(int val, int reg)
|
||||
{
|
||||
outb(reg++, REG);
|
||||
outb(val >> 8, VAL);
|
||||
outb(reg, REG);
|
||||
outb(val, VAL);
|
||||
}
|
||||
|
||||
static inline void superio_set_mask(int mask, int reg)
|
||||
{
|
||||
u8 curr_val = superio_inb(reg);
|
||||
|
@ -479,15 +479,10 @@ static struct platform_device *gpio_mockup_pdevs[GPIO_MOCKUP_MAX_GC];
|
||||
|
||||
static void gpio_mockup_unregister_pdevs(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++) {
|
||||
pdev = gpio_mockup_pdevs[i];
|
||||
|
||||
if (pdev)
|
||||
platform_device_unregister(pdev);
|
||||
}
|
||||
for (i = 0; i < GPIO_MOCKUP_MAX_GC; i++)
|
||||
platform_device_unregister(gpio_mockup_pdevs[i]);
|
||||
}
|
||||
|
||||
static __init char **gpio_mockup_make_line_names(const char *label,
|
||||
|
@ -9,6 +9,7 @@
|
||||
* kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/spinlock.h>
|
||||
@ -18,6 +19,8 @@
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
@ -303,8 +306,8 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
struct device_node *np = pdev->dev.of_node;
|
||||
struct mpc8xxx_gpio_chip *mpc8xxx_gc;
|
||||
struct gpio_chip *gc;
|
||||
const struct mpc8xxx_gpio_devtype *devtype =
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
const struct mpc8xxx_gpio_devtype *devtype = NULL;
|
||||
struct fwnode_handle *fwnode;
|
||||
int ret;
|
||||
|
||||
mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL);
|
||||
@ -315,14 +318,14 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
|
||||
raw_spin_lock_init(&mpc8xxx_gc->lock);
|
||||
|
||||
mpc8xxx_gc->regs = of_iomap(np, 0);
|
||||
if (!mpc8xxx_gc->regs)
|
||||
return -ENOMEM;
|
||||
mpc8xxx_gc->regs = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(mpc8xxx_gc->regs))
|
||||
return PTR_ERR(mpc8xxx_gc->regs);
|
||||
|
||||
gc = &mpc8xxx_gc->gc;
|
||||
gc->parent = &pdev->dev;
|
||||
|
||||
if (of_property_read_bool(np, "little-endian")) {
|
||||
if (device_property_read_bool(&pdev->dev, "little-endian")) {
|
||||
ret = bgpio_init(gc, &pdev->dev, 4,
|
||||
mpc8xxx_gc->regs + GPIO_DAT,
|
||||
NULL, NULL,
|
||||
@ -345,6 +348,7 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
|
||||
mpc8xxx_gc->direction_output = gc->direction_output;
|
||||
|
||||
devtype = device_get_match_data(&pdev->dev);
|
||||
if (!devtype)
|
||||
devtype = &mpc8xxx_gpio_devtype_default;
|
||||
|
||||
@ -369,24 +373,29 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
* associated input enable must be set (GPIOxGPIE[IEn]=1) to propagate
|
||||
* the port value to the GPIO Data Register.
|
||||
*/
|
||||
fwnode = dev_fwnode(&pdev->dev);
|
||||
if (of_device_is_compatible(np, "fsl,qoriq-gpio") ||
|
||||
of_device_is_compatible(np, "fsl,ls1028a-gpio") ||
|
||||
of_device_is_compatible(np, "fsl,ls1088a-gpio"))
|
||||
of_device_is_compatible(np, "fsl,ls1088a-gpio") ||
|
||||
is_acpi_node(fwnode))
|
||||
gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
|
||||
|
||||
ret = gpiochip_add_data(gc, mpc8xxx_gc);
|
||||
if (ret) {
|
||||
pr_err("%pOF: GPIO chip registration failed with status %d\n",
|
||||
np, ret);
|
||||
dev_err(&pdev->dev,
|
||||
"GPIO chip registration failed with status %d\n", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0);
|
||||
mpc8xxx_gc->irqn = platform_get_irq(pdev, 0);
|
||||
if (!mpc8xxx_gc->irqn)
|
||||
return 0;
|
||||
|
||||
mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
|
||||
&mpc8xxx_gpio_irq_ops, mpc8xxx_gc);
|
||||
mpc8xxx_gc->irq = irq_domain_create_linear(fwnode,
|
||||
MPC8XXX_GPIO_PINS,
|
||||
&mpc8xxx_gpio_irq_ops,
|
||||
mpc8xxx_gc);
|
||||
|
||||
if (!mpc8xxx_gc->irq)
|
||||
return 0;
|
||||
|
||||
@ -399,8 +408,9 @@ static int mpc8xxx_probe(struct platform_device *pdev)
|
||||
IRQF_SHARED, "gpio-cascade",
|
||||
mpc8xxx_gc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "%s: failed to devm_request_irq(%d), ret = %d\n",
|
||||
np->full_name, mpc8xxx_gc->irqn, ret);
|
||||
dev_err(&pdev->dev,
|
||||
"failed to devm_request_irq(%d), ret = %d\n",
|
||||
mpc8xxx_gc->irqn, ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -425,12 +435,21 @@ static int mpc8xxx_remove(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id gpio_acpi_ids[] = {
|
||||
{"NXP0031",},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, gpio_acpi_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver mpc8xxx_plat_driver = {
|
||||
.probe = mpc8xxx_probe,
|
||||
.remove = mpc8xxx_remove,
|
||||
.driver = {
|
||||
.name = "gpio-mpc8xxx",
|
||||
.of_match_table = mpc8xxx_gpio_ids,
|
||||
.acpi_match_table = ACPI_PTR(gpio_acpi_ids),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -60,11 +60,6 @@ static inline int is_imx23_gpio(struct mxs_gpio_port *port)
|
||||
return port->devid == IMX23_GPIO;
|
||||
}
|
||||
|
||||
static inline int is_imx28_gpio(struct mxs_gpio_port *port)
|
||||
{
|
||||
return port->devid == IMX28_GPIO;
|
||||
}
|
||||
|
||||
/* Note: This driver assumes 32 GPIOs are handled in one register */
|
||||
|
||||
static int mxs_gpio_set_irq_type(struct irq_data *d, unsigned int type)
|
||||
|
@ -1373,15 +1373,14 @@ static int omap_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *node = dev->of_node;
|
||||
const struct of_device_id *match;
|
||||
const struct omap_gpio_platform_data *pdata;
|
||||
struct gpio_bank *bank;
|
||||
struct irq_chip *irqc;
|
||||
int ret;
|
||||
|
||||
match = of_match_device(of_match_ptr(omap_gpio_match), dev);
|
||||
pdata = device_get_match_data(dev);
|
||||
|
||||
pdata = match ? match->data : dev_get_platdata(dev);
|
||||
pdata = pdata ?: dev_get_platdata(dev);
|
||||
if (!pdata)
|
||||
return -EINVAL;
|
||||
|
||||
|
325
drivers/gpio/gpio-realtek-otto.c
Normal file
325
drivers/gpio/gpio-realtek-otto.c
Normal file
@ -0,0 +1,325 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/minmax.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
/*
|
||||
* Total register block size is 0x1C for one bank of four ports (A, B, C, D).
|
||||
* An optional second bank, with ports E, F, G, and H, may be present, starting
|
||||
* at register offset 0x1C.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Pin select: (0) "normal", (1) "dedicate peripheral"
|
||||
* Not used on RTL8380/RTL8390, peripheral selection is managed by control bits
|
||||
* in the peripheral registers.
|
||||
*/
|
||||
#define REALTEK_GPIO_REG_CNR 0x00
|
||||
/* Clear bit (0) for input, set bit (1) for output */
|
||||
#define REALTEK_GPIO_REG_DIR 0x08
|
||||
#define REALTEK_GPIO_REG_DATA 0x0C
|
||||
/* Read bit for IRQ status, write 1 to clear IRQ */
|
||||
#define REALTEK_GPIO_REG_ISR 0x10
|
||||
/* Two bits per GPIO in IMR registers */
|
||||
#define REALTEK_GPIO_REG_IMR 0x14
|
||||
#define REALTEK_GPIO_REG_IMR_AB 0x14
|
||||
#define REALTEK_GPIO_REG_IMR_CD 0x18
|
||||
#define REALTEK_GPIO_IMR_LINE_MASK GENMASK(1, 0)
|
||||
#define REALTEK_GPIO_IRQ_EDGE_FALLING 1
|
||||
#define REALTEK_GPIO_IRQ_EDGE_RISING 2
|
||||
#define REALTEK_GPIO_IRQ_EDGE_BOTH 3
|
||||
|
||||
#define REALTEK_GPIO_MAX 32
|
||||
#define REALTEK_GPIO_PORTS_PER_BANK 4
|
||||
|
||||
/**
|
||||
* realtek_gpio_ctrl - Realtek Otto GPIO driver data
|
||||
*
|
||||
* @gc: Associated gpio_chip instance
|
||||
* @base: Base address of the register block for a GPIO bank
|
||||
* @lock: Lock for accessing the IRQ registers and values
|
||||
* @intr_mask: Mask for interrupts lines
|
||||
* @intr_type: Interrupt type selection
|
||||
*
|
||||
* Because the interrupt mask register (IMR) combines the function of IRQ type
|
||||
* selection and masking, two extra values are stored. @intr_mask is used to
|
||||
* mask/unmask the interrupts for a GPIO port, and @intr_type is used to store
|
||||
* the selected interrupt types. The logical AND of these values is written to
|
||||
* IMR on changes.
|
||||
*/
|
||||
struct realtek_gpio_ctrl {
|
||||
struct gpio_chip gc;
|
||||
void __iomem *base;
|
||||
raw_spinlock_t lock;
|
||||
u16 intr_mask[REALTEK_GPIO_PORTS_PER_BANK];
|
||||
u16 intr_type[REALTEK_GPIO_PORTS_PER_BANK];
|
||||
};
|
||||
|
||||
/* Expand with more flags as devices with other quirks are added */
|
||||
enum realtek_gpio_flags {
|
||||
/*
|
||||
* Allow disabling interrupts, for cases where the port order is
|
||||
* unknown. This may result in a port mismatch between ISR and IMR.
|
||||
* An interrupt would appear to come from a different line than the
|
||||
* line the IRQ handler was assigned to, causing uncaught interrupts.
|
||||
*/
|
||||
GPIO_INTERRUPTS_DISABLED = BIT(0),
|
||||
};
|
||||
|
||||
static struct realtek_gpio_ctrl *irq_data_to_ctrl(struct irq_data *data)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(data);
|
||||
|
||||
return container_of(gc, struct realtek_gpio_ctrl, gc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Normal port order register access
|
||||
*
|
||||
* Port information is stored with the first port at offset 0, followed by the
|
||||
* second, etc. Most registers store one bit per GPIO and use a u8 value per
|
||||
* port. The two interrupt mask registers store two bits per GPIO, so use u16
|
||||
* values.
|
||||
*/
|
||||
static void realtek_gpio_write_imr(struct realtek_gpio_ctrl *ctrl,
|
||||
unsigned int port, u16 irq_type, u16 irq_mask)
|
||||
{
|
||||
iowrite16(irq_type & irq_mask, ctrl->base + REALTEK_GPIO_REG_IMR + 2 * port);
|
||||
}
|
||||
|
||||
static void realtek_gpio_clear_isr(struct realtek_gpio_ctrl *ctrl,
|
||||
unsigned int port, u8 mask)
|
||||
{
|
||||
iowrite8(mask, ctrl->base + REALTEK_GPIO_REG_ISR + port);
|
||||
}
|
||||
|
||||
static u8 realtek_gpio_read_isr(struct realtek_gpio_ctrl *ctrl, unsigned int port)
|
||||
{
|
||||
return ioread8(ctrl->base + REALTEK_GPIO_REG_ISR + port);
|
||||
}
|
||||
|
||||
/* Set the rising and falling edge mask bits for a GPIO port pin */
|
||||
static u16 realtek_gpio_imr_bits(unsigned int pin, u16 value)
|
||||
{
|
||||
return (value & REALTEK_GPIO_IMR_LINE_MASK) << 2 * pin;
|
||||
}
|
||||
|
||||
static void realtek_gpio_irq_ack(struct irq_data *data)
|
||||
{
|
||||
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
|
||||
irq_hw_number_t line = irqd_to_hwirq(data);
|
||||
unsigned int port = line / 8;
|
||||
unsigned int port_pin = line % 8;
|
||||
|
||||
realtek_gpio_clear_isr(ctrl, port, BIT(port_pin));
|
||||
}
|
||||
|
||||
static void realtek_gpio_irq_unmask(struct irq_data *data)
|
||||
{
|
||||
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
|
||||
unsigned int line = irqd_to_hwirq(data);
|
||||
unsigned int port = line / 8;
|
||||
unsigned int port_pin = line % 8;
|
||||
unsigned long flags;
|
||||
u16 m;
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
m = ctrl->intr_mask[port];
|
||||
m |= realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
|
||||
ctrl->intr_mask[port] = m;
|
||||
realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static void realtek_gpio_irq_mask(struct irq_data *data)
|
||||
{
|
||||
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
|
||||
unsigned int line = irqd_to_hwirq(data);
|
||||
unsigned int port = line / 8;
|
||||
unsigned int port_pin = line % 8;
|
||||
unsigned long flags;
|
||||
u16 m;
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
m = ctrl->intr_mask[port];
|
||||
m &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
|
||||
ctrl->intr_mask[port] = m;
|
||||
realtek_gpio_write_imr(ctrl, port, ctrl->intr_type[port], m);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
}
|
||||
|
||||
static int realtek_gpio_irq_set_type(struct irq_data *data, unsigned int flow_type)
|
||||
{
|
||||
struct realtek_gpio_ctrl *ctrl = irq_data_to_ctrl(data);
|
||||
unsigned int line = irqd_to_hwirq(data);
|
||||
unsigned int port = line / 8;
|
||||
unsigned int port_pin = line % 8;
|
||||
unsigned long flags;
|
||||
u16 type, t;
|
||||
|
||||
switch (flow_type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
type = REALTEK_GPIO_IRQ_EDGE_FALLING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
type = REALTEK_GPIO_IRQ_EDGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
type = REALTEK_GPIO_IRQ_EDGE_BOTH;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
irq_set_handler_locked(data, handle_edge_irq);
|
||||
|
||||
raw_spin_lock_irqsave(&ctrl->lock, flags);
|
||||
t = ctrl->intr_type[port];
|
||||
t &= ~realtek_gpio_imr_bits(port_pin, REALTEK_GPIO_IMR_LINE_MASK);
|
||||
t |= realtek_gpio_imr_bits(port_pin, type);
|
||||
ctrl->intr_type[port] = t;
|
||||
realtek_gpio_write_imr(ctrl, port, t, ctrl->intr_mask[port]);
|
||||
raw_spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void realtek_gpio_irq_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct gpio_chip *gc = irq_desc_get_handler_data(desc);
|
||||
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
|
||||
struct irq_chip *irq_chip = irq_desc_get_chip(desc);
|
||||
unsigned int lines_done;
|
||||
unsigned int port_pin_count;
|
||||
unsigned int irq;
|
||||
unsigned long status;
|
||||
int offset;
|
||||
|
||||
chained_irq_enter(irq_chip, desc);
|
||||
|
||||
for (lines_done = 0; lines_done < gc->ngpio; lines_done += 8) {
|
||||
status = realtek_gpio_read_isr(ctrl, lines_done / 8);
|
||||
port_pin_count = min(gc->ngpio - lines_done, 8U);
|
||||
for_each_set_bit(offset, &status, port_pin_count) {
|
||||
irq = irq_find_mapping(gc->irq.domain, offset);
|
||||
generic_handle_irq(irq);
|
||||
}
|
||||
}
|
||||
|
||||
chained_irq_exit(irq_chip, desc);
|
||||
}
|
||||
|
||||
static int realtek_gpio_irq_init(struct gpio_chip *gc)
|
||||
{
|
||||
struct realtek_gpio_ctrl *ctrl = gpiochip_get_data(gc);
|
||||
unsigned int port;
|
||||
|
||||
for (port = 0; (port * 8) < gc->ngpio; port++) {
|
||||
realtek_gpio_write_imr(ctrl, port, 0, 0);
|
||||
realtek_gpio_clear_isr(ctrl, port, GENMASK(7, 0));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct irq_chip realtek_gpio_irq_chip = {
|
||||
.name = "realtek-otto-gpio",
|
||||
.irq_ack = realtek_gpio_irq_ack,
|
||||
.irq_mask = realtek_gpio_irq_mask,
|
||||
.irq_unmask = realtek_gpio_irq_unmask,
|
||||
.irq_set_type = realtek_gpio_irq_set_type,
|
||||
};
|
||||
|
||||
static const struct of_device_id realtek_gpio_of_match[] = {
|
||||
{
|
||||
.compatible = "realtek,otto-gpio",
|
||||
.data = (void *)GPIO_INTERRUPTS_DISABLED,
|
||||
},
|
||||
{
|
||||
.compatible = "realtek,rtl8380-gpio",
|
||||
},
|
||||
{
|
||||
.compatible = "realtek,rtl8390-gpio",
|
||||
},
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, realtek_gpio_of_match);
|
||||
|
||||
static int realtek_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
unsigned int dev_flags;
|
||||
struct gpio_irq_chip *girq;
|
||||
struct realtek_gpio_ctrl *ctrl;
|
||||
u32 ngpios;
|
||||
int err, irq;
|
||||
|
||||
ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
|
||||
if (!ctrl)
|
||||
return -ENOMEM;
|
||||
|
||||
dev_flags = (unsigned int) device_get_match_data(dev);
|
||||
|
||||
ngpios = REALTEK_GPIO_MAX;
|
||||
device_property_read_u32(dev, "ngpios", &ngpios);
|
||||
|
||||
if (ngpios > REALTEK_GPIO_MAX) {
|
||||
dev_err(&pdev->dev, "invalid ngpios (max. %d)\n",
|
||||
REALTEK_GPIO_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctrl->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(ctrl->base))
|
||||
return PTR_ERR(ctrl->base);
|
||||
|
||||
raw_spin_lock_init(&ctrl->lock);
|
||||
|
||||
err = bgpio_init(&ctrl->gc, dev, 4,
|
||||
ctrl->base + REALTEK_GPIO_REG_DATA, NULL, NULL,
|
||||
ctrl->base + REALTEK_GPIO_REG_DIR, NULL,
|
||||
BGPIOF_BIG_ENDIAN_BYTE_ORDER);
|
||||
if (err) {
|
||||
dev_err(dev, "unable to init generic GPIO");
|
||||
return err;
|
||||
}
|
||||
|
||||
ctrl->gc.ngpio = ngpios;
|
||||
ctrl->gc.owner = THIS_MODULE;
|
||||
|
||||
irq = platform_get_irq_optional(pdev, 0);
|
||||
if (!(dev_flags & GPIO_INTERRUPTS_DISABLED) && irq > 0) {
|
||||
girq = &ctrl->gc.irq;
|
||||
girq->chip = &realtek_gpio_irq_chip;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
girq->parent_handler = realtek_gpio_irq_handler;
|
||||
girq->num_parents = 1;
|
||||
girq->parents = devm_kcalloc(dev, girq->num_parents,
|
||||
sizeof(*girq->parents), GFP_KERNEL);
|
||||
if (!girq->parents)
|
||||
return -ENOMEM;
|
||||
girq->parents[0] = irq;
|
||||
girq->init_hw = realtek_gpio_irq_init;
|
||||
}
|
||||
|
||||
return devm_gpiochip_add_data(dev, &ctrl->gc, ctrl);
|
||||
}
|
||||
|
||||
static struct platform_driver realtek_gpio_driver = {
|
||||
.driver = {
|
||||
.name = "realtek-otto-gpio",
|
||||
.of_match_table = realtek_gpio_of_match,
|
||||
},
|
||||
.probe = realtek_gpio_probe,
|
||||
};
|
||||
module_platform_driver(realtek_gpio_driver);
|
||||
|
||||
MODULE_DESCRIPTION("Realtek Otto GPIO support");
|
||||
MODULE_AUTHOR("Sander Vanheule <sander@svanheule.net>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -7,33 +7,55 @@
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci_ids.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define GEN 0x00
|
||||
#define GIO 0x04
|
||||
#define GLV 0x08
|
||||
#define GTPE 0x0c
|
||||
#define GTNE 0x10
|
||||
#define GGPE 0x14
|
||||
#define GSMI 0x18
|
||||
#define GTS 0x1c
|
||||
|
||||
#define CORE_BANK_OFFSET 0x00
|
||||
#define RESUME_BANK_OFFSET 0x20
|
||||
|
||||
/*
|
||||
* iLB datasheet describes GPE0BLK registers, in particular GPE0E.GPIO bit.
|
||||
* Document Number: 328195-001
|
||||
*/
|
||||
#define GPE0E_GPIO 14
|
||||
|
||||
struct sch_gpio {
|
||||
struct gpio_chip chip;
|
||||
struct irq_chip irqchip;
|
||||
spinlock_t lock;
|
||||
unsigned short iobase;
|
||||
unsigned short resume_base;
|
||||
|
||||
/* GPE handling */
|
||||
u32 gpe;
|
||||
acpi_gpe_handler gpe_handler;
|
||||
};
|
||||
|
||||
static unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio,
|
||||
unsigned int reg)
|
||||
{
|
||||
unsigned int base = 0;
|
||||
unsigned int base = CORE_BANK_OFFSET;
|
||||
|
||||
if (gpio >= sch->resume_base) {
|
||||
gpio -= sch->resume_base;
|
||||
base += 0x20;
|
||||
base = RESUME_BANK_OFFSET;
|
||||
}
|
||||
|
||||
return base + reg + gpio / 8;
|
||||
@ -79,10 +101,11 @@ static void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned i
|
||||
static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
|
||||
{
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&sch->lock);
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
sch_gpio_reg_set(sch, gpio_num, GIO, 1);
|
||||
spin_unlock(&sch->lock);
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -96,20 +119,22 @@ static int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num)
|
||||
static void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val)
|
||||
{
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&sch->lock);
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
sch_gpio_reg_set(sch, gpio_num, GLV, val);
|
||||
spin_unlock(&sch->lock);
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
}
|
||||
|
||||
static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num,
|
||||
int val)
|
||||
{
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock(&sch->lock);
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
sch_gpio_reg_set(sch, gpio_num, GIO, 0);
|
||||
spin_unlock(&sch->lock);
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
|
||||
/*
|
||||
* according to the datasheet, writing to the level register has no
|
||||
@ -144,10 +169,145 @@ static const struct gpio_chip sch_gpio_chip = {
|
||||
.get_direction = sch_gpio_get_direction,
|
||||
};
|
||||
|
||||
static int sch_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio_num = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
int rising, falling;
|
||||
|
||||
switch (type & IRQ_TYPE_SENSE_MASK) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
rising = 1;
|
||||
falling = 0;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
rising = 0;
|
||||
falling = 1;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
rising = 1;
|
||||
falling = 1;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
|
||||
sch_gpio_reg_set(sch, gpio_num, GTPE, rising);
|
||||
sch_gpio_reg_set(sch, gpio_num, GTNE, falling);
|
||||
|
||||
irq_set_handler_locked(d, handle_edge_irq);
|
||||
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sch_irq_ack(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio_num = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
sch_gpio_reg_set(sch, gpio_num, GTS, 1);
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
}
|
||||
|
||||
static void sch_irq_mask_unmask(struct irq_data *d, int val)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct sch_gpio *sch = gpiochip_get_data(gc);
|
||||
irq_hw_number_t gpio_num = irqd_to_hwirq(d);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
sch_gpio_reg_set(sch, gpio_num, GGPE, val);
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
}
|
||||
|
||||
static void sch_irq_mask(struct irq_data *d)
|
||||
{
|
||||
sch_irq_mask_unmask(d, 0);
|
||||
}
|
||||
|
||||
static void sch_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
sch_irq_mask_unmask(d, 1);
|
||||
}
|
||||
|
||||
static u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
|
||||
{
|
||||
struct sch_gpio *sch = context;
|
||||
struct gpio_chip *gc = &sch->chip;
|
||||
unsigned long core_status, resume_status;
|
||||
unsigned long pending;
|
||||
unsigned long flags;
|
||||
int offset;
|
||||
u32 ret;
|
||||
|
||||
spin_lock_irqsave(&sch->lock, flags);
|
||||
|
||||
core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS);
|
||||
resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS);
|
||||
|
||||
spin_unlock_irqrestore(&sch->lock, flags);
|
||||
|
||||
pending = (resume_status << sch->resume_base) | core_status;
|
||||
for_each_set_bit(offset, &pending, sch->chip.ngpio)
|
||||
generic_handle_irq(irq_find_mapping(gc->irq.domain, offset));
|
||||
|
||||
/* Set returning value depending on whether we handled an interrupt */
|
||||
ret = pending ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
|
||||
|
||||
/* Acknowledge GPE to ACPICA */
|
||||
ret |= ACPI_REENABLE_GPE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sch_gpio_remove_gpe_handler(void *data)
|
||||
{
|
||||
struct sch_gpio *sch = data;
|
||||
|
||||
acpi_disable_gpe(NULL, sch->gpe);
|
||||
acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler);
|
||||
}
|
||||
|
||||
static int sch_gpio_install_gpe_handler(struct sch_gpio *sch)
|
||||
{
|
||||
struct device *dev = sch->chip.parent;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_install_gpe_handler(NULL, sch->gpe, ACPI_GPE_LEVEL_TRIGGERED,
|
||||
sch->gpe_handler, sch);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "Failed to install GPE handler for %u: %s\n",
|
||||
sch->gpe, acpi_format_exception(status));
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
status = acpi_enable_gpe(NULL, sch->gpe);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(dev, "Failed to enable GPE handler for %u: %s\n",
|
||||
sch->gpe, acpi_format_exception(status));
|
||||
acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return devm_add_action_or_reset(dev, sch_gpio_remove_gpe_handler, sch);
|
||||
}
|
||||
|
||||
static int sch_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct gpio_irq_chip *girq;
|
||||
struct sch_gpio *sch;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
|
||||
if (!sch)
|
||||
@ -207,6 +367,28 @@ static int sch_gpio_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, sch);
|
||||
|
||||
sch->irqchip.name = "sch_gpio";
|
||||
sch->irqchip.irq_ack = sch_irq_ack;
|
||||
sch->irqchip.irq_mask = sch_irq_mask;
|
||||
sch->irqchip.irq_unmask = sch_irq_unmask;
|
||||
sch->irqchip.irq_set_type = sch_irq_type;
|
||||
|
||||
girq = &sch->chip.irq;
|
||||
girq->chip = &sch->irqchip;
|
||||
girq->num_parents = 0;
|
||||
girq->parents = NULL;
|
||||
girq->parent_handler = NULL;
|
||||
girq->default_type = IRQ_TYPE_NONE;
|
||||
girq->handler = handle_bad_irq;
|
||||
|
||||
/* GPE setup is optional */
|
||||
sch->gpe = GPE0E_GPIO;
|
||||
sch->gpe_handler = sch_gpio_gpe_handler;
|
||||
|
||||
ret = sch_gpio_install_gpe_handler(sch);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n");
|
||||
|
||||
return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
|
||||
}
|
||||
|
||||
|
@ -1291,6 +1291,13 @@ void acpi_gpiochip_remove(struct gpio_chip *chip)
|
||||
kfree(acpi_gpio);
|
||||
}
|
||||
|
||||
void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
|
||||
{
|
||||
/* Set default fwnode to parent's one if present */
|
||||
if (gc->parent)
|
||||
ACPI_COMPANION_SET(&gdev->dev, ACPI_COMPANION(gc->parent));
|
||||
}
|
||||
|
||||
static int acpi_gpio_package_count(const union acpi_object *obj)
|
||||
{
|
||||
const union acpi_object *element = obj->package.elements;
|
||||
@ -1438,6 +1445,20 @@ static const struct dmi_system_id gpiolib_acpi_quirks[] __initconst = {
|
||||
.no_edge_events_on_boot = true,
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* The Dell Venue 10 Pro 5055, with Bay Trail SoC + TI PMIC uses an
|
||||
* external embedded-controller connected via I2C + an ACPI GPIO
|
||||
* event handler on INT33FFC:02 pin 12, causing spurious wakeups.
|
||||
*/
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Venue 10 Pro 5055"),
|
||||
},
|
||||
.driver_data = &(struct acpi_gpiolib_dmi_quirk) {
|
||||
.ignore_wake = "INT33FC:02@12",
|
||||
},
|
||||
},
|
||||
{
|
||||
/*
|
||||
* HP X2 10 models with Cherry Trail SoC + TI PMIC use an
|
||||
|
@ -36,6 +36,8 @@ struct acpi_gpio_info {
|
||||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
||||
|
||||
void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev);
|
||||
|
||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
||||
|
||||
@ -58,6 +60,8 @@ int acpi_gpio_count(struct device *dev, const char *con_id);
|
||||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
||||
|
||||
static inline void acpi_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev) { }
|
||||
|
||||
static inline void
|
||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
||||
|
||||
|
@ -1042,11 +1042,13 @@ void of_gpiochip_remove(struct gpio_chip *chip)
|
||||
|
||||
void of_gpio_dev_init(struct gpio_chip *gc, struct gpio_device *gdev)
|
||||
{
|
||||
/* Set default OF node to parent's one if present */
|
||||
if (gc->parent)
|
||||
gdev->dev.of_node = gc->parent->of_node;
|
||||
|
||||
/* If the gpiochip has an assigned OF node this takes precedence */
|
||||
if (gc->of_node)
|
||||
gdev->dev.of_node = gc->of_node;
|
||||
else
|
||||
gc->of_node = gdev->dev.of_node;
|
||||
if (gdev->dev.of_node)
|
||||
gdev->dev.fwnode = of_fwnode_handle(gdev->dev.of_node);
|
||||
}
|
||||
|
@ -586,14 +586,12 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
if (!gdev)
|
||||
return -ENOMEM;
|
||||
gdev->dev.bus = &gpio_bus_type;
|
||||
gdev->dev.parent = gc->parent;
|
||||
gdev->chip = gc;
|
||||
gc->gpiodev = gdev;
|
||||
if (gc->parent) {
|
||||
gdev->dev.parent = gc->parent;
|
||||
gdev->dev.of_node = gc->parent->of_node;
|
||||
}
|
||||
|
||||
of_gpio_dev_init(gc, gdev);
|
||||
acpi_gpio_dev_init(gc, gdev);
|
||||
|
||||
/*
|
||||
* Assign fwnode depending on the result of the previous calls,
|
||||
@ -1465,9 +1463,8 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
||||
struct lock_class_key *lock_key,
|
||||
struct lock_class_key *request_key)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(&gc->gpiodev->dev);
|
||||
struct irq_chip *irqchip = gc->irq.chip;
|
||||
const struct irq_domain_ops *ops = NULL;
|
||||
struct device_node *np;
|
||||
unsigned int type;
|
||||
unsigned int i;
|
||||
|
||||
@ -1479,7 +1476,6 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
np = gc->gpiodev->dev.of_node;
|
||||
type = gc->irq.default_type;
|
||||
|
||||
/*
|
||||
@ -1487,16 +1483,10 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
||||
* used to configure the interrupts, as you may end up with
|
||||
* conflicting triggers. Tell the user, and reset to NONE.
|
||||
*/
|
||||
if (WARN(np && type != IRQ_TYPE_NONE,
|
||||
"%s: Ignoring %u default trigger\n", np->full_name, type))
|
||||
if (WARN(fwnode && type != IRQ_TYPE_NONE,
|
||||
"%pfw: Ignoring %u default trigger\n", fwnode, type))
|
||||
type = IRQ_TYPE_NONE;
|
||||
|
||||
if (has_acpi_companion(gc->parent) && type != IRQ_TYPE_NONE) {
|
||||
acpi_handle_warn(ACPI_HANDLE(gc->parent),
|
||||
"Ignoring %u default trigger\n", type);
|
||||
type = IRQ_TYPE_NONE;
|
||||
}
|
||||
|
||||
if (gc->to_irq)
|
||||
chip_warn(gc, "to_irq is redefined in %s and you shouldn't rely on it\n", __func__);
|
||||
|
||||
@ -1512,15 +1502,11 @@ static int gpiochip_add_irqchip(struct gpio_chip *gc,
|
||||
return ret;
|
||||
} else {
|
||||
/* Some drivers provide custom irqdomain ops */
|
||||
if (gc->irq.domain_ops)
|
||||
ops = gc->irq.domain_ops;
|
||||
|
||||
if (!ops)
|
||||
ops = &gpiochip_domain_ops;
|
||||
gc->irq.domain = irq_domain_add_simple(np,
|
||||
gc->irq.domain = irq_domain_create_simple(fwnode,
|
||||
gc->ngpio,
|
||||
gc->irq.first,
|
||||
ops, gc);
|
||||
gc->irq.domain_ops ?: &gpiochip_domain_ops,
|
||||
gc);
|
||||
if (!gc->irq.domain)
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -3684,11 +3670,12 @@ EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
|
||||
*/
|
||||
int gpiod_count(struct device *dev, const char *con_id)
|
||||
{
|
||||
const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
|
||||
int count = -ENOENT;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && dev && dev->of_node)
|
||||
if (is_of_node(fwnode))
|
||||
count = of_gpio_get_count(dev, con_id);
|
||||
else if (IS_ENABLED(CONFIG_ACPI) && dev && ACPI_HANDLE(dev))
|
||||
else if (is_acpi_node(fwnode))
|
||||
count = acpi_gpio_count(dev, con_id);
|
||||
|
||||
if (count < 0)
|
||||
@ -3826,18 +3813,17 @@ struct gpio_desc *__must_check gpiod_get_index(struct device *dev,
|
||||
int ret;
|
||||
/* Maybe we have a device name, maybe not */
|
||||
const char *devname = dev ? dev_name(dev) : "?";
|
||||
const struct fwnode_handle *fwnode = dev ? dev_fwnode(dev) : NULL;
|
||||
|
||||
dev_dbg(dev, "GPIO lookup for consumer %s\n", con_id);
|
||||
|
||||
if (dev) {
|
||||
/* Using device tree? */
|
||||
if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
|
||||
dev_dbg(dev, "using device tree for GPIO lookup\n");
|
||||
desc = of_find_gpio(dev, con_id, idx, &lookupflags);
|
||||
} else if (ACPI_COMPANION(dev)) {
|
||||
dev_dbg(dev, "using ACPI for GPIO lookup\n");
|
||||
desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
|
||||
}
|
||||
/* Using device tree? */
|
||||
if (is_of_node(fwnode)) {
|
||||
dev_dbg(dev, "using device tree for GPIO lookup\n");
|
||||
desc = of_find_gpio(dev, con_id, idx, &lookupflags);
|
||||
} else if (is_acpi_node(fwnode)) {
|
||||
dev_dbg(dev, "using ACPI for GPIO lookup\n");
|
||||
desc = acpi_find_gpio(dev, con_id, idx, &flags, &lookupflags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -3921,9 +3907,6 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
struct gpio_desc *desc = ERR_PTR(-ENODEV);
|
||||
int ret;
|
||||
|
||||
if (!fwnode)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
if (is_of_node(fwnode)) {
|
||||
desc = gpiod_get_from_of_node(to_of_node(fwnode),
|
||||
propname, index,
|
||||
@ -3939,7 +3922,8 @@ struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
|
||||
|
||||
acpi_gpio_update_gpiod_flags(&dflags, &info);
|
||||
acpi_gpio_update_gpiod_lookup_flags(&lflags, &info);
|
||||
}
|
||||
} else
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
/* Currently only ACPI takes this path */
|
||||
ret = gpiod_request(desc, label);
|
||||
@ -4220,11 +4204,13 @@ EXPORT_SYMBOL_GPL(gpiod_put_array);
|
||||
|
||||
static int gpio_bus_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
struct fwnode_handle *fwnode = dev_fwnode(dev);
|
||||
|
||||
/*
|
||||
* Only match if the fwnode doesn't already have a proper struct device
|
||||
* created for it.
|
||||
*/
|
||||
if (dev->fwnode && dev->fwnode->dev != dev)
|
||||
if (fwnode && fwnode->dev != dev)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
struct device;
|
||||
|
||||
/*
|
||||
* bitmaps provide bit arrays that consume one or more unsigned
|
||||
@ -118,54 +120,59 @@
|
||||
* Allocation and deallocation of bitmap.
|
||||
* Provided in lib/bitmap.c to avoid circular dependency.
|
||||
*/
|
||||
extern unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags);
|
||||
extern unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags);
|
||||
extern void bitmap_free(const unsigned long *bitmap);
|
||||
unsigned long *bitmap_alloc(unsigned int nbits, gfp_t flags);
|
||||
unsigned long *bitmap_zalloc(unsigned int nbits, gfp_t flags);
|
||||
void bitmap_free(const unsigned long *bitmap);
|
||||
|
||||
/* Managed variants of the above. */
|
||||
unsigned long *devm_bitmap_alloc(struct device *dev,
|
||||
unsigned int nbits, gfp_t flags);
|
||||
unsigned long *devm_bitmap_zalloc(struct device *dev,
|
||||
unsigned int nbits, gfp_t flags);
|
||||
|
||||
/*
|
||||
* lib/bitmap.c provides these functions:
|
||||
*/
|
||||
|
||||
extern int __bitmap_equal(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern bool __pure __bitmap_or_equal(const unsigned long *src1,
|
||||
const unsigned long *src2,
|
||||
const unsigned long *src3,
|
||||
unsigned int nbits);
|
||||
extern void __bitmap_complement(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int nbits);
|
||||
extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits);
|
||||
extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits);
|
||||
extern void bitmap_cut(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int first, unsigned int cut,
|
||||
unsigned int nbits);
|
||||
extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
int __bitmap_equal(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
bool __pure __bitmap_or_equal(const unsigned long *src1,
|
||||
const unsigned long *src2,
|
||||
const unsigned long *src3,
|
||||
unsigned int nbits);
|
||||
void __bitmap_complement(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int nbits);
|
||||
void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits);
|
||||
void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int shift, unsigned int nbits);
|
||||
void bitmap_cut(unsigned long *dst, const unsigned long *src,
|
||||
unsigned int first, unsigned int cut, unsigned int nbits);
|
||||
int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
void __bitmap_replace(unsigned long *dst,
|
||||
const unsigned long *old, const unsigned long *new,
|
||||
const unsigned long *mask, unsigned int nbits);
|
||||
int __bitmap_intersects(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern void __bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern int __bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern void __bitmap_replace(unsigned long *dst,
|
||||
const unsigned long *old, const unsigned long *new,
|
||||
const unsigned long *mask, unsigned int nbits);
|
||||
extern int __bitmap_intersects(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern int __bitmap_subset(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
extern int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
|
||||
extern void __bitmap_set(unsigned long *map, unsigned int start, int len);
|
||||
extern void __bitmap_clear(unsigned long *map, unsigned int start, int len);
|
||||
int __bitmap_subset(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, unsigned int nbits);
|
||||
int __bitmap_weight(const unsigned long *bitmap, unsigned int nbits);
|
||||
void __bitmap_set(unsigned long *map, unsigned int start, int len);
|
||||
void __bitmap_clear(unsigned long *map, unsigned int start, int len);
|
||||
|
||||
extern unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned int nr,
|
||||
unsigned long align_mask,
|
||||
unsigned long align_offset);
|
||||
unsigned long bitmap_find_next_zero_area_off(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned int nr,
|
||||
unsigned long align_mask,
|
||||
unsigned long align_offset);
|
||||
|
||||
/**
|
||||
* bitmap_find_next_zero_area - find a contiguous aligned zero area
|
||||
@ -190,33 +197,33 @@ bitmap_find_next_zero_area(unsigned long *map,
|
||||
align_mask, 0);
|
||||
}
|
||||
|
||||
extern int bitmap_parse(const char *buf, unsigned int buflen,
|
||||
int bitmap_parse(const char *buf, unsigned int buflen,
|
||||
unsigned long *dst, int nbits);
|
||||
extern int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
|
||||
int bitmap_parse_user(const char __user *ubuf, unsigned int ulen,
|
||||
unsigned long *dst, int nbits);
|
||||
extern int bitmap_parselist(const char *buf, unsigned long *maskp,
|
||||
int bitmap_parselist(const char *buf, unsigned long *maskp,
|
||||
int nmaskbits);
|
||||
extern int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen,
|
||||
int bitmap_parselist_user(const char __user *ubuf, unsigned int ulen,
|
||||
unsigned long *dst, int nbits);
|
||||
extern void bitmap_remap(unsigned long *dst, const unsigned long *src,
|
||||
void bitmap_remap(unsigned long *dst, const unsigned long *src,
|
||||
const unsigned long *old, const unsigned long *new, unsigned int nbits);
|
||||
extern int bitmap_bitremap(int oldbit,
|
||||
int bitmap_bitremap(int oldbit,
|
||||
const unsigned long *old, const unsigned long *new, int bits);
|
||||
extern void bitmap_onto(unsigned long *dst, const unsigned long *orig,
|
||||
void bitmap_onto(unsigned long *dst, const unsigned long *orig,
|
||||
const unsigned long *relmap, unsigned int bits);
|
||||
extern void bitmap_fold(unsigned long *dst, const unsigned long *orig,
|
||||
void bitmap_fold(unsigned long *dst, const unsigned long *orig,
|
||||
unsigned int sz, unsigned int nbits);
|
||||
extern int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order);
|
||||
extern void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order);
|
||||
extern int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order);
|
||||
int bitmap_find_free_region(unsigned long *bitmap, unsigned int bits, int order);
|
||||
void bitmap_release_region(unsigned long *bitmap, unsigned int pos, int order);
|
||||
int bitmap_allocate_region(unsigned long *bitmap, unsigned int pos, int order);
|
||||
|
||||
#ifdef __BIG_ENDIAN
|
||||
extern void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
|
||||
void bitmap_copy_le(unsigned long *dst, const unsigned long *src, unsigned int nbits);
|
||||
#else
|
||||
#define bitmap_copy_le bitmap_copy
|
||||
#endif
|
||||
extern unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits);
|
||||
extern int bitmap_print_to_pagebuf(bool list, char *buf,
|
||||
unsigned int bitmap_ord_to_pos(const unsigned long *bitmap, unsigned int ord, unsigned int nbits);
|
||||
int bitmap_print_to_pagebuf(bool list, char *buf,
|
||||
const unsigned long *maskp, int nmaskbits);
|
||||
|
||||
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) & (BITS_PER_LONG - 1)))
|
||||
@ -265,9 +272,9 @@ static inline void bitmap_copy_clear_tail(unsigned long *dst,
|
||||
* therefore conversion is not needed when copying data from/to arrays of u32.
|
||||
*/
|
||||
#if BITS_PER_LONG == 64
|
||||
extern void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf,
|
||||
void bitmap_from_arr32(unsigned long *bitmap, const u32 *buf,
|
||||
unsigned int nbits);
|
||||
extern void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap,
|
||||
void bitmap_to_arr32(u32 *buf, const unsigned long *bitmap,
|
||||
unsigned int nbits);
|
||||
#else
|
||||
#define bitmap_from_arr32(bitmap, buf, nbits) \
|
||||
|
@ -227,7 +227,7 @@ struct gpio_irq_chip {
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
* If not %NULL holds bitmask of GPIOs which are valid to be included
|
||||
* If not %NULL, holds bitmask of GPIOs which are valid to be included
|
||||
* in IRQ domain of the chip.
|
||||
*/
|
||||
unsigned long *valid_mask;
|
||||
@ -346,7 +346,7 @@ struct gpio_irq_chip {
|
||||
* output.
|
||||
*
|
||||
* A gpio_chip can help platforms abstract various sources of GPIOs so
|
||||
* they can all be accessed through a common programing interface.
|
||||
* they can all be accessed through a common programming interface.
|
||||
* Example sources would be SOC controllers, FPGAs, multifunction
|
||||
* chips, dedicated GPIO expanders, and so on.
|
||||
*
|
||||
@ -435,15 +435,15 @@ struct gpio_chip {
|
||||
/**
|
||||
* @valid_mask:
|
||||
*
|
||||
* If not %NULL holds bitmask of GPIOs which are valid to be used
|
||||
* If not %NULL, holds bitmask of GPIOs which are valid to be used
|
||||
* from the chip.
|
||||
*/
|
||||
unsigned long *valid_mask;
|
||||
|
||||
#if defined(CONFIG_OF_GPIO)
|
||||
/*
|
||||
* If CONFIG_OF is enabled, then all GPIO controllers described in the
|
||||
* device tree automatically may have an OF translation
|
||||
* If CONFIG_OF_GPIO is enabled, then all GPIO controllers described in
|
||||
* the device tree automatically may have an OF translation
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -508,7 +508,7 @@ extern int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
|
||||
* for GPIOs will fail rudely.
|
||||
*
|
||||
* gpiochip_add_data() must only be called after gpiolib initialization,
|
||||
* ie after core_initcall().
|
||||
* i.e. after core_initcall().
|
||||
*
|
||||
* If gc->base is negative, this requests dynamic assignment of
|
||||
* a range of valid GPIOs.
|
||||
|
@ -256,11 +256,11 @@ struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
|
||||
irq_hw_number_t hwirq_max, int direct_max,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data);
|
||||
struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
@ -325,6 +325,15 @@ static inline struct irq_domain *irq_find_host(struct device_node *node)
|
||||
return d;
|
||||
}
|
||||
|
||||
static inline struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
{
|
||||
return irq_domain_create_simple(of_node_to_fwnode(of_node), size, first_irq, ops, host_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* irq_domain_add_linear() - Allocate and register a linear revmap irq_domain.
|
||||
* @of_node: pointer to interrupt controller's device tree node.
|
||||
|
@ -295,8 +295,8 @@ void irq_domain_update_bus_token(struct irq_domain *domain,
|
||||
EXPORT_SYMBOL_GPL(irq_domain_update_bus_token);
|
||||
|
||||
/**
|
||||
* irq_domain_add_simple() - Register an irq_domain and optionally map a range of irqs
|
||||
* @of_node: pointer to interrupt controller's device tree node.
|
||||
* irq_domain_create_simple() - Register an irq_domain and optionally map a range of irqs
|
||||
* @fwnode: firmware node for the interrupt controller
|
||||
* @size: total number of irqs in mapping
|
||||
* @first_irq: first number of irq block assigned to the domain,
|
||||
* pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
|
||||
@ -312,15 +312,15 @@ EXPORT_SYMBOL_GPL(irq_domain_update_bus_token);
|
||||
* irqs get mapped dynamically on the fly. However, if the controller requires
|
||||
* static virq assignments (non-DT boot) then it will set that up correctly.
|
||||
*/
|
||||
struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode,
|
||||
unsigned int size,
|
||||
unsigned int first_irq,
|
||||
const struct irq_domain_ops *ops,
|
||||
void *host_data)
|
||||
{
|
||||
struct irq_domain *domain;
|
||||
|
||||
domain = __irq_domain_add(of_node_to_fwnode(of_node), size, size, 0, ops, host_data);
|
||||
domain = __irq_domain_add(fwnode, size, size, 0, ops, host_data);
|
||||
if (!domain)
|
||||
return NULL;
|
||||
|
||||
@ -328,7 +328,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
|
||||
if (IS_ENABLED(CONFIG_SPARSE_IRQ)) {
|
||||
/* attempt to allocated irq_descs */
|
||||
int rc = irq_alloc_descs(first_irq, first_irq, size,
|
||||
of_node_to_nid(of_node));
|
||||
of_node_to_nid(to_of_node(fwnode)));
|
||||
if (rc < 0)
|
||||
pr_info("Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
|
||||
first_irq);
|
||||
@ -338,7 +338,7 @@ struct irq_domain *irq_domain_add_simple(struct device_node *of_node,
|
||||
|
||||
return domain;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_domain_add_simple);
|
||||
EXPORT_SYMBOL_GPL(irq_domain_create_simple);
|
||||
|
||||
/**
|
||||
* irq_domain_add_legacy() - Allocate and register a legacy revmap irq_domain.
|
||||
|
42
lib/bitmap.c
42
lib/bitmap.c
@ -3,17 +3,19 @@
|
||||
* lib/bitmap.c
|
||||
* Helper functions for bitmap.h.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/thread_info.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
@ -1271,6 +1273,38 @@ void bitmap_free(const unsigned long *bitmap)
|
||||
}
|
||||
EXPORT_SYMBOL(bitmap_free);
|
||||
|
||||
static void devm_bitmap_free(void *data)
|
||||
{
|
||||
unsigned long *bitmap = data;
|
||||
|
||||
bitmap_free(bitmap);
|
||||
}
|
||||
|
||||
unsigned long *devm_bitmap_alloc(struct device *dev,
|
||||
unsigned int nbits, gfp_t flags)
|
||||
{
|
||||
unsigned long *bitmap;
|
||||
int ret;
|
||||
|
||||
bitmap = bitmap_alloc(nbits, flags);
|
||||
if (!bitmap)
|
||||
return NULL;
|
||||
|
||||
ret = devm_add_action_or_reset(dev, devm_bitmap_free, bitmap);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_bitmap_alloc);
|
||||
|
||||
unsigned long *devm_bitmap_zalloc(struct device *dev,
|
||||
unsigned int nbits, gfp_t flags)
|
||||
{
|
||||
return devm_bitmap_alloc(dev, nbits, flags | __GFP_ZERO);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_bitmap_zalloc);
|
||||
|
||||
#if BITS_PER_LONG == 64
|
||||
/**
|
||||
* bitmap_from_arr32 - copy the contents of u32 array of bits to bitmap
|
||||
|
@ -272,3 +272,4 @@ char *next_arg(char *args, char **param, char **val)
|
||||
/* Chew up trailing spaces. */
|
||||
return skip_spaces(args);
|
||||
}
|
||||
EXPORT_SYMBOL(next_arg);
|
||||
|
@ -20,7 +20,7 @@
|
||||
#define CONSUMER "gpio-utils"
|
||||
|
||||
/**
|
||||
* doc: Operation of gpio
|
||||
* DOC: Operation of gpio
|
||||
*
|
||||
* Provide the api of gpiochip for chardev interface. There are two
|
||||
* types of api. The first one provide as same function as each
|
||||
@ -100,7 +100,7 @@ exit_free_name:
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_set_values(): Set the value of gpio(s)
|
||||
* gpiotools_set_values() - Set the value of gpio(s)
|
||||
* @fd: The fd returned by
|
||||
* gpiotools_request_line().
|
||||
* @values: The array of values want to set.
|
||||
@ -124,7 +124,7 @@ int gpiotools_set_values(const int fd, struct gpio_v2_line_values *values)
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_get_values(): Get the value of gpio(s)
|
||||
* gpiotools_get_values() - Get the value of gpio(s)
|
||||
* @fd: The fd returned by
|
||||
* gpiotools_request_line().
|
||||
* @values: The array of values get from hardware.
|
||||
@ -148,7 +148,7 @@ int gpiotools_get_values(const int fd, struct gpio_v2_line_values *values)
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_release_line(): Release the line(s) of gpiochip
|
||||
* gpiotools_release_line() - Release the line(s) of gpiochip
|
||||
* @fd: The fd returned by
|
||||
* gpiotools_request_line().
|
||||
*
|
||||
@ -169,7 +169,7 @@ int gpiotools_release_line(const int fd)
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_get(): Get value from specific line
|
||||
* gpiotools_get() - Get value from specific line
|
||||
* @device_name: The name of gpiochip without prefix "/dev/",
|
||||
* such as "gpiochip0"
|
||||
* @line: number of line, such as 2.
|
||||
@ -191,7 +191,7 @@ int gpiotools_get(const char *device_name, unsigned int line)
|
||||
|
||||
|
||||
/**
|
||||
* gpiotools_gets(): Get values from specific lines.
|
||||
* gpiotools_gets() - Get values from specific lines.
|
||||
* @device_name: The name of gpiochip without prefix "/dev/",
|
||||
* such as "gpiochip0".
|
||||
* @lines: An array desired lines, specified by offset
|
||||
@ -230,7 +230,7 @@ int gpiotools_gets(const char *device_name, unsigned int *lines,
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_set(): Set value to specific line
|
||||
* gpiotools_set() - Set value to specific line
|
||||
* @device_name: The name of gpiochip without prefix "/dev/",
|
||||
* such as "gpiochip0"
|
||||
* @line: number of line, such as 2.
|
||||
@ -248,13 +248,13 @@ int gpiotools_set(const char *device_name, unsigned int line,
|
||||
}
|
||||
|
||||
/**
|
||||
* gpiotools_sets(): Set values to specific lines.
|
||||
* gpiotools_sets() - Set values to specific lines.
|
||||
* @device_name: The name of gpiochip without prefix "/dev/",
|
||||
* such as "gpiochip0".
|
||||
* @lines: An array desired lines, specified by offset
|
||||
* index for the associated GPIO device.
|
||||
* @num_lines: The number of lines to request.
|
||||
* @value: The array of values set to gpiochip, must be
|
||||
* @values: The array of values set to gpiochip, must be
|
||||
* 0(low) or 1(high).
|
||||
*
|
||||
* Return: On success return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user