From patchwork Fri Jun 26 00:01:31 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Brownell X-Patchwork-Id: 32481 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n5Q05cCl029723 for ; Fri, 26 Jun 2009 00:05:39 GMT Received: from dlep35.itg.ti.com ([157.170.170.118]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id n5Q03aiE029642; Thu, 25 Jun 2009 19:03:41 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep35.itg.ti.com (8.13.7/8.13.7) with ESMTP id n5Q03Y6Z000598; Thu, 25 Jun 2009 19:03:34 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 654C680627; Thu, 25 Jun 2009 19:03:32 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp51.itg.ti.com (dflp51.itg.ti.com [128.247.22.94]) by linux.omap.com (Postfix) with ESMTP id CFC8E80626 for ; Thu, 25 Jun 2009 19:03:31 -0500 (CDT) Received: from medina.ext.ti.com (localhost [127.0.0.1]) by dflp51.itg.ti.com (8.13.7/8.13.7) with ESMTP id n5Q03Vju021310 for ; Thu, 25 Jun 2009 19:03:31 -0500 (CDT) Received: from mail68-tx2-R.bigfish.com (mail-tx2.bigfish.com [65.55.88.112]) by medina.ext.ti.com (8.13.7/8.13.7) with ESMTP id n5Q03QG8012047 for ; Thu, 25 Jun 2009 19:03:31 -0500 Received: from mail68-tx2 (localhost.localdomain [127.0.0.1]) by mail68-tx2-R.bigfish.com (Postfix) with ESMTP id 220EC9102C5 for ; Fri, 26 Jun 2009 00:03:26 +0000 (UTC) X-SpamScore: 0 X-BigFish: vps0(zzzz1202hzzz2dh5eh6bh61h) X-Spam-TCS-SCL: 0:0 X-FB-SS: 5, X-MS-Exchange-Organization-Antispam-Report: OrigIP: 67.195.14.95; Service: EHS Received: by mail68-tx2 (MessageSwitch) id 1245974603686699_16797; Fri, 26 Jun 2009 00:03:23 +0000 (UCT) Received: from smtp110.sbc.mail.gq1.yahoo.com (smtp110.sbc.mail.gq1.yahoo.com [67.195.14.95]) by mail68-tx2.bigfish.com (Postfix) with SMTP id 44FF216D004B for ; Fri, 26 Jun 2009 00:03:23 +0000 (UTC) Received: (qmail 49405 invoked from network); 26 Jun 2009 00:03:22 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=pacbell.net; h=Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Subject:Date:User-Agent:MIME-Version:Content-Disposition:Message-Id:Content-Type:Content-Transfer-Encoding; b=Gn9rbHF64To+BpXnWtNhGyGAanajJrZNFBEr6o+VnNWcLoCBbIacXh0NtGkhtAk4st3Lde3fH7An0leGwjn/05kEu+IiqnM7CBZXpaADLaAwDrihoM62+Kp8eFetFaFw2gu/LqkmZ0CFWptQMASuYuh7PhloPYZ7bnmVkdAUcRw= ; Received: from unknown (HELO albert) (david-b@69.226.238.162 with plain) by smtp110.sbc.mail.gq1.yahoo.com with SMTP; 26 Jun 2009 00:03:22 -0000 X-Yahoo-SMTP: HIlLYKCswBDnjrunw3O.NnLyvismjGf1HBYfVTvuneM- X-YMail-OSG: b4gjjzYVM1kW4hNWODRTfSVwk2KBhT1mfCtuJ9lqONsVB7sM2s1hrUCZjkpq8KCQ2SJOTeQjwHdxeghTYx.tjoIGFF7mhWpcPbkXTkjEDWyKewUEXOChxzZsvE2im5B5rrBxu6nLT2hwhlJZa3CEJ08qXM22rIE2nXvctD82SHE6H0.n9OS2gbiatqoQNZvE5O_gZ6TBWBlrjz8eCzF9YEDLMemxOf2NPI9VvKtKwP4VsdsKLYUi0NjiKiGdJ7P8sbey3IFFIGufL9JG8jV4Xcu2R70KJREtAKJ0yFgwzUuKY5h1.fDWXwAcIQ-- X-Yahoo-Newman-Property: ymail-3 From: David Brownell To: DaVinci Date: Thu, 25 Jun 2009 17:01:31 -0700 User-Agent: KMail/1.9.10 MIME-Version: 1.0 Content-Disposition: inline Message-Id: <200906251701.31774.david-b@pacbell.net> Subject: [patch davinci-git] davinci: dm365 gpio irq support X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.4 Precedence: list List-Id: davinci-linux-open-source.linux.davincidsp.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com From: David Brownell Support DM365 GPIOs ... primarily by handling non-banked GPIO IRQs: - Flag DM365 chips as using non-banked GPIO interrupts, using a new soc_info field. - Replace the gpio_to_irq() mapping logic. This now uses some runtime infrastructure, keyed off that new soc_info field, which doesn't handle irq_to_gpio(). - Provide a new irq_chip ... GPIO IRQs handled directly by AINTC still need edge triggering managed by the GPIO controller. DM365 chips no longer falsely report 104 GPIO IRQs as they boot. Intelligence about IRQ muxing is missing, so for the moment this only exposes the first eight DM365 GPIOs, which are never muxed. The next eight are muxed, half with Ethernet (which uses most of those pins anyway). Tested on DM355 (10 unbanked IRQs _or_ 104 banked ones) and also on DM365 (16 unbanked ones, only 8 made available). Signed-off-by: David Brownell --- arch/arm/mach-davinci/dm365.c | 3 arch/arm/mach-davinci/gpio.c | 105 ++++++++++++++++++++++++-- arch/arm/mach-davinci/include/mach/common.h | 1 arch/arm/mach-davinci/include/mach/gpio.h | 8 - 4 files changed, 105 insertions(+), 12 deletions(-) --- a/arch/arm/mach-davinci/dm365.c +++ b/arch/arm/mach-davinci/dm365.c @@ -878,7 +878,8 @@ static struct davinci_soc_info davinci_s .timer_info = &dm365_timer_info, .gpio_base = IO_ADDRESS(DAVINCI_GPIO_BASE), .gpio_num = 104, - .gpio_irq = 44, + .gpio_irq = IRQ_DM365_GPIO0, + .gpio_unbanked = 8, /* really 16 ... skip muxed GPIOs */ .serial_dev = &dm365_serial_device, .emac_pdata = &dm365_emac_pdata, .sram_dma = 0x00010000, --- a/arch/arm/mach-davinci/gpio.c +++ b/arch/arm/mach-davinci/gpio.c @@ -34,6 +34,7 @@ static DEFINE_SPINLOCK(gpio_lock); struct davinci_gpio { struct gpio_chip chip; struct gpio_controller *__iomem regs; + int irq_base; }; static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)]; @@ -161,8 +162,7 @@ pure_initcall(davinci_gpio_setup); * used as output pins ... which is convenient for testing. * * NOTE: The first few GPIOs also have direct INTC hookups in addition - * to their GPIOBNK0 irq, with a bit less overhead but less flexibility - * on triggering (e.g. no edge options). We don't try to use those. + * to their GPIOBNK0 irq, with a bit less overhead. * * All those INTC hookups (direct, plus several IRQ banks) can also * serve as EDMA event triggers. @@ -171,7 +171,7 @@ pure_initcall(davinci_gpio_setup); static void gpio_irq_disable(unsigned irq) { struct gpio_controller *__iomem g = get_irq_chip_data(irq); - u32 mask = __gpio_mask(irq_to_gpio(irq)); + u32 mask = (u32) get_irq_data(irq); __raw_writel(mask, &g->clr_falling); __raw_writel(mask, &g->clr_rising); @@ -180,7 +180,7 @@ static void gpio_irq_disable(unsigned ir static void gpio_irq_enable(unsigned irq) { struct gpio_controller *__iomem g = get_irq_chip_data(irq); - u32 mask = __gpio_mask(irq_to_gpio(irq)); + u32 mask = (u32) get_irq_data(irq); unsigned status = irq_desc[irq].status; status &= IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING; @@ -196,7 +196,7 @@ static void gpio_irq_enable(unsigned irq static int gpio_irq_type(unsigned irq, unsigned trigger) { struct gpio_controller *__iomem g = get_irq_chip_data(irq); - u32 mask = __gpio_mask(irq_to_gpio(irq)); + u32 mask = (u32) get_irq_data(irq); if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) return -EINVAL; @@ -260,6 +260,45 @@ gpio_irq_handler(unsigned irq, struct ir /* now it may re-trigger */ } +static int gpio_to_irq_banked(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip); + + if (d->irq_base >= 0) + return d->irq_base + offset; + else + return -ENODEV; +} + +static int gpio_to_irq_unbanked(struct gpio_chip *chip, unsigned offset) +{ + struct davinci_soc_info *soc_info = &davinci_soc_info; + + /* NOTE: we assume for now that only irqs in the first gpio_chip + * can provide direct-mapped IRQs to AINTC (up to 32 GPIOs). + */ + if (offset < soc_info->gpio_unbanked) + return soc_info->gpio_irq + offset; + else + return -ENODEV; +} + +static int gpio_irq_type_unbanked(unsigned irq, unsigned trigger) +{ + struct gpio_controller *__iomem g = get_irq_chip_data(irq); + u32 mask = (u32) get_irq_data(irq); + + if (trigger & ~(IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) + return -EINVAL; + + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_FALLING) + ? &g->set_falling : &g->clr_falling); + __raw_writel(mask, (trigger & IRQ_TYPE_EDGE_RISING) + ? &g->set_rising : &g->clr_rising); + + return 0; +} + /* * NOTE: for suspend/resume, probably best to make a platform_device with * suspend_late/resume_resume calls hooking into results of the set_wake() @@ -275,6 +314,7 @@ static int __init davinci_gpio_irq_setup u32 binten = 0; unsigned ngpio, bank_irq; struct davinci_soc_info *soc_info = &davinci_soc_info; + struct gpio_controller *__iomem g; ngpio = soc_info->gpio_num; @@ -292,12 +332,63 @@ static int __init davinci_gpio_irq_setup } clk_enable(clk); + /* Arrange gpio_to_irq() support, handling either direct IRQs or + * banked IRQs. Having GPIOs in the first GPIO bank use direct + * IRQs, while the others use banked IRQs, would need some setup + * tweaks to recognize hardware which can do that. + */ + for (gpio = 0, bank = 0; gpio < ngpio; bank++, gpio += 32) { + chips[bank].chip.to_irq = gpio_to_irq_banked; + chips[bank].irq_base = soc_info->gpio_unbanked + ? -EINVAL + : (soc_info->intc_irq_num + gpio); + } + + /* + * AINTC can handle direct/unbanked IRQs for GPIOs, with the GPIO + * controller only handling trigger modes. We currently assume no + * IRQ mux conflicts; gpio_irq_type_unbanked() is only for GPIOs. + */ + if (soc_info->gpio_unbanked) { + static struct irq_chip gpio_irqchip_unbanked; + + /* pass "bank 0" GPIO IRQs to AINTC */ + chips[0].chip.to_irq = gpio_to_irq_unbanked; + binten = BIT(0); + + /* AINTC handles mask/unmask; GPIO handles triggering */ + irq = bank_irq; + gpio_irqchip_unbanked = *get_irq_desc_chip(irq_to_desc(irq)); + gpio_irqchip_unbanked.name = "GPIO-AINTC"; + gpio_irqchip_unbanked.set_type = gpio_irq_type_unbanked; + + /* default trigger: both edges */ + g = gpio2controller(0); + __raw_writel(~0, &g->set_falling); + __raw_writel(~0, &g->set_rising); + + /* set the direct IRQs up to use that irqchip */ + for (gpio = 0; gpio < soc_info->gpio_unbanked; gpio++, irq++) { + set_irq_chip(irq, &gpio_irqchip_unbanked); + set_irq_data(irq, (void *) __gpio_mask(gpio)); + set_irq_chip_data(irq, g); + irq_desc[irq].status |= IRQ_TYPE_EDGE_BOTH; + } + + goto done; + } + + /* + * Or, AINTC can handle IRQs for banks of 16 GPIO IRQs, which we + * then chain through our own handler. + */ for (gpio = 0, irq = gpio_to_irq(0), bank = 0; gpio < ngpio; bank++, bank_irq++) { - struct gpio_controller *__iomem g = gpio2controller(gpio); unsigned i; + /* disabled by default, enabled only as needed */ + g = gpio2controller(gpio); __raw_writel(~0, &g->clr_falling); __raw_writel(~0, &g->clr_rising); @@ -309,6 +400,7 @@ static int __init davinci_gpio_irq_setup for (i = 0; i < 16 && gpio < ngpio; i++, irq++, gpio++) { set_irq_chip(irq, &gpio_irqchip); set_irq_chip_data(irq, g); + set_irq_data(irq, (void *) __gpio_mask(gpio)); set_irq_handler(irq, handle_simple_irq); set_irq_flags(irq, IRQF_VALID); } @@ -316,6 +408,7 @@ static int __init davinci_gpio_irq_setup binten |= BIT(bank); } +done: /* BINTEN -- per-bank interrupt enable. genirq would also let these * bits be set/cleared dynamically. */ --- a/arch/arm/mach-davinci/include/mach/common.h +++ b/arch/arm/mach-davinci/include/mach/common.h @@ -63,6 +63,7 @@ struct davinci_soc_info { void __iomem *gpio_base; unsigned gpio_num; unsigned gpio_irq; + unsigned gpio_unbanked; struct platform_device *serial_dev; struct emac_platform_data *emac_pdata; dma_addr_t sram_dma; --- a/arch/arm/mach-davinci/include/mach/gpio.h +++ b/arch/arm/mach-davinci/include/mach/gpio.h @@ -142,15 +142,13 @@ static inline int gpio_cansleep(unsigned static inline int gpio_to_irq(unsigned gpio) { - if (gpio >= DAVINCI_N_GPIO) - return -EINVAL; - return davinci_soc_info.intc_irq_num + gpio; + return __gpio_to_irq(gpio); } static inline int irq_to_gpio(unsigned irq) { - /* caller guarantees gpio_to_irq() succeeded */ - return irq - davinci_soc_info.intc_irq_num; + /* don't support the reverse mapping */ + return -ENOSYS; } #endif /* __DAVINCI_GPIO_H */