regmap: Updates for v5.20
The big thing this release is a big cleanup of the interrupt code from Aidan MacDonald, plus a few new API updates: - Rework of the interrupt code, making it much simpler and easier to extend. - Support for device specific update bits operations with devices that otherwise use bitstream interfaces. - Support for bit operations on fields as well as whole registers. -----BEGIN PGP SIGNATURE----- iQEzBAABCgAdFiEEreZoqmdXGLWf4p/qJNaLcl1Uh9AFAmLnvh0ACgkQJNaLcl1U h9DlbQf/RELySinbi6WTIthuigJTfQq7xFIrR3LsEIrLWTuKsb+mBtxPkv0sAUF4 lmTtxmixtCAp3z2xWLXTw99dxDcII49YPmR1TzKZ9vBsK0vkAof6t7BQyhFoICpy cbGdw4Mqi3qOHHeDH3obNbYhz1IwWL47Q0eASkNyaHrrnxykIyjeJ0TTURoVWJpX FEzGwvFtH4+5w3yc0aE+WvjzHXgPj/xAsyE835TF9jv8cW9a2/KAYPLo7gW+icaz Qx4JrmwMBuxzJEuaRvx2dxtasDCZKPFyod1cKS2gTpF4OnNKHocDwC3cSoGDLztr BRljUV3VfWzOB8DdeAaB5XQM8LJeiw== =talc -----END PGP SIGNATURE----- Merge tag 'regmap-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap Pull regmap updates from Mark Brown: "The big thing this release is a big cleanup of the interrupt code from Aidan MacDonald, plus a few new API updates: - Rework of the interrupt code, making it much simpler and easier to extend - Support for device specific update bits operations with devices that otherwise use bitstream interfaces - Support for bit operations on fields as well as whole registers" * tag 'regmap-v5.20' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regmap: regmap: permit to set reg_update_bits with bulk implementation regmap: add WARN_ONCE when invalid mask is provided to regmap_field_init() regmap-irq: Fix bug in regmap_irq_get_irq_reg_linear() regmap: cache: Add extra parameter check in regcache_init regmap-irq: Deprecate the not_fixed_stride flag regmap-irq: Add get_irq_reg() callback regmap-irq: Fix inverted handling of unmask registers regmap-irq: Deprecate type registers and virtual registers regmap-irq: Introduce config registers for irq types regmap-irq: Refactor checks for status bulk read support regmap-irq: Remove mask_writeonly and regmap_irq_update_bits() regmap-irq: Remove inappropriate uses of regmap_irq_update_bits() regmap-irq: Remove an unnecessary restriction on type_in_mask regmap-irq: Cleanup sizeof(...) use in memory allocation regmap-irq: Remove unused type_reg_stride field regmap-irq: Convert bool bitfields to unsigned int regmap: Don't warn about cache only mode for devices with no cache regmap: provide regmap_field helpers for simple bit operations regmap: cache: Fix syntax errors in comments
This commit is contained in:
commit
2e7a95156d
@ -133,6 +133,12 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (config->num_reg_defaults && !config->reg_defaults) {
|
||||
dev_err(map->dev,
|
||||
"Register defaults number are set without the reg!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0; i < config->num_reg_defaults; i++)
|
||||
if (config->reg_defaults[i].reg % map->reg_stride)
|
||||
return -EINVAL;
|
||||
@ -495,7 +501,8 @@ EXPORT_SYMBOL_GPL(regcache_drop_region);
|
||||
void regcache_cache_only(struct regmap *map, bool enable)
|
||||
{
|
||||
map->lock(map->lock_arg);
|
||||
WARN_ON(map->cache_bypass && enable);
|
||||
WARN_ON(map->cache_type != REGCACHE_NONE &&
|
||||
map->cache_bypass && enable);
|
||||
map->cache_only = enable;
|
||||
trace_regmap_cache_only(map, enable);
|
||||
map->unlock(map->lock_arg);
|
||||
@ -531,7 +538,7 @@ EXPORT_SYMBOL_GPL(regcache_mark_dirty);
|
||||
* @enable: flag if changes should not be written to the cache
|
||||
*
|
||||
* When a register map is marked with the cache bypass option, writes
|
||||
* to the register map API will only update the hardware and not the
|
||||
* to the register map API will only update the hardware and not
|
||||
* the cache directly. This is useful when syncing the cache back to
|
||||
* the hardware.
|
||||
*/
|
||||
|
@ -30,6 +30,9 @@ struct regmap_irq_chip_data {
|
||||
int irq;
|
||||
int wake_count;
|
||||
|
||||
unsigned int mask_base;
|
||||
unsigned int unmask_base;
|
||||
|
||||
void *status_reg_buf;
|
||||
unsigned int *main_status_buf;
|
||||
unsigned int *status_buf;
|
||||
@ -39,34 +42,16 @@ struct regmap_irq_chip_data {
|
||||
unsigned int *type_buf;
|
||||
unsigned int *type_buf_def;
|
||||
unsigned int **virt_buf;
|
||||
unsigned int **config_buf;
|
||||
|
||||
unsigned int irq_reg_stride;
|
||||
unsigned int type_reg_stride;
|
||||
|
||||
bool clear_status:1;
|
||||
unsigned int (*get_irq_reg)(struct regmap_irq_chip_data *data,
|
||||
unsigned int base, int index);
|
||||
|
||||
unsigned int 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)
|
||||
@ -74,6 +59,20 @@ struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
|
||||
return &data->chip->irqs[irq];
|
||||
}
|
||||
|
||||
static bool regmap_irq_can_bulk_read_status(struct regmap_irq_chip_data *data)
|
||||
{
|
||||
struct regmap *map = data->map;
|
||||
|
||||
/*
|
||||
* While possible that a user-defined ->get_irq_reg() callback might
|
||||
* be linear enough to support bulk reads, most of the time it won't.
|
||||
* Therefore only allow them if the default callback is being used.
|
||||
*/
|
||||
return data->irq_reg_stride == 1 && map->reg_stride == 1 &&
|
||||
data->get_irq_reg == regmap_irq_get_irq_reg_linear &&
|
||||
!map->use_single_read;
|
||||
}
|
||||
|
||||
static void regmap_irq_lock(struct irq_data *data)
|
||||
{
|
||||
struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
|
||||
@ -81,23 +80,12 @@ static void regmap_irq_lock(struct irq_data *data)
|
||||
mutex_lock(&d->lock);
|
||||
}
|
||||
|
||||
static int regmap_irq_update_bits(struct regmap_irq_chip_data *d,
|
||||
unsigned int reg, unsigned int mask,
|
||||
unsigned int val)
|
||||
{
|
||||
if (d->chip->mask_writeonly)
|
||||
return regmap_write_bits(d->map, reg, mask, val);
|
||||
else
|
||||
return regmap_update_bits(d->map, reg, mask, val);
|
||||
}
|
||||
|
||||
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, j, ret;
|
||||
u32 reg;
|
||||
u32 unmask_offset;
|
||||
u32 val;
|
||||
|
||||
if (d->chip->runtime_pm) {
|
||||
@ -109,7 +97,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 = sub_irq_reg(d, d->chip->status_base, i);
|
||||
reg = d->get_irq_reg(d, d->chip->status_base, i);
|
||||
|
||||
ret = regmap_read(map, reg, &val);
|
||||
if (ret)
|
||||
@ -126,44 +114,32 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
||||
* suppress pointless writes.
|
||||
*/
|
||||
for (i = 0; i < d->chip->num_regs; i++) {
|
||||
if (!d->chip->mask_base)
|
||||
continue;
|
||||
|
||||
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]);
|
||||
} else if (d->chip->unmask_base) {
|
||||
/* set mask with mask_base register */
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
d->mask_buf_def[i], ~d->mask_buf[i]);
|
||||
if (ret < 0)
|
||||
dev_err(d->map->dev,
|
||||
"Failed to sync unmasks in %x\n",
|
||||
if (d->mask_base) {
|
||||
reg = d->get_irq_reg(d, d->mask_base, i);
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i], d->mask_buf[i]);
|
||||
if (ret)
|
||||
dev_err(d->map->dev, "Failed to sync masks in %x\n",
|
||||
reg);
|
||||
unmask_offset = d->chip->unmask_base -
|
||||
d->chip->mask_base;
|
||||
/* clear mask with unmask_base register */
|
||||
ret = regmap_irq_update_bits(d,
|
||||
reg + unmask_offset,
|
||||
d->mask_buf_def[i],
|
||||
d->mask_buf[i]);
|
||||
} else {
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
d->mask_buf_def[i], d->mask_buf[i]);
|
||||
}
|
||||
if (ret != 0)
|
||||
dev_err(d->map->dev, "Failed to sync masks in %x\n",
|
||||
reg);
|
||||
|
||||
reg = sub_irq_reg(d, d->chip->wake_base, i);
|
||||
if (d->unmask_base) {
|
||||
reg = d->get_irq_reg(d, d->unmask_base, i);
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i], ~d->mask_buf[i]);
|
||||
if (ret)
|
||||
dev_err(d->map->dev, "Failed to sync masks in %x\n",
|
||||
reg);
|
||||
}
|
||||
|
||||
reg = d->get_irq_reg(d, d->chip->wake_base, i);
|
||||
if (d->wake_buf) {
|
||||
if (d->chip->wake_invert)
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i],
|
||||
~d->wake_buf[i]);
|
||||
else
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i],
|
||||
d->wake_buf[i]);
|
||||
if (ret != 0)
|
||||
@ -180,7 +156,7 @@ 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 = sub_irq_reg(d, d->chip->ack_base, i);
|
||||
reg = d->get_irq_reg(d, d->chip->ack_base, i);
|
||||
|
||||
/* some chips ack by write 0 */
|
||||
if (d->chip->ack_invert)
|
||||
@ -204,12 +180,12 @@ 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 = sub_irq_reg(d, d->chip->type_base, i);
|
||||
reg = d->get_irq_reg(d, d->chip->type_base, i);
|
||||
if (d->chip->type_invert)
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->type_buf_def[i], ~d->type_buf[i]);
|
||||
else
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, 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",
|
||||
@ -220,8 +196,8 @@ 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);
|
||||
reg = d->get_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,
|
||||
@ -231,6 +207,17 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < d->chip->num_config_bases; i++) {
|
||||
for (j = 0; j < d->chip->num_config_regs; j++) {
|
||||
reg = d->get_irq_reg(d, d->chip->config_base[i], j);
|
||||
ret = regmap_write(map, reg, d->config_buf[i][j]);
|
||||
if (ret)
|
||||
dev_err(d->map->dev,
|
||||
"Failed to write config %x: %d\n",
|
||||
reg, ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (d->chip->runtime_pm)
|
||||
pm_runtime_put(map->dev);
|
||||
|
||||
@ -253,22 +240,19 @@ static void regmap_irq_enable(struct irq_data *data)
|
||||
struct regmap *map = d->map;
|
||||
const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
|
||||
unsigned int reg = irq_data->reg_offset / map->reg_stride;
|
||||
unsigned int mask, type;
|
||||
|
||||
type = irq_data->type.type_falling_val | irq_data->type.type_rising_val;
|
||||
unsigned int 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.
|
||||
* separate mask bits for each interrupt trigger type, but we want
|
||||
* to have a single logical interrupt with a configurable type.
|
||||
*
|
||||
* 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 the interrupt we're enabling defines any supported types
|
||||
* 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)
|
||||
if (d->chip->type_in_mask && irq_data->type.types_supported)
|
||||
mask = d->type_buf[reg] & irq_data->mask;
|
||||
else
|
||||
mask = irq_data->mask;
|
||||
@ -293,7 +277,7 @@ 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;
|
||||
int reg, ret;
|
||||
const struct regmap_irq_type *t = &irq_data->type;
|
||||
|
||||
if ((t->types_supported & type) != type)
|
||||
@ -333,9 +317,19 @@ static int regmap_irq_set_type(struct irq_data *data, unsigned int type)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (d->chip->set_type_virt)
|
||||
return d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
|
||||
reg);
|
||||
if (d->chip->set_type_virt) {
|
||||
ret = d->chip->set_type_virt(d->virt_buf, type, data->hwirq,
|
||||
reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (d->chip->set_type_config) {
|
||||
ret = d->chip->set_type_config(d->config_buf, type,
|
||||
irq_data, reg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -376,14 +370,17 @@ static inline int read_sub_irq_data(struct regmap_irq_chip_data *data,
|
||||
const struct regmap_irq_chip *chip = data->chip;
|
||||
struct regmap *map = data->map;
|
||||
struct regmap_irq_sub_irq_map *subreg;
|
||||
unsigned int reg;
|
||||
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]);
|
||||
reg = data->get_irq_reg(data, chip->status_base, b);
|
||||
ret = regmap_read(map, reg, &data->status_buf[b]);
|
||||
} else {
|
||||
/*
|
||||
* Note we can't use ->get_irq_reg() here because the offsets
|
||||
* in 'subreg' are *not* interchangeable with indices.
|
||||
*/
|
||||
subreg = &chip->sub_reg_offsets[b];
|
||||
for (i = 0; i < subreg->num_regs; i++) {
|
||||
unsigned int offset = subreg->offset[i];
|
||||
@ -449,10 +446,18 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
* 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]);
|
||||
/*
|
||||
* For not_fixed_stride, don't use ->get_irq_reg().
|
||||
* It would produce an incorrect result.
|
||||
*/
|
||||
if (data->chip->not_fixed_stride)
|
||||
reg = chip->main_status +
|
||||
i * map->reg_stride * data->irq_reg_stride;
|
||||
else
|
||||
reg = data->get_irq_reg(data,
|
||||
chip->main_status, i);
|
||||
|
||||
ret = regmap_read(map, reg, &data->main_status_buf[i]);
|
||||
if (ret) {
|
||||
dev_err(map->dev,
|
||||
"Failed to read IRQ status %d\n",
|
||||
@ -481,8 +486,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
}
|
||||
|
||||
}
|
||||
} else if (!map->use_single_read && map->reg_stride == 1 &&
|
||||
data->irq_reg_stride == 1) {
|
||||
} else if (regmap_irq_can_bulk_read_status(data)) {
|
||||
|
||||
u8 *buf8 = data->status_reg_buf;
|
||||
u16 *buf16 = data->status_reg_buf;
|
||||
@ -518,7 +522,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
|
||||
|
||||
} else {
|
||||
for (i = 0; i < data->chip->num_regs; i++) {
|
||||
unsigned int reg = sub_irq_reg(data,
|
||||
unsigned int reg = data->get_irq_reg(data,
|
||||
data->chip->status_base, i);
|
||||
ret = regmap_read(map, reg, &data->status_buf[i]);
|
||||
|
||||
@ -546,7 +550,7 @@ 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 = sub_irq_reg(data, data->chip->ack_base, i);
|
||||
reg = data->get_irq_reg(data, data->chip->ack_base, i);
|
||||
|
||||
if (chip->ack_invert)
|
||||
ret = regmap_write(map, reg,
|
||||
@ -606,6 +610,91 @@ static const struct irq_domain_ops regmap_domain_ops = {
|
||||
.xlate = irq_domain_xlate_onetwocell,
|
||||
};
|
||||
|
||||
/**
|
||||
* regmap_irq_get_irq_reg_linear() - Linear IRQ register mapping callback.
|
||||
* @data: Data for the &struct regmap_irq_chip
|
||||
* @base: Base register
|
||||
* @index: Register index
|
||||
*
|
||||
* Returns the register address corresponding to the given @base and @index
|
||||
* by the formula ``base + index * regmap_stride * irq_reg_stride``.
|
||||
*/
|
||||
unsigned int regmap_irq_get_irq_reg_linear(struct regmap_irq_chip_data *data,
|
||||
unsigned int base, int index)
|
||||
{
|
||||
const struct regmap_irq_chip *chip = data->chip;
|
||||
struct regmap *map = data->map;
|
||||
|
||||
/*
|
||||
* FIXME: This is for backward compatibility and should be removed
|
||||
* when not_fixed_stride is dropped (it's only used by qcom-pm8008).
|
||||
*/
|
||||
if (chip->not_fixed_stride && chip->sub_reg_offsets) {
|
||||
struct regmap_irq_sub_irq_map *subreg;
|
||||
|
||||
subreg = &chip->sub_reg_offsets[0];
|
||||
return base + subreg->offset[0];
|
||||
}
|
||||
|
||||
return base + index * map->reg_stride * data->irq_reg_stride;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_irq_get_irq_reg_linear);
|
||||
|
||||
/**
|
||||
* regmap_irq_set_type_config_simple() - Simple IRQ type configuration callback.
|
||||
* @buf: Buffer containing configuration register values, this is a 2D array of
|
||||
* `num_config_bases` rows, each of `num_config_regs` elements.
|
||||
* @type: The requested IRQ type.
|
||||
* @irq_data: The IRQ being configured.
|
||||
* @idx: Index of the irq's config registers within each array `buf[i]`
|
||||
*
|
||||
* This is a &struct regmap_irq_chip->set_type_config callback suitable for
|
||||
* chips with one config register. Register values are updated according to
|
||||
* the &struct regmap_irq_type data associated with an IRQ.
|
||||
*/
|
||||
int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
|
||||
const struct regmap_irq *irq_data, int idx)
|
||||
{
|
||||
const struct regmap_irq_type *t = &irq_data->type;
|
||||
|
||||
if (t->type_reg_mask)
|
||||
buf[0][idx] &= ~t->type_reg_mask;
|
||||
else
|
||||
buf[0][idx] &= ~(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:
|
||||
buf[0][idx] |= t->type_falling_val;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
buf[0][idx] |= t->type_rising_val;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
buf[0][idx] |= (t->type_falling_val |
|
||||
t->type_rising_val);
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
buf[0][idx] |= t->type_level_high_val;
|
||||
break;
|
||||
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
buf[0][idx] |= t->type_level_low_val;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_irq_set_type_config_simple);
|
||||
|
||||
/**
|
||||
* regmap_add_irq_chip_fwnode() - Use standard regmap IRQ controller handling
|
||||
*
|
||||
@ -634,7 +723,6 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
int ret = -ENOMEM;
|
||||
int num_type_reg;
|
||||
u32 reg;
|
||||
u32 unmask_offset;
|
||||
|
||||
if (chip->num_regs <= 0)
|
||||
return -EINVAL;
|
||||
@ -651,11 +739,19 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
}
|
||||
|
||||
if (chip->not_fixed_stride) {
|
||||
dev_warn(map->dev, "not_fixed_stride is deprecated; use ->get_irq_reg() instead");
|
||||
|
||||
for (i = 0; i < chip->num_regs; i++)
|
||||
if (chip->sub_reg_offsets[i].num_regs != 1)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (chip->num_type_reg)
|
||||
dev_warn(map->dev, "type registers are deprecated; use config registers instead");
|
||||
|
||||
if (chip->num_virt_regs || chip->virt_reg_base || chip->set_type_virt)
|
||||
dev_warn(map->dev, "virtual registers are deprecated; use config registers instead");
|
||||
|
||||
if (irq_base) {
|
||||
irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
|
||||
if (irq_base < 0) {
|
||||
@ -671,30 +767,30 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
|
||||
if (chip->num_main_regs) {
|
||||
d->main_status_buf = kcalloc(chip->num_main_regs,
|
||||
sizeof(unsigned int),
|
||||
sizeof(*d->main_status_buf),
|
||||
GFP_KERNEL);
|
||||
|
||||
if (!d->main_status_buf)
|
||||
goto err_alloc;
|
||||
}
|
||||
|
||||
d->status_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||
d->status_buf = kcalloc(chip->num_regs, sizeof(*d->status_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->status_buf)
|
||||
goto err_alloc;
|
||||
|
||||
d->mask_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||
d->mask_buf = kcalloc(chip->num_regs, sizeof(*d->mask_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->mask_buf)
|
||||
goto err_alloc;
|
||||
|
||||
d->mask_buf_def = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||
d->mask_buf_def = kcalloc(chip->num_regs, sizeof(*d->mask_buf_def),
|
||||
GFP_KERNEL);
|
||||
if (!d->mask_buf_def)
|
||||
goto err_alloc;
|
||||
|
||||
if (chip->wake_base) {
|
||||
d->wake_buf = kcalloc(chip->num_regs, sizeof(unsigned int),
|
||||
d->wake_buf = kcalloc(chip->num_regs, sizeof(*d->wake_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->wake_buf)
|
||||
goto err_alloc;
|
||||
@ -703,11 +799,11 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
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);
|
||||
sizeof(*d->type_buf_def), GFP_KERNEL);
|
||||
if (!d->type_buf_def)
|
||||
goto err_alloc;
|
||||
|
||||
d->type_buf = kcalloc(num_type_reg, sizeof(unsigned int),
|
||||
d->type_buf = kcalloc(num_type_reg, sizeof(*d->type_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->type_buf)
|
||||
goto err_alloc;
|
||||
@ -724,13 +820,31 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
|
||||
for (i = 0; i < chip->num_virt_regs; i++) {
|
||||
d->virt_buf[i] = kcalloc(chip->num_regs,
|
||||
sizeof(unsigned int),
|
||||
sizeof(**d->virt_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->virt_buf[i])
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
if (chip->num_config_bases && chip->num_config_regs) {
|
||||
/*
|
||||
* Create config_buf[num_config_bases][num_config_regs]
|
||||
*/
|
||||
d->config_buf = kcalloc(chip->num_config_bases,
|
||||
sizeof(*d->config_buf), GFP_KERNEL);
|
||||
if (!d->config_buf)
|
||||
goto err_alloc;
|
||||
|
||||
for (i = 0; i < chip->num_config_regs; i++) {
|
||||
d->config_buf[i] = kcalloc(chip->num_config_regs,
|
||||
sizeof(**d->config_buf),
|
||||
GFP_KERNEL);
|
||||
if (!d->config_buf[i])
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
d->irq_chip = regmap_irq_chip;
|
||||
d->irq_chip.name = chip->name;
|
||||
d->irq = irq;
|
||||
@ -738,18 +852,53 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
d->chip = chip;
|
||||
d->irq_base = irq_base;
|
||||
|
||||
if (chip->mask_base && chip->unmask_base &&
|
||||
!chip->mask_unmask_non_inverted) {
|
||||
/*
|
||||
* Chips that specify both mask_base and unmask_base used to
|
||||
* get inverted mask behavior by default, with no way to ask
|
||||
* for the normal, non-inverted behavior. This "inverted by
|
||||
* default" behavior is deprecated, but we have to support it
|
||||
* until existing drivers have been fixed.
|
||||
*
|
||||
* Existing drivers should be updated by swapping mask_base
|
||||
* and unmask_base and setting mask_unmask_non_inverted=true.
|
||||
* New drivers should always set the flag.
|
||||
*/
|
||||
dev_warn(map->dev, "mask_base and unmask_base are inverted, please fix it");
|
||||
|
||||
/* Might as well warn about mask_invert while we're at it... */
|
||||
if (chip->mask_invert)
|
||||
dev_warn(map->dev, "mask_invert=true ignored");
|
||||
|
||||
d->mask_base = chip->unmask_base;
|
||||
d->unmask_base = chip->mask_base;
|
||||
} else if (chip->mask_invert) {
|
||||
/*
|
||||
* Swap the roles of mask_base and unmask_base if the bits are
|
||||
* inverted. This is deprecated, drivers should use unmask_base
|
||||
* directly.
|
||||
*/
|
||||
dev_warn(map->dev, "mask_invert=true is deprecated; please switch to unmask_base");
|
||||
|
||||
d->mask_base = chip->unmask_base;
|
||||
d->unmask_base = chip->mask_base;
|
||||
} else {
|
||||
d->mask_base = chip->mask_base;
|
||||
d->unmask_base = chip->unmask_base;
|
||||
}
|
||||
|
||||
if (chip->irq_reg_stride)
|
||||
d->irq_reg_stride = chip->irq_reg_stride;
|
||||
else
|
||||
d->irq_reg_stride = 1;
|
||||
|
||||
if (chip->type_reg_stride)
|
||||
d->type_reg_stride = chip->type_reg_stride;
|
||||
if (chip->get_irq_reg)
|
||||
d->get_irq_reg = chip->get_irq_reg;
|
||||
else
|
||||
d->type_reg_stride = 1;
|
||||
d->get_irq_reg = regmap_irq_get_irq_reg_linear;
|
||||
|
||||
if (!map->use_single_read && map->reg_stride == 1 &&
|
||||
d->irq_reg_stride == 1) {
|
||||
if (regmap_irq_can_bulk_read_status(d)) {
|
||||
d->status_reg_buf = kmalloc_array(chip->num_regs,
|
||||
map->format.val_bytes,
|
||||
GFP_KERNEL);
|
||||
@ -766,35 +915,34 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
/* Mask all the interrupts by default */
|
||||
for (i = 0; i < chip->num_regs; i++) {
|
||||
d->mask_buf[i] = d->mask_buf_def[i];
|
||||
if (!chip->mask_base)
|
||||
continue;
|
||||
|
||||
reg = sub_irq_reg(d, d->chip->mask_base, i);
|
||||
if (d->mask_base) {
|
||||
reg = d->get_irq_reg(d, d->mask_base, i);
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i], d->mask_buf[i]);
|
||||
if (ret) {
|
||||
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
|
||||
reg, ret);
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
if (chip->mask_invert)
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
d->mask_buf[i], ~d->mask_buf[i]);
|
||||
else if (d->chip->unmask_base) {
|
||||
unmask_offset = d->chip->unmask_base -
|
||||
d->chip->mask_base;
|
||||
ret = regmap_irq_update_bits(d,
|
||||
reg + unmask_offset,
|
||||
d->mask_buf[i],
|
||||
d->mask_buf[i]);
|
||||
} else
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
d->mask_buf[i], d->mask_buf[i]);
|
||||
if (ret != 0) {
|
||||
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
|
||||
reg, ret);
|
||||
goto err_alloc;
|
||||
if (d->unmask_base) {
|
||||
reg = d->get_irq_reg(d, d->unmask_base, i);
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i], ~d->mask_buf[i]);
|
||||
if (ret) {
|
||||
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
|
||||
reg, ret);
|
||||
goto err_alloc;
|
||||
}
|
||||
}
|
||||
|
||||
if (!chip->init_ack_masked)
|
||||
continue;
|
||||
|
||||
/* Ack masked but set interrupts */
|
||||
reg = sub_irq_reg(d, d->chip->status_base, i);
|
||||
reg = d->get_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",
|
||||
@ -806,7 +954,7 @@ int regmap_add_irq_chip_fwnode(struct fwnode_handle *fwnode,
|
||||
d->status_buf[i] = ~d->status_buf[i];
|
||||
|
||||
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
|
||||
reg = sub_irq_reg(d, d->chip->ack_base, i);
|
||||
reg = d->get_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]));
|
||||
@ -831,14 +979,14 @@ 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 = sub_irq_reg(d, d->chip->wake_base, i);
|
||||
reg = d->get_irq_reg(d, d->chip->wake_base, i);
|
||||
|
||||
if (chip->wake_invert)
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i],
|
||||
0);
|
||||
else
|
||||
ret = regmap_irq_update_bits(d, reg,
|
||||
ret = regmap_update_bits(d->map, reg,
|
||||
d->mask_buf_def[i],
|
||||
d->wake_buf[i]);
|
||||
if (ret != 0) {
|
||||
@ -851,7 +999,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 = sub_irq_reg(d, d->chip->type_base, i);
|
||||
reg = d->get_irq_reg(d, d->chip->type_base, i);
|
||||
|
||||
ret = regmap_read(map, reg, &d->type_buf_def[i]);
|
||||
|
||||
@ -907,6 +1055,11 @@ err_alloc:
|
||||
kfree(d->virt_buf[i]);
|
||||
kfree(d->virt_buf);
|
||||
}
|
||||
if (d->config_buf) {
|
||||
for (i = 0; i < chip->num_config_bases; i++)
|
||||
kfree(d->config_buf[i]);
|
||||
kfree(d->config_buf);
|
||||
}
|
||||
kfree(d);
|
||||
return ret;
|
||||
}
|
||||
@ -947,7 +1100,7 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
|
||||
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
|
||||
{
|
||||
unsigned int virq;
|
||||
int hwirq;
|
||||
int i, hwirq;
|
||||
|
||||
if (!d)
|
||||
return;
|
||||
@ -977,6 +1130,11 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
|
||||
kfree(d->mask_buf);
|
||||
kfree(d->status_reg_buf);
|
||||
kfree(d->status_buf);
|
||||
if (d->config_buf) {
|
||||
for (i = 0; i < d->chip->num_config_bases; i++)
|
||||
kfree(d->config_buf[i]);
|
||||
kfree(d->config_buf);
|
||||
}
|
||||
kfree(d);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
|
||||
|
@ -882,6 +882,8 @@ struct regmap *__regmap_init(struct device *dev,
|
||||
|
||||
if (config && config->read && config->write) {
|
||||
map->reg_read = _regmap_bus_read;
|
||||
if (config->reg_update_bits)
|
||||
map->reg_update_bits = config->reg_update_bits;
|
||||
|
||||
/* Bulk read/write */
|
||||
map->read = config->read;
|
||||
@ -1298,6 +1300,9 @@ static void regmap_field_init(struct regmap_field *rm_field,
|
||||
rm_field->reg = reg_field.reg;
|
||||
rm_field->shift = reg_field.lsb;
|
||||
rm_field->mask = GENMASK(reg_field.msb, reg_field.lsb);
|
||||
|
||||
WARN_ONCE(rm_field->mask == 0, "invalid empty mask defined\n");
|
||||
|
||||
rm_field->id_size = reg_field.id_size;
|
||||
rm_field->id_offset = reg_field.id_offset;
|
||||
}
|
||||
@ -2218,6 +2223,28 @@ int regmap_field_update_bits_base(struct regmap_field *field,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_field_update_bits_base);
|
||||
|
||||
/**
|
||||
* regmap_field_test_bits() - Check if all specified bits are set in a
|
||||
* register field.
|
||||
*
|
||||
* @field: Register field to operate on
|
||||
* @bits: Bits to test
|
||||
*
|
||||
* Returns -1 if the underlying regmap_field_read() fails, 0 if at least one of the
|
||||
* tested bits is not set and 1 if all tested bits are set.
|
||||
*/
|
||||
int regmap_field_test_bits(struct regmap_field *field, unsigned int bits)
|
||||
{
|
||||
unsigned int val, ret;
|
||||
|
||||
ret = regmap_field_read(field, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return (val & bits) == bits;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(regmap_field_test_bits);
|
||||
|
||||
/**
|
||||
* regmap_fields_update_bits_base() - Perform a read/modify/write cycle a
|
||||
* register field with port ID
|
||||
|
@ -1336,6 +1336,22 @@ static inline int regmap_field_update_bits(struct regmap_field *field,
|
||||
NULL, false, false);
|
||||
}
|
||||
|
||||
static inline int regmap_field_set_bits(struct regmap_field *field,
|
||||
unsigned int bits)
|
||||
{
|
||||
return regmap_field_update_bits_base(field, bits, bits, NULL, false,
|
||||
false);
|
||||
}
|
||||
|
||||
static inline int regmap_field_clear_bits(struct regmap_field *field,
|
||||
unsigned int bits)
|
||||
{
|
||||
return regmap_field_update_bits_base(field, bits, 0, NULL, false,
|
||||
false);
|
||||
}
|
||||
|
||||
int regmap_field_test_bits(struct regmap_field *field, unsigned int bits);
|
||||
|
||||
static inline int
|
||||
regmap_field_force_update_bits(struct regmap_field *field,
|
||||
unsigned int mask, unsigned int val)
|
||||
@ -1424,6 +1440,8 @@ struct regmap_irq_sub_irq_map {
|
||||
unsigned int *offset;
|
||||
};
|
||||
|
||||
struct regmap_irq_chip_data;
|
||||
|
||||
/**
|
||||
* struct regmap_irq_chip - Description of a generic regmap irq_chip.
|
||||
*
|
||||
@ -1451,32 +1469,50 @@ struct regmap_irq_sub_irq_map {
|
||||
* main_status set.
|
||||
*
|
||||
* @status_base: Base status register address.
|
||||
* @mask_base: Base mask register address.
|
||||
* @mask_writeonly: Base mask register is write only.
|
||||
* @unmask_base: Base unmask register address. for chips who have
|
||||
* separate mask and unmask registers
|
||||
* @mask_base: Base mask register address. Mask bits are set to 1 when an
|
||||
* interrupt is masked, 0 when unmasked.
|
||||
* @unmask_base: Base unmask register address. Unmask bits are set to 1 when
|
||||
* an interrupt is unmasked and 0 when masked.
|
||||
* @ack_base: Base ack address. If zero then the chip is clear on read.
|
||||
* 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.
|
||||
* @type_base: Base address for irq type. If zero unsupported. Deprecated,
|
||||
* use @config_base instead.
|
||||
* @virt_reg_base: Base addresses for extra config regs. Deprecated, use
|
||||
* @config_base instead.
|
||||
* @config_base: Base address for IRQ type config regs. If null unsupported.
|
||||
* @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.
|
||||
* Deprecated; prefer describing an inverted mask register as
|
||||
* an unmask register.
|
||||
* @mask_unmask_non_inverted: Controls mask bit inversion for chips that set
|
||||
* both @mask_base and @unmask_base. If false, mask and unmask bits are
|
||||
* inverted (which is deprecated behavior); if true, bits will not be
|
||||
* inverted and the registers keep their normal behavior. Note that if
|
||||
* you use only one of @mask_base or @unmask_base, this flag has no
|
||||
* effect and is unnecessary. Any new drivers that set both @mask_base
|
||||
* and @unmask_base should set this to true to avoid relying on the
|
||||
* deprecated behavior.
|
||||
* @use_ack: Use @ack register even if it is zero.
|
||||
* @ack_invert: Inverted ack register: cleared bits for ack.
|
||||
* @clear_ack: Use this to set 1 and 0 or vice-versa to clear interrupts.
|
||||
* @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.
|
||||
* @type_invert: Invert the type flags. Deprecated, use config registers
|
||||
* instead.
|
||||
* @type_in_mask: Use the mask registers for controlling irq type. Use this if
|
||||
* the hardware provides separate bits for rising/falling edge
|
||||
* or low/high level interrupts and they should be combined into
|
||||
* a single logical interrupt. Use &struct regmap_irq_type data
|
||||
* to define the mask bit for each irq type.
|
||||
* @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.
|
||||
* stride. Must be used with sub_reg_offsets containing the
|
||||
* offsets to each peripheral. Deprecated; the same thing
|
||||
* can be accomplished with a @get_irq_reg callback, without
|
||||
* the need for a @sub_reg_offsets table.
|
||||
* @status_invert: Inverted status register: cleared bits are active interrupts.
|
||||
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
|
||||
*
|
||||
@ -1484,17 +1520,28 @@ struct regmap_irq_sub_irq_map {
|
||||
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
|
||||
* assigned based on the index in the array of the interrupt.
|
||||
* @num_irqs: Number of descriptors.
|
||||
* @num_type_reg: Number of type registers.
|
||||
* @num_type_reg: Number of type registers. Deprecated, use config registers
|
||||
* instead.
|
||||
* @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.
|
||||
* If zero unsupported. Deprecated, use config registers
|
||||
* instead.
|
||||
* @num_config_bases: Number of config base registers.
|
||||
* @num_config_regs: Number of config registers for each config base register.
|
||||
* @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.
|
||||
* and configure virt regs. Deprecated, use @set_type_config
|
||||
* callback and config registers instead.
|
||||
* @set_type_config: Callback used for configuring irq types.
|
||||
* @get_irq_reg: Callback for mapping (base register, index) pairs to register
|
||||
* addresses. The base register will be one of @status_base,
|
||||
* @mask_base, etc., @main_status, or any of @config_base.
|
||||
* The index will be in the range [0, num_main_regs[ for the
|
||||
* main status base, [0, num_type_settings[ for any config
|
||||
* register base, and [0, num_regs[ for any other base.
|
||||
* If unspecified then regmap_irq_get_irq_reg_linear() is used.
|
||||
* @irq_drv_data: Driver specific IRQ data which is passed as parameter when
|
||||
* driver specific pre/post interrupt handler is called.
|
||||
*
|
||||
@ -1517,20 +1564,21 @@ struct regmap_irq_chip {
|
||||
unsigned int wake_base;
|
||||
unsigned int type_base;
|
||||
unsigned int *virt_reg_base;
|
||||
const unsigned int *config_base;
|
||||
unsigned int irq_reg_stride;
|
||||
bool mask_writeonly:1;
|
||||
bool init_ack_masked:1;
|
||||
bool mask_invert:1;
|
||||
bool use_ack:1;
|
||||
bool ack_invert:1;
|
||||
bool clear_ack:1;
|
||||
bool wake_invert:1;
|
||||
bool runtime_pm:1;
|
||||
bool type_invert:1;
|
||||
bool type_in_mask:1;
|
||||
bool clear_on_unmask:1;
|
||||
bool not_fixed_stride:1;
|
||||
bool status_invert:1;
|
||||
unsigned int init_ack_masked:1;
|
||||
unsigned int mask_invert:1;
|
||||
unsigned int mask_unmask_non_inverted:1;
|
||||
unsigned int use_ack:1;
|
||||
unsigned int ack_invert:1;
|
||||
unsigned int clear_ack:1;
|
||||
unsigned int wake_invert:1;
|
||||
unsigned int runtime_pm:1;
|
||||
unsigned int type_invert:1;
|
||||
unsigned int type_in_mask:1;
|
||||
unsigned int clear_on_unmask:1;
|
||||
unsigned int not_fixed_stride:1;
|
||||
unsigned int status_invert:1;
|
||||
|
||||
int num_regs;
|
||||
|
||||
@ -1539,16 +1587,24 @@ struct regmap_irq_chip {
|
||||
|
||||
int num_type_reg;
|
||||
int num_virt_regs;
|
||||
unsigned int type_reg_stride;
|
||||
int num_config_bases;
|
||||
int num_config_regs;
|
||||
|
||||
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);
|
||||
int (*set_type_config)(unsigned int **buf, unsigned int type,
|
||||
const struct regmap_irq *irq_data, int idx);
|
||||
unsigned int (*get_irq_reg)(struct regmap_irq_chip_data *data,
|
||||
unsigned int base, int index);
|
||||
void *irq_drv_data;
|
||||
};
|
||||
|
||||
struct regmap_irq_chip_data;
|
||||
unsigned int regmap_irq_get_irq_reg_linear(struct regmap_irq_chip_data *data,
|
||||
unsigned int base, int index);
|
||||
int regmap_irq_set_type_config_simple(unsigned int **buf, unsigned int type,
|
||||
const struct regmap_irq *irq_data, int idx);
|
||||
|
||||
int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
||||
int irq_base, const struct regmap_irq_chip *chip,
|
||||
@ -1769,6 +1825,27 @@ regmap_field_force_update_bits(struct regmap_field *field,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_field_set_bits(struct regmap_field *field,
|
||||
unsigned int bits)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_field_clear_bits(struct regmap_field *field,
|
||||
unsigned int bits)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_field_test_bits(struct regmap_field *field,
|
||||
unsigned int bits)
|
||||
{
|
||||
WARN_ONCE(1, "regmap API is disabled");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline int regmap_fields_write(struct regmap_field *field,
|
||||
unsigned int id, unsigned int val)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user