mirror of https://gitee.com/openkylin/linux.git
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:
parent
848684246f
commit
2f2a7d5ef7
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue