From patchwork Mon Jun 11 15:25:01 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lee Jones X-Patchwork-Id: 9200 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 85F1123EB4 for ; Mon, 11 Jun 2012 15:25:40 +0000 (UTC) Received: from mail-yx0-f180.google.com (mail-yx0-f180.google.com [209.85.213.180]) by fiordland.canonical.com (Postfix) with ESMTP id 2C700A186CC for ; Mon, 11 Jun 2012 15:25:40 +0000 (UTC) Received: by yenq6 with SMTP id q6so2835390yen.11 for ; Mon, 11 Jun 2012 08:25:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=bpjrQRX4Z98e7/3LFHK5DCZK32p4L/X0lg7jgMM7a5s=; b=AwnqeBr8dvhEI7WfjtEedszWvEeE1NYkhB4TJSTJXS4ObmgNrsPHh2Lf6OhLRFWi2/ IPsQY5cpy+q7pcDUWF5utCOcgkrv/foRFeJgq/cnKsmDrnwRSVT1WrBUhWbHgjks+aPA xVkcTWlRCmHIS91G3P4sNjqP397jMwXcguYN3Jk8r9bv9RcS3QJUSWohXfsyEPU9iyjr g7ECj1aM/X96t3NzPC4bf+puy0nHZxY9s3ff+SoWx77P1wOljDaLR8cJ4H9uWOXX+dE3 0e9A3xoZXoXRuGMqwNwyQEH9E4/9BYkWFjRGBqvw68gmKNIAAQdPjhtgoqoxrLGWyxuD TTtQ== Received: by 10.50.195.234 with SMTP id ih10mr6670760igc.0.1339428339392; Mon, 11 Jun 2012 08:25:39 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.231.24.148 with SMTP id v20csp115734ibb; Mon, 11 Jun 2012 08:25:38 -0700 (PDT) Received: by 10.14.99.200 with SMTP id x48mr3072074eef.77.1339428338035; Mon, 11 Jun 2012 08:25:38 -0700 (PDT) Received: from mail-we0-f178.google.com (mail-we0-f178.google.com [74.125.82.178]) by mx.google.com with ESMTPS id h46si11093593wed.105.2012.06.11.08.25.37 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 11 Jun 2012 08:25:38 -0700 (PDT) Received-SPF: neutral (google.com: 74.125.82.178 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) client-ip=74.125.82.178; Authentication-Results: mx.google.com; spf=neutral (google.com: 74.125.82.178 is neither permitted nor denied by best guess record for domain of lee.jones@linaro.org) smtp.mail=lee.jones@linaro.org Received: by mail-we0-f178.google.com with SMTP id e53so2963103wer.37 for ; Mon, 11 Jun 2012 08:25:37 -0700 (PDT) Received: by 10.180.83.197 with SMTP id s5mr21792968wiy.9.1339428337502; Mon, 11 Jun 2012 08:25:37 -0700 (PDT) Received: from localhost.localdomain (cpc1-aztw13-0-0-cust473.18-1.cable.virginmedia.com. [77.102.241.218]) by mx.google.com with ESMTPS id ch9sm39413606wib.8.2012.06.11.08.25.35 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 11 Jun 2012 08:25:36 -0700 (PDT) From: Lee Jones To: linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Cc: linus.walleij@stericsson.com, arnd@arndb.de, grant.likely@secretlab.ca, Lee Jones , Samuel Ortiz Subject: [PATCH 08/14] mfd: Add IRQ domain support for the AB8500 Date: Mon, 11 Jun 2012 16:25:01 +0100 Message-Id: <1339428307-3850-9-git-send-email-lee.jones@linaro.org> X-Mailer: git-send-email 1.7.9.5 In-Reply-To: <1339428307-3850-1-git-send-email-lee.jones@linaro.org> References: <1339428307-3850-1-git-send-email-lee.jones@linaro.org> X-Gm-Message-State: ALoCoQl/eQvj5qZX9vYcGNjoExhV7rH2QxbxcqAupK6B1a8CNS8oh3DtCZQWOaVeukMCRzHuxYPP As the AB8500 is an IRQ controller in its own right, here we provide the AB8500 driver with IRQ domain support. This is required if we wish to reference any of its IRQs from a platform's Device Tree. Cc: Samuel Ortiz Signed-off-by: Lee Jones --- drivers/mfd/Kconfig | 1 + drivers/mfd/ab8500-core.c | 112 +++++++++++++++++++++---------------- include/linux/mfd/abx500/ab8500.h | 4 ++ 3 files changed, 70 insertions(+), 47 deletions(-) diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 170072e..e3637c2 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig @@ -696,6 +696,7 @@ config AB8500_CORE bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" depends on GENERIC_HARDIRQS && ABX500_CORE && MFD_DB8500_PRCMU select MFD_CORE + select IRQ_DOMAIN help Select this option to enable access to AB8500 power management chip. This connects to U8500 either on the SSP/SPI bus (deprecated diff --git a/drivers/mfd/ab8500-core.c b/drivers/mfd/ab8500-core.c index 4dc5024..82cd31d 100644 --- a/drivers/mfd/ab8500-core.c +++ b/drivers/mfd/ab8500-core.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -361,7 +362,7 @@ static void ab8500_irq_sync_unlock(struct irq_data *data) static void ab8500_irq_mask(struct irq_data *data) { struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); - int offset = data->irq - ab8500->irq_base; + int offset = data->irq; int index = offset / 8; int mask = 1 << (offset % 8); @@ -371,7 +372,7 @@ static void ab8500_irq_mask(struct irq_data *data) static void ab8500_irq_unmask(struct irq_data *data) { struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data); - int offset = data->irq - ab8500->irq_base; + int offset = data->irq; int index = offset / 8; int mask = 1 << (offset % 8); @@ -501,7 +502,7 @@ static irqreturn_t ab8500_irq(int irq, void *dev) int bit = __ffs(value); int line = i * 8 + bit; - handle_nested_irq(ab8500->irq_base + line); + handle_nested_irq(line); value &= ~(1 << bit); } while (value); @@ -510,38 +511,51 @@ static irqreturn_t ab8500_irq(int irq, void *dev) return IRQ_HANDLED; } -static int ab8500_irq_init(struct ab8500 *ab8500) +/** + * ab8500_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ + * + * Useful for drivers to request their own IRQs. + * + * @ab8500: ab8500_irq controller to operate on. + * @irq: index of the interrupt requested in the chip IRQs + */ +int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq) { - int base = ab8500->irq_base; - int irq; - int num_irqs; + if (!ab8500) + return -EINVAL; - if (is_ab9540(ab8500)) - num_irqs = AB9540_NR_IRQS; - else if (is_ab8505(ab8500)) - num_irqs = AB8505_NR_IRQS; - else - num_irqs = AB8500_NR_IRQS; + return irq_create_mapping(ab8500->domain, irq); +} +EXPORT_SYMBOL_GPL(ab8500_irq_get_virq); + +static int ab8500_irq_map(struct irq_domain *d, unsigned int virq, + irq_hw_number_t hwirq) +{ + struct ab8500 *ab8500 = d->host_data; - for (irq = base; irq < base + num_irqs; irq++) { - irq_set_chip_data(irq, ab8500); - irq_set_chip_and_handler(irq, &ab8500_irq_chip, - handle_simple_irq); - irq_set_nested_thread(irq, 1); + if (!ab8500) + return -EINVAL; + + irq_set_chip_data(virq, ab8500); + irq_set_chip_and_handler(virq, &ab8500_irq_chip, + handle_simple_irq); + irq_set_nested_thread(virq, 1); #ifdef CONFIG_ARM - set_irq_flags(irq, IRQF_VALID); + set_irq_flags(virq, IRQF_VALID); #else - irq_set_noprobe(irq); + irq_set_noprobe(virq); #endif - } return 0; } -static void ab8500_irq_remove(struct ab8500 *ab8500) +static struct irq_domain_ops ab8500_irq_ops = { + .map = ab8500_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int ab8500_irq_init(struct ab8500 *ab8500, struct device_node *np) { - int base = ab8500->irq_base; - int irq; int num_irqs; if (is_ab9540(ab8500)) @@ -551,13 +565,22 @@ static void ab8500_irq_remove(struct ab8500 *ab8500) else num_irqs = AB8500_NR_IRQS; - for (irq = base; irq < base + num_irqs; irq++) { -#ifdef CONFIG_ARM - set_irq_flags(irq, 0); -#endif - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); + if (np) { + ab8500->domain = irq_domain_add_linear( + np, num_irqs, &ab8500_irq_ops, ab8500); + } + else { + ab8500->domain = irq_domain_add_legacy( + NULL, num_irqs, ab8500->irq_base, + 0, &ab8500_irq_ops, ab8500); + } + + if (!ab8500->domain) { + dev_err(ab8500->dev, "Failed to create irqdomain\n"); + return -ENOSYS; } + + return 0; } int ab8500_suspend(struct ab8500 *ab8500) @@ -1233,11 +1256,9 @@ static int __devinit ab8500_probe(struct platform_device *pdev) if (plat) ab8500->irq_base = plat->irq_base; - else if (np) - ret = of_property_read_u32(np, "stericsson,irq-base", &ab8500->irq_base); - if (!ab8500->irq_base) { - dev_info(&pdev->dev, "couldn't find irq-base\n"); + if (!(ab8500->irq_base || np)) { + dev_info(&pdev->dev, "couldn't find irq-base and not doing DT boot\n"); ret = -EINVAL; goto out_free_ab8500; } @@ -1323,7 +1344,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev) AB8500_SWITCH_OFF_STATUS, &value); if (ret < 0) return ret; - dev_info(ab8500->dev, "switch off status: %#x", value); + dev_info(ab8500->dev, "switch off status: %#x\n", value); if (plat && plat->init) plat->init(ab8500); @@ -1352,8 +1373,8 @@ static int __devinit ab8500_probe(struct platform_device *pdev) for (i = 0; i < ab8500->mask_size; i++) ab8500->mask[i] = ab8500->oldmask[i] = 0xff; - if (ab8500->irq_base) { - ret = ab8500_irq_init(ab8500); + if (ab8500->irq_base || np) { + ret = ab8500_irq_init(ab8500, np); if (ret) goto out_freeoldmask; @@ -1370,7 +1391,7 @@ static int __devinit ab8500_probe(struct platform_device *pdev) IRQF_ONESHOT | IRQF_NO_SUSPEND, "ab8500", ab8500); if (ret) - goto out_removeirq; + goto out_freeoldmask; } if (!np) { @@ -1417,15 +1438,12 @@ static int __devinit ab8500_probe(struct platform_device *pdev) &ab8500_attr_group); if (ret) dev_err(ab8500->dev, "error creating sysfs entries\n"); - else - return ret; + + return ret; out_freeirq: - if (ab8500->irq_base) + if (ab8500->irq_base || np) free_irq(ab8500->irq, ab8500); -out_removeirq: - if (ab8500->irq_base) - ab8500_irq_remove(ab8500); out_freeoldmask: kfree(ab8500->oldmask); out_freemask: @@ -1439,16 +1457,16 @@ out_free_ab8500: static int __devexit ab8500_remove(struct platform_device *pdev) { struct ab8500 *ab8500 = platform_get_drvdata(pdev); + struct device_node *np = pdev->dev.of_node; if (is_ab9540(ab8500)) sysfs_remove_group(&ab8500->dev->kobj, &ab9540_attr_group); else sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group); mfd_remove_devices(ab8500->dev); - if (ab8500->irq_base) { + if (ab8500->irq_base || np) free_irq(ab8500->irq, ab8500); - ab8500_irq_remove(ab8500); - } + kfree(ab8500->oldmask); kfree(ab8500->mask); kfree(ab8500); diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h index 91dd3ef..48f126c 100644 --- a/include/linux/mfd/abx500/ab8500.h +++ b/include/linux/mfd/abx500/ab8500.h @@ -227,6 +227,7 @@ enum ab8500_version { * @irq_lock: genirq bus lock * @transfer_ongoing: 0 if no transfer ongoing * @irq: irq line + * @irq_domain: irq domain * @version: chip version id (e.g. ab8500 or ab9540) * @chip_id: chip revision id * @write: register write @@ -247,6 +248,7 @@ struct ab8500 { atomic_t transfer_ongoing; int irq_base; int irq; + struct irq_domain *domain; enum ab8500_version version; u8 chip_id; @@ -336,4 +338,6 @@ static inline int is_ab8500_2p0(struct ab8500 *ab) return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0)); } +int ab8500_irq_get_virq(struct ab8500 *ab8500, int irq); + #endif /* MFD_AB8500_H */