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
58331d61
Commit
58331d61
authored
Dec 19, 2018
by
Mark Brown
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'regmap/topic/irq' into regmap-next
parents
9b268ebe
c82ea33e
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
198 additions
and
81 deletions
+198
-81
drivers/base/regmap/regmap-irq.c
drivers/base/regmap/regmap-irq.c
+99
-43
drivers/gpio/gpio-max77620.c
drivers/gpio/gpio-max77620.c
+64
-32
include/linux/regmap.h
include/linux/regmap.h
+35
-6
No files found.
drivers/base/regmap/regmap-irq.c
View file @
58331d61
...
...
@@ -44,6 +44,8 @@ struct regmap_irq_chip_data {
unsigned
int
irq_reg_stride
;
unsigned
int
type_reg_stride
;
bool
clear_status
:
1
;
};
static
inline
const
...
...
@@ -77,6 +79,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
int
i
,
ret
;
u32
reg
;
u32
unmask_offset
;
u32
val
;
if
(
d
->
chip
->
runtime_pm
)
{
ret
=
pm_runtime_get_sync
(
map
->
dev
);
...
...
@@ -85,6 +88,20 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
ret
);
}
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
);
ret
=
regmap_read
(
map
,
reg
,
&
val
);
if
(
ret
)
dev_err
(
d
->
map
->
dev
,
"Failed to clear the interrupt status bits
\n
"
);
}
d
->
clear_status
=
false
;
}
/*
* If there's been a change in the mask write it back to the
* hardware. We rely on the use of the regmap core cache to
...
...
@@ -157,20 +174,23 @@ 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
);
if
(
d
->
chip
->
type_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
~
d
->
type_buf
[
i
]);
else
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
d
->
type_buf
[
i
]);
if
(
ret
!=
0
)
dev_err
(
d
->
map
->
dev
,
"Failed to sync type in %x
\n
"
,
reg
);
/* Don't update the type bits if we're using mask bits for irq type. */
if
(
!
d
->
chip
->
type_in_mask
)
{
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
);
if
(
d
->
chip
->
type_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
~
d
->
type_buf
[
i
]);
else
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
d
->
type_buf
[
i
]);
if
(
ret
!=
0
)
dev_err
(
d
->
map
->
dev
,
"Failed to sync type in %x
\n
"
,
reg
);
}
}
if
(
d
->
chip
->
runtime_pm
)
...
...
@@ -194,8 +214,30 @@ static void regmap_irq_enable(struct irq_data *data)
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
struct
regmap
*
map
=
d
->
map
;
const
struct
regmap_irq
*
irq_data
=
irq_to_regmap_irq
(
d
,
data
->
hwirq
);
unsigned
int
mask
,
type
;
type
=
irq_data
->
type
.
type_falling_val
|
irq_data
->
type
.
type_rising_val
;
d
->
mask_buf
[
irq_data
->
reg_offset
/
map
->
reg_stride
]
&=
~
irq_data
->
mask
;
/*
* The type_in_mask flag means that the underlying hardware uses
* separate mask bits for rising and falling edge interrupts, but
* we want to make them into a single virtual interrupt with
* configurable edge.
*
* If the interrupt we're enabling defines the falling or rising
* masks then instead of using the regular mask bits for this
* interrupt, use the value previously written to the type buffer
* at the corresponding offset in regmap_irq_set_type().
*/
if
(
d
->
chip
->
type_in_mask
&&
type
)
mask
=
d
->
type_buf
[
irq_data
->
reg_offset
/
map
->
reg_stride
];
else
mask
=
irq_data
->
mask
;
if
(
d
->
chip
->
clear_on_unmask
)
d
->
clear_status
=
true
;
d
->
mask_buf
[
irq_data
->
reg_offset
/
map
->
reg_stride
]
&=
~
mask
;
}
static
void
regmap_irq_disable
(
struct
irq_data
*
data
)
...
...
@@ -212,27 +254,42 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
struct
regmap_irq_chip_data
*
d
=
irq_data_get_irq_chip_data
(
data
);
struct
regmap
*
map
=
d
->
map
;
const
struct
regmap_irq
*
irq_data
=
irq_to_regmap_irq
(
d
,
data
->
hwirq
);
int
reg
=
irq_data
->
type_reg_offset
/
map
->
reg_stride
;
int
reg
;
const
struct
regmap_irq_type
*
t
=
&
irq_data
->
type
;
if
(
!
(
irq_data
->
type_rising_mask
|
irq_data
->
type_falling_mask
)
)
return
0
;
if
(
(
t
->
types_supported
&
type
)
!=
type
)
return
-
ENOTSUPP
;
d
->
type_buf
[
reg
]
&=
~
(
irq_data
->
type_falling_mask
|
irq_data
->
type_rising_mask
);
reg
=
t
->
type_reg_offset
/
map
->
reg_stride
;
if
(
t
->
type_reg_mask
)
d
->
type_buf
[
reg
]
&=
~
t
->
type_reg_mask
;
else
d
->
type_buf
[
reg
]
&=
~
(
t
->
type_falling_val
|
t
->
type_rising_val
|
t
->
type_level_low_val
|
t
->
type_level_high_val
);
switch
(
type
)
{
case
IRQ_TYPE_EDGE_FALLING
:
d
->
type_buf
[
reg
]
|=
irq_data
->
type_falling_mask
;
d
->
type_buf
[
reg
]
|=
t
->
type_falling_val
;
break
;
case
IRQ_TYPE_EDGE_RISING
:
d
->
type_buf
[
reg
]
|=
irq_data
->
type_rising_mask
;
d
->
type_buf
[
reg
]
|=
t
->
type_rising_val
;
break
;
case
IRQ_TYPE_EDGE_BOTH
:
d
->
type_buf
[
reg
]
|=
(
irq_data
->
type_falling_mask
|
irq_data
->
type_rising_mask
);
d
->
type_buf
[
reg
]
|=
(
t
->
type_falling_val
|
t
->
type_rising_val
);
break
;
case
IRQ_TYPE_LEVEL_HIGH
:
d
->
type_buf
[
reg
]
|=
t
->
type_level_high_val
;
break
;
case
IRQ_TYPE_LEVEL_LOW
:
d
->
type_buf
[
reg
]
|=
t
->
type_level_low_val
;
break
;
default:
return
-
EINVAL
;
}
...
...
@@ -430,12 +487,16 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
struct
regmap_irq_chip_data
*
d
;
int
i
;
int
ret
=
-
ENOMEM
;
int
num_type_reg
;
u32
reg
;
u32
unmask_offset
;
if
(
chip
->
num_regs
<=
0
)
return
-
EINVAL
;
if
(
chip
->
clear_on_unmask
&&
(
chip
->
ack_base
||
chip
->
use_ack
))
return
-
EINVAL
;
for
(
i
=
0
;
i
<
chip
->
num_irqs
;
i
++
)
{
if
(
chip
->
irqs
[
i
].
reg_offset
%
map
->
reg_stride
)
return
-
EINVAL
;
...
...
@@ -479,13 +540,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
goto
err_alloc
;
}
if
(
chip
->
num_type_reg
)
{
d
->
type_buf_def
=
kcalloc
(
chip
->
num_type_reg
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
num_type_reg
=
chip
->
type_in_mask
?
chip
->
num_regs
:
chip
->
num_type_reg
;
if
(
num_type_reg
)
{
d
->
type_buf_def
=
kcalloc
(
num_type_reg
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
if
(
!
d
->
type_buf_def
)
goto
err_alloc
;
d
->
type_buf
=
kcalloc
(
chip
->
num_type_reg
,
sizeof
(
unsigned
int
),
d
->
type_buf
=
kcalloc
(
num_type_reg
,
sizeof
(
unsigned
int
),
GFP_KERNEL
);
if
(
!
d
->
type_buf
)
goto
err_alloc
;
...
...
@@ -600,27 +662,21 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
}
}
if
(
chip
->
num_type_reg
)
{
for
(
i
=
0
;
i
<
chip
->
num_irqs
;
i
++
)
{
reg
=
chip
->
irqs
[
i
].
type_reg_offset
/
map
->
reg_stride
;
d
->
type_buf_def
[
reg
]
|=
chip
->
irqs
[
i
].
type_rising_mask
|
chip
->
irqs
[
i
].
type_falling_mask
;
}
if
(
chip
->
num_type_reg
&&
!
chip
->
type_in_mask
)
{
for
(
i
=
0
;
i
<
chip
->
num_type_reg
;
++
i
)
{
if
(
!
d
->
type_buf_def
[
i
])
continue
;
reg
=
chip
->
type_base
+
(
i
*
map
->
reg_stride
*
d
->
type_reg_stride
);
if
(
chip
->
type_invert
)
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
0xFF
);
else
ret
=
regmap_irq_update_bits
(
d
,
reg
,
d
->
type_buf_def
[
i
],
0x0
);
if
(
ret
!=
0
)
{
dev_err
(
map
->
dev
,
"Failed to set type in 0x%x: %x
\n
"
,
ret
=
regmap_read
(
map
,
reg
,
&
d
->
type_buf_def
[
i
]);
if
(
d
->
chip
->
type_invert
)
d
->
type_buf_def
[
i
]
=
~
d
->
type_buf_def
[
i
];
if
(
ret
)
{
dev_err
(
map
->
dev
,
"Failed to get type defaults at 0x%x: %d
\n
"
,
reg
,
ret
);
goto
err_alloc
;
}
...
...
drivers/gpio/gpio-max77620.c
View file @
58331d61
...
...
@@ -25,60 +25,92 @@ struct max77620_gpio {
static
const
struct
regmap_irq
max77620_gpio_irqs
[]
=
{
[
0
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE0
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
0
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE0
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
0
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
1
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE1
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
1
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE1
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
1
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
2
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE2
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
2
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE2
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
2
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
3
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE3
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
3
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE3
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
3
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
4
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE4
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
4
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE4
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
4
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
5
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE5
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
5
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE5
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
5
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
6
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE6
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
6
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE6
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
6
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
[
7
]
=
{
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE7
,
.
type_rising_mask
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_mask
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
reg_offset
=
0
,
.
type_reg_offset
=
7
,
.
mask
=
MAX77620_IRQ_LVL2_GPIO_EDGE7
,
.
type
=
{
.
type_rising_val
=
MAX77620_CNFG_GPIO_INT_RISING
,
.
type_falling_val
=
MAX77620_CNFG_GPIO_INT_FALLING
,
.
type_reg_mask
=
MAX77620_CNFG_GPIO_INT_MASK
,
.
type_reg_offset
=
7
,
.
types_supported
=
IRQ_TYPE_EDGE_BOTH
,
},
},
};
...
...
include/linux/regmap.h
View file @
58331d61
...
...
@@ -1089,27 +1089,48 @@ int regmap_fields_read(struct regmap_field *field, unsigned int id,
int
regmap_fields_update_bits_base
(
struct
regmap_field
*
field
,
unsigned
int
id
,
unsigned
int
mask
,
unsigned
int
val
,
bool
*
change
,
bool
async
,
bool
force
);
/**
* struct regmap_irq_type - IRQ type definitions.
*
* @type_reg_offset: Offset register for the irq type setting.
* @type_rising_val: Register value to configure RISING type irq.
* @type_falling_val: Register value to configure FALLING type irq.
* @type_level_low_val: Register value to configure LEVEL_LOW type irq.
* @type_level_high_val: Register value to configure LEVEL_HIGH type irq.
* @types_supported: logical OR of IRQ_TYPE_* flags indicating supported types.
*/
struct
regmap_irq_type
{
unsigned
int
type_reg_offset
;
unsigned
int
type_reg_mask
;
unsigned
int
type_rising_val
;
unsigned
int
type_falling_val
;
unsigned
int
type_level_low_val
;
unsigned
int
type_level_high_val
;
unsigned
int
types_supported
;
};
/**
* struct regmap_irq - Description of an IRQ for the generic regmap irq_chip.
*
* @reg_offset: Offset of the status/mask register within the bank
* @mask: Mask used to flag/control the register.
* @type_reg_offset: Offset register for the irq type setting.
* @type_rising_mask: Mask bit to configure RISING type irq.
* @type_falling_mask: Mask bit to configure FALLING type irq.
* @type: IRQ trigger type setting details if supported.
*/
struct
regmap_irq
{
unsigned
int
reg_offset
;
unsigned
int
mask
;
unsigned
int
type_reg_offset
;
unsigned
int
type_rising_mask
;
unsigned
int
type_falling_mask
;
struct
regmap_irq_type
type
;
};
#define REGMAP_IRQ_REG(_irq, _off, _mask) \
[_irq] = { .reg_offset = (_off), .mask = (_mask) }
#define REGMAP_IRQ_REG_LINE(_id, _reg_bits) \
[_id] = { \
.mask = BIT((_id) % (_reg_bits)), \
.reg_offset = (_id) / (_reg_bits), \
}
/**
* struct regmap_irq_chip - Description of a generic regmap irq_chip.
*
...
...
@@ -1131,6 +1152,12 @@ struct regmap_irq {
* @ack_invert: Inverted ack register: cleared bits for ack.
* @wake_invert: Inverted wake register: cleared bits are wake enabled.
* @type_invert: Invert the type flags.
* @type_in_mask: Use the mask registers for controlling irq type. For
* interrupts defining type_rising/falling_mask use mask_base
* for edge configuration and never update bits in type_base.
* @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.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
*
* @num_regs: Number of registers in each control bank.
...
...
@@ -1169,6 +1196,8 @@ struct regmap_irq_chip {
bool
wake_invert
:
1
;
bool
runtime_pm
:
1
;
bool
type_invert
:
1
;
bool
type_in_mask
:
1
;
bool
clear_on_unmask
:
1
;
int
num_regs
;
...
...
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