aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/pm8921-core.c54
-rw-r--r--drivers/mfd/pm8xxx-irq.c371
-rw-r--r--include/linux/mfd/pm8xxx/core.h10
-rw-r--r--include/linux/mfd/pm8xxx/irq.h59
-rw-r--r--include/linux/mfd/pm8xxx/pm8921.h4
7 files changed, 509 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index d42328873dc..8344fc0ab85 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -709,6 +709,16 @@ config MFD_PM8921_CORE
709 Say M here if you want to include support for PM8921 chip as a module. 709 Say M here if you want to include support for PM8921 chip as a module.
710 This will build a module called "pm8921-core". 710 This will build a module called "pm8921-core".
711 711
712config MFD_PM8XXX_IRQ
713 bool "Support for Qualcomm PM8xxx IRQ features"
714 depends on MFD_PM8XXX
715 default y if MFD_PM8XXX
716 help
717 This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
718
719 This is required to use certain other PM 8xxx features, such as GPIO
720 and MPP.
721
712endif # MFD_SUPPORT 722endif # MFD_SUPPORT
713 723
714menu "Multimedia Capabilities Port drivers" 724menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index d32a7b8f57f..1acb8f29a96 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -92,3 +92,4 @@ obj-$(CONFIG_MFD_WL1273_CORE) += wl1273-core.o
92obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o 92obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
93obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o 93obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o
94obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o 94obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
95obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index a2ecd3233b1..e873b15753d 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
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
new file mode 100644
index 00000000000..d452dd01308
--- /dev/null
+++ b/drivers/mfd/pm8xxx-irq.c
@@ -0,0 +1,371 @@
1/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/err.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19#include <linux/kernel.h>
20#include <linux/mfd/pm8xxx/core.h>
21#include <linux/mfd/pm8xxx/irq.h>
22#include <linux/platform_device.h>
23#include <linux/slab.h>
24
25/* PMIC8xxx IRQ */
26
27#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
28
29#define SSBI_REG_ADDR_IRQ_ROOT (SSBI_REG_ADDR_IRQ_BASE + 0)
30#define SSBI_REG_ADDR_IRQ_M_STATUS1 (SSBI_REG_ADDR_IRQ_BASE + 1)
31#define SSBI_REG_ADDR_IRQ_M_STATUS2 (SSBI_REG_ADDR_IRQ_BASE + 2)
32#define SSBI_REG_ADDR_IRQ_M_STATUS3 (SSBI_REG_ADDR_IRQ_BASE + 3)
33#define SSBI_REG_ADDR_IRQ_M_STATUS4 (SSBI_REG_ADDR_IRQ_BASE + 4)
34#define SSBI_REG_ADDR_IRQ_BLK_SEL (SSBI_REG_ADDR_IRQ_BASE + 5)
35#define SSBI_REG_ADDR_IRQ_IT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 6)
36#define SSBI_REG_ADDR_IRQ_CONFIG (SSBI_REG_ADDR_IRQ_BASE + 7)
37#define SSBI_REG_ADDR_IRQ_RT_STATUS (SSBI_REG_ADDR_IRQ_BASE + 8)
38
39#define PM_IRQF_LVL_SEL 0x01 /* level select */
40#define PM_IRQF_MASK_FE 0x02 /* mask falling edge */
41#define PM_IRQF_MASK_RE 0x04 /* mask rising edge */
42#define PM_IRQF_CLR 0x08 /* clear interrupt */
43#define PM_IRQF_BITS_MASK 0x70
44#define PM_IRQF_BITS_SHIFT 4
45#define PM_IRQF_WRITE 0x80
46
47#define PM_IRQF_MASK_ALL (PM_IRQF_MASK_FE | \
48 PM_IRQF_MASK_RE)
49
50struct pm_irq_chip {
51 struct device *dev;
52 spinlock_t pm_irq_lock;
53 unsigned int devirq;
54 unsigned int irq_base;
55 unsigned int num_irqs;
56 unsigned int num_blocks;
57 unsigned int num_masters;
58 u8 config[0];
59};
60
61static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
62{
63 return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
64}
65
66static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
67{
68 return pm8xxx_readb(chip->dev,
69 SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
70}
71
72static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
73{
74 int rc;
75
76 spin_lock(&chip->pm_irq_lock);
77 rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
78 if (rc) {
79 pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
80 goto bail;
81 }
82
83 rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
84 if (rc)
85 pr_err("Failed Reading Status rc=%d\n", rc);
86bail:
87 spin_unlock(&chip->pm_irq_lock);
88 return rc;
89}
90
91static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
92{
93 int rc;
94
95 spin_lock(&chip->pm_irq_lock);
96 rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
97 if (rc) {
98 pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
99 goto bail;
100 }
101
102 cp |= PM_IRQF_WRITE;
103 rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
104 if (rc)
105 pr_err("Failed Configuring IRQ rc=%d\n", rc);
106bail:
107 spin_unlock(&chip->pm_irq_lock);
108 return rc;
109}
110
111static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
112{
113 int pmirq, irq, i, ret = 0;
114 u8 bits;
115
116 ret = pm8xxx_read_block_irq(chip, block, &bits);
117 if (ret) {
118 pr_err("Failed reading %d block ret=%d", block, ret);
119 return ret;
120 }
121 if (!bits) {
122 pr_err("block bit set in master but no irqs: %d", block);
123 return 0;
124 }
125
126 /* Check IRQ bits */
127 for (i = 0; i < 8; i++) {
128 if (bits & (1 << i)) {
129 pmirq = block * 8 + i;
130 irq = pmirq + chip->irq_base;
131 generic_handle_irq(irq);
132 }
133 }
134 return 0;
135}
136
137static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
138{
139 u8 blockbits;
140 int block_number, i, ret = 0;
141
142 ret = pm8xxx_read_master_irq(chip, master, &blockbits);
143 if (ret) {
144 pr_err("Failed to read master %d ret=%d\n", master, ret);
145 return ret;
146 }
147 if (!blockbits) {
148 pr_err("master bit set in root but no blocks: %d", master);
149 return 0;
150 }
151
152 for (i = 0; i < 8; i++)
153 if (blockbits & (1 << i)) {
154 block_number = master * 8 + i; /* block # */
155 ret |= pm8xxx_irq_block_handler(chip, block_number);
156 }
157 return ret;
158}
159
160static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
161{
162 struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
163 struct irq_chip *irq_chip = irq_desc_get_chip(desc);
164 u8 root;
165 int i, ret, masters = 0;
166
167 ret = pm8xxx_read_root_irq(chip, &root);
168 if (ret) {
169 pr_err("Can't read root status ret=%d\n", ret);
170 return;
171 }
172
173 /* on pm8xxx series masters start from bit 1 of the root */
174 masters = root >> 1;
175
176 /* Read allowed masters for blocks. */
177 for (i = 0; i < chip->num_masters; i++)
178 if (masters & (1 << i))
179 pm8xxx_irq_master_handler(chip, i);
180
181 irq_chip->irq_ack(&desc->irq_data);
182}
183
184static void pm8xxx_irq_mask_ack(struct irq_data *d)
185{
186 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
187 unsigned int pmirq = d->irq - chip->irq_base;
188 int master, irq_bit;
189 u8 block, config;
190
191 block = pmirq / 8;
192 master = block / 8;
193 irq_bit = pmirq % 8;
194
195 config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
196 pm8xxx_config_irq(chip, block, config);
197}
198
199static void pm8xxx_irq_unmask(struct irq_data *d)
200{
201 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
202 unsigned int pmirq = d->irq - chip->irq_base;
203 int master, irq_bit;
204 u8 block, config;
205
206 block = pmirq / 8;
207 master = block / 8;
208 irq_bit = pmirq % 8;
209
210 config = chip->config[pmirq];
211 pm8xxx_config_irq(chip, block, config);
212}
213
214static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
215{
216 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
217 unsigned int pmirq = d->irq - chip->irq_base;
218 int master, irq_bit;
219 u8 block, config;
220
221 block = pmirq / 8;
222 master = block / 8;
223 irq_bit = pmirq % 8;
224
225 chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
226 | PM_IRQF_MASK_ALL;
227 if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
228 if (flow_type & IRQF_TRIGGER_RISING)
229 chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
230 if (flow_type & IRQF_TRIGGER_FALLING)
231 chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
232 } else {
233 chip->config[pmirq] |= PM_IRQF_LVL_SEL;
234
235 if (flow_type & IRQF_TRIGGER_HIGH)
236 chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
237 else
238 chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
239 }
240
241 config = chip->config[pmirq] | PM_IRQF_CLR;
242 return pm8xxx_config_irq(chip, block, config);
243}
244
245static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
246{
247 return 0;
248}
249
250static struct irq_chip pm8xxx_irq_chip = {
251 .name = "pm8xxx",
252 .irq_mask_ack = pm8xxx_irq_mask_ack,
253 .irq_unmask = pm8xxx_irq_unmask,
254 .irq_set_type = pm8xxx_irq_set_type,
255 .irq_set_wake = pm8xxx_irq_set_wake,
256 .flags = IRQCHIP_MASK_ON_SUSPEND,
257};
258
259/**
260 * pm8xxx_get_irq_stat - get the status of the irq line
261 * @chip: pointer to identify a pmic irq controller
262 * @irq: the irq number
263 *
264 * The pm8xxx gpio and mpp rely on the interrupt block to read
265 * the values on their pins. This function is to facilitate reading
266 * the status of a gpio or an mpp line. The caller has to convert the
267 * gpio number to irq number.
268 *
269 * RETURNS:
270 * an int indicating the value read on that line
271 */
272int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
273{
274 int pmirq, rc;
275 u8 block, bits, bit;
276 unsigned long flags;
277
278 if (chip == NULL || irq < chip->irq_base ||
279 irq >= chip->irq_base + chip->num_irqs)
280 return -EINVAL;
281
282 pmirq = irq - chip->irq_base;
283
284 block = pmirq / 8;
285 bit = pmirq % 8;
286
287 spin_lock_irqsave(&chip->pm_irq_lock, flags);
288
289 rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
290 if (rc) {
291 pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
292 irq, pmirq, block, rc);
293 goto bail_out;
294 }
295
296 rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
297 if (rc) {
298 pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
299 irq, pmirq, block, rc);
300 goto bail_out;
301 }
302
303 rc = (bits & (1 << bit)) ? 1 : 0;
304
305bail_out:
306 spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
307
308 return rc;
309}
310EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
311
312struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
313 const struct pm8xxx_irq_platform_data *pdata)
314{
315 struct pm_irq_chip *chip;
316 int devirq, rc;
317 unsigned int pmirq;
318
319 if (!pdata) {
320 pr_err("No platform data\n");
321 return ERR_PTR(-EINVAL);
322 }
323
324 devirq = pdata->devirq;
325 if (devirq < 0) {
326 pr_err("missing devirq\n");
327 rc = devirq;
328 return ERR_PTR(-EINVAL);
329 }
330
331 chip = kzalloc(sizeof(struct pm_irq_chip)
332 + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
333 if (!chip) {
334 pr_err("Cannot alloc pm_irq_chip struct\n");
335 return ERR_PTR(-EINVAL);
336 }
337
338 chip->dev = dev;
339 chip->devirq = devirq;
340 chip->irq_base = pdata->irq_base;
341 chip->num_irqs = pdata->irq_cdata.nirqs;
342 chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
343 chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
344 spin_lock_init(&chip->pm_irq_lock);
345
346 for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
347 irq_set_chip_and_handler(chip->irq_base + pmirq,
348 &pm8xxx_irq_chip,
349 handle_level_irq);
350 irq_set_chip_data(chip->irq_base + pmirq, chip);
351#ifdef CONFIG_ARM
352 set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
353#else
354 irq_set_noprobe(chip->irq_base + pmirq);
355#endif
356 }
357
358 irq_set_irq_type(devirq, pdata->irq_trigger_flag);
359 irq_set_handler_data(devirq, chip);
360 irq_set_chained_handler(devirq, pm8xxx_irq_handler);
361 set_irq_wake(devirq, 1);
362
363 return chip;
364}
365
366int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
367{
368 irq_set_chained_handler(chip->devirq, NULL);
369 kfree(chip);
370 return 0;
371}
diff --git a/include/linux/mfd/pm8xxx/core.h b/include/linux/mfd/pm8xxx/core.h
index 36ccb33332e..bd2f4f64e93 100644
--- a/include/linux/mfd/pm8xxx/core.h
+++ b/include/linux/mfd/pm8xxx/core.h
@@ -27,6 +27,7 @@ struct pm8xxx_drvdata {
27 int n); 27 int n);
28 int (*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf, 28 int (*pmic_write_buf) (const struct device *dev, u16 addr, u8 *buf,
29 int n); 29 int n);
30 int (*pmic_read_irq_stat) (const struct device *dev, int irq);
30 void *pm_chip_data; 31 void *pm_chip_data;
31}; 32};
32 33
@@ -68,4 +69,13 @@ static inline int pm8xxx_write_buf(const struct device *dev, u16 addr, u8 *buf,
68 return dd->pmic_write_buf(dev, addr, buf, n); 69 return dd->pmic_write_buf(dev, addr, buf, n);
69} 70}
70 71
72static inline int pm8xxx_read_irq_stat(const struct device *dev, int irq)
73{
74 struct pm8xxx_drvdata *dd = dev_get_drvdata(dev);
75
76 if (!dd)
77 return -EINVAL;
78 return dd->pmic_read_irq_stat(dev, irq);
79}
80
71#endif 81#endif
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
new file mode 100644
index 00000000000..4b21769f448
--- /dev/null
+++ b/include/linux/mfd/pm8xxx/irq.h
@@ -0,0 +1,59 @@
1/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13/*
14 * Qualcomm PMIC irq 8xxx driver header file
15 *
16 */
17
18#ifndef __MFD_PM8XXX_IRQ_H
19#define __MFD_PM8XXX_IRQ_H
20
21#include <linux/errno.h>
22#include <linux/err.h>
23
24struct pm8xxx_irq_core_data {
25 u32 rev;
26 int nirqs;
27};
28
29struct pm8xxx_irq_platform_data {
30 int irq_base;
31 struct pm8xxx_irq_core_data irq_cdata;
32 int devirq;
33 int irq_trigger_flag;
34};
35
36struct pm_irq_chip;
37
38#ifdef CONFIG_MFD_PM8XXX_IRQ
39int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
40struct pm_irq_chip * __devinit pm8xxx_irq_init(struct device *dev,
41 const struct pm8xxx_irq_platform_data *pdata);
42int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip);
43#else
44static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
45{
46 return -ENXIO;
47}
48static inline struct pm_irq_chip * __devinit pm8xxx_irq_init(
49 const struct device *dev,
50 const struct pm8xxx_irq_platform_data *pdata)
51{
52 return ERR_PTR(-ENXIO);
53}
54static inline int __devexit pm8xxx_irq_exit(struct pm_irq_chip *chip)
55{
56 return -ENXIO;
57}
58#endif /* CONFIG_MFD_PM8XXX_IRQ */
59#endif /* __MFD_PM8XXX_IRQ_H */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
index 33fbe9c960a..d5517fd32d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921.h
+++ b/include/linux/mfd/pm8xxx/pm8921.h
@@ -19,9 +19,13 @@
19#define __MFD_PM8921_H 19#define __MFD_PM8921_H
20 20
21#include <linux/device.h> 21#include <linux/device.h>
22#include <linux/mfd/pm8xxx/irq.h>
23
24#define PM8921_NR_IRQS 256
22 25
23struct pm8921_platform_data { 26struct pm8921_platform_data {
24 int irq_base; 27 int irq_base;
28 struct pm8xxx_irq_platform_data *irq_pdata;
25}; 29};
26 30
27#endif 31#endif