From patchwork Mon Mar 27 06:23:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Nandor Han X-Patchwork-Id: 743635 Return-Path: X-Original-To: incoming-dt@patchwork.ozlabs.org Delivered-To: patchwork-incoming-dt@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 3vs4xm3Jcvz9ryj for ; Mon, 27 Mar 2017 18:13:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751483AbdC0HN0 (ORCPT ); Mon, 27 Mar 2017 03:13:26 -0400 Received: from mx0b-00176a03.pphosted.com ([67.231.157.48]:60510 "EHLO mx0a-00176a03.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1751466AbdC0HNZ (ORCPT ); Mon, 27 Mar 2017 03:13:25 -0400 X-Greylist: delayed 2997 seconds by postgrey-1.27 at vger.kernel.org; Mon, 27 Mar 2017 03:13:23 EDT Received: from pps.filterd (m0048299.ppops.net [127.0.0.1]) by m0048299.ppops.net-00176a03. (8.16.0.20/8.16.0.20) with SMTP id v2R6N6eO036602; Mon, 27 Mar 2017 02:23:24 -0400 From: Nandor Han To: linus.walleij@linaro.org, gnurou@gmail.com, robh+dt@kernel.org, mark.rutland@arm.com, linux-gpio@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Nandor Han , Semi Malinen Subject: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver Date: Mon, 27 Mar 2017 09:23:00 +0300 Message-Id: <6bf04ba1761f0692cb461558f0c8836f0d1f7ad8.1490595641.git.nandor.han@ge.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: References: MIME-Version: 1.0 In-Reply-To: References: X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:, , definitions=2017-03-27_06:, , signatures=0 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 spamscore=0 suspectscore=0 malwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1702020001 definitions=main-1703270058 Sender: devicetree-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: devicetree@vger.kernel.org This is a simple driver that provides a /sys/class/gpio interface for controlling and configuring the GPIO lines. It does not provide support for chip select or interrupts. Signed-off-by: Nandor Han Signed-off-by: Semi Malinen --- .../devicetree/bindings/vendor-prefixes.txt | 1 + drivers/gpio/Kconfig | 5 + drivers/gpio/Makefile | 1 + drivers/gpio/gpio-xra1403.c | 252 +++++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 drivers/gpio/gpio-xra1403.c diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt index 0ad67d5..7ca9d41 100644 --- a/Documentation/devicetree/bindings/vendor-prefixes.txt +++ b/Documentation/devicetree/bindings/vendor-prefixes.txt @@ -103,6 +103,7 @@ ettus NI Ettus Research eukrea Eukréa Electromatique everest Everest Semiconductor Co. Ltd. everspin Everspin Technologies, Inc. +exar Exar Corporation excito Excito ezchip EZchip Semiconductor faraday Faraday Technology Corporation diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6e3cfd..3a6c9a3 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -1208,6 +1208,11 @@ config GPIO_PISOSR GPIO driver for SPI compatible parallel-in/serial-out shift registers. These are input only devices. +config GPIO_XRA1403 + tristate "EXAR XRA1403 16-bit GPIO expander" + help + GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. + endmenu menu "SPI or I2C GPIO expanders" diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index bd995dc..8f50844 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -139,6 +139,7 @@ obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o obj-$(CONFIG_GPIO_XLP) += gpio-xlp.o +obj-$(CONFIG_GPIO_XRA1403) += gpio-xra1403.o obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o obj-$(CONFIG_GPIO_ZYNQ) += gpio-zynq.o diff --git a/drivers/gpio/gpio-xra1403.c b/drivers/gpio/gpio-xra1403.c new file mode 100644 index 0000000..1b7138a8 --- /dev/null +++ b/drivers/gpio/gpio-xra1403.c @@ -0,0 +1,252 @@ +/* + * GPIO driver for EXAR XRA1403 16-bit GPIO expander + * + * Copyright (c) 2017, General Electric Company + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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 + +/* XRA1403 registers */ +#define XRA_GSR 0x00 /* GPIO State */ +#define XRA_OCR 0x02 /* Output Control */ +#define XRA_GCR 0x06 /* GPIO Configuration */ + +/* SPI headers */ +#define XRA_READ 0x80 /* read bit of the SPI command byte */ + +struct xra1403 { + struct mutex lock; + struct gpio_chip chip; + struct spi_device *spi; +}; + +static int xra1403_get_byte(struct xra1403 *xra, unsigned int addr) +{ + return spi_w8r8(xra->spi, XRA_READ | (addr << 1)); +} + +static int xra1403_get_bit(struct xra1403 *xra, unsigned int addr, + unsigned int bit) +{ + int ret; + + ret = xra1403_get_byte(xra, addr + (bit > 7)); + if (ret < 0) + return ret; + + return !!(ret & BIT(bit % 8)); +} + +static int xra1403_set_bit(struct xra1403 *xra, unsigned int addr, + unsigned int bit, int value) +{ + int ret; + u8 mask; + u8 tx[2]; + + addr += bit > 7; + + mutex_lock(&xra->lock); + + ret = xra1403_get_byte(xra, addr); + if (ret < 0) + goto out_unlock; + + mask = BIT(bit % 8); + if (value) + value = ret | mask; + else + value = ret & ~mask; + + if (value != ret) { + tx[0] = addr << 1; + tx[1] = value; + ret = spi_write(xra->spi, tx, sizeof(tx)); + } else { + ret = 0; + } + +out_unlock: + mutex_unlock(&xra->lock); + + return ret; +} + +static int xra1403_direction_input(struct gpio_chip *chip, unsigned int offset) +{ + return xra1403_set_bit(gpiochip_get_data(chip), XRA_GCR, offset, 1); +} + +static int xra1403_direction_output(struct gpio_chip *chip, unsigned int offset, + int value) +{ + int ret; + struct xra1403 *xra = gpiochip_get_data(chip); + + ret = xra1403_set_bit(xra, XRA_OCR, offset, value); + if (ret) + return ret; + + ret = xra1403_set_bit(xra, XRA_GCR, offset, 0); + + return ret; +} + +static int xra1403_get(struct gpio_chip *chip, unsigned int offset) +{ + return xra1403_get_bit(gpiochip_get_data(chip), XRA_GSR, offset); +} + +static void xra1403_set(struct gpio_chip *chip, unsigned int offset, int value) +{ + xra1403_set_bit(gpiochip_get_data(chip), XRA_OCR, offset, value); +} + +#ifdef CONFIG_DEBUG_FS +#define XRA_REGS 0x16 +static void xra1403_dbg_show(struct seq_file *s, struct gpio_chip *chip) +{ + int reg; + struct xra1403 *xra = gpiochip_get_data(chip); + int value[XRA_REGS]; + int i; + unsigned int gcr; + unsigned int gsr; + + seq_puts(s, "xra reg:"); + for (reg = 0; reg < XRA_REGS; reg++) + seq_printf(s, " %2.2x", reg); + seq_puts(s, "\n value:"); + for (reg = 0; reg < XRA_REGS; reg++) { + value[reg] = xra1403_get_byte(xra, reg); + seq_printf(s, " %2.2x", value[reg]); + } + seq_puts(s, "\n"); + + gcr = value[XRA_GCR + 1] << 8 | value[XRA_GCR]; + gsr = value[XRA_GSR + 1] << 8 | value[XRA_GSR]; + for (i = 0; i < chip->ngpio; i++) { + const char *label = gpiochip_is_requested(chip, i); + + if (!label) + continue; + + seq_printf(s, " gpio-%-3d (%-12s) %s %s\n", + chip->base + i, label, + (gcr & BIT(i)) ? "in" : "out", + (gsr & BIT(i)) ? "hi" : "lo"); + } +} +#else +#define xra1403_dbg_show NULL +#endif + +static int xra1403_probe(struct spi_device *spi) +{ + struct xra1403 *xra; + struct gpio_desc *reset_gpio; + + xra = devm_kzalloc(&spi->dev, sizeof(*xra), GFP_KERNEL); + if (!xra) + return -ENOMEM; + + /* bring the chip out of reset */ + reset_gpio = gpiod_get_optional(&spi->dev, "reset", GPIOD_OUT_LOW); + if (IS_ERR(reset_gpio)) + dev_warn(&spi->dev, "could not get reset-gpios\n"); + else if (reset_gpio) + gpiod_put(reset_gpio); + + mutex_init(&xra->lock); + + xra->chip.direction_input = xra1403_direction_input; + xra->chip.direction_output = xra1403_direction_output; + xra->chip.get = xra1403_get; + xra->chip.set = xra1403_set; + xra->chip.dbg_show = xra1403_dbg_show; + + xra->chip.ngpio = 16; + xra->chip.label = "xra1403"; + + xra->chip.base = -1; + xra->chip.can_sleep = true; + xra->chip.parent = &spi->dev; + xra->chip.owner = THIS_MODULE; + + xra->spi = spi; + spi_set_drvdata(spi, xra); + + return gpiochip_add_data(&xra->chip, xra); +} + +static int xra1403_remove(struct spi_device *spi) +{ + struct xra1403 *xra = spi_get_drvdata(spi); + + gpiochip_remove(&xra->chip); + + return 0; +} + +static const struct spi_device_id xra1403_ids[] = { + { "xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(spi, xra1403_ids); + +static const struct of_device_id xra1403_spi_of_match[] = { + { .compatible = "exar,xra1403" }, + {}, +}; +MODULE_DEVICE_TABLE(of, xra1403_spi_of_match); + +static struct spi_driver xra1403_driver = { + .probe = xra1403_probe, + .remove = xra1403_remove, + .id_table = xra1403_ids, + .driver = { + .name = "xra1403", + .of_match_table = of_match_ptr(xra1403_spi_of_match), + }, +}; + +static int __init xra1403_init(void) +{ + return spi_register_driver(&xra1403_driver); +} + +/* + * register after spi postcore initcall and before + * subsys initcalls that may rely on these GPIOs + */ +subsys_initcall(xra1403_init); + +static void __exit xra1403_exit(void) +{ + spi_unregister_driver(&xra1403_driver); +} +module_exit(xra1403_exit); + +MODULE_AUTHOR("Nandor Han "); +MODULE_AUTHOR("Semi Malinen "); +MODULE_DESCRIPTION("GPIO expander driver for EXAR XRA1403"); +MODULE_LICENSE("GPL v2");