aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/stmpe.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/stmpe.c')
-rw-r--r--drivers/mfd/stmpe.c105
1 files changed, 103 insertions, 2 deletions
diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c
index 4b11202061be..bbccd514d3ec 100644
--- a/drivers/mfd/stmpe.c
+++ b/drivers/mfd/stmpe.c
@@ -19,6 +19,7 @@
19#include <linux/pm.h> 19#include <linux/pm.h>
20#include <linux/slab.h> 20#include <linux/slab.h>
21#include <linux/mfd/core.h> 21#include <linux/mfd/core.h>
22#include <linux/delay.h>
22#include "stmpe.h" 23#include "stmpe.h"
23 24
24static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks) 25static int __stmpe_enable(struct stmpe *stmpe, unsigned int blocks)
@@ -643,6 +644,88 @@ static struct stmpe_variant_info stmpe1601 = {
643}; 644};
644 645
645/* 646/*
647 * STMPE1801
648 */
649static const u8 stmpe1801_regs[] = {
650 [STMPE_IDX_CHIP_ID] = STMPE1801_REG_CHIP_ID,
651 [STMPE_IDX_ICR_LSB] = STMPE1801_REG_INT_CTRL_LOW,
652 [STMPE_IDX_IER_LSB] = STMPE1801_REG_INT_EN_MASK_LOW,
653 [STMPE_IDX_ISR_LSB] = STMPE1801_REG_INT_STA_LOW,
654 [STMPE_IDX_GPMR_LSB] = STMPE1801_REG_GPIO_MP_LOW,
655 [STMPE_IDX_GPSR_LSB] = STMPE1801_REG_GPIO_SET_LOW,
656 [STMPE_IDX_GPCR_LSB] = STMPE1801_REG_GPIO_CLR_LOW,
657 [STMPE_IDX_GPDR_LSB] = STMPE1801_REG_GPIO_SET_DIR_LOW,
658 [STMPE_IDX_GPRER_LSB] = STMPE1801_REG_GPIO_RE_LOW,
659 [STMPE_IDX_GPFER_LSB] = STMPE1801_REG_GPIO_FE_LOW,
660 [STMPE_IDX_IEGPIOR_LSB] = STMPE1801_REG_INT_EN_GPIO_MASK_LOW,
661 [STMPE_IDX_ISGPIOR_LSB] = STMPE1801_REG_INT_STA_GPIO_LOW,
662};
663
664static struct stmpe_variant_block stmpe1801_blocks[] = {
665 {
666 .cell = &stmpe_gpio_cell,
667 .irq = STMPE1801_IRQ_GPIOC,
668 .block = STMPE_BLOCK_GPIO,
669 },
670 {
671 .cell = &stmpe_keypad_cell,
672 .irq = STMPE1801_IRQ_KEYPAD,
673 .block = STMPE_BLOCK_KEYPAD,
674 },
675};
676
677static int stmpe1801_enable(struct stmpe *stmpe, unsigned int blocks,
678 bool enable)
679{
680 unsigned int mask = 0;
681 if (blocks & STMPE_BLOCK_GPIO)
682 mask |= STMPE1801_MSK_INT_EN_GPIO;
683
684 if (blocks & STMPE_BLOCK_KEYPAD)
685 mask |= STMPE1801_MSK_INT_EN_KPC;
686
687 return __stmpe_set_bits(stmpe, STMPE1801_REG_INT_EN_MASK_LOW, mask,
688 enable ? mask : 0);
689}
690
691static int stmpe1801_reset(struct stmpe *stmpe)
692{
693 unsigned long timeout;
694 int ret = 0;
695
696 ret = __stmpe_set_bits(stmpe, STMPE1801_REG_SYS_CTRL,
697 STMPE1801_MSK_SYS_CTRL_RESET, STMPE1801_MSK_SYS_CTRL_RESET);
698 if (ret < 0)
699 return ret;
700
701 timeout = jiffies + msecs_to_jiffies(100);
702 while (time_before(jiffies, timeout)) {
703 ret = __stmpe_reg_read(stmpe, STMPE1801_REG_SYS_CTRL);
704 if (ret < 0)
705 return ret;
706 if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET))
707 return 0;
708 usleep_range(100, 200);
709 };
710 return -EIO;
711}
712
713static struct stmpe_variant_info stmpe1801 = {
714 .name = "stmpe1801",
715 .id_val = STMPE1801_ID,
716 .id_mask = 0xfff0,
717 .num_gpios = 18,
718 .af_bits = 0,
719 .regs = stmpe1801_regs,
720 .blocks = stmpe1801_blocks,
721 .num_blocks = ARRAY_SIZE(stmpe1801_blocks),
722 .num_irqs = STMPE1801_NR_INTERNAL_IRQS,
723 .enable = stmpe1801_enable,
724 /* stmpe1801 do not have any gpio alternate function */
725 .get_altfunc = NULL,
726};
727
728/*
646 * STMPE24XX 729 * STMPE24XX
647 */ 730 */
648 731
@@ -740,6 +823,7 @@ static struct stmpe_variant_info *stmpe_variant_info[STMPE_NBR_PARTS] = {
740 [STMPE801] = &stmpe801, 823 [STMPE801] = &stmpe801,
741 [STMPE811] = &stmpe811, 824 [STMPE811] = &stmpe811,
742 [STMPE1601] = &stmpe1601, 825 [STMPE1601] = &stmpe1601,
826 [STMPE1801] = &stmpe1801,
743 [STMPE2401] = &stmpe2401, 827 [STMPE2401] = &stmpe2401,
744 [STMPE2403] = &stmpe2403, 828 [STMPE2403] = &stmpe2403,
745}; 829};
@@ -759,7 +843,7 @@ static irqreturn_t stmpe_irq(int irq, void *data)
759 struct stmpe *stmpe = data; 843 struct stmpe *stmpe = data;
760 struct stmpe_variant_info *variant = stmpe->variant; 844 struct stmpe_variant_info *variant = stmpe->variant;
761 int num = DIV_ROUND_UP(variant->num_irqs, 8); 845 int num = DIV_ROUND_UP(variant->num_irqs, 8);
762 u8 israddr = stmpe->regs[STMPE_IDX_ISR_MSB]; 846 u8 israddr;
763 u8 isr[num]; 847 u8 isr[num];
764 int ret; 848 int ret;
765 int i; 849 int i;
@@ -771,6 +855,11 @@ static irqreturn_t stmpe_irq(int irq, void *data)
771 return IRQ_HANDLED; 855 return IRQ_HANDLED;
772 } 856 }
773 857
858 if (variant->id_val == STMPE1801_ID)
859 israddr = stmpe->regs[STMPE_IDX_ISR_LSB];
860 else
861 israddr = stmpe->regs[STMPE_IDX_ISR_MSB];
862
774 ret = stmpe_block_read(stmpe, israddr, num, isr); 863 ret = stmpe_block_read(stmpe, israddr, num, isr);
775 if (ret < 0) 864 if (ret < 0)
776 return IRQ_NONE; 865 return IRQ_NONE;
@@ -938,6 +1027,12 @@ static int stmpe_chip_init(struct stmpe *stmpe)
938 if (ret) 1027 if (ret)
939 return ret; 1028 return ret;
940 1029
1030 if (id == STMPE1801_ID) {
1031 ret = stmpe1801_reset(stmpe);
1032 if (ret < 0)
1033 return ret;
1034 }
1035
941 if (stmpe->irq >= 0) { 1036 if (stmpe->irq >= 0) {
942 if (id == STMPE801_ID) 1037 if (id == STMPE801_ID)
943 icr = STMPE801_REG_SYS_CTRL_INT_EN; 1038 icr = STMPE801_REG_SYS_CTRL_INT_EN;
@@ -1015,7 +1110,10 @@ void stmpe_of_probe(struct stmpe_platform_data *pdata, struct device_node *np)
1015{ 1110{
1016 struct device_node *child; 1111 struct device_node *child;
1017 1112
1018 pdata->id = -1; 1113 pdata->id = of_alias_get_id(np, "stmpe-i2c");
1114 if (pdata->id < 0)
1115 pdata->id = -1;
1116
1019 pdata->irq_trigger = IRQF_TRIGGER_NONE; 1117 pdata->irq_trigger = IRQF_TRIGGER_NONE;
1020 1118
1021 of_property_read_u32(np, "st,autosleep-timeout", 1119 of_property_read_u32(np, "st,autosleep-timeout",
@@ -1057,6 +1155,9 @@ int stmpe_probe(struct stmpe_client_info *ci, int partnum)
1057 return -ENOMEM; 1155 return -ENOMEM;
1058 1156
1059 stmpe_of_probe(pdata, np); 1157 stmpe_of_probe(pdata, np);
1158
1159 if (of_find_property(np, "interrupts", NULL) == NULL)
1160 ci->irq = -1;
1060 } 1161 }
1061 1162
1062 stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL); 1163 stmpe = devm_kzalloc(ci->dev, sizeof(struct stmpe), GFP_KERNEL);