aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2014-02-26 13:59:21 -0500
committerLee Jones <lee.jones@linaro.org>2014-03-19 04:58:29 -0400
commitdc1a95ccaa1158948bbc6648d6dadc534a30ed92 (patch)
treedd83329603148ec2f223f41eb102381ac13c272a /drivers/mfd
parentcced3548babc6d5338261f1b43ead62d93448567 (diff)
mfd: pm8921: Migrate to irqdomains
Convert this driver to use irqdomains so that the PMIC's child devices can be converted to devicetree. Acked-by: Lee Jones <lee.jones@linaro.org> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig1
-rw-r--r--drivers/mfd/pm8921-core.c198
2 files changed, 76 insertions, 123 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 650c90f814ff..833d2c884437 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -479,6 +479,7 @@ config MFD_PM8XXX
479config MFD_PM8921_CORE 479config MFD_PM8921_CORE
480 tristate "Qualcomm PM8921 PMIC chip" 480 tristate "Qualcomm PM8921 PMIC chip"
481 depends on (ARCH_MSM || HEXAGON) 481 depends on (ARCH_MSM || HEXAGON)
482 select IRQ_DOMAIN
482 select MFD_CORE 483 select MFD_CORE
483 select MFD_PM8XXX 484 select MFD_PM8XXX
484 help 485 help
diff --git a/drivers/mfd/pm8921-core.c b/drivers/mfd/pm8921-core.c
index 9ddc31f7a71d..c25e7dae150b 100644
--- a/drivers/mfd/pm8921-core.c
+++ b/drivers/mfd/pm8921-core.c
@@ -17,15 +17,15 @@
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/irqchip/chained_irq.h> 18#include <linux/irqchip/chained_irq.h>
19#include <linux/irq.h> 19#include <linux/irq.h>
20#include <linux/irqdomain.h>
20#include <linux/module.h> 21#include <linux/module.h>
21#include <linux/platform_device.h> 22#include <linux/platform_device.h>
22#include <linux/slab.h> 23#include <linux/slab.h>
23#include <linux/err.h> 24#include <linux/err.h>
24#include <linux/ssbi.h> 25#include <linux/ssbi.h>
26#include <linux/of_platform.h>
25#include <linux/mfd/core.h> 27#include <linux/mfd/core.h>
26#include <linux/mfd/pm8xxx/pm8921.h>
27#include <linux/mfd/pm8xxx/core.h> 28#include <linux/mfd/pm8xxx/core.h>
28#include <linux/mfd/pm8xxx/irq.h>
29 29
30#define SSBI_REG_ADDR_IRQ_BASE 0x1BB 30#define SSBI_REG_ADDR_IRQ_BASE 0x1BB
31 31
@@ -53,11 +53,12 @@
53#define REG_HWREV 0x002 /* PMIC4 revision */ 53#define REG_HWREV 0x002 /* PMIC4 revision */
54#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */ 54#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
55 55
56#define PM8921_NR_IRQS 256
57
56struct pm_irq_chip { 58struct pm_irq_chip {
57 struct device *dev; 59 struct device *dev;
58 spinlock_t pm_irq_lock; 60 spinlock_t pm_irq_lock;
59 unsigned int devirq; 61 struct irq_domain *irqdomain;
60 unsigned int irq_base;
61 unsigned int num_irqs; 62 unsigned int num_irqs;
62 unsigned int num_blocks; 63 unsigned int num_blocks;
63 unsigned int num_masters; 64 unsigned int num_masters;
@@ -138,7 +139,7 @@ static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
138 for (i = 0; i < 8; i++) { 139 for (i = 0; i < 8; i++) {
139 if (bits & (1 << i)) { 140 if (bits & (1 << i)) {
140 pmirq = block * 8 + i; 141 pmirq = block * 8 + i;
141 irq = pmirq + chip->irq_base; 142 irq = irq_find_mapping(chip->irqdomain, pmirq);
142 generic_handle_irq(irq); 143 generic_handle_irq(irq);
143 } 144 }
144 } 145 }
@@ -197,12 +198,11 @@ static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
197static void pm8xxx_irq_mask_ack(struct irq_data *d) 198static void pm8xxx_irq_mask_ack(struct irq_data *d)
198{ 199{
199 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 200 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
200 unsigned int pmirq = d->irq - chip->irq_base; 201 unsigned int pmirq = irqd_to_hwirq(d);
201 int master, irq_bit; 202 int irq_bit;
202 u8 block, config; 203 u8 block, config;
203 204
204 block = pmirq / 8; 205 block = pmirq / 8;
205 master = block / 8;
206 irq_bit = pmirq % 8; 206 irq_bit = pmirq % 8;
207 207
208 config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR; 208 config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
@@ -212,12 +212,11 @@ static void pm8xxx_irq_mask_ack(struct irq_data *d)
212static void pm8xxx_irq_unmask(struct irq_data *d) 212static void pm8xxx_irq_unmask(struct irq_data *d)
213{ 213{
214 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 214 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
215 unsigned int pmirq = d->irq - chip->irq_base; 215 unsigned int pmirq = irqd_to_hwirq(d);
216 int master, irq_bit; 216 int irq_bit;
217 u8 block, config; 217 u8 block, config;
218 218
219 block = pmirq / 8; 219 block = pmirq / 8;
220 master = block / 8;
221 irq_bit = pmirq % 8; 220 irq_bit = pmirq % 8;
222 221
223 config = chip->config[pmirq]; 222 config = chip->config[pmirq];
@@ -227,12 +226,11 @@ static void pm8xxx_irq_unmask(struct irq_data *d)
227static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type) 226static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
228{ 227{
229 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d); 228 struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
230 unsigned int pmirq = d->irq - chip->irq_base; 229 unsigned int pmirq = irqd_to_hwirq(d);
231 int master, irq_bit; 230 int irq_bit;
232 u8 block, config; 231 u8 block, config;
233 232
234 block = pmirq / 8; 233 block = pmirq / 8;
235 master = block / 8;
236 irq_bit = pmirq % 8; 234 irq_bit = pmirq % 8;
237 235
238 chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT) 236 chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
@@ -287,12 +285,9 @@ static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
287 int pmirq, rc; 285 int pmirq, rc;
288 u8 block, bits, bit; 286 u8 block, bits, bit;
289 unsigned long flags; 287 unsigned long flags;
288 struct irq_data *irq_data = irq_get_irq_data(irq);
290 289
291 if (chip == NULL || irq < chip->irq_base || 290 pmirq = irq_data->hwirq;
292 irq >= chip->irq_base + chip->num_irqs)
293 return -EINVAL;
294
295 pmirq = irq - chip->irq_base;
296 291
297 block = pmirq / 8; 292 block = pmirq / 8;
298 bit = pmirq % 8; 293 bit = pmirq % 8;
@@ -321,67 +316,29 @@ bail_out:
321 return rc; 316 return rc;
322} 317}
323 318
324static struct pm_irq_chip *pm8xxx_irq_init(struct device *dev, 319static struct lock_class_key pm8xxx_irq_lock_class;
325 const struct pm8xxx_irq_platform_data *pdata)
326{
327 struct pm_irq_chip *chip;
328 int devirq, rc;
329 unsigned int pmirq;
330
331 if (!pdata) {
332 pr_err("No platform data\n");
333 return ERR_PTR(-EINVAL);
334 }
335 320
336 devirq = pdata->devirq; 321static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
337 if (devirq < 0) { 322 irq_hw_number_t hwirq)
338 pr_err("missing devirq\n"); 323{
339 rc = devirq; 324 struct pm_irq_chip *chip = d->host_data;
340 return ERR_PTR(-EINVAL);
341 }
342
343 chip = kzalloc(sizeof(struct pm_irq_chip)
344 + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
345 if (!chip) {
346 pr_err("Cannot alloc pm_irq_chip struct\n");
347 return ERR_PTR(-EINVAL);
348 }
349
350 chip->dev = dev;
351 chip->devirq = devirq;
352 chip->irq_base = pdata->irq_base;
353 chip->num_irqs = pdata->irq_cdata.nirqs;
354 chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
355 chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
356 spin_lock_init(&chip->pm_irq_lock);
357 325
358 for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) { 326 irq_set_lockdep_class(irq, &pm8xxx_irq_lock_class);
359 irq_set_chip_and_handler(chip->irq_base + pmirq, 327 irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
360 &pm8xxx_irq_chip, 328 irq_set_chip_data(irq, chip);
361 handle_level_irq);
362 irq_set_chip_data(chip->irq_base + pmirq, chip);
363#ifdef CONFIG_ARM 329#ifdef CONFIG_ARM
364 set_irq_flags(chip->irq_base + pmirq, IRQF_VALID); 330 set_irq_flags(irq, IRQF_VALID);
365#else 331#else
366 irq_set_noprobe(chip->irq_base + pmirq); 332 irq_set_noprobe(irq);
367#endif 333#endif
368 }
369
370 irq_set_irq_type(devirq, pdata->irq_trigger_flag);
371 irq_set_handler_data(devirq, chip);
372 irq_set_chained_handler(devirq, pm8xxx_irq_handler);
373 irq_set_irq_wake(devirq, 1);
374
375 return chip;
376}
377
378static int pm8xxx_irq_exit(struct pm_irq_chip *chip)
379{
380 irq_set_chained_handler(chip->devirq, NULL);
381 kfree(chip);
382 return 0; 334 return 0;
383} 335}
384 336
337static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
338 .xlate = irq_domain_xlate_twocell,
339 .map = pm8xxx_irq_domain_map,
340};
341
385static int pm8921_readb(const struct device *dev, u16 addr, u8 *val) 342static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
386{ 343{
387 const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev); 344 const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
@@ -432,42 +389,19 @@ static struct pm8xxx_drvdata pm8921_drvdata = {
432 .pmic_read_irq_stat = pm8921_read_irq_stat, 389 .pmic_read_irq_stat = pm8921_read_irq_stat,
433}; 390};
434 391
435static int pm8921_add_subdevices(const struct pm8921_platform_data
436 *pdata,
437 struct pm8921 *pmic,
438 u32 rev)
439{
440 int ret = 0, irq_base = 0;
441 struct pm_irq_chip *irq_chip;
442
443 if (pdata->irq_pdata) {
444 pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
445 pdata->irq_pdata->irq_cdata.rev = rev;
446 irq_base = pdata->irq_pdata->irq_base;
447 irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
448
449 if (IS_ERR(irq_chip)) {
450 pr_err("Failed to init interrupts ret=%ld\n",
451 PTR_ERR(irq_chip));
452 return PTR_ERR(irq_chip);
453 }
454 pmic->irq_chip = irq_chip;
455 }
456 return ret;
457}
458
459static int pm8921_probe(struct platform_device *pdev) 392static int pm8921_probe(struct platform_device *pdev)
460{ 393{
461 const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev);
462 struct pm8921 *pmic; 394 struct pm8921 *pmic;
463 int rc; 395 int rc;
464 u8 val; 396 u8 val;
397 unsigned int irq;
465 u32 rev; 398 u32 rev;
399 struct pm_irq_chip *chip;
400 unsigned int nirqs = PM8921_NR_IRQS;
466 401
467 if (!pdata) { 402 irq = platform_get_irq(pdev, 0);
468 pr_err("missing platform data\n"); 403 if (irq < 0)
469 return -EINVAL; 404 return irq;
470 }
471 405
472 pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL); 406 pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
473 if (!pmic) { 407 if (!pmic) {
@@ -498,37 +432,55 @@ static int pm8921_probe(struct platform_device *pdev)
498 pm8921_drvdata.pm_chip_data = pmic; 432 pm8921_drvdata.pm_chip_data = pmic;
499 platform_set_drvdata(pdev, &pm8921_drvdata); 433 platform_set_drvdata(pdev, &pm8921_drvdata);
500 434
501 rc = pm8921_add_subdevices(pdata, pmic, rev); 435 chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
436 sizeof(chip->config[0]) * nirqs,
437 GFP_KERNEL);
438 if (!chip)
439 return -ENOMEM;
440
441 pmic->irq_chip = chip;
442 chip->dev = &pdev->dev;
443 chip->num_irqs = nirqs;
444 chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
445 chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
446 spin_lock_init(&chip->pm_irq_lock);
447
448 chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs,
449 &pm8xxx_irq_domain_ops,
450 chip);
451 if (!chip->irqdomain)
452 return -ENODEV;
453
454 irq_set_handler_data(irq, chip);
455 irq_set_chained_handler(irq, pm8xxx_irq_handler);
456 irq_set_irq_wake(irq, 1);
457
458 rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
502 if (rc) { 459 if (rc) {
503 pr_err("Cannot add subdevices rc=%d\n", rc); 460 irq_set_chained_handler(irq, NULL);
504 goto err; 461 irq_set_handler_data(irq, NULL);
462 irq_domain_remove(chip->irqdomain);
505 } 463 }
506 464
507 /* gpio might not work if no irq device is found */ 465 return rc;
508 WARN_ON(pmic->irq_chip == NULL); 466}
509 467
468static int pm8921_remove_child(struct device *dev, void *unused)
469{
470 platform_device_unregister(to_platform_device(dev));
510 return 0; 471 return 0;
511
512err:
513 mfd_remove_devices(pmic->dev);
514 return rc;
515} 472}
516 473
517static int pm8921_remove(struct platform_device *pdev) 474static int pm8921_remove(struct platform_device *pdev)
518{ 475{
519 struct pm8xxx_drvdata *drvdata; 476 int irq = platform_get_irq(pdev, 0);
520 struct pm8921 *pmic = NULL; 477 struct pm8921 *pmic = pm8921_drvdata.pm_chip_data;
521 478 struct pm_irq_chip *chip = pmic->irq_chip;
522 drvdata = platform_get_drvdata(pdev); 479
523 if (drvdata) 480 device_for_each_child(&pdev->dev, NULL, pm8921_remove_child);
524 pmic = drvdata->pm_chip_data; 481 irq_set_chained_handler(irq, NULL);
525 if (pmic) { 482 irq_set_handler_data(irq, NULL);
526 mfd_remove_devices(pmic->dev); 483 irq_domain_remove(chip->irqdomain);
527 if (pmic->irq_chip) {
528 pm8xxx_irq_exit(pmic->irq_chip);
529 pmic->irq_chip = NULL;
530 }
531 }
532 484
533 return 0; 485 return 0;
534} 486}