Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/4] pinctrl: add abx500 pinctrl driver core
From: Linus Walleij @ 2013-01-15  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Patrice Chotard <patrice.chotard@st.com>

This adds the AB8500 core driver, which will be utilized by
the follow-on drivers for different ABx500 variants.
Sselect the driver from the DBX500_SOC, as this chip is
powering and clocking that SoC.

Cc: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: Patrice Chotard <patrice.chotard@st.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
Hi Sam, it'd be great if you could ACK this so we could proceed
with rewriting the GPIO driver.
---
 arch/arm/mach-ux500/Kconfig            |    1 +
 arch/arm/mach-ux500/board-mop500.c     |   19 +-
 drivers/pinctrl/Kconfig                |    7 +
 drivers/pinctrl/Makefile               |    1 +
 drivers/pinctrl/pinctrl-abx500.c       | 1233 ++++++++++++++++++++++++++++++++
 drivers/pinctrl/pinctrl-abx500.h       |  229 ++++++
 include/linux/mfd/abx500/ab8500-gpio.h |   15 +-
 include/linux/mfd/abx500/ab8500.h      |    2 +-
 8 files changed, 1486 insertions(+), 21 deletions(-)
 create mode 100644 drivers/pinctrl/pinctrl-abx500.c
 create mode 100644 drivers/pinctrl/pinctrl-abx500.h

diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 5dea906..2c090d7 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -11,6 +11,7 @@ config UX500_SOC_COMMON
 	select COMMON_CLK
 	select PINCTRL
 	select PINCTRL_NOMADIK
+	select PINCTRL_ABX500
 	select PL310_ERRATA_753970 if CACHE_PL310
 
 config UX500_SOC_DB8500
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c
index d453522..b6f14ee 100644
--- a/arch/arm/mach-ux500/board-mop500.c
+++ b/arch/arm/mach-ux500/board-mop500.c
@@ -90,26 +90,9 @@ static struct platform_device snowball_gpio_en_3v3_regulator_dev = {
        },
 };
 
-static struct ab8500_gpio_platform_data ab8500_gpio_pdata = {
+static struct abx500_gpio_platform_data ab8500_gpio_pdata = {
 	.gpio_base		= MOP500_AB8500_PIN_GPIO(1),
 	.irq_base		= MOP500_AB8500_VIR_GPIO_IRQ_BASE,
-	/* config_reg is the initial configuration of ab8500 pins.
-	 * The pins can be configured as GPIO or alt functions based
-	 * on value present in GpioSel1 to GpioSel6 and AlternatFunction
-	 * register. This is the array of 7 configuration settings.
-	 * One has to compile time decide these settings. Below is the
-	 * explanation of these setting
-	 * GpioSel1 = 0x00 => Pins GPIO1 to GPIO8 are not used as GPIO
-	 * GpioSel2 = 0x1E => Pins GPIO10 to GPIO13 are configured as GPIO
-	 * GpioSel3 = 0x80 => Pin GPIO24 is configured as GPIO
-	 * GpioSel4 = 0x01 => Pin GPIo25 is configured as GPIO
-	 * GpioSel5 = 0x7A => Pins GPIO34, GPIO36 to GPIO39 are conf as GPIO
-	 * GpioSel6 = 0x00 => Pins GPIO41 & GPIo42 are not configured as GPIO
-	 * AlternaFunction = 0x00 => If Pins GPIO10 to 13 are not configured
-	 * as GPIO then this register selectes the alternate fucntions
-	 */
-	.config_reg		= {0x00, 0x1E, 0x80, 0x01,
-					0x7A, 0x00, 0x00},
 };
 
 /* ab8500-codec */
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c31aeb0..ec819d8 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -26,6 +26,13 @@ config DEBUG_PINCTRL
 	help
 	  Say Y here to add some extra checks and diagnostics to PINCTRL calls.
 
+config PINCTRL_ABX500
+	bool "ST-Ericsson ABx500 family Mixed Signal Circuit gpio functions"
+	depends on AB8500_CORE
+	select GENERIC_PINCONF
+	help
+	  Select this to enable the ABx500 family IC GPIO driver
+
 config PINCTRL_AT91
 	bool "AT91 pinctrl driver"
 	depends on OF
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index fc4606f..d10bf87 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -9,6 +9,7 @@ ifeq ($(CONFIG_OF),y)
 obj-$(CONFIG_PINCTRL)		+= devicetree.o
 endif
 obj-$(CONFIG_GENERIC_PINCONF)	+= pinconf-generic.o
+obj-$(CONFIG_PINCTRL_ABX500)	+= pinctrl-abx500.o
 obj-$(CONFIG_PINCTRL_AT91)	+= pinctrl-at91.o
 obj-$(CONFIG_PINCTRL_BCM2835)	+= pinctrl-bcm2835.o
 obj-$(CONFIG_PINCTRL_IMX)	+= pinctrl-imx.o
diff --git a/drivers/pinctrl/pinctrl-abx500.c b/drivers/pinctrl/pinctrl-abx500.c
new file mode 100644
index 0000000..ac89e10
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.c
@@ -0,0 +1,1233 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2013
+ *
+ * Author: Patrice Chotard <patrice.chotard@st.com>
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * 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 <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/mfd/abx500.h>
+#include <linux/mfd/abx500/ab8500.h>
+#include <linux/mfd/abx500/ab8500-gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+
+#include "pinctrl-abx500.h"
+
+/*
+ * The AB9540 and AB8540 GPIO support are extended versions
+ * of the AB8500 GPIO support.
+ * The AB9540 supports an additional (7th) register so that
+ * more GPIO may be configured and used.
+ * The AB8540 supports 4 new gpios (GPIOx_VBAT) that have
+ * internal pull-up and pull-down capabilities.
+ */
+
+/*
+ * GPIO registers offset
+ * Bank: 0x10
+ */
+#define AB8500_GPIO_SEL1_REG	0x00
+#define AB8500_GPIO_SEL2_REG	0x01
+#define AB8500_GPIO_SEL3_REG	0x02
+#define AB8500_GPIO_SEL4_REG	0x03
+#define AB8500_GPIO_SEL5_REG	0x04
+#define AB8500_GPIO_SEL6_REG	0x05
+#define AB9540_GPIO_SEL7_REG	0x06
+
+#define AB8500_GPIO_DIR1_REG	0x10
+#define AB8500_GPIO_DIR2_REG	0x11
+#define AB8500_GPIO_DIR3_REG	0x12
+#define AB8500_GPIO_DIR4_REG	0x13
+#define AB8500_GPIO_DIR5_REG	0x14
+#define AB8500_GPIO_DIR6_REG	0x15
+#define AB9540_GPIO_DIR7_REG	0x16
+
+#define AB8500_GPIO_OUT1_REG	0x20
+#define AB8500_GPIO_OUT2_REG	0x21
+#define AB8500_GPIO_OUT3_REG	0x22
+#define AB8500_GPIO_OUT4_REG	0x23
+#define AB8500_GPIO_OUT5_REG	0x24
+#define AB8500_GPIO_OUT6_REG	0x25
+#define AB9540_GPIO_OUT7_REG	0x26
+
+#define AB8500_GPIO_PUD1_REG	0x30
+#define AB8500_GPIO_PUD2_REG	0x31
+#define AB8500_GPIO_PUD3_REG	0x32
+#define AB8500_GPIO_PUD4_REG	0x33
+#define AB8500_GPIO_PUD5_REG	0x34
+#define AB8500_GPIO_PUD6_REG	0x35
+#define AB9540_GPIO_PUD7_REG	0x36
+
+#define AB8500_GPIO_IN1_REG	0x40
+#define AB8500_GPIO_IN2_REG	0x41
+#define AB8500_GPIO_IN3_REG	0x42
+#define AB8500_GPIO_IN4_REG	0x43
+#define AB8500_GPIO_IN5_REG	0x44
+#define AB8500_GPIO_IN6_REG	0x45
+#define AB9540_GPIO_IN7_REG	0x46
+#define AB8540_GPIO_VINSEL_REG	0x47
+#define AB8540_GPIO_PULL_UPDOWN_REG	0x48
+#define AB8500_GPIO_ALTFUN_REG	0x50
+#define AB8500_NUM_VIR_GPIO_IRQ	16
+#define AB8540_GPIO_PULL_UPDOWN_MASK	0x03
+#define AB8540_GPIO_VINSEL_MASK	0x03
+#define AB8540_GPIOX_VBAT_START	51
+#define AB8540_GPIOX_VBAT_END	54
+
+enum abx500_gpio_action {
+	NONE,
+	STARTUP,
+	SHUTDOWN,
+	MASK,
+	UNMASK
+};
+
+struct abx500_pinctrl {
+	struct device *dev;
+	struct pinctrl_dev *pctldev;
+	struct abx500_pinctrl_soc_data *soc;
+	struct gpio_chip chip;
+	struct ab8500 *parent;
+	struct mutex lock;
+	u32 irq_base;
+	enum abx500_gpio_action irq_action;
+	u16 rising;
+	u16 falling;
+	struct abx500_gpio_irq_cluster *irq_cluster;
+	int irq_cluster_size;
+	int irq_gpio_rising_offset;
+	int irq_gpio_falling_offset;
+	int irq_gpio_factor;
+};
+
+/**
+ * to_abx500_pinctrl() - get the pointer to abx500_pinctrl
+ * @chip:	Member of the structure abx500_pinctrl
+ */
+static inline struct abx500_pinctrl *to_abx500_pinctrl(struct gpio_chip *chip)
+{
+	return container_of(chip, struct abx500_pinctrl, chip);
+}
+
+static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
+					unsigned offset, bool *bit)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	u8 val;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_get_register_interruptible(pct->dev,
+						AB8500_MISC, reg, &val);
+
+	*bit = !!(val & BIT(pos));
+
+	if (ret < 0)
+		dev_err(pct->dev,
+			"%s read reg =%x, offset=%x failed\n",
+			__func__, reg, offset);
+
+	return ret;
+}
+
+static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
+					unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 pos = offset % 8;
+	int ret;
+
+	reg += offset / 8;
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+				AB8500_MISC, reg, 1 << pos, val << pos);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+	return ret;
+}
+/**
+ * abx500_gpio_get() - Get the particular GPIO value
+ * @chip: Gpio device
+ * @offset: GPIO number to read
+ */
+static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	u8 mask = 1 << (offset % 8);
+	u8 reg = AB8500_GPIO_IN1_REG + (offset / 8);
+	int ret;
+	u8 data;
+	ret = abx500_get_register_interruptible(pct->dev, AB8500_MISC,
+						reg, &data);
+	if (ret < 0) {
+		dev_err(pct->dev, "%s read failed\n", __func__);
+		return ret;
+	}
+	return (data & mask) >> (offset % 8);
+}
+
+static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int ret;
+	/* Write the data */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+	if (ret < 0)
+		dev_err(pct->dev, "%s write failed\n", __func__);
+}
+
+static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
+				int offset, enum abx500_gpio_pull_updown val)
+{
+	u8 pos;
+	int ret;
+	struct pullud *pullud;
+
+	if (!pct->soc->pullud) {
+		dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
+				__func__);
+		ret = -EPERM;
+		goto out;
+	}
+
+	pullud = pct->soc->pullud;
+
+	if ((offset < pullud->first_pin)
+		|| (offset > pullud->last_pin)) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	pos = offset << 1;
+
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+			AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
+			AB8540_GPIO_PULL_UPDOWN_MASK << pos, val << pos);
+
+out:
+	if (ret < 0)
+		dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
+	return ret;
+}
+
+static int abx500_gpio_direction_output(struct gpio_chip *chip,
+					unsigned offset,
+					int val)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pullud *pullud = pct->soc->pullud;
+	unsigned gpio;
+	int ret;
+	/* set direction as output */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* disable pull down */
+	ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
+	if (ret < 0)
+		return ret;
+
+	/* if supported, disable both pull down and pull up */
+	gpio = offset + 1;
+	if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
+		ret = abx500_config_pull_updown(pct,
+				offset,
+				ABX500_GPIO_PULL_NONE);
+		if (ret < 0)
+			return ret;
+	}
+	/* set the output as 1 or 0 */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
+}
+
+static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+	/* set the register as input */
+	return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
+}
+
+static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int base = pct->irq_base;
+	int i;
+
+	for (i = 0; i < pct->irq_cluster_size; i++) {
+		struct abx500_gpio_irq_cluster *cluster =
+			&pct->irq_cluster[i];
+
+		if (offset >= cluster->start && offset <= cluster->end)
+			return base + offset - cluster->start;
+
+		/* Advance by the number of gpios in this cluster */
+		base += cluster->end + cluster->offset - cluster->start + 1;
+	}
+
+	return -EINVAL;
+}
+
+static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+		unsigned gpio, int alt_setting)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+	int ret;
+	int val;
+	unsigned offset;
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	/* sanity check */
+	if (((alt_setting == ABX500_ALT_A) && (af.gpiosel_bit == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_B) && (af.alt_bit1 == UNUSED)) ||
+	    ((alt_setting == ABX500_ALT_C) && (af.alt_bit2 == UNUSED))) {
+		dev_dbg(pct->dev, "pin %d doesn't support %s mode\n", gpio,
+				modes[alt_setting]);
+		return -EINVAL;
+	}
+
+	/* on ABx5xx, there is no GPIO0, so adjust the offset */
+	offset = gpio - 1;
+	switch (alt_setting) {
+	case ABX500_DEFAULT:
+		/*
+		 * for ABx5xx family, default mode is always selected by
+		 * writing 0 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, default mode is selected
+		 * by writing 1 to GPIOSELx register
+		 */
+		val = 0;
+		if (af.alt_bit1 != UNUSED)
+			val++;
+
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					   offset, val);
+		break;
+	case ABX500_ALT_A:
+		/*
+		 * for ABx5xx family, alt_a mode is always selected by
+		 * writing 1 to GPIOSELx register, except for pins which
+		 * support at least ALT_B mode, alt_a mode is selected
+		 * by writing 0 to GPIOSELx register and 0 in ALTFUNC
+		 * register
+		 */
+		if (af.alt_bit1 != UNUSED) {
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 0);
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit1,
+					!!(af.alta_val && BIT(0)));
+			if (af.alt_bit2 != UNUSED)
+				ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.alta_val && BIT(1)));
+		} else
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+					offset, 1);
+		break;
+	case ABX500_ALT_B:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit1, !!(af.altb_val && BIT(0)));
+		if (af.alt_bit2 != UNUSED)
+			ret = abx500_gpio_set_bits(chip,
+					AB8500_GPIO_ALTFUN_REG,
+					af.alt_bit2,
+					!!(af.altb_val && BIT(1)));
+		break;
+	case ABX500_ALT_C:
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
+				offset, 0);
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(0)));
+		ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
+				af.alt_bit2, !!(af.altc_val && BIT(1)));
+		break;
+
+	default:
+		dev_dbg(pct->dev, "unknow alt_setting %d\n", alt_setting);
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+		unsigned gpio)
+{
+	u8 mode;
+	bool bit_mode;
+	bool alt_bit1;
+	bool alt_bit2;
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct alternate_functions af = pct->soc->alternate_functions[gpio];
+
+	/*
+	 * if gpiosel_bit is set to unused,
+	 * it means no GPIO or special case
+	 */
+	if (af.gpiosel_bit == UNUSED)
+		return ABX500_DEFAULT;
+
+	/* read GpioSelx register */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (gpio / 8),
+			af.gpiosel_bit, &bit_mode);
+	mode = bit_mode;
+
+	/* sanity check */
+	if ((af.alt_bit1 < UNUSED) || (af.alt_bit1 > 7) ||
+	    (af.alt_bit2 < UNUSED) || (af.alt_bit2 > 7)) {
+		dev_err(pct->dev,
+			"alt_bitX value not in correct range (-1 to 7)\n");
+		return -EINVAL;
+	}
+	/* if alt_bit2 is used, alt_bit1 must be used too */
+	if ((af.alt_bit2 != UNUSED) && (af.alt_bit1 == UNUSED)) {
+		dev_err(pct->dev,
+			"if alt_bit2 is used, alt_bit1 can't be unused\n");
+		return -EINVAL;
+	}
+
+	/* check if pin use AlternateFunction register */
+	if ((af.alt_bit1 == UNUSED) && (af.alt_bit1 == UNUSED))
+		return mode;
+	/*
+	 * if pin GPIOSEL bit is set and pin supports alternate function,
+	 * it means DEFAULT mode
+	 */
+	if (mode)
+		return ABX500_DEFAULT;
+	/*
+	 * pin use the AlternatFunction register
+	 * read alt_bit1 value
+	 */
+	abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
+			    af.alt_bit1, &alt_bit1);
+
+	if (af.alt_bit2 != UNUSED)
+		/* read alt_bit2 value */
+		abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
+				&alt_bit2);
+	else
+		alt_bit2 = 0;
+
+	mode = (alt_bit2 << 1) + alt_bit1;
+	if (mode == af.alta_val)
+		return ABX500_ALT_A;
+	else if (mode == af.altb_val)
+		return ABX500_ALT_B;
+	else
+		return ABX500_ALT_C;
+}
+
+#ifdef CONFIG_DEBUG_FS
+
+#include <linux/seq_file.h>
+
+static void abx500_gpio_dbg_show_one(struct seq_file *s,
+	struct pinctrl_dev *pctldev, struct gpio_chip *chip,
+	unsigned offset, unsigned gpio)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	const char *label = gpiochip_is_requested(chip, offset - 1);
+	u8 gpio_offset = offset - 1;
+	int mode = -1;
+	bool is_out;
+	bool pull;
+	const char *modes[] = {
+		[ABX500_DEFAULT]	= "default",
+		[ABX500_ALT_A]		= "altA",
+		[ABX500_ALT_B]		= "altB",
+		[ABX500_ALT_C]		= "altC",
+	};
+
+	abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
+	abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
+
+	if (pctldev)
+		mode = abx500_get_mode(pctldev, chip, offset);
+
+	seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
+		   gpio, label ?: "(none)",
+		   is_out ? "out" : "in ",
+		   is_out ?
+		   (chip->get
+		   ? (chip->get(chip, offset) ? "hi" : "lo")
+		   : "?  ")
+		   : (pull ? "pull up" : "pull down"),
+		   (mode < 0) ? "unknown" : modes[mode]);
+
+	if (label && !is_out) {
+		int irq = gpio_to_irq(gpio);
+		struct irq_desc	*desc = irq_to_desc(irq);
+
+		if (irq >= 0 && desc->action) {
+			char *trigger;
+			int irq_offset = irq - pct->irq_base;
+
+			if (pct->rising & BIT(irq_offset))
+				trigger = "edge-rising";
+			else if (pct->falling & BIT(irq_offset))
+				trigger = "edge-falling";
+			else
+				trigger = "edge-undefined";
+
+			seq_printf(s, " irq-%d %s", irq, trigger);
+		}
+	}
+}
+
+static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+	unsigned i;
+	unsigned gpio = chip->base;
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	struct pinctrl_dev *pctldev = pct->pctldev;
+
+	for (i = 0; i < chip->ngpio; i++, gpio++) {
+		/* On AB8500, there is no GPIO0, the first is the GPIO 1 */
+		abx500_gpio_dbg_show_one(s, pctldev, chip, i + 1, gpio);
+		seq_printf(s, "\n");
+	}
+}
+
+#else
+static inline void abx500_gpio_dbg_show_one(struct seq_file *s,
+					 struct pinctrl_dev *pctldev,
+					 struct gpio_chip *chip,
+					 unsigned offset, unsigned gpio)
+{
+}
+#define abx500_gpio_dbg_show	NULL
+#endif
+
+int abx500_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	return pinctrl_request_gpio(gpio);
+}
+
+void abx500_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+	int gpio = chip->base + offset;
+
+	pinctrl_free_gpio(gpio);
+}
+
+static struct gpio_chip abx500gpio_chip = {
+	.label			= "abx500-gpio",
+	.owner			= THIS_MODULE,
+	.request		= abx500_gpio_request,
+	.free			= abx500_gpio_free,
+	.direction_input	= abx500_gpio_direction_input,
+	.get			= abx500_gpio_get,
+	.direction_output	= abx500_gpio_direction_output,
+	.set			= abx500_gpio_set,
+	.to_irq			= abx500_gpio_to_irq,
+	.dbg_show		= abx500_gpio_dbg_show,
+};
+
+static unsigned int irq_to_rising(unsigned int irq)
+{
+	struct abx500_pinctrl *pct = irq_get_chip_data(irq);
+	int offset = irq - pct->irq_base;
+	int new_irq;
+
+	new_irq = offset * pct->irq_gpio_factor
+		+ pct->irq_gpio_rising_offset
+		+ pct->parent->irq_base;
+
+	return new_irq;
+}
+
+static unsigned int irq_to_falling(unsigned int irq)
+{
+	struct abx500_pinctrl *pct = irq_get_chip_data(irq);
+	int offset = irq - pct->irq_base;
+	int new_irq;
+
+	new_irq = offset * pct->irq_gpio_factor
+		+ pct->irq_gpio_falling_offset
+		+ pct->parent->irq_base;
+	return new_irq;
+
+}
+
+static unsigned int rising_to_irq(unsigned int irq, void *dev)
+{
+	struct abx500_pinctrl *pct = dev;
+	int offset, new_irq;
+
+	offset = irq - pct->irq_gpio_rising_offset
+		- pct->parent->irq_base;
+	new_irq = (offset / pct->irq_gpio_factor)
+		+ pct->irq_base;
+
+	return new_irq;
+}
+
+static unsigned int falling_to_irq(unsigned int irq, void *dev)
+{
+	struct abx500_pinctrl *pct = dev;
+	int offset, new_irq;
+
+	offset = irq - pct->irq_gpio_falling_offset
+		- pct->parent->irq_base;
+	new_irq = (offset / pct->irq_gpio_factor)
+		+ pct->irq_base;
+
+	return new_irq;
+}
+
+/*
+ * IRQ handler
+ */
+
+static irqreturn_t handle_rising(int irq, void *dev)
+{
+
+	handle_nested_irq(rising_to_irq(irq , dev));
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t handle_falling(int irq, void *dev)
+{
+
+	handle_nested_irq(falling_to_irq(irq, dev));
+	return IRQ_HANDLED;
+}
+
+static void abx500_gpio_irq_lock(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	mutex_lock(&pct->lock);
+}
+
+static void abx500_gpio_irq_sync_unlock(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	unsigned int irq = data->irq;
+	int offset = irq - pct->irq_base;
+	bool rising = pct->rising & BIT(offset);
+	bool falling = pct->falling & BIT(offset);
+	int ret;
+
+	switch (pct->irq_action)	{
+	case STARTUP:
+		if (rising)
+			ret = request_threaded_irq(irq_to_rising(irq),
+					NULL, handle_rising,
+					IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
+					"abx500-gpio-r", pct);
+		if (falling)
+			ret = request_threaded_irq(irq_to_falling(irq),
+				       NULL, handle_falling,
+				       IRQF_TRIGGER_FALLING | IRQF_NO_SUSPEND,
+				       "abx500-gpio-f", pct);
+		break;
+	case SHUTDOWN:
+		if (rising)
+			free_irq(irq_to_rising(irq), pct);
+		if (falling)
+			free_irq(irq_to_falling(irq), pct);
+		break;
+	case MASK:
+		if (rising)
+			disable_irq(irq_to_rising(irq));
+		if (falling)
+			disable_irq(irq_to_falling(irq));
+		break;
+	case UNMASK:
+		if (rising)
+			enable_irq(irq_to_rising(irq));
+		if (falling)
+			enable_irq(irq_to_falling(irq));
+		break;
+	case NONE:
+		break;
+	}
+	pct->irq_action = NONE;
+	pct->rising &= ~(BIT(offset));
+	pct->falling &= ~(BIT(offset));
+	mutex_unlock(&pct->lock);
+}
+
+
+static void abx500_gpio_irq_mask(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = MASK;
+}
+
+static void abx500_gpio_irq_unmask(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct =  irq_data_get_irq_chip_data(data);
+	pct->irq_action = UNMASK;
+}
+
+static int abx500_gpio_irq_set_type(struct irq_data *data, unsigned int type)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	unsigned int irq = data->irq;
+	int offset = irq - pct->irq_base;
+
+	if (type == IRQ_TYPE_EDGE_BOTH) {
+		pct->rising =  BIT(offset);
+		pct->falling = BIT(offset);
+	} else if (type == IRQ_TYPE_EDGE_RISING) {
+		pct->rising =  BIT(offset);
+	} else  {
+		pct->falling = BIT(offset);
+	}
+	return 0;
+}
+
+static unsigned int abx500_gpio_irq_startup(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = STARTUP;
+	return 0;
+}
+
+static void abx500_gpio_irq_shutdown(struct irq_data *data)
+{
+	struct abx500_pinctrl *pct = irq_data_get_irq_chip_data(data);
+	pct->irq_action = SHUTDOWN;
+}
+
+static struct irq_chip abx500_gpio_irq_chip = {
+	.name			= "abx500-gpio",
+	.irq_startup		= abx500_gpio_irq_startup,
+	.irq_shutdown		= abx500_gpio_irq_shutdown,
+	.irq_bus_lock		= abx500_gpio_irq_lock,
+	.irq_bus_sync_unlock	= abx500_gpio_irq_sync_unlock,
+	.irq_mask		= abx500_gpio_irq_mask,
+	.irq_unmask		= abx500_gpio_irq_unmask,
+	.irq_set_type		= abx500_gpio_irq_set_type,
+};
+
+static int abx500_gpio_irq_init(struct abx500_pinctrl *pct)
+{
+	u32 base = pct->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
+		irq_set_chip_data(irq, pct);
+		irq_set_chip_and_handler(irq, &abx500_gpio_irq_chip,
+				handle_simple_irq);
+		irq_set_nested_thread(irq, 1);
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, IRQF_VALID);
+#else
+		irq_set_noprobe(irq);
+#endif
+	}
+
+	return 0;
+}
+
+static void abx500_gpio_irq_remove(struct abx500_pinctrl *pct)
+{
+	int base = pct->irq_base;
+	int irq;
+
+	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
+#ifdef CONFIG_ARM
+		set_irq_flags(irq, 0);
+#endif
+		irq_set_chip_and_handler(irq, NULL, NULL);
+		irq_set_chip_data(irq, NULL);
+	}
+}
+
+static int abx500_pmx_get_funcs_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->nfunctions;
+}
+
+static const char *abx500_pmx_get_func_name(struct pinctrl_dev *pctldev,
+					 unsigned function)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->functions[function].name;
+}
+
+static int abx500_pmx_get_func_groups(struct pinctrl_dev *pctldev,
+				   unsigned function,
+				   const char * const **groups,
+				   unsigned * const num_groups)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*groups = pct->soc->functions[function].groups;
+	*num_groups = pct->soc->functions[function].ngroups;
+
+	return 0;
+}
+
+static void abx500_disable_lazy_irq(struct gpio_chip *chip, unsigned gpio)
+{
+	struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
+	int irq;
+	int offset;
+	bool rising;
+	bool falling;
+
+	/*
+	 * check if gpio has interrupt capability and convert
+	 * gpio number to irq
+	 * On ABx5xx, there is no GPIO0, GPIO1 is the
+	 * first one, so adjust gpio number
+	 */
+	gpio--;
+	irq =  gpio_to_irq(gpio + chip->base);
+	if (irq < 0)
+		return;
+
+	offset = irq - pct->irq_base;
+	rising = pct->rising & BIT(offset);
+	falling = pct->falling & BIT(offset);
+
+	/* nothing to do ?*/
+	if (!rising && !falling)
+		return;
+
+	if (rising) {
+		disable_irq(irq_to_rising(irq));
+		free_irq(irq_to_rising(irq), pct);
+	}
+	if (falling) {
+		disable_irq(irq_to_falling(irq));
+		free_irq(irq_to_falling(irq), pct);
+	}
+}
+
+static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
+			  unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+	const struct abx500_pingroup *g;
+	int i;
+	int ret = 0;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return -EINVAL;
+
+	dev_dbg(pct->dev, "enable group %s, %u pins\n", g->name, g->npins);
+
+	for (i = 0; i < g->npins; i++) {
+		dev_dbg(pct->dev, "setting pin %d to altsetting %d\n",
+			g->pins[i], g->altsetting);
+
+		abx500_disable_lazy_irq(chip, g->pins[i]);
+		ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
+	}
+	return ret;
+}
+
+static void abx500_pmx_disable(struct pinctrl_dev *pctldev,
+			    unsigned function, unsigned group)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	const struct abx500_pingroup *g;
+
+	g = &pct->soc->groups[group];
+	if (g->altsetting < 0)
+		return;
+
+	/* Poke out the mux, set the pin to some default state? */
+	dev_dbg(pct->dev, "disable group %s, %u pins\n", g->name, g->npins);
+}
+
+int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
+			    struct pinctrl_gpio_range *range,
+			    unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	u8 reg = AB8500_GPIO_SEL1_REG + (offset / 8);
+	u8 pos = offset % 8;
+	int ret;
+
+	if (!range) {
+		dev_err(pct->dev, "invalid range\n");
+		return -EINVAL;
+	}
+	if (!range->gc) {
+		dev_err(pct->dev, "missing GPIO chip in range\n");
+		return -EINVAL;
+	}
+	dev_dbg(pct->dev, "enable pin %u as GPIO\n", offset);
+
+	/*
+	 * by default, for ABx5xx family, GPIO mode is selected by
+	 * writing 1 in GPIOSELx registers
+	 */
+	ret = abx500_mask_and_set_register_interruptible(pct->dev,
+		AB8500_MISC, reg, 1 << pos, 1 << pos);
+
+	if (ret < 0) {
+		dev_err(pct->dev, "%s write failed\n", __func__);
+		return ret;
+	}
+	return ret;
+}
+
+static void abx500_gpio_disable_free(struct pinctrl_dev *pctldev,
+			   struct pinctrl_gpio_range *range,
+			   unsigned offset)
+{
+}
+
+static struct pinmux_ops abx500_pinmux_ops = {
+	.get_functions_count = abx500_pmx_get_funcs_cnt,
+	.get_function_name = abx500_pmx_get_func_name,
+	.get_function_groups = abx500_pmx_get_func_groups,
+	.enable = abx500_pmx_enable,
+	.disable = abx500_pmx_disable,
+	.gpio_request_enable = abx500_gpio_request_enable,
+	.gpio_disable_free = abx500_gpio_disable_free,
+};
+
+static int abx500_get_groups_cnt(struct pinctrl_dev *pctldev)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->ngroups;
+}
+
+static const char *abx500_get_group_name(struct pinctrl_dev *pctldev,
+				       unsigned selector)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	return pct->soc->groups[selector].name;
+}
+
+static int abx500_get_group_pins(struct pinctrl_dev *pctldev,
+		unsigned selector,
+		const unsigned **pins,
+		unsigned *num_pins)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+
+	*pins = pct->soc->groups[selector].pins;
+	*num_pins = pct->soc->groups[selector].npins;
+	return 0;
+}
+
+static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
+		struct seq_file *s, unsigned offset)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct gpio_chip *chip = &pct->chip;
+
+	abx500_gpio_dbg_show_one(s, pctldev, chip, offset,
+				 chip->base + offset - 1);
+}
+
+static struct pinctrl_ops abx500_pinctrl_ops = {
+	.get_groups_count = abx500_get_groups_cnt,
+	.get_group_name = abx500_get_group_name,
+	.get_group_pins = abx500_get_group_pins,
+	.pin_dbg_show = abx500_pin_dbg_show,
+};
+
+int abx500_pin_config_get(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long *config)
+{
+	/* Not implemented */
+	return -EINVAL;
+}
+
+int abx500_pin_config_set(struct pinctrl_dev *pctldev,
+		       unsigned pin,
+		       unsigned long config)
+{
+	struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
+	struct pullud *pullud = pct->soc->pullud;
+	struct gpio_chip *chip = &pct->chip;
+	unsigned offset;
+	int ret;
+	enum pin_config_param param = pinconf_to_config_param(config);
+	enum pin_config_param argument = pinconf_to_config_argument(config);
+
+	dev_dbg(chip->dev, "pin %d [%#lx]: %s %s\n",
+		pin, config, (param == PIN_CONFIG_OUTPUT) ? "output " : "input",
+		(param == PIN_CONFIG_OUTPUT) ? (argument ? "high" : "low") :
+		(argument ? "pull up" : "pull down"));
+	/* on ABx500, there is no GPIO0, so adjust the offset */
+	offset = pin - 1;
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		/*
+		 * if argument = 1 set the pull down
+		 * else clear the pull down
+		 */
+		ret = abx500_gpio_direction_input(chip, offset);
+		/* check if pin supports pull updown feature */
+		if (pullud && pin >= pullud->first_pin	&& pin <= pullud->last_pin)
+			ret = abx500_config_pull_updown(pct,
+				offset,
+				argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
+		else
+			ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
+				offset, argument ? 0 : 1);
+	break;
+	case PIN_CONFIG_OUTPUT:
+		ret = abx500_gpio_direction_output(chip, offset, argument);
+	break;
+	default:
+		dev_err(chip->dev, "illegal configuration requested\n");
+		return -EINVAL;
+	}
+	return ret;
+}
+
+static struct pinconf_ops abx500_pinconf_ops = {
+	.pin_config_get = abx500_pin_config_get,
+	.pin_config_set = abx500_pin_config_set,
+};
+
+static struct pinctrl_desc abx500_pinctrl_desc = {
+	.name = "pinctrl-abx500",
+	.pctlops = &abx500_pinctrl_ops,
+	.pmxops = &abx500_pinmux_ops,
+	.confops = &abx500_pinconf_ops,
+	.owner = THIS_MODULE,
+};
+
+static int abx500_get_gpio_num(struct abx500_pinctrl_soc_data *soc)
+{
+	unsigned int lowest = 0;
+	unsigned int highest = 0;
+	unsigned int npins = 0;
+	int i;
+
+	/*
+	 * Compute number of GPIOs from the last SoC gpio range descriptors
+	 * These ranges may include "holes" but the GPIO number space shall
+	 * still be homogeneous, so we need to detect and account for any
+	 * such holes so that these are included in the number of GPIO pins.
+	 */
+	for (i = 0; i < soc->gpio_num_ranges; i++) {
+		unsigned gstart;
+		unsigned gend;
+		const struct abx500_pinrange *p;
+
+		p = &soc->gpio_ranges[i];
+		gstart = p->offset;
+		gend = p->offset + p->npins - 1;
+
+		if (i == 0) {
+			/* First iteration, set start values */
+			lowest = gstart;
+			highest = gend;
+		} else {
+			if (gstart < lowest)
+				lowest = gstart;
+			if (gend > highest)
+				highest = gend;
+		}
+	}
+	/* this gives the absolute number of pins */
+	npins = highest - lowest + 1;
+	return npins;
+}
+
+static int __devinit abx500_gpio_probe(struct platform_device *pdev)
+{
+	struct ab8500_platform_data *abx500_pdata =
+				dev_get_platdata(pdev->dev.parent);
+	struct abx500_gpio_platform_data *pdata;
+	struct abx500_pinctrl *pct;
+	const struct platform_device_id *platid = platform_get_device_id(pdev);
+	int ret;
+	int i;
+
+	pdata = abx500_pdata->gpio;
+	if (!pdata)	{
+		dev_err(&pdev->dev, "gpio platform data missing\n");
+		return -ENODEV;
+	}
+
+	pct = devm_kzalloc(&pdev->dev, sizeof(struct abx500_pinctrl),
+				   GFP_KERNEL);
+	if (pct == NULL) {
+		dev_err(&pdev->dev,
+			"failed to allocate memory for pct\n");
+		return -ENOMEM;
+	}
+
+	pct->dev = &pdev->dev;
+	pct->parent = dev_get_drvdata(pdev->dev.parent);
+	pct->chip = abx500gpio_chip;
+	pct->chip.dev = &pdev->dev;
+	pct->chip.base = pdata->gpio_base;
+	pct->irq_base = pdata->irq_base;
+
+	/* initialize the lock */
+	mutex_init(&pct->lock);
+
+	/* Poke in other ASIC variants here */
+	switch (platid->driver_data) {
+	case PINCTRL_AB8500:
+		abx500_pinctrl_ab8500_init(&pct->soc);
+		break;
+	case PINCTRL_AB8540:
+		abx500_pinctrl_ab8540_init(&pct->soc);
+		break;
+	case PINCTRL_AB9540:
+		abx500_pinctrl_ab9540_init(&pct->soc);
+		break;
+	case PINCTRL_AB8505:
+		abx500_pinctrl_ab8505_init(&pct->soc);
+		break;
+	default:
+		dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n",
+				(int) platid->driver_data);
+		return -EINVAL;
+	}
+
+	if (!pct->soc) {
+		dev_err(&pdev->dev, "Invalid SOC data\n");
+		return -EINVAL;
+	}
+
+	pct->chip.ngpio = abx500_get_gpio_num(pct->soc);
+	pct->irq_cluster = pct->soc->gpio_irq_cluster;
+	pct->irq_cluster_size = pct->soc->ngpio_irq_cluster;
+	pct->irq_gpio_rising_offset = pct->soc->irq_gpio_rising_offset;
+	pct->irq_gpio_falling_offset = pct->soc->irq_gpio_falling_offset;
+	pct->irq_gpio_factor = pct->soc->irq_gpio_factor;
+
+	ret = abx500_gpio_irq_init(pct);
+	if (ret)
+		goto out_free;
+	ret = gpiochip_add(&pct->chip);
+	if (ret) {
+		dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
+				ret);
+		goto out_rem_irq;
+	}
+	dev_info(&pdev->dev, "added gpiochip\n");
+
+	abx500_pinctrl_desc.pins = pct->soc->pins;
+	abx500_pinctrl_desc.npins = pct->soc->npins;
+	pct->pctldev = pinctrl_register(&abx500_pinctrl_desc, &pdev->dev, pct);
+	if (!pct->pctldev) {
+		dev_err(&pdev->dev,
+			"could not register abx500 pinctrl driver\n");
+		goto out_rem_chip;
+	}
+	dev_info(&pdev->dev, "registered pin controller\n");
+
+	/* We will handle a range of GPIO pins */
+	for (i = 0; i < pct->soc->gpio_num_ranges; i++) {
+		const struct abx500_pinrange *p = &pct->soc->gpio_ranges[i];
+
+		ret = gpiochip_add_pin_range(&pct->chip,
+					dev_name(&pdev->dev),
+					p->offset, p->offset, p->npins);
+		if (ret < 0)
+			return ret;
+	}
+
+	platform_set_drvdata(pdev, pct);
+	dev_info(&pdev->dev, "initialized abx500 pinctrl driver\n");
+
+	return 0;
+
+out_rem_chip:
+	ret = gpiochip_remove(&pct->chip);
+	if (ret)
+		dev_info(&pdev->dev, "failed to remove gpiochip\n");
+out_rem_irq:
+	abx500_gpio_irq_remove(pct);
+out_free:
+	mutex_destroy(&pct->lock);
+	return ret;
+}
+
+/*
+ * abx500_gpio_remove() - remove Ab8500-gpio driver
+ * @pdev :	Platform device registered
+ */
+static int __devexit abx500_gpio_remove(struct platform_device *pdev)
+{
+	struct abx500_pinctrl *pct = platform_get_drvdata(pdev);
+	int ret;
+
+	ret = gpiochip_remove(&pct->chip);
+	if (ret < 0) {
+		dev_err(pct->dev, "unable to remove gpiochip: %d\n",
+			ret);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, NULL);
+	mutex_destroy(&pct->lock);
+	kfree(pct);
+
+	return 0;
+}
+
+static const struct platform_device_id abx500_pinctrl_id[] = {
+	{ "pinctrl-ab8500", PINCTRL_AB8500 },
+	{ "pinctrl-ab8540", PINCTRL_AB8540 },
+	{ "pinctrl-ab9540", PINCTRL_AB9540 },
+	{ "pinctrl-ab8505", PINCTRL_AB8505 },
+	{ },
+};
+
+static struct platform_driver abx500_gpio_driver = {
+	.driver = {
+		.name = "abx500-gpio",
+		.owner = THIS_MODULE,
+	},
+	.probe = abx500_gpio_probe,
+	.remove = __devexit_p(abx500_gpio_remove),
+	.id_table = abx500_pinctrl_id,
+};
+
+static int __init abx500_gpio_init(void)
+{
+	return platform_driver_register(&abx500_gpio_driver);
+}
+core_initcall(abx500_gpio_init);
+
+MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>");
+MODULE_DESCRIPTION("Driver allows to use AxB5xx unused pins to be used as GPIO");
+MODULE_ALIAS("platform:abx500-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/pinctrl-abx500.h b/drivers/pinctrl/pinctrl-abx500.h
new file mode 100644
index 0000000..359cb30
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-abx500.h
@@ -0,0 +1,229 @@
+#ifndef PINCTRL_PINCTRL_ABx5O0_H
+#define PINCTRL_PINCTRL_ABx500_H
+
+/* Package definitions */
+#define PINCTRL_AB8500	0
+#define PINCTRL_AB8540	1
+#define PINCTRL_AB9540	2
+#define PINCTRL_AB8505	3
+
+/* pins alternate function */
+enum abx500_pin_func {
+	ABX500_DEFAULT,
+	ABX500_ALT_A,
+	ABX500_ALT_B,
+	ABX500_ALT_C,
+};
+
+/**
+ * struct abx500_function - ABx500 pinctrl mux function
+ * @name: The name of the function, exported to pinctrl core.
+ * @groups: An array of pin groups that may select this function.
+ * @ngroups: The number of entries in @groups.
+ */
+struct abx500_function {
+	const char *name;
+	const char * const *groups;
+	unsigned ngroups;
+};
+
+/**
+ * struct abx500_pingroup - describes a ABx500 pin group
+ * @name: the name of this specific pin group
+ * @pins: an array of discrete physical pins used in this group, taken
+ *	from the driver-local pin enumeration space
+ * @num_pins: the number of pins in this group array, i.e. the number of
+ *	elements in .pins so we can iterate over that array
+ * @altsetting: the altsetting to apply to all pins in this group to
+ *	configure them to be used by a function
+ */
+struct abx500_pingroup {
+	const char *name;
+	const unsigned int *pins;
+	const unsigned npins;
+	int altsetting;
+};
+
+#define ALTERNATE_FUNCTIONS(pin, sel_bit, alt1, alt2, alta, altb, altc)	\
+{									\
+	.pin_number = pin,						\
+	.gpiosel_bit = sel_bit,						\
+	.alt_bit1 = alt1,						\
+	.alt_bit2 = alt2,						\
+	.alta_val = alta,						\
+	.altb_val = altb,						\
+	.altc_val = altc,						\
+}
+
+#define UNUSED -1
+/**
+ * struct alternate_functions
+ * @pin_number:		The pin number
+ * @gpiosel_bit:	Control bit in GPIOSEL register,
+ * @alt_bit1:		First AlternateFunction bit used to select the
+ *			alternate function
+ * @alt_bit2:		Second AlternateFunction bit used to select the
+ *			alternate function
+ *
+ *			these 3 following fields are necessary due to none
+ *			coherency on how to select the altA, altB and altC
+ *			function between the ABx500 SOC family when using
+ *			alternatfunc register.
+ * @alta_val:		value to write in alternatfunc to select altA function
+ * @altb_val:		value to write in alternatfunc to select altB function
+ * @altc_val:		value to write in alternatfunc to select altC function
+ */
+struct alternate_functions {
+	unsigned pin_number;
+	s8 gpiosel_bit;
+	s8 alt_bit1;
+	s8 alt_bit2;
+	u8 alta_val;
+	u8 altb_val;
+	u8 altc_val;
+};
+
+/**
+ * struct pullud - specific pull up/down feature
+ * @first_pin:		The pin number of the first pins which support
+ *			specific pull up/down
+ * @last_pin:		The pin number of the last pins
+ */
+struct pullud {
+	unsigned first_pin;
+	unsigned last_pin;
+};
+
+#define GPIO_IRQ_CLUSTER(a, b, c)	\
+{					\
+	.start = a,			\
+	.end = b,			\
+	.offset = c,			\
+}
+
+/**
+ * struct abx500_gpio_irq_cluster - indicates GPIOs which are interrupt
+ *			capable
+ * @start:		The pin number of the first pin interrupt capable
+ * @end:		The pin number of the last pin interrupt capable
+ * @offset:		offset used to compute specific setting strategy of
+ *			the interrupt line
+ */
+
+struct abx500_gpio_irq_cluster {
+	int start;
+	int end;
+	int offset;
+};
+
+/**
+ * struct abx500_pinrange - map pin numbers to GPIO offsets
+ * @offset:		offset into the GPIO local numberspace, incidentally
+ *			identical to the offset into the local pin numberspace
+ * @npins:		number of pins to map from both offsets
+ */
+struct abx500_pinrange {
+	unsigned int offset;
+	unsigned int npins;
+};
+
+#define ABX500_PINRANGE(a, b) { .offset = a, .npins = b }
+
+/**
+ * struct abx500_pinctrl_soc_data - ABx500 pin controller per-SoC configuration
+ * @gpio_ranges:	An array of GPIO ranges for this SoC
+ * @gpio_num_ranges:	The number of GPIO ranges for this SoC
+ * @pins:		An array describing all pins the pin controller affects.
+ *			All pins which are also GPIOs must be listed first within the
+ *			array, and be numbered identically to the GPIO controller's
+ *			numbering.
+ * @npins:		The number of entries in @pins.
+ * @functions:		The functions supported on this SoC.
+ * @nfunction:		The number of entries in @functions.
+ * @groups:		An array describing all pin groups the pin SoC supports.
+ * @ngroups:		The number of entries in @groups.
+ * @alternate_functions: array describing pins which supports alternate and
+ *			how to set it.
+ * @pullud:		array describing pins which supports pull up/down
+ *			specific registers.
+ * @gpio_irq_cluster:	An array of GPIO interrupt capable for this SoC
+ * @ngpio_irq_cluster:	The number of GPIO inetrrupt capable for this SoC
+ * @irq_gpio_rising_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the rising interrupt line
+ * @irq_gpio_falling_offset: Interrupt offset used as base to compute specific
+ *			setting strategy of the falling interrupt line
+ * @irq_gpio_factor:	Factor used to compute specific setting strategy of
+ *			the interrupt line
+ */
+
+struct abx500_pinctrl_soc_data {
+	const struct abx500_pinrange *gpio_ranges;
+	unsigned gpio_num_ranges;
+	const struct pinctrl_pin_desc *pins;
+	unsigned npins;
+	const struct abx500_function *functions;
+	unsigned nfunctions;
+	const struct abx500_pingroup *groups;
+	unsigned ngroups;
+	struct alternate_functions *alternate_functions;
+	struct pullud *pullud;
+	struct abx500_gpio_irq_cluster *gpio_irq_cluster;
+	unsigned ngpio_irq_cluster;
+	int irq_gpio_rising_offset;
+	int irq_gpio_falling_offset;
+	int irq_gpio_factor;
+};
+
+#ifdef CONFIG_PINCTRL_AB8500
+
+void abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8500_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8540
+
+void abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB9540
+
+void abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab9540_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#ifdef CONFIG_PINCTRL_AB8505
+
+void abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc);
+
+#else
+
+static inline void
+abx500_pinctrl_ab8505_init(struct abx500_pinctrl_soc_data **soc)
+{
+}
+
+#endif
+
+#endif /* PINCTRL_PINCTRL_ABx500_H */
diff --git a/include/linux/mfd/abx500/ab8500-gpio.h b/include/linux/mfd/abx500/ab8500-gpio.h
index 2387c20..e8c8281 100644
--- a/include/linux/mfd/abx500/ab8500-gpio.h
+++ b/include/linux/mfd/abx500/ab8500-gpio.h
@@ -14,10 +14,21 @@
  * registers.
  */
 
-struct ab8500_gpio_platform_data {
+struct abx500_gpio_platform_data {
 	int gpio_base;
 	u32 irq_base;
-	u8  config_reg[8];
+};
+
+enum abx500_gpio_pull_updown {
+	ABX500_GPIO_PULL_DOWN = 0x0,
+	ABX500_GPIO_PULL_NONE = 0x1,
+	ABX500_GPIO_PULL_UP = 0x3,
+};
+
+enum abx500_gpio_vinsel {
+	ABX500_GPIO_VINSEL_VBAT = 0x0,
+	ABX500_GPIO_VINSEL_VIN_1V8 = 0x1,
+	ABX500_GPIO_VINSEL_VDD_BIF = 0x2,
 };
 
 #endif /* _AB8500_GPIO_H */
diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index e640ea0..fc05344 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -385,7 +385,7 @@ struct ab8500_platform_data {
 	struct ab8500_regulator_reg_init *regulator_reg_init;
 	int num_regulator;
 	struct regulator_init_data *regulator;
-	struct ab8500_gpio_platform_data *gpio;
+	struct abx500_gpio_platform_data *gpio;
 	struct ab8500_codec_platform_data *codec;
 };
 
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH 2/4] gpio: delete AB8500 driver
From: Linus Walleij @ 2013-01-15  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

From: Linus Walleij <linus.walleij@linaro.org>

The AB8500 GPIO driver has been marked BROKEN for ages, and we
have something better in store: a shiny new pinctrl driver. So
let use delete this old driver as the first step.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 drivers/gpio/Kconfig       |   6 -
 drivers/gpio/Makefile      |   1 -
 drivers/gpio/gpio-ab8500.c | 520 ---------------------------------------------
 3 files changed, 527 deletions(-)
 delete mode 100644 drivers/gpio/gpio-ab8500.c

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de75..e5116fa 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -657,12 +657,6 @@ config GPIO_JANZ_TTL
 	  This driver provides support for driving the pins in output
 	  mode only. Input mode is not supported.
 
-config GPIO_AB8500
-	bool "ST-Ericsson AB8500 Mixed Signal Circuit gpio functions"
-	depends on AB8500_CORE && BROKEN
-	help
-	  Select this to enable the AB8500 IC GPIO driver
-
 config GPIO_TPS6586X
 	bool "TPS6586X GPIO"
 	depends on MFD_TPS6586X
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c5aebd0..45a388c 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -10,7 +10,6 @@ obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
 obj-$(CONFIG_GPIO_GENERIC)	+= gpio-generic.o
 
 obj-$(CONFIG_GPIO_74X164)	+= gpio-74x164.o
-obj-$(CONFIG_GPIO_AB8500)	+= gpio-ab8500.o
 obj-$(CONFIG_GPIO_ADNP)		+= gpio-adnp.o
 obj-$(CONFIG_GPIO_ADP5520)	+= gpio-adp5520.o
 obj-$(CONFIG_GPIO_ADP5588)	+= gpio-adp5588.o
diff --git a/drivers/gpio/gpio-ab8500.c b/drivers/gpio/gpio-ab8500.c
deleted file mode 100644
index 983ad42..0000000
--- a/drivers/gpio/gpio-ab8500.c
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- * Copyright (C) ST-Ericsson SA 2011
- *
- * Author: BIBEK BASU <bibek.basu@stericsson.com>
- * License terms: GNU General Public License (GPL) version 2
- *
- * 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 <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/irq.h>
-#include <linux/interrupt.h>
-#include <linux/mfd/ab8500.h>
-#include <linux/mfd/abx500.h>
-#include <linux/mfd/ab8500/gpio.h>
-
-/*
- * GPIO registers offset
- * Bank: 0x10
- */
-#define AB8500_GPIO_SEL1_REG	0x00
-#define AB8500_GPIO_SEL2_REG	0x01
-#define AB8500_GPIO_SEL3_REG	0x02
-#define AB8500_GPIO_SEL4_REG	0x03
-#define AB8500_GPIO_SEL5_REG	0x04
-#define AB8500_GPIO_SEL6_REG	0x05
-
-#define AB8500_GPIO_DIR1_REG	0x10
-#define AB8500_GPIO_DIR2_REG	0x11
-#define AB8500_GPIO_DIR3_REG	0x12
-#define AB8500_GPIO_DIR4_REG	0x13
-#define AB8500_GPIO_DIR5_REG	0x14
-#define AB8500_GPIO_DIR6_REG	0x15
-
-#define AB8500_GPIO_OUT1_REG	0x20
-#define AB8500_GPIO_OUT2_REG	0x21
-#define AB8500_GPIO_OUT3_REG	0x22
-#define AB8500_GPIO_OUT4_REG	0x23
-#define AB8500_GPIO_OUT5_REG	0x24
-#define AB8500_GPIO_OUT6_REG	0x25
-
-#define AB8500_GPIO_PUD1_REG	0x30
-#define AB8500_GPIO_PUD2_REG	0x31
-#define AB8500_GPIO_PUD3_REG	0x32
-#define AB8500_GPIO_PUD4_REG	0x33
-#define AB8500_GPIO_PUD5_REG	0x34
-#define AB8500_GPIO_PUD6_REG	0x35
-
-#define AB8500_GPIO_IN1_REG	0x40
-#define AB8500_GPIO_IN2_REG	0x41
-#define AB8500_GPIO_IN3_REG	0x42
-#define AB8500_GPIO_IN4_REG	0x43
-#define AB8500_GPIO_IN5_REG	0x44
-#define AB8500_GPIO_IN6_REG	0x45
-#define AB8500_GPIO_ALTFUN_REG	0x45
-#define ALTFUN_REG_INDEX	6
-#define AB8500_NUM_GPIO		42
-#define AB8500_NUM_VIR_GPIO_IRQ	16
-
-enum ab8500_gpio_action {
-	NONE,
-	STARTUP,
-	SHUTDOWN,
-	MASK,
-	UNMASK
-};
-
-struct ab8500_gpio {
-	struct gpio_chip chip;
-	struct ab8500 *parent;
-	struct device *dev;
-	struct mutex lock;
-	u32 irq_base;
-	enum ab8500_gpio_action irq_action;
-	u16 rising;
-	u16 falling;
-};
-/**
- * to_ab8500_gpio() - get the pointer to ab8500_gpio
- * @chip:	Member of the structure ab8500_gpio
- */
-static inline struct ab8500_gpio *to_ab8500_gpio(struct gpio_chip *chip)
-{
-	return container_of(chip, struct ab8500_gpio, chip);
-}
-
-static int ab8500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
-					unsigned offset, int val)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	u8 pos = offset % 8;
-	int ret;
-
-	reg = reg + (offset / 8);
-	ret = abx500_mask_and_set_register_interruptible(ab8500_gpio->dev,
-				AB8500_MISC, reg, 1 << pos, val << pos);
-	if (ret < 0)
-		dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-	return ret;
-}
-/**
- * ab8500_gpio_get() - Get the particular GPIO value
- * @chip: Gpio device
- * @offset: GPIO number to read
- */
-static int ab8500_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	u8 mask = 1 << (offset % 8);
-	u8 reg = AB8500_GPIO_OUT1_REG + (offset / 8);
-	int ret;
-	u8 data;
-	ret = abx500_get_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
-						reg, &data);
-	if (ret < 0) {
-		dev_err(ab8500_gpio->dev, "%s read failed\n", __func__);
-		return ret;
-	}
-	return (data & mask) >> (offset % 8);
-}
-
-static void ab8500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
-{
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	int ret;
-	/* Write the data */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, 1);
-	if (ret < 0)
-		dev_err(ab8500_gpio->dev, "%s write failed\n", __func__);
-}
-
-static int ab8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
-					int val)
-{
-	int ret;
-	/* set direction as output */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
-	if (ret < 0)
-		return ret;
-	/* disable pull down */
-	ret = ab8500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
-	if (ret < 0)
-		return ret;
-	/* set the output as 1 or 0 */
-	return ab8500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
-
-}
-
-static int ab8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
-	/* set the register as input */
-	return ab8500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
-}
-
-static int ab8500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
-{
-	/*
-	 * Only some GPIOs are interrupt capable, and they are
-	 * organized in discontiguous clusters:
-	 *
-	 *	GPIO6 to GPIO13
-	 *	GPIO24 and GPIO25
-	 *	GPIO36 to GPIO41
-	 */
-	static struct ab8500_gpio_irq_cluster {
-		int start;
-		int end;
-	} clusters[] = {
-		{.start = 6,  .end = 13},
-		{.start = 24, .end = 25},
-		{.start = 36, .end = 41},
-	};
-	struct ab8500_gpio *ab8500_gpio = to_ab8500_gpio(chip);
-	int base = ab8500_gpio->irq_base;
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(clusters); i++) {
-		struct ab8500_gpio_irq_cluster *cluster = &clusters[i];
-
-		if (offset >= cluster->start && offset <= cluster->end)
-			return base + offset - cluster->start;
-
-		/* Advance by the number of gpios in this cluster */
-		base += cluster->end - cluster->start + 1;
-	}
-
-	return -EINVAL;
-}
-
-static struct gpio_chip ab8500gpio_chip = {
-	.label			= "ab8500_gpio",
-	.owner			= THIS_MODULE,
-	.direction_input	= ab8500_gpio_direction_input,
-	.get			= ab8500_gpio_get,
-	.direction_output	= ab8500_gpio_direction_output,
-	.set			= ab8500_gpio_set,
-	.to_irq			= ab8500_gpio_to_irq,
-};
-
-static unsigned int irq_to_rising(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	int new_irq = offset +  AB8500_INT_GPIO6R
-			+ ab8500_gpio->parent->irq_base;
-	return new_irq;
-}
-
-static unsigned int irq_to_falling(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	int new_irq = offset +  AB8500_INT_GPIO6F
-			+  ab8500_gpio->parent->irq_base;
-	return new_irq;
-
-}
-
-static unsigned int rising_to_irq(unsigned int irq, void *dev)
-{
-	struct ab8500_gpio *ab8500_gpio = dev;
-	int offset = irq - AB8500_INT_GPIO6R
-			- ab8500_gpio->parent->irq_base ;
-	int new_irq = offset + ab8500_gpio->irq_base;
-	return new_irq;
-}
-
-static unsigned int falling_to_irq(unsigned int irq, void *dev)
-{
-	struct ab8500_gpio *ab8500_gpio = dev;
-	int offset = irq - AB8500_INT_GPIO6F
-			- ab8500_gpio->parent->irq_base ;
-	int new_irq = offset + ab8500_gpio->irq_base;
-	return new_irq;
-
-}
-
-/*
- * IRQ handler
- */
-
-static irqreturn_t handle_rising(int irq, void *dev)
-{
-
-	handle_nested_irq(rising_to_irq(irq , dev));
-	return IRQ_HANDLED;
-}
-
-static irqreturn_t handle_falling(int irq, void *dev)
-{
-
-	handle_nested_irq(falling_to_irq(irq, dev));
-	return IRQ_HANDLED;
-}
-
-static void ab8500_gpio_irq_lock(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	mutex_lock(&ab8500_gpio->lock);
-}
-
-static void ab8500_gpio_irq_sync_unlock(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-	bool rising = ab8500_gpio->rising & BIT(offset);
-	bool falling = ab8500_gpio->falling & BIT(offset);
-	int ret;
-
-	switch (ab8500_gpio->irq_action)	{
-	case STARTUP:
-		if (rising)
-			ret = request_threaded_irq(irq_to_rising(irq),
-					NULL, handle_rising,
-					IRQF_TRIGGER_RISING,
-					"ab8500-gpio-r", ab8500_gpio);
-		if (falling)
-			ret = request_threaded_irq(irq_to_falling(irq),
-				       NULL, handle_falling,
-				       IRQF_TRIGGER_FALLING,
-				       "ab8500-gpio-f", ab8500_gpio);
-		break;
-	case SHUTDOWN:
-		if (rising)
-			free_irq(irq_to_rising(irq), ab8500_gpio);
-		if (falling)
-			free_irq(irq_to_falling(irq), ab8500_gpio);
-		break;
-	case MASK:
-		if (rising)
-			disable_irq(irq_to_rising(irq));
-		if (falling)
-			disable_irq(irq_to_falling(irq));
-		break;
-	case UNMASK:
-		if (rising)
-			enable_irq(irq_to_rising(irq));
-		if (falling)
-			enable_irq(irq_to_falling(irq));
-		break;
-	case NONE:
-		break;
-	}
-	ab8500_gpio->irq_action = NONE;
-	ab8500_gpio->rising &= ~(BIT(offset));
-	ab8500_gpio->falling &= ~(BIT(offset));
-	mutex_unlock(&ab8500_gpio->lock);
-}
-
-
-static void ab8500_gpio_irq_mask(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = MASK;
-}
-
-static void ab8500_gpio_irq_unmask(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = UNMASK;
-}
-
-static int ab8500_gpio_irq_set_type(unsigned int irq, unsigned int type)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	int offset = irq - ab8500_gpio->irq_base;
-
-	if (type == IRQ_TYPE_EDGE_BOTH) {
-		ab8500_gpio->rising =  BIT(offset);
-		ab8500_gpio->falling = BIT(offset);
-	} else if (type == IRQ_TYPE_EDGE_RISING) {
-		ab8500_gpio->rising =  BIT(offset);
-	} else  {
-		ab8500_gpio->falling = BIT(offset);
-	}
-	return 0;
-}
-
-unsigned int ab8500_gpio_irq_startup(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = STARTUP;
-	return 0;
-}
-
-void ab8500_gpio_irq_shutdown(unsigned int irq)
-{
-	struct ab8500_gpio *ab8500_gpio = get_irq_chip_data(irq);
-	ab8500_gpio->irq_action = SHUTDOWN;
-}
-
-static struct irq_chip ab8500_gpio_irq_chip = {
-	.name			= "ab8500-gpio",
-	.startup		= ab8500_gpio_irq_startup,
-	.shutdown		= ab8500_gpio_irq_shutdown,
-	.bus_lock		= ab8500_gpio_irq_lock,
-	.bus_sync_unlock	= ab8500_gpio_irq_sync_unlock,
-	.mask			= ab8500_gpio_irq_mask,
-	.unmask			= ab8500_gpio_irq_unmask,
-	.set_type		= ab8500_gpio_irq_set_type,
-};
-
-static int ab8500_gpio_irq_init(struct ab8500_gpio *ab8500_gpio)
-{
-	u32 base = ab8500_gpio->irq_base;
-	int irq;
-
-	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ ; irq++) {
-		set_irq_chip_data(irq, ab8500_gpio);
-		set_irq_chip_and_handler(irq, &ab8500_gpio_irq_chip,
-				handle_simple_irq);
-		set_irq_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
-		set_irq_flags(irq, IRQF_VALID);
-#else
-		set_irq_noprobe(irq);
-#endif
-	}
-
-	return 0;
-}
-
-static void ab8500_gpio_irq_remove(struct ab8500_gpio *ab8500_gpio)
-{
-	int base = ab8500_gpio->irq_base;
-	int irq;
-
-	for (irq = base; irq < base + AB8500_NUM_VIR_GPIO_IRQ; irq++) {
-#ifdef CONFIG_ARM
-		set_irq_flags(irq, 0);
-#endif
-		set_irq_chip_and_handler(irq, NULL, NULL);
-		set_irq_chip_data(irq, NULL);
-	}
-}
-
-static int ab8500_gpio_probe(struct platform_device *pdev)
-{
-	struct ab8500_platform_data *ab8500_pdata =
-				dev_get_platdata(pdev->dev.parent);
-	struct ab8500_gpio_platform_data *pdata;
-	struct ab8500_gpio *ab8500_gpio;
-	int ret;
-	int i;
-
-	pdata = ab8500_pdata->gpio;
-	if (!pdata)	{
-		dev_err(&pdev->dev, "gpio platform data missing\n");
-		return -ENODEV;
-	}
-
-	ab8500_gpio = kzalloc(sizeof(struct ab8500_gpio), GFP_KERNEL);
-	if (ab8500_gpio == NULL) {
-		dev_err(&pdev->dev, "failed to allocate memory\n");
-		return -ENOMEM;
-	}
-	ab8500_gpio->dev = &pdev->dev;
-	ab8500_gpio->parent = dev_get_drvdata(pdev->dev.parent);
-	ab8500_gpio->chip = ab8500gpio_chip;
-	ab8500_gpio->chip.ngpio = AB8500_NUM_GPIO;
-	ab8500_gpio->chip.dev = &pdev->dev;
-	ab8500_gpio->chip.base = pdata->gpio_base;
-	ab8500_gpio->irq_base = pdata->irq_base;
-	/* initialize the lock */
-	mutex_init(&ab8500_gpio->lock);
-	/*
-	 * AB8500 core will handle and clear the IRQ
-	 * configre GPIO based on config-reg value.
-	 * These values are for selecting the PINs as
-	 * GPIO or alternate function
-	 */
-	for (i = AB8500_GPIO_SEL1_REG; i <= AB8500_GPIO_SEL6_REG; i++)	{
-		ret = abx500_set_register_interruptible(ab8500_gpio->dev,
-				AB8500_MISC, i,
-				pdata->config_reg[i]);
-		if (ret < 0)
-			goto out_free;
-	}
-	ret = abx500_set_register_interruptible(ab8500_gpio->dev, AB8500_MISC,
-				AB8500_GPIO_ALTFUN_REG,
-				pdata->config_reg[ALTFUN_REG_INDEX]);
-	if (ret < 0)
-		goto out_free;
-
-	ret = ab8500_gpio_irq_init(ab8500_gpio);
-	if (ret)
-		goto out_free;
-	ret = gpiochip_add(&ab8500_gpio->chip);
-	if (ret) {
-		dev_err(&pdev->dev, "unable to add gpiochip: %d\n",
-				ret);
-		goto out_rem_irq;
-	}
-	platform_set_drvdata(pdev, ab8500_gpio);
-	return 0;
-
-out_rem_irq:
-	ab8500_gpio_irq_remove(ab8500_gpio);
-out_free:
-	mutex_destroy(&ab8500_gpio->lock);
-	kfree(ab8500_gpio);
-	return ret;
-}
-
-/*
- * ab8500_gpio_remove() - remove Ab8500-gpio driver
- * @pdev :	Platform device registered
- */
-static int ab8500_gpio_remove(struct platform_device *pdev)
-{
-	struct ab8500_gpio *ab8500_gpio = platform_get_drvdata(pdev);
-	int ret;
-
-	ret = gpiochip_remove(&ab8500_gpio->chip);
-	if (ret < 0) {
-		dev_err(ab8500_gpio->dev, "unable to remove gpiochip: %d\n",
-			ret);
-		return ret;
-	}
-
-	platform_set_drvdata(pdev, NULL);
-	mutex_destroy(&ab8500_gpio->lock);
-	kfree(ab8500_gpio);
-
-	return 0;
-}
-
-static struct platform_driver ab8500_gpio_driver = {
-	.driver = {
-		.name = "ab8500-gpio",
-		.owner = THIS_MODULE,
-	},
-	.probe = ab8500_gpio_probe,
-	.remove = ab8500_gpio_remove,
-};
-
-static int __init ab8500_gpio_init(void)
-{
-	return platform_driver_register(&ab8500_gpio_driver);
-}
-arch_initcall(ab8500_gpio_init);
-
-static void __exit ab8500_gpio_exit(void)
-{
-	platform_driver_unregister(&ab8500_gpio_driver);
-}
-module_exit(ab8500_gpio_exit);
-
-MODULE_AUTHOR("BIBEK BASU <bibek.basu@stericsson.com>");
-MODULE_DESCRIPTION("Driver allows to use AB8500 unused pins to be used as GPIO");
-MODULE_ALIAS("platform:ab8500-gpio");
-MODULE_LICENSE("GPL v2");
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH 1/4] mfd: ab8500: update header file and version detection
From: Linus Walleij @ 2013-01-15  9:42 UTC (permalink / raw)
  To: linux-arm-kernel

From: Linus Walleij <linus.walleij@linaro.org>

This updates the AB8500 register map with defines for a few
new chip variants and adds version detection helpers to handle
the different variants.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
 include/linux/mfd/abx500/ab8500.h | 277 ++++++++++++++++++++++++++++++--------
 1 file changed, 222 insertions(+), 55 deletions(-)

diff --git a/include/linux/mfd/abx500/ab8500.h b/include/linux/mfd/abx500/ab8500.h
index 1cb5698..e640ea0 100644
--- a/include/linux/mfd/abx500/ab8500.h
+++ b/include/linux/mfd/abx500/ab8500.h
@@ -24,7 +24,7 @@ enum ab8500_version {
 	AB8500_VERSION_AB8500 = 0x0,
 	AB8500_VERSION_AB8505 = 0x1,
 	AB8500_VERSION_AB9540 = 0x2,
-	AB8500_VERSION_AB8540 = 0x3,
+	AB8500_VERSION_AB8540 = 0x4,
 	AB8500_VERSION_UNDEFINED,
 };
 
@@ -32,6 +32,7 @@ enum ab8500_version {
 #define AB8500_CUTEARLY	0x00
 #define AB8500_CUT1P0	0x10
 #define AB8500_CUT1P1	0x11
+#define AB8500_CUT1P2	0x12 /* Only valid for AB8540 */
 #define AB8500_CUT2P0	0x20
 #define AB8500_CUT3P0	0x30
 #define AB8500_CUT3P3	0x33
@@ -39,6 +40,7 @@ enum ab8500_version {
 /*
  * AB8500 bank addresses
  */
+#define AB8500_M_FSM_RANK	0x0
 #define AB8500_SYS_CTRL1_BLOCK	0x1
 #define AB8500_SYS_CTRL2_BLOCK	0x2
 #define AB8500_REGU_CTRL1	0x3
@@ -58,6 +60,7 @@ enum ab8500_version {
 #define AB8500_DEVELOPMENT	0x11
 #define AB8500_DEBUG		0x12
 #define AB8500_PROD_TEST	0x13
+#define AB8500_STE_TEST		0x14
 #define AB8500_OTP_EMUL		0x15
 
 /*
@@ -65,11 +68,11 @@ enum ab8500_version {
  * Values used to index into array ab8500_irq_regoffset[] defined in
  * drivers/mdf/ab8500-core.c
  */
-/* Definitions for AB8500 and AB9540 */
+/* Definitions for AB8500, AB9540 and AB8540 */
 /* ab8500_irq_regoffset[0] -> IT[Source|Latch|Mask]1 */
 #define AB8500_INT_MAIN_EXT_CH_NOT_OK	0 /* not 8505/9540 */
-#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540 */
-#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540 */
+#define AB8500_INT_UN_PLUG_TV_DET	1 /* not 8505/9540/8540 */
+#define AB8500_INT_PLUG_TV_DET		2 /* not 8505/9540/8540 */
 #define AB8500_INT_TEMP_WARM		3
 #define AB8500_INT_PON_KEY2DB_F		4
 #define AB8500_INT_PON_KEY2DB_R		5
@@ -77,18 +80,19 @@ enum ab8500_version {
 #define AB8500_INT_PON_KEY1DB_R		7
 /* ab8500_irq_regoffset[1] -> IT[Source|Latch|Mask]2 */
 #define AB8500_INT_BATT_OVV		8
-#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505 */
-#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505 */
+#define AB8500_INT_MAIN_CH_UNPLUG_DET	10 /* not 8505/8540 */
+#define AB8500_INT_MAIN_CH_PLUG_DET	11 /* not 8505/8540 */
 #define AB8500_INT_VBUS_DET_F		14
 #define AB8500_INT_VBUS_DET_R		15
 /* ab8500_irq_regoffset[2] -> IT[Source|Latch|Mask]3 */
 #define AB8500_INT_VBUS_CH_DROP_END	16
 #define AB8500_INT_RTC_60S		17
 #define AB8500_INT_RTC_ALARM		18
+#define AB8540_INT_BIF_INT		19
 #define AB8500_INT_BAT_CTRL_INDB	20
 #define AB8500_INT_CH_WD_EXP		21
 #define AB8500_INT_VBUS_OVV		22
-#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540 */
+#define AB8500_INT_MAIN_CH_DROP_END	23 /* not 8505/9540/8540 */
 /* ab8500_irq_regoffset[3] -> IT[Source|Latch|Mask]4 */
 #define AB8500_INT_CCN_CONV_ACC		24
 #define AB8500_INT_INT_AUD		25
@@ -99,7 +103,7 @@ enum ab8500_version {
 #define AB8500_INT_BUP_CHG_NOT_OK	30
 #define AB8500_INT_BUP_CHG_OK		31
 /* ab8500_irq_regoffset[4] -> IT[Source|Latch|Mask]5 */
-#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505 */
+#define AB8500_INT_GP_HW_ADC_CONV_END	32 /* not 8505/8540 */
 #define AB8500_INT_ACC_DETECT_1DB_F	33
 #define AB8500_INT_ACC_DETECT_1DB_R	34
 #define AB8500_INT_ACC_DETECT_22DB_F	35
@@ -108,23 +112,23 @@ enum ab8500_version {
 #define AB8500_INT_ACC_DETECT_21DB_R	38
 #define AB8500_INT_GP_SW_ADC_CONV_END	39
 /* ab8500_irq_regoffset[5] -> IT[Source|Latch|Mask]7 */
-#define AB8500_INT_GPIO6R		40 /* not 8505/9540 */
-#define AB8500_INT_GPIO7R		41 /* not 8505/9540 */
-#define AB8500_INT_GPIO8R		42 /* not 8505/9540 */
-#define AB8500_INT_GPIO9R		43 /* not 8505/9540 */
-#define AB8500_INT_GPIO10R		44
-#define AB8500_INT_GPIO11R		45
-#define AB8500_INT_GPIO12R		46 /* not 8505 */
-#define AB8500_INT_GPIO13R		47
+#define AB8500_INT_GPIO6R		40 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO7R		41 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO8R		42 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO9R		43 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO10R		44 /* not 8540 */
+#define AB8500_INT_GPIO11R		45 /* not 8540 */
+#define AB8500_INT_GPIO12R		46 /* not 8505/8540 */
+#define AB8500_INT_GPIO13R		47 /* not 8540 */
 /* ab8500_irq_regoffset[6] -> IT[Source|Latch|Mask]8 */
-#define AB8500_INT_GPIO24R		48 /* not 8505 */
-#define AB8500_INT_GPIO25R		49 /* not 8505 */
-#define AB8500_INT_GPIO36R		50 /* not 8505/9540 */
-#define AB8500_INT_GPIO37R		51 /* not 8505/9540 */
-#define AB8500_INT_GPIO38R		52 /* not 8505/9540 */
-#define AB8500_INT_GPIO39R		53 /* not 8505/9540 */
-#define AB8500_INT_GPIO40R		54
-#define AB8500_INT_GPIO41R		55
+#define AB8500_INT_GPIO24R		48 /* not 8505/8540 */
+#define AB8500_INT_GPIO25R		49 /* not 8505/8540 */
+#define AB8500_INT_GPIO36R		50 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO37R		51 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO38R		52 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO39R		53 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO40R		54 /* not 8540 */
+#define AB8500_INT_GPIO41R		55 /* not 8540 */
 /* ab8500_irq_regoffset[7] -> IT[Source|Latch|Mask]9 */
 #define AB8500_INT_GPIO6F		56 /* not 8505/9540 */
 #define AB8500_INT_GPIO7F		57 /* not 8505/9540 */
@@ -135,14 +139,14 @@ enum ab8500_version {
 #define AB8500_INT_GPIO12F		62 /* not 8505 */
 #define AB8500_INT_GPIO13F		63
 /* ab8500_irq_regoffset[8] -> IT[Source|Latch|Mask]10 */
-#define AB8500_INT_GPIO24F		64 /* not 8505 */
-#define AB8500_INT_GPIO25F		65 /* not 8505 */
-#define AB8500_INT_GPIO36F		66 /* not 8505/9540 */
-#define AB8500_INT_GPIO37F		67 /* not 8505/9540 */
-#define AB8500_INT_GPIO38F		68 /* not 8505/9540 */
-#define AB8500_INT_GPIO39F		69 /* not 8505/9540 */
-#define AB8500_INT_GPIO40F		70
-#define AB8500_INT_GPIO41F		71
+#define AB8500_INT_GPIO24F		64 /* not 8505/8540 */
+#define AB8500_INT_GPIO25F		65 /* not 8505/8540 */
+#define AB8500_INT_GPIO36F		66 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO37F		67 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO38F		68 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO39F		69 /* not 8505/9540/8540 */
+#define AB8500_INT_GPIO40F		70 /* not 8540 */
+#define AB8500_INT_GPIO41F		71 /* not 8540 */
 /* ab8500_irq_regoffset[9] -> IT[Source|Latch|Mask]12 */
 #define AB8500_INT_ADP_SOURCE_ERROR	72
 #define AB8500_INT_ADP_SINK_ERROR	73
@@ -160,42 +164,44 @@ enum ab8500_version {
 #define AB8500_INT_SRP_DETECT		88
 #define AB8500_INT_USB_CHARGER_NOT_OKR	89
 #define AB8500_INT_ID_WAKEUP_R		90
+#define AB8500_INT_ID_DET_PLUGR         91 /* 8505/9540 cut2.0 */
 #define AB8500_INT_ID_DET_R1R		92
 #define AB8500_INT_ID_DET_R2R		93
 #define AB8500_INT_ID_DET_R3R		94
 #define AB8500_INT_ID_DET_R4R		95
 /* ab8500_irq_regoffset[12] -> IT[Source|Latch|Mask]21 */
-#define AB8500_INT_ID_WAKEUP_F		96
-#define AB8500_INT_ID_DET_R1F		98
-#define AB8500_INT_ID_DET_R2F		99
-#define AB8500_INT_ID_DET_R3F		100
-#define AB8500_INT_ID_DET_R4F		101
-#define AB8500_INT_CHAUTORESTARTAFTSEC  102
+#define AB8500_INT_ID_WAKEUP_F		96 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_PLUGF		97 /* 8505/9540 cut2.0 */
+#define AB8500_INT_ID_DET_R1F		98 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R2F		99 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R3F		100 /* not 8505/9540 */
+#define AB8500_INT_ID_DET_R4F		101 /* not 8505/9540 */
+#define AB8500_INT_CHAUTORESTARTAFTSEC	102 /* not 8505/9540 */
 #define AB8500_INT_CHSTOPBYSEC		103
 /* ab8500_irq_regoffset[13] -> IT[Source|Latch|Mask]22 */
 #define AB8500_INT_USB_CH_TH_PROT_F	104
-#define AB8500_INT_USB_CH_TH_PROT_R    105
+#define AB8500_INT_USB_CH_TH_PROT_R	105
 #define AB8500_INT_MAIN_CH_TH_PROT_F	106 /* not 8505/9540 */
 #define AB8500_INT_MAIN_CH_TH_PROT_R	107 /* not 8505/9540 */
 #define AB8500_INT_CHCURLIMNOHSCHIRP	109
 #define AB8500_INT_CHCURLIMHSCHIRP	110
 #define AB8500_INT_XTAL32K_KO		111
 
-/* Definitions for AB9540 */
+/* Definitions for AB9540 / AB8505 */
 /* ab8500_irq_regoffset[14] -> IT[Source|Latch|Mask]13 */
-#define AB9540_INT_GPIO50R		113
-#define AB9540_INT_GPIO51R		114 /* not 8505 */
-#define AB9540_INT_GPIO52R		115
-#define AB9540_INT_GPIO53R		116
-#define AB9540_INT_GPIO54R		117 /* not 8505 */
+#define AB9540_INT_GPIO50R		113 /* not 8540 */
+#define AB9540_INT_GPIO51R		114 /* not 8505/8540 */
+#define AB9540_INT_GPIO52R		115 /* not 8540 */
+#define AB9540_INT_GPIO53R		116 /* not 8540 */
+#define AB9540_INT_GPIO54R		117 /* not 8505/8540 */
 #define AB9540_INT_IEXT_CH_RF_BFN_R	118
-#define AB9540_INT_IEXT_CH_RF_BFN_F	119
 /* ab8500_irq_regoffset[15] -> IT[Source|Latch|Mask]14 */
-#define AB9540_INT_GPIO50F		121
-#define AB9540_INT_GPIO51F		122 /* not 8505 */
-#define AB9540_INT_GPIO52F		123
-#define AB9540_INT_GPIO53F		124
-#define AB9540_INT_GPIO54F		125 /* not 8505 */
+#define AB9540_INT_GPIO50F		121 /* not 8540 */
+#define AB9540_INT_GPIO51F		122 /* not 8505/8540 */
+#define AB9540_INT_GPIO52F		123 /* not 8540 */
+#define AB9540_INT_GPIO53F		124 /* not 8540 */
+#define AB9540_INT_GPIO54F		125 /* not 8505/8540 */
+#define AB9540_INT_IEXT_CH_RF_BFN_F	126
 /* ab8500_irq_regoffset[16] -> IT[Source|Latch|Mask]25 */
 #define AB8505_INT_KEYSTUCK		128
 #define AB8505_INT_IKR			129
@@ -204,6 +210,87 @@ enum ab8500_version {
 #define AB8505_INT_KEYDEGLITCH		132
 #define AB8505_INT_MODPWRSTATUSF	134
 #define AB8505_INT_MODPWRSTATUSR	135
+/* ab8500_irq_regoffset[17] -> IT[Source|Latch|Mask]6 */
+#define AB8500_INT_HOOK_DET_NEG_F	138
+#define AB8500_INT_HOOK_DET_NEG_R	139
+#define AB8500_INT_HOOK_DET_POS_F	140
+#define AB8500_INT_HOOK_DET_POS_R	141
+#define AB8500_INT_PLUG_DET_COMP_F	142
+#define AB8500_INT_PLUG_DET_COMP_R	143
+/* ab8500_irq_regoffset[18] -> IT[Source|Latch|Mask]23 */
+#define AB8505_INT_COLL			144
+#define AB8505_INT_RESERR		145
+#define AB8505_INT_FRAERR		146
+#define AB8505_INT_COMERR		147
+#define AB8505_INT_SPDSET		148
+#define AB8505_INT_DSENT		149
+#define AB8505_INT_DREC			150
+#define AB8505_INT_ACC_INT		151
+/* ab8500_irq_regoffset[19] -> IT[Source|Latch|Mask]24 */
+#define AB8505_INT_NOPINT		152
+/* ab8540_irq_regoffset[20] -> IT[Source|Latch|Mask]26 */
+#define AB8540_INT_IDPLUGDETCOMPF	160
+#define AB8540_INT_IDPLUGDETCOMPR	161
+#define AB8540_INT_FMDETCOMPLOF		162
+#define AB8540_INT_FMDETCOMPLOR		163
+#define AB8540_INT_FMDETCOMPHIF		164
+#define AB8540_INT_FMDETCOMPHIR		165
+#define AB8540_INT_ID5VDETCOMPF		166
+#define AB8540_INT_ID5VDETCOMPR		167
+/* ab8540_irq_regoffset[21] -> IT[Source|Latch|Mask]27 */
+#define AB8540_INT_GPIO43F		168
+#define AB8540_INT_GPIO43R		169
+#define AB8540_INT_GPIO44F		170
+#define AB8540_INT_GPIO44R		171
+#define AB8540_INT_KEYPOSDETCOMPF	172
+#define AB8540_INT_KEYPOSDETCOMPR	173
+#define AB8540_INT_KEYNEGDETCOMPF	174
+#define AB8540_INT_KEYNEGDETCOMPR	175
+/* ab8540_irq_regoffset[22] -> IT[Source|Latch|Mask]28 */
+#define AB8540_INT_GPIO1VBATF		176
+#define AB8540_INT_GPIO1VBATR		177
+#define AB8540_INT_GPIO2VBATF		178
+#define AB8540_INT_GPIO2VBATR		179
+#define AB8540_INT_GPIO3VBATF		180
+#define AB8540_INT_GPIO3VBATR		181
+#define AB8540_INT_GPIO4VBATF		182
+#define AB8540_INT_GPIO4VBATR		183
+/* ab8540_irq_regoffset[23] -> IT[Source|Latch|Mask]29 */
+#define AB8540_INT_SYSCLKREQ2F		184
+#define AB8540_INT_SYSCLKREQ2R		185
+#define AB8540_INT_SYSCLKREQ3F		186
+#define AB8540_INT_SYSCLKREQ3R		187
+#define AB8540_INT_SYSCLKREQ4F		188
+#define AB8540_INT_SYSCLKREQ4R		189
+#define AB8540_INT_SYSCLKREQ5F		190
+#define AB8540_INT_SYSCLKREQ5R		191
+/* ab8540_irq_regoffset[24] -> IT[Source|Latch|Mask]30 */
+#define AB8540_INT_PWMOUT1F		192
+#define AB8540_INT_PWMOUT1R		193
+#define AB8540_INT_PWMCTRL0F		194
+#define AB8540_INT_PWMCTRL0R		195
+#define AB8540_INT_PWMCTRL1F		196
+#define AB8540_INT_PWMCTRL1R		197
+#define AB8540_INT_SYSCLKREQ6F		198
+#define AB8540_INT_SYSCLKREQ6R		199
+/* ab8540_irq_regoffset[25] -> IT[Source|Latch|Mask]31 */
+#define AB8540_INT_PWMEXTVIBRA1F	200
+#define AB8540_INT_PWMEXTVIBRA1R	201
+#define AB8540_INT_PWMEXTVIBRA2F	202
+#define AB8540_INT_PWMEXTVIBRA2R	203
+#define AB8540_INT_PWMOUT2F		204
+#define AB8540_INT_PWMOUT2R		205
+#define AB8540_INT_PWMOUT3F		206
+#define AB8540_INT_PWMOUT3R		207
+/* ab8540_irq_regoffset[26] -> IT[Source|Latch|Mask]32 */
+#define AB8540_INT_ADDATA2F		208
+#define AB8540_INT_ADDATA2R		209
+#define AB8540_INT_DADATA2F		210
+#define AB8540_INT_DADATA2R		211
+#define AB8540_INT_FSYNC2F		212
+#define AB8540_INT_FSYNC2R		213
+#define AB8540_INT_BITCLK2F		214
+#define AB8540_INT_BITCLK2R		215
 
 /*
  * AB8500_AB9540_NR_IRQS is used when configuring the IRQ numbers for the
@@ -213,13 +300,24 @@ enum ab8500_version {
  * which is larger.
  */
 #define AB8500_NR_IRQS			112
-#define AB8505_NR_IRQS			136
-#define AB9540_NR_IRQS			136
+#define AB8505_NR_IRQS			153
+#define AB9540_NR_IRQS			153
+#define AB8540_NR_IRQS			216
 /* This is set to the roof of any AB8500 chip variant IRQ counts */
-#define AB8500_MAX_NR_IRQS		AB9540_NR_IRQS
+#define AB8500_MAX_NR_IRQS		AB8540_NR_IRQS
 
 #define AB8500_NUM_IRQ_REGS		14
-#define AB9540_NUM_IRQ_REGS		17
+#define AB9540_NUM_IRQ_REGS		20
+#define AB8540_NUM_IRQ_REGS		27
+
+/* Turn On Status Event */
+#define AB8500_POR_ON_VBAT		0x01
+#define AB8500_POW_KEY_1_ON		0x02
+#define AB8500_POW_KEY_2_ON		0x04
+#define AB8500_RTC_ALARM		0x08
+#define AB8500_MAIN_CH_DET		0x10
+#define AB8500_VBUS_DET			0x20
+#define AB8500_USB_ID_DET		0x40
 
 /**
  * struct ab8500 - ab8500 internal structure
@@ -335,10 +433,79 @@ static inline int is_ab8500_2p0_or_earlier(struct ab8500 *ab)
 	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT2P0));
 }
 
+static inline int is_ab8500_3p3_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8500(ab) && (ab->chip_id <= AB8500_CUT3P3));
+}
+
 /* exclude also ab8505, ab9540... */
 static inline int is_ab8500_2p0(struct ab8500 *ab)
 {
 	return (is_ab8500(ab) && (ab->chip_id == AB8500_CUT2P0));
 }
 
+static inline int is_ab8505_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+static inline int is_ab8505_2p0(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+static inline int is_ab9540_1p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab9540(ab) && (ab->chip_id <= AB8500_CUT1P0));
+}
+
+static inline int is_ab9540_2p0(struct ab8500 *ab)
+{
+	return (is_ab9540(ab) && (ab->chip_id == AB8500_CUT2P0));
+}
+
+/*
+ * Be careful, the marketing name for this chip is 2.1
+ * but the value read from the chip is 3.0 (0x30)
+ */
+static inline int is_ab9540_3p0(struct ab8500 *ab)
+{
+	return (is_ab9540(ab) && (ab->chip_id == AB8500_CUT3P0));
+}
+
+static inline int is_ab8540_1p0_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P0);
+}
+
+static inline int is_ab8540_1p1_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P1);
+}
+
+static inline int is_ab8540_1p2_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT1P2);
+}
+
+static inline int is_ab8540_2p0_or_earlier(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id <= AB8500_CUT2P0);
+}
+
+static inline int is_ab8540_2p0(struct ab8500 *ab)
+{
+	return is_ab8540(ab) && (ab->chip_id == AB8500_CUT2P0);
+}
+
+static inline int is_ab8505_2p0_earlier(struct ab8500 *ab)
+{
+	return (is_ab8505(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
+static inline int is_ab9540_2p0_or_earlier(struct ab8500 *ab)
+{
+	return (is_ab9540(ab) && (ab->chip_id < AB8500_CUT2P0));
+}
+
 #endif /* MFD_AB8500_H */
-- 
1.7.11.3

^ permalink raw reply related

* [PATCH v5 6/9] ARM: davinci: Remoteproc driver support for OMAP-L138 DSP
From: Sekhar Nori @ 2013-01-15  9:15 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <13514BD7FAEBA745BBD7D8A672905C14311FE538@DFLE08.ent.ti.com>

On 1/12/2013 7:56 AM, Tivy, Robert wrote:

>> From: Ohad Ben-Cohen [mailto:ohad at wizery.com]
>> Sent: Friday, January 11, 2013 4:26 AM

>> On Fri, Jan 11, 2013 at 2:23 AM, Robert Tivy <rtivy@ti.com> wrote:
>>> +static int davinci_rproc_probe(struct platform_device *pdev)
>>> +{
>>> +       struct da8xx_rproc_pdata *pdata = pdev->dev.platform_data;
>>> +       struct davinci_rproc *drproc;
>>> +       struct rproc *rproc;
>>> +       struct clk *dsp_clk;
>>> +       int ret;
>>> +
>>> +       if (!fw_name) {
>>> +               dev_err(&pdev->dev, "No firmware file specified\n");
>>> +
>>> +               return -EINVAL;
>>> +       }

>> There are a few issues with this fw_name module param:
>>
>> 1. Usually we don't rely on users providing the firmware file name for
>> drivers to work. Drivers should know the name beforehand, and if there
>> may be several different instances of firmwares (for different cores
>> you may have), then it's just better to get it from the platform data.
> 
> Is this suggesting that there be separate platform device instances for each different potential fw, and that each platform device instance hardcodes the fw filename?

I am not convinced firmware name should be in platform data (or DT)
since it is not hardware specific. User can choose multiple different
firmwares to load on the DSP depending the application he is running all
for the same platform (da850 evm).

> 
>>
>> 2. You may still want to have such a module param in order to be able
>> to override the default firmware name (for debugging purposes?), but
>> I'm not sure it should be davinci-specific. if we do want it to be
>> then please prefix the name with 'davinci'.
> 
> Sekhar asked that there not be a default fw name, so there's conflicting feedback on this point.  I prefer to have a default name plus the module parameter override (but don't have much opinion on whether it should be davinci-specific (and passed with davinci_remoteproc.ko) or general (and passed with remoteproc.ko), please advise).

Rob, I don't remember objecting to a default firmware name if module
parameter is not passed. On 29th November 2012 you wrote:

"
Sounds OK.  I propose then to have the above be the default firmware
name, along with a module parameter that will override if specified.
"

and I wrote back:

"
Sounds good.
"

As you can see, there was no objection from me.

> 
> Since the fw file (i.e., DSP program) is typically paired with a particular Linux app, I like the ability to specify the fw filename at runtime, depending on the Linux app I need to run.

Right, and platform data is not the way to achieve this.

Thanks,
Sekhar

^ permalink raw reply

* [PATCH 04/18] power: ab8500_fg: Replace msleep() with usleep_range() for greater accuracy
From: Linus Walleij @ 2013-01-15  8:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130115084821.GT12385@gmail.com>

On Tue, Jan 15, 2013 at 9:48 AM, Lee Jones <lee.jones@linaro.org> wrote:
> On Mon, 14 Jan 2013, Joe Perches wrote:

>> > -           msleep(5);
>> > +           usleep_range(5000, 5001);
>>
>> If you're going to give a range that small
>> you might as well use usleep instead.
>>
>> Otherwise, add some tolerance to allow any
>> other coalesced wakeup to occur.
>
> I can't increase the tolerance, as I don't know how that would
> effect the running of the system, and the person who would know
> is off on parental leave.
>
> What I can tell you is we're only using usleep_range() because
> there is no usleep in the kernel. At least that's what we've
> been led to believe:
>
> Documentation/timers/timers-howto.txt:
>
>                 - Why is there no "usleep" / What is a good range?
>                         Since usleep_range is built on top of hrtimers, the
>                         wakeup will be very precise (ish), thus a simple
>                         usleep function would likely introduce a large number
>                         of undesired interrupts.

And I think the above is why we have this in the kernel:
arch/arm/mach-davinci/board-da850-evm.c:
usleep_range(1000, 1000);
arch/arm/mach-tegra/pcie.c:             usleep_range(1000, 1000);
drivers/clk/clk-wm831x.c:       usleep_range(2000, 2000);
drivers/media/i2c/m5mols/m5mols_core.c: usleep_range(200, 200);
drivers/media/i2c/s5k6aa.c:     usleep_range(4000, 4000);
drivers/media/i2c/smiapp/smiapp-core.c: usleep_range(1000, 1000);
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c:
usleep_range(1000, 1000);

There are quite a few of these.

Let's ping John Stultz for some clarification ...

Yours,
Linus Walleij

^ permalink raw reply

* OMAP baseline test results for v3.8-rc3
From: Felipe Balbi @ 2013-01-15  8:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130115073225.GB14505@arwen.pp.htv.fi>

Hi,

(quick parens here)

I think n900's problems will go away if you add omap_i2c_wait_for_ardy()
from my patchset.

On Tue, Jan 15, 2013 at 09:32:25AM +0200, Felipe Balbi wrote:
> > [    4.281280] twl 1-0048: PIH (irq 23) chaining IRQs 338..346
> > [    4.281433] twl 1-0048: power (irq 343) chaining IRQs 346..353
> > [    4.281616] i2c i2c-1: master_xfer[0] W, addr=0x49, len=1
> > [    4.281677] i2c i2c-1: master_xfer[1] R, addr=0x49, len=1
> > [    4.281707] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x0, stop: 0
> > [    4.281799] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
> > [    4.281829] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x1, stop: 1
> > [    4.281921] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
> > [    4.296905] i2c i2c-1: master_xfer[0] W, addr=0x49, len=2
> > [    4.296936] omap_i2c omap_i2c.1: addr: 0x0049, len: 2, flags: 0x0, stop: 1
> > [    4.296997] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
> > [    4.313476] twl4030_gpio twl4030_gpio: gpio (irq 338) chaining IRQs 354..371
> > 
> > This log excerpt has only 3 transfers, but the time duration is already
> > 10x longer compared to vanilla 3.8-rc3.
> 
> weird, there's nothing extremely expensive added by my patchset, I'll go
> over them and try to figure out what's going on.
> 
> Thanks for notifying me about it.

Here's from v3.8-rc3 vanilla (just added two small prints):

[    1.688079] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
[    1.688110] omap_i2c omap_i2c.1: starting transfer
[    1.688140] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.688201] omap_i2c omap_i2c.1: IRQ (ISR = 0x0004)
[    1.688232] omap_i2c omap_i2c.1: finishing transfer
[    1.688232] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x1, stop: 1
[    1.688262] omap_i2c omap_i2c.1: starting transfer
[    1.688354] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
[    1.688354] omap_i2c omap_i2c.1: IRQ (ISR = 0x0004)
[    1.688385] omap_i2c omap_i2c.1: finishing transfer
[    1.688415] i2c i2c-1: master_xfer[0] W, addr=0x48, len=2
[    1.688446] omap_i2c omap_i2c.1: addr: 0x0048, len: 2, flags: 0x0, stop: 1
[    1.688446] omap_i2c omap_i2c.1: starting transfer
[    1.688476] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.688568] omap_i2c omap_i2c.1: IRQ (ISR = 0x0004)
[    1.688598] omap_i2c omap_i2c.1: finishing transfer
[    1.688629] i2c i2c-1: master_xfer[0] W, addr=0x48, len=1
[    1.688659] i2c i2c-1: master_xfer[1] R, addr=0x48, len=6
[    1.688659] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
[    1.688690] omap_i2c omap_i2c.1: starting transfer
[    1.688720] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.688781] omap_i2c omap_i2c.1: IRQ (ISR = 0x0004)
[    1.688812] omap_i2c omap_i2c.1: finishing transfer
[    1.688812] omap_i2c omap_i2c.1: addr: 0x0048, len: 6, flags: 0x1, stop: 1

and here's from my patchset:

[    1.993865] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x0, stop: 0
[    1.993896] omap_i2c omap_i2c.1: starting transfer
[    1.993927] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.993957] omap_i2c omap_i2c.1: finished transfer
[    1.993988] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x1, stop: 1
[    1.993988] omap_i2c omap_i2c.1: starting transfer
[    1.994079] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
[    1.994110] omap_i2c omap_i2c.1: finished transfer
[    2.009490] i2c i2c-1: master_xfer[0] W, addr=0x49, len=2
[    2.009490] omap_i2c omap_i2c.1: addr: 0x0049, len: 2, flags: 0x0, stop: 1
[    2.009521] omap_i2c omap_i2c.1: starting transfer
[    2.009552] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    2.009582] omap_i2c omap_i2c.1: finished transfer
[    2.025054] i2c i2c-1: master_xfer[0] W, addr=0x49, len=1
[    2.025054] i2c i2c-1: master_xfer[1] R, addr=0x49, len=1
[    2.025085] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x0, stop: 0
[    2.025085] omap_i2c omap_i2c.1: starting transfer
[    2.025146] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    2.025177] omap_i2c omap_i2c.1: finished transfer
[    2.025177] omap_i2c omap_i2c.1: addr: 0x0049, len: 1, flags: 0x1, stop: 1
[    2.025207] omap_i2c omap_i2c.1: starting transfer
[    2.025268] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
[    2.025329] omap_i2c omap_i2c.1: finished transfer
[    2.040679] i2c i2c-1: master_xfer[0] W, addr=0x49, len=2
[    2.040710] omap_i2c omap_i2c.1: addr: 0x0049, len: 2, flags: 0x0, stop: 1
[    2.040710] omap_i2c omap_i2c.1: starting transfer
[    2.040771] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    2.040802] omap_i2c omap_i2c.1: finished transfer

Looks like the transfer itself is faster with my patchset. I don't have
an idea of what's causing extra delay, for whatever reason client driver
seems to take longer to start more i2c transfers. I've added extra
prints to see what's going on:


| [    1.818725] omap_i2c omap_i2c.1: pm_runtime_get_sync()
| [    1.818725] omap_i2c omap_i2c.1: omap_i2c_wait_for_bb()
| [    1.818725] omap_i2c omap_i2c.1: omap_i2c_xfer_msg()
| [    1.818756] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
| [    1.818756] omap_i2c omap_i2c.1: starting transfer
| [    1.818786] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
| [    1.818847] omap_i2c omap_i2c.1: finished transfer
| [    1.818847] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x1, stop: 1
| [    1.818847] omap_i2c omap_i2c.1: starting transfer
| [    1.818939] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
| [    1.818969] omap_i2c omap_i2c.1: finished transfer
| [    1.819000] omap_i2c omap_i2c.1: waiting for ARDY
| [    1.819000] omap_i2c omap_i2c.1: ARDY
| [    1.819000] omap_i2c omap_i2c.1: 2. omap_i2c_wait_for_bb()
| [    1.819030] omap_i2c omap_i2c.1: pm_runtime_mark_last_busy()
| [    1.819030] omap_i2c omap_i2c.1: return
| [    1.819061] i2c i2c-1: master_xfer[0] W, addr=0x48, len=1
| [    1.819061] i2c i2c-1: master_xfer[1] R, addr=0x48, len=1
| [    1.819091] omap_i2c omap_i2c.1: pm_runtime_get_sync()
| [    1.819091] omap_i2c omap_i2c.1: omap_i2c_wait_for_bb()
| [    1.819122] omap_i2c omap_i2c.1: omap_i2c_xfer_msg()
| [    1.819122] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
| [    1.819122] omap_i2c omap_i2c.1: starting transfer
| [    1.819183] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
| [    1.819213] omap_i2c omap_i2c.1: finished transfer
| [    1.819213] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x1, stop: 1
| [    1.819244] omap_i2c omap_i2c.1: starting transfer
| [    1.819305] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
| [    1.819366] omap_i2c omap_i2c.1: finished transfer
| [    1.819366] omap_i2c omap_i2c.1: waiting for ARDY
| [    1.819366] omap_i2c omap_i2c.1: ARDY
| [    1.819396] omap_i2c omap_i2c.1: 2. omap_i2c_wait_for_bb()
| [    1.819396] omap_i2c omap_i2c.1: pm_runtime_mark_last_busy()
| [    1.819396] omap_i2c omap_i2c.1: return
| [    1.819427] i2c i2c-1: master_xfer[0] W, addr=0x48, len=1
| [    1.819458] i2c i2c-1: master_xfer[1] R, addr=0x48, len=1
| [    1.819458] omap_i2c omap_i2c.1: pm_runtime_get_sync()
| [    1.819458] omap_i2c omap_i2c.1: omap_i2c_wait_for_bb()
| [    1.819488] omap_i2c omap_i2c.1: omap_i2c_xfer_msg()
| [    1.819488] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
| [    1.819519] omap_i2c omap_i2c.1: starting transfer
| [    1.819549] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
| [    1.819580] omap_i2c omap_i2c.1: finished transfer
| [    1.819580] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x1, stop: 1
| [    1.819610] omap_i2c omap_i2c.1: starting transfer
| [    1.819671] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
| [    1.819732] omap_i2c omap_i2c.1: finished transfer
| [    1.819732] omap_i2c omap_i2c.1: waiting for ARDY
| [    1.819732] omap_i2c omap_i2c.1: ARDY
| [    1.819763] omap_i2c omap_i2c.1: 2. omap_i2c_wait_for_bb()
| [    1.819763] omap_i2c omap_i2c.1: pm_runtime_mark_last_busy()
| [    1.819793] omap_i2c omap_i2c.1: return

as you can see, from pm_runtime_get_sync() to return, the time spent is
about the same in all cases (around 305us).

one thing I note, however, is that after we start waiting for ARDY,
there's no point in "omap_i2c_wait_for_bb()" since I only exit
omap_i2c_xfer_msg() after all bytes have been unloaded on SDA line.

Removing that saves some extra time (about 30us):

[    1.751983] omap_i2c omap_i2c.1: pm_runtime_get_sync()
[    1.751983] omap_i2c omap_i2c.1: omap_i2c_xfer_msg()
[    1.751983] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x0, stop: 0
[    1.752014] omap_i2c omap_i2c.1: starting transfer
[    1.752044] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.752075] omap_i2c omap_i2c.1: finished transfer
[    1.752105] omap_i2c omap_i2c.1: addr: 0x0048, len: 1, flags: 0x1, stop: 1
[    1.752105] omap_i2c omap_i2c.1: starting transfer
[    1.752197] omap_i2c omap_i2c.1: IRQ (ISR = 0x0008)
[    1.752227] omap_i2c omap_i2c.1: finished transfer
[    1.752227] omap_i2c omap_i2c.1: waiting for ARDY
[    1.752258] omap_i2c omap_i2c.1: ARDY
[    1.752258] omap_i2c omap_i2c.1: pm_runtime_mark_last_busy()
[    1.752258] omap_i2c omap_i2c.1: return
[    1.752288] i2c i2c-1: master_xfer[0] W, addr=0x48, len=2
[    1.752319] omap_i2c omap_i2c.1: pm_runtime_get_sync()
[    1.752319] omap_i2c omap_i2c.1: omap_i2c_xfer_msg()
[    1.752349] omap_i2c omap_i2c.1: addr: 0x0048, len: 2, flags: 0x0, stop: 1
[    1.752349] omap_i2c omap_i2c.1: starting transfer
[    1.752380] omap_i2c omap_i2c.1: IRQ (ISR = 0x0010)
[    1.752410] omap_i2c omap_i2c.1: finished transfer
[    1.752441] omap_i2c omap_i2c.1: waiting for ARDY
[    1.752441] omap_i2c omap_i2c.1: ARDY
[    1.752471] omap_i2c omap_i2c.1: pm_runtime_mark_last_busy()
[    1.752471] omap_i2c omap_i2c.1: return

For whatever reason, in some cases client driver takes longer to
initiate a transfer and I don't think there's anything we can do about
that during boot up.

Anyway, whenever I can see a big delay, it's always from "return" to the
next "i2c i2c-1: master_xfer[0] W, addr=0x48, len=1" message.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130115/ed31a283/attachment.sig>

^ permalink raw reply

* rtc: vt8500: Fix year field in vt8500_rtc_set_time
From: Alessandro Zummo @ 2013-01-15  8:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358234563.6868.13.camel@gitbox>

On Tue, 15 Jan 2013 20:22:43 +1300
Tony Prisk <linux@prisktech.co.nz> wrote:

> Alessandro,
> 
> This patch was sent out at the same time as two other RTC fixes for
> vt8500 but this one seems to have stopped somewhere along the way while
> the other two have been accepted.

 Hi, Andrew usually picks up the patches directly from the rtc mailing list,
 unless there's an arch specific tree to carry it. 

 This one seems fine so I'm sure it's just an overlook

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Torino, Italy

  http://www.towertech.it

^ permalink raw reply

* [GIT PULL] ste_dma40 updates for 3.9
From: Fabio Baltieri @ 2013-01-15  8:55 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMg6FqsaqZiGeK14n4==dF-y=iMYSGRDBYSwkGWO0J69Yg@mail.gmail.com>

Hello Olof,

On Mon, Jan 14, 2013 at 10:48:15PM -0800, Olof Johansson wrote:
> > This contains a series of updates and fixes for the ste_dma40 driver.
> >
> > The driver is specific for the ux500, and the patches were acked by both Linus
> > Walleij, and Vinod Koul (dmaengine), who agreed to push this through arm-soc.
> >
> > Can you please pull those in for -next?
> 
> While I don't mind taking this through arm-soc, I don't see a strong
> reason to do so?
> 
> This series of patches only modify the ste_dma40 driver, there are no
> corresponding changes under arch/arm that need to be coordinated or
> considered w.r.t. merge conflicts. I.e. they all seem nicely isolated
> to only the driver.
> 
> So is there a specific reason for why these shouldn't just go in
> through the dmaengine tree?

The idea was to have this in the same tree as other ux500 specific
driver patches to easy up testing a bit, but now that you point it out
I see that current arm-soc tree is pretty clear of driver patches (mmci
was what I had in mind) and those should end up to other trees anyway,
so you're probably right and these should go in dmaengine tree.

Vinod, would you please consider pulling these into dmaengine's next
tree?

Thanks,
Fabio

-- 
Fabio Baltieri

^ permalink raw reply

* [GIT PULL] ste_dma40 updates for 3.9
From: Linus Walleij @ 2013-01-15  8:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOesGMg6FqsaqZiGeK14n4==dF-y=iMYSGRDBYSwkGWO0J69Yg@mail.gmail.com>

On Tue, Jan 15, 2013 at 7:48 AM, Olof Johansson <olof@lixom.net> wrote:

> This series of patches only modify the ste_dma40 driver, there are no
> corresponding changes under arch/arm that need to be coordinated or
> considered w.r.t. merge conflicts. I.e. they all seem nicely isolated
> to only the driver.
>
> So is there a specific reason for why these shouldn't just go in
> through the dmaengine tree?

One reason would be if there are DMA bindings to device tree coming
this merge window, as I'm told, and it implicates a lot of platform code
changes on top of this as we adopt to it.

But maybe this will be wholly confined to the DMAengine tree?

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH 04/18] power: ab8500_fg: Replace msleep() with usleep_range() for greater accuracy
From: Lee Jones @ 2013-01-15  8:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358183857.19400.13.camel@joe-AO722>

On Mon, 14 Jan 2013, Joe Perches wrote:

> On Fri, 2013-01-11 at 13:12 +0000, Lee Jones wrote:
> > Doing so provides a greater degree of accuracy when dealing with
> > time-frames between 1us and 20ms. msleep() is only accurate for
> > wake-ups greater than 20ms.
> []
> > diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
> []
> > @@ -956,7 +956,7 @@ static int ab8500_fg_load_comp_volt_to_capacity(struct ab8500_fg *di)
> >  	do {
> >  		vbat += ab8500_fg_bat_voltage(di);
> >  		i++;
> > -		msleep(5);
> > +		usleep_range(5000, 5001);
> 
> If you're going to give a range that small
> you might as well use usleep instead.
> 
> Otherwise, add some tolerance to allow any
> other coalesced wakeup to occur.

I can't increase the tolerance, as I don't know how that would
effect the running of the system, and the person who would know
is off on parental leave.

What I can tell you is we're only using usleep_range() because
there is no usleep in the kernel. At least that's what we've
been led to believe:

Documentation/timers/timers-howto.txt:

                - Why is there no "usleep" / What is a good range?
                        Since usleep_range is built on top of hrtimers, the
                        wakeup will be very precise (ish), thus a simple
                        usleep function would likely introduce a large number
                        of undesired interrupts.

-- 
Lee Jones
Linaro ST-Ericsson Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* [RFC PATCH 7/7] ARM: dts: omap: Add omap control usb data
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Add omap control usb data in omap4 device tree file. This will have the
register address of registers to power on the PHY and to write to
mailbox.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/boot/dts/omap4.dtsi |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index b7e2ba3..5d770be 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -545,5 +545,13 @@
 			ram_bits = <12>;
 			ti,has_mailbox;
 		};
+
+		omap_control_usb at 4a002300 {
+			compatible = "ti,omap-control-usb";
+			reg = <0x4a002300 0x4>,
+			      <0x4a00233c 0x4>;
+			reg-names = "control_dev_conf", "otghs_control";
+			ti,has_mailbox;
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 6/7] ARM: dts: omap: Add omap-usb2 dt data
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Add omap-usb2 data node in omap4 device tree file. Since omap-usb2 is
connected to ocp2scp, omap-usb2 dt data is added as a child node
of ocp2scp.

Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/boot/dts/omap4.dtsi |    4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 7bbf1fb..b7e2ba3 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -438,6 +438,10 @@
 			#size-cells = <1>;
 			ranges;
 			ti,hwmods = "ocp2scp_usb_phy";
+			usb2phy at 4a0ad080 {
+				compatible = "ti,omap-usb2";
+				reg = <0x4a0ad080 0x58>;
+			};
 		};
 
 		timer1: timer at 4a318000 {
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 5/7] ARM: dts: omap: Add usb_otg and glue data
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Add usb otg data node in omap4/omap3 device tree file. Also update
the node with board specific setting in omapx-<board>.dts file.
The dt data specifies among others the interface type (ULPI or UTMI), mode
which is mostly OTG, power that specifies the amount of power this can supply
when in host mode.

Acked-by: Felipe Balbi <balbi@ti.com>
Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/boot/dts/omap3-beagle-xm.dts |    6 ++++++
 arch/arm/boot/dts/omap3-evm.dts       |    6 ++++++
 arch/arm/boot/dts/omap3-overo.dtsi    |    6 ++++++
 arch/arm/boot/dts/omap3.dtsi          |   11 +++++++++++
 arch/arm/boot/dts/omap4-panda.dts     |    6 ++++++
 arch/arm/boot/dts/omap4-sdp.dts       |    6 ++++++
 arch/arm/boot/dts/omap4.dtsi          |   12 ++++++++++++
 7 files changed, 53 insertions(+)

diff --git a/arch/arm/boot/dts/omap3-beagle-xm.dts b/arch/arm/boot/dts/omap3-beagle-xm.dts
index 3705a81..cb07583 100644
--- a/arch/arm/boot/dts/omap3-beagle-xm.dts
+++ b/arch/arm/boot/dts/omap3-beagle-xm.dts
@@ -107,3 +107,9 @@
 	 */
 	ti,pulldowns = <0x03a1c4>;
 };
+
+&usb_otg_hs {
+	interface_type = <0>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/arch/arm/boot/dts/omap3-evm.dts b/arch/arm/boot/dts/omap3-evm.dts
index e8ba1c2..afb9ba9 100644
--- a/arch/arm/boot/dts/omap3-evm.dts
+++ b/arch/arm/boot/dts/omap3-evm.dts
@@ -59,3 +59,9 @@
 &twl_gpio {
 	ti,use-leds;
 };
+
+&usb_otg_hs {
+	interface_type = <0>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/arch/arm/boot/dts/omap3-overo.dtsi b/arch/arm/boot/dts/omap3-overo.dtsi
index 89808ce..4b3d157 100644
--- a/arch/arm/boot/dts/omap3-overo.dtsi
+++ b/arch/arm/boot/dts/omap3-overo.dtsi
@@ -55,3 +55,9 @@
 &twl_gpio {
 	ti,use-leds;
 };
+
+&usb_otg_hs {
+	interface_type = <0>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index 1acc261..8d03736 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -397,5 +397,16 @@
 			ti,timer-alwon;
 			ti,timer-secure;
 		};
+
+		usb_otg_hs: usb_otg_hs at 480ab000 {
+			compatible = "ti,omap3-musb";
+			reg = <0x480ab000 0x1000>;
+			interrupts = <0 92 0x4>, <0 93 0x4>;
+			interrupt-names = "mc", "dma";
+			ti,hwmods = "usb_otg_hs";
+			multipoint = <1>;
+			num_eps = <16>;
+			ram_bits = <12>;
+		};
 	};
 };
diff --git a/arch/arm/boot/dts/omap4-panda.dts b/arch/arm/boot/dts/omap4-panda.dts
index 4122efe..612c9bb 100644
--- a/arch/arm/boot/dts/omap4-panda.dts
+++ b/arch/arm/boot/dts/omap4-panda.dts
@@ -206,3 +206,9 @@
 &twl_usb_comparator {
 	usb-supply = <&vusb>;
 };
+
+&usb_otg_hs {
+	interface_type = <1>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/arch/arm/boot/dts/omap4-sdp.dts b/arch/arm/boot/dts/omap4-sdp.dts
index 43e5258..582d7ee 100644
--- a/arch/arm/boot/dts/omap4-sdp.dts
+++ b/arch/arm/boot/dts/omap4-sdp.dts
@@ -428,3 +428,9 @@
 &twl_usb_comparator {
 	usb-supply = <&vusb>;
 };
+
+&usb_otg_hs {
+	interface_type = <1>;
+	mode = <3>;
+	power = <50>;
+};
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 739bb79..7bbf1fb 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -529,5 +529,17 @@
 			ti,hwmods = "timer11";
 			ti,timer-pwm;
 		};
+
+		usb_otg_hs: usb_otg_hs at 4a0ab000 {
+			compatible = "ti,omap4-musb";
+			reg = <0x4a0ab000 0x7ff>;
+			interrupts = <0 92 0x4>, <0 93 0x4>;
+			interrupt-names = "mc", "dma";
+			ti,hwmods = "usb_otg_hs";
+			multipoint = <1>;
+			num_eps = <16>;
+			ram_bits = <12>;
+			ti,has_mailbox;
+		};
 	};
 };
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 4/7] drivers: usb: start using the control module driver
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Start using the control module driver for powering on the PHY and for
writing to the mailbox instead of writing to the control module
registers on their own.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/usb/omap-usb.txt |    4 ++
 Documentation/devicetree/bindings/usb/usb-phy.txt  |    7 +--
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |   13 ----
 drivers/usb/musb/Kconfig                           |    1 +
 drivers/usb/musb/omap2430.c                        |   64 ++++++++------------
 drivers/usb/musb/omap2430.h                        |    9 ---
 drivers/usb/phy/Kconfig                            |    1 +
 drivers/usb/phy/omap-usb2.c                        |   38 +++---------
 include/linux/usb/omap_usb.h                       |    4 +-
 9 files changed, 42 insertions(+), 99 deletions(-)

diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index d58dae3..3f0152b 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -3,6 +3,9 @@ OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS
 OMAP MUSB GLUE
  - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
  - ti,hwmods : must be "usb_otg_hs"
+ - ti,has_mailbox : to specify that omap uses an external mailbox
+   (in control module) to communicate with the musb core during device connect
+   and disconnect.
  - multipoint : Should be "1" indicating the musb controller supports
    multipoint. This is a MUSB configuration-specific setting.
  - num_eps : Specifies the number of endpoints. This is also a
@@ -20,6 +23,7 @@ SOC specific device node entry
 usb_otg_hs: usb_otg_hs at 4a0ab000 {
 	compatible = "ti,omap4-musb";
 	ti,hwmods = "usb_otg_hs";
+	ti,has_mailbox;
 	multipoint = <1>;
 	num_eps = <16>;
 	ram_bits = <12>;
diff --git a/Documentation/devicetree/bindings/usb/usb-phy.txt b/Documentation/devicetree/bindings/usb/usb-phy.txt
index 80d4148..ee14cb7 100644
--- a/Documentation/devicetree/bindings/usb/usb-phy.txt
+++ b/Documentation/devicetree/bindings/usb/usb-phy.txt
@@ -4,14 +4,11 @@ OMAP USB2 PHY
 
 Required properties:
  - compatible: Should be "ti,omap-usb2"
- - reg : Address and length of the register set for the device. Also
-add the address of control module dev conf register until a driver for
-control module is added
+ - reg : Address and length of the register set for the device.
 
 This is usually a subnode of ocp2scp to which it is connected.
 
 usb2phy at 4a0ad080 {
 	compatible = "ti,omap-usb2";
-	reg = <0x4a0ad080 0x58>,
-	      <0x4a002300 0x4>;
+	reg = <0x4a0ad080 0x58>;
 };
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 129d508..103f4ba 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -2698,13 +2698,6 @@ static struct resource omap44xx_usb_phy_and_pll_addrs[] = {
 		.end		= 0x4a0ae000,
 		.flags		= IORESOURCE_MEM,
 	},
-	{
-		/* XXX: Remove this once control module driver is in place */
-		.name		= "ctrl_dev",
-		.start		= 0x4a002300,
-		.end		= 0x4a002303,
-		.flags		= IORESOURCE_MEM,
-	},
 	{ }
 };
 
@@ -6152,12 +6145,6 @@ static struct omap_hwmod_addr_space omap44xx_usb_otg_hs_addrs[] = {
 		.pa_end		= 0x4a0ab7ff,
 		.flags		= ADDR_TYPE_RT
 	},
-	{
-		/* XXX: Remove this once control module driver is in place */
-		.pa_start	= 0x4a00233c,
-		.pa_end		= 0x4a00233f,
-		.flags		= ADDR_TYPE_RT
-	},
 	{ }
 };
 
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 23a0b7f..de6e5ce 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -11,6 +11,7 @@ config USB_MUSB_HDRC
 	select NOP_USB_XCEIV if (SOC_TI81XX || SOC_AM33XX)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
+	select OMAP_CONTROL_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
 	select USB_OTG_UTILS
 	help
 	  Say Y here if your system has a dual role high speed USB
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index da00af4..3e7ceef 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -37,6 +37,7 @@
 #include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/usb/musb-omap.h>
+#include <linux/usb/omap_control_usb.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
@@ -46,7 +47,7 @@ struct omap2430_glue {
 	struct platform_device	*musb;
 	enum omap_musb_vbus_id_status status;
 	struct work_struct	omap_musb_mailbox_work;
-	u32 __iomem		*control_otghs;
+	struct device		*control_otghs;
 };
 #define glue_to_musb(g)		platform_get_drvdata(g->musb)
 
@@ -54,26 +55,6 @@ struct omap2430_glue		*_glue;
 
 static struct timer_list musb_idle_timer;
 
-/**
- * omap4_usb_phy_mailbox - write to usb otg mailbox
- * @glue: struct omap2430_glue *
- * @val: the value to be written to the mailbox
- *
- * On detection of a device (ID pin is grounded), this API should be called
- * to set AVALID, VBUSVALID and ID pin is grounded.
- *
- * When OMAP is connected to a host (OMAP in device mode), this API
- * is called to set AVALID, VBUSVALID and ID pin in high impedance.
- *
- * XXX: This function will be removed once we have a seperate driver for
- * control module
- */
-static void omap4_usb_phy_mailbox(struct omap2430_glue *glue, u32 val)
-{
-	if (glue->control_otghs)
-		writel(val, glue->control_otghs);
-}
-
 static void musb_do_idle(unsigned long _musb)
 {
 	struct musb	*musb = (void *)_musb;
@@ -269,7 +250,6 @@ EXPORT_SYMBOL_GPL(omap_musb_mailbox);
 
 static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 {
-	u32 val;
 	struct musb *musb = glue_to_musb(glue);
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *pdata = dev->platform_data;
@@ -285,8 +265,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 		musb->xceiv->last_event = USB_EVENT_ID;
 		if (musb->gadget_driver) {
 			pm_runtime_get_sync(dev);
-			val = AVALID | VBUSVALID;
-			omap4_usb_phy_mailbox(glue, val);
+			if (!IS_ERR(glue->control_otghs))
+				omap_control_usb_host_mode(glue->control_otghs);
 			omap2430_musb_set_vbus(musb, 1);
 		}
 		break;
@@ -299,8 +279,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 		musb->xceiv->last_event = USB_EVENT_VBUS;
 		if (musb->gadget_driver)
 			pm_runtime_get_sync(dev);
-		val = IDDIG | AVALID | VBUSVALID;
-		omap4_usb_phy_mailbox(glue, val);
+		if (!IS_ERR(glue->control_otghs))
+			omap_control_usb_device_mode(glue->control_otghs);
 		break;
 
 	case OMAP_MUSB_ID_FLOAT:
@@ -317,8 +297,8 @@ static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 			if (musb->xceiv->otg->set_vbus)
 				otg_set_vbus(musb->xceiv->otg, 0);
 		}
-		val = SESSEND | IDDIG;
-		omap4_usb_phy_mailbox(glue, val);
+		if (!IS_ERR(glue->control_otghs))
+			omap_control_usb_set_sessionend(glue->control_otghs);
 		break;
 	default:
 		dev_dbg(dev, "ID float\n");
@@ -415,7 +395,6 @@ err1:
 static void omap2430_musb_enable(struct musb *musb)
 {
 	u8		devctl;
-	u32		val;
 	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
@@ -425,8 +404,8 @@ static void omap2430_musb_enable(struct musb *musb)
 	switch (glue->status) {
 
 	case OMAP_MUSB_ID_GROUND:
-		val = AVALID | VBUSVALID;
-		omap4_usb_phy_mailbox(glue, val);
+		if (!IS_ERR(glue->control_otghs))
+			omap_control_usb_host_mode(glue->control_otghs);
 		if (data->interface_type != MUSB_INTERFACE_UTMI)
 			break;
 		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -445,8 +424,8 @@ static void omap2430_musb_enable(struct musb *musb)
 		break;
 
 	case OMAP_MUSB_VBUS_VALID:
-		val = IDDIG | AVALID | VBUSVALID;
-		omap4_usb_phy_mailbox(glue, val);
+		if (!IS_ERR(glue->control_otghs))
+			omap_control_usb_device_mode(glue->control_otghs);
 		break;
 
 	default:
@@ -456,13 +435,12 @@ static void omap2430_musb_enable(struct musb *musb)
 
 static void omap2430_musb_disable(struct musb *musb)
 {
-	u32 val;
 	struct device *dev = musb->controller;
 	struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 
 	if (glue->status != OMAP_MUSB_UNKNOWN) {
-		val = SESSEND | IDDIG;
-		omap4_usb_phy_mailbox(glue, val);
+		if (!IS_ERR(glue->control_otghs))
+			omap_control_usb_set_sessionend(glue->control_otghs);
 	}
 }
 
@@ -523,9 +501,6 @@ static int omap2430_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
-	glue->control_otghs = devm_request_and_ioremap(&pdev->dev, res);
-	if (glue->control_otghs == NULL)
-		dev_dbg(&pdev->dev, "Failed to obtain control memory\n");
 
 	if (np) {
 		pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
@@ -558,11 +533,22 @@ static int omap2430_probe(struct platform_device *pdev)
 		of_property_read_u32(np, "ram_bits", (u32 *)&config->ram_bits);
 		of_property_read_u32(np, "power", (u32 *)&pdata->power);
 		config->multipoint = of_property_read_bool(np, "multipoint");
+		pdata->has_mailbox = of_property_read_bool(np,
+		    "ti,has_mailbox");
 
 		pdata->board_data	= data;
 		pdata->config		= config;
 	}
 
+	if (pdata->has_mailbox) {
+		glue->control_otghs = get_omap_control_dev();
+		if (IS_ERR(glue->control_otghs)) {
+			dev_vdbg(&pdev->dev, "Failed to get control device\n");
+			return -ENODEV;
+		}
+	} else {
+		glue->control_otghs = ERR_PTR(-ENODEV);
+	}
 	pdata->platform_ops		= &omap2430_ops;
 
 	platform_set_drvdata(pdev, glue);
diff --git a/drivers/usb/musb/omap2430.h b/drivers/usb/musb/omap2430.h
index 8ef6566..1b5e83a 100644
--- a/drivers/usb/musb/omap2430.h
+++ b/drivers/usb/musb/omap2430.h
@@ -49,13 +49,4 @@
 #define OTG_FORCESTDBY		0x414
 #	define	ENABLEFORCE		(1 << 0)
 
-/*
- * Control Module bit definitions
- * XXX: Will be removed once we have a driver for control module.
- */
-#define	AVALID				BIT(0)
-#define	BVALID				BIT(1)
-#define	VBUSVALID			BIT(2)
-#define	SESSEND				BIT(3)
-#define	IDDIG				BIT(4)
 #endif	/* __MUSB_OMAP243X_H__ */
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index a7277ee..16bdaca 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -8,6 +8,7 @@ config OMAP_USB2
 	tristate "OMAP USB2 PHY Driver"
 	depends on ARCH_OMAP2PLUS
 	select USB_OTG_UTILS
+	select OMAP_CONTROL_USB
 	help
 	  Enable this to support the transceiver that is part of SOC. This
 	  driver takes care of all the PHY functionality apart from comparator.
diff --git a/drivers/usb/phy/omap-usb2.c b/drivers/usb/phy/omap-usb2.c
index 26ae8f4..2152ce4 100644
--- a/drivers/usb/phy/omap-usb2.c
+++ b/drivers/usb/phy/omap-usb2.c
@@ -27,6 +27,7 @@
 #include <linux/err.h>
 #include <linux/pm_runtime.h>
 #include <linux/delay.h>
+#include <linux/usb/omap_control_usb.h>
 
 /**
  * omap_usb2_set_comparator - links the comparator present in the sytem with
@@ -52,29 +53,6 @@ int omap_usb2_set_comparator(struct phy_companion *comparator)
 }
 EXPORT_SYMBOL_GPL(omap_usb2_set_comparator);
 
-/**
- * omap_usb_phy_power - power on/off the phy using control module reg
- * @phy: struct omap_usb *
- * @on: 0 or 1, based on powering on or off the PHY
- *
- * XXX: Remove this function once control module driver gets merged
- */
-static void omap_usb_phy_power(struct omap_usb *phy, int on)
-{
-	u32 val;
-
-	if (on) {
-		val = readl(phy->control_dev);
-		if (val & PHY_PD) {
-			writel(~PHY_PD, phy->control_dev);
-			/* XXX: add proper documentation for this delay */
-			mdelay(200);
-		}
-	} else {
-		writel(PHY_PD, phy->control_dev);
-	}
-}
-
 static int omap_usb_set_vbus(struct usb_otg *otg, bool enabled)
 {
 	struct omap_usb *phy = phy_to_omapusb(otg->phy);
@@ -124,7 +102,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend)
 	struct omap_usb *phy = phy_to_omapusb(x);
 
 	if (suspend && !phy->is_suspended) {
-		omap_usb_phy_power(phy, 0);
+		omap_control_usb_phy_power(phy->control_dev, 0);
 		pm_runtime_put_sync(phy->dev);
 		phy->is_suspended = 1;
 	} else if (!suspend && phy->is_suspended) {
@@ -134,7 +112,7 @@ static int omap_usb2_suspend(struct usb_phy *x, int suspend)
 									ret);
 			return ret;
 		}
-		omap_usb_phy_power(phy, 1);
+		omap_control_usb_phy_power(phy->control_dev, 1);
 		phy->is_suspended = 0;
 	}
 
@@ -168,14 +146,14 @@ static int omap_usb2_probe(struct platform_device *pdev)
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 
-	phy->control_dev = devm_request_and_ioremap(&pdev->dev, res);
-	if (phy->control_dev == NULL) {
-		dev_err(&pdev->dev, "Failed to obtain io memory\n");
-		return -ENXIO;
+	phy->control_dev = get_omap_control_dev();
+	if (IS_ERR(phy->control_dev)) {
+		dev_dbg(&pdev->dev, "Failed to get control device\n");
+		return -ENODEV;
 	}
 
 	phy->is_suspended	= 1;
-	omap_usb_phy_power(phy, 0);
+	omap_control_usb_phy_power(phy->control_dev, 0);
 
 	otg->set_host		= omap_usb_set_host;
 	otg->set_peripheral	= omap_usb_set_peripheral;
diff --git a/include/linux/usb/omap_usb.h b/include/linux/usb/omap_usb.h
index 0ea17f8..3db9b53 100644
--- a/include/linux/usb/omap_usb.h
+++ b/include/linux/usb/omap_usb.h
@@ -25,13 +25,11 @@ struct omap_usb {
 	struct usb_phy		phy;
 	struct phy_companion	*comparator;
 	struct device		*dev;
-	u32 __iomem		*control_dev;
+	struct device		*control_dev;
 	struct clk		*wkupclk;
 	u8			is_suspended:1;
 };
 
-#define	PHY_PD	0x1
-
 #define	phy_to_omapusb(x)	container_of((x), struct omap_usb, phy)
 
 #if defined(CONFIG_OMAP_USB2) || defined(CONFIG_OMAP_USB2_MODULE)
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 3/7] ARM: OMAP2: MUSB: Specify omap4 has mailbox
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Added has_mailbox to the musb platform data to specify that omap uses
an external mailbox (in control module) to communicate with the musb
core during device connect and disconnect.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/mach-omap2/usb-musb.c |    3 +++
 include/linux/usb/musb.h       |    2 ++
 2 files changed, 5 insertions(+)

diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 7b33b37..9d27e3f 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -85,6 +85,9 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
 	musb_plat.mode = board_data->mode;
 	musb_plat.extvbus = board_data->extvbus;
 
+	if (cpu_is_omap44xx())
+		musb_plat.has_mailbox = true;
+
 	if (soc_is_am35xx()) {
 		oh_name = "am35x_otg_hs";
 		name = "musb-am35x";
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
index eb50525..053c268 100644
--- a/include/linux/usb/musb.h
+++ b/include/linux/usb/musb.h
@@ -99,6 +99,8 @@ struct musb_hdrc_platform_data {
 	/* MUSB_HOST, MUSB_PERIPHERAL, or MUSB_OTG */
 	u8		mode;
 
+	u8		has_mailbox:1;
+
 	/* for clk_get() */
 	const char	*clock;
 
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 2/7] ARM: OMAP: devices: create device for usb part of control module
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

A seperate driver has been added to handle the usb part of control
module. A device for the above driver is created here, using the register
address information to be used by the driver for powering on the PHY and
for writing to the mailbox.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 arch/arm/mach-omap2/devices.c |   50 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 5e304d0..a761faf4 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -20,6 +20,7 @@
 #include <linux/pinctrl/machine.h>
 #include <linux/platform_data/omap4-keypad.h>
 #include <linux/platform_data/omap_ocp2scp.h>
+#include <linux/usb/omap_control_usb.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/map.h>
@@ -254,6 +255,54 @@ static inline void omap_init_camera(void)
 #endif
 }
 
+#if (defined(CONFIG_OMAP_CONTROL_USB) || \
+				defined(CONFIG_OMAP_CONTROL_USB_MODULE))
+
+static struct omap_control_usb_platform_data omap4_control_usb_pdata = {
+	.has_mailbox = true,
+};
+
+struct resource omap4_control_usb_res[] = {
+	{
+		.name	= "control_dev_conf",
+		.start	= 0x4a002300,
+		.end	= 0x4a002303,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.name	= "otghs_control",
+		.start	= 0x4a00233c,
+		.end	= 0x4a00233f,
+		.flags	= IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device omap4_control_usb = {
+	.name		= "omap-control-usb",
+	.id		= -1,
+	.dev = {
+		.platform_data = &omap4_control_usb_pdata,
+	},
+	.num_resources = 2,
+	.resource = omap4_control_usb_res,
+};
+
+static inline void __init omap_init_control_usb(void)
+{
+	int ret = 0;
+
+	if (cpu_is_omap44xx()) {
+		ret = platform_device_register(&omap4_control_usb);
+		if (ret)
+			pr_err("Error registering omap_control_usb device: %d\n"
+			    , ret);
+	}
+}
+
+#else
+static inline void omap_init_control_usb(void) { }
+#endif /* CONFIG_OMAP_CONTROL_USB */
+
 int __init omap4_keyboard_init(struct omap4_keypad_platform_data
 			*sdp4430_keypad_data, struct omap_board_data *bdata)
 {
@@ -721,6 +770,7 @@ static int __init omap2_init_devices(void)
 	omap_init_mbox();
 	/* If dtb is there, the devices will be created dynamically */
 	if (!of_have_populated_dt()) {
+		omap_init_control_usb();
 		omap_init_dmic();
 		omap_init_mcpdm();
 		omap_init_mcspi();
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 1/7] drivers: usb: phy: add a new driver for usb part of control module
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239378-10030-1-git-send-email-kishon@ti.com>

Added a new driver for the usb part of control module. This has an API
to power on the USB2 phy and an API to write to the mailbox depending on
whether MUSB has to act in host mode or in device mode.

Writing to control module registers for doing the above task which was
previously done in omap glue and in omap-usb2 phy will be removed.

Signed-off-by: Kishon Vijay Abraham I <kishon@ti.com>
---
 Documentation/devicetree/bindings/usb/omap-usb.txt |   21 +-
 drivers/usb/phy/Kconfig                            |    9 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/omap-control-usb.c                 |  204 ++++++++++++++++++++
 include/linux/usb/omap_control_usb.h               |   73 +++++++
 5 files changed, 307 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/phy/omap-control-usb.c
 create mode 100644 include/linux/usb/omap_control_usb.h

diff --git a/Documentation/devicetree/bindings/usb/omap-usb.txt b/Documentation/devicetree/bindings/usb/omap-usb.txt
index 29a043e..d58dae3 100644
--- a/Documentation/devicetree/bindings/usb/omap-usb.txt
+++ b/Documentation/devicetree/bindings/usb/omap-usb.txt
@@ -1,4 +1,4 @@
-OMAP GLUE
+OMAP GLUE AND OTHER OMAP SPECIFIC COMPONENTS
 
 OMAP MUSB GLUE
  - compatible : Should be "ti,omap4-musb" or "ti,omap3-musb"
@@ -31,3 +31,22 @@ Board specific device node entry
 	mode = <3>;
 	power = <50>;
 };
+
+OMAP CONTROL USB
+
+Required properties:
+ - compatible: Should be "ti,omap-control-usb"
+ - reg : Address and length of the register set for the device. It contains
+   the address of "control_dev_conf" and "otghs_control".
+ - reg-names: The names of the register addresses corresponding to the registers
+   filled in "reg".
+ - ti,has_mailbox: This is used to specify if the platform uses mailbox in
+   control module.
+
+omap_control_usb at 4a002300 {
+	compatible = "ti,omap-control-usb";
+	reg = <0x4a002300 0x4>,
+	      <0x4a00233c 0x4>;
+	reg-names = "control_dev_conf", "otghs_control";
+	ti,has_mailbox;
+};
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index 5de6e7f..a7277ee 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -14,6 +14,15 @@ config OMAP_USB2
 	  The USB OTG controller communicates with the comparator using this
 	  driver.
 
+config OMAP_CONTROL_USB
+	tristate "OMAP CONTROL USB Driver"
+	depends on ARCH_OMAP2PLUS
+	help
+	  Enable this to add support for the USB part present in the control
+	  module. This driver has API to power on the PHY and to write to the
+	  mailbox. The mailbox is present only in omap4 and the register to
+	  power on the PHY is present in omap4 and omap5.
+
 config USB_ISP1301
 	tristate "NXP ISP1301 USB transceiver support"
 	depends on USB || USB_GADGET
diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile
index 1a579a8..0dea4d2 100644
--- a/drivers/usb/phy/Makefile
+++ b/drivers/usb/phy/Makefile
@@ -5,6 +5,7 @@
 ccflags-$(CONFIG_USB_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_OMAP_USB2)			+= omap-usb2.o
+obj-$(CONFIG_OMAP_CONTROL_USB)		+= omap-control-usb.o
 obj-$(CONFIG_USB_ISP1301)		+= isp1301.o
 obj-$(CONFIG_MV_U3D_PHY)		+= mv_u3d_phy.o
 obj-$(CONFIG_USB_EHCI_TEGRA)	+= tegra_usb_phy.o
diff --git a/drivers/usb/phy/omap-control-usb.c b/drivers/usb/phy/omap-control-usb.c
new file mode 100644
index 0000000..bed41a9
--- /dev/null
+++ b/drivers/usb/phy/omap-control-usb.c
@@ -0,0 +1,204 @@
+/*
+ * omap-control-usb.c - The USB part of control module.
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * 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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/usb/omap_control_usb.h>
+
+static struct omap_control_usb *control_usb;
+
+/**
+ * get_omap_control_dev - returns the device pointer for this control device
+ *
+ * This API should be called to get the device pointer for this control
+ * module device. This device pointer should be passed to all other API's
+ * in this driver.
+ *
+ * To be used by PHY driver and glue driver
+ */
+struct device *get_omap_control_dev(void)
+{
+	if (!control_usb)
+		return ERR_PTR(-ENODEV);
+
+	return control_usb->dev;
+}
+EXPORT_SYMBOL_GPL(get_omap_control_dev);
+
+/**
+ * omap_control_usb_phy_power - power on/off the phy using control module reg
+ * @dev: the control module device
+ * @on: 0 or 1, based on powering on or off the PHY
+ */
+void omap_control_usb_phy_power(struct device *dev, int on)
+{
+	u32 val;
+	struct omap_control_usb	*control_usb = dev_get_drvdata(dev);
+
+	if (on) {
+		val = readl(control_usb->dev_conf);
+		if (val & PHY_PD)
+			writel(~PHY_PD, control_usb->dev_conf);
+	} else {
+		writel(PHY_PD, control_usb->dev_conf);
+	}
+}
+EXPORT_SYMBOL_GPL(omap_control_usb_phy_power);
+
+/**
+ * omap_control_usb_host_mode - set AVALID, VBUSVALID and ID pin in grounded
+ * @dev: struct device *
+ *
+ * This is an API to write to the mailbox register to notify the usb core that
+ * a usb device has been connected.
+ */
+void omap_control_usb_host_mode(struct device *dev)
+{
+	u32 val;
+	struct omap_control_usb	*control_usb = dev_get_drvdata(dev);
+
+	val = AVALID | VBUSVALID;
+
+	writel(val, control_usb->otghs_control);
+}
+EXPORT_SYMBOL_GPL(omap_control_usb_host_mode);
+
+/**
+ * omap_control_usb_device_mode - set AVALID, VBUSVALID and ID pin in high
+ * impedance
+ * @dev: struct device *
+ *
+ * This is an API to write to the mailbox register to notify the usb core that
+ * it has been connected to a usb host.
+ */
+void omap_control_usb_device_mode(struct device *dev)
+{
+	u32 val;
+	struct omap_control_usb	*control_usb = dev_get_drvdata(dev);
+
+	val = IDDIG | AVALID | VBUSVALID;
+
+	writel(val, control_usb->otghs_control);
+}
+EXPORT_SYMBOL_GPL(omap_control_usb_device_mode);
+
+/**
+ * omap_control_usb_set_sessionend - Enable SESSIONEND and IDIG to high
+ * impedance
+ * @dev: struct device *
+ *
+ * This is an API to write to the mailbox register to notify the usb core
+ * it's now in disconnected state.
+ */
+void omap_control_usb_set_sessionend(struct device *dev)
+{
+	u32 val;
+	struct omap_control_usb	*control_usb = dev_get_drvdata(dev);
+
+	val = SESSEND | IDDIG;
+
+	writel(val, control_usb->otghs_control);
+}
+EXPORT_SYMBOL_GPL(omap_control_usb_set_sessionend);
+
+static int omap_control_usb_probe(struct platform_device *pdev)
+{
+	struct resource	*res;
+	struct device_node *np = pdev->dev.of_node;
+	struct omap_control_usb_platform_data *pdata = pdev->dev.platform_data;
+
+	control_usb = devm_kzalloc(&pdev->dev, sizeof(*control_usb),
+	    GFP_KERNEL);
+	if (!control_usb) {
+		dev_err(&pdev->dev, "unable to alloc memory for control usb\n");
+		return -ENOMEM;
+	}
+
+	if (np) {
+		control_usb->has_mailbox = of_property_read_bool(np,
+		    "ti,has_mailbox");
+	} else if (pdata) {
+		control_usb->has_mailbox = pdata->has_mailbox;
+	} else {
+		dev_err(&pdev->dev, "no pdata present\n");
+		return -EINVAL;
+	}
+
+	control_usb->dev	= &pdev->dev;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+	    "control_dev_conf");
+	control_usb->dev_conf = devm_request_and_ioremap(&pdev->dev, res);
+	if (control_usb->dev_conf == NULL) {
+		dev_err(&pdev->dev, "Failed to obtain io memory\n");
+		return -ENXIO;
+	}
+
+	if (control_usb->has_mailbox) {
+		res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+		    "otghs_control");
+		control_usb->otghs_control = devm_request_and_ioremap(
+		    &pdev->dev, res);
+		if (control_usb->otghs_control == NULL) {
+			dev_err(&pdev->dev, "Failed to obtain io memory\n");
+			return -ENXIO;
+		}
+	}
+
+	dev_set_drvdata(control_usb->dev, control_usb);
+
+	return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id omap_control_usb_id_table[] = {
+	{ .compatible = "ti,omap-control-usb" },
+	{}
+};
+MODULE_DEVICE_TABLE(of, omap_control_usb_id_table);
+#endif
+
+static struct platform_driver omap_control_usb_driver = {
+	.probe		= omap_control_usb_probe,
+	.driver		= {
+		.name	= "omap-control-usb",
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(omap_control_usb_id_table),
+	},
+};
+
+static int __init omap_control_usb_init(void)
+{
+	return platform_driver_register(&omap_control_usb_driver);
+}
+subsys_initcall(omap_control_usb_init);
+
+static void __exit omap_control_usb_exit(void)
+{
+	platform_driver_unregister(&omap_control_usb_driver);
+}
+module_exit(omap_control_usb_exit);
+
+MODULE_ALIAS("platform: omap_control_usb");
+MODULE_AUTHOR("Texas Instruments Inc.");
+MODULE_DESCRIPTION("OMAP CONTROL USB DRIVER");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/usb/omap_control_usb.h b/include/linux/usb/omap_control_usb.h
new file mode 100644
index 0000000..fbc7407
--- /dev/null
+++ b/include/linux/usb/omap_control_usb.h
@@ -0,0 +1,73 @@
+/*
+ * omap_control_usb.h - Header file for the USB part of control module.
+ *
+ * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com
+ * 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.
+ *
+ * Author: Kishon Vijay Abraham I <kishon@ti.com>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __OMAP_CONTROL_USB_H__
+#define __OMAP_CONTROL_USB_H__
+
+struct omap_control_usb {
+	struct device *dev;
+
+	u32 __iomem *dev_conf;
+	u32 __iomem *otghs_control;
+
+	u8 has_mailbox:1;
+};
+
+struct omap_control_usb_platform_data {
+	u8 has_mailbox:1;
+};
+
+#define	PHY_PD		BIT(0)
+
+#define	AVALID		BIT(0)
+#define	BVALID		BIT(1)
+#define	VBUSVALID	BIT(2)
+#define	SESSEND		BIT(3)
+#define	IDDIG		BIT(4)
+
+#if (defined(CONFIG_OMAP_CONTROL_USB) || \
+				defined(CONFIG_OMAP_CONTROL_USB_MODULE))
+extern struct device *get_omap_control_dev(void);
+extern void omap_control_usb_phy_power(struct device *dev, int on);
+extern void omap_control_usb_host_mode(struct device *dev);
+extern void omap_control_usb_device_mode(struct device *dev);
+extern void omap_control_usb_set_sessionend(struct device *dev);
+#else
+static inline struct device *get_omap_control_dev()
+{
+	return ERR_PTR(-ENODEV);
+}
+
+static inline void omap_control_usb_phy_power(struct device *dev, int on)
+{
+}
+
+static inline void omap_control_usb_host_mode(struct device *dev)
+{
+}
+
+static inline void omap_control_usb_device_mode(struct device *dev)
+{
+}
+
+static inline void omap_control_usb_set_sessionend(struct device *dev)
+{
+}
+#endif
+
+#endif	/* __OMAP_CONTROL_USB_H__ */
-- 
1.7.9.5

^ permalink raw reply related

* [RFC PATCH 0/7] usb: musb: add driver for control module
From: Kishon Vijay Abraham I @ 2013-01-15  8:42 UTC (permalink / raw)
  To: linux-arm-kernel

Added a new driver for the usb part of control module. This has an API
to power on the USB2 phy and an API to write to the mailbox depending on
whether MUSB has to act in host mode or in device mode.

Writing to control module registers for doing the above task which was
previously done in omap glue and in omap-usb2 phy is removed.

Also added the dt data to get MUSB working in OMAP platforms.
This series has patches for both drivers and ARCH folders, so If it has to
be split I'll do it.

This series was developed on
git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git xceiv

Did basic enumeration testing in omap4 beagle, omap4 sdp and omap3 beagle.

Kishon Vijay Abraham I (7):
  drivers: usb: phy: add a new driver for usb part of control module
  ARM: OMAP: devices: create device for usb part of control module
  ARM: OMAP2: MUSB: Specify omap4 has mailbox
  drivers: usb: start using the control module driver
  ARM: dts: omap: Add usb_otg and glue data
  ARM: dts: omap: Add omap-usb2 dt data
  ARM: dts: omap: Add omap control usb data

 Documentation/devicetree/bindings/usb/omap-usb.txt |   25 ++-
 Documentation/devicetree/bindings/usb/usb-phy.txt  |    7 +-
 arch/arm/boot/dts/omap3-beagle-xm.dts              |    6 +
 arch/arm/boot/dts/omap3-evm.dts                    |    6 +
 arch/arm/boot/dts/omap3-overo.dtsi                 |    6 +
 arch/arm/boot/dts/omap3.dtsi                       |   11 ++
 arch/arm/boot/dts/omap4-panda.dts                  |    6 +
 arch/arm/boot/dts/omap4-sdp.dts                    |    6 +
 arch/arm/boot/dts/omap4.dtsi                       |   24 +++
 arch/arm/mach-omap2/devices.c                      |   50 +++++
 arch/arm/mach-omap2/omap_hwmod_44xx_data.c         |   13 --
 arch/arm/mach-omap2/usb-musb.c                     |    3 +
 drivers/usb/musb/Kconfig                           |    1 +
 drivers/usb/musb/omap2430.c                        |   64 +++---
 drivers/usb/musb/omap2430.h                        |    9 -
 drivers/usb/phy/Kconfig                            |   10 +
 drivers/usb/phy/Makefile                           |    1 +
 drivers/usb/phy/omap-control-usb.c                 |  204 ++++++++++++++++++++
 drivers/usb/phy/omap-usb2.c                        |   38 +---
 include/linux/usb/musb.h                           |    2 +
 include/linux/usb/omap_control_usb.h               |   73 +++++++
 include/linux/usb/omap_usb.h                       |    4 +-
 22 files changed, 469 insertions(+), 100 deletions(-)
 create mode 100644 drivers/usb/phy/omap-control-usb.c
 create mode 100644 include/linux/usb/omap_control_usb.h

-- 
1.7.9.5

^ permalink raw reply

* [PATCH 2/2] gpio: devm_gpio_* support should not depend on GPIOLIB
From: Shawn Guo @ 2013-01-15  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239056-703-1-git-send-email-shawn.guo@linaro.org>

Some architectures (e.g. blackfin) provide gpio API without requiring
GPIOLIB support (ARCH_WANT_OPTIONAL_GPIOLIB).  devm_gpio_* functions
should also work for these architectures, since they do not really
depend on GPIOLIB.

Add a new option GPIO_DEVRES (enabled by default) to control the build
of devres.c, and move devm_gpio_* function declarations out from #ifdef
CONFIG_GPIOLIB in include/asm-generic/gpio.h, so that they can be
available to client drivers without unnecessary dependency on GPIOLIB.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 drivers/gpio/Kconfig       |    3 +++
 drivers/gpio/Makefile      |    3 ++-
 include/asm-generic/gpio.h |   17 ++++++++---------
 3 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 682de75..d972932 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -30,6 +30,9 @@ config ARCH_REQUIRE_GPIOLIB
 	  Selecting this from the architecture code will cause the gpiolib
 	  code to always get built in.
 
+config GPIO_DEVRES
+	def_bool y
+	depends on HAS_IOMEM
 
 
 menuconfig GPIOLIB
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index c5aebd0..36ca605 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -2,7 +2,8 @@
 
 ccflags-$(CONFIG_DEBUG_GPIO)	+= -DDEBUG
 
-obj-$(CONFIG_GPIOLIB)		+= gpiolib.o devres.o
+obj-$(CONFIG_GPIO_DEVRES)	+= devres.o
+obj-$(CONFIG_GPIOLIB)		+= gpiolib.o
 obj-$(CONFIG_OF_GPIO)		+= gpiolib-of.o
 obj-$(CONFIG_GPIO_ACPI)		+= gpiolib-acpi.o
 
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 2341014..71fd984 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -7,6 +7,8 @@
 #include <linux/of.h>
 #include <linux/pinctrl/pinctrl.h>
 
+struct device;
+
 #ifdef CONFIG_GPIOLIB
 
 #include <linux/compiler.h>
@@ -42,7 +44,6 @@ static inline bool gpio_is_valid(int number)
 	return number >= 0 && number < ARCH_NR_GPIOS;
 }
 
-struct device;
 struct gpio;
 struct seq_file;
 struct module;
@@ -192,12 +193,6 @@ extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *labe
 extern int gpio_request_array(const struct gpio *array, size_t num);
 extern void gpio_free_array(const struct gpio *array, size_t num);
 
-/* bindings for managed devices that want to request gpios */
-int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
-int devm_gpio_request_one(struct device *dev, unsigned gpio,
-			  unsigned long flags, const char *label);
-void devm_gpio_free(struct device *dev, unsigned int gpio);
-
 #ifdef CONFIG_GPIO_SYSFS
 
 /*
@@ -280,9 +275,13 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
 
 #endif /* !CONFIG_GPIOLIB */
 
-#ifndef CONFIG_GPIO_SYSFS
+/* bindings for managed devices that want to request gpios */
+int devm_gpio_request(struct device *dev, unsigned gpio, const char *label);
+int devm_gpio_request_one(struct device *dev, unsigned gpio,
+			  unsigned long flags, const char *label);
+void devm_gpio_free(struct device *dev, unsigned int gpio);
 
-struct device;
+#ifndef CONFIG_GPIO_SYSFS
 
 /* sysfs support is only available with gpiolib, where it's optional */
 
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 1/2] gpio: fix warning of 'struct gpio_chip' declaration
From: Shawn Guo @ 2013-01-15  8:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358239056-703-1-git-send-email-shawn.guo@linaro.org>

The struct gpio_chip is only defined inside #ifdef CONFIG_GPIOLIB,
but it's referenced by gpiochip_add_pin_range() and
gpiochip_remove_pin_ranges() which are outside #ifdef CONFIG_GPIOLIB.
Thus, we see the following warning when building blackfin image, where
GPIOLIB is not required.

  CC      arch/blackfin/kernel/bfin_gpio.o
  CC      init/version.o
In file included from arch/blackfin/include/asm/gpio.h:321,
                 from arch/blackfin/kernel/bfin_gpio.c:15:
include/asm-generic/gpio.h:298: warning: ?struct gpio_chip? declared inside parameter list
include/asm-generic/gpio.h:298: warning: its scope is only this definition or declaration, which is probably not what you want
include/asm-generic/gpio.h:304: warning: ?struct gpio_chip? declared inside parameter list

Move pinctrl trunk into #ifdef CONFIG_GPIOLIB to fix the warning,
since it appears that pinctrl gpio range support depends on GPIOLIB.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
---
 include/asm-generic/gpio.h |   74 ++++++++++++++++++++++----------------------
 1 file changed, 37 insertions(+), 37 deletions(-)

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 20ca766..2341014 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -212,6 +212,43 @@ extern void gpio_unexport(unsigned gpio);
 
 #endif	/* CONFIG_GPIO_SYSFS */
 
+#ifdef CONFIG_PINCTRL
+
+/**
+ * struct gpio_pin_range - pin range controlled by a gpio chip
+ * @head: list for maintaining set of pin ranges, used internally
+ * @pctldev: pinctrl device which handles corresponding pins
+ * @range: actual range of pins controlled by a gpio controller
+ */
+
+struct gpio_pin_range {
+	struct list_head node;
+	struct pinctrl_dev *pctldev;
+	struct pinctrl_gpio_range range;
+};
+
+int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+			   unsigned int gpio_offset, unsigned int pin_offset,
+			   unsigned int npins);
+void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
+
+#else
+
+static inline int
+gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
+		       unsigned int gpio_offset, unsigned int pin_offset,
+		       unsigned int npins)
+{
+	return 0;
+}
+
+static inline void
+gpiochip_remove_pin_ranges(struct gpio_chip *chip)
+{
+}
+
+#endif /* CONFIG_PINCTRL */
+
 #else	/* !CONFIG_GPIOLIB */
 
 static inline bool gpio_is_valid(int number)
@@ -270,41 +307,4 @@ static inline void gpio_unexport(unsigned gpio)
 }
 #endif	/* CONFIG_GPIO_SYSFS */
 
-#ifdef CONFIG_PINCTRL
-
-/**
- * struct gpio_pin_range - pin range controlled by a gpio chip
- * @head: list for maintaining set of pin ranges, used internally
- * @pctldev: pinctrl device which handles corresponding pins
- * @range: actual range of pins controlled by a gpio controller
- */
-
-struct gpio_pin_range {
-	struct list_head node;
-	struct pinctrl_dev *pctldev;
-	struct pinctrl_gpio_range range;
-};
-
-int gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
-			   unsigned int gpio_offset, unsigned int pin_offset,
-			   unsigned int npins);
-void gpiochip_remove_pin_ranges(struct gpio_chip *chip);
-
-#else
-
-static inline int
-gpiochip_add_pin_range(struct gpio_chip *chip, const char *pinctl_name,
-		       unsigned int gpio_offset, unsigned int pin_offset,
-		       unsigned int npins)
-{
-	return 0;
-}
-
-static inline void
-gpiochip_remove_pin_ranges(struct gpio_chip *chip)
-{
-}
-
-#endif /* CONFIG_PINCTRL */
-
 #endif /* _ASM_GENERIC_GPIO_H */
-- 
1.7.9.5

^ permalink raw reply related

* [PATCH 0/2] A couple of gpio fixes
From: Shawn Guo @ 2013-01-15  8:37 UTC (permalink / raw)
  To: linux-arm-kernel

I recently sent a patch "mmc: slot-gpio: use devm_* managed functions
to ease users" for mmc-next inclusion, and got a error report [1] from
Fengguang (Thanks!), saying it breaks blackfin build.  It seems to me
that the error is caused by devm_gpio_* unnecessary dependency on
GPIOLIB.

While at it, I also include a patch (#1) to fix the 'struct gpio_chip'
declaration warning that's already been there with blackfin build.
And the patch #2 remove the unnecessary dependency between devm_gpio_*
and GPIOLIB to get the reported error fixed.

[1] http://thread.gmane.org/gmane.linux.kernel.mmc/18650

Shawn Guo (2):
  gpio: fix warning of 'struct gpio_chip' declaration
  gpio: devm_gpio_* support should not depend on GPIOLIB

 drivers/gpio/Kconfig       |    3 ++
 drivers/gpio/Makefile      |    3 +-
 include/asm-generic/gpio.h |   91 ++++++++++++++++++++++----------------------
 3 files changed, 50 insertions(+), 47 deletions(-)

-- 
1.7.9.5

^ permalink raw reply

* OMAP baseline test results for v3.8-rc3
From: Peter Ujfalusi @ 2013-01-15  8:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1301141756460.20390@utopia.booyaka.com>

Hi Paul,

On 01/14/2013 06:59 PM, Paul Walmsley wrote:
> Failing tests: needing investigation
> ------------------------------------
> 
> Build tests:
> 
> * rmk_3430_ldp_allnoconfig, rmk_4430_sdp_allnoconfig: twl4030 build failures
>   - in drivers/mfd/twl-core.c

The following patch fixes these:
https://lkml.org/lkml/2012/12/24/3


-- 
P?ter

^ permalink raw reply

* [v3 9/9] ARM: tegra: Add initial support for Tegra 114 SoC.
From: Hiroshi Doyu @ 2013-01-15  8:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358237598-32413-1-git-send-email-hdoyu@nvidia.com>

Add new Tegra 114 SoC support.

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
 arch/arm/mach-tegra/Kconfig             |   10 +++++++
 arch/arm/mach-tegra/Makefile            |    1 +
 arch/arm/mach-tegra/board-dt-tegra114.c |   48 +++++++++++++++++++++++++++++++
 arch/arm/mach-tegra/common.c            |    1 +
 4 files changed, 60 insertions(+)
 create mode 100644 arch/arm/mach-tegra/board-dt-tegra114.c

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 1ec7f80..d976ef2 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -44,6 +44,16 @@ config ARCH_TEGRA_3x_SOC
 	  Support for NVIDIA Tegra T30 processor family, based on the
 	  ARM CortexA9MP CPU and the ARM PL310 L2 cache controller
 
+config ARCH_TEGRA_114_SOC
+	bool "Enable support for Tegra114 family"
+	select ARM_GIC
+	select CPU_V7
+	select ARM_L1_CACHE_SHIFT_6
+	select ARM_ARCH_TIMER
+	help
+	  Support for NVIDIA Tegra T114 processor family, based on the
+	  ARM CortexA15MP CPU
+
 config TEGRA_PCI
 	bool "PCI Express support"
 	depends on ARCH_TEGRA_2x_SOC
diff --git a/arch/arm/mach-tegra/Makefile b/arch/arm/mach-tegra/Makefile
index 660ee03..219c2ed 100644
--- a/arch/arm/mach-tegra/Makefile
+++ b/arch/arm/mach-tegra/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_TEGRA_PCI)			+= pcie.o
 
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-dt-tegra20.o
 obj-$(CONFIG_ARCH_TEGRA_3x_SOC)		+= board-dt-tegra30.o
+obj-$(CONFIG_ARCH_TEGRA_114_SOC)	+= board-dt-tegra114.o
 
 obj-$(CONFIG_ARCH_TEGRA_2x_SOC)		+= board-harmony-pcie.o
 
diff --git a/arch/arm/mach-tegra/board-dt-tegra114.c b/arch/arm/mach-tegra/board-dt-tegra114.c
new file mode 100644
index 0000000..4c36dd0
--- /dev/null
+++ b/arch/arm/mach-tegra/board-dt-tegra114.c
@@ -0,0 +1,48 @@
+/*
+ * NVIDIA Tegra114 device tree board support
+ *
+ * Copyright (C) 2012 NVIDIA Corporation
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * 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.
+ *
+ */
+
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/clocksource.h>
+
+#include <asm/mach/arch.h>
+#include <asm/hardware/gic.h>
+
+#include "board.h"
+#include "common.h"
+
+static void __init tegra114_dt_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char * const tegra114_dt_board_compat[] = {
+	"nvidia,tegra114",
+	NULL,
+};
+
+DT_MACHINE_START(TEGRA114_DT, "NVIDIA Tegra114 (Flattened Device Tree)")
+	.smp		= smp_ops(tegra_smp_ops),
+	.map_io		= tegra_map_common_io,
+	.init_early	= tegra30_init_early,
+	.init_irq	= tegra_dt_init_irq,
+	.handle_irq	= gic_handle_irq,
+	.init_time	= clocksource_of_init,
+	.init_machine	= tegra114_dt_init,
+	.init_late	= tegra_init_late,
+	.restart	= tegra_assert_system_reset,
+	.dt_compat	= tegra114_dt_board_compat,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/common.c b/arch/arm/mach-tegra/common.c
index 3efe80b..b6bfc0c 100644
--- a/arch/arm/mach-tegra/common.c
+++ b/arch/arm/mach-tegra/common.c
@@ -59,6 +59,7 @@ u32 tegra_uart_config[4] = {
 
 #ifdef CONFIG_OF
 static const struct of_device_id tegra_dt_irq_match[] __initconst = {
+	{ .compatible = "arm,cortex-a15-gic", .data = gic_of_init },
 	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init },
 	{ }
 };
-- 
1.7.9.5

^ permalink raw reply related

* [v3 8/9] ARM: dt: tegra114: Add new board, Pluto
From: Hiroshi Doyu @ 2013-01-15  8:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358237598-32413-1-git-send-email-hdoyu@nvidia.com>

Add a new evaluation board, Pluto for Tegra 114 family.

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
 arch/arm/boot/dts/Makefile           |    3 ++-
 arch/arm/boot/dts/tegra114-pluto.dts |   21 +++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/tegra114-pluto.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 04e43d2..32f47ce 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -148,7 +148,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
 	tegra30-cardhu-a02.dtb \
 	tegra30-cardhu-a04.dtb \
 	tegra30-beaver.dtb \
-	tegra114-dalmore.dtb
+	tegra114-dalmore.dtb \
+	tegra114-pluto.dtb
 dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
 	vexpress-v2p-ca9.dtb \
 	vexpress-v2p-ca15-tc1.dtb \
diff --git a/arch/arm/boot/dts/tegra114-pluto.dts b/arch/arm/boot/dts/tegra114-pluto.dts
new file mode 100644
index 0000000..9bea8f5
--- /dev/null
+++ b/arch/arm/boot/dts/tegra114-pluto.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/include/ "tegra114.dtsi"
+
+/ {
+	model = "NVIDIA Tegra114 Pluto evaluation board";
+	compatible = "nvidia,pluto", "nvidia,tegra114";
+
+	memory {
+		reg = <0x80000000 0x40000000>;
+	};
+
+	serial at 70006300 {
+		status = "okay";
+		clock-frequency = <408000000>;
+	};
+
+	pmc {
+		nvidia,invert-interrupt;
+	};
+};
-- 
1.7.9.5

^ permalink raw reply related

* [v3 7/9] ARM: dt: tegra114: Add new board, Dalmore
From: Hiroshi Doyu @ 2013-01-15  8:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1358237598-32413-1-git-send-email-hdoyu@nvidia.com>

Add a new evaluation board, Dalmore for Tegra 114 family.

Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com>
---
 arch/arm/boot/dts/Makefile             |    3 ++-
 arch/arm/boot/dts/tegra114-dalmore.dts |   21 +++++++++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/tegra114-dalmore.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b511bc1..04e43d2 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -147,7 +147,8 @@ dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
 	tegra20-whistler.dtb \
 	tegra30-cardhu-a02.dtb \
 	tegra30-cardhu-a04.dtb \
-	tegra30-beaver.dtb
+	tegra30-beaver.dtb \
+	tegra114-dalmore.dtb
 dtb-$(CONFIG_ARCH_VEXPRESS) += vexpress-v2p-ca5s.dtb \
 	vexpress-v2p-ca9.dtb \
 	vexpress-v2p-ca15-tc1.dtb \
diff --git a/arch/arm/boot/dts/tegra114-dalmore.dts b/arch/arm/boot/dts/tegra114-dalmore.dts
new file mode 100644
index 0000000..a30aca6
--- /dev/null
+++ b/arch/arm/boot/dts/tegra114-dalmore.dts
@@ -0,0 +1,21 @@
+/dts-v1/;
+
+/include/ "tegra114.dtsi"
+
+/ {
+	model = "NVIDIA Tegra114 Dalmore evaluation board";
+	compatible = "nvidia,dalmore", "nvidia,tegra114";
+
+	memory {
+		reg = <0x80000000 0x40000000>;
+	};
+
+	serial at 70006300 {
+		status = "okay";
+		clock-frequency = <408000000>;
+	};
+
+	pmc {
+		nvidia,invert-interrupt;
+	};
+};
-- 
1.7.9.5

^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox