mfd: Drop twl4030-irq's edge_work

... and do all the synchronization with the
hardware during bus_sync_unlock. We can now
remove all the workqueues.

Signed-off-by: Felipe Balbi <balbi@ti.com>
Reviewed-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
Felipe Balbi 2011-06-30 12:51:08 +03:00 committed by Samuel Ortiz
parent 848684246f
commit 2f2a7d5ef7
1 changed files with 52 additions and 72 deletions

View File

@ -422,8 +422,6 @@ static inline void activate_irq(int irq)
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
static struct workqueue_struct *wq;
struct sih_agent { struct sih_agent {
int irq_base; int irq_base;
const struct sih *sih; const struct sih *sih;
@ -432,68 +430,10 @@ struct sih_agent {
bool imr_change_pending; bool imr_change_pending;
u32 edge_change; u32 edge_change;
struct work_struct edge_work;
struct mutex irq_lock; struct mutex irq_lock;
}; };
static void twl4030_sih_do_edge(struct work_struct *work)
{
struct sih_agent *agent;
const struct sih *sih;
u8 bytes[6];
u32 edge_change;
int status;
agent = container_of(work, struct sih_agent, edge_work);
/* see what work we have */
edge_change = agent->edge_change;
agent->edge_change = 0;
sih = edge_change ? agent->sih : NULL;
if (!sih)
return;
/* Read, reserving first byte for write scratch. Yes, this
* could be cached for some speedup ... but be careful about
* any processor on the other IRQ line, EDR registers are
* shared.
*/
status = twl_i2c_read(sih->module, bytes + 1,
sih->edr_offset, sih->bytes_edr);
if (status) {
pr_err("twl4030: %s, %s --> %d\n", __func__,
"read", status);
return;
}
/* Modify only the bits we know must change */
while (edge_change) {
int i = fls(edge_change) - 1;
struct irq_data *idata = irq_get_irq_data(i + agent->irq_base);
int byte = 1 + (i >> 2);
int off = (i & 0x3) * 2;
unsigned int type;
bytes[byte] &= ~(0x03 << off);
type = irqd_get_trigger_type(idata);
if (type & IRQ_TYPE_EDGE_RISING)
bytes[byte] |= BIT(off + 1);
if (type & IRQ_TYPE_EDGE_FALLING)
bytes[byte] |= BIT(off + 0);
edge_change &= ~BIT(i);
}
/* Write */
status = twl_i2c_write(sih->module, bytes,
sih->edr_offset, sih->bytes_edr);
if (status)
pr_err("twl4030: %s, %s --> %d\n", __func__,
"write", status);
}
/*----------------------------------------------------------------------*/ /*----------------------------------------------------------------------*/
/* /*
@ -526,10 +466,8 @@ static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger)
if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING))
return -EINVAL; return -EINVAL;
if (irqd_get_trigger_type(data) != trigger) { if (irqd_get_trigger_type(data) != trigger)
agent->edge_change |= BIT(data->irq - agent->irq_base); agent->edge_change |= BIT(data->irq - agent->irq_base);
queue_work(wq, &agent->edge_work);
}
return 0; return 0;
} }
@ -566,6 +504,56 @@ static void twl4030_sih_bus_sync_unlock(struct irq_data *data)
"write", status); "write", status);
} }
if (agent->edge_change) {
u32 edge_change;
u8 bytes[6];
edge_change = agent->edge_change;
agent->edge_change = 0;
/*
* Read, reserving first byte for write scratch. Yes, this
* could be cached for some speedup ... but be careful about
* any processor on the other IRQ line, EDR registers are
* shared.
*/
status = twl_i2c_read(sih->module, bytes + 1,
sih->edr_offset, sih->bytes_edr);
if (status) {
pr_err("twl4030: %s, %s --> %d\n", __func__,
"read", status);
return;
}
/* Modify only the bits we know must change */
while (edge_change) {
int i = fls(edge_change) - 1;
struct irq_data *idata;
int byte = 1 + (i >> 2);
int off = (i & 0x3) * 2;
unsigned int type;
idata = irq_get_irq_data(i + agent->irq_base);
bytes[byte] &= ~(0x03 << off);
type = irqd_get_trigger_type(idata);
if (type & IRQ_TYPE_EDGE_RISING)
bytes[byte] |= BIT(off + 1);
if (type & IRQ_TYPE_EDGE_FALLING)
bytes[byte] |= BIT(off + 0);
edge_change &= ~BIT(i);
}
/* Write */
status = twl_i2c_write(sih->module, bytes,
sih->edr_offset, sih->bytes_edr);
if (status)
pr_err("twl4030: %s, %s --> %d\n", __func__,
"write", status);
}
mutex_unlock(&agent->irq_lock); mutex_unlock(&agent->irq_lock);
} }
@ -672,7 +660,6 @@ int twl4030_sih_setup(int module)
agent->sih = sih; agent->sih = sih;
agent->imr = ~0; agent->imr = ~0;
mutex_init(&agent->irq_lock); mutex_init(&agent->irq_lock);
INIT_WORK(&agent->edge_work, twl4030_sih_do_edge);
for (i = 0; i < sih->bits; i++) { for (i = 0; i < sih->bits; i++) {
irq = irq_base + i; irq = irq_base + i;
@ -720,12 +707,6 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
if (status < 0) if (status < 0)
return status; return status;
wq = create_singlethread_workqueue("twl4030-irqchip");
if (!wq) {
pr_err("twl4030: workqueue FAIL\n");
return -ESRCH;
}
twl4030_irq_base = irq_base; twl4030_irq_base = irq_base;
/* install an irq handler for each of the SIH modules; /* install an irq handler for each of the SIH modules;
@ -766,8 +747,7 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
fail: fail:
for (i = irq_base; i < irq_end; i++) for (i = irq_base; i < irq_end; i++)
irq_set_chip_and_handler(i, NULL, NULL); irq_set_chip_and_handler(i, NULL, NULL);
destroy_workqueue(wq);
wq = NULL;
return status; return status;
} }