diff options
33 files changed, 618 insertions, 302 deletions
diff --git a/arch/x86/platform/olpc/olpc-xo1.c b/arch/x86/platform/olpc/olpc-xo1.c index 99513642a0e..ab81fb27176 100644 --- a/arch/x86/platform/olpc/olpc-xo1.c +++ b/arch/x86/platform/olpc/olpc-xo1.c @@ -72,9 +72,9 @@ static int __devinit olpc_xo1_probe(struct platform_device *pdev) dev_err(&pdev->dev, "can't fetch device resource info\n"); return -EIO; } - if (strcmp(pdev->name, "olpc-xo1-pms") == 0) + if (strcmp(pdev->name, "cs5535-pms") == 0) pms_base = res->start; - else if (strcmp(pdev->name, "olpc-xo1-ac-acpi") == 0) + else if (strcmp(pdev->name, "olpc-xo1-pm-acpi") == 0) acpi_base = res->start; /* If we have both addresses, we can override the poweroff hook */ @@ -90,9 +90,9 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev) { mfd_cell_disable(pdev); - if (strcmp(pdev->name, "olpc-xo1-pms") == 0) + if (strcmp(pdev->name, "cs5535-pms") == 0) pms_base = 0; - else if (strcmp(pdev->name, "olpc-xo1-acpi") == 0) + else if (strcmp(pdev->name, "olpc-xo1-pm-acpi") == 0) acpi_base = 0; pm_power_off = NULL; @@ -101,7 +101,7 @@ static int __devexit olpc_xo1_remove(struct platform_device *pdev) static struct platform_driver cs5535_pms_drv = { .driver = { - .name = "olpc-xo1-pms", + .name = "cs5535-pms", .owner = THIS_MODULE, }, .probe = olpc_xo1_probe, @@ -110,7 +110,7 @@ static struct platform_driver cs5535_pms_drv = { static struct platform_driver cs5535_acpi_drv = { .driver = { - .name = "olpc-xo1-acpi", + .name = "olpc-xo1-pm-acpi", .owner = THIS_MODULE, }, .probe = olpc_xo1_probe, @@ -121,22 +121,21 @@ static int __init olpc_xo1_init(void) { int r; - r = mfd_shared_platform_driver_register(&cs5535_pms_drv, "cs5535-pms"); + r = platform_driver_register(&cs5535_pms_drv); if (r) return r; - r = mfd_shared_platform_driver_register(&cs5535_acpi_drv, - "cs5535-acpi"); + r = platform_driver_register(&cs5535_acpi_drv); if (r) - mfd_shared_platform_driver_unregister(&cs5535_pms_drv); + platform_driver_unregister(&cs5535_pms_drv); return r; } static void __exit olpc_xo1_exit(void) { - mfd_shared_platform_driver_unregister(&cs5535_acpi_drv); - mfd_shared_platform_driver_unregister(&cs5535_pms_drv); + platform_driver_unregister(&cs5535_acpi_drv); + platform_driver_unregister(&cs5535_pms_drv); } MODULE_AUTHOR("Daniel Drake <dsd@laptop.org>"); diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c index 9c511c1604a..011cb6ce861 100644 --- a/drivers/mfd/88pm860x-core.c +++ b/drivers/mfd/88pm860x-core.c @@ -416,7 +416,6 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, : chip->companion; unsigned char status_buf[INT_STATUS_NUM]; unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - struct irq_desc *desc; int i, data, mask, ret = -EINVAL; int __irq; @@ -468,19 +467,17 @@ static int __devinit device_irq_init(struct pm860x_chip *chip, if (!chip->core_irq) goto out; - desc = irq_to_desc(chip->core_irq); - /* register IRQ by genirq */ for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) { __irq = i + chip->irq_base; - set_irq_chip_data(__irq, chip); - set_irq_chip_and_handler(__irq, &pm860x_irq_chip, + irq_set_chip_data(__irq, chip); + irq_set_chip_and_handler(__irq, &pm860x_irq_chip, handle_edge_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #else - set_irq_noprobe(__irq); + irq_set_noprobe(__irq); #endif } diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index a9a1af49281..e986f91fff9 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -133,6 +133,7 @@ config TPS6105X tristate "TPS61050/61052 Boost Converters" depends on I2C select REGULATOR + select MFD_CORE select REGULATOR_FIXED_VOLTAGE help This option enables a driver for the TP61050/TPS61052 diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 47f5709f382..ef489f25340 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -63,7 +63,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o max8925-objs := max8925-core.o max8925-i2c.o obj-$(CONFIG_MFD_MAX8925) += max8925.o -obj-$(CONFIG_MFD_MAX8997) += max8997.o +obj-$(CONFIG_MFD_MAX8997) += max8997.o max8997-irq.o obj-$(CONFIG_MFD_MAX8998) += max8998.o max8998-irq.o pcf50633-objs := pcf50633-core.o pcf50633-irq.o diff --git a/drivers/mfd/ab3550-core.c b/drivers/mfd/ab3550-core.c index c12d0428522..ff86acf3e6b 100644 --- a/drivers/mfd/ab3550-core.c +++ b/drivers/mfd/ab3550-core.c @@ -668,7 +668,7 @@ static int ab3550_startup_irq_enabled(struct device *dev, unsigned int irq) struct ab3550_platform_data *plf_data; bool val; - ab = get_irq_chip_data(irq); + ab = irq_get_chip_data(irq); plf_data = ab->i2c_client[0]->dev.platform_data; irq -= plf_data->irq.base; val = ((ab->startup_events[irq / 8] & BIT(irq % 8)) != 0); @@ -1296,14 +1296,14 @@ static int __init ab3550_probe(struct i2c_client *client, unsigned int irq; irq = ab3550_plf_data->irq.base + i; - set_irq_chip_data(irq, ab); - set_irq_chip_and_handler(irq, &ab3550_irq_chip, - handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_chip_data(irq, ab); + irq_set_chip_and_handler(irq, &ab3550_irq_chip, + handle_simple_irq); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 6e185b272d0..62e33e2258d 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -334,14 +334,14 @@ static int ab8500_irq_init(struct ab8500 *ab8500) int irq; for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { - set_irq_chip_data(irq, ab8500); - set_irq_chip_and_handler(irq, &ab8500_irq_chip, + irq_set_chip_data(irq, ab8500); + irq_set_chip_and_handler(irq, &ab8500_irq_chip, handle_simple_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -357,8 +357,8 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c index 0241f08fc00..d4a851c6b5b 100644 --- a/drivers/mfd/asic3.c +++ b/drivers/mfd/asic3.c @@ -139,13 +139,12 @@ static void asic3_irq_flip_edge(struct asic3 *asic, static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) { + struct asic3 *asic = irq_desc_get_handler_data(desc); + struct irq_data *data = irq_desc_get_irq_data(desc); int iter, i; unsigned long flags; - struct asic3 *asic; - - desc->irq_data.chip->irq_ack(&desc->irq_data); - asic = get_irq_data(irq); + data->chip->irq_ack(irq_data); for (iter = 0 ; iter < MAX_ASIC_ISR_LOOPS; iter++) { u32 status; @@ -188,8 +187,7 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) irqnr = asic->irq_base + (ASIC3_GPIOS_PER_BANK * bank) + i; - desc = irq_to_desc(irqnr); - desc->handle_irq(irqnr, desc); + generic_handle_irq(irqnr); if (asic->irq_bothedge[bank] & bit) asic3_irq_flip_edge(asic, base, bit); @@ -200,11 +198,8 @@ static void asic3_irq_demux(unsigned int irq, struct irq_desc *desc) /* Handle remaining IRQs in the status register */ for (i = ASIC3_NUM_GPIOS; i < ASIC3_NR_IRQS; i++) { /* They start at bit 4 and go up */ - if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) { - desc = irq_to_desc(asic->irq_base + i); - desc->handle_irq(asic->irq_base + i, - desc); - } + if (status & (1 << (i - ASIC3_NUM_GPIOS + 4))) + generic_handle_irq(asic->irq_base + i); } } @@ -393,21 +388,21 @@ static int __init asic3_irq_probe(struct platform_device *pdev) for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { if (irq < asic->irq_base + ASIC3_NUM_GPIOS) - set_irq_chip(irq, &asic3_gpio_irq_chip); + irq_set_chip(irq, &asic3_gpio_irq_chip); else - set_irq_chip(irq, &asic3_irq_chip); + irq_set_chip(irq, &asic3_irq_chip); - set_irq_chip_data(irq, asic); - set_irq_handler(irq, handle_level_irq); + irq_set_chip_data(irq, asic); + irq_set_handler(irq, handle_level_irq); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } asic3_write_register(asic, ASIC3_OFFSET(INTR, INT_MASK), ASIC3_INTMASK_GINTMASK); - set_irq_chained_handler(asic->irq_nr, asic3_irq_demux); - set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); - set_irq_data(asic->irq_nr, asic); + irq_set_chained_handler(asic->irq_nr, asic3_irq_demux); + irq_set_irq_type(asic->irq_nr, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(asic->irq_nr, asic); return 0; } @@ -421,11 +416,10 @@ static void asic3_irq_remove(struct platform_device *pdev) for (irq = irq_base; irq < irq_base + ASIC3_NR_IRQS; irq++) { set_irq_flags(irq, 0); - set_irq_handler(irq, NULL); - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } - set_irq_chained_handler(asic->irq_nr, NULL); + irq_set_chained_handler(asic->irq_nr, NULL); } /* GPIOs */ diff --git a/drivers/mfd/cs5535-mfd.c b/drivers/mfd/cs5535-mfd.c index 886a0687106..155fa040788 100644 --- a/drivers/mfd/cs5535-mfd.c +++ b/drivers/mfd/cs5535-mfd.c @@ -27,6 +27,7 @@ #include <linux/mfd/core.h> #include <linux/module.h> #include <linux/pci.h> +#include <asm/olpc.h> #define DRV_NAME "cs5535-mfd" @@ -111,6 +112,20 @@ static __devinitdata struct mfd_cell cs5535_mfd_cells[] = { }, }; +#ifdef CONFIG_OLPC +static void __devinit cs5535_clone_olpc_cells(void) +{ + const char *acpi_clones[] = { "olpc-xo1-pm-acpi", "olpc-xo1-sci-acpi" }; + + if (!machine_is_olpc()) + return; + + mfd_clone_cell("cs5535-acpi", acpi_clones, ARRAY_SIZE(acpi_clones)); +} +#else +static void cs5535_clone_olpc_cells(void) { } +#endif + static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -139,6 +154,7 @@ static int __devinit cs5535_mfd_probe(struct pci_dev *pdev, dev_err(&pdev->dev, "MFD add devices failed: %d\n", err); goto err_disable; } + cs5535_clone_olpc_cells(); dev_info(&pdev->dev, "%zu devices registered.\n", ARRAY_SIZE(cs5535_mfd_cells)); diff --git a/drivers/mfd/ezx-pcap.c b/drivers/mfd/ezx-pcap.c index 9e2d8dd5f9e..f2f4029e21a 100644 --- a/drivers/mfd/ezx-pcap.c +++ b/drivers/mfd/ezx-pcap.c @@ -162,6 +162,7 @@ static void pcap_unmask_irq(struct irq_data *d) static struct irq_chip pcap_irq_chip = { .name = "pcap", + .irq_disable = pcap_mask_irq, .irq_mask = pcap_mask_irq, .irq_unmask = pcap_unmask_irq, }; @@ -196,17 +197,8 @@ static void pcap_isr_work(struct work_struct *work) local_irq_disable(); service = isr & ~msr; for (irq = pcap->irq_base; service; service >>= 1, irq++) { - if (service & 1) { - struct irq_desc *desc = irq_to_desc(irq); - - if (WARN(!desc, "Invalid PCAP IRQ %d\n", irq)) - break; - - if (desc->status & IRQ_DISABLED) - note_interrupt(irq, desc, IRQ_NONE); - else - desc->handle_irq(irq, desc); - } + if (service & 1) + generic_handle_irq(irq); } local_irq_enable(); ezx_pcap_write(pcap, PCAP_REG_MSR, pcap->msr); @@ -215,7 +207,7 @@ static void pcap_isr_work(struct work_struct *work) static void pcap_irq_handler(unsigned int irq, struct irq_desc *desc) { - struct pcap_chip *pcap = get_irq_data(irq); + struct pcap_chip *pcap = irq_get_handler_data(irq); desc->irq_data.chip->irq_ack(&desc->irq_data); queue_work(pcap->workqueue, &pcap->isr_work); @@ -419,7 +411,7 @@ static int __devexit ezx_pcap_remove(struct spi_device *spi) /* cleanup irqchip */ for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(pcap->workqueue); @@ -476,12 +468,12 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) /* setup irq chip */ for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) { - set_irq_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); - set_irq_chip_data(i, pcap); + irq_set_chip_and_handler(i, &pcap_irq_chip, handle_simple_irq); + irq_set_chip_data(i, pcap); #ifdef CONFIG_ARM set_irq_flags(i, IRQF_VALID); #else - set_irq_noprobe(i); + irq_set_noprobe(i); #endif } @@ -490,10 +482,10 @@ static int __devinit ezx_pcap_probe(struct spi_device *spi) ezx_pcap_write(pcap, PCAP_REG_ISR, PCAP_CLEAR_INTERRUPT_REGISTER); pcap->msr = PCAP_MASK_ALL_INTERRUPT; - set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); - set_irq_data(spi->irq, pcap); - set_irq_chained_handler(spi->irq, pcap_irq_handler); - set_irq_wake(spi->irq, 1); + irq_set_irq_type(spi->irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(spi->irq, pcap); + irq_set_chained_handler(spi->irq, pcap_irq_handler); + irq_set_irq_wake(spi->irq, 1); /* ADC */ adc_irq = pcap_to_irq(pcap, (pdata->config & PCAP_SECOND_PORT) ? @@ -522,7 +514,7 @@ remove_subdevs: free_irq(adc_irq, pcap); free_irqchip: for (i = pcap->irq_base; i < (pcap->irq_base + PCAP_NIRQS); i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); /* destroy_workqueue: */ destroy_workqueue(pcap->workqueue); free_pcap: diff --git a/drivers/mfd/htc-egpio.c b/drivers/mfd/htc-egpio.c index d00b6d1a69e..bbaec0ccba8 100644 --- a/drivers/mfd/htc-egpio.c +++ b/drivers/mfd/htc-egpio.c @@ -100,7 +100,7 @@ static struct irq_chip egpio_muxed_chip = { static void egpio_handler(unsigned int irq, struct irq_desc *desc) { - struct egpio_info *ei = get_irq_data(irq); + struct egpio_info *ei = irq_desc_get_handler_data(desc); int irqpin; /* Read current pins. */ @@ -113,9 +113,7 @@ static void egpio_handler(unsigned int irq, struct irq_desc *desc) for_each_set_bit(irqpin, &readval, ei->nirqs) { /* Run irq handler */ pr_debug("got IRQ %d\n", irqpin); - irq = ei->irq_start + irqpin; - desc = irq_to_desc(irq); - desc->handle_irq(irq, desc); + generic_handle_irq(ei->irq_start + irqpin); } } @@ -346,14 +344,14 @@ static int __init egpio_probe(struct platform_device *pdev) ei->ack_write = 0; irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, &egpio_muxed_chip); - set_irq_chip_data(irq, ei); - set_irq_handler(irq, handle_simple_irq); + irq_set_chip_and_handler(irq, &egpio_muxed_chip, + handle_simple_irq); + irq_set_chip_data(irq, ei); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); - set_irq_data(ei->chained_irq, ei); - set_irq_chained_handler(ei->chained_irq, egpio_handler); + irq_set_irq_type(ei->chained_irq, IRQ_TYPE_EDGE_RISING); + irq_set_handler_data(ei->chained_irq, ei); + irq_set_chained_handler(ei->chained_irq, egpio_handler); ack_irqs(ei); device_init_wakeup(&pdev->dev, 1); @@ -375,11 +373,10 @@ static int __exit egpio_remove(struct platform_device *pdev) if (ei->chained_irq) { irq_end = ei->irq_start + ei->nirqs; for (irq = ei->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, NULL); - set_irq_handler(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); set_irq_flags(irq, 0); } - set_irq_chained_handler(ei->chained_irq, NULL); + irq_set_chained_handler(ei->chained_irq, NULL); device_init_wakeup(&pdev->dev, 0); } iounmap(ei->base_addr); diff --git a/drivers/mfd/htc-i2cpld.c b/drivers/mfd/htc-i2cpld.c index 296ad1562f6..d55065cc324 100644 --- a/drivers/mfd/htc-i2cpld.c +++ b/drivers/mfd/htc-i2cpld.c @@ -58,6 +58,7 @@ struct htcpld_chip { uint irq_start; int nirqs; + unsigned int flow_type; /* * Work structure to allow for setting values outside of any * possible interrupt context @@ -97,12 +98,7 @@ static void htcpld_unmask(struct irq_data *data) static int htcpld_set_type(struct irq_data *data, unsigned int flags) { - struct irq_desc *d = irq_to_desc(data->irq); - - if (!d) { - pr_err("HTCPLD invalid IRQ: %d\n", data->irq); - return -EINVAL; - } + struct htcpld_chip *chip = irq_data_get_irq_chip_data(data); if (flags & ~IRQ_TYPE_SENSE_MASK) return -EINVAL; @@ -111,9 +107,7 @@ static int htcpld_set_type(struct irq_data *data, unsigned int flags) if (flags & (IRQ_TYPE_LEVEL_LOW|IRQ_TYPE_LEVEL_HIGH)) return -EINVAL; - d->status &= ~IRQ_TYPE_SENSE_MASK; - d->status |= flags; - + chip->flow_type = flags; return 0; } @@ -135,7 +129,6 @@ static irqreturn_t htcpld_handler(int irq, void *dev) unsigned int i; unsigned long flags; int irqpin; - struct irq_desc *desc; if (!htcpld) { pr_debug("htcpld is null in ISR\n"); @@ -195,23 +188,19 @@ static irqreturn_t htcpld_handler(int irq, void *dev) * associated interrupts. */ for (irqpin = 0; irqpin < chip->nirqs; irqpin++) { - unsigned oldb, newb; - int flags; + unsigned oldb, newb, type = chip->flow_type; irq = chip->irq_start + irqpin; - desc = irq_to_desc(irq); - flags = desc->status; /* Run the IRQ handler, but only if the bit value * changed, and the proper flags are set */ oldb = (old_val >> irqpin) & 1; newb = (uval >> irqpin) & 1; - if ((!oldb && newb && (flags & IRQ_TYPE_EDGE_RISING)) || - (oldb && !newb && - (flags & IRQ_TYPE_EDGE_FALLING))) { + if ((!oldb && newb && (type & IRQ_TYPE_EDGE_RISING)) || + (oldb && !newb && (type & IRQ_TYPE_EDGE_FALLING))) { pr_debug("fire IRQ %d\n", irqpin); - desc->handle_irq(irq, desc); + generic_handle_irq(irq); } } } @@ -359,13 +348,13 @@ static int __devinit htcpld_setup_chip_irq( /* Setup irq handlers */ irq_end = chip->irq_start + chip->nirqs; for (irq = chip->irq_start; irq < irq_end; irq++) { - set_irq_chip(irq, &htcpld_muxed_chip); - set_irq_chip_data(irq, chip); - set_irq_handler(irq, handle_simple_irq); + irq_set_chip_and_handler(irq, &htcpld_muxed_chip, + handle_simple_irq); + irq_set_chip_data(irq, chip); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #else - set_irq_probe(irq); + irq_set_probe(irq); #endif } diff --git a/drivers/mfd/jz4740-adc.c b/drivers/mfd/jz4740-adc.c index aa518b9beaf..a0bd0cf05af 100644 --- a/drivers/mfd/jz4740-adc.c +++ b/drivers/mfd/jz4740-adc.c @@ -112,7 +112,7 @@ static struct irq_chip jz4740_adc_irq_chip = { static void jz4740_adc_irq_demux(unsigned int irq, struct irq_desc *desc) { - struct jz4740_adc *adc = get_irq_desc_data(desc); + struct jz4740_adc *adc = irq_desc_get_handler_data(desc); uint8_t status; unsigned int i; @@ -310,13 +310,13 @@ static int __devinit jz4740_adc_probe(struct platform_device *pdev) platform_set_drvdata(pdev, adc); for (irq = adc->irq_base; irq < adc->irq_base + 5; ++irq) { - set_irq_chip_data(irq, adc); - set_irq_chip_and_handler(irq, &jz4740_adc_irq_chip, - handle_level_irq); + irq_set_chip_data(irq, adc); + irq_set_chip_and_handler(irq, &jz4740_adc_irq_chip, + handle_level_irq); } - set_irq_data(adc->irq, adc); - set_irq_chained_handler(adc->irq, jz4740_adc_irq_demux); + irq_set_handler_data(adc->irq, adc); + irq_set_chained_handler(adc->irq, jz4740_adc_irq_demux); writeb(0x00, adc->base + JZ_REG_ADC_ENABLE); writeb(0xff, adc->base + JZ_REG_ADC_CTRL); @@ -347,8 +347,8 @@ static int __devexit jz4740_adc_remove(struct platform_device *pdev) mfd_remove_devices(&pdev->dev); - set_irq_data(adc->irq, NULL); - set_irq_chained_handler(adc->irq, NULL); + irq_set_handler_data(adc->irq, NULL); + irq_set_chained_handler(adc->irq, NULL); iounmap(adc->base); release_mem_region(adc->mem->start, resource_size(adc->mem)); diff --git a/drivers/mfd/max8925-core.c b/drivers/mfd/max8925-core.c index 0e998dc4e7d..58cc5fdde01 100644 --- a/drivers/mfd/max8925-core.c +++ b/drivers/mfd/max8925-core.c @@ -517,7 +517,6 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, struct max8925_platform_data *pdata) { unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT; - struct irq_desc *desc; int i, ret; int __irq; @@ -544,19 +543,18 @@ static int max8925_irq_init(struct max8925_chip *chip, int irq, mutex_init(&chip->irq_lock); chip->core_irq = irq; chip->irq_base = pdata->irq_base; - desc = irq_to_desc(chip->core_irq); /* register with genirq */ for (i = 0; i < ARRAY_SIZE(max8925_irqs); i++) { __irq = i + chip->irq_base; - set_irq_chip_data(__irq, chip); - set_irq_chip_and_handler(__irq, &max8925_irq_chip, + irq_set_chip_data(__irq, chip); + irq_set_chip_and_handler(__irq, &max8925_irq_chip, handle_edge_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #else - set_irq_noprobe(__irq); + irq_set_noprobe(__irq); #endif } if (!irq) { diff --git a/drivers/mfd/max8997-irq.c b/drivers/mfd/max8997-irq.c new file mode 100644 index 00000000000..638bf7e4d3b --- /dev/null +++ b/drivers/mfd/max8997-irq.c @@ -0,0 +1,377 @@ +/* + * max8997-irq.c - Interrupt controller support for MAX8997 + * + * Copyright (C) 2011 Samsung Electronics Co.Ltd + * MyungJoo Ham <myungjoo.ham@samsung.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * This driver is based on max8998-irq.c + */ + +#include <linux/err.h> +#include <linux/irq.h> +#include <linux/interrupt.h> +#include <linux/mfd/max8997.h> +#include <linux/mfd/max8997-private.h> + +static const u8 max8997_mask_reg[] = { + [PMIC_INT1] = MAX8997_REG_INT1MSK, + [PMIC_INT2] = MAX8997_REG_INT2MSK, + [PMIC_INT3] = MAX8997_REG_INT3MSK, + [PMIC_INT4] = MAX8997_REG_INT4MSK, + [FUEL_GAUGE] = MAX8997_REG_INVALID, + [MUIC_INT1] = MAX8997_MUIC_REG_INTMASK1, + [MUIC_INT2] = MAX8997_MUIC_REG_INTMASK2, + [MUIC_INT3] = MAX8997_MUIC_REG_INTMASK3, + [GPIO_LOW] = MAX8997_REG_INVALID, + [GPIO_HI] = MAX8997_REG_INVALID, + [FLASH_STATUS] = MAX8997_REG_INVALID, +}; + +static struct i2c_client *get_i2c(struct max8997_dev *max8997, + enum max8997_irq_source src) +{ + switch (src) { + case PMIC_INT1 ... PMIC_INT4: + return max8997->i2c; + case FUEL_GAUGE: + return NULL; + case MUIC_INT1 ... MUIC_INT3: + return max8997->muic; + case GPIO_LOW ... GPIO_HI: + return max8997->i2c; + case FLASH_STATUS: + return max8997->i2c; + default: + return ERR_PTR(-EINVAL); + } + + return ERR_PTR(-EINVAL); +} + +struct max8997_irq_data { + int mask; + enum max8997_irq_source group; +}; + +#define DECLARE_IRQ(idx, _group, _mask) \ + [(idx)] = { .group = (_group), .mask = (_mask) } +static const struct max8997_irq_data max8997_irqs[] = { + DECLARE_IRQ(MAX8997_PMICIRQ_PWRONR, PMIC_INT1, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_PWRONF, PMIC_INT1, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_PWRON1SEC, PMIC_INT1, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGONR, PMIC_INT1, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGONF, PMIC_INT1, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT2, PMIC_INT1, 1 << 6), + DECLARE_IRQ(MAX8997_PMICIRQ_LOWBAT1, PMIC_INT1, 1 << 7), + + DECLARE_IRQ(MAX8997_PMICIRQ_JIGR, PMIC_INT2, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_JIGF, PMIC_INT2, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_MR, PMIC_INT2, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS1OK, PMIC_INT2, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS2OK, PMIC_INT2, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS3OK, PMIC_INT2, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_DVS4OK, PMIC_INT2, 1 << 6), + + DECLARE_IRQ(MAX8997_PMICIRQ_CHGINS, PMIC_INT3, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_CHGRM, PMIC_INT3, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_DCINOVP, PMIC_INT3, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_TOPOFFR, PMIC_INT3, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_CHGRSTF, PMIC_INT3, 1 << 5), + DECLARE_IRQ(MAX8997_PMICIRQ_MBCHGTMEXPD, PMIC_INT3, 1 << 7), + + DECLARE_IRQ(MAX8997_PMICIRQ_RTC60S, PMIC_INT4, 1 << 0), + DECLARE_IRQ(MAX8997_PMICIRQ_RTCA1, PMIC_INT4, 1 << 1), + DECLARE_IRQ(MAX8997_PMICIRQ_RTCA2, PMIC_INT4, 1 << 2), + DECLARE_IRQ(MAX8997_PMICIRQ_SMPL_INT, PMIC_INT4, 1 << 3), + DECLARE_IRQ(MAX8997_PMICIRQ_RTC1S, PMIC_INT4, 1 << 4), + DECLARE_IRQ(MAX8997_PMICIRQ_WTSR, PMIC_INT4, 1 << 5), + + DECLARE_IRQ(MAX8997_MUICIRQ_ADCError, MUIC_INT1, 1 << 2), + DECLARE_IRQ(MAX8997_MUICIRQ_ADCLow, MUIC_INT1, 1 << 1), + DECLARE_IRQ(MAX8997_MUICIRQ_ADC, MUIC_INT1, 1 << 0), + + DECLARE_IRQ(MAX8997_MUICIRQ_VBVolt, MUIC_INT2, 1 << 4), + DECLARE_IRQ(MAX8997_MUICIRQ_DBChg, MUIC_INT2, 1 << 3), + DECLARE_IRQ(MAX8997_MUICIRQ_DCDTmr, MUIC_INT2, 1 << 2), + DECLARE_IRQ(MAX8997_MUICIRQ_ChgDetRun, MUIC_INT2, 1 << 1), + DECLARE_IRQ(MAX8997_MUICIRQ_ChgTyp, MUIC_INT2, 1 << 0), + + DECLARE_IRQ(MAX8997_MUICIRQ_OVP, MUIC_INT3, 1 << 2), +}; + +static void max8997_irq_lock(struct irq_data *data) +{ + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); + + mutex_lock(&max8997->irqlock); +} + +static void max8997_irq_sync_unlock(struct irq_data *data) +{ + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); + int i; + + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { + u8 mask_reg = max8997_mask_reg[i]; + struct i2c_client *i2c = get_i2c(max8997, i); + + if (mask_reg == MAX8997_REG_INVALID || + IS_ERR_OR_NULL(i2c)) + continue; + max8997->irq_masks_cache[i] = max8997->irq_masks_cur[i]; + + max8997_write_reg(i2c, max8997_mask_reg[i], + max8997->irq_masks_cur[i]); + } + + mutex_unlock(&max8997->irqlock); +} + +static const inline struct max8997_irq_data * +irq_to_max8997_irq(struct max8997_dev *max8997, int irq) +{ + return &max8997_irqs[irq - max8997->irq_base]; +} + +static void max8997_irq_mask(struct irq_data *data) +{ + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); + const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, + data->irq); + + max8997->irq_masks_cur[irq_data->group] |= irq_data->mask; +} + +static void max8997_irq_unmask(struct irq_data *data) +{ + struct max8997_dev *max8997 = irq_get_chip_data(data->irq); + const struct max8997_irq_data *irq_data = irq_to_max8997_irq(max8997, + data->irq); + + max8997->irq_masks_cur[irq_data->group] &= ~irq_data->mask; +} + +static struct irq_chip max8997_irq_chip = { + .name = "max8997", + .irq_bus_lock = max8997_irq_lock, + .irq_bus_sync_unlock = max8997_irq_sync_unlock, + .irq_mask = max8997_irq_mask, + .irq_unmask = max8997_irq_unmask, +}; + +#define MAX8997_IRQSRC_PMIC (1 << 1) +#define MAX8997_IRQSRC_FUELGAUGE (1 << 2) +#define MAX8997_IRQSRC_MUIC (1 << 3) +#define MAX8997_IRQSRC_GPIO (1 << 4) +#define MAX8997_IRQSRC_FLASH (1 << 5) +static irqreturn_t max8997_irq_thread(int irq, void *data) +{ + struct max8997_dev *max8997 = data; + u8 irq_reg[MAX8997_IRQ_GROUP_NR] = {}; + u8 irq_src; + int ret; + int i; + + ret = max8997_read_reg(max8997->i2c, MAX8997_REG_INTSRC, &irq_src); + if (ret < 0) { + dev_err(max8997->dev, "Failed to read interrupt source: %d\n", + ret); + return IRQ_NONE; + } + + if (irq_src & MAX8997_IRQSRC_PMIC) { + /* PMIC INT1 ~ INT4 */ + max8997_bulk_read(max8997->i2c, MAX8997_REG_INT1, 4, + &irq_reg[PMIC_INT1]); + } + if (irq_src & MAX8997_IRQSRC_FUELGAUGE) { + /* + * TODO: FUEL GAUGE + * + * This is to be supported by Max17042 driver. When + * an interrupt incurs here, it should be relayed to a + * Max17042 device that is connected (probably by + * platform-data). However, we do not have interrupt + * handling in Max17042 driver currently. The Max17042 IRQ + * driver should be ready to be used as a stand-alone device and + * a Max8997-dependent device. Because it is not ready in + * Max17042-side and it is not too critical in operating + * Max8997, we do not implement this in initial releases. + */ + irq_reg[FUEL_GAUGE] = 0; + } + if (irq_src & MAX8997_IRQSRC_MUIC) { + /* MUIC INT1 ~ INT3 */ + max8997_bulk_read(max8997->muic, MAX8997_MUIC_REG_INT1, 3, + &irq_reg[MUIC_INT1]); + } + if (irq_src & MAX8997_IRQSRC_GPIO) { + /* GPIO Interrupt */ + u8 gpio_info[MAX8997_NUM_GPIO]; + + irq_reg[GPIO_LOW] = 0; + irq_reg[GPIO_HI] = 0; + + max8997_bulk_read(max8997->i2c, MAX8997_REG_GPIOCNTL1, + MAX8997_NUM_GPIO, gpio_info); + for (i = 0; i < MAX8997_NUM_GPIO; i++) { + bool interrupt = false; + + switch (gpio_info[i] & MAX8997_GPIO_INT_MASK) { + case MAX8997_GPIO_INT_BOTH: + if (max8997->gpio_status[i] != gpio_info[i]) + interrupt = true; + break; + case MAX8997_GPIO_INT_RISE: + if ((max8997->gpio_status[i] != gpio_info[i]) && + (gpio_info[i] & MAX8997_GPIO_DATA_MASK)) + interrupt = true; + break; + case MAX8997_GPIO_INT_FALL: + if ((max8997->gpio_status[i] != gpio_info[i]) && + !(gpio_info[i] & MAX8997_GPIO_DATA_MASK)) + interrupt = true; + break; + default: + break; + } + + if (interrupt) { + if (i < 8) + irq_reg[GPIO_LOW] |= (1 << i); + else + irq_reg[GPIO_HI] |= (1 << (i - 8)); + } + + } + } + if (irq_src & MAX8997_IRQSRC_FLASH) { + /* Flash Status Interrupt */ + ret = max8997_read_reg(max8997->i2c, MAX8997_REG_FLASHSTATUS, + &irq_reg[FLASH_STATUS]); + } + + /* Apply masking */ + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) + irq_reg[i] &= ~max8997->irq_masks_cur[i]; + + /* Report */ + for (i = 0; i < MAX8997_IRQ_NR; i++) { + if (irq_reg[max8997_irqs[i].group] & max8997_irqs[i].mask) + handle_nested_irq(max8997->irq_base + i); + } + + return IRQ_HANDLED; +} + +int max8997_irq_resume(struct max8997_dev *max8997) +{ + if (max8997->irq && max8997->irq_base) + max8997_irq_thread(max8997->irq_base, max8997); + return 0; +} + +int max8997_irq_init(struct max8997_dev *max8997) +{ + int i; + int cur_irq; + int ret; + u8 val; + + if (!max8997->irq) { + dev_warn(max8997->dev, "No interrupt specified.\n"); + max8997->irq_base = 0; + return 0; + } + + if (!max8997->irq_base) { + dev_err(max8997->dev, "No interrupt base specified.\n"); + return 0; + } + + mutex_init(&max8997->irqlock); + + /* Mask individual interrupt sources */ + for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) { + struct i2c_client *i2c; + + max8997->irq_masks_cur[i] = 0xff; + max8997->irq_masks_cache[i] = 0xff; + i2c = get_i2c(max8997, i); + + if (IS_ERR_OR_NULL(i2c)) + continue; + if (max8997_mask_reg[i] == MAX8997_REG_INVALID) + continue; + + max8997_write_reg(i2c, max8997_mask_reg[i], 0xff); + } + + for (i = 0; i < MAX8997_NUM_GPIO; i++) { + max8997->gpio_status[i] = (max8997_read_reg(max8997->i2c, + MAX8997_REG_GPIOCNTL1 + i, + &val) + & MAX8997_GPIO_DATA_MASK) ? + true : false; + } + + /* Register with genirq */ + for (i = 0; i < MAX8997_IRQ_NR; i++) { + cur_irq = i + max8997->irq_base; + irq_set_chip_data(cur_irq, max8997); + irq_set_chip_and_handler(cur_irq, &max8997_irq_chip, + handle_edge_irq); + irq_set_nested_thread(cur_irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(cur_irq, IRQF_VALID); +#else + irq_set_noprobe(cur_irq); +#endif + } + + ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "max8997-irq", max8997); + + if (ret) { + dev_err(max8997->dev, "Failed to request IRQ %d: %d\n", + max8997->irq, ret); + return ret; + } + + if (!max8997->ono) + return 0; + + ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | + IRQF_ONESHOT, "max8997-ono", max8997); + + if (ret) + dev_err(max8997->dev, "Failed to request ono-IRQ %d: %d\n", + max8997->ono, ret); + + return 0; +} + +void max8997_irq_exit(struct max8997_dev *max8997) +{ + if (max8997->ono) + free_irq(max8997->ono, max8997); + + if (max8997->irq) + free_irq(max8997->irq, max8997); +} diff --git a/drivers/mfd/max8998-irq.c b/drivers/mfd/max8998-irq.c index 3903e1fbb33..5919710dc9e 100644 --- a/drivers/mfd/max8998-irq.c +++ b/drivers/mfd/max8998-irq.c @@ -224,14 +224,14 @@ int max8998_irq_init(struct max8998_dev *max8998) /* register with genirq */ for (i = 0; i < MAX8998_IRQ_NR; i++) { cur_irq = i + max8998->irq_base; - set_irq_chip_data(cur_irq, max8998); - set_irq_chip_and_handler(cur_irq, &max8998_irq_chip, + irq_set_chip_data(cur_irq, max8998); + irq_set_chip_and_handler(cur_irq, &max8998_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/max8998.c b/drivers/mfd/max8998.c index c00214257da..9ec7570f5b8 100644 --- a/drivers/mfd/max8998.c +++ b/drivers/mfd/max8998.c @@ -209,7 +209,7 @@ static int max8998_suspend(struct device *dev) struct max8998_dev *max8998 = i2c_get_clientdata(i2c); if (max8998->wakeup) - set_irq_wake(max8998->irq, 1); + irq_set_irq_wake(max8998->irq, 1); return 0; } @@ -219,7 +219,7 @@ static int max8998_resume(struct device *dev) struct max8998_dev *max8998 = i2c_get_clientdata(i2c); if (max8998->wakeup) - set_irq_wake(max8998->irq, 0); + irq_set_irq_wake(max8998->irq, 0); /* * In LP3974, if IRQ registers are not "read & clear" * when it's set during sleep, the interrupt becomes diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c index 79eda0264fb..d01574d9887 100644 --- a/drivers/mfd/mfd-core.c +++ b/drivers/mfd/mfd-core.c @@ -184,16 +184,12 @@ void mfd_remove_devices(struct device *parent) } EXPORT_SYMBOL(mfd_remove_devices); -static int add_shared_platform_device(const char *cell, const char *name) +int mfd_clone_cell(const char *cell, const char **clones, size_t n_clones) { struct mfd_cell cell_entry; struct device *dev; struct platform_device *pdev; - int err; - - /* check if we've already registered a device (don't fail if we have) */ - if (bus_find_device_by_name(&platform_bus_type, NULL, name)) - return 0; + int i; /* fetch the parent cell's device (should already be registered!) */ dev = bus_find_device_by_name(&platform_bus_type, NULL, cell); @@ -206,44 +202,17 @@ static int add_shared_platform_device(const char *cell, const char *name) WARN_ON(!cell_entry.enable); - cell_entry.name = name; - err = mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0); - if (err) - dev_err(dev, "MFD add devices failed: %d\n", err); - return err; -} - -int mfd_shared_platform_driver_register(struct platform_driver *drv, - const char *cellname) -{ - int err; - - err = add_shared_platform_device(cellname, drv->driver.name); - if (err) - printk(KERN_ERR "failed to add platform device %s\n", - drv->driver.name); - - err = platform_driver_register(drv); - if (err) - printk(KERN_ERR "failed to add platform driver %s\n", - drv->driver.name); - - return err; -} -EXPORT_SYMBOL(mfd_shared_platform_driver_register); - -void mfd_shared_platform_driver_unregister(struct platform_driver *drv) -{ - struct device *dev; - - dev = bus_find_device_by_name(&platform_bus_type, NULL, - drv->driver.name); - if (dev) - platform_device_unregister(to_platform_device(dev)); + for (i = 0; i < n_clones; i++) { + cell_entry.name = clones[i]; + /* don't give up if a single call fails; just report error */ + if (mfd_add_device(pdev->dev.parent, -1, &cell_entry, NULL, 0)) + dev_err(dev, "failed to create platform device '%s'\n", + clones[i]); + } - platform_driver_unregister(drv); + return 0; } -EXPORT_SYMBOL(mfd_shared_platform_driver_unregister); +EXPORT_SYMBOL(mfd_clone_cell); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov"); diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c index c1306ed43e3..c7687f6a78a 100644 --- a/drivers/mfd/pcf50633-core.c +++ b/drivers/mfd/pcf50633-core.c @@ -356,7 +356,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client) return 0; } -static struct i2c_device_id pcf50633_id_table[] = { +static const struct i2c_device_id pcf50633_id_table[] = { {"pcf50633", 0x73}, {/* end of list */} }; diff --git a/drivers/mfd/rdc321x-southbridge.c b/drivers/mfd/rdc321x-southbridge.c index 193c940225b..10dbe6374a8 100644 --- a/drivers/mfd/rdc321x-southbridge.c +++ b/drivers/mfd/rdc321x-southbridge.c @@ -97,6 +97,7 @@ static DEFINE_PCI_DEVICE_TABLE(rdc321x_sb_table) = { { PCI_DEVICE(PCI_VENDOR_ID_RDC, PCI_DEVICE_ID_RDC_R6030) }, {} }; +MODULE_DEVICE_TABLE(pci, rdc321x_sb_table); static struct pci_driver rdc321x_sb_driver = { .name = "RDC321x Southbridge", diff --git a/drivers/mfd/stmpe.c b/drivers/mfd/stmpe.c index 3e5732b58c4..7ab7746631d 100644 --- a/drivers/mfd/stmpe.c +++ b/drivers/mfd/stmpe.c @@ -762,14 +762,14 @@ static int __devinit stmpe_irq_init(struct stmpe *stmpe) int irq; for (irq = base; irq < base + num_irqs; irq++) { - set_irq_chip_data(irq, stmpe); - set_irq_chip_and_handler(irq, &stmpe_irq_chip, + irq_set_chip_data(irq, stmpe); + irq_set_chip_and_handler(irq, &stmpe_irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -786,8 +786,8 @@ static void stmpe_irq_remove(struct stmpe *stmpe) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c index af57fc706a4..42830e69296 100644 --- a/drivers/mfd/t7l66xb.c +++ b/drivers/mfd/t7l66xb.c @@ -186,7 +186,7 @@ static struct mfd_cell t7l66xb_cells[] = { /* Handle the T7L66XB interrupt mux */ static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc) { - struct t7l66xb *t7l66xb = get_irq_data(irq); + struct t7l66xb *t7l66xb = irq_get_handler_data(irq); unsigned int isr; unsigned int i, irq_base; @@ -243,17 +243,16 @@ static void t7l66xb_attach_irq(struct platform_device *dev) irq_base = t7l66xb->irq_base; for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { - set_irq_chip(irq, &t7l66xb_chip); - set_irq_chip_data(irq, t7l66xb); - set_irq_handler(irq, handle_level_irq); + irq_set_chip_and_handler(irq, &t7l66xb_chip, handle_level_irq); + irq_set_chip_data(irq, t7l66xb); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); #endif } - set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); - set_irq_data(t7l66xb->irq, t7l66xb); - set_irq_chained_handler(t7l66xb->irq, t7l66xb_irq); + irq_set_irq_type(t7l66xb->irq, IRQ_TYPE_EDGE_FALLING); + irq_set_handler_data(t7l66xb->irq, t7l66xb); + irq_set_chained_handler(t7l66xb->irq, t7l66xb_irq); } static void t7l66xb_detach_irq(struct platform_device *dev) @@ -263,15 +262,15 @@ static void t7l66xb_detach_irq(struct platform_device *dev) irq_base = t7l66xb->irq_base; - set_irq_chained_handler(t7l66xb->irq, NULL); - set_irq_data(t7l66xb->irq, NULL); + irq_set_chained_handler(t7l66xb->irq, NULL); + irq_set_handler_data(t7l66xb->irq, NULL); for (irq = irq_base; irq < irq_base + T7L66XB_NR_IRQS; irq++) { #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c index 729dbeed2ce..c27e515b072 100644 --- a/drivers/mfd/tc3589x.c +++ b/drivers/mfd/tc3589x.c @@ -192,14 +192,14 @@ static int tc3589x_irq_init(struct tc3589x *tc3589x) int irq; for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) { - set_irq_chip_data(irq, tc3589x); - set_irq_chip_and_handler(irq, &dummy_irq_chip, + irq_set_chip_data(irq, tc3589x); + irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_edge_irq); - set_irq_nested_thread(irq, 1); + irq_set_nested_thread(irq, 1); #ifdef CONFIG_ARM set_irq_flags(irq, IRQF_VALID); #else - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -215,8 +215,8 @@ static void tc3589x_irq_remove(struct tc3589x *tc3589x) #ifdef CONFIG_ARM set_irq_flags(irq, 0); #endif - set_irq_chip_and_handler(irq, NULL, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip_and_handler(irq, NULL, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c index 3d62ded86a8..fc53ce28760 100644 --- a/drivers/mfd/tc6393xb.c +++ b/drivers/mfd/tc6393xb.c @@ -513,7 +513,7 @@ static int tc6393xb_register_gpio(struct tc6393xb *tc6393xb, int gpio_base) static void tc6393xb_irq(unsigned int irq, struct irq_desc *desc) { - struct tc6393xb *tc6393xb = get_irq_data(irq); + struct tc6393xb *tc6393xb = irq_get_handler_data(irq); unsigned int isr; unsigned int i, irq_base; @@ -572,15 +572,14 @@ static void tc6393xb_attach_irq(struct platform_device *dev) irq_base = tc6393xb->irq_base; for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { - set_irq_chip(irq, &tc6393xb_chip); - set_irq_chip_data(irq, tc6393xb); - set_irq_handler(irq, handle_edge_irq); + irq_set_chip_and_handler(irq, &tc6393xb_chip, handle_edge_irq); + irq_set_chip_data(irq, tc6393xb); set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); } - set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); - set_irq_data(tc6393xb->irq, tc6393xb); - set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq); + irq_set_irq_type(tc6393xb->irq, IRQ_TYPE_EDGE_FALLING); + irq_set_handler_data(tc6393xb->irq, tc6393xb); + irq_set_chained_handler(tc6393xb->irq, tc6393xb_irq); } static void tc6393xb_detach_irq(struct platform_device *dev) @@ -588,15 +587,15 @@ static void tc6393xb_detach_irq(struct platform_device *dev) struct tc6393xb *tc6393xb = platform_get_drvdata(dev); unsigned int irq, irq_base; - set_irq_chained_handler(tc6393xb->irq, NULL); - set_irq_data(tc6393xb->irq, NULL); + irq_set_chained_handler(tc6393xb->irq, NULL); + irq_set_handler_data(tc6393xb->irq, NULL); irq_base = tc6393xb->irq_base; for (irq = irq_base; irq < irq_base + TC6393XB_NR_IRQS; irq++) { set_irq_flags(irq, 0); - set_irq_chip(irq, NULL); - set_irq_chip_data(irq, NULL); + irq_set_chip(irq, NULL); + irq_set_chip_data(irq, NULL); } } diff --git a/drivers/mfd/tps6586x.c b/drivers/mfd/tps6586x.c index 0aa9186aec1..b600808690c 100644 --- a/drivers/mfd/tps6586x.c +++ b/drivers/mfd/tps6586x.c @@ -422,10 +422,10 @@ static int __devinit tps6586x_irq_init(struct tps6586x *tps6586x, int irq, for (i = 0; i < ARRAY_SIZE(tps6586x_irqs); i++) { int __irq = i + tps6586x->irq_base; - set_irq_chip_data(__irq, tps6586x); - set_irq_chip_and_handler(__irq, &tps6586x->irq_chip, + irq_set_chip_data(__irq, tps6586x); + irq_set_chip_and_handler(__irq, &tps6586x->irq_chip, handle_simple_irq); - set_irq_nested_thread(__irq, 1); + irq_set_nested_thread(__irq, 1); #ifdef CONFIG_ARM set_irq_flags(__irq, IRQF_VALID); #endif diff --git a/drivers/mfd/twl4030-irq.c b/drivers/mfd/twl4030-irq.c index 63a30e88908..8a7ee3139b8 100644 --- a/drivers/mfd/twl4030-irq.c +++ b/drivers/mfd/twl4030-irq.c @@ -320,24 +320,8 @@ static int twl4030_irq_thread(void *data) for (module_irq = twl4030_irq_base; pih_isr; pih_isr >>= 1, module_irq++) { - if (pih_isr & 0x1) { - struct irq_desc *d = irq_to_desc(module_irq); - - if (!d) { - pr_err("twl4030: Invalid SIH IRQ: %d\n", - module_irq); - return -EINVAL; - } - - /* These can't be masked ... always warn - * if we get any surprises. - */ - if (d->status & IRQ_DISABLED) - note_interrupt(module_irq, d, - IRQ_NONE); - else - d->handle_irq(module_irq, d); - } + if (pih_isr & 0x1) + generic_handle_irq(module_irq); } local_irq_enable(); @@ -470,7 +454,7 @@ static inline void activate_irq(int irq) set_irq_flags(irq, IRQF_VALID); #else /* same effect on other architectures */ - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -560,24 +544,18 @@ static void twl4030_sih_do_edge(struct work_struct *work) /* Modify only the bits we know must change */ while (edge_change) { int i = fls(edge_change) - 1; - struct irq_desc *d = irq_to_desc(i + agent->irq_base); + struct irq_data *idata = irq_get_irq_data(i + agent->irq_base); int byte = 1 + (i >> 2); int off = (i & 0x3) * 2; - - if (!d) { - pr_err("twl4030: Invalid IRQ: %d\n", - i + agent->irq_base); - return; - } + unsigned int type; bytes[byte] &= ~(0x03 << off); - raw_spin_lock_irq(&d->lock); - if (d->status & IRQ_TYPE_EDGE_RISING) + type = irqd_get_trigger_type(idata); + if (type & IRQ_TYPE_EDGE_RISING) bytes[byte] |= BIT(off + 1); - if (d->status & IRQ_TYPE_EDGE_FALLING) + if (type & IRQ_TYPE_EDGE_FALLING) bytes[byte] |= BIT(off + 0); - raw_spin_unlock_irq(&d->lock); edge_change &= ~BIT(i); } @@ -626,21 +604,13 @@ static void twl4030_sih_unmask(struct irq_data *data) static int twl4030_sih_set_type(struct irq_data *data, unsigned trigger) { struct sih_agent *sih = irq_data_get_irq_chip_data(data); - struct irq_desc *desc = irq_to_desc(data->irq); unsigned long flags; - if (!desc) { - pr_err("twl4030: Invalid IRQ: %d\n", data->irq); - return -EINVAL; - } - if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; spin_lock_irqsave(&sih_agent_lock, flags); - if ((desc->status & IRQ_TYPE_SENSE_MASK) != trigger) { - desc->status &= ~IRQ_TYPE_SENSE_MASK; - desc->status |= trigger; + if (irqd_get_trigger_type(data) != trigger) { sih->edge_change |= BIT(data->irq - sih->irq_base); queue_work(wq, &sih->edge_work); } @@ -680,7 +650,7 @@ static inline int sih_read_isr(const struct sih *sih) */ static void handle_twl4030_sih(unsigned irq, struct irq_desc *desc) { - struct sih_agent *agent = get_irq_data(irq); + struct sih_agent *agent = irq_get_handler_data(irq); const struct sih *sih = agent->sih; int isr; @@ -754,9 +724,9 @@ int twl4030_sih_setup(int module) for (i = 0; i < sih->bits; i++) { irq = irq_base + i; - set_irq_chip_and_handler(irq, &twl4030_sih_irq_chip, - handle_edge_irq); - set_irq_chip_data(irq, agent); + irq_set_chip_and_handler(irq, &twl4030_sih_irq_chip, + handle_edge_irq); + irq_set_chip_data(irq, agent); activate_irq(irq); } @@ -765,8 +735,8 @@ int twl4030_sih_setup(int module) /* replace generic PIH handler (handle_simple_irq) */ irq = sih_mod + twl4030_irq_base; - set_irq_data(irq, agent); - set_irq_chained_handler(irq, handle_twl4030_sih); + irq_set_handler_data(irq, agent); + irq_set_chained_handler(irq, handle_twl4030_sih); pr_info("twl4030: %s (irq %d) chaining IRQs %d..%d\n", sih->name, irq, irq_base, twl4030_irq_next - 1); @@ -815,8 +785,8 @@ int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl4030_sih_irq_chip.irq_ack = dummy_irq_chip.irq_ack; for (i = irq_base; i < irq_end; i++) { - set_irq_chip_and_handler(i, &twl4030_irq_chip, - handle_simple_irq); + irq_set_chip_and_handler(i, &twl4030_irq_chip, + handle_simple_irq); activate_irq(i); } twl4030_irq_next = i; @@ -856,7 +826,7 @@ fail_rqirq: /* clean up twl4030_sih_setup */ fail: for (i = irq_base; i < irq_end; i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); destroy_workqueue(wq); wq = NULL; return status; diff --git a/drivers/mfd/twl6030-irq.c b/drivers/mfd/twl6030-irq.c index 4082ed73613..fa937052fba 100644 --- a/drivers/mfd/twl6030-irq.c +++ b/drivers/mfd/twl6030-irq.c @@ -140,22 +140,7 @@ static int twl6030_irq_thread(void *data) if (sts.int_sts & 0x1) { int module_irq = twl6030_irq_base + twl6030_interrupt_mapping[i]; - struct irq_desc *d = irq_to_desc(module_irq); - - if (!d) { - pr_err("twl6030: Invalid SIH IRQ: %d\n", - module_irq); - return -EINVAL; - } - - /* These can't be masked ... always warn - * if we get any surprises. - */ - if (d->status & IRQ_DISABLED) - note_interrupt(module_irq, d, - IRQ_NONE); - else - d->handle_irq(module_irq, d); + generic_handle_irq(module_irq); } local_irq_enable(); @@ -198,7 +183,7 @@ static inline void activate_irq(int irq) set_irq_flags(irq, IRQF_VALID); #else /* same effect on other architectures */ - set_irq_noprobe(irq); + irq_set_noprobe(irq); #endif } @@ -335,8 +320,8 @@ int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end) twl6030_irq_chip.irq_set_type = NULL; for (i = irq_base; i < irq_end; i++) { - set_irq_chip_and_handler(i, &twl6030_irq_chip, - handle_simple_irq); + irq_set_chip_and_handler(i, &twl6030_irq_chip, + handle_simple_irq); activate_irq(i); } @@ -365,7 +350,7 @@ fail_irq: fail_kthread: for (i = irq_base; i < irq_end; i++) - set_irq_chip_and_handler(i, NULL, NULL); + irq_set_chip_and_handler(i, NULL, NULL); return status; } diff --git a/drivers/mfd/wl1273-core.c b/drivers/mfd/wl1273-core.c index f76f6c79804..04914f2836c 100644 --- a/drivers/mfd/wl1273-core.c +++ b/drivers/mfd/wl1273-core.c @@ -25,7 +25,7 @@ #define DRIVER_DESC "WL1273 FM Radio Core" -static struct i2c_device_id wl1273_driver_id_table[] = { +static const struct i2c_device_id wl1273_driver_id_table[] = { { WL1273_FM_DRIVER_NAME, 0 }, { } }; diff --git a/drivers/mfd/wm831x-irq.c b/drivers/mfd/wm831x-irq.c index a5cd17e18d0..23e66af89de 100644 --- a/drivers/mfd/wm831x-irq.c +++ b/drivers/mfd/wm831x-irq.c @@ -553,17 +553,17 @@ int wm831x_irq_init(struct wm831x *wm831x, int irq) for (cur_irq = wm831x->irq_base; cur_irq < ARRAY_SIZE(wm831x_irqs) + wm831x->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm831x); - set_irq_chip_and_handler(cur_irq, &wm831x_irq_chip, + irq_set_chip_data(cur_irq, wm831x); + irq_set_chip_and_handler(cur_irq, &wm831x_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c index 5839966ebd8..ed4b22a167b 100644 --- a/drivers/mfd/wm8350-irq.c +++ b/drivers/mfd/wm8350-irq.c @@ -518,17 +518,17 @@ int wm8350_irq_init(struct wm8350 *wm8350, int irq, for (cur_irq = wm8350->irq_base; cur_irq < ARRAY_SIZE(wm8350_irqs) + wm8350->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm8350); - set_irq_chip_and_handler(cur_irq, &wm8350_irq_chip, + irq_set_chip_data(cur_irq, wm8350); + irq_set_chip_and_handler(cur_irq, &wm8350_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/drivers/mfd/wm8994-irq.c b/drivers/mfd/wm8994-irq.c index 1e3bf4a2ff8..71c6e8f9aed 100644 --- a/drivers/mfd/wm8994-irq.c +++ b/drivers/mfd/wm8994-irq.c @@ -278,17 +278,17 @@ int wm8994_irq_init(struct wm8994 *wm8994) for (cur_irq = wm8994->irq_base; cur_irq < ARRAY_SIZE(wm8994_irqs) + wm8994->irq_base; cur_irq++) { - set_irq_chip_data(cur_irq, wm8994); - set_irq_chip_and_handler(cur_irq, &wm8994_irq_chip, + irq_set_chip_data(cur_irq, wm8994); + irq_set_chip_and_handler(cur_irq, &wm8994_irq_chip, handle_edge_irq); - set_irq_nested_thread(cur_irq, 1); + irq_set_nested_thread(cur_irq, 1); /* ARM needs us to explicitly flag the IRQ as valid * and will set them noprobe when we do so. */ #ifdef CONFIG_ARM set_irq_flags(cur_irq, IRQF_VALID); #else - set_irq_noprobe(cur_irq); + irq_set_noprobe(cur_irq); #endif } diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h index 1408bf8eed5..ad1b19aa650 100644 --- a/include/linux/mfd/core.h +++ b/include/linux/mfd/core.h @@ -63,6 +63,24 @@ extern int mfd_cell_enable(struct platform_device *pdev); extern int mfd_cell_disable(struct platform_device *pdev); /* + * "Clone" multiple platform devices for a single cell. This is to be used + * for devices that have multiple users of a cell. For example, if an mfd + * driver wants the cell "foo" to be used by a GPIO driver, an MTD driver, + * and a platform driver, the following bit of code would be use after first + * calling mfd_add_devices(): + * + * const char *fclones[] = { "foo-gpio", "foo-mtd" }; + * err = mfd_clone_cells("foo", fclones, ARRAY_SIZE(fclones)); + * + * Each driver (MTD, GPIO, and platform driver) would then register + * platform_drivers for "foo-mtd", "foo-gpio", and "foo", respectively. + * The cell's .enable/.disable hooks should be used to deal with hardware + * resource contention. + */ +extern int mfd_clone_cell(const char *cell, const char **clones, + size_t n_clones); + +/* * Given a platform device that's been created by mfd_add_devices(), fetch * the mfd_cell that created it. */ @@ -87,13 +105,4 @@ extern int mfd_add_devices(struct device *parent, int id, extern void mfd_remove_devices(struct device *parent); -/* - * For MFD drivers with clients sharing access to resources, these create - * multiple platform devices per cell. Contention handling must still be - * handled via drivers (ie, with enable/disable hooks). - */ -extern int mfd_shared_platform_driver_register(struct platform_driver *drv, - const char *cellname); -extern void mfd_shared_platform_driver_unregister(struct platform_driver *drv); - #endif diff --git a/include/linux/mfd/max8997-private.h b/include/linux/mfd/max8997-private.h index 93a9477e075..69d1010e2e5 100644 --- a/include/linux/mfd/max8997-private.h +++ b/include/linux/mfd/max8997-private.h @@ -24,6 +24,8 @@ #include <linux/i2c.h> +#define MAX8997_REG_INVALID (0xff) + enum max8997_pmic_reg { MAX8997_REG_PMIC_ID0 = 0x00, MAX8997_REG_PMIC_ID1 = 0x01, @@ -313,6 +315,7 @@ enum max8997_irq { #define MAX8997_REG_BUCK2DVS(x) (MAX8997_REG_BUCK2DVS1 + (x) - 1) #define MAX8997_REG_BUCK5DVS(x) (MAX8997_REG_BUCK5DVS1 + (x) - 1) +#define MAX8997_NUM_GPIO 12 struct max8997_dev { struct device *dev; struct i2c_client *i2c; /* 0xcc / PMIC, Battery Control, and FLASH */ @@ -324,11 +327,19 @@ struct max8997_dev { int type; struct platform_device *battery; /* battery control (not fuel gauge) */ + int irq; + int ono; + int irq_base; bool wakeup; + struct mutex irqlock; + int irq_masks_cur[MAX8997_IRQ_GROUP_NR]; + int irq_masks_cache[MAX8997_IRQ_GROUP_NR]; /* For hibernation */ u8 reg_dump[MAX8997_REG_PMIC_END + MAX8997_MUIC_REG_END + MAX8997_HAPTIC_REG_END]; + + bool gpio_status[MAX8997_NUM_GPIO]; }; enum max8997_types { @@ -336,6 +347,10 @@ enum max8997_types { TYPE_MAX8966, }; +extern int max8997_irq_init(struct max8997_dev *max8997); +extern void max8997_irq_exit(struct max8997_dev *max8997); +extern int max8997_irq_resume(struct max8997_dev *max8997); + extern int max8997_read_reg(struct i2c_client *i2c, u8 reg, u8 *dest); extern int max8997_bulk_read(struct i2c_client *i2c, u8 reg, int count, u8 *buf); @@ -344,4 +359,10 @@ extern int max8997_bulk_write(struct i2c_client *i2c, u8 reg, int count, u8 *buf); extern int max8997_update_reg(struct i2c_client *i2c, u8 reg, u8 val, u8 mask); +#define MAX8997_GPIO_INT_BOTH (0x3 << 4) +#define MAX8997_GPIO_INT_RISE (0x2 << 4) +#define MAX8997_GPIO_INT_FALL (0x1 << 4) + +#define MAX8997_GPIO_INT_MASK (0x3 << 4) +#define MAX8997_GPIO_DATA_MASK (0x1 << 2) #endif /* __LINUX_MFD_MAX8997_PRIV_H */ diff --git a/include/linux/mfd/max8997.h b/include/linux/mfd/max8997.h index cb671b3451b..60931d08942 100644 --- a/include/linux/mfd/max8997.h +++ b/include/linux/mfd/max8997.h @@ -78,8 +78,11 @@ struct max8997_regulator_data { }; struct max8997_platform_data { - bool wakeup; - /* IRQ: Not implemented */ + /* IRQ */ + int irq_base; + int ono; + int wakeup; + /* ---- PMIC ---- */ struct max8997_regulator_data *regulators; int num_regulators; |