Commit 7f7f4ea1 authored by Viresh Kumar's avatar Viresh Kumar Committed by Samuel Ortiz

mfd: Add support for stmpe variant 801

STMPE801 is a GPIO expander. Registers for 801 are much different from other
variants. This patch adds support for STMPE801 in stmpe mfd driver.
Signed-off-by: default avatarBhupesh Sharma <bhupesh.sharma@st.com>
Signed-off-by: default avatarPratyush Anand <pratyush.anand@st.com>
Signed-off-by: default avatarViresh Kumar <viresh.kumar@st.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
parent 1cda2394
......@@ -72,6 +72,7 @@ static int __devexit stmpe_i2c_remove(struct i2c_client *i2c)
static const struct i2c_device_id stmpe_i2c_id[] = {
{ "stmpe610", STMPE610 },
{ "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 },
{ "stmpe2401", STMPE2401 },
......
......@@ -110,6 +110,7 @@ static int __devexit stmpe_spi_remove(struct spi_device *spi)
static const struct spi_device_id stmpe_spi_id[] = {
{ "stmpe610", STMPE610 },
{ "stmpe801", STMPE801 },
{ "stmpe811", STMPE811 },
{ "stmpe1601", STMPE1601 },
{ "stmpe2401", STMPE2401 },
......
......@@ -241,12 +241,14 @@ int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins, enum stmpe_block block)
u8 regaddr = stmpe->regs[STMPE_IDX_GPAFR_U_MSB];
int af_bits = variant->af_bits;
int numregs = DIV_ROUND_UP(stmpe->num_gpios * af_bits, 8);
int afperreg = 8 / af_bits;
int mask = (1 << af_bits) - 1;
u8 regs[numregs];
int af;
int ret;
int af, afperreg, ret;
if (!variant->get_altfunc)
return 0;
afperreg = 8 / af_bits;
mutex_lock(&stmpe->lock);
ret = __stmpe_enable(stmpe, STMPE_BLOCK_GPIO);
......@@ -320,6 +322,50 @@ static struct mfd_cell stmpe_keypad_cell = {
.num_resources = ARRAY_SIZE(stmpe_keypad_resources),
};
/*
* STMPE801
*/
static const u8 stmpe801_regs[] = {
[STMPE_IDX_CHIP_ID] = STMPE801_REG_CHIP_ID,
[STMPE_IDX_ICR_LSB] = STMPE801_REG_SYS_CTRL,
[STMPE_IDX_GPMR_LSB] = STMPE801_REG_GPIO_MP_STA,
[STMPE_IDX_GPSR_LSB] = STMPE801_REG_GPIO_SET_PIN,
[STMPE_IDX_GPCR_LSB] = STMPE801_REG_GPIO_SET_PIN,
[STMPE_IDX_GPDR_LSB] = STMPE801_REG_GPIO_DIR,
[STMPE_IDX_IEGPIOR_LSB] = STMPE801_REG_GPIO_INT_EN,
[STMPE_IDX_ISGPIOR_MSB] = STMPE801_REG_GPIO_INT_STA,
};
static struct stmpe_variant_block stmpe801_blocks[] = {
{
.cell = &stmpe_gpio_cell,
.irq = 0,
.block = STMPE_BLOCK_GPIO,
},
};
static int stmpe801_enable(struct stmpe *stmpe, unsigned int blocks,
bool enable)
{
if (blocks & STMPE_BLOCK_GPIO)
return 0;
else
return -EINVAL;
}
static struct stmpe_variant_info stmpe801 = {
.name = "stmpe801",
.id_val = STMPE801_ID,
.id_mask = 0xffff,
.num_gpios = 8,
.regs = stmpe801_regs,
.blocks = stmpe801_blocks,
.num_blocks = ARRAY_SIZE(stmpe801_blocks),
.num_irqs = STMPE801_NR_INTERNAL_IRQS,
.enable = stmpe801_enable,
};
/*
* Touchscreen (STMPE811 or STMPE610)
*/
......@@ -667,6 +713,7 @@ static struct stmpe_variant_info stmpe2403 = {
static struct stmpe_variant_info *stmpe_variant_info[] = {
[STMPE610] = &stmpe610,
[STMPE801] = &stmpe801,
[STMPE811] = &stmpe811,
[STMPE1601] = &stmpe1601,
[STMPE2401] = &stmpe2401,
......@@ -683,6 +730,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
int ret;
int i;
if (variant->id_val == STMPE801_ID) {
handle_nested_irq(stmpe->irq_base);
return IRQ_HANDLED;
}
ret = stmpe_block_read(stmpe, israddr, num, isr);
if (ret < 0)
return IRQ_NONE;
......@@ -769,14 +821,17 @@ static struct irq_chip stmpe_irq_chip = {
static int __devinit stmpe_irq_init(struct stmpe *stmpe)
{
struct irq_chip *chip = NULL;
int num_irqs = stmpe->variant->num_irqs;
int base = stmpe->irq_base;
int irq;
if (stmpe->variant->id_val != STMPE801_ID)
chip = &stmpe_irq_chip;
for (irq = base; irq < base + num_irqs; irq++) {
irq_set_chip_data(irq, stmpe);
irq_set_chip_and_handler(irq, &stmpe_irq_chip,
handle_edge_irq);
irq_set_chip_and_handler(irq, chip, handle_edge_irq);
irq_set_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
......@@ -808,7 +863,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 = STMPE_ICR_LSB_GIM;
u8 icr;
unsigned int id;
u8 data[2];
int ret;
......@@ -831,16 +886,32 @@ static int __devinit stmpe_chip_init(struct stmpe *stmpe)
if (ret)
return ret;
if (irq_trigger == IRQF_TRIGGER_FALLING ||
irq_trigger == IRQF_TRIGGER_RISING)
icr |= STMPE_ICR_LSB_EDGE;
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)
icr |= STMPE_ICR_LSB_HIGH;
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)
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) {
ret = stmpe_autosleep(stmpe, autosleep_timeout);
......
......@@ -104,6 +104,25 @@ int stmpe_remove(struct stmpe *stmpe);
#define STMPE_ICR_LSB_EDGE (1 << 1)
#define STMPE_ICR_LSB_GIM (1 << 0)
/*
* STMPE801
*/
#define STMPE801_ID 0x0108
#define STMPE801_NR_INTERNAL_IRQS 1
#define STMPE801_REG_CHIP_ID 0x00
#define STMPE801_REG_VERSION_ID 0x02
#define STMPE801_REG_SYS_CTRL 0x04
#define STMPE801_REG_GPIO_INT_EN 0x08
#define STMPE801_REG_GPIO_INT_STA 0x09
#define STMPE801_REG_GPIO_MP_STA 0x10
#define STMPE801_REG_GPIO_SET_PIN 0x11
#define STMPE801_REG_GPIO_DIR 0x12
#define STMPE801_REG_SYS_CTRL_RESET (1 << 7)
#define STMPE801_REG_SYS_CTRL_INT_EN (1 << 2)
#define STMPE801_REG_SYS_CTRL_INT_HI (1 << 0)
/*
* STMPE811
*/
......
......@@ -21,6 +21,7 @@ enum stmpe_block {
enum stmpe_partnum {
STMPE610,
STMPE801,
STMPE811,
STMPE1601,
STMPE2401,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment