From patchwork Fri Sep 22 18:41:47 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bernd Edlinger X-Patchwork-Id: 817666 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-gpio-owner@vger.kernel.org; receiver=) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3xzMlM4GhXz9s4s for ; Sat, 23 Sep 2017 04:41:51 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751880AbdIVSlu (ORCPT ); Fri, 22 Sep 2017 14:41:50 -0400 Received: from mail-oln040092071107.outbound.protection.outlook.com ([40.92.71.107]:52219 "EHLO EUR03-DB5-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751868AbdIVSlt (ORCPT ); Fri, 22 Sep 2017 14:41:49 -0400 Received: from AM5EUR03FT051.eop-EUR03.prod.protection.outlook.com (10.152.16.54) by AM5EUR03HT241.eop-EUR03.prod.protection.outlook.com (10.152.16.188) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.20.35.14; Fri, 22 Sep 2017 18:41:47 +0000 Received: from AM5PR0701MB2657.eurprd07.prod.outlook.com (10.152.16.55) by AM5EUR03FT051.mail.protection.outlook.com (10.152.16.246) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256_P256) id 15.20.56.11 via Frontend Transport; Fri, 22 Sep 2017 18:41:47 +0000 Received: from AM5PR0701MB2657.eurprd07.prod.outlook.com ([fe80::8c96:1341:5db1:7f8c]) by AM5PR0701MB2657.eurprd07.prod.outlook.com ([fe80::8c96:1341:5db1:7f8c%18]) with mapi id 15.20.0077.011; Fri, 22 Sep 2017 18:41:47 +0000 From: Bernd Edlinger To: "linux-gpio@vger.kernel.org" CC: Linus Walleij Subject: [PATCH] Add a GPIO driver for Altera FPGA Manager Fabric I/O Thread-Topic: [PATCH] Add a GPIO driver for Altera FPGA Manager Fabric I/O Thread-Index: AQHTM9JxJ2gQJ6Z1CEqEycwuEcrPDQ== Date: Fri, 22 Sep 2017 18:41:47 +0000 Message-ID: Accept-Language: de-DE, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: vger.kernel.org; dkim=none (message not signed) header.d=none; vger.kernel.org; dmarc=none action=none header.from=hotmail.de; x-incomingtopheadermarker: OriginalChecksum:9711EC83663EC4F55FD239026CED1E89B73C06C08DD714875C9DF6B1060DD7A1; UpperCasedChecksum:BF13FE09AA149BB4D3BBABFCDCFFFE18BEB2C470F85CE9ED0F815508CA5E8C67; SizeAsReceived:7036; Count:45 x-ms-exchange-messagesentrepresentingtype: 1 x-tmn: [6AWIL0Ac/YqhACXWzXsNNh0fiN3gx3oG] x-ms-publictraffictype: Email x-microsoft-exchange-diagnostics: 1; AM5EUR03HT241; 6:RJIveD30rtu+zipXJCR3tVLdOc1XogOQeE67Sa7llW8k5hxbCMrm5coFJMBlJiFli/TJXHKnFcDS6rK8bMeV0mViiJmnAsHTB1Iw9zM+HBVQpX/ivze5qDzD/fqZFN8dxVfzkl4Vly4FkERa41Qpa74P7yoEZ/+KsR5WuosLOMA9YznGuJnvXZx3hx86jBufHrrOJyhRdj/lfS3w/KDIkymIBFUFxhKjgeQoGhWiX647rGerV1gSh7Y+ga/NjqT8RxecFA+FKT4eLbrzh41LZi1k+KxBFqpBUXlentGz1JDj4zSAhzDMeSgU9Oie22RU9+JcyOfHd3h43mX3Q3Paog==; 5:ywZ4Sh7/duRxrm1C9nJIRIjZS01I7kkNjiMbOZ3aV4Jk00HGs03kzqjIrbS4G2gmZn0ritBglIvvZCp72Fy13YJp/QHeGyI+tYAb+9BDi2MFQphAT7JZ5podoAv4QQoSRo4dx4HqskE+wF8gKVDZBw==; 24:JnMQlloqhkdsUpWqi+q8gNqR34WbJym5aDHR/jVSKjgjEYjdO3/cXdVnXiVlF7ocAJ4E4o99WroXHYzbOpHP0QM664WNKxEGwPoXI3kbd78=; 7:rPQDxkw0MSwk2DyZKsNU4XGdiTmDvEXCZSHOnimng95sFhGXafm8c5klTY5W2Cmmhtd4QFY4m1XEQ6Q7pjhaZ87J8WQNLvlVUmsEpeomHpIKhjnARgJLmAk6DtCF+TvQnD1+Ws12xMB3VGPfnGb+HMllurEJmWeR+SxbEptf1z1cbhmtJHSCk/LvkaGQ8Qwdf/I6g7z8Z0dmk0cLVuvPDzeKb7H997SXA58fHqAEnh4= x-incomingheadercount: 45 x-eopattributedmessage: 0 x-ms-office365-filtering-correlation-id: 5d788114-9002-4fd4-daa3-08d501e99425 x-microsoft-antispam: UriScan:; BCL:0; PCL:0; RULEID:(300000500095)(300135000095)(300000501095)(300135300095)(22001)(300000502095)(300135100095)(300000503095)(300135400095)(201702061074)(5061506573)(5061507331)(1603103135)(2017031320274)(2017031324274)(2017031323274)(2017031322404)(1601125374)(1603101448)(1701031045)(300000504095)(300135200095)(300000505095)(300135600095)(300000506095)(300135500095); SRVR:AM5EUR03HT241; x-ms-traffictypediagnostic: AM5EUR03HT241: x-exchange-antispam-report-test: UriScan:(158256107679635); x-exchange-antispam-report-cfa-test: BCL:0; PCL:0; RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(444000031); SRVR:AM5EUR03HT241; BCL:0; PCL:0; RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095); SRVR:AM5EUR03HT241; x-forefront-prvs: 0438F90F17 x-forefront-antispam-report: SFV:NSPM; SFS:(7070007)(98901004); DIR:OUT; SFP:1901; SCL:1; SRVR:AM5EUR03HT241; H:AM5PR0701MB2657.eurprd07.prod.outlook.com; FPR:; SPF:None; LANG:; spamdiagnosticoutput: 1:99 spamdiagnosticmetadata: NSPM Content-ID: <8FF4A5484827E04DB26319BB28D7D2DE@eurprd07.prod.outlook.com> MIME-Version: 1.0 X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-originalarrivaltime: 22 Sep 2017 18:41:47.4184 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Internet X-MS-Exchange-CrossTenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM5EUR03HT241 Sender: linux-gpio-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-gpio@vger.kernel.org This is an internal 32-bit input and 32-bit output port to the FPGA logic. Instantiate this in the device tree as: gpio3: gpio@ff706010 { #address-cells = <1>; #size-cells = <0>; compatible = "altr,fpgamgr-gpio"; reg = <0xff706010 0x8>; status = "okay"; portd: gpio-controller@0 { compatible = "altr,fpgamgr-gpio-output"; gpio-controller; #gpio-cells = <2>; reg = <0>; }; porte: gpio-controller@1 { compatible = "altr,fpgamgr-gpio-input"; gpio-controller; #gpio-cells = <2>; reg = <1>; }; }; Signed-off-by: Bernd Edlinger --- drivers/gpio/Kconfig | 6 ++ drivers/gpio/Makefile | 1 + drivers/gpio/gpio-fpgamgr.c | 256 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 263 insertions(+) create mode 100644 drivers/gpio/gpio-fpgamgr.c +MODULE_DESCRIPTION("Altera fpgamgr GPIO driver"); -- 2.7.4 Signed-off-by: Bernd Edlinger diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 3388d54..e0c5a35 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -192,6 +192,12 @@ config GPIO_EXAR Selecting this option will enable handling of GPIO pins present on Exar XR17V352/354/358 chips. +config GPIO_FPGAMGR + tristate "Altera FPGAMGR GPIO" + depends on OF_GPIO + help + Say yes here to support the Altera FPGAMGR GPIO device. + config GPIO_GE_FPGA bool "GE FPGA based GPIO" depends on GE_FPGA diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index aeb70e9d..88a32ab 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -50,6 +50,7 @@ obj-$(CONFIG_GPIO_ETRAXFS) += gpio-etraxfs.o obj-$(CONFIG_GPIO_EXAR) += gpio-exar.o obj-$(CONFIG_GPIO_F7188X) += gpio-f7188x.o obj-$(CONFIG_GPIO_FTGPIO010) += gpio-ftgpio010.o +obj-$(CONFIG_GPIO_FPGAMGR) += gpio-fpgamgr.o obj-$(CONFIG_GPIO_GE_FPGA) += gpio-ge.o obj-$(CONFIG_GPIO_GPIO_MM) += gpio-gpio-mm.o obj-$(CONFIG_GPIO_GRGPIO) += gpio-grgpio.o diff --git a/drivers/gpio/gpio-fpgamgr.c b/drivers/gpio/gpio-fpgamgr.c new file mode 100644 index 0000000..8aa86e7 --- /dev/null +++ b/drivers/gpio/gpio-fpgamgr.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2015 Softing Industrial Automation GmbH + * + * 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. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct fpgamgr_port_property { + struct device_node *node; + const char *name; + unsigned int idx; +}; + +struct fpgamgr_platform_data { + struct fpgamgr_port_property *properties; + unsigned int nports; +}; + +struct fpgamgr_gpio_port { + struct gpio_chip bgc; + bool is_registered; + struct fpgamgr_gpio *gpio; + unsigned int idx; +}; + +struct fpgamgr_gpio { + struct device *dev; + void __iomem *regs; + struct fpgamgr_gpio_port *ports; + unsigned int nr_ports; +}; + +static int fpgamgr_gpio_add_port(struct fpgamgr_gpio *gpio, + struct fpgamgr_port_property *pp, + unsigned int offs) +{ + struct fpgamgr_gpio_port *port; + void __iomem *dat; + int err; + + port = &gpio->ports[offs]; + port->gpio = gpio; + port->idx = pp->idx; + + dat = gpio->regs + (pp->idx * 4); + + err = bgpio_init(&port->bgc, gpio->dev, 4, dat, NULL, NULL, + NULL, NULL, 0); + if (err) { + dev_err(gpio->dev, "failed to init gpio chip for %s\n", + pp->name); + return err; + } + +#ifdef CONFIG_OF_GPIO + port->bgc.of_node = pp->node; +#endif + + err = gpiochip_add(&port->bgc); + if (err) + dev_err(gpio->dev, "failed to register gpiochip for %s\n", + pp->name); + else + port->is_registered = true; + + return err; +} + +static void fpgamgr_gpio_unregister(struct fpgamgr_gpio *gpio) +{ + unsigned int m; + + for (m = 0; m < gpio->nr_ports; ++m) + if (gpio->ports[m].is_registered) + gpiochip_remove(&gpio->ports[m].bgc); +} + +static struct fpgamgr_platform_data * +fpgamgr_gpio_get_pdata_of(struct device *dev) +{ + struct device_node *node, *port_np; + struct fpgamgr_platform_data *pdata; + struct fpgamgr_port_property *pp; + int nports; + int i; + + node = dev->of_node; + if (!IS_ENABLED(CONFIG_OF_GPIO) || !node) + return ERR_PTR(-ENODEV); + + nports = of_get_child_count(node); + if (nports == 0) + return ERR_PTR(-ENODEV); + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL); + if (!pdata->properties) { + kfree(pdata); + return ERR_PTR(-ENOMEM); + } + + pdata->nports = nports; + + i = 0; + for_each_child_of_node(node, port_np) { + pp = &pdata->properties[i++]; + pp->node = port_np; + + if (of_property_read_u32(port_np, "reg", &pp->idx) || + pp->idx > 1) { + dev_err(dev, "missing/invalid port index for %s\n", + port_np->full_name); + kfree(pdata->properties); + kfree(pdata); + return ERR_PTR(-EINVAL); + } + + pp->name = port_np->full_name; + } + + return pdata; +} + +static inline void fpgamgr_free_pdata_of(struct fpgamgr_platform_data *pdata) +{ + if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata) + return; + + kfree(pdata->properties); + kfree(pdata); +} + +static int fpgamgr_gpio_probe(struct platform_device *pdev) +{ + unsigned int i; + struct resource *res; + struct fpgamgr_gpio *gpio; + int err; + struct device *dev = &pdev->dev; + struct fpgamgr_platform_data *pdata = dev_get_platdata(dev); + bool is_pdata_alloc = !pdata; + + if (is_pdata_alloc) { + pdata = fpgamgr_gpio_get_pdata_of(dev); + if (IS_ERR(pdata)) + return PTR_ERR(pdata); + } + + if (!pdata->nports) { + err = -ENODEV; + goto out_err; + } + + gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); + if (!gpio) { + err = -ENOMEM; + goto out_err; + } + gpio->dev = &pdev->dev; + gpio->nr_ports = pdata->nports; + + gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports, + sizeof(*gpio->ports), GFP_KERNEL); + if (!gpio->ports) { + err = -ENOMEM; + goto out_err; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gpio->regs = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(gpio->regs)) { + err = PTR_ERR(gpio->regs); + goto out_err; + } + + for (i = 0; i < gpio->nr_ports; i++) { + err = fpgamgr_gpio_add_port(gpio, &pdata->properties[i], i); + if (err) + goto out_unregister; + } + platform_set_drvdata(pdev, gpio); + + goto out_err; + +out_unregister: + fpgamgr_gpio_unregister(gpio); + +out_err: + if (is_pdata_alloc) + fpgamgr_free_pdata_of(pdata); + + return err; +} + +static int fpgamgr_gpio_remove(struct platform_device *pdev) +{ + struct fpgamgr_gpio *gpio = platform_get_drvdata(pdev); + + fpgamgr_gpio_unregister(gpio); + + return 0; +} + +static const struct of_device_id fpgamgr_of_match[] = { + { .compatible = "altr,fpgamgr-gpio" }, + { /* Sentinel */ } +}; +MODULE_DEVICE_TABLE(of, fpgamgr_of_match); + +#ifdef CONFIG_PM_SLEEP +static int fpgamgr_gpio_suspend(struct device *dev) +{ + return 0; +} + +static int fpgamgr_gpio_resume(struct device *dev) +{ + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(fpgamgr_gpio_pm_ops, fpgamgr_gpio_suspend, + fpgamgr_gpio_resume); + +static struct platform_driver fpgamgr_gpio_driver = { + .driver = { + .name = "gpio-fpgamgr", + .owner = THIS_MODULE, + .pm = &fpgamgr_gpio_pm_ops, + .of_match_table = of_match_ptr(fpgamgr_of_match), + }, + .probe = fpgamgr_gpio_probe, + .remove = fpgamgr_gpio_remove, +}; + +module_platform_driver(fpgamgr_gpio_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bernd Edlinger");