regmap: Support for split mask and unmask interrupt registers
This branch adds an interface for supporting devices which have separate mask and unmask registers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJV+ptkAAoJECTWi3JdVIfQeIoH/3e1rQhIJFwO+iOV8A/vWSyk P+NlBqPRCH77NofBfmilRHSTzI7bhuW5IDaD9mMvTcXID8j9p0HvJxJPVsrWtr8X p7MaBYjNUitIUyO1coBDQ9YIh+gtVn5GaSzmfa5o+B0g8wpAKoqqE2BG08jR8yvH oKp+Z/RZsIpjIgTLPLvoNX6WsjkOKMH5GB7uBAv5epmDarCJsi8gb+vs8OFoITdN lBm0PSRD77nMn1a37n0FHa79yf/pszma0ep/mU662Ym+52BtSQM/UloNheoYQZ4Z D7cgQjeXCJo57p1sXW6L26o1LhHRy1ovtr47nV+EXa7z0u1oY5EEwxOdUzXKiCA= =+gx/ -----END PGP SIGNATURE----- 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>"
This commit is contained in:
commit
ba5890a0c7
|
@ -63,6 +63,7 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
|||
struct regmap *map = d->map;
|
||||
int i, ret;
|
||||
u32 reg;
|
||||
u32 unmask_offset;
|
||||
|
||||
if (d->chip->runtime_pm) {
|
||||
ret = pm_runtime_get_sync(map->dev);
|
||||
|
@ -79,12 +80,28 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
|
|||
for (i = 0; i < d->chip->num_regs; i++) {
|
||||
reg = d->chip->mask_base +
|
||||
(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,
|
||||
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,
|
||||
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);
|
||||
|
@ -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)) {
|
||||
reg = d->chip->ack_base +
|
||||
(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]);
|
||||
if (ret != 0)
|
||||
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,
|
|||
int i;
|
||||
int ret = -ENOMEM;
|
||||
u32 reg;
|
||||
u32 unmask_offset;
|
||||
|
||||
if (chip->num_regs <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -420,7 +442,14 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
|
|||
if (chip->mask_invert)
|
||||
ret = regmap_update_bits(map, reg,
|
||||
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,
|
||||
d->mask_buf[i], d->mask_buf[i]);
|
||||
if (ret != 0) {
|
||||
|
@ -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)) {
|
||||
reg = chip->ack_base +
|
||||
(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,
|
||||
d->status_buf[i] & d->mask_buf[i]);
|
||||
if (ret != 0) {
|
||||
|
|
|
@ -800,6 +800,8 @@ struct regmap_irq {
|
|||
*
|
||||
* @status_base: Base status 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.
|
||||
* Using zero value is possible with @use_ack bit.
|
||||
* @wake_base: Base address for wake enables. If zero unsupported.
|
||||
|
@ -807,6 +809,7 @@ struct regmap_irq {
|
|||
* @init_ack_masked: Ack all masked interrupts once during initalization.
|
||||
* @mask_invert: Inverted mask register: cleared bits are masked out.
|
||||
* @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.
|
||||
* @runtime_pm: Hold a runtime PM lock on the device when accessing it.
|
||||
*
|
||||
|
@ -820,12 +823,14 @@ struct regmap_irq_chip {
|
|||
|
||||
unsigned int status_base;
|
||||
unsigned int mask_base;
|
||||
unsigned int unmask_base;
|
||||
unsigned int ack_base;
|
||||
unsigned int wake_base;
|
||||
unsigned int irq_reg_stride;
|
||||
bool init_ack_masked:1;
|
||||
bool mask_invert:1;
|
||||
bool use_ack:1;
|
||||
bool ack_invert:1;
|
||||
bool wake_invert:1;
|
||||
bool runtime_pm:1;
|
||||
|
||||
|
|
Loading…
Reference in a new issue