All of lore.kernel.org
 help / color / mirror / Atom feed
From: Peter Hung <hpeter@gmail.com>
To: linus.walleij@linaro.org, gnurou@gmail.com,
	gregkh@linuxfoundation.org, andriy.shevchenko@linux.intel.com,
	paul.gortmaker@windriver.com, lee.jones@linaro.org,
	jslaby@suse.com, peter_hong@fintek.com.tw
Cc: heikki.krogerus@linux.intel.com, peter@hurleysoftware.com,
	soeren.grunewald@desy.de, udknight@gmail.com,
	adam.lee@canonical.com, arnd@arndb.de, manabian@gmail.com,
	scottwood@freescale.com, yamada.masahiro@socionext.com,
	paul.burton@imgtec.com, mans@mansr.com, matthias.bgg@gmail.com,
	ralf@linux-mips.org, linux-kernel@vger.kernel.org,
	linux-gpio@vger.kernel.org, linux-serial@vger.kernel.org,
	tom_tsai@fintek.com.tw,
	Peter Hung <hpeter+linux_kernel@gmail.com>
Subject: [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support
Date: Thu, 28 Jan 2016 17:20:36 +0800	[thread overview]
Message-ID: <1453972838-30268-3-git-send-email-hpeter+linux_kernel@gmail.com> (raw)
In-Reply-To: <1453972838-30268-1-git-send-email-hpeter+linux_kernel@gmail.com>

This driver is GPIOLIB driver for F81504/508/512, it'll handle the
GPIOLIB operation of this device. This module will depend on
MFD_FINTEK_F81504_CORE.

IC function list:
    F81504: Max 2x8 GPIOs and max 4 serial ports
        port2/3 are multi-function
    F81508: Max 6x8 GPIOs and max 8 serial ports
        port2/3 are multi-function, port8/9/10/11 are gpio only
    F81512: Max 6x8 GPIOs and max 12 serial ports
        port2/3/8/9/10/11 are multi-function

GPIO register:
PCI Configuration space:
    F0h: bit0~5: Enable GPIO0~5
         bit6~7: Reserve
    F3h: bit0~5: Multi-Functional Flag (0:GPIO/1:UART)
         bit0: UART2 pin out for UART2 / GPIO0
         bit1: UART3 pin out for UART3 / GPIO1
         bit2: UART8 pin out for UART8 / GPIO2
         bit3: UART9 pin out for UART9 / GPIO3
         bit4: UART10 pin out for UART10 / GPIO4
         bit5: UART11 pin out for UART11 / GPIO5
         bit6~7: Reserve
    F1h: IO address (LSB)
    F2h: IO address (MSB)
    F8h + 8 * set: Direction control (bitwise)
         bitx: 0 - Input mode
         bitx: 1 - Output mode
    F9h + 8 * set: Drive ability control (bitwise)
         bitx: 0 - Open drain (default)
         bitx: 1 - Push Pull
         In this driver, we only implements open drain mode.

IO space:
    (IO base + 0~5): GPIO-0x~5x in/out value (bitwise)

Suggested-by: One Thousand Gnomes <gnomes@lxorguk.ukuu.org.uk>
Suggested-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Peter Hung <hpeter+linux_kernel@gmail.com>
---
 drivers/gpio/Kconfig       |  10 ++
 drivers/gpio/Makefile      |   1 +
 drivers/gpio/gpio-f81504.c | 257 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 268 insertions(+)
 create mode 100644 drivers/gpio/gpio-f81504.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index b18bea0..633a65f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -900,6 +900,16 @@ config GPIO_WM8994
 	  Say yes here to access the GPIO signals of WM8994 audio hub
 	  CODECs from Wolfson Microelectronics.
 
+config GPIO_F81504
+        tristate "Fintek F81504/508/512 PCIE-to-UART/GPIO support"
+        depends on MFD_FINTEK_F81504_CORE
+        select MFD_CORE
+        help
+          Say yes here to support the GPIO functionality of Fintek
+          F81504/508/512 PCIE-to-UART/GPIO.
+
+          If unsure, say N.
+
 endmenu
 
 menu "PCI GPIO expanders"
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 986dbd8..06fb240 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -111,6 +111,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_F81504)       += gpio-f81504.o
 obj-$(CONFIG_GPIO_XGENE)	+= gpio-xgene.o
 obj-$(CONFIG_GPIO_XGENE_SB)	+= gpio-xgene-sb.o
 obj-$(CONFIG_GPIO_XILINX)	+= gpio-xilinx.o
diff --git a/drivers/gpio/gpio-f81504.c b/drivers/gpio/gpio-f81504.c
new file mode 100644
index 0000000..817b926
--- /dev/null
+++ b/drivers/gpio/gpio-f81504.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2016 Fintek Corporation
+ * Based on gpio-mpc8xxx.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/pci.h>
+#include <linux/mfd/f81504.h>
+
+struct f81504_gpio_chip {
+	struct gpio_chip chip;
+	struct mutex locker;
+	u8 idx;
+	u8 save_out_en;
+	u8 save_drive_en;
+	u8 save_value;
+};
+
+static struct f81504_gpio_chip *gpio_to_f81504_chip(struct gpio_chip *chip)
+{
+	return container_of(chip, struct f81504_gpio_chip, chip);
+}
+
+static int f81504_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	u8 tmp;
+	struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip);
+	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+
+	mutex_lock(&gc->locker);
+
+	/* set input mode */
+	pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			&tmp);
+	pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			tmp & ~BIT(offset));
+
+	mutex_unlock(&gc->locker);
+	return 0;
+}
+
+static int f81504_gpio_direction_out(struct gpio_chip *chip, unsigned offset,
+		int value)
+{
+	u8 tmp;
+	struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip);
+	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+	struct f81504_pci_private *priv = pci_get_drvdata(pci_dev);
+
+	mutex_lock(&gc->locker);
+
+	/* set output mode */
+	pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			&tmp);
+	pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			tmp | BIT(offset));
+
+	/*
+	 * The GPIO default driven mode for this device is open-drain. The
+	 * GPIOLIB had no change GPIO mode API currently. So we leave the
+	 * Push-Pull code below.
+	 *
+	 * pci_read_config_byte(dev, GPIO_START_ADDR + idx * GPIO_SET_OFFSET +
+	 *			GPIO_DRIVE_EN_OFFSET, &tmp);
+	 * pci_write_config_byte(dev, GPIO_START_ADDR + idx * GPIO_SET_OFFSET +
+	 *			GPIO_DRIVE_EN_OFFSET, tmp | BIT(gpio_num));
+	 */
+
+	/* set output data */
+	tmp = inb(priv->gpio_ioaddr + gc->idx);
+
+	if (value)
+		outb(tmp | BIT(offset), priv->gpio_ioaddr + gc->idx);
+	else
+		outb(tmp & ~BIT(offset), priv->gpio_ioaddr + gc->idx);
+
+	mutex_unlock(&gc->locker);
+	return 0;
+}
+
+static int f81504_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	u8 tmp;
+	struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip);
+	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+
+	mutex_lock(&gc->locker);
+	pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET, &tmp);
+	mutex_unlock(&gc->locker);
+
+	if (tmp & BIT(offset))
+		return GPIOF_DIR_OUT;
+
+	return GPIOF_DIR_IN;
+}
+
+static int f81504_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	int tmp;
+	struct f81504_gpio_chip *gc = gpio_to_f81504_chip(chip);
+	struct platform_device *pdev = to_platform_device(chip->dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+	struct f81504_pci_private *priv = pci_get_drvdata(pci_dev);
+
+	mutex_lock(&gc->locker);
+	tmp = inb(priv->gpio_ioaddr + gc->idx);
+	mutex_unlock(&gc->locker);
+
+	return !!(tmp & BIT(offset));
+}
+
+static void f81504_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	f81504_gpio_direction_out(chip, offset, value);
+}
+
+static int f81504_gpio_suspend(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+	struct f81504_pci_private *priv = pci_get_drvdata(pci_dev);
+	struct f81504_gpio_chip *gc = platform_get_drvdata(pdev);
+
+	mutex_lock(&gc->locker);
+	pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			&gc->save_out_en);
+
+	pci_read_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_DRIVE_EN_OFFSET,
+			&gc->save_drive_en);
+
+	gc->save_value = inb(priv->gpio_ioaddr + gc->idx);
+	mutex_unlock(&gc->locker);
+	return 0;
+}
+
+static int f81504_gpio_resume(struct device *dev)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct pci_dev *pci_dev = to_pci_dev(pdev->dev.parent);
+	struct f81504_pci_private *priv = pci_get_drvdata(pci_dev);
+	struct f81504_gpio_chip *gc = platform_get_drvdata(pdev);
+
+	mutex_lock(&gc->locker);
+	pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_OUT_EN_OFFSET,
+			gc->save_out_en);
+
+	pci_write_config_byte(pci_dev, F81504_GPIO_START_ADDR + gc->idx *
+			F81504_GPIO_SET_OFFSET + F81504_GPIO_DRIVE_EN_OFFSET,
+			gc->save_drive_en);
+
+	outb(gc->save_value, priv->gpio_ioaddr + gc->idx);
+	mutex_unlock(&gc->locker);
+	return 0;
+}
+
+static int f81504_gpio_probe(struct platform_device *pdev)
+{
+	int status;
+	struct f81504_gpio_chip *gc;
+	void *data = dev_get_platdata(&pdev->dev);
+	u8 gpio_idx = *(u8 *)data;
+	char *name;
+
+	if (gpio_idx >= ARRAY_SIZE(fintek_gpio_mapping)) {
+		dev_err(&pdev->dev, "%s: gpio_idx:%d out of range.\n",
+				__func__, gpio_idx);
+		return -ENODEV;
+	}
+
+	gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL);
+	if (!gc)
+		return -ENOMEM;
+
+	kfree(data);
+	mutex_init(&gc->locker);
+	platform_set_drvdata(pdev, gc);
+
+	name = devm_kzalloc(&pdev->dev, FINTEK_GPIO_NAME_LEN, GFP_KERNEL);
+	if (!name)
+		return -ENOMEM;
+
+	/* This will display like as GPIO-1x */
+	sprintf(name, "%s-%dx", FINTEK_GPIO_DISPLAY, gpio_idx);
+
+	gc->chip.owner = THIS_MODULE;
+	gc->chip.label = name;
+	gc->chip.ngpio = 8;
+	gc->chip.dev = &pdev->dev;
+	gc->chip.get = f81504_gpio_get;
+	gc->chip.set = f81504_gpio_set;
+	gc->chip.direction_input = f81504_gpio_direction_in;
+	gc->chip.direction_output = f81504_gpio_direction_out;
+	gc->chip.get_direction = f81504_gpio_get_direction;
+	gc->chip.can_sleep = 1;
+	gc->chip.base = -1;
+	gc->idx = gpio_idx;
+
+	status = gpiochip_add(&gc->chip);
+	if (status) {
+		dev_err(&pdev->dev, "%s: gpiochip_add failed: %d\n", __func__,
+				status);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static int f81504_gpio_remove(struct platform_device *pdev)
+{
+	struct f81504_gpio_chip *gc = platform_get_drvdata(pdev);
+
+	gpiochip_remove(&gc->chip);
+	return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(f81504_gpio_pm_ops, f81504_gpio_suspend,
+		f81504_gpio_resume);
+
+static struct platform_driver f81504_gpio_driver = {
+	.driver = {
+		.name	= F81504_GPIO_NAME,
+		.owner	= THIS_MODULE,
+		.pm     = &f81504_gpio_pm_ops,
+	},
+	.probe		= f81504_gpio_probe,
+	.remove		= f81504_gpio_remove,
+};
+
+module_platform_driver(f81504_gpio_driver);
+
+MODULE_AUTHOR("Peter Hong <Peter_Hong@fintek.com.tw>");
+MODULE_DESCRIPTION("Fintek F81504/508/512 PCIE GPIOLIB driver");
+MODULE_LICENSE("GPL");
-- 
1.9.1

  parent reply	other threads:[~2016-01-28  9:20 UTC|newest]

Thread overview: 35+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-01-28  9:20 [PATCH V2 0/4] Transform Fintek PCIE driver from 8250 to MFD Peter Hung
2016-01-28  9:20 ` [PATCH V2 1/4] mfd: f81504-core: Add Fintek F81504/508/512 PCIE-to-UART/GPIO core support Peter Hung
2016-01-28 10:04   ` One Thousand Gnomes
2016-01-29  2:22     ` Peter Hung
2016-01-28 11:55   ` Andy Shevchenko
2016-01-29  5:50     ` Peter Hung
2016-01-29  8:21       ` Lee Jones
2016-01-29  8:21         ` Lee Jones
2016-01-29 12:47         ` Andy Shevchenko
2016-02-01  8:29           ` Lee Jones
2016-01-29 13:41       ` Andy Shevchenko
2016-02-01  2:51         ` Peter Hung
2016-02-01  2:51           ` Peter Hung
2016-01-28  9:20 ` Peter Hung [this message]
2016-01-28  9:54   ` [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support kbuild test robot
2016-01-28  9:54   ` [PATCH] gpio: gpio-f81504: fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-28 12:03   ` [PATCH V2 2/4] gpio: gpio-f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO GPIOLIB support Andy Shevchenko
2016-01-29  8:15     ` Peter Hung
2016-01-29  8:15       ` Peter Hung
2016-02-10  9:08   ` Linus Walleij
2016-02-10  9:08     ` Linus Walleij
2016-02-16  7:03     ` Peter Hung
2016-02-16  7:03       ` Peter Hung
2016-01-28  9:20 ` [PATCH V2 3/4] 8250: 8250_f81504: Add Fintek F81504/508/512 PCIE-to-UART/GPIO UART support Peter Hung
2016-01-28 10:17   ` One Thousand Gnomes
2016-01-28 11:06   ` kbuild test robot
2016-01-28 11:06   ` [PATCH] 8250: 8250_f81504: fix platform_no_drv_owner.cocci warnings kbuild test robot
2016-01-28  9:20 ` [PATCH V2 4/4] serial: 8250_pci: Remove Fintek F81504/508/512 UART driver Peter Hung
2016-01-28 12:04   ` Andy Shevchenko
2016-01-29  8:20     ` Peter Hung
2016-01-29  8:20       ` Peter Hung
2016-01-29 12:40       ` Andy Shevchenko
2016-01-29 12:40         ` Andy Shevchenko
2016-02-01  3:33         ` Peter Hung
2016-02-01  3:33           ` Peter Hung

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1453972838-30268-3-git-send-email-hpeter+linux_kernel@gmail.com \
    --to=hpeter@gmail.com \
    --cc=adam.lee@canonical.com \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=arnd@arndb.de \
    --cc=gnurou@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=heikki.krogerus@linux.intel.com \
    --cc=hpeter+linux_kernel@gmail.com \
    --cc=jslaby@suse.com \
    --cc=lee.jones@linaro.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-gpio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=manabian@gmail.com \
    --cc=mans@mansr.com \
    --cc=matthias.bgg@gmail.com \
    --cc=paul.burton@imgtec.com \
    --cc=paul.gortmaker@windriver.com \
    --cc=peter@hurleysoftware.com \
    --cc=peter_hong@fintek.com.tw \
    --cc=ralf@linux-mips.org \
    --cc=scottwood@freescale.com \
    --cc=soeren.grunewald@desy.de \
    --cc=tom_tsai@fintek.com.tw \
    --cc=udknight@gmail.com \
    --cc=yamada.masahiro@socionext.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.