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
ccf1e9e1
Commit
ccf1e9e1
authored
Sep 23, 2016
by
Linus Walleij
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gpio-irq-validmask' into devel
parents
31ebe86d
79b804cb
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
75 additions
and
3 deletions
+75
-3
Documentation/gpio/driver.txt
Documentation/gpio/driver.txt
+6
-0
drivers/gpio/gpiolib.c
drivers/gpio/gpiolib.c
+63
-3
include/linux/gpio/driver.h
include/linux/gpio/driver.h
+6
-0
No files found.
Documentation/gpio/driver.txt
View file @
ccf1e9e1
...
...
@@ -262,6 +262,12 @@ symbol:
to the container using container_of().
(See Documentation/driver-model/design-patterns.txt)
If there is a need to exclude certain GPIOs from the IRQ domain, one can
set .irq_need_valid_mask of the gpiochip before gpiochip_add_data() is
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
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
...
...
drivers/gpio/gpiolib.c
View file @
ccf1e9e1
...
...
@@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices);
static
void
gpiochip_free_hogs
(
struct
gpio_chip
*
chip
);
static
void
gpiochip_irqchip_remove
(
struct
gpio_chip
*
gpiochip
);
static
int
gpiochip_irqchip_init_valid_mask
(
struct
gpio_chip
*
gpiochip
);
static
void
gpiochip_irqchip_free_valid_mask
(
struct
gpio_chip
*
gpiochip
);
static
bool
gpiolib_initialized
;
...
...
@@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
if
(
status
)
goto
err_remove_from_list
;
status
=
gpiochip_irqchip_init_valid_mask
(
chip
);
if
(
status
)
goto
err_remove_from_list
;
status
=
of_gpiochip_add
(
chip
);
if
(
status
)
goto
err_remove_chip
;
...
...
@@ -1192,6 +1198,7 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
acpi_gpiochip_remove
(
chip
);
gpiochip_free_hogs
(
chip
);
of_gpiochip_remove
(
chip
);
gpiochip_irqchip_free_valid_mask
(
chip
);
err_remove_from_list:
spin_lock_irqsave
(
&
gpio_lock
,
flags
);
list_del
(
&
gdev
->
list
);
...
...
@@ -1401,6 +1408,40 @@ static struct gpio_chip *find_chip_by_name(const char *name)
* The following is irqchip helper code for gpiochips.
*/
static
int
gpiochip_irqchip_init_valid_mask
(
struct
gpio_chip
*
gpiochip
)
{
int
i
;
if
(
!
gpiochip
->
irq_need_valid_mask
)
return
0
;
gpiochip
->
irq_valid_mask
=
kcalloc
(
BITS_TO_LONGS
(
gpiochip
->
ngpio
),
sizeof
(
long
),
GFP_KERNEL
);
if
(
!
gpiochip
->
irq_valid_mask
)
return
-
ENOMEM
;
/* Assume by default all GPIOs are valid */
for
(
i
=
0
;
i
<
gpiochip
->
ngpio
;
i
++
)
set_bit
(
i
,
gpiochip
->
irq_valid_mask
);
return
0
;
}
static
void
gpiochip_irqchip_free_valid_mask
(
struct
gpio_chip
*
gpiochip
)
{
kfree
(
gpiochip
->
irq_valid_mask
);
gpiochip
->
irq_valid_mask
=
NULL
;
}
static
bool
gpiochip_irqchip_irq_valid
(
const
struct
gpio_chip
*
gpiochip
,
unsigned
int
offset
)
{
/* No mask means all valid */
if
(
likely
(
!
gpiochip
->
irq_valid_mask
))
return
true
;
return
test_bit
(
offset
,
gpiochip
->
irq_valid_mask
);
}
/**
* gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
* @gpiochip: the gpiochip to set the irqchip chain to
...
...
@@ -1442,9 +1483,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
}
/* Set the parent IRQ for all affected IRQs */
for
(
offset
=
0
;
offset
<
gpiochip
->
ngpio
;
offset
++
)
for
(
offset
=
0
;
offset
<
gpiochip
->
ngpio
;
offset
++
)
{
if
(
!
gpiochip_irqchip_irq_valid
(
gpiochip
,
offset
))
continue
;
irq_set_parent
(
irq_find_mapping
(
gpiochip
->
irqdomain
,
offset
),
parent_irq
);
}
}
EXPORT_SYMBOL_GPL
(
gpiochip_set_chained_irqchip
);
...
...
@@ -1551,9 +1595,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
/* Remove all IRQ mappings and delete the domain */
if
(
gpiochip
->
irqdomain
)
{
for
(
offset
=
0
;
offset
<
gpiochip
->
ngpio
;
offset
++
)
for
(
offset
=
0
;
offset
<
gpiochip
->
ngpio
;
offset
++
)
{
if
(
!
gpiochip_irqchip_irq_valid
(
gpiochip
,
offset
))
continue
;
irq_dispose_mapping
(
irq_find_mapping
(
gpiochip
->
irqdomain
,
offset
));
}
irq_domain_remove
(
gpiochip
->
irqdomain
);
}
...
...
@@ -1562,6 +1609,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
gpiochip
->
irqchip
->
irq_release_resources
=
NULL
;
gpiochip
->
irqchip
=
NULL
;
}
gpiochip_irqchip_free_valid_mask
(
gpiochip
);
}
/**
...
...
@@ -1597,6 +1646,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
struct
lock_class_key
*
lock_key
)
{
struct
device_node
*
of_node
;
bool
irq_base_set
=
false
;
unsigned
int
offset
;
unsigned
irq_base
=
0
;
...
...
@@ -1646,13 +1696,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
* necessary to allocate descriptors for all IRQs.
*/
for
(
offset
=
0
;
offset
<
gpiochip
->
ngpio
;
offset
++
)
{
if
(
!
gpiochip_irqchip_irq_valid
(
gpiochip
,
offset
))
continue
;
irq_base
=
irq_create_mapping
(
gpiochip
->
irqdomain
,
offset
);
if
(
offset
==
0
)
if
(
!
irq_base_set
)
{
/*
* Store the base into the gpiochip to be used when
* unmapping the irqs.
*/
gpiochip
->
irq_base
=
irq_base
;
irq_base_set
=
true
;
}
}
acpi_gpiochip_request_interrupts
(
gpiochip
);
...
...
@@ -1664,6 +1718,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add);
#else
/* CONFIG_GPIOLIB_IRQCHIP */
static
void
gpiochip_irqchip_remove
(
struct
gpio_chip
*
gpiochip
)
{}
static
inline
int
gpiochip_irqchip_init_valid_mask
(
struct
gpio_chip
*
gpiochip
)
{
return
0
;
}
static
inline
void
gpiochip_irqchip_free_valid_mask
(
struct
gpio_chip
*
gpiochip
)
{
}
#endif
/* CONFIG_GPIOLIB_IRQCHIP */
...
...
include/linux/gpio/driver.h
View file @
ccf1e9e1
...
...
@@ -112,6 +112,10 @@ enum single_ended_mode {
* initialization, provided by GPIO driver
* @irq_parent: GPIO IRQ chip parent/bank linux irq number,
* provided by GPIO driver
* @irq_need_valid_mask: If set core allocates @irq_valid_mask with all
* bits set to one
* @irq_valid_mask: If not %NULL holds bitmask of GPIOs which are valid to
* be included in IRQ domain of the chip
* @lock_key: per GPIO IRQ chip lockdep class
*
* A gpio_chip can help platforms abstract various sources of GPIOs so
...
...
@@ -190,6 +194,8 @@ struct gpio_chip {
irq_flow_handler_t
irq_handler
;
unsigned
int
irq_default_type
;
int
irq_parent
;
bool
irq_need_valid_mask
;
unsigned
long
*
irq_valid_mask
;
struct
lock_class_key
*
lock_key
;
#endif
...
...
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