mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 15:29:16 +00:00
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: Bhupesh Sharma <bhupesh.sharma@st.com> Signed-off-by: Pratyush Anand <pratyush.anand@st.com> Signed-off-by: Viresh Kumar <viresh.kumar@st.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
This commit is contained in:
parent
1cda2394e9
commit
7f7f4ea15e
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user