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
nexedi
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
Show 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,6 +174,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
}
}
/* 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
;
...
...
@@ -172,6 +191,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
dev_err
(
d
->
map
->
dev
,
"Failed to sync type in %x
\n
"
,
reg
);
}
}
if
(
d
->
chip
->
runtime_pm
)
pm_runtime_put
(
map
->
dev
);
...
...
@@ -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
,
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
,
.
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
,
.
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
,
.
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
,
.
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
,
.
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
,
.
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
,
.
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
,
.
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