Commit ba5890a0 authored by Mark Brown's avatar Mark Brown

Merge tag 'regmap-irq-unmask' into regmap-next

regmap: Support for split mask and unmask interrupt registers

This branch adds an interface for supporting devices which have separate
mask and unmask registers.

# gpg: Signature made Thu 17 Sep 2015 11:52:20 BST using RSA key ID 5D5487D0
# gpg: Oops: keyid_from_fingerprint: no pubkey
# gpg: Oops: keyid_from_fingerprint: no pubkey
# gpg: key 00000000 occurs more than once in the trustdb
# gpg: key 16005C11: no public key for trusted key - skipped
# gpg: key 16005C11 marked as ultimately trusted
# gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>"
# gpg:                 aka "Mark Brown <broonie@debian.org>"
# gpg:                 aka "Mark Brown <broonie@kernel.org>"
# gpg:                 aka "Mark Brown <broonie@tardis.ed.ac.uk>"
# gpg:                 aka "Mark Brown <broonie@linaro.org>"
# gpg:                 aka "Mark Brown <Mark.Brown@linaro.org>"
parents 25cb62b7 a650fdd9
...@@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
struct regmap *map = d->map; struct regmap *map = d->map;
int i, ret; int i, ret;
u32 reg; u32 reg;
u32 unmask_offset;
if (d->chip->runtime_pm) { if (d->chip->runtime_pm) {
ret = pm_runtime_get_sync(map->dev); ret = pm_runtime_get_sync(map->dev);
...@@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
for (i = 0; i < d->chip->num_regs; i++) { for (i = 0; i < d->chip->num_regs; i++) {
reg = d->chip->mask_base + reg = d->chip->mask_base +
(i * map->reg_stride * d->irq_reg_stride); (i * map->reg_stride * d->irq_reg_stride);
if (d->chip->mask_invert) if (d->chip->mask_invert) {
ret = regmap_update_bits(d->map, reg, ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i], ~d->mask_buf[i]); d->mask_buf_def[i], ~d->mask_buf[i]);
else } else if (d->chip->unmask_base) {
/* set mask with mask_base register */
ret = regmap_update_bits(d->map, 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",
reg);
unmask_offset = d->chip->unmask_base -
d->chip->mask_base;
/* clear mask with unmask_base register */
ret = regmap_update_bits(d->map,
reg + unmask_offset,
d->mask_buf_def[i],
d->mask_buf[i]);
} else {
ret = regmap_update_bits(d->map, reg, ret = regmap_update_bits(d->map, reg,
d->mask_buf_def[i], d->mask_buf[i]); d->mask_buf_def[i], d->mask_buf[i]);
}
if (ret != 0) if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n", dev_err(d->map->dev, "Failed to sync masks in %x\n",
reg); reg);
...@@ -116,6 +133,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data) ...@@ -116,6 +133,10 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) { if (d->mask_buf[i] && (d->chip->ack_base || d->chip->use_ack)) {
reg = d->chip->ack_base + reg = d->chip->ack_base +
(i * map->reg_stride * d->irq_reg_stride); (i * map->reg_stride * d->irq_reg_stride);
/* some chips ack by write 0 */
if (d->chip->ack_invert)
ret = regmap_write(map, reg, ~d->mask_buf[i]);
else
ret = regmap_write(map, reg, d->mask_buf[i]); ret = regmap_write(map, reg, d->mask_buf[i]);
if (ret != 0) if (ret != 0)
dev_err(d->map->dev, "Failed to ack 0x%x: %d\n", dev_err(d->map->dev, "Failed to ack 0x%x: %d\n",
...@@ -339,6 +360,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -339,6 +360,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
int i; int i;
int ret = -ENOMEM; int ret = -ENOMEM;
u32 reg; u32 reg;
u32 unmask_offset;
if (chip->num_regs <= 0) if (chip->num_regs <= 0)
return -EINVAL; return -EINVAL;
...@@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (chip->mask_invert) if (chip->mask_invert)
ret = regmap_update_bits(map, reg, ret = regmap_update_bits(map, reg,
d->mask_buf[i], ~d->mask_buf[i]); d->mask_buf[i], ~d->mask_buf[i]);
else else if (d->chip->unmask_base) {
unmask_offset = d->chip->unmask_base -
d->chip->mask_base;
ret = regmap_update_bits(d->map,
reg + unmask_offset,
d->mask_buf[i],
d->mask_buf[i]);
} else
ret = regmap_update_bits(map, reg, ret = regmap_update_bits(map, reg,
d->mask_buf[i], d->mask_buf[i]); d->mask_buf[i], d->mask_buf[i]);
if (ret != 0) { if (ret != 0) {
...@@ -445,6 +474,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags, ...@@ -445,6 +474,10 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) { if (d->status_buf[i] && (chip->ack_base || chip->use_ack)) {
reg = chip->ack_base + reg = chip->ack_base +
(i * map->reg_stride * d->irq_reg_stride); (i * map->reg_stride * d->irq_reg_stride);
if (chip->ack_invert)
ret = regmap_write(map, reg,
~(d->status_buf[i] & d->mask_buf[i]));
else
ret = regmap_write(map, reg, ret = regmap_write(map, reg,
d->status_buf[i] & d->mask_buf[i]); d->status_buf[i] & d->mask_buf[i]);
if (ret != 0) { if (ret != 0) {
......
...@@ -800,6 +800,8 @@ struct regmap_irq { ...@@ -800,6 +800,8 @@ struct regmap_irq {
* *
* @status_base: Base status register address. * @status_base: Base status register address.
* @mask_base: Base mask register address. * @mask_base: Base mask register address.
* @unmask_base: Base unmask register address. for chips who have
* separate mask and unmask registers
* @ack_base: Base ack address. If zero then the chip is clear on read. * @ack_base: Base ack address. If zero then the chip is clear on read.
* Using zero value is possible with @use_ack bit. * Using zero value is possible with @use_ack bit.
* @wake_base: Base address for wake enables. If zero unsupported. * @wake_base: Base address for wake enables. If zero unsupported.
...@@ -807,6 +809,7 @@ struct regmap_irq { ...@@ -807,6 +809,7 @@ struct regmap_irq {
* @init_ack_masked: Ack all masked interrupts once during initalization. * @init_ack_masked: Ack all masked interrupts once during initalization.
* @mask_invert: Inverted mask register: cleared bits are masked out. * @mask_invert: Inverted mask register: cleared bits are masked out.
* @use_ack: Use @ack register even if it is zero. * @use_ack: Use @ack register even if it is zero.
* @ack_invert: Inverted ack register: cleared bits for ack.
* @wake_invert: Inverted wake register: cleared bits are wake enabled. * @wake_invert: Inverted wake register: cleared bits are wake enabled.
* @runtime_pm: Hold a runtime PM lock on the device when accessing it. * @runtime_pm: Hold a runtime PM lock on the device when accessing it.
* *
...@@ -820,12 +823,14 @@ struct regmap_irq_chip { ...@@ -820,12 +823,14 @@ struct regmap_irq_chip {
unsigned int status_base; unsigned int status_base;
unsigned int mask_base; unsigned int mask_base;
unsigned int unmask_base;
unsigned int ack_base; unsigned int ack_base;
unsigned int wake_base; unsigned int wake_base;
unsigned int irq_reg_stride; unsigned int irq_reg_stride;
bool init_ack_masked:1; bool init_ack_masked:1;
bool mask_invert:1; bool mask_invert:1;
bool use_ack:1; bool use_ack:1;
bool ack_invert:1;
bool wake_invert:1; bool wake_invert:1;
bool runtime_pm:1; bool runtime_pm:1;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment