mfd: wcd9xxx: Update WCD codec interrupt registers

It is possible that interrupt register addresses
are different depending on the version of the WCD
codec. Currently IRQ driver assumes that these
addresses are same across codecs. Add condition
to check the WCD codec version and update the
interrupt registers accordingly so that IRQ driver
can access the correct set of registers for interrupt
processing.

Change-Id: I65308cd865517b363cbce01c9fe57d5e13373aea
Signed-off-by: Aravind Kumar <akumark@codeaurora.org>
This commit is contained in:
Phani Kumar Uppalapati 2015-02-14 01:46:34 -08:00 committed by Aravind Kumar
parent e1d8a232cb
commit c495a9ab1c
3 changed files with 69 additions and 17 deletions

View File

@ -1120,6 +1120,41 @@ static int wcd9xxx_regmap_init_cache(struct wcd9xxx *wcd9xxx)
return rc;
}
static void wcd9xxx_core_res_update_irq_regs(
struct wcd9xxx_core_resource *core_res,
u16 id_major)
{
switch (id_major) {
case TASHA_MAJOR:
core_res->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
WCD9335_INTR_PIN1_STATUS0;
core_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
WCD9335_INTR_PIN1_CLEAR0;
core_res->intr_reg[WCD9XXX_INTR_MASK_BASE] =
WCD9335_INTR_PIN1_MASK0;
core_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
WCD9335_INTR_LEVEL0;
core_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
WCD9335_INTR_CLR_COMMIT;
break;
case TABLA_MAJOR:
case TOMTOM_MAJOR:
case TAIKO_MAJOR:
default:
core_res->intr_reg[WCD9XXX_INTR_STATUS_BASE] =
WCD9XXX_A_INTR_STATUS0;
core_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] =
WCD9XXX_A_INTR_CLEAR0;
core_res->intr_reg[WCD9XXX_INTR_MASK_BASE] =
WCD9XXX_A_INTR_MASK0;
core_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] =
WCD9XXX_A_INTR_LEVEL0;
core_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT] =
WCD9XXX_A_INTR_MODE;
break;
};
}
static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
{
int ret = 0;
@ -1159,6 +1194,8 @@ static int wcd9xxx_device_init(struct wcd9xxx *wcd9xxx)
core_res->intr_table = intr_tbl_v2;
core_res->intr_table_size = ARRAY_SIZE(intr_tbl_v2);
}
wcd9xxx_core_res_update_irq_regs(&wcd9xxx->core_res,
wcd9xxx->codec_type->id_major);
wcd9xxx_core_res_init(&wcd9xxx->core_res,
wcd9xxx->codec_type->num_irqs,

View File

@ -1,4 +1,4 @@
/* Copyright (c) 2011-2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -90,8 +90,8 @@ static void wcd9xxx_irq_sync_unlock(struct irq_data *data)
wcd9xxx_res->irq_masks_cache[i] =
wcd9xxx_res->irq_masks_cur[i];
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MASK0 + i,
wcd9xxx_res->irq_masks_cur[i]);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
wcd9xxx_res->irq_masks_cur[i]);
}
}
@ -252,23 +252,27 @@ static void wcd9xxx_irq_dispatch(struct wcd9xxx_core_resource *wcd9xxx_res,
if (irqdata->clear_first) {
wcd9xxx_nested_irq_lock(wcd9xxx_res);
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MODE, 0x02);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
wcd9xxx_nested_irq_unlock(wcd9xxx_res);
} else {
wcd9xxx_nested_irq_lock(wcd9xxx_res);
handle_nested_irq(phyirq_to_virq(wcd9xxx_res, irqbit));
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_CLEAR0 + BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE] +
BIT_BYTE(irqbit),
BYTE_BIT_MASK(irqbit));
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MODE, 0x02);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
wcd9xxx_nested_irq_unlock(wcd9xxx_res);
}
@ -298,8 +302,8 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
}
ret = wcd9xxx_res->codec_bulk_read(wcd9xxx_res,
WCD9XXX_A_INTR_STATUS0,
num_irq_regs, status);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_STATUS_BASE],
num_irq_regs, status);
if (ret < 0) {
dev_err(wcd9xxx_res->dev,
@ -354,11 +358,12 @@ static irqreturn_t wcd9xxx_irq_thread(int irq, void *data)
memset(status, 0xff, num_irq_regs);
ret = wcd9xxx_res->codec_bulk_write(wcd9xxx_res,
WCD9XXX_A_INTR_CLEAR0,
num_irq_regs, status);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLEAR_BASE],
num_irq_regs, status);
if (wcd9xxx_get_intf_type() == WCD9XXX_INTERFACE_TYPE_I2C)
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MODE, 0x02);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_CLR_COMMIT],
0x02);
}
wcd9xxx_unlock_sleep(wcd9xxx_res);
@ -485,11 +490,11 @@ int wcd9xxx_irq_init(struct wcd9xxx_core_resource *wcd9xxx_res)
for (i = 0; i < wcd9xxx_res->num_irq_regs; i++) {
/* Initialize interrupt mask and level registers */
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_LEVEL0 + i,
wcd9xxx_res->intr_reg[WCD9XXX_INTR_LEVEL_BASE] + i,
irq_level[i]);
wcd9xxx_res->codec_reg_write(wcd9xxx_res,
WCD9XXX_A_INTR_MASK0 + i,
wcd9xxx_res->irq_masks_cur[i]);
wcd9xxx_res->intr_reg[WCD9XXX_INTR_MASK_BASE] + i,
wcd9xxx_res->irq_masks_cur[i]);
}
ret = request_threaded_irq(wcd9xxx_res->irq, NULL, wcd9xxx_irq_thread,

View File

@ -31,6 +31,15 @@ enum wcd9xxx_pm_state {
WCD9XXX_PM_ASLEEP,
};
enum {
WCD9XXX_INTR_STATUS_BASE = 0,
WCD9XXX_INTR_CLEAR_BASE,
WCD9XXX_INTR_MASK_BASE,
WCD9XXX_INTR_LEVEL_BASE,
WCD9XXX_INTR_CLR_COMMIT,
WCD9XXX_INTR_REG_MAX,
};
enum wcd9xxx_intf_status {
WCD9XXX_INTERFACE_TYPE_PROBING,
WCD9XXX_INTERFACE_TYPE_SLIMBUS,
@ -59,6 +68,7 @@ struct wcd9xxx_core_resource {
bool irq_level_high[WCD9XXX_MAX_NUM_IRQS];
int num_irqs;
int num_irq_regs;
u16 intr_reg[WCD9XXX_INTR_REG_MAX];
/* Callback functions to read/write codec registers */
int (*codec_reg_read) (struct wcd9xxx_core_resource *,