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
66fb181d
Commit
66fb181d
authored
Jan 29, 2019
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/irq' into regmap-next
parents
31172d10
a2d21848
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
126 additions
and
4 deletions
+126
-4
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-irq.c
+95
-4
include/linux/regmap.h
include/linux/regmap.h
+31
-0
No files found.
drivers/base/regmap/regmap-irq.c
View file @
66fb181d
...
...
@@ -35,6 +35,7 @@ struct regmap_irq_chip_data {
int
wake_count
;
void
*
status_reg_buf
;
unsigned
int
*
main_status_buf
;
unsigned
int
*
status_buf
;
unsigned
int
*
mask_buf
;
unsigned
int
*
mask_buf_def
;
...
...
@@ -329,6 +330,33 @@ static const struct irq_chip regmap_irq_chip = {
.
irq_set_wake
=
regmap_irq_set_wake
,
};
static
inline
int
read_sub_irq_data
(
struct
regmap_irq_chip_data
*
data
,
unsigned
int
b
)
{
const
struct
regmap_irq_chip
*
chip
=
data
->
chip
;
struct
regmap
*
map
=
data
->
map
;
struct
regmap_irq_sub_irq_map
*
subreg
;
int
i
,
ret
=
0
;
if
(
!
chip
->
sub_reg_offsets
)
{
/* Assume linear mapping */
ret
=
regmap_read
(
map
,
chip
->
status_base
+
(
b
*
map
->
reg_stride
*
data
->
irq_reg_stride
),
&
data
->
status_buf
[
b
]);
}
else
{
subreg
=
&
chip
->
sub_reg_offsets
[
b
];
for
(
i
=
0
;
i
<
subreg
->
num_regs
;
i
++
)
{
unsigned
int
offset
=
subreg
->
offset
[
i
];
ret
=
regmap_read
(
map
,
chip
->
status_base
+
offset
,
&
data
->
status_buf
[
offset
]);
if
(
ret
)
break
;
}
}
return
ret
;
}
static
irqreturn_t
regmap_irq_thread
(
int
irq
,
void
*
d
)
{
struct
regmap_irq_chip_data
*
data
=
d
;
...
...
@@ -352,11 +380,65 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}
/*
* Read in the statuses, using a single bulk read if possible
* in order to reduce the I/O overheads.
* Read only registers with active IRQs if the chip has 'main status
* register'. Else read in the statuses, using a single bulk read if
* possible in order to reduce the I/O overheads.
*/
if
(
!
map
->
use_single_read
&&
map
->
reg_stride
==
1
&&
data
->
irq_reg_stride
==
1
)
{
if
(
chip
->
num_main_regs
)
{
unsigned
int
max_main_bits
;
unsigned
long
size
;
size
=
chip
->
num_regs
*
sizeof
(
unsigned
int
);
max_main_bits
=
(
chip
->
num_main_status_bits
)
?
chip
->
num_main_status_bits
:
chip
->
num_regs
;
/* Clear the status buf as we don't read all status regs */
memset
(
data
->
status_buf
,
0
,
size
);
/* We could support bulk read for main status registers
* but I don't expect to see devices with really many main
* status registers so let's only support single reads for the
* sake of simplicity. and add bulk reads only if needed
*/
for
(
i
=
0
;
i
<
chip
->
num_main_regs
;
i
++
)
{
ret
=
regmap_read
(
map
,
chip
->
main_status
+
(
i
*
map
->
reg_stride
*
data
->
irq_reg_stride
),
&
data
->
main_status_buf
[
i
]);
if
(
ret
)
{
dev_err
(
map
->
dev
,
"Failed to read IRQ status %d
\n
"
,
ret
);
goto
exit
;
}
}
/* Read sub registers with active IRQs */
for
(
i
=
0
;
i
<
chip
->
num_main_regs
;
i
++
)
{
unsigned
int
b
;
const
unsigned
long
mreg
=
data
->
main_status_buf
[
i
];
for_each_set_bit
(
b
,
&
mreg
,
map
->
format
.
val_bytes
*
8
)
{
if
(
i
*
map
->
format
.
val_bytes
*
8
+
b
>
max_main_bits
)
break
;
ret
=
read_sub_irq_data
(
data
,
b
);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to read IRQ status %d
\n
"
,
ret
);
if
(
chip
->
runtime_pm
)
pm_runtime_put
(
map
->
dev
);
goto
exit
;
}
}
}
}
else
if
(
!
map
->
use_single_read
&&
map
->
reg_stride
==
1
&&
data
->
irq_reg_stride
==
1
)
{
u8
*
buf8
=
data
->
status_reg_buf
;
u16
*
buf16
=
data
->
status_reg_buf
;
u32
*
buf32
=
data
->
status_reg_buf
;
...
...
@@ -521,6 +603,15 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if
(
!
d
)
return
-
ENOMEM
;
if
(
chip
->
num_main_regs
)
{
d
->
main_status_buf
=
kcalloc
(
chip
->
num_main_regs
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
if
(
!
d
->
main_status_buf
)
goto
err_alloc
;
}
d
->
status_buf
=
kcalloc
(
chip
->
num_regs
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
if
(
!
d
->
status_buf
)
...
...
include/linux/regmap.h
View file @
66fb181d
...
...
@@ -1131,11 +1131,37 @@ struct regmap_irq {
.reg_offset = (_id) / (_reg_bits), \
}
#define REGMAP_IRQ_MAIN_REG_OFFSET(arr) \
{ .num_regs = ARRAY_SIZE((arr)), .offset = &(arr)[0] }
struct
regmap_irq_sub_irq_map
{
unsigned
int
num_regs
;
unsigned
int
*
offset
;
};
/**
* struct regmap_irq_chip - Description of a generic regmap irq_chip.
*
* @name: Descriptive name for IRQ controller.
*
* @main_status: Base main status register address. For chips which have
* interrupts arranged in separate sub-irq blocks with own IRQ
* registers and which have a main IRQ registers indicating
* sub-irq blocks with unhandled interrupts. For such chips fill
* sub-irq register information in status_base, mask_base and
* ack_base.
* @num_main_status_bits: Should be given to chips where number of meaningfull
* main status bits differs from num_regs.
* @sub_reg_offsets: arrays of mappings from main register bits to sub irq
* registers. First item in array describes the registers
* for first main status bit. Second array for second bit etc.
* Offset is given as sub register status offset to
* status_base. Should contain num_regs arrays.
* Can be provided for chips with more complex mapping than
* 1.st bit to 1.st sub-reg, 2.nd bit to 2.nd sub-reg, ...
* @num_main_regs: Number of 'main status' irq registers for chips which have
* main_status set.
*
* @status_base: Base status register address.
* @mask_base: Base mask register address.
* @mask_writeonly: Base mask register is write only.
...
...
@@ -1181,6 +1207,11 @@ struct regmap_irq {
struct
regmap_irq_chip
{
const
char
*
name
;
unsigned
int
main_status
;
unsigned
int
num_main_status_bits
;
struct
regmap_irq_sub_irq_map
*
sub_reg_offsets
;
int
num_main_regs
;
unsigned
int
status_base
;
unsigned
int
mask_base
;
unsigned
int
unmask_base
;
...
...
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