All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kevin Strasser <kevin.strasser@linux.intel.com>
To: linux-kernel@vger.kernel.org
Cc: Michael Brunner <michael.brunner@kontron.com>,
	Samuel Ortiz <sameo@linux.intel.com>,
	Wolfram Sang <wsa@the-dreams.de>, Ben Dooks <ben-linux@fluff.org>,
	linux-i2c@vger.kernel.org,
	Grant Likely <grant.likely@secretlab.ca>,
	Linus Walleij <linus.walleij@linaro.org>,
	Wim Van Sebroeck <wim@iguana.be>,
	linux-watchdog@vger.kernel.org,
	Darren Hart <dvhart@linux.intel.com>,
	Michael Brunner <mibru@gmx.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	Kevin Strasser <kevin.strasser@linux.intel.com>
Subject: [PATCH 3/4] gpio: Kontron PLD gpio driver
Date: Mon,  8 Apr 2013 10:15:20 -0700	[thread overview]
Message-ID: <1365441321-21952-3-git-send-email-kevin.strasser@linux.intel.com> (raw)
In-Reply-To: <1365441321-21952-1-git-send-email-kevin.strasser@linux.intel.com>

From: Michael Brunner <michael.brunner@kontron.com>

Add gpio support for the on-board PLD found on some Kontron embedded
modules.

Signed-off-by: Michael Brunner <michael.brunner@kontron.com>
Signed-off-by: Kevin Strasser <kevin.strasser@linux.intel.com>
---
 drivers/gpio/Kconfig            |   22 ++
 drivers/gpio/Makefile           |    2 +
 drivers/gpio/gpio-kempld.c      |  476 +++++++++++++++++++++++++++++++++++++++
 drivers/gpio/gpio-kempld.h      |   50 ++++
 drivers/gpio/gpio-kempld_now1.c |  280 +++++++++++++++++++++++
 5 files changed, 830 insertions(+)
 create mode 100644 drivers/gpio/gpio-kempld.c
 create mode 100644 drivers/gpio/gpio-kempld.h
 create mode 100644 drivers/gpio/gpio-kempld_now1.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 93aaadf..88e1bc9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -658,6 +658,28 @@ config GPIO_UCB1400
 	  This enables support for the Philips UCB1400 GPIO pins.
 	  The UCB1400 is an AC97 audio codec.
 
+comment "LPC GPIO expanders:"
+
+config GPIO_KEMPLD
+	tristate "Kontron COM GPIO"
+	depends on MFD_KEMPLD
+	help
+	  This enables support for the PLD GPIO interface on some Kontron ETX
+	  and COMexpress (ETXexpress) modules.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called gpio-kempld.
+
+config GPIO_NOW1_KEMPLD
+	tristate "Kontron COMe-mSP1 (nanoETXexpress-SP) GPIO"
+	depends on MFD_KEMPLD
+	help
+	  This enables support for the PLD GPIO interface on the Kontron
+	  COMe-mSP1 (nanoETXexpress-SP) module.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called gpio-kempld_now1.
+
 comment "MODULbus GPIO expanders:"
 
 config GPIO_JANZ_TTL
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 22e07bc..59919db 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_GPIO_GE_FPGA)	+= gpio-ge.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
 obj-$(CONFIG_GPIO_IT8761E)	+= gpio-it8761e.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
+obj-$(CONFIG_GPIO_KEMPLD)   += gpio-kempld.o
+obj-$(CONFIG_GPIO_NOW1_KEMPLD) += gpio-kempld_now1.o
 obj-$(CONFIG_ARCH_KS8695)	+= gpio-ks8695.o
 obj-$(CONFIG_GPIO_LANGWELL)	+= gpio-langwell.o
 obj-$(CONFIG_ARCH_LPC32XX)	+= gpio-lpc32xx.o
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
new file mode 100644
index 0000000..e18967d
--- /dev/null
+++ b/drivers/gpio/gpio-kempld.c
@@ -0,0 +1,476 @@
+/*
+ *  kempld_gpio.c - Kontron PLD GPIO driver
+ *
+ *  Copyright (c) 2010-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+#include <linux/seq_file.h>
+
+#include "gpio-kempld.h"
+
+static int gpiobase = -1;
+static int gpioien = 0x00;
+static int gpioevt_lvl_edge = -1;
+static int gpioevt_low_high = -1;
+static int gpionmien = 0x00;
+
+static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+	return status;
+}
+
+static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset,
+				int value)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_LVL_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+}
+
+static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_DIR_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_DIR_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+
+
+	return 0;
+}
+
+static int kempld_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_LVL_NUM(offset), status);
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status |= KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_DIR_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+static int kempld_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	return gpio->irq;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_DIR_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_ien(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_IEN_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_IEN_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_evt_lvl_edge(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_EVT_LVL_EDGE_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_EVT_LVL_EDGE_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_evt_high_low(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	gpio = dev_get_drvdata(chip->dev);
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_EVT_LOW_HIGH_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_EVT_LOW_HIGH_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_nmien(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	gpio = dev_get_drvdata(chip->dev);
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_NMIEN_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_NMIEN_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static void kempld_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < chip->ngpio; i++) {
+		int gpio = i + chip->base;
+
+		seq_printf(s, " gpio-%-3d %s %s", gpio,
+				kempld_gpio_get_direction(chip, i)
+				? "out" : "in",
+				kempld_gpio_get(chip, i)
+				? "hi" : "lo");
+		seq_printf(s, ", event on %s (irq %s, nmi %s)\n",
+				(kempld_gpio_get_evt_lvl_edge(chip, i)
+				? (kempld_gpio_get_evt_high_low(chip, i)
+				? "rising edge" : "falling edge") :
+				(kempld_gpio_get_evt_high_low(chip, i)
+				? "high level" : "low level")),
+				kempld_gpio_get_ien(chip, i)
+				? "enabled" : "disabled",
+				kempld_gpio_get_nmien(chip, i)
+				? "enabled" : "disabled");
+	}
+}
+#else
+#define kempld_gpio_dbg_show NULL
+#endif
+
+static int kempld_gpio_setup_event(struct kempld_gpio_data *gpio)
+{
+	struct kempld_device_data *pld = gpio->pld;
+	struct gpio_chip *chip = &gpio->chip;
+	int irq;
+
+	irq = gpio->irq;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_IRQ_GPIO);
+	irq = kempld_read8(pld, KEMPLD_IRQ_GPIO);
+
+	/* Leave if interrupts are not supported by the GPIO core */
+	if ((irq & 0xf0) == 0xf0)
+		return 0;
+
+	gpio->irq = irq & 0x0f;
+
+	if (gpioien & !gpio->mask) {
+		dev_err(chip->dev, "gpioien parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if (gpionmien & !gpio->mask) {
+		dev_err(chip->dev, "gpionmien parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if ((gpioevt_lvl_edge & !gpio->mask) && (gpioevt_lvl_edge != -1)) {
+		dev_err(chip->dev, "gpioevt_lvl_edge parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if ((gpioevt_low_high & !gpio->mask) && (gpioevt_low_high != -1)) {
+		dev_err(chip->dev, "gpioevt_low_high parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if (!gpio->irq)
+		return -EIO;
+
+	if (gpioevt_lvl_edge != -1)
+		kempld_write8(pld, KEMPLD_GPIO_EVT_LVL_EDGE, gpioevt_lvl_edge);
+
+	if (gpioevt_low_high != -1)
+		kempld_write8(pld, KEMPLD_GPIO_EVT_LOW_HIGH, gpioevt_low_high);
+
+	kempld_write8(pld, KEMPLD_GPIO_NMIEN, gpionmien);
+	kempld_write8(pld, KEMPLD_GPIO_IEN, gpioien);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+
+static int kempld_gpio_detect(struct kempld_gpio_data *gpio)
+{
+	struct kempld_device_data *pld = gpio->pld;
+	struct gpio_chip *chip = &gpio->chip;
+	u16 evt, evt_back;
+	int i;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_IEN);
+
+	/* Backup event register as it might be already initialized */
+	evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+
+	/* Disable interrupt enables and set event register to zero */
+	kempld_write16(pld, KEMPLD_GPIO_IEN, 0x0000);
+	kempld_write16(pld, KEMPLD_GPIO_NMIEN, 0x0000);
+	kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000);
+
+	/* Read back event register */
+	evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+
+	/* Restore event register */
+	kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back);
+
+	kempld_release_mutex(pld);
+
+	gpio->mask = ~evt;
+
+	/* Now check how many GPIO pins we have */
+	for (i = 0; i < KEMPLD_GPIO_MAX_NUM; i++) {
+		if (evt & 0x1)
+			break;
+		evt >>= 1;
+	}
+
+	chip->ngpio = i;
+
+	return 0;
+}
+
+static int kempld_gpio_probe(struct platform_device *pdev)
+{
+	struct kempld_device_data *pld;
+	struct kempld_gpio_data *gpio;
+	struct gpio_chip *chip;
+	int ret;
+
+	pld = dev_get_drvdata(pdev->dev.parent);
+
+	if (pld->info.spec_major < 2) {
+		dev_err(&pdev->dev,
+			"driver only supports GPIO devices "
+			"compatible to PLD spec. rev. 2.0 or higher\n");
+		ret = -ENXIO;
+		goto err_check_rev;
+	}
+
+	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+	if (gpio == NULL) {
+		dev_err(&pdev->dev, "unable to get memory for device data\n");
+		ret = -ENOMEM;
+		goto err_alloc_dev_data;
+	}
+
+	gpio->pld = pld;
+
+	platform_set_drvdata(pdev, gpio);
+
+	chip = &gpio->chip;
+	chip->label =		"kempld-gpio";
+	chip->owner =		THIS_MODULE;
+	chip->dev =		&pdev->dev;
+	chip->can_sleep =	1;
+	chip->base =		gpiobase;
+	chip->ngpio =		KEMPLD_GPIO_MAX_NUM;
+
+	if (kempld_gpio_detect(gpio))
+		dev_err(&pdev->dev, "GPIO detection failed\n");
+	if (kempld_gpio_setup_event(gpio))
+		dev_err(&pdev->dev, "Initializing events failed\n");
+
+	chip->direction_input =		kempld_gpio_direction_input;
+	chip->direction_output =	kempld_gpio_direction_output;
+	chip->get =			kempld_gpio_get;
+	chip->set =			kempld_gpio_set;
+	chip->dbg_show =		kempld_gpio_dbg_show;
+	if (gpio->irq)
+		chip->to_irq =		kempld_gpio_to_irq;
+
+	ret = gpiochip_add(chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register GPIO chip\n");
+		goto err_gpiochip_add;
+	}
+
+	dev_info(&pdev->dev,
+		 "GPIO functionality initialized with %d IOs mask (0x%04x)\n",
+		 chip->ngpio, gpio->mask);
+
+	return 0;
+
+err_gpiochip_add:
+	kfree(gpio);
+err_alloc_dev_data:
+err_check_rev:
+
+	return ret;
+}
+
+static int kempld_gpio_remove(struct platform_device *pdev)
+{
+	struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&gpio->chip);
+	if (ret == 0) {
+		kfree(gpio);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return ret;
+}
+
+static struct platform_driver kempld_gpio_driver = {
+	.driver = {
+		.name = "kempld-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe		= kempld_gpio_probe,
+	.remove		= kempld_gpio_remove,
+};
+
+static int __init kempld_gpio_init(void)
+{
+	return platform_driver_register(&kempld_gpio_driver);
+}
+
+static void __exit kempld_gpio_exit(void)
+{
+	platform_driver_unregister(&kempld_gpio_driver);
+}
+
+module_init(kempld_gpio_init);
+module_exit(kempld_gpio_exit);
+
+module_param(gpiobase, int, 0444);
+module_param(gpioien, int, 0444);
+module_param(gpioevt_lvl_edge, int, 0444);
+module_param(gpioevt_low_high, int, 0444);
+module_param(gpionmien, int, 0444);
+
+MODULE_DESCRIPTION("KEM PLD GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_gpio");
+MODULE_PARM_DESC(gpiobase, "Set GPIO base (default -1=dynamic)");
+MODULE_PARM_DESC(gpioien, "Set GPIO IEN register (default 0x00)");
+MODULE_PARM_DESC(gpioevt_lvl_edge,
+			"Set GPIO EVT_LVL_EDGE register (default -1=no change)");
+MODULE_PARM_DESC(gpioevt_low_high,
+			"Set GPIO EVT_LOW_HIGH register (default -1=no change)");
+MODULE_PARM_DESC(gpionmien, "Set GPIO NMIEN register (default 0x00)");
+
diff --git a/drivers/gpio/gpio-kempld.h b/drivers/gpio/gpio-kempld.h
new file mode 100644
index 0000000..173932c
--- /dev/null
+++ b/drivers/gpio/gpio-kempld.h
@@ -0,0 +1,50 @@
+/*
+ *  kempld_gpio.h - Kontron PLD GPIO driver definitions
+ *
+ *  Copyright (c) 2010-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _KEMPLD_GPIO_H_
+#define _KEMPLD_GPIO_H_
+
+#define KEMPLD_GPIO_MAX_NUM		16
+
+#define KEMPLD_GPIO_MASK(x)		(1<<(x%8))
+
+#define KEMPLD_GPIO_DIR			0x40
+#define KEMPLD_GPIO_DIR_NUM(x)		(0x40+x/8)
+#define KEMPLD_GPIO_LVL			0x42
+#define KEMPLD_GPIO_LVL_NUM(x)		(0x42+x/8)
+#define KEMPLD_GPIO_STS			0x44
+#define KEMPLD_GPIO_STS_NUM(x)		(0x44+x/8)
+#define KEMPLD_GPIO_EVT_LVL_EDGE	0x46
+#define KEMPLD_GPIO_EVT_LVL_EDGE_NUM(x)	(0x46+x/8)
+#define KEMPLD_GPIO_EVT_LOW_HIGH	0x48
+#define KEMPLD_GPIO_EVT_LOW_HIGH_NUM(x)	(0x48+x/8)
+#define KEMPLD_GPIO_IEN			0x4A
+#define KEMPLD_GPIO_IEN_NUM(x)		(0x4A+x/8)
+#define KEMPLD_GPIO_NMIEN		0x4C
+#define KEMPLD_GPIO_NMIEN_NUM(x)	(0x4C+x/8)
+
+struct kempld_gpio_data {
+	struct gpio_chip		chip;
+	int				irq;
+	struct kempld_device_data	*pld;
+	uint16_t			mask;
+};
+
+#endif /* _KEMPLD_GPIO_H_ */
diff --git a/drivers/gpio/gpio-kempld_now1.c b/drivers/gpio/gpio-kempld_now1.c
new file mode 100644
index 0000000..50ebd67
--- /dev/null
+++ b/drivers/gpio/gpio-kempld_now1.c
@@ -0,0 +1,280 @@
+/*
+ *  kempld_now1_gpio.c - Kontron PLD GPIO driver for COMe-mSP1
+ *
+ *  Copyright (c) 2011-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+#include <linux/seq_file.h>
+
+#include "gpio-kempld.h"
+
+#define KEMPLD_NOW1_GPIO_MAX_NUM	8
+
+#define KEMPLD_NOW1_FUNCTION		0x70
+#define		KEMPLD_NOW1_FUNCTION_ALF_SDIO	0x01
+#define		KEMPLD_NOW1_FUNCTION_USBCC	0x02
+#define KEMPLD_NOW1_GPIO_DIR		0xA0
+#define KEMPLD_NOW1_GPIO_LVL		0xA1
+
+static int kempld_now1_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	kempld_release_mutex(pld);
+
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	return status ? 1 : 0;
+}
+
+static void kempld_now1_gpio_set(struct gpio_chip *chip, unsigned offset,
+				int value)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_LVL, status);
+
+	kempld_release_mutex(pld);
+}
+
+static int kempld_now1_gpio_direction_input(struct gpio_chip *chip,
+						unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+	status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_DIR, status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+static int kempld_now1_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_LVL, status);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+	status |= KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_DIR, status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int kempld_now1_gpio_get_direction(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	kempld_release_mutex(pld);
+
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	return status ? 1 : 0;
+}
+
+static void kempld_now1_gpio_dbg_show(struct seq_file *s,
+				struct gpio_chip *chip)
+{
+	struct kempld_device_data *pld;
+	int function;
+	int i;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_FUNCTION);
+
+	function = kempld_read8(pld, KEMPLD_NOW1_FUNCTION);
+
+	kempld_release_mutex(pld);
+
+	for (i = 0; i < chip->ngpio; i++) {
+		int gpio = i + chip->base;
+
+		seq_printf(s, " gpio-%-3d %s %s %s\n", gpio,
+				kempld_now1_gpio_get_direction(chip, i)
+				? "out" : "in",
+				kempld_now1_gpio_get(chip, i)
+				? "hi" : "lo",
+				function & KEMPLD_NOW1_FUNCTION_ALF_SDIO
+				? "sdio" :
+				((function & KEMPLD_NOW1_FUNCTION_USBCC)
+					&& (i == 0))
+				? "usbcc" : "gpio");
+	}
+}
+#else
+#define kempld_now1_gpio_dbg_show NULL
+#endif
+
+static int kempld_now1_gpio_probe(struct platform_device *pdev)
+{
+	struct kempld_device_data *pld;
+	struct gpio_chip *chip;
+	int function;
+	int ret;
+
+	pld = dev_get_drvdata(pdev->dev.parent);
+
+	chip = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL);
+	if (chip == NULL) {
+		dev_err(&pdev->dev, "unable to get memory for device data\n");
+		ret = -ENOMEM;
+		goto err_alloc_dev_data;
+	}
+
+	chip->label =		"kempld_now1-gpio";
+	chip->owner =		THIS_MODULE;
+	chip->can_sleep =	1;
+	chip->dev =		&pdev->dev;
+	chip->base =		-1;
+	chip->ngpio =		KEMPLD_NOW1_GPIO_MAX_NUM;
+
+	chip->direction_input =		kempld_now1_gpio_direction_input;
+	chip->direction_output =	kempld_now1_gpio_direction_output;
+	chip->get =			kempld_now1_gpio_get;
+	chip->set =			kempld_now1_gpio_set;
+	chip->dbg_show =		kempld_now1_gpio_dbg_show;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_FUNCTION);
+
+	function = kempld_read8(pld, KEMPLD_NOW1_FUNCTION);
+
+	kempld_release_mutex(pld);
+
+	if (function & KEMPLD_NOW1_FUNCTION_ALF_SDIO)
+		dev_warn(&pdev->dev, "GPIO pins are used for SDIO\n");
+	if (function & KEMPLD_NOW1_FUNCTION_USBCC) {
+		dev_info(&pdev->dev,
+			 "GPI[0] is forwarded to USB cable connect\n");
+	}
+
+	platform_set_drvdata(pdev, chip);
+
+	ret = gpiochip_add(chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register GPIO chip\n");
+		goto err_gpiochip_add;
+	}
+
+	dev_info(&pdev->dev, "GPIO functionality initialized\n");
+
+	return 0;
+
+err_gpiochip_add:
+	kfree(chip);
+err_alloc_dev_data:
+
+	return ret;
+}
+
+static int kempld_now1_gpio_remove(struct platform_device *pdev)
+{
+	struct gpio_chip *chip = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(chip);
+	if (ret == 0) {
+		kfree(chip);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return ret;
+}
+
+static struct platform_driver kempld_now1_gpio_driver = {
+	.driver = {
+		.name = "kempld_now1-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe		= kempld_now1_gpio_probe,
+	.remove		= kempld_now1_gpio_remove,
+};
+
+static int __init kempld_now1_gpio_init(void)
+{
+	return platform_driver_register(&kempld_now1_gpio_driver);
+}
+
+static void __exit kempld_now1_gpio_exit(void)
+{
+	platform_driver_unregister(&kempld_now1_gpio_driver);
+}
+
+module_init(kempld_now1_gpio_init);
+module_exit(kempld_now1_gpio_exit);
+
+MODULE_DESCRIPTION("KEM PLD nanoETXexpress-SP GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_now1-gpio");
-- 
1.7.9.5


WARNING: multiple messages have this Message-ID (diff)
From: Kevin Strasser <kevin.strasser-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Michael Brunner
	<michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>,
	Samuel Ortiz <sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	Wolfram Sang <wsa-z923LK4zBo2bacvFa/9K2g@public.gmane.org>,
	Ben Dooks <ben-linux-elnMNo+KYs3YtjvyW6yDsg@public.gmane.org>,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Grant Likely
	<grant.likely-s3s/WqlpOiPyB63q8FvJNQ@public.gmane.org>,
	Linus Walleij
	<linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
	Wim Van Sebroeck <wim-IQzOog9fTRqzQB+pC5nmwQ@public.gmane.org>,
	linux-watchdog-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Darren Hart <dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>,
	Michael Brunner <mibru-Mmb7MZpHnFY@public.gmane.org>,
	Greg Kroah-Hartman
	<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>,
	Kevin Strasser
	<kevin.strasser-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Subject: [PATCH 3/4] gpio: Kontron PLD gpio driver
Date: Mon,  8 Apr 2013 10:15:20 -0700	[thread overview]
Message-ID: <1365441321-21952-3-git-send-email-kevin.strasser@linux.intel.com> (raw)
In-Reply-To: <1365441321-21952-1-git-send-email-kevin.strasser-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

From: Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>

Add gpio support for the on-board PLD found on some Kontron embedded
modules.

Signed-off-by: Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>
Signed-off-by: Kevin Strasser <kevin.strasser-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/gpio/Kconfig            |   22 ++
 drivers/gpio/Makefile           |    2 +
 drivers/gpio/gpio-kempld.c      |  476 +++++++++++++++++++++++++++++++++++++++
 drivers/gpio/gpio-kempld.h      |   50 ++++
 drivers/gpio/gpio-kempld_now1.c |  280 +++++++++++++++++++++++
 5 files changed, 830 insertions(+)
 create mode 100644 drivers/gpio/gpio-kempld.c
 create mode 100644 drivers/gpio/gpio-kempld.h
 create mode 100644 drivers/gpio/gpio-kempld_now1.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 93aaadf..88e1bc9 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -658,6 +658,28 @@ config GPIO_UCB1400
 	  This enables support for the Philips UCB1400 GPIO pins.
 	  The UCB1400 is an AC97 audio codec.
 
+comment "LPC GPIO expanders:"
+
+config GPIO_KEMPLD
+	tristate "Kontron COM GPIO"
+	depends on MFD_KEMPLD
+	help
+	  This enables support for the PLD GPIO interface on some Kontron ETX
+	  and COMexpress (ETXexpress) modules.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called gpio-kempld.
+
+config GPIO_NOW1_KEMPLD
+	tristate "Kontron COMe-mSP1 (nanoETXexpress-SP) GPIO"
+	depends on MFD_KEMPLD
+	help
+	  This enables support for the PLD GPIO interface on the Kontron
+	  COMe-mSP1 (nanoETXexpress-SP) module.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called gpio-kempld_now1.
+
 comment "MODULbus GPIO expanders:"
 
 config GPIO_JANZ_TTL
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 22e07bc..59919db 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -28,6 +28,8 @@ obj-$(CONFIG_GPIO_GE_FPGA)	+= gpio-ge.o
 obj-$(CONFIG_GPIO_ICH)		+= gpio-ich.o
 obj-$(CONFIG_GPIO_IT8761E)	+= gpio-it8761e.o
 obj-$(CONFIG_GPIO_JANZ_TTL)	+= gpio-janz-ttl.o
+obj-$(CONFIG_GPIO_KEMPLD)   += gpio-kempld.o
+obj-$(CONFIG_GPIO_NOW1_KEMPLD) += gpio-kempld_now1.o
 obj-$(CONFIG_ARCH_KS8695)	+= gpio-ks8695.o
 obj-$(CONFIG_GPIO_LANGWELL)	+= gpio-langwell.o
 obj-$(CONFIG_ARCH_LPC32XX)	+= gpio-lpc32xx.o
diff --git a/drivers/gpio/gpio-kempld.c b/drivers/gpio/gpio-kempld.c
new file mode 100644
index 0000000..e18967d
--- /dev/null
+++ b/drivers/gpio/gpio-kempld.c
@@ -0,0 +1,476 @@
+/*
+ *  kempld_gpio.c - Kontron PLD GPIO driver
+ *
+ *  Copyright (c) 2010-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+#include <linux/seq_file.h>
+
+#include "gpio-kempld.h"
+
+static int gpiobase = -1;
+static int gpioien = 0x00;
+static int gpioevt_lvl_edge = -1;
+static int gpioevt_low_high = -1;
+static int gpionmien = 0x00;
+
+static int kempld_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+	return status;
+}
+
+static void kempld_gpio_set(struct gpio_chip *chip, unsigned offset,
+				int value)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_LVL_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+}
+
+static int kempld_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_DIR_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_DIR_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+
+
+	return 0;
+}
+
+static int kempld_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_LVL_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_LVL_NUM(offset));
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_LVL_NUM(offset), status);
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status |= KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_GPIO_DIR_NUM(offset), status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+static int kempld_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	return gpio->irq;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int kempld_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_DIR_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_DIR_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_ien(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_IEN_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_IEN_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_evt_lvl_edge(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_EVT_LVL_EDGE_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_EVT_LVL_EDGE_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_evt_high_low(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	gpio = dev_get_drvdata(chip->dev);
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_EVT_LOW_HIGH_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_EVT_LOW_HIGH_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static int kempld_gpio_get_nmien(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_gpio_data *gpio
+		= container_of(chip, struct kempld_gpio_data, chip);
+	struct kempld_device_data *pld = gpio->pld;
+	int status;
+
+	gpio = dev_get_drvdata(chip->dev);
+	pld = gpio->pld;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_NMIEN_NUM(offset));
+
+	status = kempld_read8(pld, KEMPLD_GPIO_NMIEN_NUM(offset));
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	kempld_release_mutex(pld);
+
+
+	return status ? 1 : 0;
+}
+
+static void kempld_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	int i;
+
+	for (i = 0; i < chip->ngpio; i++) {
+		int gpio = i + chip->base;
+
+		seq_printf(s, " gpio-%-3d %s %s", gpio,
+				kempld_gpio_get_direction(chip, i)
+				? "out" : "in",
+				kempld_gpio_get(chip, i)
+				? "hi" : "lo");
+		seq_printf(s, ", event on %s (irq %s, nmi %s)\n",
+				(kempld_gpio_get_evt_lvl_edge(chip, i)
+				? (kempld_gpio_get_evt_high_low(chip, i)
+				? "rising edge" : "falling edge") :
+				(kempld_gpio_get_evt_high_low(chip, i)
+				? "high level" : "low level")),
+				kempld_gpio_get_ien(chip, i)
+				? "enabled" : "disabled",
+				kempld_gpio_get_nmien(chip, i)
+				? "enabled" : "disabled");
+	}
+}
+#else
+#define kempld_gpio_dbg_show NULL
+#endif
+
+static int kempld_gpio_setup_event(struct kempld_gpio_data *gpio)
+{
+	struct kempld_device_data *pld = gpio->pld;
+	struct gpio_chip *chip = &gpio->chip;
+	int irq;
+
+	irq = gpio->irq;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_IRQ_GPIO);
+	irq = kempld_read8(pld, KEMPLD_IRQ_GPIO);
+
+	/* Leave if interrupts are not supported by the GPIO core */
+	if ((irq & 0xf0) == 0xf0)
+		return 0;
+
+	gpio->irq = irq & 0x0f;
+
+	if (gpioien & !gpio->mask) {
+		dev_err(chip->dev, "gpioien parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if (gpionmien & !gpio->mask) {
+		dev_err(chip->dev, "gpionmien parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if ((gpioevt_lvl_edge & !gpio->mask) && (gpioevt_lvl_edge != -1)) {
+		dev_err(chip->dev, "gpioevt_lvl_edge parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if ((gpioevt_low_high & !gpio->mask) && (gpioevt_low_high != -1)) {
+		dev_err(chip->dev, "gpioevt_low_high parameter is invalid");
+		gpio->irq = 0;
+	}
+
+	if (!gpio->irq)
+		return -EIO;
+
+	if (gpioevt_lvl_edge != -1)
+		kempld_write8(pld, KEMPLD_GPIO_EVT_LVL_EDGE, gpioevt_lvl_edge);
+
+	if (gpioevt_low_high != -1)
+		kempld_write8(pld, KEMPLD_GPIO_EVT_LOW_HIGH, gpioevt_low_high);
+
+	kempld_write8(pld, KEMPLD_GPIO_NMIEN, gpionmien);
+	kempld_write8(pld, KEMPLD_GPIO_IEN, gpioien);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+
+static int kempld_gpio_detect(struct kempld_gpio_data *gpio)
+{
+	struct kempld_device_data *pld = gpio->pld;
+	struct gpio_chip *chip = &gpio->chip;
+	u16 evt, evt_back;
+	int i;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_GPIO_IEN);
+
+	/* Backup event register as it might be already initialized */
+	evt_back = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+
+	/* Disable interrupt enables and set event register to zero */
+	kempld_write16(pld, KEMPLD_GPIO_IEN, 0x0000);
+	kempld_write16(pld, KEMPLD_GPIO_NMIEN, 0x0000);
+	kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, 0x0000);
+
+	/* Read back event register */
+	evt = kempld_read16(pld, KEMPLD_GPIO_EVT_LVL_EDGE);
+
+	/* Restore event register */
+	kempld_write16(pld, KEMPLD_GPIO_EVT_LVL_EDGE, evt_back);
+
+	kempld_release_mutex(pld);
+
+	gpio->mask = ~evt;
+
+	/* Now check how many GPIO pins we have */
+	for (i = 0; i < KEMPLD_GPIO_MAX_NUM; i++) {
+		if (evt & 0x1)
+			break;
+		evt >>= 1;
+	}
+
+	chip->ngpio = i;
+
+	return 0;
+}
+
+static int kempld_gpio_probe(struct platform_device *pdev)
+{
+	struct kempld_device_data *pld;
+	struct kempld_gpio_data *gpio;
+	struct gpio_chip *chip;
+	int ret;
+
+	pld = dev_get_drvdata(pdev->dev.parent);
+
+	if (pld->info.spec_major < 2) {
+		dev_err(&pdev->dev,
+			"driver only supports GPIO devices "
+			"compatible to PLD spec. rev. 2.0 or higher\n");
+		ret = -ENXIO;
+		goto err_check_rev;
+	}
+
+	gpio = kzalloc(sizeof(*gpio), GFP_KERNEL);
+	if (gpio == NULL) {
+		dev_err(&pdev->dev, "unable to get memory for device data\n");
+		ret = -ENOMEM;
+		goto err_alloc_dev_data;
+	}
+
+	gpio->pld = pld;
+
+	platform_set_drvdata(pdev, gpio);
+
+	chip = &gpio->chip;
+	chip->label =		"kempld-gpio";
+	chip->owner =		THIS_MODULE;
+	chip->dev =		&pdev->dev;
+	chip->can_sleep =	1;
+	chip->base =		gpiobase;
+	chip->ngpio =		KEMPLD_GPIO_MAX_NUM;
+
+	if (kempld_gpio_detect(gpio))
+		dev_err(&pdev->dev, "GPIO detection failed\n");
+	if (kempld_gpio_setup_event(gpio))
+		dev_err(&pdev->dev, "Initializing events failed\n");
+
+	chip->direction_input =		kempld_gpio_direction_input;
+	chip->direction_output =	kempld_gpio_direction_output;
+	chip->get =			kempld_gpio_get;
+	chip->set =			kempld_gpio_set;
+	chip->dbg_show =		kempld_gpio_dbg_show;
+	if (gpio->irq)
+		chip->to_irq =		kempld_gpio_to_irq;
+
+	ret = gpiochip_add(chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register GPIO chip\n");
+		goto err_gpiochip_add;
+	}
+
+	dev_info(&pdev->dev,
+		 "GPIO functionality initialized with %d IOs mask (0x%04x)\n",
+		 chip->ngpio, gpio->mask);
+
+	return 0;
+
+err_gpiochip_add:
+	kfree(gpio);
+err_alloc_dev_data:
+err_check_rev:
+
+	return ret;
+}
+
+static int kempld_gpio_remove(struct platform_device *pdev)
+{
+	struct kempld_gpio_data *gpio = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&gpio->chip);
+	if (ret == 0) {
+		kfree(gpio);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return ret;
+}
+
+static struct platform_driver kempld_gpio_driver = {
+	.driver = {
+		.name = "kempld-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe		= kempld_gpio_probe,
+	.remove		= kempld_gpio_remove,
+};
+
+static int __init kempld_gpio_init(void)
+{
+	return platform_driver_register(&kempld_gpio_driver);
+}
+
+static void __exit kempld_gpio_exit(void)
+{
+	platform_driver_unregister(&kempld_gpio_driver);
+}
+
+module_init(kempld_gpio_init);
+module_exit(kempld_gpio_exit);
+
+module_param(gpiobase, int, 0444);
+module_param(gpioien, int, 0444);
+module_param(gpioevt_lvl_edge, int, 0444);
+module_param(gpioevt_low_high, int, 0444);
+module_param(gpionmien, int, 0444);
+
+MODULE_DESCRIPTION("KEM PLD GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_gpio");
+MODULE_PARM_DESC(gpiobase, "Set GPIO base (default -1=dynamic)");
+MODULE_PARM_DESC(gpioien, "Set GPIO IEN register (default 0x00)");
+MODULE_PARM_DESC(gpioevt_lvl_edge,
+			"Set GPIO EVT_LVL_EDGE register (default -1=no change)");
+MODULE_PARM_DESC(gpioevt_low_high,
+			"Set GPIO EVT_LOW_HIGH register (default -1=no change)");
+MODULE_PARM_DESC(gpionmien, "Set GPIO NMIEN register (default 0x00)");
+
diff --git a/drivers/gpio/gpio-kempld.h b/drivers/gpio/gpio-kempld.h
new file mode 100644
index 0000000..173932c
--- /dev/null
+++ b/drivers/gpio/gpio-kempld.h
@@ -0,0 +1,50 @@
+/*
+ *  kempld_gpio.h - Kontron PLD GPIO driver definitions
+ *
+ *  Copyright (c) 2010-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _KEMPLD_GPIO_H_
+#define _KEMPLD_GPIO_H_
+
+#define KEMPLD_GPIO_MAX_NUM		16
+
+#define KEMPLD_GPIO_MASK(x)		(1<<(x%8))
+
+#define KEMPLD_GPIO_DIR			0x40
+#define KEMPLD_GPIO_DIR_NUM(x)		(0x40+x/8)
+#define KEMPLD_GPIO_LVL			0x42
+#define KEMPLD_GPIO_LVL_NUM(x)		(0x42+x/8)
+#define KEMPLD_GPIO_STS			0x44
+#define KEMPLD_GPIO_STS_NUM(x)		(0x44+x/8)
+#define KEMPLD_GPIO_EVT_LVL_EDGE	0x46
+#define KEMPLD_GPIO_EVT_LVL_EDGE_NUM(x)	(0x46+x/8)
+#define KEMPLD_GPIO_EVT_LOW_HIGH	0x48
+#define KEMPLD_GPIO_EVT_LOW_HIGH_NUM(x)	(0x48+x/8)
+#define KEMPLD_GPIO_IEN			0x4A
+#define KEMPLD_GPIO_IEN_NUM(x)		(0x4A+x/8)
+#define KEMPLD_GPIO_NMIEN		0x4C
+#define KEMPLD_GPIO_NMIEN_NUM(x)	(0x4C+x/8)
+
+struct kempld_gpio_data {
+	struct gpio_chip		chip;
+	int				irq;
+	struct kempld_device_data	*pld;
+	uint16_t			mask;
+};
+
+#endif /* _KEMPLD_GPIO_H_ */
diff --git a/drivers/gpio/gpio-kempld_now1.c b/drivers/gpio/gpio-kempld_now1.c
new file mode 100644
index 0000000..50ebd67
--- /dev/null
+++ b/drivers/gpio/gpio-kempld_now1.c
@@ -0,0 +1,280 @@
+/*
+ *  kempld_now1_gpio.c - Kontron PLD GPIO driver for COMe-mSP1
+ *
+ *  Copyright (c) 2011-2012 Kontron Europe GmbH
+ *  Author: Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License 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; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <linux/acpi.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/mfd/kempld.h>
+#include <linux/seq_file.h>
+
+#include "gpio-kempld.h"
+
+#define KEMPLD_NOW1_GPIO_MAX_NUM	8
+
+#define KEMPLD_NOW1_FUNCTION		0x70
+#define		KEMPLD_NOW1_FUNCTION_ALF_SDIO	0x01
+#define		KEMPLD_NOW1_FUNCTION_USBCC	0x02
+#define KEMPLD_NOW1_GPIO_DIR		0xA0
+#define KEMPLD_NOW1_GPIO_LVL		0xA1
+
+static int kempld_now1_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	kempld_release_mutex(pld);
+
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	return status ? 1 : 0;
+}
+
+static void kempld_now1_gpio_set(struct gpio_chip *chip, unsigned offset,
+				int value)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_LVL);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_LVL, status);
+
+	kempld_release_mutex(pld);
+}
+
+static int kempld_now1_gpio_direction_input(struct gpio_chip *chip,
+						unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+	status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_DIR, status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+static int kempld_now1_gpio_direction_output(struct gpio_chip *chip,
+					 unsigned offset, int value)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_LVL);
+	if (value)
+		status |= KEMPLD_GPIO_MASK(offset);
+	else
+		status &= ~KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_LVL, status);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+	status |= KEMPLD_GPIO_MASK(offset);
+	kempld_write8(pld, KEMPLD_NOW1_GPIO_DIR, status);
+
+	kempld_release_mutex(pld);
+
+	return 0;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int kempld_now1_gpio_get_direction(struct gpio_chip *chip,
+					unsigned offset)
+{
+	struct kempld_device_data *pld;
+	int status;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	status = kempld_read8(pld, KEMPLD_NOW1_GPIO_DIR);
+
+	kempld_release_mutex(pld);
+
+	status &= KEMPLD_GPIO_MASK(offset);
+
+	return status ? 1 : 0;
+}
+
+static void kempld_now1_gpio_dbg_show(struct seq_file *s,
+				struct gpio_chip *chip)
+{
+	struct kempld_device_data *pld;
+	int function;
+	int i;
+
+	pld = dev_get_drvdata(chip->dev->parent);
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_FUNCTION);
+
+	function = kempld_read8(pld, KEMPLD_NOW1_FUNCTION);
+
+	kempld_release_mutex(pld);
+
+	for (i = 0; i < chip->ngpio; i++) {
+		int gpio = i + chip->base;
+
+		seq_printf(s, " gpio-%-3d %s %s %s\n", gpio,
+				kempld_now1_gpio_get_direction(chip, i)
+				? "out" : "in",
+				kempld_now1_gpio_get(chip, i)
+				? "hi" : "lo",
+				function & KEMPLD_NOW1_FUNCTION_ALF_SDIO
+				? "sdio" :
+				((function & KEMPLD_NOW1_FUNCTION_USBCC)
+					&& (i == 0))
+				? "usbcc" : "gpio");
+	}
+}
+#else
+#define kempld_now1_gpio_dbg_show NULL
+#endif
+
+static int kempld_now1_gpio_probe(struct platform_device *pdev)
+{
+	struct kempld_device_data *pld;
+	struct gpio_chip *chip;
+	int function;
+	int ret;
+
+	pld = dev_get_drvdata(pdev->dev.parent);
+
+	chip = kzalloc(sizeof(struct gpio_chip), GFP_KERNEL);
+	if (chip == NULL) {
+		dev_err(&pdev->dev, "unable to get memory for device data\n");
+		ret = -ENOMEM;
+		goto err_alloc_dev_data;
+	}
+
+	chip->label =		"kempld_now1-gpio";
+	chip->owner =		THIS_MODULE;
+	chip->can_sleep =	1;
+	chip->dev =		&pdev->dev;
+	chip->base =		-1;
+	chip->ngpio =		KEMPLD_NOW1_GPIO_MAX_NUM;
+
+	chip->direction_input =		kempld_now1_gpio_direction_input;
+	chip->direction_output =	kempld_now1_gpio_direction_output;
+	chip->get =			kempld_now1_gpio_get;
+	chip->set =			kempld_now1_gpio_set;
+	chip->dbg_show =		kempld_now1_gpio_dbg_show;
+
+	kempld_get_mutex_set_index(pld, KEMPLD_NOW1_FUNCTION);
+
+	function = kempld_read8(pld, KEMPLD_NOW1_FUNCTION);
+
+	kempld_release_mutex(pld);
+
+	if (function & KEMPLD_NOW1_FUNCTION_ALF_SDIO)
+		dev_warn(&pdev->dev, "GPIO pins are used for SDIO\n");
+	if (function & KEMPLD_NOW1_FUNCTION_USBCC) {
+		dev_info(&pdev->dev,
+			 "GPI[0] is forwarded to USB cable connect\n");
+	}
+
+	platform_set_drvdata(pdev, chip);
+
+	ret = gpiochip_add(chip);
+	if (ret) {
+		dev_err(&pdev->dev, "Could not register GPIO chip\n");
+		goto err_gpiochip_add;
+	}
+
+	dev_info(&pdev->dev, "GPIO functionality initialized\n");
+
+	return 0;
+
+err_gpiochip_add:
+	kfree(chip);
+err_alloc_dev_data:
+
+	return ret;
+}
+
+static int kempld_now1_gpio_remove(struct platform_device *pdev)
+{
+	struct gpio_chip *chip = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(chip);
+	if (ret == 0) {
+		kfree(chip);
+		platform_set_drvdata(pdev, NULL);
+	}
+
+	return ret;
+}
+
+static struct platform_driver kempld_now1_gpio_driver = {
+	.driver = {
+		.name = "kempld_now1-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe		= kempld_now1_gpio_probe,
+	.remove		= kempld_now1_gpio_remove,
+};
+
+static int __init kempld_now1_gpio_init(void)
+{
+	return platform_driver_register(&kempld_now1_gpio_driver);
+}
+
+static void __exit kempld_now1_gpio_exit(void)
+{
+	platform_driver_unregister(&kempld_now1_gpio_driver);
+}
+
+module_init(kempld_now1_gpio_init);
+module_exit(kempld_now1_gpio_exit);
+
+MODULE_DESCRIPTION("KEM PLD nanoETXexpress-SP GPIO Driver");
+MODULE_AUTHOR("Michael Brunner <michael.brunner-2UyDCMiLNfhBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:kempld_now1-gpio");
-- 
1.7.9.5

  parent reply	other threads:[~2013-04-08 17:18 UTC|newest]

Thread overview: 67+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-04-08 17:15 [PATCH 1/4] mfd: Kontron PLD mfd driver Kevin Strasser
2013-04-08 17:15 ` [PATCH 2/4] i2c: Kontron PLD i2c bus driver Kevin Strasser
2013-04-08 17:15   ` Kevin Strasser
2013-04-10 17:02   ` Guenter Roeck
2013-04-10 17:02     ` Guenter Roeck
2013-04-16  9:53     ` Wolfram Sang
2013-04-16  9:53       ` Wolfram Sang
2013-04-08 17:15 ` Kevin Strasser [this message]
2013-04-08 17:15   ` [PATCH 3/4] gpio: Kontron PLD gpio driver Kevin Strasser
2013-04-09  8:46   ` Linus Walleij
2013-04-09 16:41     ` Guenter Roeck
2013-04-09 16:41       ` Guenter Roeck
2013-04-10 20:06       ` Linus Walleij
2013-04-10 20:45   ` Linus Walleij
2013-04-12 11:09     ` Michael Brunner
2013-04-12 11:09       ` Michael Brunner
2013-04-12 22:05       ` Linus Walleij
2013-04-08 17:15 ` [PATCH 4/4] watchdog: Kontron PLD watchdog timer Kevin Strasser
2013-04-08 17:15   ` Kevin Strasser
2013-04-10 16:47   ` Guenter Roeck
2013-04-10 16:57     ` Kevin Strasser
2013-04-10 16:57       ` Kevin Strasser
2013-05-26 14:38       ` Wim Van Sebroeck
2013-04-13 20:38 ` [PATCH 1/4] mfd: Kontron PLD mfd driver Thomas Gleixner
2013-04-18  4:19   ` Guenter Roeck
2013-04-18  4:40     ` Joe Perches
2013-04-18  4:40       ` Joe Perches
2013-04-18 13:35       ` Guenter Roeck
2013-04-18 13:35         ` Guenter Roeck
2013-04-18 16:42         ` Joe Perches
2013-04-18 18:40           ` Guenter Roeck
2013-06-18 21:04 ` [PATCH v2 0/4] Kontron PLD drivers Kevin Strasser
2013-06-18 21:04   ` Kevin Strasser
2013-06-18 21:04   ` [PATCH v2 1/4] mfd: Kontron PLD mfd driver Kevin Strasser
2013-06-19  8:40     ` Linus Walleij
2013-06-19  9:11       ` Samuel Ortiz
2013-06-19  9:48         ` Mark Brown
2013-06-19  9:12     ` Thomas Gleixner
2013-06-19 18:03       ` Kevin Strasser
2013-06-19 20:35         ` Guenter Roeck
2013-06-18 21:04   ` [PATCH v2 2/4] i2c: Kontron PLD i2c bus driver Kevin Strasser
2013-06-18 21:04   ` [PATCH v2 3/4] gpio: Kontron PLD gpio driver Kevin Strasser
2013-06-19  8:36     ` Linus Walleij
2013-06-27 22:14       ` Kevin Strasser
2013-06-18 21:04   ` [PATCH v2 4/4] watchdog: Kontron PLD watchdog timer driver Kevin Strasser
2013-06-24  4:00 ` [PATCH v3 0/4] Kontron PLD drivers Kevin Strasser
2013-06-24  4:00   ` Kevin Strasser
2013-06-24  4:00   ` [PATCH v3 1/4] mfd: Kontron PLD mfd driver Kevin Strasser
2013-06-24  4:00   ` [PATCH v3 2/4] i2c: Kontron PLD i2c bus driver Kevin Strasser
2013-07-01  6:40     ` Wolfram Sang
2013-07-01  6:40       ` Wolfram Sang
2013-06-24  4:00   ` [PATCH v3 3/4] gpio: Kontron PLD gpio driver Kevin Strasser
2013-07-21 14:31     ` Linus Walleij
2013-06-24  4:00   ` [PATCH v3 4/4] watchdog: Kontron PLD watchdog timer driver Kevin Strasser
2013-06-27 18:23     ` Kevin Strasser
2013-06-27 21:47       ` Samuel Ortiz
2013-06-27 21:47         ` Samuel Ortiz
2013-06-27 22:05         ` Kevin Strasser
2013-06-27 22:05           ` Kevin Strasser
2013-06-24 12:06   ` [PATCH v3 0/4] Kontron PLD drivers Samuel Ortiz
2013-06-24 12:06     ` Samuel Ortiz
2013-06-24 16:09     ` Wolfram Sang
2013-06-24 16:09       ` Wolfram Sang
2013-06-27 20:34     ` Wim Van Sebroeck
2013-06-27 20:34       ` Wim Van Sebroeck
2013-06-27 21:48       ` Samuel Ortiz
2013-06-27 21:48         ` Samuel Ortiz

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=1365441321-21952-3-git-send-email-kevin.strasser@linux.intel.com \
    --to=kevin.strasser@linux.intel.com \
    --cc=ben-linux@fluff.org \
    --cc=dvhart@linux.intel.com \
    --cc=grant.likely@secretlab.ca \
    --cc=gregkh@linuxfoundation.org \
    --cc=linus.walleij@linaro.org \
    --cc=linux-i2c@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-watchdog@vger.kernel.org \
    --cc=mibru@gmx.de \
    --cc=michael.brunner@kontron.com \
    --cc=sameo@linux.intel.com \
    --cc=wim@iguana.be \
    --cc=wsa@the-dreams.de \
    /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.