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),
|
.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)
|
* 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,
|
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
|
||||||
bool enable)
|
bool enable)
|
||||||
{
|
{
|
||||||
|
@ -367,6 +379,17 @@ static struct stmpe_variant_info stmpe801 = {
|
||||||
.enable = stmpe801_enable,
|
.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)
|
* Touchscreen (STMPE811 or STMPE610)
|
||||||
*/
|
*/
|
||||||
|
@ -712,7 +735,7 @@ static struct stmpe_variant_info stmpe2403 = {
|
||||||
.enable_autosleep = stmpe1601_autosleep, /* same as stmpe1601 */
|
.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,
|
[STMPE610] = &stmpe610,
|
||||||
[STMPE801] = &stmpe801,
|
[STMPE801] = &stmpe801,
|
||||||
[STMPE811] = &stmpe811,
|
[STMPE811] = &stmpe811,
|
||||||
|
@ -721,6 +744,16 @@ static struct stmpe_variant_info *stmpe_variant_info[] = {
|
||||||
[STMPE2403] = &stmpe2403,
|
[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)
|
static irqreturn_t stmpe_irq(int irq, void *data)
|
||||||
{
|
{
|
||||||
struct stmpe *stmpe = 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;
|
unsigned int irq_trigger = stmpe->pdata->irq_trigger;
|
||||||
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
|
int autosleep_timeout = stmpe->pdata->autosleep_timeout;
|
||||||
struct stmpe_variant_info *variant = stmpe->variant;
|
struct stmpe_variant_info *variant = stmpe->variant;
|
||||||
u8 icr;
|
u8 icr = 0;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
u8 data[2];
|
u8 data[2];
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -887,31 +920,33 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (id == STMPE801_ID)
|
if (stmpe->irq >= 0) {
|
||||||
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 (id == STMPE801_ID)
|
if (id == STMPE801_ID)
|
||||||
icr |= STMPE801_REG_SYS_CTRL_INT_HI;
|
icr = STMPE801_REG_SYS_CTRL_INT_EN;
|
||||||
else
|
else
|
||||||
icr |= STMPE_ICR_LSB_HIGH;
|
icr = STMPE_ICR_LSB_GIM;
|
||||||
}
|
|
||||||
|
|
||||||
if (stmpe->pdata->irq_invert_polarity) {
|
/* STMPE801 doesn't support Edge interrupts */
|
||||||
if (id == STMPE801_ID)
|
if (id != STMPE801_ID) {
|
||||||
icr ^= STMPE801_REG_SYS_CTRL_INT_HI;
|
if (irq_trigger == IRQF_TRIGGER_FALLING ||
|
||||||
else
|
irq_trigger == IRQF_TRIGGER_RISING)
|
||||||
icr ^= STMPE_ICR_LSB_HIGH;
|
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) {
|
if (stmpe->pdata->autosleep) {
|
||||||
|
@ -1001,19 +1036,38 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||||
stmpe->irq = ci->irq;
|
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);
|
ret = stmpe_chip_init(stmpe);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_gpio;
|
goto free_gpio;
|
||||||
|
|
||||||
ret = stmpe_irq_init(stmpe);
|
if (stmpe->irq >= 0) {
|
||||||
if (ret)
|
ret = stmpe_irq_init(stmpe);
|
||||||
goto free_gpio;
|
if (ret)
|
||||||
|
goto free_gpio;
|
||||||
|
|
||||||
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
|
ret = request_threaded_irq(stmpe->irq, NULL, stmpe_irq,
|
||||||
pdata->irq_trigger | IRQF_ONESHOT, "stmpe", stmpe);
|
pdata->irq_trigger | IRQF_ONESHOT,
|
||||||
if (ret) {
|
"stmpe", stmpe);
|
||||||
dev_err(stmpe->dev, "failed to request IRQ: %d\n", ret);
|
if (ret) {
|
||||||
goto out_removeirq;
|
dev_err(stmpe->dev, "failed to request IRQ: %d\n",
|
||||||
|
ret);
|
||||||
|
goto out_removeirq;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = stmpe_devices_init(stmpe);
|
ret = stmpe_devices_init(stmpe);
|
||||||
|
@ -1026,9 +1080,11 @@ int __devinit stmpe_probe(struct stmpe_client_info *ci, int partnum)
|
||||||
|
|
||||||
out_removedevs:
|
out_removedevs:
|
||||||
mfd_remove_devices(stmpe->dev);
|
mfd_remove_devices(stmpe->dev);
|
||||||
free_irq(stmpe->irq, stmpe);
|
if (stmpe->irq >= 0)
|
||||||
|
free_irq(stmpe->irq, stmpe);
|
||||||
out_removeirq:
|
out_removeirq:
|
||||||
stmpe_irq_remove(stmpe);
|
if (stmpe->irq >= 0)
|
||||||
|
stmpe_irq_remove(stmpe);
|
||||||
free_gpio:
|
free_gpio:
|
||||||
if (pdata->irq_over_gpio)
|
if (pdata->irq_over_gpio)
|
||||||
gpio_free(pdata->irq_gpio);
|
gpio_free(pdata->irq_gpio);
|
||||||
|
@ -1041,8 +1097,10 @@ int stmpe_remove(struct stmpe *stmpe)
|
||||||
{
|
{
|
||||||
mfd_remove_devices(stmpe->dev);
|
mfd_remove_devices(stmpe->dev);
|
||||||
|
|
||||||
free_irq(stmpe->irq, stmpe);
|
if (stmpe->irq >= 0) {
|
||||||
stmpe_irq_remove(stmpe);
|
free_irq(stmpe->irq, stmpe);
|
||||||
|
stmpe_irq_remove(stmpe);
|
||||||
|
}
|
||||||
|
|
||||||
if (stmpe->pdata->irq_over_gpio)
|
if (stmpe->pdata->irq_over_gpio)
|
||||||
gpio_free(stmpe->pdata->irq_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);
|
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);
|
enable_irq_wake(stmpe->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1067,7 +1125,7 @@ static int stmpe_resume(struct device *dev)
|
||||||
{
|
{
|
||||||
struct stmpe *stmpe = dev_get_drvdata(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);
|
disable_irq_wake(stmpe->irq);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum stmpe_partnum {
|
||||||
STMPE1601,
|
STMPE1601,
|
||||||
STMPE2401,
|
STMPE2401,
|
||||||
STMPE2403,
|
STMPE2403,
|
||||||
|
STMPE_NBR_PARTS
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
Loading…
Reference in a new issue