Received: from mail.onstor.com (66.201.51.107) by exch1.onstor.net
 (10.0.0.225) with Microsoft SMTP Server id 8.1.311.2; Sat, 1 Nov 2008
 01:26:34 -0700
Received: from chiesmta2-3.messageone.com ([216.203.30.55]) by mail.onstor.com
 with Microsoft SMTPSVC(6.0.3790.3959);	 Sat, 1 Nov 2008 01:26:33 -0700
Received: from ftp.linux-mips.org (ftp.linux-mips.org [213.58.128.207])	by
 chiesmta2-3.messageone.com (8.13.8/8.13.8) with ESMTP id mA18QWDV029265	for
 <andy.sharp@onstor.com>; Sat, 1 Nov 2008 03:26:32 -0500
Received: from localhost.localdomain ([127.0.0.1]:5576 "EHLO
	ftp.linux-mips.org") by ftp.linux-mips.org with ESMTP	id S22881311AbYKAIZb
 (ORCPT <rfc822;andy.sharp@onstor.com>);	Sat, 1 Nov 2008 08:25:31 +0000
Received: with ECARTIS (v1.0.0; list linux-mips); Sat, 01 Nov 2008 08:25:15
 +0000 (GMT)
Received: from orbit.nwl.cc ([81.169.176.177]:32465 "EHLO
	mail.ifyouseekate.net") by ftp.linux-mips.org with ESMTP	id S22834062AbYJaO6T
 (ORCPT <rfc822;linux-mips@linux-mips.org>);	Fri, 31 Oct 2008 14:58:19 +0000
Received: from base (localhost [127.0.0.1])	by mail.ifyouseekate.net (Postfix)
 with ESMTP id 9182B38CE6F7;	Fri, 31 Oct 2008 15:58:11 +0100 (CET)
From: Phil Sutter <n0-1@freewrt.org>
To: Ralf Baechle <ralf@linux-mips.org>
CC: "linux-mips@linux-mips.org" <linux-mips@linux-mips.org>
Sender: "linux-mips-bounce@linux-mips.org" <linux-mips-bounce@linux-mips.org>
Date: Fri, 31 Oct 2008 07:58:08 -0700
Subject: [PATCH] provide functions for gpio configuration
Thread-Topic: [PATCH] provide functions for gpio configuration
Thread-Index: Ack7+406zGCFOSbbRpWBWnlVOuYD+Q==
Message-ID: <1225465088-29365-1-git-send-email-n0-1@freewrt.org>
References: <1225412757-17894-1-git-send-email-n0-1@freewrt.org>
In-Reply-To: <1225412757-17894-1-git-send-email-n0-1@freewrt.org>
Accept-Language: en-US
X-MS-Exchange-Organization-AuthAs: Internal
X-MS-Exchange-Organization-AuthMechanism: 0b
X-MS-Exchange-Organization-AuthSource: exch1.onstor.net
X-MS-Has-Attach:
X-Auto-Response-Suppress: All
X-MS-TNEF-Correlator:
x-originalarrivaltime: 01 Nov 2008 08:26:33.0892 (UTC)
 FILETIME=[8CA05E40:01C93BFB]
errors-to: linux-mips-bounce@linux-mips.org
x-ems-proccessed: 2K3Xl1OQTInXD6xxuA8z3Q==
x-ems-stamp: Evwx3qFJDE+b+W0Bj33lkg==
x-messageone-virus-version: vendor=fsecure
 engine=4.65.7400:2.4.4,1.2.40,4.0.164
 definitions=2008-10-31_11:2008-10-10,2008-10-31,2008-10-31 signatures=0
x-messageone-virus-scanned: Clean
x-messageone-envelope-sender: linux-mips-bounce@linux-mips.org
x-messageone-spam-details: rule=m773emszm_notspam policy=m773emszm score=0
 spamscore=0 ipscore=0 phishscore=0 bulkscore=0 adultscore=0 classifier=spam
 adjust=0 reason=mlx engine=3.1.0-0810130000 definitions=main-0811010008
x-messageone-spam-score: 0
x-messageone-spam-bar:
x-list: linux-mips
x-archive-position: 21141
x-ecartis-version: Ecartis v1.0.0
x-original-sender: n0-1@freewrt.org
Content-Type: text/plain; charset="iso-8859-1"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0

As gpiolib doesn't support pin multiplexing, it provides no way to
access the GPIOFUNC register. Also there is no support for setting
interrupt status and level. These functions provide access to them and
are needed by the CompactFlash driver.

This is a combined version of the first two patches send in this thread
on the linux-mips mailinglist. It's also addressing the conflict
generated due to the change in arch/mips/include/asm/mach-rc32434/rb.h.
Though this patch depends on it, it has been moved to another
(yet uncommitted) patch changing the same part of rb.h.

Signed-off-by: Phil Sutter <n0-1@freewrt.org>
---
 arch/mips/include/asm/mach-rc32434/gpio.h |    2 +
 arch/mips/rb532/gpio.c                    |  191 +++++++++++--------------=
----
 2 files changed, 76 insertions(+), 117 deletions(-)

diff --git a/arch/mips/include/asm/mach-rc32434/gpio.h b/arch/mips/include/=
asm/mach-rc32434/gpio.h
index c8e554e..b5cf645 100644
--- a/arch/mips/include/asm/mach-rc32434/gpio.h
+++ b/arch/mips/include/asm/mach-rc32434/gpio.h
@@ -84,5 +84,7 @@ extern void set_434_reg(unsigned reg_offs, unsigned bit, =
unsigned len, unsigned
 extern unsigned get_434_reg(unsigned reg_offs);
 extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask);
 extern unsigned char get_latch_u5(void);
+extern void rb532_gpio_set_ilevel(int bit, unsigned gpio);
+extern void rb532_gpio_set_istat(int bit, unsigned gpio);
=20
 #endif /* _RC32434_GPIO_H_ */
diff --git a/arch/mips/rb532/gpio.c b/arch/mips/rb532/gpio.c
index 76a7fd9..de29aba 100644
--- a/arch/mips/rb532/gpio.c
+++ b/arch/mips/rb532/gpio.c
@@ -39,10 +39,6 @@
 struct rb532_gpio_chip {
 	struct gpio_chip chip;
 	void __iomem	 *regbase;
-	void		(*set_int_level)(struct gpio_chip *chip, unsigned offset, int value=
);
-	int		(*get_int_level)(struct gpio_chip *chip, unsigned offset);
-	void		(*set_int_status)(struct gpio_chip *chip, unsigned offset, int valu=
e);
-	int		(*get_int_status)(struct gpio_chip *chip, unsigned offset);
 };
=20
 struct mpmc_device dev3;
@@ -111,15 +107,47 @@ unsigned char get_latch_u5(void)
 }
 EXPORT_SYMBOL(get_latch_u5);
=20
+/* rb532_set_bit - sanely set a bit
+ *=20
+ * bitval: new value for the bit
+ * offset: bit index in the 4 byte address range
+ * ioaddr: 4 byte aligned address being altered
+ */
+static inline void rb532_set_bit(unsigned bitval,
+		unsigned offset, void __iomem *ioaddr)
+{
+	unsigned long flags;
+	u32 val;
+
+	bitval =3D !!bitval;              /* map parameter to {0,1} */
+
+	local_irq_save(flags);
+
+	val =3D readl(ioaddr);
+	val &=3D ~( ~bitval << offset );   /* unset bit if bitval =3D=3D 0 */
+	val |=3D  (  bitval << offset );   /* set bit if bitval =3D=3D 1 */
+	writel(val, ioaddr);
+
+	local_irq_restore(flags);
+}
+
+/* rb532_get_bit - read a bit
+ *
+ * returns the boolean state of the bit, which may be > 1
+ */
+static inline int rb532_get_bit(unsigned offset, void __iomem *ioaddr)
+{
+	return (readl(ioaddr) & (1 << offset));
+}
+
 /*
  * Return GPIO level */
 static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
 {
-	u32			mask =3D 1 << offset;
 	struct rb532_gpio_chip	*gpch;
=20
 	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	return readl(gpch->regbase + GPIOD) & mask;
+	return rb532_get_bit(offset, gpch->regbase + GPIOD);
 }
=20
 /*
@@ -128,23 +156,10 @@ static int rb532_gpio_get(struct gpio_chip *chip, uns=
igned offset)
 static void rb532_gpio_set(struct gpio_chip *chip,
 				unsigned offset, int value)
 {
-	unsigned long		flags;
-	u32			mask =3D 1 << offset;
-	u32			tmp;
 	struct rb532_gpio_chip	*gpch;
-	void __iomem		*gpvr;
=20
 	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	gpvr =3D gpch->regbase + GPIOD;
-
-	local_irq_save(flags);
-	tmp =3D readl(gpvr);
-	if (value)
-		tmp |=3D mask;
-	else
-		tmp &=3D ~mask;
-	writel(tmp, gpvr);
-	local_irq_restore(flags);
+	rb532_set_bit(value, offset, gpch->regbase + GPIOD);
 }
=20
 /*
@@ -152,21 +167,14 @@ static void rb532_gpio_set(struct gpio_chip *chip,
  */
 static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned off=
set)
 {
-	unsigned long		flags;
-	u32			mask =3D 1 << offset;
-	u32			value;
 	struct rb532_gpio_chip	*gpch;
-	void __iomem		*gpdr;
=20
 	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	gpdr =3D gpch->regbase + GPIOCFG;
=20
-	local_irq_save(flags);
-	value =3D readl(gpdr);
-	value &=3D ~mask;
-	writel(value, gpdr);
-	local_irq_restore(flags);
+	if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
+		return 1;	/* alternate function, GPIOCFG is ignored */
=20
+	rb532_set_bit(0, offset, gpch->regbase + GPIOCFG);
 	return 0;
 }
=20
@@ -176,117 +184,60 @@ static int rb532_gpio_direction_input(struct gpio_ch=
ip *chip, unsigned offset)
 static int rb532_gpio_direction_output(struct gpio_chip *chip,
 					unsigned offset, int value)
 {
-	unsigned long		flags;
-	u32			mask =3D 1 << offset;
-	u32			tmp;
 	struct rb532_gpio_chip	*gpch;
-	void __iomem		*gpdr;
=20
 	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	writel(mask, gpch->regbase + GPIOD);
-	gpdr =3D gpch->regbase + GPIOCFG;
=20
-	local_irq_save(flags);
-	tmp =3D readl(gpdr);
-	tmp |=3D mask;
-	writel(tmp, gpdr);
-	local_irq_restore(flags);
+	if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
+		return 1;	/* alternate function, GPIOCFG is ignored */
+
+	/* set the initial output value */
+	rb532_set_bit(value, offset, gpch->regbase + GPIOD);
=20
+	rb532_set_bit(1, offset, gpch->regbase + GPIOCFG);
 	return 0;
 }
=20
-/*
- * Set the GPIO interrupt level
- */
-static void rb532_gpio_set_int_level(struct gpio_chip *chip,
-					unsigned offset, int value)
-{
-	unsigned long		flags;
-	u32			mask =3D 1 << offset;
-	u32			tmp;
-	struct rb532_gpio_chip	*gpch;
-	void __iomem		*gpil;
-
-	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	gpil =3D gpch->regbase + GPIOILEVEL;
-
-	local_irq_save(flags);
-	tmp =3D readl(gpil);
-	if (value)
-		tmp |=3D mask;
-	else
-		tmp &=3D ~mask;
-	writel(tmp, gpil);
-	local_irq_restore(flags);
-}
+static struct rb532_gpio_chip rb532_gpio_chip[] =3D {
+	[0] =3D {
+		.chip =3D {
+			.label			=3D "gpio0",
+			.direction_input	=3D rb532_gpio_direction_input,
+			.direction_output	=3D rb532_gpio_direction_output,
+			.get			=3D rb532_gpio_get,
+			.set			=3D rb532_gpio_set,
+			.base			=3D 0,
+			.ngpio			=3D 32,
+		},
+	},
+};
=20
 /*
- * Get the GPIO interrupt level
+ * Set GPIO interrupt level
  */
-static int rb532_gpio_get_int_level(struct gpio_chip *chip, unsigned offse=
t)
+void rb532_gpio_set_ilevel(int bit, unsigned gpio)
 {
-	u32			mask =3D 1 << offset;
-	struct rb532_gpio_chip	*gpch;
-
-	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	return readl(gpch->regbase + GPIOILEVEL) & mask;
+	rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOILEVEL);
 }
+EXPORT_SYMBOL(rb532_gpio_set_ilevel);
=20
 /*
- * Set the GPIO interrupt status
+ * Set GPIO interrupt status=20
  */
-static void rb532_gpio_set_int_status(struct gpio_chip *chip,
-				unsigned offset, int value)
+void rb532_gpio_set_istat(int bit, unsigned gpio)
 {
-	unsigned long		flags;
-	u32			mask =3D 1 << offset;
-	u32			tmp;
-	struct rb532_gpio_chip	*gpch;
-	void __iomem		*gpis;
-
-	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	gpis =3D gpch->regbase + GPIOISTAT;
-
-	local_irq_save(flags);
-	tmp =3D readl(gpis);
-	if (value)
-		tmp |=3D mask;
-	else
-		tmp &=3D ~mask;
-	writel(tmp, gpis);
-	local_irq_restore(flags);
+	rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOISTAT);
 }
+EXPORT_SYMBOL(rb532_gpio_set_istat);
=20
 /*
- * Get the GPIO interrupt status
+ * Configure GPIO alternate function
  */
-static int rb532_gpio_get_int_status(struct gpio_chip *chip, unsigned offs=
et)
+static void rb532_gpio_set_func(int bit, unsigned gpio)
 {
-	u32			mask =3D 1 << offset;
-	struct rb532_gpio_chip	*gpch;
-
-	gpch =3D container_of(chip, struct rb532_gpio_chip, chip);
-	return readl(gpch->regbase + GPIOISTAT) & mask;
+       rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOFUNC);
 }
=20
-static struct rb532_gpio_chip rb532_gpio_chip[] =3D {
-	[0] =3D {
-		.chip =3D {
-			.label			=3D "gpio0",
-			.direction_input	=3D rb532_gpio_direction_input,
-			.direction_output	=3D rb532_gpio_direction_output,
-			.get			=3D rb532_gpio_get,
-			.set			=3D rb532_gpio_set,
-			.base			=3D 0,
-			.ngpio			=3D 32,
-		},
-		.get_int_level		=3D rb532_gpio_get_int_level,
-		.set_int_level		=3D rb532_gpio_set_int_level,
-		.get_int_status		=3D rb532_gpio_get_int_status,
-		.set_int_status		=3D rb532_gpio_set_int_status,
-	},
-};
-
 int __init rb532_gpio_init(void)
 {
 	struct resource *r;
@@ -310,6 +261,12 @@ int __init rb532_gpio_init(void)
 		return -ENXIO;
 	}
=20
+	/* configure CF_GPIO_NUM as CFRDY IRQ source */
+	rb532_gpio_set_func(0, CF_GPIO_NUM);
+	rb532_gpio_direction_input(&rb532_gpio_chip->chip, CF_GPIO_NUM);
+	rb532_gpio_set_ilevel(1, CF_GPIO_NUM);
+	rb532_gpio_set_istat(0, CF_GPIO_NUM);
+
 	return 0;
 }
 arch_initcall(rb532_gpio_init);
--=20
1.5.6.4


