aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/pm8921-core.c
diff options
context:
space:
mode:
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>2011-04-05 17:40:53 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2011-05-26 13:45:28 -0400
commitc013f0a56c56b88ac63c4037f2dfaaf2422fa863 (patch)
tree54d8e003ba72caf0cc9ff4fcf12cea2eb8727ea9 /drivers/mfd/pm8921-core.c
parentcbdb53e1f33baf60ded045dc79cd0dd4e9705fa5 (diff)
mfd: Add pm8xxx irq support
Add support for the irq controller in Qualcomm 8xxx pmic. The 8xxx interrupt controller provides control for gpio and mpp configured as interrupts in addition to other subdevice interrupts. The interrupt controller also provides a way to read the real time status of an interrupt. This real time status is the only way one can get the input values of gpio and mpp lines. Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/pm8921-core.c')
-rw-r--r--drivers/mfd/pm8921-core.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index a2ecd3233b1b..e873b15753d8 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -16,6 +16,7 @@
16#include <linux/kernel.h> 16#include <linux/kernel.h>
17#include <linux/platform_device.h> 17#include <linux/platform_device.h>
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/err.h>
19#include <linux/msm_ssbi.h> 20#include <linux/msm_ssbi.h>
20#include <linux/mfd/core.h> 21#include <linux/mfd/core.h>
21#include <linux/mfd/pm8xxx/pm8921.h> 22#include <linux/mfd/pm8xxx/pm8921.h>
@@ -26,6 +27,7 @@
26 27
27struct pm8921 { 28struct pm8921 {
28 struct device *dev; 29 struct device *dev;
30 struct pm_irq_chip *irq_chip;
29}; 31};
30 32
31static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) 33static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
@@ -62,19 +64,53 @@ static int pm8921_write_buf(const struct device *dev, u16 addr, u8 *buf,
62 return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt); 64 return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
63} 65}
64 66
67static int pm8921_read_irq_stat(const struct device *dev, int irq)
68{
69 const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
70 const struct pm8921 *pmic = pm8921_drvdata->pm_chip_data;
71
72 return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
73}
74
65static struct pm8xxx_drvdata pm8921_drvdata = { 75static struct pm8xxx_drvdata pm8921_drvdata = {
66 .pmic_readb = pm8921_readb, 76 .pmic_readb = pm8921_readb,
67 .pmic_writeb = pm8921_writeb, 77 .pmic_writeb = pm8921_writeb,
68 .pmic_read_buf = pm8921_read_buf, 78 .pmic_read_buf = pm8921_read_buf,
69 .pmic_write_buf = pm8921_write_buf, 79 .pmic_write_buf = pm8921_write_buf,
80 .pmic_read_irq_stat = pm8921_read_irq_stat,
70}; 81};
71 82
83static int __devinit pm8921_add_subdevices(const struct pm8921_platform_data
84 *pdata,
85 struct pm8921 *pmic,
86 u32 rev)
87{
88 int ret = 0, irq_base = 0;
89 struct pm_irq_chip *irq_chip;
90
91 if (pdata->irq_pdata) {
92 pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
93 pdata->irq_pdata->irq_cdata.rev = rev;
94 irq_base = pdata->irq_pdata->irq_base;
95 irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
96
97 if (IS_ERR(irq_chip)) {
98 pr_err("Failed to init interrupts ret=%ld\n",
99 PTR_ERR(irq_chip));
100 return PTR_ERR(irq_chip);
101 }
102 pmic->irq_chip = irq_chip;
103 }
104 return ret;
105}
106
72static int __devinit pm8921_probe(struct platform_device *pdev) 107static int __devinit pm8921_probe(struct platform_device *pdev)
73{ 108{
74 const struct pm8921_platform_data *pdata = pdev->dev.platform_data; 109 const struct pm8921_platform_data *pdata = pdev->dev.platform_data;
75 struct pm8921 *pmic; 110 struct pm8921 *pmic;
76 int rc; 111 int rc;
77 u8 val; 112 u8 val;
113 u32 rev;
78 114
79 if (!pdata) { 115 if (!pdata) {
80 pr_err("missing platform data\n"); 116 pr_err("missing platform data\n");
@@ -94,6 +130,7 @@ static int __devinit pm8921_probe(struct platform_device *pdev)
94 goto err_read_rev; 130 goto err_read_rev;
95 } 131 }
96 pr_info("PMIC revision 1: %02X\n", val); 132 pr_info("PMIC revision 1: %02X\n", val);
133 rev = val;
97 134
98 /* Read PMIC chip revision 2 */ 135 /* Read PMIC chip revision 2 */
99 rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val)); 136 rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
@@ -103,13 +140,26 @@ static int __devinit pm8921_probe(struct platform_device *pdev)
103 goto err_read_rev; 140 goto err_read_rev;
104 } 141 }
105 pr_info("PMIC revision 2: %02X\n", val); 142 pr_info("PMIC revision 2: %02X\n", val);
143 rev |= val << BITS_PER_BYTE;
106 144
107 pmic->dev = &pdev->dev; 145 pmic->dev = &pdev->dev;
108 pm8921_drvdata.pm_chip_data = pmic; 146 pm8921_drvdata.pm_chip_data = pmic;
109 platform_set_drvdata(pdev, &pm8921_drvdata); 147 platform_set_drvdata(pdev, &pm8921_drvdata);
110 148
149 rc = pm8921_add_subdevices(pdata, pmic, rev);
150 if (rc) {
151 pr_err("Cannot add subdevices rc=%d\n", rc);
152 goto err;
153 }
154
155 /* gpio might not work if no irq device is found */
156 WARN_ON(pmic->irq_chip == NULL);
157
111 return 0; 158 return 0;
112 159
160err:
161 mfd_remove_devices(pmic->dev);
162 platform_set_drvdata(pdev, NULL);
113err_read_rev: 163err_read_rev:
114 kfree(pmic); 164 kfree(pmic);
115 return rc; 165 return rc;
@@ -125,6 +175,10 @@ static int __devexit pm8921_remove(struct platform_device *pdev)
125 pmic = drvdata->pm_chip_data; 175 pmic = drvdata->pm_chip_data;
126 if (pmic) 176 if (pmic)
127 mfd_remove_devices(pmic->dev); 177 mfd_remove_devices(pmic->dev);
178 if (pmic->irq_chip) {
179 pm8xxx_irq_exit(pmic->irq_chip);
180 pmic->irq_chip = NULL;
181 }
128 platform_set_drvdata(pdev, NULL); 182 platform_set_drvdata(pdev, NULL);
129 kfree(pmic); 183 kfree(pmic);
130 184