mfd: Add support for no-interrupt stmpe config
Adds support for boards which have an STMPE device without the interrupt pin connected. Acked-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Chris Blair <chris.blair@stericsson.com> Tested-by: Michel Jaouen <michel.jaouen@stericsson.com> Reviewed-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Acked-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
0dc299a3c4
commit
e31f9b8264
2 changed files with 97 additions and 38 deletions
|
@ -298,6 +298,11 @@ static struct mfd_cell stmpe_gpio_cell = {
|
|||
.num_resources = ARRAY_SIZE(stmpe_gpio_resources),
|
||||
};
|
||||
|
||||
static struct mfd_cell stmpe_gpio_cell_noirq = {
|
||||
.name = "stmpe-gpio",
|
||||
/* gpio cell resources consist of an irq only so no resources here */
|
||||
};
|
||||
|
||||
/*
|
||||
* Keypad (1601, 2401, 2403)
|
||||
*/
|
||||
|
@ -346,6 +351,13 @@ static struct stmpe_variant_block stmpe801_blocks[] = {
|
|||
},
|
||||
};
|
||||
|
||||
static struct stmpe_variant_block stmpe801_blocks_noirq[] = {
|
||||
{
|
||||
.cell = &stmpe_gpio_cell_noirq,
|
||||
.block = STMPE_BLOCK_GPIO,
|
||||
},
|
||||
};
|
||||
|
||||
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
|
||||
bool enable)
|
||||
{
|
||||
|
@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
|
|||
.enable = stmpe801_enable,
|
||||
};
|
||||
|
||||
static struct stmpe_variant_info stmpe801_noirq = {
|
||||
.name = "stmpe801",
|
||||
.id_val = STMPE801_ID,
|
||||
.id_mask = 0xffff,
|
||||
.num_gpios = 8,
|
||||
.regs = stmpe801_regs,
|
||||
.blocks = stmpe801_blocks_noirq,
|
||||
.num_blocks = ARRAY_SIZE(stmpe801_blocks_noirq),
|
||||
.enable = stmpe801_enable,
|
||||
};
|
||||
|
||||
/*
|
||||
* Touchscreen (STMPE811 or STMPE610)
|
||||
*/
|
||||
|
@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
|
|||
.enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
|
||||
};
|
||||
|
||||
static struct stmpe_variant_info *stmpe_variant_info[] = {
|
||||
static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
|
||||
[STMPE610] = &stmpe610,
|
||||
[STMPE801] = &stmpe801,
|
||||
[STMPE811] = &stmpe811,
|
||||
|
@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
|
|||
[STMPE2403] = &stmpe2403,
|
||||
};
|
||||
|
||||
/*
|
||||
* These devices can be connected in a 'no-irq' configuration - the irq pin
|
||||
* is not used and the device cannot interrupt the CPU. Here we only list
|
||||
* devices which support this configuration - the driver will fail probing
|
||||
* for any devices not listed here which are configured in this way.
|
||||
*/
|
||||
static struct stmpe_variant_info *stmpe_noirq_variant_info[STMPE_NBR_PARTS] = {
|
||||
[STMPE801] = &stmpe801_noirq,
|
||||
};
|
||||
|
||||
static irqreturn_t stmpe_irq(int irq, void *data)
|
||||
{
|
||||
struct stmpe *stmpe = data;
|
||||
|
@ -864,7 +897,7 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
|
|||
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
|
||||
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
|
||||
struct stmpe_variant_info *variant = stmpe->variant;
|
||||
u8 icr;
|
||||
u8 icr = 0;
|
||||
unsigned int id;
|
||||
u8 data[2];
|
||||
int ret;
|
||||
|
@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (id == STMPE801_ID)
|
||||
icr = STMPE801_REG_SYS_CTRL_INT_EN;
|
||||
else
|
||||
icr = STMPE_ICR_LSB_GIM;
|
||||
|
||||
/* STMPE801 doesn't support Edge interrupts */
|
||||
if (id != STMPE801_ID) {
|
||||
if (irq_trigger == IRQF_TRIGGER_FALLING ||
|
||||
irq_trigger == IRQF_TRIGGER_RISING)
|
||||
icr |= STMPE_ICR_LSB_EDGE;
|
||||
}
|
||||
|
||||
if (irq_trigger == IRQF_TRIGGER_RISING ||
|
||||
irq_trigger == IRQF_TRIGGER_HIGH) {
|
||||
if (stmpe->irq >= 0) {
|
||||
if (id == STMPE801_ID)
|
||||
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
|
||||
icr = STMPE801_REG_SYS_CTRL_INT_EN;
|
||||
else
|
||||
icr |= STMPE_ICR_LSB_HIGH;
|
||||
}
|
||||
icr = STMPE_ICR_LSB_GIM;
|
||||
|
||||
if (stmpe->pdata->irq_invert_polarity) {
|
||||
if (id == STMPE801_ID)
|
||||
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
|
||||
else
|
||||
icr ^= STMPE_ICR_LSB_HIGH;
|
||||
/* STMPE801 doesn't support Edge interrupts */
|
||||
if (id != STMPE801_ID) {
|
||||
if (irq_trigger == IRQF_TRIGGER_FALLING ||
|
||||
irq_trigger == IRQF_TRIGGER_RISING)
|
||||
icr |= STMPE_ICR_LSB_EDGE;
|
||||
}
|
||||
|
||||
if (irq_trigger == IRQF_TRIGGER_RISING ||
|
||||
irq_trigger == IRQF_TRIGGER_HIGH) {
|
||||
if (id == STMPE801_ID)
|
||||
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
|
||||
else
|
||||
icr |= STMPE_ICR_LSB_HIGH;
|
||||
}
|
||||
|
||||
if (stmpe->pdata->irq_invert_polarity) {
|
||||
if (id == STMPE801_ID)
|
||||
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
|
||||
else
|
||||
icr ^= STMPE_ICR_LSB_HIGH;
|
||||
}
|
||||
}
|
||||
|
||||
if (stmpe->pdata->autosleep) {
|
||||
|
@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
|||
stmpe->irq = ci->irq;
|
||||
}
|
||||
|
||||
if (stmpe->irq < 0) {
|
||||
/* use alternate variant info for no-irq mode, if supported */
|
||||
dev_info(stmpe->dev,
|
||||
"%s configured in no-irq mode by platform data\n",
|
||||
stmpe->variant->name);
|
||||
if (!stmpe_noirq_variant_info[stmpe->partnum]) {
|
||||
dev_err(stmpe->dev,
|
||||
"%s does not support no-irq mode!\n",
|
||||
stmpe->variant->name);
|
||||
ret = -ENODEV;
|
||||
goto free_gpio;
|
||||
}
|
||||
stmpe->variant = stmpe_noirq_variant_info[stmpe->partnum];
|
||||
}
|
||||
|
||||
ret = stmpe_chip_init(stmpe);
|
||||
if (ret)
|
||||
goto free_gpio;
|
||||
|
||||
ret = stmpe_irq_init(stmpe);
|
||||
if (ret)
|
||||
goto free_gpio;
|
||||
if (stmpe->irq >= 0) {
|
||||
ret = stmpe_irq_init(stmpe);
|
||||
if (ret)
|
||||
goto free_gpio;
|
||||
|
||||
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
|
||||
pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
|
||||
if (ret) {
|
||||
dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
|
||||
goto out_removeirq;
|
||||
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
|
||||
pdata->irq_trigger | IRQF_ONESHOT,
|
||||
"stmpe", stmpe);
|
||||
if (ret) {
|
||||
dev_err(stmpe->dev, "failed to request IRQ: %d\n",
|
||||
ret);
|
||||
goto out_removeirq;
|
||||
}
|
||||
}
|
||||
|
||||
ret = stmpe_devices_init(stmpe);
|
||||
|
@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
|||
|
||||
out_removedevs:
|
||||
mfd_remove_devices(stmpe->dev);
|
||||
free_irq(stmpe->irq, stmpe);
|
||||
if (stmpe->irq >= 0)
|
||||
free_irq(stmpe->irq, stmpe);
|
||||
out_removeirq:
|
||||
stmpe_irq_remove(stmpe);
|
||||
if (stmpe->irq >= 0)
|
||||
stmpe_irq_remove(stmpe);
|
||||
free_gpio:
|
||||
if (pdata->irq_over_gpio)
|
||||
gpio_free(pdata->irq_gpio);
|
||||
|
@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
|
|||
{
|
||||
mfd_remove_devices(stmpe->dev);
|
||||
|
||||
free_irq(stmpe->irq, stmpe);
|
||||
stmpe_irq_remove(stmpe);
|
||||
if (stmpe->irq >= 0) {
|
||||
free_irq(stmpe->irq, stmpe);
|
||||
stmpe_irq_remove(stmpe);
|
||||
}
|
||||
|
||||
if (stmpe->pdata->irq_over_gpio)
|
||||
gpio_free(stmpe->pdata->irq_gpio);
|
||||
|
@ -1057,7 +1115,7 @@ static int stmpe_suspend(struct device *dev)
|
|||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
if (stmpe->irq >= 0 && device_may_wakeup(dev))
|
||||
enable_irq_wake(stmpe->irq);
|
||||
|
||||
return 0;
|
||||
|
@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
|
|||
{
|
||||
struct stmpe *stmpe = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
if (stmpe->irq >= 0 && device_may_wakeup(dev))
|
||||
disable_irq_wake(stmpe->irq);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -26,6 +26,7 @@ enum stmpe_partnum {
|
|||
STMPE1601,
|
||||
STMPE2401,
|
||||
STMPE2403,
|
||||
STMPE_NBR_PARTS
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue