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
Kirill Smelkov
linux
Commits
27b5ea2f
Commit
27b5ea2f
authored
Nov 11, 2020
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'devel' into for-next
parents
b72de3ff
b9bf9710
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
63 additions
and
332 deletions
+63
-332
Documentation/driver-api/gpio/driver.rst
Documentation/driver-api/gpio/driver.rst
+44
-23
drivers/gpio/TODO
drivers/gpio/TODO
+0
-49
drivers/gpio/gpio-104-idi-48.c
drivers/gpio/gpio-104-idi-48.c
+2
-4
drivers/gpio/gpio-stmpe.c
drivers/gpio/gpio-stmpe.c
+1
-9
drivers/gpio/gpiolib-cdev.c
drivers/gpio/gpiolib-cdev.c
+8
-16
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.c
+8
-160
include/linux/gpio/driver.h
include/linux/gpio/driver.h
+0
-71
No files found.
Documentation/driver-api/gpio/driver.rst
View file @
27b5ea2f
...
...
@@ -416,7 +416,8 @@ The preferred way to set up the helpers is to fill in the
struct gpio_irq_chip inside struct gpio_chip before adding the gpio_chip.
If you do this, the additional irq_chip will be set up by gpiolib at the
same time as setting up the rest of the GPIO functionality. The following
is a typical example of a cascaded interrupt handler using gpio_irq_chip:
is a typical example of a chained cascaded interrupt handler using
the gpio_irq_chip:
.. code-block:: c
...
...
@@ -452,7 +453,46 @@ is a typical example of a cascaded interrupt handler using gpio_irq_chip:
return devm_gpiochip_add_data(dev, &g->gc, g);
The helper support using hierarchical interrupt controllers as well.
The helper supports using threaded interrupts as well. Then you just request
the interrupt separately and go with it:
.. code-block:: c
/* Typical state container with dynamic irqchip */
struct my_gpio {
struct gpio_chip gc;
struct irq_chip irq;
};
int irq; /* from platform etc */
struct my_gpio *g;
struct gpio_irq_chip *girq;
/* Set up the irqchip dynamically */
g->irq.name = "my_gpio_irq";
g->irq.irq_ack = my_gpio_ack_irq;
g->irq.irq_mask = my_gpio_mask_irq;
g->irq.irq_unmask = my_gpio_unmask_irq;
g->irq.irq_set_type = my_gpio_set_irq_type;
ret = devm_request_threaded_irq(dev, irq, NULL,
irq_thread_fn, IRQF_ONESHOT, "my-chip", g);
if (ret < 0)
return ret;
/* Get a pointer to the gpio_irq_chip */
girq = &g->gc.irq;
girq->chip = &g->irq;
/* This will let us handle the parent IRQ in the driver */
girq->parent_handler = NULL;
girq->num_parents = 0;
girq->parents = NULL;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
return devm_gpiochip_add_data(dev, &g->gc, g);
The helper supports using hierarchical interrupt controllers as well.
In this case the typical set-up will look like this:
.. code-block:: c
...
...
@@ -493,32 +533,13 @@ the parent hardware irq from a child (i.e. this gpio chip) hardware irq.
As always it is good to look at examples in the kernel tree for advice
on how to find the required pieces.
The old way of adding irqchips to gpiochips after registration is also still
available but we try to move away from this:
- DEPRECATED: gpiochip_irqchip_add(): adds a chained cascaded irqchip to a
gpiochip. It will pass 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 to the container using container_of().
(See Documentation/driver-api/driver-model/design-patterns.rst)
- gpiochip_irqchip_add_nested(): adds a nested cascaded irqchip to a gpiochip,
as discussed above regarding different types of cascaded irqchips. The
cascaded irq has to be handled by a threaded interrupt handler.
Apart from that it works exactly like the chained irqchip.
- gpiochip_set_nested_irqchip(): sets up a nested cascaded 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 GPIO lines from the IRQ domain handled by
these helpers, we can set .irq.need_valid_mask of the gpiochip before
devm_gpiochip_add_data() or gpiochip_add_data() is called. This allocates an
.irq.valid_mask with as many bits set as there are GPIO lines in the chip, each
bit representing line 0..n-1. Drivers can exclude GPIO lines by clearing bits
from this mask. The mask
must be filled in before gpiochip_irqchip_add() or
gpiochip_irqchip_add_nested() is called
.
from this mask. The mask
can be filled in the init_valid_mask() callback
that is part of the struct gpio_irq_chip
.
To use the helpers please keep the following in mind:
...
...
drivers/gpio/TODO
View file @
27b5ea2f
...
...
@@ -129,58 +129,9 @@ GPIOLIB irqchip
The GPIOLIB irqchip is a helper irqchip for "simple cases" that should
try to cover any generic kind of irqchip cascaded from a GPIO.
- Convert all the GPIOLIB_IRQCHIP users to pass an irqchip template,
parent and flags before calling [devm_]gpiochip_add[_data]().
Currently we set up the irqchip after setting up the gpiochip
using gpiochip_irqchip_add() and gpiochip_set_[chained|nested]_irqchip().
This is too complex, so convert all users over to just set up
the irqchip before registering the gpio_chip, typical example:
/* Typical state container with dynamic irqchip */
struct my_gpio {
struct gpio_chip gc;
struct irq_chip irq;
};
int irq; /* from platform etc */
struct my_gpio *g;
struct gpio_irq_chip *girq;
/* Set up the irqchip dynamically */
g->irq.name = "my_gpio_irq";
g->irq.irq_ack = my_gpio_ack_irq;
g->irq.irq_mask = my_gpio_mask_irq;
g->irq.irq_unmask = my_gpio_unmask_irq;
g->irq.irq_set_type = my_gpio_set_irq_type;
/* Get a pointer to the gpio_irq_chip */
girq = &g->gc.irq;
girq->chip = &g->irq;
girq->parent_handler = ftgpio_gpio_irq_handler;
girq->num_parents = 1;
girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),
GFP_KERNEL);
if (!girq->parents)
return -ENOMEM;
girq->default_type = IRQ_TYPE_NONE;
girq->handler = handle_bad_irq;
girq->parents[0] = irq;
When this is done, we will delete the old APIs for instatiating
GPIOLIB_IRQCHIP and simplify the code.
- Look over and identify any remaining easily converted drivers and
dry-code conversions to gpiolib irqchip for maintainers to test
- Drop gpiochip_set_chained_irqchip() when all the chained irqchips
have been converted to the above infrastructure.
- Add more infrastructure to make it possible to also pass a threaded
irqchip in struct gpio_irq_chip.
- Drop gpiochip_irqchip_add_nested() when all the chained irqchips
have been converted to the above infrastructure.
Increase integration with pin control
...
...
drivers/gpio/gpio-104-idi-48.c
View file @
27b5ea2f
...
...
@@ -132,8 +132,7 @@ static void idi_48_irq_mask(struct irq_data *data)
outb
(
idi48gpio
->
cos_enb
,
idi48gpio
->
base
+
7
);
raw_spin_unlock_irqrestore
(
&
idi48gpio
->
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
idi48gpio
->
lock
,
flags
);
}
return
;
...
...
@@ -166,8 +165,7 @@ static void idi_48_irq_unmask(struct irq_data *data)
outb
(
idi48gpio
->
cos_enb
,
idi48gpio
->
base
+
7
);
raw_spin_unlock_irqrestore
(
&
idi48gpio
->
lock
,
flags
);
raw_spin_unlock_irqrestore
(
&
idi48gpio
->
lock
,
flags
);
}
return
;
...
...
drivers/gpio/gpio-stmpe.c
View file @
27b5ea2f
...
...
@@ -474,15 +474,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio
->
chip
.
parent
=
&
pdev
->
dev
;
stmpe_gpio
->
chip
.
of_node
=
np
;
stmpe_gpio
->
chip
.
base
=
-
1
;
/*
* REVISIT: this makes sure the valid mask gets allocated and
* filled in when adding the gpio_chip, but the rest of the
* gpio_irqchip is still filled in using the old method
* in gpiochip_irqchip_add_nested() so clean this up once we
* get the gpio_irqchip to initialize while adding the
* gpio_chip also for threaded irqchips.
*/
stmpe_gpio
->
chip
.
irq
.
init_valid_mask
=
stmpe_init_irq_valid_mask
;
if
(
IS_ENABLED
(
CONFIG_DEBUG_FS
))
stmpe_gpio
->
chip
.
dbg_show
=
stmpe_dbg_show
;
...
...
@@ -520,6 +511,7 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
girq
->
default_type
=
IRQ_TYPE_NONE
;
girq
->
handler
=
handle_simple_irq
;
girq
->
threaded
=
true
;
girq
->
init_valid_mask
=
stmpe_init_irq_valid_mask
;
}
ret
=
gpiochip_add_data
(
&
stmpe_gpio
->
chip
,
stmpe_gpio
);
...
...
drivers/gpio/gpiolib-cdev.c
View file @
27b5ea2f
...
...
@@ -1479,21 +1479,10 @@ static __poll_t lineevent_poll(struct file *file,
return
events
;
}
static
ssize_t
lineevent_get_size
(
void
)
{
#if defined(CONFIG_X86_64) && !defined(CONFIG_UML)
/* i386 has no padding after 'id' */
if
(
in_ia32_syscall
())
{
struct
compat_gpioeevent_data
{
compat_u64
timestamp
;
u32
id
;
};
return
sizeof
(
struct
compat_gpioeevent_data
);
}
#endif
return
sizeof
(
struct
gpioevent_data
);
}
struct
compat_gpioeevent_data
{
compat_u64
timestamp
;
u32
id
;
};
static
ssize_t
lineevent_read
(
struct
file
*
file
,
char
__user
*
buf
,
...
...
@@ -1515,7 +1504,10 @@ static ssize_t lineevent_read(struct file *file,
* actual sizeof() and pass this as an argument to copy_to_user() to
* drop unneeded bytes from the output.
*/
ge_size
=
lineevent_get_size
();
if
(
compat_need_64bit_alignment_fixup
())
ge_size
=
sizeof
(
struct
compat_gpioeevent_data
);
else
ge_size
=
sizeof
(
struct
gpioevent_data
);
if
(
count
<
ge_size
)
return
-
EINVAL
;
...
...
drivers/gpio/gpiolib.c
View file @
27b5ea2f
...
...
@@ -936,67 +936,6 @@ bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gc,
}
EXPORT_SYMBOL_GPL
(
gpiochip_irqchip_irq_valid
);
/**
* gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
* @gc: the gpiochip to set the irqchip chain to
* @parent_irq: the irq number corresponding to the parent IRQ for this
* cascaded 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
*/
static
void
gpiochip_set_cascaded_irqchip
(
struct
gpio_chip
*
gc
,
unsigned
int
parent_irq
,
irq_flow_handler_t
parent_handler
)
{
struct
gpio_irq_chip
*
girq
=
&
gc
->
irq
;
struct
device
*
dev
=
&
gc
->
gpiodev
->
dev
;
if
(
!
girq
->
domain
)
{
chip_err
(
gc
,
"called %s before setting up irqchip
\n
"
,
__func__
);
return
;
}
if
(
parent_handler
)
{
if
(
gc
->
can_sleep
)
{
chip_err
(
gc
,
"you cannot have chained interrupts on a chip that may sleep
\n
"
);
return
;
}
girq
->
parents
=
devm_kcalloc
(
dev
,
1
,
sizeof
(
*
girq
->
parents
),
GFP_KERNEL
);
if
(
!
girq
->
parents
)
{
chip_err
(
gc
,
"out of memory allocating parent IRQ
\n
"
);
return
;
}
girq
->
parents
[
0
]
=
parent_irq
;
girq
->
num_parents
=
1
;
/*
* The parent irqchip is already using the chip_data for this
* irqchip, so our callbacks simply use the handler_data.
*/
irq_set_chained_handler_and_data
(
parent_irq
,
parent_handler
,
gc
);
}
}
/**
* gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
* @gc: 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
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
parent_irq
)
{
gpiochip_set_cascaded_irqchip
(
gc
,
parent_irq
,
NULL
);
}
EXPORT_SYMBOL_GPL
(
gpiochip_set_nested_irqchip
);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
/**
...
...
@@ -1647,98 +1586,6 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
gpiochip_irqchip_free_valid_mask
(
gc
);
}
/**
* gpiochip_irqchip_add_key() - adds an irqchip to a gpiochip
* @gc: the gpiochip to add the irqchip to
* @irqchip: the irqchip to add to the gpiochip
* @first_irq: if not dynamically assigned, the base (first) IRQ to
* allocate gpiochip irqs from
* @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
* to have the core avoid setting up any default type in the hardware.
* @threaded: whether this irqchip uses a nested thread handler
* @lock_key: lockdep class for IRQ lock
* @request_key: lockdep class for IRQ request
*
* This function closely associates a certain irqchip with a certain
* gpiochip, providing an irq domain to translate the local IRQs to
* global irqs in the gpiolib core, and making sure that the gpiochip
* is passed as chip data to all related functions. Driver callbacks
* need to use gpiochip_get_data() to get their local state containers back
* from the gpiochip passed as chip data. An irqdomain will be stored
* in the gpiochip that shall be used by the driver to handle IRQ number
* translation. The gpiochip will need to be initialized and registered
* before calling this function.
*
* This function will handle two cell:ed simple IRQs and assumes all
* the pins on the gpiochip can generate a unique IRQ. Everything else
* need to be open coded.
*/
int
gpiochip_irqchip_add_key
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
,
bool
threaded
,
struct
lock_class_key
*
lock_key
,
struct
lock_class_key
*
request_key
)
{
struct
device_node
*
of_node
;
if
(
!
gc
||
!
irqchip
)
return
-
EINVAL
;
if
(
!
gc
->
parent
)
{
chip_err
(
gc
,
"missing gpiochip .dev parent pointer
\n
"
);
return
-
EINVAL
;
}
gc
->
irq
.
threaded
=
threaded
;
of_node
=
gc
->
parent
->
of_node
;
#ifdef CONFIG_OF_GPIO
/*
* If the gpiochip has an assigned OF node this takes precedence
* FIXME: get rid of this and use gc->parent->of_node
* everywhere
*/
if
(
gc
->
of_node
)
of_node
=
gc
->
of_node
;
#endif
/*
* Specifying a default trigger is a terrible idea if DT or ACPI is
* used to configure the interrupts, as you may end-up with
* conflicting triggers. Tell the user, and reset to NONE.
*/
if
(
WARN
(
of_node
&&
type
!=
IRQ_TYPE_NONE
,
"%pOF: Ignoring %d default trigger
\n
"
,
of_node
,
type
))
type
=
IRQ_TYPE_NONE
;
if
(
has_acpi_companion
(
gc
->
parent
)
&&
type
!=
IRQ_TYPE_NONE
)
{
acpi_handle_warn
(
ACPI_HANDLE
(
gc
->
parent
),
"Ignoring %d default trigger
\n
"
,
type
);
type
=
IRQ_TYPE_NONE
;
}
gc
->
irq
.
chip
=
irqchip
;
gc
->
irq
.
handler
=
handler
;
gc
->
irq
.
default_type
=
type
;
gc
->
to_irq
=
gpiochip_to_irq
;
gc
->
irq
.
lock_key
=
lock_key
;
gc
->
irq
.
request_key
=
request_key
;
gc
->
irq
.
domain
=
irq_domain_add_simple
(
of_node
,
gc
->
ngpio
,
first_irq
,
&
gpiochip_domain_ops
,
gc
);
if
(
!
gc
->
irq
.
domain
)
{
gc
->
irq
.
chip
=
NULL
;
return
-
EINVAL
;
}
gpiochip_set_irq_hooks
(
gc
);
acpi_gpiochip_request_interrupts
(
gc
);
return
0
;
}
EXPORT_SYMBOL_GPL
(
gpiochip_irqchip_add_key
);
/**
* gpiochip_irqchip_add_domain() - adds an irqdomain to a gpiochip
* @gc: the gpiochip to add the irqchip to
...
...
@@ -2268,8 +2115,8 @@ static int gpio_set_config(struct gpio_desc *desc, enum pin_config_param mode)
static
int
gpio_set_bias
(
struct
gpio_desc
*
desc
)
{
int
bias
=
0
;
int
ret
=
0
;
enum
pin_config_param
bias
;
int
ret
;
if
(
test_bit
(
FLAG_BIAS_DISABLE
,
&
desc
->
flags
))
bias
=
PIN_CONFIG_BIAS_DISABLE
;
...
...
@@ -2277,12 +2124,13 @@ static int gpio_set_bias(struct gpio_desc *desc)
bias
=
PIN_CONFIG_BIAS_PULL_UP
;
else
if
(
test_bit
(
FLAG_PULL_DOWN
,
&
desc
->
flags
))
bias
=
PIN_CONFIG_BIAS_PULL_DOWN
;
else
return
0
;
ret
=
gpio_set_config
(
desc
,
bias
);
if
(
ret
!=
-
ENOTSUPP
)
return
ret
;
if
(
bias
)
{
ret
=
gpio_set_config
(
desc
,
bias
);
if
(
ret
!=
-
ENOTSUPP
)
return
ret
;
}
return
0
;
}
...
...
include/linux/gpio/driver.h
View file @
27b5ea2f
...
...
@@ -621,83 +621,12 @@ int gpiochip_irq_domain_activate(struct irq_domain *domain,
void
gpiochip_irq_domain_deactivate
(
struct
irq_domain
*
domain
,
struct
irq_data
*
data
);
void
gpiochip_set_nested_irqchip
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
parent_irq
);
int
gpiochip_irqchip_add_key
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
,
bool
threaded
,
struct
lock_class_key
*
lock_key
,
struct
lock_class_key
*
request_key
);
bool
gpiochip_irqchip_irq_valid
(
const
struct
gpio_chip
*
gc
,
unsigned
int
offset
);
int
gpiochip_irqchip_add_domain
(
struct
gpio_chip
*
gc
,
struct
irq_domain
*
domain
);
#ifdef CONFIG_LOCKDEP
/*
* Lockdep requires that each irqchip instance be created with a
* unique key so as to avoid unnecessary warnings. This upfront
* boilerplate static inlines provides such a key for each
* unique instance.
*/
static
inline
int
gpiochip_irqchip_add
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
)
{
static
struct
lock_class_key
lock_key
;
static
struct
lock_class_key
request_key
;
return
gpiochip_irqchip_add_key
(
gc
,
irqchip
,
first_irq
,
handler
,
type
,
false
,
&
lock_key
,
&
request_key
);
}
static
inline
int
gpiochip_irqchip_add_nested
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
)
{
static
struct
lock_class_key
lock_key
;
static
struct
lock_class_key
request_key
;
return
gpiochip_irqchip_add_key
(
gc
,
irqchip
,
first_irq
,
handler
,
type
,
true
,
&
lock_key
,
&
request_key
);
}
#else
/* ! CONFIG_LOCKDEP */
static
inline
int
gpiochip_irqchip_add
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
)
{
return
gpiochip_irqchip_add_key
(
gc
,
irqchip
,
first_irq
,
handler
,
type
,
false
,
NULL
,
NULL
);
}
static
inline
int
gpiochip_irqchip_add_nested
(
struct
gpio_chip
*
gc
,
struct
irq_chip
*
irqchip
,
unsigned
int
first_irq
,
irq_flow_handler_t
handler
,
unsigned
int
type
)
{
return
gpiochip_irqchip_add_key
(
gc
,
irqchip
,
first_irq
,
handler
,
type
,
true
,
NULL
,
NULL
);
}
#endif
/* CONFIG_LOCKDEP */
int
gpiochip_generic_request
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
);
void
gpiochip_generic_free
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
);
int
gpiochip_generic_config
(
struct
gpio_chip
*
gc
,
unsigned
int
offset
,
...
...
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