summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraeme Gregory <gg@slimlogic.co.uk>2012-05-14 22:40:43 +0900
committerSimone Willett <swillett@nvidia.com>2012-07-03 15:03:33 -0700
commit6d80ad162f51dfae870b32889de1d42bd51ccb4f (patch)
tree81b5f29015500246fca15d3ff2fd6375c96139ed
parent51978f469bcd8e5c59932938a72a8f20e7d5c73f (diff)
regmap: add support for non contiguous status to regmap-irq
In some chips the IRQ status registers are not contiguous in the register map but spaced at even spaces. This is an easy case to handle with minor changes. It is assume for this purpose that the stride for status is equal to the stride for mask/ack registers as well. Signed-off-by: Graeme Gregory <gg@slimlogic.co.uk> Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> (cherry picked from commit 022f926a2401c80ed36ebb48a1bffbac08f34d98) Change-Id: I68a59c8fd8a67062dac0eceaefcc85ed597f4a29 Reviewed-on: http://git-master/r/111484 Reviewed-by: Automatic_Commit_Validation_User Tested-by: Pradeep Goudagunta <pgoudagunta@nvidia.com> GVS: Gerrit_Virtual_Submit Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
-rw-r--r--drivers/base/regmap/regmap-irq.c54
-rw-r--r--include/linux/regmap.h2
2 files changed, 23 insertions, 33 deletions
diff --git a/drivers/base/regmap/regmap-irq.c b/drivers/base/regmap/regmap-irq.c
index cc7b4f764d63..2691907757c4 100644
--- a/drivers/base/regmap/regmap-irq.c
+++ b/drivers/base/regmap/regmap-irq.c
@@ -26,10 +26,11 @@ struct regmap_irq_chip_data {
int irq_base;
- void *status_reg_buf;
unsigned int *status_buf;
unsigned int *mask_buf;
unsigned int *mask_buf_def;
+
+ unsigned int irq_reg_stride;
};
static inline const
@@ -59,7 +60,8 @@ static void regmap_irq_sync_unlock(struct irq_data *data)
*/
for (i = 0; i < d->chip->num_regs; i++) {
ret = regmap_update_bits(d->map, d->chip->mask_base +
- (i * map->reg_stride),
+ (i * map->reg_stride *
+ d->irq_reg_stride),
d->mask_buf_def[i], d->mask_buf[i]);
if (ret != 0)
dev_err(d->map->dev, "Failed to sync masks in %x\n",
@@ -101,18 +103,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
struct regmap_irq_chip *chip = data->chip;
struct regmap *map = data->map;
int ret, i;
- u8 *buf8 = data->status_reg_buf;
- u16 *buf16 = data->status_reg_buf;
- u32 *buf32 = data->status_reg_buf;
bool handled = false;
- ret = regmap_bulk_read(map, chip->status_base, data->status_reg_buf,
- chip->num_regs);
- if (ret != 0) {
- dev_err(map->dev, "Failed to read IRQ status: %d\n", ret);
- return IRQ_NONE;
- }
-
/*
* Ignore masked IRQs and ack if we need to; we ack early so
* there is no race between handling and acknowleding the
@@ -121,18 +113,13 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
* doing a write per register.
*/
for (i = 0; i < data->chip->num_regs; i++) {
- switch (map->format.val_bytes) {
- case 1:
- data->status_buf[i] = buf8[i];
- break;
- case 2:
- data->status_buf[i] = buf16[i];
- break;
- case 4:
- data->status_buf[i] = buf32[i];
- break;
- default:
- BUG();
+ ret = regmap_read(map, chip->mask_base + (i * map->reg_stride
+ * data->irq_reg_stride),
+ &data->status_buf[i]);
+
+ if (ret != 0) {
+ dev_err(map->dev, "Failed to read IRQ status: %d\n",
+ ret);
return IRQ_NONE;
}
@@ -140,7 +127,8 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
if (data->status_buf[i] && chip->ack_base) {
ret = regmap_write(map, chip->ack_base +
- (i * map->reg_stride),
+ (i * map->reg_stride *
+ data->irq_reg_stride),
data->status_buf[i]);
if (ret != 0)
dev_err(map->dev, "Failed to ack 0x%x: %d\n",
@@ -210,11 +198,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
if (!d->status_buf)
goto err_alloc;
- d->status_reg_buf = kzalloc(map->format.val_bytes * chip->num_regs,
- GFP_KERNEL);
- if (!d->status_reg_buf)
- goto err_alloc;
-
d->mask_buf = kzalloc(sizeof(unsigned int) * chip->num_regs,
GFP_KERNEL);
if (!d->mask_buf)
@@ -228,6 +211,12 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
d->map = map;
d->chip = chip;
d->irq_base = irq_base;
+
+ if (chip->irq_reg_stride)
+ d->irq_reg_stride = chip->irq_reg_stride;
+ else
+ d->irq_reg_stride = 1;
+
mutex_init(&d->lock);
for (i = 0; i < chip->num_irqs; i++)
@@ -237,7 +226,8 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
/* Mask all the interrupts by default */
for (i = 0; i < chip->num_regs; i++) {
d->mask_buf[i] = d->mask_buf_def[i];
- ret = regmap_write(map, chip->mask_base + (i * map->reg_stride),
+ ret = regmap_write(map, chip->mask_base + (i * map->reg_stride
+ * d->irq_reg_stride),
d->mask_buf[i]);
if (ret != 0) {
dev_err(map->dev, "Failed to set masks in 0x%x: %d\n",
@@ -276,7 +266,6 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
err_alloc:
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
return ret;
@@ -297,7 +286,6 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
free_irq(irq, d);
kfree(d->mask_buf_def);
kfree(d->mask_buf);
- kfree(d->status_reg_buf);
kfree(d->status_buf);
kfree(d);
}
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 6986d16aeca8..3a97248c5125 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -212,6 +212,7 @@ struct regmap_irq {
* @status_base: Base status register address.
* @mask_base: Base mask register address.
* @ack_base: Base ack address. If zero then the chip is clear on read.
+ * @irq_reg_stride: Stride to use for chips where registers are not contiguous.
*
* @num_regs: Number of registers in each control bank.
* @irqs: Descriptors for individual IRQs. Interrupt numbers are
@@ -224,6 +225,7 @@ struct regmap_irq_chip {
unsigned int status_base;
unsigned int mask_base;
unsigned int ack_base;
+ unsigned int irq_reg_stride;
int num_regs;