Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
e1a0d869
Commit
e1a0d869
authored
Dec 07, 2016
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'thread-irq-simpler' of /home/linus/linux-gpio into devel
parents
88979a02
35ca3f61
Changes
13
Show whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
177 additions
and
106 deletions
+177
-106
Documentation/gpio/driver.txt
Documentation/gpio/driver.txt
+36
-26
drivers/gpio/gpio-adnp.c
drivers/gpio/gpio-adnp.c
+7
-5
drivers/gpio/gpio-crystalcove.c
drivers/gpio/gpio-crystalcove.c
+4
-2
drivers/gpio/gpio-dln2.c
drivers/gpio/gpio-dln2.c
+0
-1
drivers/gpio/gpio-max732x.c
drivers/gpio/gpio-max732x.c
+8
-9
drivers/gpio/gpio-mcp23s08.c
drivers/gpio/gpio-mcp23s08.c
+8
-9
drivers/gpio/gpio-pca953x.c
drivers/gpio/gpio-pca953x.c
+8
-8
drivers/gpio/gpio-pcf857x.c
drivers/gpio/gpio-pcf857x.c
+6
-5
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-stmpe.c
+8
-9
drivers/gpio/gpio-tc3589x.c
drivers/gpio/gpio-tc3589x.c
+8
-9
drivers/gpio/gpio-wcove.c
drivers/gpio/gpio-wcove.c
+4
-2
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.c
+56
-13
include/linux/gpio/driver.h
include/linux/gpio/driver.h
+24
-8
No files found.
Documentation/gpio/driver.txt
View file @
e1a0d869
...
@@ -175,8 +175,8 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using
...
@@ -175,8 +175,8 @@ The IRQ portions of the GPIO block are implemented using an irqchip, using
the header <linux/irq.h>. So basically such a driver is utilizing two sub-
the header <linux/irq.h>. So basically such a driver is utilizing two sub-
systems simultaneously: gpio and irq.
systems simultaneously: gpio and irq.
RT_FULL:
GPIO driver should not use spinlock_t or any sleepable APIs
RT_FULL:
a realtime compliant GPIO driver should not use spinlock_t or any
(like PM runtime) as part of its irq_chip implementation on -RT
.
sleepable APIs (like PM runtime) as part of its irq_chip implementation
.
- spinlock_t should be replaced with raw_spinlock_t [1].
- spinlock_t should be replaced with raw_spinlock_t [1].
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
- If sleepable APIs have to be used, these can be done from the .irq_bus_lock()
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
and .irq_bus_unlock() callbacks, as these are the only slowpath callbacks
...
@@ -185,33 +185,32 @@ RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
...
@@ -185,33 +185,32 @@ RT_FULL: GPIO driver should not use spinlock_t or any sleepable APIs
GPIO irqchips usually fall in one of two categories:
GPIO irqchips usually fall in one of two categories:
* CHAINED GPIO irqchips: these are usually the type that is embedded on
* CHAINED GPIO irqchips: these are usually the type that is embedded on
an SoC. This means that there is a fast IRQ handler for the GPIOs that
an SoC. This means that there is a fast IRQ
flow
handler for the GPIOs that
gets called in a chain from the parent IRQ handler, most typically the
gets called in a chain from the parent IRQ handler, most typically the
system interrupt controller. This means the GPIO irqchip is registered
system interrupt controller. This means that the GPIO irqchip handler will
using irq_set_chained_handler() or the corresponding
be called immediately from the parent irqchip, while holding the IRQs
gpiochip_set_chained_irqchip() helper function, and the GPIO irqchip
disabled. The GPIO irqchip will then end up calling something like this
handler will be called immediately from the parent irqchip, while
sequence in its interrupt handler:
holding the IRQs disabled. The GPIO irqchip will then end up calling
something like this sequence in its interrupt handler:
static irqreturn_t foo_gpio_irq(int irq, void *data)
static irqreturn_t tc3589x_gpio_irq(int irq, void *data)
chained_irq_enter(...);
chained_irq_enter(...);
generic_handle_irq(...);
generic_handle_irq(...);
chained_irq_exit(...);
chained_irq_exit(...);
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
Chained GPIO irqchips typically can NOT set the .can_sleep flag on
struct gpio_chip, as everything happens directly in the callbacks.
struct gpio_chip, as everything happens directly in the callbacks: no
slow bus traffic like I2C can be used.
RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
RT_FULL: Note, chained IRQ handlers will not be forced threaded on -RT.
As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
As result, spinlock_t or any sleepable APIs (like PM runtime) can't be used
in chained IRQ handler.
in chained IRQ handler.
i
f required (and if it can't be converted to the nested threaded GPIO irqchip)
I
f required (and if it can't be converted to the nested threaded GPIO irqchip)
-
chained IRQ handler can be converted to generic irq handler and this way
a
chained IRQ handler can be converted to generic irq handler and this way
it will be
threaded IRQ handler on -RT and
hard IRQ handler on non-RT
it will be
a threaded IRQ handler on -RT and a
hard IRQ handler on non-RT
(for example, see [3]).
(for example, see [3]).
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
Know W/A: The generic_handle_irq() is expected to be called with IRQ disabled,
so
IRQ core will complain if it will be called from
IRQ handler which is
so
the IRQ core will complain if it is called from an
IRQ handler which is
forced thread. The "fake?" raw lock can be used to W/A this problem:
forced t
o a t
hread. The "fake?" raw lock can be used to W/A this problem:
raw_spinlock_t wa_lock;
raw_spinlock_t wa_lock;
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
static irqreturn_t omap_gpio_irq_handler(int irq, void *gpiobank)
...
@@ -243,7 +242,7 @@ GPIO irqchips usually fall in one of two categories:
...
@@ -243,7 +242,7 @@ GPIO irqchips usually fall in one of two categories:
by the driver. The hallmark of this driver is to call something like
by the driver. The hallmark of this driver is to call something like
this in its interrupt handler:
this in its interrupt handler:
static irqreturn_t
tc3589x
_gpio_irq(int irq, void *data)
static irqreturn_t
foo
_gpio_irq(int irq, void *data)
...
...
handle_nested_irq(irq);
handle_nested_irq(irq);
...
@@ -256,23 +255,31 @@ associated irqdomain and resource allocation callbacks, the gpiolib has
...
@@ -256,23 +255,31 @@ associated irqdomain and resource allocation callbacks, the gpiolib has
some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
some helpers that can be enabled by selecting the GPIOLIB_IRQCHIP Kconfig
symbol:
symbol:
* gpiochip_irqchip_add(): adds a
n
irqchip to a gpiochip. It will pass
* gpiochip_irqchip_add(): adds a
chained
irqchip to a gpiochip. It will pass
the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks
the struct gpio_chip* for the chip to all IRQ callbacks, so the callbacks
need to embed the gpio_chip in its state container and obtain a pointer
need to embed the gpio_chip in its state container and obtain a pointer
to the container using container_of().
to the container using container_of().
(See Documentation/driver-model/design-patterns.txt)
(See Documentation/driver-model/design-patterns.txt)
If there is a need to exclude certain GPIOs from the IRQ domain, one can
* gpiochip_irqchip_add_nested(): adds a nested irqchip to a gpiochip.
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
Apart from that it works exactly like the chained irqchip.
called. This allocates .irq_valid_mask with as many bits set as there are
GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
mask. The mask must be filled in before gpiochip_irqchip_add() is called.
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
* gpiochip_set_chained_irqchip(): sets up a chained irq handler for a
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
gpio_chip from a parent IRQ and passes the struct gpio_chip* as handler
data. (Notice handler data, since the irqchip data is likely used by the
data. (Notice handler data, since the irqchip data is likely used by the
parent irqchip!) This is for the chained type of chip. This is also used
parent irqchip!).
to set up a nested irqchip if NULL is passed as handler.
* gpiochip_set_nested_irqchip(): sets up a nested irq handler for a
gpio_chip from a parent IRQ. As the parent IRQ has usually been
explicitly requested by the driver, this does very little more than
mark all the child IRQs as having the other IRQ as parent.
If there is a need to exclude certain GPIOs from the IRQ domain, you can
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
called. This allocates an .irq_valid_mask with as many bits set as there
are GPIOs in the chip. Drivers can exclude GPIOs by clearing bits from this
mask. The mask must be filled in before gpiochip_irqchip_add() or
gpiochip_irqchip_add_nested() is called.
To use the helpers please keep the following in mind:
To use the helpers please keep the following in mind:
...
@@ -323,6 +330,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
...
@@ -323,6 +330,9 @@ When implementing an irqchip inside a GPIO driver, these two functions should
typically be called in the .startup() and .shutdown() callbacks from the
typically be called in the .startup() and .shutdown() callbacks from the
irqchip.
irqchip.
When using the gpiolib irqchip helpers, these callback are automatically
assigned.
Real-Time compliance for GPIO IRQ chips
Real-Time compliance for GPIO IRQ chips
---------------------------------------
---------------------------------------
...
...
drivers/gpio/gpio-adnp.c
View file @
e1a0d869
...
@@ -468,7 +468,7 @@ static int adnp_irq_setup(struct adnp *adnp)
...
@@ -468,7 +468,7 @@ static int adnp_irq_setup(struct adnp *adnp)
return
err
;
return
err
;
}
}
err
=
gpiochip_irqchip_add
(
chip
,
err
=
gpiochip_irqchip_add
_nested
(
chip
,
&
adnp_irq_chip
,
&
adnp_irq_chip
,
0
,
0
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -479,6 +479,8 @@ static int adnp_irq_setup(struct adnp *adnp)
...
@@ -479,6 +479,8 @@ static int adnp_irq_setup(struct adnp *adnp)
return
err
;
return
err
;
}
}
gpiochip_set_nested_irqchip
(
chip
,
&
adnp_irq_chip
,
adnp
->
client
->
irq
);
return
0
;
return
0
;
}
}
...
...
drivers/gpio/gpio-crystalcove.c
View file @
e1a0d869
...
@@ -351,7 +351,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
...
@@ -351,7 +351,7 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return
retval
;
return
retval
;
}
}
gpiochip_irqchip_add
(
&
cg
->
chip
,
&
crystalcove_irqchip
,
0
,
gpiochip_irqchip_add
_nested
(
&
cg
->
chip
,
&
crystalcove_irqchip
,
0
,
handle_simple_irq
,
IRQ_TYPE_NONE
);
handle_simple_irq
,
IRQ_TYPE_NONE
);
retval
=
request_threaded_irq
(
irq
,
NULL
,
crystalcove_gpio_irq_handler
,
retval
=
request_threaded_irq
(
irq
,
NULL
,
crystalcove_gpio_irq_handler
,
...
@@ -362,6 +362,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
...
@@ -362,6 +362,8 @@ static int crystalcove_gpio_probe(struct platform_device *pdev)
return
retval
;
return
retval
;
}
}
gpiochip_set_nested_irqchip
(
&
cg
->
chip
,
&
crystalcove_irqchip
,
irq
);
return
0
;
return
0
;
}
}
...
...
drivers/gpio/gpio-dln2.c
View file @
e1a0d869
...
@@ -467,7 +467,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
...
@@ -467,7 +467,6 @@ static int dln2_gpio_probe(struct platform_device *pdev)
dln2
->
gpio
.
base
=
-
1
;
dln2
->
gpio
.
base
=
-
1
;
dln2
->
gpio
.
ngpio
=
pins
;
dln2
->
gpio
.
ngpio
=
pins
;
dln2
->
gpio
.
can_sleep
=
true
;
dln2
->
gpio
.
can_sleep
=
true
;
dln2
->
gpio
.
irq_not_threaded
=
true
;
dln2
->
gpio
.
set
=
dln2_gpio_set
;
dln2
->
gpio
.
set
=
dln2_gpio_set
;
dln2
->
gpio
.
get
=
dln2_gpio_get
;
dln2
->
gpio
.
get
=
dln2_gpio_get
;
dln2
->
gpio
.
request
=
dln2_gpio_request
;
dln2
->
gpio
.
request
=
dln2_gpio_request
;
...
...
drivers/gpio/gpio-max732x.c
View file @
e1a0d869
...
@@ -520,7 +520,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
...
@@ -520,7 +520,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
client
->
irq
);
client
->
irq
);
return
ret
;
return
ret
;
}
}
ret
=
gpiochip_irqchip_add
(
&
chip
->
gpio_chip
,
ret
=
gpiochip_irqchip_add
_nested
(
&
chip
->
gpio_chip
,
&
max732x_irq_chip
,
&
max732x_irq_chip
,
irq_base
,
irq_base
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -530,10 +530,9 @@ static int max732x_irq_setup(struct max732x_chip *chip,
...
@@ -530,10 +530,9 @@ static int max732x_irq_setup(struct max732x_chip *chip,
"could not connect irqchip to gpiochip
\n
"
);
"could not connect irqchip to gpiochip
\n
"
);
return
ret
;
return
ret
;
}
}
gpiochip_set_
chain
ed_irqchip
(
&
chip
->
gpio_chip
,
gpiochip_set_
nest
ed_irqchip
(
&
chip
->
gpio_chip
,
&
max732x_irq_chip
,
&
max732x_irq_chip
,
client
->
irq
,
client
->
irq
);
NULL
);
}
}
return
0
;
return
0
;
...
...
drivers/gpio/gpio-mcp23s08.c
View file @
e1a0d869
...
@@ -473,7 +473,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
...
@@ -473,7 +473,7 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return
err
;
return
err
;
}
}
err
=
gpiochip_irqchip_add
(
chip
,
err
=
gpiochip_irqchip_add
_nested
(
chip
,
&
mcp23s08_irq_chip
,
&
mcp23s08_irq_chip
,
0
,
0
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -484,10 +484,9 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
...
@@ -484,10 +484,9 @@ static int mcp23s08_irq_setup(struct mcp23s08 *mcp)
return
err
;
return
err
;
}
}
gpiochip_set_
chain
ed_irqchip
(
chip
,
gpiochip_set_
nest
ed_irqchip
(
chip
,
&
mcp23s08_irq_chip
,
&
mcp23s08_irq_chip
,
mcp
->
irq
,
mcp
->
irq
);
NULL
);
return
0
;
return
0
;
}
}
...
...
drivers/gpio/gpio-pca953x.c
View file @
e1a0d869
...
@@ -635,7 +635,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
...
@@ -635,7 +635,7 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return
ret
;
return
ret
;
}
}
ret
=
gpiochip_irqchip_add
(
&
chip
->
gpio_chip
,
ret
=
gpiochip_irqchip_add
_nested
(
&
chip
->
gpio_chip
,
&
pca953x_irq_chip
,
&
pca953x_irq_chip
,
irq_base
,
irq_base
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -646,9 +646,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
...
@@ -646,9 +646,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
return
ret
;
return
ret
;
}
}
gpiochip_set_
chain
ed_irqchip
(
&
chip
->
gpio_chip
,
gpiochip_set_
nest
ed_irqchip
(
&
chip
->
gpio_chip
,
&
pca953x_irq_chip
,
&
pca953x_irq_chip
,
client
->
irq
,
NULL
);
client
->
irq
);
}
}
return
0
;
return
0
;
...
...
drivers/gpio/gpio-pcf857x.c
View file @
e1a0d869
...
@@ -378,7 +378,8 @@ static int pcf857x_probe(struct i2c_client *client,
...
@@ -378,7 +378,8 @@ static int pcf857x_probe(struct i2c_client *client,
/* Enable irqchip if we have an interrupt */
/* Enable irqchip if we have an interrupt */
if
(
client
->
irq
)
{
if
(
client
->
irq
)
{
status
=
gpiochip_irqchip_add
(
&
gpio
->
chip
,
&
pcf857x_irq_chip
,
status
=
gpiochip_irqchip_add_nested
(
&
gpio
->
chip
,
&
pcf857x_irq_chip
,
0
,
handle_level_irq
,
0
,
handle_level_irq
,
IRQ_TYPE_NONE
);
IRQ_TYPE_NONE
);
if
(
status
)
{
if
(
status
)
{
...
@@ -393,8 +394,8 @@ static int pcf857x_probe(struct i2c_client *client,
...
@@ -393,8 +394,8 @@ static int pcf857x_probe(struct i2c_client *client,
if
(
status
)
if
(
status
)
goto
fail
;
goto
fail
;
gpiochip_set_
chain
ed_irqchip
(
&
gpio
->
chip
,
&
pcf857x_irq_chip
,
gpiochip_set_
nest
ed_irqchip
(
&
gpio
->
chip
,
&
pcf857x_irq_chip
,
client
->
irq
,
NULL
);
client
->
irq
);
gpio
->
irq_parent
=
client
->
irq
;
gpio
->
irq_parent
=
client
->
irq
;
}
}
...
...
drivers/gpio/gpio-stmpe.c
View file @
e1a0d869
...
@@ -484,7 +484,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
...
@@ -484,7 +484,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
if
(
stmpe_gpio
->
norequest_mask
&
BIT
(
i
))
if
(
stmpe_gpio
->
norequest_mask
&
BIT
(
i
))
clear_bit
(
i
,
stmpe_gpio
->
chip
.
irq_valid_mask
);
clear_bit
(
i
,
stmpe_gpio
->
chip
.
irq_valid_mask
);
}
}
ret
=
gpiochip_irqchip_add
(
&
stmpe_gpio
->
chip
,
ret
=
gpiochip_irqchip_add
_nested
(
&
stmpe_gpio
->
chip
,
&
stmpe_gpio_irq_chip
,
&
stmpe_gpio_irq_chip
,
0
,
0
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -495,10 +495,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
...
@@ -495,10 +495,9 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
goto
out_disable
;
goto
out_disable
;
}
}
gpiochip_set_
chain
ed_irqchip
(
&
stmpe_gpio
->
chip
,
gpiochip_set_
nest
ed_irqchip
(
&
stmpe_gpio
->
chip
,
&
stmpe_gpio_irq_chip
,
&
stmpe_gpio_irq_chip
,
irq
,
irq
);
NULL
);
}
}
platform_set_drvdata
(
pdev
,
stmpe_gpio
);
platform_set_drvdata
(
pdev
,
stmpe_gpio
);
...
...
drivers/gpio/gpio-tc3589x.c
View file @
e1a0d869
...
@@ -337,7 +337,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
...
@@ -337,7 +337,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return
ret
;
return
ret
;
}
}
ret
=
gpiochip_irqchip_add
(
&
tc3589x_gpio
->
chip
,
ret
=
gpiochip_irqchip_add
_nested
(
&
tc3589x_gpio
->
chip
,
&
tc3589x_gpio_irq_chip
,
&
tc3589x_gpio_irq_chip
,
0
,
0
,
handle_simple_irq
,
handle_simple_irq
,
...
@@ -348,10 +348,9 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
...
@@ -348,10 +348,9 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
return
ret
;
return
ret
;
}
}
gpiochip_set_
chain
ed_irqchip
(
&
tc3589x_gpio
->
chip
,
gpiochip_set_
nest
ed_irqchip
(
&
tc3589x_gpio
->
chip
,
&
tc3589x_gpio_irq_chip
,
&
tc3589x_gpio_irq_chip
,
irq
,
irq
);
NULL
);
platform_set_drvdata
(
pdev
,
tc3589x_gpio
);
platform_set_drvdata
(
pdev
,
tc3589x_gpio
);
...
...
drivers/gpio/gpio-wcove.c
View file @
e1a0d869
...
@@ -426,7 +426,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
...
@@ -426,7 +426,7 @@ static int wcove_gpio_probe(struct platform_device *pdev)
return
ret
;
return
ret
;
}
}
ret
=
gpiochip_irqchip_add
(
&
wg
->
chip
,
&
wcove_irqchip
,
0
,
ret
=
gpiochip_irqchip_add
_nested
(
&
wg
->
chip
,
&
wcove_irqchip
,
0
,
handle_simple_irq
,
IRQ_TYPE_NONE
);
handle_simple_irq
,
IRQ_TYPE_NONE
);
if
(
ret
)
{
if
(
ret
)
{
dev_err
(
dev
,
"Failed to add irqchip: %d
\n
"
,
ret
);
dev_err
(
dev
,
"Failed to add irqchip: %d
\n
"
,
ret
);
...
@@ -446,6 +446,8 @@ static int wcove_gpio_probe(struct platform_device *pdev)
...
@@ -446,6 +446,8 @@ static int wcove_gpio_probe(struct platform_device *pdev)
return
ret
;
return
ret
;
}
}
gpiochip_set_nested_irqchip
(
&
wg
->
chip
,
&
wcove_irqchip
,
virq
);
return
0
;
return
0
;
}
}
...
...
drivers/gpio/gpiolib.c
View file @
e1a0d869
...
@@ -1439,7 +1439,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
...
@@ -1439,7 +1439,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
}
}
/**
/**
* gpiochip_set_c
hained_irqchip() - sets a chain
ed irqchip to a gpiochip
* gpiochip_set_c
ascaded_irqchip() - connects a cascad
ed irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
* @gpiochip: the gpiochip to set the irqchip chain to
* @irqchip: the irqchip to chain to the gpiochip
* @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* @parent_irq: the irq number corresponding to the parent IRQ for this
...
@@ -1448,7 +1448,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
...
@@ -1448,7 +1448,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
* coming out of the gpiochip. If the interrupt is nested rather than
* coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument
* cascaded, pass NULL in this handler argument
*/
*/
void
gpiochip_set_chain
ed_irqchip
(
struct
gpio_chip
*
gpiochip
,
static
void
gpiochip_set_cascad
ed_irqchip
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
struct
irq_chip
*
irqchip
,
int
parent_irq
,
int
parent_irq
,
irq_flow_handler_t
parent_handler
)
irq_flow_handler_t
parent_handler
)
...
@@ -1475,7 +1475,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
...
@@ -1475,7 +1475,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
irq_set_chained_handler_and_data
(
parent_irq
,
parent_handler
,
irq_set_chained_handler_and_data
(
parent_irq
,
parent_handler
,
gpiochip
);
gpiochip
);
gpiochip
->
irq_parent
=
parent_irq
;
gpiochip
->
irq_
chained_
parent
=
parent_irq
;
}
}
/* Set the parent IRQ for all affected IRQs */
/* Set the parent IRQ for all affected IRQs */
...
@@ -1486,8 +1486,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
...
@@ -1486,8 +1486,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
parent_irq
);
parent_irq
);
}
}
}
}
/**
* gpiochip_set_chained_irqchip() - connects a chained irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
* @irqchip: the irqchip to chain to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* chained irqchip
* @parent_handler: the parent interrupt handler for the accumulated IRQ
* coming out of the gpiochip. If the interrupt is nested rather than
* cascaded, pass NULL in this handler argument
*/
void
gpiochip_set_chained_irqchip
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
int
parent_irq
,
irq_flow_handler_t
parent_handler
)
{
gpiochip_set_cascaded_irqchip
(
gpiochip
,
irqchip
,
parent_irq
,
parent_handler
);
}
EXPORT_SYMBOL_GPL
(
gpiochip_set_chained_irqchip
);
EXPORT_SYMBOL_GPL
(
gpiochip_set_chained_irqchip
);
/**
* gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip nested handler to
* @irqchip: the irqchip to nest to the gpiochip
* @parent_irq: the irq number corresponding to the parent IRQ for this
* nested irqchip
*/
void
gpiochip_set_nested_irqchip
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
int
parent_irq
)
{
if
(
!
gpiochip
->
irq_nested
)
{
chip_err
(
gpiochip
,
"tried to nest a chained gpiochip
\n
"
);
return
;
}
gpiochip_set_cascaded_irqchip
(
gpiochip
,
irqchip
,
parent_irq
,
NULL
);
}
EXPORT_SYMBOL_GPL
(
gpiochip_set_nested_irqchip
);
/**
/**
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
* gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
* @d: the irqdomain used by this irqchip
* @d: the irqdomain used by this irqchip
...
@@ -1510,8 +1549,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
...
@@ -1510,8 +1549,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
*/
*/
irq_set_lockdep_class
(
irq
,
chip
->
lock_key
);
irq_set_lockdep_class
(
irq
,
chip
->
lock_key
);
irq_set_chip_and_handler
(
irq
,
chip
->
irqchip
,
chip
->
irq_handler
);
irq_set_chip_and_handler
(
irq
,
chip
->
irqchip
,
chip
->
irq_handler
);
/* Chips that
can sleep need nested thread handlers
*/
/* Chips that
use nested thread handlers have them marked
*/
if
(
chip
->
can_sleep
&&
!
chip
->
irq_not_thread
ed
)
if
(
chip
->
irq_nest
ed
)
irq_set_nested_thread
(
irq
,
1
);
irq_set_nested_thread
(
irq
,
1
);
irq_set_noprobe
(
irq
);
irq_set_noprobe
(
irq
);
...
@@ -1529,7 +1568,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
...
@@ -1529,7 +1568,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
{
{
struct
gpio_chip
*
chip
=
d
->
host_data
;
struct
gpio_chip
*
chip
=
d
->
host_data
;
if
(
chip
->
can_sleep
)
if
(
chip
->
irq_nested
)
irq_set_nested_thread
(
irq
,
0
);
irq_set_nested_thread
(
irq
,
0
);
irq_set_chip_and_handler
(
irq
,
NULL
,
NULL
);
irq_set_chip_and_handler
(
irq
,
NULL
,
NULL
);
irq_set_chip_data
(
irq
,
NULL
);
irq_set_chip_data
(
irq
,
NULL
);
...
@@ -1584,9 +1623,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
...
@@ -1584,9 +1623,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
acpi_gpiochip_free_interrupts
(
gpiochip
);
acpi_gpiochip_free_interrupts
(
gpiochip
);
if
(
gpiochip
->
irq_parent
)
{
if
(
gpiochip
->
irq_
chained_
parent
)
{
irq_set_chained_handler
(
gpiochip
->
irq_parent
,
NULL
);
irq_set_chained_handler
(
gpiochip
->
irq_
chained_
parent
,
NULL
);
irq_set_handler_data
(
gpiochip
->
irq_parent
,
NULL
);
irq_set_handler_data
(
gpiochip
->
irq_
chained_
parent
,
NULL
);
}
}
/* Remove all IRQ mappings and delete the domain */
/* Remove all IRQ mappings and delete the domain */
...
@@ -1610,7 +1649,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
...
@@ -1610,7 +1649,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
}
}
/**
/**
* gpiochip_irqchip_add() - adds an irqchip to a gpiochip
*
_
gpiochip_irqchip_add() - adds an irqchip to a gpiochip
* @gpiochip: the gpiochip to add the irqchip to
* @gpiochip: the gpiochip to add the irqchip to
* @irqchip: the irqchip to add to the gpiochip
* @irqchip: the irqchip to add to the gpiochip
* @first_irq: if not dynamically assigned, the base (first) IRQ to
* @first_irq: if not dynamically assigned, the base (first) IRQ to
...
@@ -1618,6 +1657,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
...
@@ -1618,6 +1657,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
* @handler: the irq handler to use (often a predefined irq core function)
* @handler: the irq handler to use (often a predefined irq core function)
* @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
* @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
* to have the core avoid setting up any default type in the hardware.
* to have the core avoid setting up any default type in the hardware.
* @nested: whether this is a nested irqchip calling handle_nested_irq()
* in its IRQ handler
* @lock_key: lockdep class
* @lock_key: lockdep class
*
*
* This function closely associates a certain irqchip with a certain
* This function closely associates a certain irqchip with a certain
...
@@ -1639,6 +1680,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
...
@@ -1639,6 +1680,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
unsigned
int
first_irq
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
irq_flow_handler_t
handler
,
unsigned
int
type
,
unsigned
int
type
,
bool
nested
,
struct
lock_class_key
*
lock_key
)
struct
lock_class_key
*
lock_key
)
{
{
struct
device_node
*
of_node
;
struct
device_node
*
of_node
;
...
@@ -1653,6 +1695,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
...
@@ -1653,6 +1695,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
pr_err
(
"missing gpiochip .dev parent pointer
\n
"
);
pr_err
(
"missing gpiochip .dev parent pointer
\n
"
);
return
-
EINVAL
;
return
-
EINVAL
;
}
}
gpiochip
->
irq_nested
=
nested
;
of_node
=
gpiochip
->
parent
->
of_node
;
of_node
=
gpiochip
->
parent
->
of_node
;
#ifdef CONFIG_OF_GPIO
#ifdef CONFIG_OF_GPIO
/*
/*
...
...
include/linux/gpio/driver.h
View file @
e1a0d869
...
@@ -82,8 +82,6 @@ enum single_ended_mode {
...
@@ -82,8 +82,6 @@ enum single_ended_mode {
* implies that if the chip supports IRQs, these IRQs need to be threaded
* implies that if the chip supports IRQs, these IRQs need to be threaded
* as the chip access may sleep when e.g. reading out the IRQ status
* as the chip access may sleep when e.g. reading out the IRQ status
* registers.
* registers.
* @irq_not_threaded: flag must be set if @can_sleep is set but the
* IRQs don't need to be threaded
* @read_reg: reader function for generic GPIO
* @read_reg: reader function for generic GPIO
* @write_reg: writer function for generic GPIO
* @write_reg: writer function for generic GPIO
* @pin2mask: some generic GPIO controllers work with the big-endian bits
* @pin2mask: some generic GPIO controllers work with the big-endian bits
...
@@ -109,8 +107,10 @@ enum single_ended_mode {
...
@@ -109,8 +107,10 @@ enum single_ended_mode {
* for GPIO IRQs, provided by GPIO driver
* for GPIO IRQs, provided by GPIO driver
* @irq_default_type: default IRQ triggering type applied during GPIO driver
* @irq_default_type: default IRQ triggering type applied during GPIO driver
* initialization, provided by GPIO driver
* initialization, provided by GPIO driver
* @irq_parent: GPIO IRQ chip parent/bank linux irq number,
* @irq_chained_parent: GPIO IRQ chip parent/bank linux irq number,
* provided by GPIO driver
* provided by GPIO driver for chained interrupt (not for nested
* interrupts).
* @irq_nested: True if set the interrupt handling is nested.
* @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
* @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
* bits set to one
* bits set to one
* @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
* @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
...
@@ -166,7 +166,6 @@ struct gpio_chip {
...
@@ -166,7 +166,6 @@ struct gpio_chip {
u16
ngpio
;
u16
ngpio
;
const
char
*
const
*
names
;
const
char
*
const
*
names
;
bool
can_sleep
;
bool
can_sleep
;
bool
irq_not_threaded
;
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
#if IS_ENABLED(CONFIG_GPIO_GENERIC)
unsigned
long
(
*
read_reg
)(
void
__iomem
*
reg
);
unsigned
long
(
*
read_reg
)(
void
__iomem
*
reg
);
...
@@ -192,7 +191,8 @@ struct gpio_chip {
...
@@ -192,7 +191,8 @@ struct gpio_chip {
unsigned
int
irq_base
;
unsigned
int
irq_base
;
irq_flow_handler_t
irq_handler
;
irq_flow_handler_t
irq_handler
;
unsigned
int
irq_default_type
;
unsigned
int
irq_default_type
;
int
irq_parent
;
int
irq_chained_parent
;
bool
irq_nested
;
bool
irq_need_valid_mask
;
bool
irq_need_valid_mask
;
unsigned
long
*
irq_valid_mask
;
unsigned
long
*
irq_valid_mask
;
struct
lock_class_key
*
lock_key
;
struct
lock_class_key
*
lock_key
;
...
@@ -270,24 +270,40 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
...
@@ -270,24 +270,40 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
int
parent_irq
,
int
parent_irq
,
irq_flow_handler_t
parent_handler
);
irq_flow_handler_t
parent_handler
);
void
gpiochip_set_nested_irqchip
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
int
parent_irq
);
int
_gpiochip_irqchip_add
(
struct
gpio_chip
*
gpiochip
,
int
_gpiochip_irqchip_add
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
irq_flow_handler_t
handler
,
unsigned
int
type
,
unsigned
int
type
,
bool
nested
,
struct
lock_class_key
*
lock_key
);
struct
lock_class_key
*
lock_key
);
/* FIXME: I assume threaded IRQchips do not have the lockdep problem */
static
inline
int
gpiochip_irqchip_add_nested
(
struct
gpio_chip
*
gpiochip
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
)
{
return
_gpiochip_irqchip_add
(
gpiochip
,
irqchip
,
first_irq
,
handler
,
type
,
true
,
NULL
);
}
#ifdef CONFIG_LOCKDEP
#ifdef CONFIG_LOCKDEP
#define gpiochip_irqchip_add(...) \
#define gpiochip_irqchip_add(...) \
( \
( \
({ \
({ \
static struct lock_class_key _key; \
static struct lock_class_key _key; \
_gpiochip_irqchip_add(__VA_ARGS__,
&_key);
\
_gpiochip_irqchip_add(__VA_ARGS__,
false, &_key);
\
}) \
}) \
)
)
#else
#else
#define gpiochip_irqchip_add(...) \
#define gpiochip_irqchip_add(...) \
_gpiochip_irqchip_add(__VA_ARGS__, NULL)
_gpiochip_irqchip_add(__VA_ARGS__,
false,
NULL)
#endif
#endif
#endif
/* CONFIG_GPIOLIB_IRQCHIP */
#endif
/* CONFIG_GPIOLIB_IRQCHIP */
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment