From patchwork Thu Jul 31 19:03:25 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Feng Kan X-Patchwork-Id: 4658631 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id BFA349F36A for ; Thu, 31 Jul 2014 19:05:04 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 9E9312015E for ; Thu, 31 Jul 2014 19:05:03 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 7326A20158 for ; Thu, 31 Jul 2014 19:05:02 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XCvd4-0002dY-64; Thu, 31 Jul 2014 19:03:06 +0000 Received: from exprod5og109.obsmtp.com ([64.18.0.188]) by bombadil.infradead.org with smtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XCvct-0002RR-Nl for linux-arm-kernel@lists.infradead.org; Thu, 31 Jul 2014 19:02:56 +0000 Received: from mail-pd0-f178.google.com ([209.85.192.178]) (using TLSv1) by exprod5ob109.postini.com ([64.18.4.12]) with SMTP ID DSNKU9qSyrl7RCTFOMPVUOxPyjySXQ4vNjIq@postini.com; Thu, 31 Jul 2014 12:02:55 PDT Received: by mail-pd0-f178.google.com with SMTP id w10so3981267pde.23 for ; Thu, 31 Jul 2014 12:02:33 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=eJyuNwFA7ECLPDSOp8DL/4Ck8Ul1srF265TA7Hd57cw=; b=QjY/v0B5Su3YByf6BrBQmSBJNBUfrwRjk7EY0HQWRTKH12P1ouLNirdQoG89rGYuxJ 8Deqnpsqeb+D2QPoM9xZ6TBBrwy5+z3n3Dj4FPwP3JfqEeQKWw1qHyJAOMb/8pKzzg9S p0nw7otVNxA30PriozYJKRwEOaWjEvzP5/5e7TXB2JgrcXNrGTU43nbSycgH6DNguQDc DeUpOXxEI9HOYObMF+NWPn1DZOiHMUfIxfFShSzVZOKD/DsEXwCDSI9Oln4QoD91Cv+D pnIoKNPXgbiMBrpNJLRgtlp9T2V4rQUjv+brWAjSyvgwBiOOiubi77UsKkZT9LLnbMCb g7Og== X-Gm-Message-State: ALoCoQlWdvIURyU2OP2hvRBW7TYrynp/9yC/PQMwZGMXapLMKMND0D2dLUihnbtTxcvMHeTGkv/2TFLj/3Q4zZvLnFqQszptGxgoEI8rXxJOtvshvj7By4En9e+3AXik26JqTkcGqp8oT/+amdMiwydvb2BUIZbYqQ== X-Received: by 10.68.251.201 with SMTP id zm9mr213242pbc.22.1406833353941; Thu, 31 Jul 2014 12:02:33 -0700 (PDT) X-Received: by 10.68.251.201 with SMTP id zm9mr213214pbc.22.1406833353774; Thu, 31 Jul 2014 12:02:33 -0700 (PDT) Received: from fkan-lpt.amcc.com (63-147-59-2.dia.static.qwest.net. [63.147.59.2]) by mx.google.com with ESMTPSA id v1sm6309339pbs.1.2014.07.31.12.02.32 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 31 Jul 2014 12:02:32 -0700 (PDT) From: Feng Kan To: patches@apm.com, linus.walleij@linaro.org, gnurou@gmail.com, linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org Subject: [PATCH V6 1/3] gpio: Add APM X-Gene SoC GPIO controller support Date: Thu, 31 Jul 2014 12:03:25 -0700 Message-Id: <1406833407-28316-2-git-send-email-fkan@apm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1406833407-28316-1-git-send-email-fkan@apm.com> References: <1406833407-28316-1-git-send-email-fkan@apm.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140731_120255_841583_62E5AC74 X-CRM114-Status: GOOD ( 18.67 ) X-Spam-Score: -2.3 (--) Cc: Feng Kan X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Add APM X-Gene SoC gpio controller driver. Signed-off-by: Feng Kan --- drivers/gpio/Kconfig | 9 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-xgene.c | 250 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 260 insertions(+) create mode 100644 drivers/gpio/gpio-xgene.c diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 4a1b511..833996a02 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -334,6 +334,15 @@ config GPIO_TZ1090_PDC help Say yes here to support Toumaz Xenif TZ1090 PDC GPIOs. +config GPIO_XGENE + bool "APM X-Gene GPIO controller support" + depends on ARM64 && OF_GPIO + help + This driver is to support the GPIO block within the APM X-Gene SoC + platform's generic flash controller. The GPIO pins are muxed with + the generic flash controller's address and data pins. Say yes + here to enable the GFC GPIO functionality. + config GPIO_XILINX bool "Xilinx GPIO support" depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index d10f6a9..1bf5f82 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -98,6 +98,7 @@ obj-$(CONFIG_GPIO_VX855) += gpio-vx855.o obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o +obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o diff --git a/drivers/gpio/gpio-xgene.c b/drivers/gpio/gpio-xgene.c new file mode 100644 index 0000000..e25ba14 --- /dev/null +++ b/drivers/gpio/gpio-xgene.c @@ -0,0 +1,250 @@ +/* + * AppliedMicro X-Gene SoC GPIO Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Feng Kan . + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_SET_DR_OFFSET 0x0C +#define GPIO_DATA_OFFSET 0x14 +#define GPIO_BANK_STRIDE 0x0C + +#define XGENE_GPIOS_PER_BANK 16 +#define XGENE_MAX_GPIO_BANKS 3 +#define XGENE_MAX_GPIOS (XGENE_GPIOS_PER_BANK * XGENE_MAX_GPIO_BANKS) + +#define GPIO_BIT_OFFSET(x) (x % XGENE_GPIOS_PER_BANK) +#define GPIO_BANK_OFFSET(x) ((x / XGENE_GPIOS_PER_BANK) * GPIO_BANK_STRIDE) + +struct xgene_gpio; + +struct xgene_gpio { + struct gpio_chip chip; + void __iomem *base; + spinlock_t lock; +#ifdef CONFIG_PM + u32 set_dr_val[XGENE_MAX_GPIO_BANKS]; +#endif +}; + +static inline struct xgene_gpio *to_xgene_gpio(struct gpio_chip *chip) +{ + return container_of(chip, struct xgene_gpio, chip); +} + +static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 bit_offset; + + bank_offset = GPIO_DATA_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + return !!(ioread32(chip->base + bank_offset) & BIT(bit_offset)); +} + +static void __xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long bank_offset; + u32 setval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset) + XGENE_GPIOS_PER_BANK; + + setval = ioread32(chip->base + bank_offset); + if (val) + setval |= BIT(bit_offset); + else + setval &= ~BIT(bit_offset); + iowrite32(setval, chip->base + bank_offset); +} + +static void xgene_gpio_set(struct gpio_chip *gc, unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags; + + spin_lock_irqsave(&chip->lock, flags); + __xgene_gpio_set(gc, offset, val); + spin_unlock_irqrestore(&chip->lock, flags); +} + +static int xgene_gpio_dir_in(struct gpio_chip *gc, unsigned int offset) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval |= BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +static int xgene_gpio_dir_out(struct gpio_chip *gc, + unsigned int offset, int val) +{ + struct xgene_gpio *chip = to_xgene_gpio(gc); + unsigned long flags, bank_offset; + u32 dirval, bit_offset; + + bank_offset = GPIO_SET_DR_OFFSET + GPIO_BANK_OFFSET(offset); + bit_offset = GPIO_BIT_OFFSET(offset); + + spin_lock_irqsave(&chip->lock, flags); + + dirval = ioread32(chip->base + bank_offset); + dirval &= ~BIT(bit_offset); + iowrite32(dirval, chip->base + bank_offset); + __xgene_gpio_set(gc, offset, val); + + spin_unlock_irqrestore(&chip->lock, flags); + + return 0; +} + +#ifdef CONFIG_PM +static int xgene_gpio_suspend(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + gpio->set_dr_val[bank] = ioread32(gpio->base + bank_offset); + } + return 0; +} + +static int xgene_gpio_resume(struct device *dev) +{ + struct xgene_gpio *gpio = dev_get_drvdata(dev); + unsigned long bank_offset; + unsigned int bank; + + for (bank = 0; bank < XGENE_MAX_GPIO_BANKS; bank++) { + bank_offset = GPIO_SET_DR_OFFSET + bank * GPIO_BANK_STRIDE; + iowrite32(gpio->set_dr_val[bank], gpio->base + bank_offset); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume); +#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm) +#else +#define XGENE_GPIO_PM_OPS NULL +#endif + +static int xgene_gpio_probe(struct platform_device *pdev) +{ + struct resource *res; + struct xgene_gpio *gpio; + int err = 0; + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + err = -ENOMEM; + goto err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->base = devm_ioremap_nocache(&pdev->dev, res->start, + resource_size(res)); + if (IS_ERR(gpio->base)) { + err = PTR_ERR(gpio->base); + goto err; + } + + gpio->chip.ngpio = XGENE_MAX_GPIOS; + + gpio->chip.dev = &pdev->dev; + gpio->chip.direction_input = xgene_gpio_dir_in; + gpio->chip.direction_output = xgene_gpio_dir_out; + gpio->chip.get = xgene_gpio_get; + gpio->chip.set = xgene_gpio_set; + gpio->chip.label = dev_name(&pdev->dev); + gpio->chip.base = -1; + + platform_set_drvdata(pdev, gpio); + + err = gpiochip_add(&gpio->chip); + if (err) { + dev_err(&pdev->dev, + "failed to register gpiochip.\n"); + goto err; + } + + dev_info(&pdev->dev, "X-Gene GPIO driver registered.\n"); + return 0; +err: + dev_err(&pdev->dev, "X-Gene GPIO driver registration failed.\n"); + return err; +} + +static int xgene_gpio_remove(struct platform_device *pdev) +{ + struct xgene_gpio *gpio = platform_get_drvdata(pdev); + int ret = 0; + + ret = gpiochip_remove(&gpio->chip); + if (ret) + dev_err(&pdev->dev, "unable to remove gpio_chip.\n"); + return ret; +} + +#ifdef CONFIG_OF +static const struct of_device_id xgene_gpio_of_match[] = { + { .compatible = "apm,xgene-gpio", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xgene_gpio_of_match); +#endif + +static struct platform_driver xgene_gpio_driver = { + .driver = { + .name = "xgene-gpio", + .owner = THIS_MODULE, + .of_match_table = xgene_gpio_of_match, + .pm = XGENE_GPIO_PM_OPS, + }, + .probe = xgene_gpio_probe, + .remove = xgene_gpio_remove, +}; + +module_platform_driver(xgene_gpio_driver); + +MODULE_AUTHOR("Feng Kan "); +MODULE_DESCRIPTION("APM X-Gene GPIO driver"); +MODULE_LICENSE("GPL");