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
ccac12ac
Commit
ccac12ac
authored
Apr 07, 2021
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/for-5.13' into regmap-next
parents
78d88970
14e13b1c
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
113 additions
and
29 deletions
+113
-29
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-irq.c
+97
-29
include/linux/regmap.h
include/linux/regmap.h
+16
-0
No files found.
drivers/base/regmap/regmap-irq.c
View file @
ccac12ac
...
...
@@ -38,6 +38,7 @@ struct regmap_irq_chip_data {
unsigned
int
*
wake_buf
;
unsigned
int
*
type_buf
;
unsigned
int
*
type_buf_def
;
unsigned
int
**
virt_buf
;
unsigned
int
irq_reg_stride
;
unsigned
int
type_reg_stride
;
...
...
@@ -45,6 +46,27 @@ struct regmap_irq_chip_data {
bool
clear_status
:
1
;
};
static
int
sub_irq_reg
(
struct
regmap_irq_chip_data
*
data
,
unsigned
int
base_reg
,
int
i
)
{
const
struct
regmap_irq_chip
*
chip
=
data
->
chip
;
struct
regmap
*
map
=
data
->
map
;
struct
regmap_irq_sub_irq_map
*
subreg
;
unsigned
int
offset
;
int
reg
=
0
;
if
(
!
chip
->
sub_reg_offsets
||
!
chip
->
not_fixed_stride
)
{
/* Assume linear mapping */
reg
=
base_reg
+
(
i
*
map
->
reg_stride
*
data
->
irq_reg_stride
);
}
else
{
subreg
=
&
chip
->
sub_reg_offsets
[
i
];
offset
=
subreg
->
offset
[
0
];
reg
=
base_reg
+
offset
;
}
return
reg
;
}
static
inline
const
struct
regmap_irq
*
irq_to_regmap_irq
(
struct
regmap_irq_chip_data
*
data
,
int
irq
)
...
...
@@ -73,7 +95,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
{
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
struct
regmap
*
map
=
d
->
map
;
int
i
,
ret
;
int
i
,
j
,
ret
;
u32
reg
;
u32
unmask_offset
;
u32
val
;
...
...
@@ -87,8 +109,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if
(
d
->
clear_status
)
{
for
(
i
=
0
;
i
<
d
->
chip
->
num_regs
;
i
++
)
{
reg
=
d
->
chip
->
status_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
status_base
,
i
);
ret
=
regmap_read
(
map
,
reg
,
&
val
);
if
(
ret
)
...
...
@@ -108,8 +129,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if
(
!
d
->
chip
->
mask_base
)
continue
;
reg
=
d
->
chip
->
mask_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
mask_base
,
i
);
if
(
d
->
chip
->
mask_invert
)
{
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
mask_buf_def
[
i
],
~
d
->
mask_buf
[
i
]);
...
...
@@ -136,8 +156,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
dev_err
(
d
->
map
->
dev
,
"Failed to sync masks in %x
\n
"
,
reg
);
reg
=
d
->
chip
->
wake_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
wake_base
,
i
);
if
(
d
->
wake_buf
)
{
if
(
d
->
chip
->
wake_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
...
...
@@ -161,8 +180,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
* it'll be ignored in irq handler, then may introduce irq storm
*/
if
(
d
->
mask_buf
[
i
]
&&
(
d
->
chip
->
ack_base
||
d
->
chip
->
use_ack
))
{
reg
=
d
->
chip
->
ack_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
ack_base
,
i
);
/* some chips ack by write 0 */
if
(
d
->
chip
->
ack_invert
)
ret
=
regmap_write
(
map
,
reg
,
~
d
->
mask_buf
[
i
]);
...
...
@@ -187,8 +206,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
for
(
i
=
0
;
i
<
d
->
chip
->
num_type_reg
;
i
++
)
{
if
(
!
d
->
type_buf_def
[
i
])
continue
;
reg
=
d
->
chip
->
type_base
+
(
i
*
map
->
reg_stride
*
d
->
type_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
type_base
,
i
);
if
(
d
->
chip
->
type_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
~
d
->
type_buf
[
i
]);
...
...
@@ -201,6 +219,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
}
}
if
(
d
->
chip
->
num_virt_regs
)
{
for
(
i
=
0
;
i
<
d
->
chip
->
num_virt_regs
;
i
++
)
{
for
(
j
=
0
;
j
<
d
->
chip
->
num_regs
;
j
++
)
{
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
virt_reg_base
[
i
],
j
);
ret
=
regmap_write
(
map
,
reg
,
d
->
virt_buf
[
i
][
j
]);
if
(
ret
!=
0
)
dev_err
(
d
->
map
->
dev
,
"Failed to write virt 0x%x: %d
\n
"
,
reg
,
ret
);
}
}
}
if
(
d
->
chip
->
runtime_pm
)
pm_runtime_put
(
map
->
dev
);
...
...
@@ -301,6 +333,11 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
default:
return
-
EINVAL
;
}
if
(
d
->
chip
->
set_type_virt
)
return
d
->
chip
->
set_type_virt
(
d
->
virt_buf
,
type
,
data
->
hwirq
,
reg
);
return
0
;
}
...
...
@@ -352,8 +389,15 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
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
(
chip
->
not_fixed_stride
)
ret
=
regmap_read
(
map
,
chip
->
status_base
+
offset
,
&
data
->
status_buf
[
b
]);
else
ret
=
regmap_read
(
map
,
chip
->
status_base
+
offset
,
&
data
->
status_buf
[
offset
]);
if
(
ret
)
break
;
}
...
...
@@ -474,10 +518,9 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
}
else
{
for
(
i
=
0
;
i
<
data
->
chip
->
num_regs
;
i
++
)
{
ret
=
regmap_read
(
map
,
chip
->
status_base
+
(
i
*
map
->
reg_stride
*
data
->
irq_reg_stride
),
&
data
->
status_buf
[
i
]);
unsigned
int
reg
=
sub_irq_reg
(
data
,
data
->
chip
->
status_base
,
i
);
ret
=
regmap_read
(
map
,
reg
,
&
data
->
status_buf
[
i
]);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
...
...
@@ -499,8 +542,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
data
->
status_buf
[
i
]
&=
~
data
->
mask_buf
[
i
];
if
(
data
->
status_buf
[
i
]
&&
(
chip
->
ack_base
||
chip
->
use_ack
))
{
reg
=
chip
->
ack_base
+
(
i
*
map
->
reg_stride
*
data
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
data
,
data
->
chip
->
ack_base
,
i
);
if
(
chip
->
ack_invert
)
ret
=
regmap_write
(
map
,
reg
,
~
data
->
status_buf
[
i
]);
...
...
@@ -605,6 +648,12 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
return
-
EINVAL
;
}
if
(
chip
->
not_fixed_stride
)
{
for
(
i
=
0
;
i
<
chip
->
num_regs
;
i
++
)
if
(
chip
->
sub_reg_offsets
[
i
].
num_regs
!=
1
)
return
-
EINVAL
;
}
if
(
irq_base
)
{
irq_base
=
irq_alloc_descs
(
irq_base
,
0
,
chip
->
num_irqs
,
0
);
if
(
irq_base
<
0
)
{
...
...
@@ -662,6 +711,24 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
goto
err_alloc
;
}
if
(
chip
->
num_virt_regs
)
{
/*
* Create virt_buf[chip->num_extra_config_regs][chip->num_regs]
*/
d
->
virt_buf
=
kcalloc
(
chip
->
num_virt_regs
,
sizeof
(
*
d
->
virt_buf
),
GFP_KERNEL
);
if
(
!
d
->
virt_buf
)
goto
err_alloc
;
for
(
i
=
0
;
i
<
chip
->
num_virt_regs
;
i
++
)
{
d
->
virt_buf
[
i
]
=
kcalloc
(
chip
->
num_regs
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
if
(
!
d
->
virt_buf
[
i
])
goto
err_alloc
;
}
}
d
->
irq_chip
=
regmap_irq_chip
;
d
->
irq_chip
.
name
=
chip
->
name
;
d
->
irq
=
irq
;
...
...
@@ -700,8 +767,8 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
if
(
!
chip
->
mask_base
)
continue
;
reg
=
chip
->
mask_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
mask_base
,
i
);
if
(
chip
->
mask_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
mask_buf
[
i
],
~
d
->
mask_buf
[
i
]);
...
...
@@ -725,8 +792,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
continue
;
/* Ack masked but set interrupts */
reg
=
chip
->
status_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
status_base
,
i
);
ret
=
regmap_read
(
map
,
reg
,
&
d
->
status_buf
[
i
]);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to read IRQ status: %d
\n
"
,
...
...
@@ -735,8 +801,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
}
if
(
d
->
status_buf
[
i
]
&&
(
chip
->
ack_base
||
chip
->
use_ack
))
{
reg
=
chip
->
ack_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
ack_base
,
i
);
if
(
chip
->
ack_invert
)
ret
=
regmap_write
(
map
,
reg
,
~
(
d
->
status_buf
[
i
]
&
d
->
mask_buf
[
i
]));
...
...
@@ -765,8 +830,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
if
(
d
->
wake_buf
)
{
for
(
i
=
0
;
i
<
chip
->
num_regs
;
i
++
)
{
d
->
wake_buf
[
i
]
=
d
->
mask_buf_def
[
i
];
reg
=
chip
->
wake_base
+
(
i
*
map
->
reg_stride
*
d
->
irq_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
wake_base
,
i
);
if
(
chip
->
wake_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
...
...
@@ -786,8 +850,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
if
(
chip
->
num_type_reg
&&
!
chip
->
type_in_mask
)
{
for
(
i
=
0
;
i
<
chip
->
num_type_reg
;
++
i
)
{
reg
=
chip
->
type_base
+
(
i
*
map
->
reg_stride
*
d
->
type_reg_stride
);
reg
=
sub_irq_reg
(
d
,
d
->
chip
->
type_base
,
i
);
ret
=
regmap_read
(
map
,
reg
,
&
d
->
type_buf_def
[
i
]);
...
...
@@ -838,6 +901,11 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
kfree
(
d
->
mask_buf
);
kfree
(
d
->
status_buf
);
kfree
(
d
->
status_reg_buf
);
if
(
d
->
virt_buf
)
{
for
(
i
=
0
;
i
<
chip
->
num_virt_regs
;
i
++
)
kfree
(
d
->
virt_buf
[
i
]);
kfree
(
d
->
virt_buf
);
}
kfree
(
d
);
return
ret
;
}
...
...
include/linux/regmap.h
View file @
ccac12ac
...
...
@@ -1378,6 +1378,9 @@ struct regmap_irq_sub_irq_map {
* 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, ...
* When used with not_fixed_stride, each one-element array
* member contains offset calculated as address from each
* peripheral to first peripheral.
* @num_main_regs: Number of 'main status' irq registers for chips which have
* main_status set.
*
...
...
@@ -1390,6 +1393,7 @@ struct regmap_irq_sub_irq_map {
* Using zero value is possible with @use_ack bit.
* @wake_base: Base address for wake enables. If zero unsupported.
* @type_base: Base address for irq type. If zero unsupported.
* @virt_reg_base: Base addresses for extra config regs.
* @irq_reg_stride: Stride to use for chips where registers are not contiguous.
* @init_ack_masked: Ack all masked interrupts once during initalization.
* @mask_invert: Inverted mask register: cleared bits are masked out.
...
...
@@ -1404,6 +1408,9 @@ struct regmap_irq_sub_irq_map {
* @clear_on_unmask: For chips with interrupts cleared on read: read the status
* registers before unmasking interrupts to clear any bits
* set when they were masked.
* @not_fixed_stride: Used when chip peripherals are not laid out with fixed
* stride. Must be used with sub_reg_offsets containing the
* offsets to each peripheral.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
*
* @num_regs: Number of registers in each control bank.
...
...
@@ -1411,12 +1418,16 @@ struct regmap_irq_sub_irq_map {
* assigned based on the index in the array of the interrupt.
* @num_irqs: Number of descriptors.
* @num_type_reg: Number of type registers.
* @num_virt_regs: Number of non-standard irq configuration registers.
* If zero unsupported.
* @type_reg_stride: Stride to use for chips where type registers are not
* contiguous.
* @handle_pre_irq: Driver specific callback to handle interrupt from device
* before regmap_irq_handler process the interrupts.
* @handle_post_irq: Driver specific callback to handle interrupt from device
* after handling the interrupts in regmap_irq_handler().
* @set_type_virt: Driver specific callback to extend regmap_irq_set_type()
* and configure virt regs.
* @irq_drv_data: Driver specific IRQ data which is passed as parameter when
* driver specific pre/post interrupt handler is called.
*
...
...
@@ -1438,6 +1449,7 @@ struct regmap_irq_chip {
unsigned
int
ack_base
;
unsigned
int
wake_base
;
unsigned
int
type_base
;
unsigned
int
*
virt_reg_base
;
unsigned
int
irq_reg_stride
;
bool
mask_writeonly
:
1
;
bool
init_ack_masked
:
1
;
...
...
@@ -1450,6 +1462,7 @@ struct regmap_irq_chip {
bool
type_invert
:
1
;
bool
type_in_mask
:
1
;
bool
clear_on_unmask
:
1
;
bool
not_fixed_stride
:
1
;
int
num_regs
;
...
...
@@ -1457,10 +1470,13 @@ struct regmap_irq_chip {
int
num_irqs
;
int
num_type_reg
;
int
num_virt_regs
;
unsigned
int
type_reg_stride
;
int
(
*
handle_pre_irq
)(
void
*
irq_drv_data
);
int
(
*
handle_post_irq
)(
void
*
irq_drv_data
);
int
(
*
set_type_virt
)(
unsigned
int
**
buf
,
unsigned
int
type
,
unsigned
long
hwirq
,
int
reg
);
void
*
irq_drv_data
;
};
...
...
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