public inbox for linux-omap@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/9] twl4030 updates
@ 2008-09-26 11:19 Felipe Balbi
  2008-09-26 11:19 ` [PATCH 1/9] twl4030: fix potential null pointer dereference Felipe Balbi
                   ` (3 more replies)
  0 siblings, 4 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

Resending the series with madc conversion done and
another updates that I missed previously from Dave's
comments.

*** NOTE: I didn't test the madc changes (besides compile testing)
since I don't have code for testing that.

Maybe Mikko Ylinen could help us with that.

David Brownell (2):
  twl4030 gpio platform data
  twl4030 uses gpiolib

Felipe Balbi (6):
  twl4030: fix potential null pointer dereference
  i2c: clean add_children a bit
  i2c: move twl4030_keypad to new style registration
  i2c: move twl4030-usb to platform_device
  i2c: twl4030-usb: add 'vbus' sysfs file
  i2c: move twl4030-madc to new registration style

Jagadeesh Bhaskar Pakaravoor (1):
  twl4030-gpio: Remove default pullup enable/disable of GPIO

 arch/arm/mach-omap2/board-2430sdp.c         |   33 ++-
 arch/arm/mach-omap2/board-3430sdp.c         |   32 ++-
 arch/arm/mach-omap2/board-ldp.c             |   20 ++
 arch/arm/mach-omap2/board-omap2evm.c        |   34 ++-
 arch/arm/mach-omap2/board-omap3beagle.c     |   25 ++
 arch/arm/mach-omap2/board-omap3evm.c        |   86 ++++---
 arch/arm/mach-omap2/board-overo.c           |   13 +
 drivers/i2c/chips/Kconfig                   |   18 +--
 drivers/i2c/chips/twl4030-core.c            |  186 ++++++++++++--
 drivers/i2c/chips/twl4030-gpio.c            |  278 ++++++++++++++------
 drivers/i2c/chips/twl4030-madc.c            |  243 +++++++++++-------
 drivers/i2c/chips/twl4030-usb.c             |  373 ++++++++++++++-------------
 drivers/input/keyboard/omap-twl4030keypad.c |    8 +-
 include/linux/i2c/twl4030.h                 |   46 ++++-
 14 files changed, 922 insertions(+), 473 deletions(-)


^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 1/9] twl4030: fix potential null pointer dereference
  2008-09-26 11:19 [PATCH 0/9] twl4030 updates Felipe Balbi
@ 2008-09-26 11:19 ` Felipe Balbi
  2008-09-26 11:19   ` [PATCH 2/9] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
  2008-09-26 17:12 ` [PATCH 0/9] twl4030 updates David Brownell
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

The following patch fix a potential null pointer
dereference in twl4030 keypad driver when parts
of keypad platform_data aren't passed down to the
driver. At that point kp->dbg_dev is not set yet.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/input/keyboard/omap-twl4030keypad.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/input/keyboard/omap-twl4030keypad.c b/drivers/input/keyboard/omap-twl4030keypad.c
index 3893d63..48f29d3 100644
--- a/drivers/input/keyboard/omap-twl4030keypad.c
+++ b/drivers/input/keyboard/omap-twl4030keypad.c
@@ -238,7 +238,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
 		return -ENOMEM;
 
 	if (!pdata->rows || !pdata->cols || !pdata->keymap) {
-		dev_err(kp->dbg_dev, "No rows, cols or keymap from pdata\n");
+		dev_err(&pdev->dev, "No rows, cols or keymap from pdata\n");
 		kfree(kp);
 		return -EINVAL;
 	}
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 2/9] twl4030-gpio: Remove default pullup enable/disable of GPIO
  2008-09-26 11:19 ` [PATCH 1/9] twl4030: fix potential null pointer dereference Felipe Balbi
@ 2008-09-26 11:19   ` Felipe Balbi
  2008-09-26 11:19     ` [PATCH 3/9] i2c: clean add_children a bit Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap
  Cc: David Brownell, Tony Lindgren, Jagadeesh Bhaskar Pakaravoor,
	Girish S G

From: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>

One twl4030_request_gpio() should not tamper with the pullup
enabling/disabling of the rest of the GPIOs. So removing the default
pullup values written to REG_GPIOPUPDCTR1.

Signed-off-by: Girish S G <girishsg@ti.com>
Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
---
 drivers/i2c/chips/twl4030-gpio.c |    5 -----
 1 files changed, 0 insertions(+), 5 deletions(-)

diff --git a/drivers/i2c/chips/twl4030-gpio.c b/drivers/i2c/chips/twl4030-gpio.c
index 4d89abc..b51bed0 100644
--- a/drivers/i2c/chips/twl4030-gpio.c
+++ b/drivers/i2c/chips/twl4030-gpio.c
@@ -301,7 +301,6 @@ int twl4030_request_gpio(int gpio)
 	if (gpio_usage_count & (0x1 << gpio))
 		ret = -EBUSY;
 	else {
-		u8 clear_pull[6] = { 0, 0, 0, 0, 0, 0 };
 		/* First time usage? - switch on GPIO module */
 		if (!gpio_usage_count) {
 			ret =
@@ -311,10 +310,6 @@ int twl4030_request_gpio(int gpio)
 		}
 		if (!ret)
 			gpio_usage_count |= (0x1 << gpio);
-
-		ret =
-		twl4030_i2c_write(TWL4030_MODULE_GPIO, clear_pull,
-				REG_GPIOPUPDCTR1, 5);
 	}
 	up(&gpio_sem);
 	return ret;
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 3/9] i2c: clean add_children a bit
  2008-09-26 11:19   ` [PATCH 2/9] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
@ 2008-09-26 11:19     ` Felipe Balbi
  2008-09-26 11:19       ` [PATCH 4/9] i2c: move twl4030_keypad to new style registration Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

Clean up add_children a bit before adding more children
to twl4030-core.c

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/twl4030-core.c |   63 +++++++++++++++++++++----------------
 1 files changed, 36 insertions(+), 27 deletions(-)

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 47f65f8..e55f49e 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -45,6 +45,11 @@
 
 #define DRIVER_NAME			"twl4030"
 
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc()	true
+#else
+#define twl_has_rtc()	false
+#endif
 
 /* Primary Interrupt Handler on TWL4030 Registers */
 
@@ -639,34 +644,38 @@ static int add_children(struct twl4030_platform_data *pdata)
 	struct twl4030_client	*twl = NULL;
 	int			status = 0;
 
-#ifdef CONFIG_RTC_DRV_TWL4030
-	pdev = platform_device_alloc("twl4030_rtc", -1);
-	if (pdev) {
-		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
-		pdev->dev.parent = &twl->client->dev;
-		device_init_wakeup(&pdev->dev, 1);
-
-		/*
-		 * FIXME add the relevant IRQ resource, and make the
-		 * rtc driver use it instead of hard-wiring ...
-		 *
-		 * REVISIT platform_data here currently only supports
-		 * setting up the "msecure" line ... which actually
-		 * violates the "princple of least privilege", since
-		 * it's effectively always in "high trust" mode.
-		 *
-		 * For now, expect equivalent treatment at board init:
-		 * setting msecure high.  Eventually, Linux might
-		 * become more aware of those HW security concerns.
-		 */
-
-		status = platform_device_add(pdev);
-		if (status < 0)
-			platform_device_put(pdev);
-	} else
-		status = -ENOMEM;
-#endif
+	if (twl_has_rtc()) {
+		pdev = platform_device_alloc("twl4030_rtc", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+
+			/*
+			 * FIXME add the relevant IRQ resource, and make the
+			 * rtc driver use it instead of hard-wiring ...
+			 *
+			 * REVISIT platform_data here currently only supports
+			 * setting up the "msecure" line ... which actually
+			 * violates the "princple of least privilege", since
+			 * it's effectively always in "high trust" mode.
+			 *
+			 * For now, expect equivalent treatment at board init:
+			 * setting msecure high.  Eventually, Linux might
+			 * become more aware of those HW security concerns.
+			 */
+
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
 
+err:
+	pr_err("failed to add twl4030's children\n");
 	return status;
 }
 
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 4/9] i2c: move twl4030_keypad to new style registration
  2008-09-26 11:19     ` [PATCH 3/9] i2c: clean add_children a bit Felipe Balbi
@ 2008-09-26 11:19       ` Felipe Balbi
  2008-09-26 11:19         ` [PATCH 5/9] i2c: move twl4030-usb to platform_device Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

let twl4030-core.c take care of twl4030_keypad registration.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 arch/arm/mach-omap2/board-2430sdp.c         |   14 ++----
 arch/arm/mach-omap2/board-3430sdp.c         |   14 ++----
 arch/arm/mach-omap2/board-omap2evm.c        |   16 ++----
 arch/arm/mach-omap2/board-omap3evm.c        |   69 ++++++++++++--------------
 drivers/i2c/chips/twl4030-core.c            |   27 ++++++++++
 drivers/input/keyboard/omap-twl4030keypad.c |    6 +-
 include/linux/i2c/twl4030.h                 |   10 ++++
 7 files changed, 85 insertions(+), 71 deletions(-)

diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 3649a94..8c4c9dd 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -173,7 +173,7 @@ static int sdp2430_keymap[] = {
 	0
 };
 
-static struct omap_kp_platform_data sdp2430_kp_data = {
+static struct twl4030_keypad_data sdp2430_kp_data = {
 	.rows		= 5,
 	.cols		= 6,
 	.keymap		= sdp2430_keymap,
@@ -182,14 +182,6 @@ static struct omap_kp_platform_data sdp2430_kp_data = {
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
-static struct platform_device sdp2430_kp_device = {
-	.name		= "omap_twl4030keypad",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &sdp2430_kp_data,
-	},
-};
-
 static int __init msecure_init(void)
 {
 	int ret = 0;
@@ -216,7 +208,6 @@ out:
 static struct platform_device *sdp2430_devices[] __initdata = {
 	&sdp2430_smc91x_device,
 	&sdp2430_flash_device,
-	&sdp2430_kp_device,
 	&sdp2430_lcd_device,
 };
 
@@ -356,6 +347,9 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
 static struct twl4030_platform_data sdp2430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.keypad		= &sdp2430_kp_data,
 };
 
 static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 4c60d7b..fe1ba4e 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -110,7 +110,7 @@ static int sdp3430_keymap[] = {
 	0
 };
 
-static struct omap_kp_platform_data sdp3430_kp_data = {
+static struct twl4030_keypad_data sdp3430_kp_data = {
 	.rows		= 5,
 	.cols		= 6,
 	.keymap		= sdp3430_keymap,
@@ -119,14 +119,6 @@ static struct omap_kp_platform_data sdp3430_kp_data = {
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
-static struct platform_device sdp3430_kp_device = {
-	.name		= "omap_twl4030keypad",
-	.id		= -1,
-	.dev		= {
-		.platform_data	= &sdp3430_kp_data,
-	},
-};
-
 static int ts_gpio;
 
 static int __init msecure_init(void)
@@ -252,7 +244,6 @@ static struct platform_device sdp3430_lcd_device = {
 
 static struct platform_device *sdp3430_devices[] __initdata = {
 	&sdp3430_smc91x_device,
-	&sdp3430_kp_device,
 	&sdp3430_lcd_device,
 };
 
@@ -312,6 +303,9 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
 static struct twl4030_platform_data sdp3430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.keypad		= &sdp3430_kp_data,
 };
 
 static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index 6ce7740..d2a3743 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -200,23 +200,15 @@ static int omap2evm_keymap[] = {
 	KEY(3, 3, KEY_P)
 };
 
-static struct omap_kp_platform_data omap2evm_kp_data = {
+static struct twl4030_keypad_data omap2evm_kp_data = {
 	.rows		= 4,
 	.cols		= 4,
-	.keymap 	= omap2evm_keymap,
+	.keymap		= omap2evm_keymap,
 	.keymapsize	= ARRAY_SIZE(omap2evm_keymap),
 	.rep		= 1,
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
-static struct platform_device omap2evm_kp_device = {
-	.name		= "omap_twl4030keypad",
-	.id		= -1,
-	.dev		= {
-				.platform_data = &omap2evm_kp_data,
-			},
-};
-
 static void __init omap2_evm_init_irq(void)
 {
 	omap2_init_common_hw(NULL);
@@ -237,6 +229,9 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
 static struct twl4030_platform_data omap2evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.keypad		= &omap2evm_kp_data,
 };
 
 static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
@@ -259,7 +254,6 @@ static int __init omap2_evm_i2c_init(void)
 static struct platform_device *omap2_evm_devices[] __initdata = {
 	&omap2_evm_lcd_device,
 	&omap2evm_smc911x_device,
-	&omap2evm_kp_device,
 };
 
 static void __init omap2_evm_init(void)
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 6aa7e28..c4a969d 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,9 +90,41 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static int omap3evm_keymap[] = {
+	KEY(0, 0, KEY_LEFT),
+	KEY(0, 1, KEY_RIGHT),
+	KEY(0, 2, KEY_A),
+	KEY(0, 3, KEY_B),
+	KEY(1, 0, KEY_DOWN),
+	KEY(1, 1, KEY_UP),
+	KEY(1, 2, KEY_E),
+	KEY(1, 3, KEY_F),
+	KEY(2, 0, KEY_ENTER),
+	KEY(2, 1, KEY_I),
+	KEY(2, 2, KEY_J),
+	KEY(2, 3, KEY_K),
+	KEY(3, 0, KEY_M),
+	KEY(3, 1, KEY_N),
+	KEY(3, 2, KEY_O),
+	KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+	.rows		= 4,
+	.cols		= 4,
+	.keymap		= omap3evm_keymap,
+	.keymapsize	= ARRAY_SIZE(omap3evm_keymap),
+	.rep		= 1,
+	.irq		= TWL4030_MODIRQ_KEYPAD,
+};
+
+
 static struct twl4030_platform_data omap3evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.keypad		= &omap3evm_kp_data,
 };
 
 static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
@@ -168,42 +200,6 @@ struct spi_board_info omap3evm_spi_board_info[] = {
 	},
 };
 
-static int omap3evm_keymap[] = {
-	KEY(0, 0, KEY_LEFT),
-	KEY(0, 1, KEY_RIGHT),
-	KEY(0, 2, KEY_A),
-	KEY(0, 3, KEY_B),
-	KEY(1, 0, KEY_DOWN),
-	KEY(1, 1, KEY_UP),
-	KEY(1, 2, KEY_E),
-	KEY(1, 3, KEY_F),
-	KEY(2, 0, KEY_ENTER),
-	KEY(2, 1, KEY_I),
-	KEY(2, 2, KEY_J),
-	KEY(2, 3, KEY_K),
-	KEY(3, 0, KEY_M),
-	KEY(3, 1, KEY_N),
-	KEY(3, 2, KEY_O),
-	KEY(3, 3, KEY_P)
-};
-
-static struct omap_kp_platform_data omap3evm_kp_data = {
-	.rows		= 4,
-	.cols		= 4,
-	.keymap 	= omap3evm_keymap,
-	.keymapsize	= ARRAY_SIZE(omap3evm_keymap),
-	.rep		= 1,
-	.irq		= TWL4030_MODIRQ_KEYPAD,
-};
-
-static struct platform_device omap3evm_kp_device = {
-	.name		= "omap_twl4030keypad",
-	.id		= -1,
-	.dev		= {
-				.platform_data = &omap3evm_kp_data,
-			},
-};
-
 static void __init omap3_evm_init_irq(void)
 {
 	omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
@@ -219,7 +215,6 @@ static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
 
 static struct platform_device *omap3_evm_devices[] __initdata = {
 	&omap3_evm_lcd_device,
-	&omap3evm_kp_device,
 	&omap3evm_smc911x_device,
 };
 
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index e55f49e..0a2d8fe 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -51,6 +51,12 @@
 #define twl_has_rtc()	false
 #endif
 
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad()	true
+#else
+#define twl_has_keypad()	false
+#endif
+
 /* Primary Interrupt Handler on TWL4030 Registers */
 
 /* Register Definitions */
@@ -674,6 +680,27 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
+	if (twl_has_keypad() && pdata->keypad) {
+		pdev = platform_device_alloc("twl4030_keypad", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+			status = platform_device_add_data(pdev, pdata->keypad,
+					sizeof(*pdata->keypad));
+			if (status < 0) {
+				platform_device_put(pdev);
+				goto err;
+			}
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
+
 err:
 	pr_err("failed to add twl4030's children\n");
 	return status;
diff --git a/drivers/input/keyboard/omap-twl4030keypad.c b/drivers/input/keyboard/omap-twl4030keypad.c
index 48f29d3..eefdb78 100644
--- a/drivers/input/keyboard/omap-twl4030keypad.c
+++ b/drivers/input/keyboard/omap-twl4030keypad.c
@@ -38,7 +38,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/irq.h>
-#include <mach/keypad.h>
 #include "twl4030-keypad.h"
 
 #define PTV_PRESCALER		4
@@ -46,6 +45,7 @@
 #define MAX_ROWS		8 /* TWL4030 hardlimit */
 #define ROWCOL_MASK		0xFF000000
 #define KEYNUM_MASK		0x00FFFFFF
+#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
 
 /* Global variables */
 
@@ -231,7 +231,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
 	int i;
 	int ret = 0;
 	struct omap_keypad *kp;
-	struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
+	struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
 
 	kp = kzalloc(sizeof(*kp), GFP_KERNEL);
 	if (!kp)
@@ -389,7 +389,7 @@ static struct platform_driver omap_kp_driver = {
 	.probe		= omap_kp_probe,
 	.remove		= __devexit_p(omap_kp_remove),
 	.driver		= {
-		.name	= "omap_twl4030keypad",
+		.name	= "twl4030_keypad",
 		.owner	= THIS_MODULE,
 	},
 };
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 2434ad0..0ac417c 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -52,8 +52,18 @@
 #define TWL4030_MODULE_RTC		0x14
 #define TWL4030_MODULE_SECURED_REG	0x15
 
+struct twl4030_keypad_data {
+	int rows;
+	int cols;
+	int *keymap;
+	int irq;
+	unsigned int keymapsize;
+	unsigned int rep:1;
+};
+
 struct twl4030_platform_data {
 	unsigned	irq_base, irq_end;
+	struct twl4030_keypad_data *keypad;
 
 	/* REVISIT more to come ... _nothing_ should be hard-wired */
 };
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 5/9] i2c: move twl4030-usb to platform_device
  2008-09-26 11:19       ` [PATCH 4/9] i2c: move twl4030_keypad to new style registration Felipe Balbi
@ 2008-09-26 11:19         ` Felipe Balbi
  2008-09-26 11:19           ` [PATCH 6/9] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
  2008-09-28  1:01           ` [PATCH 5/9] i2c: move twl4030-usb to platform_device David Brownell
  0 siblings, 2 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

use new style twl4030-core to register a platform_device
for twl4030-usb.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 arch/arm/mach-omap2/board-2430sdp.c     |    6 +
 arch/arm/mach-omap2/board-3430sdp.c     |    5 +
 arch/arm/mach-omap2/board-ldp.c         |    7 +
 arch/arm/mach-omap2/board-omap2evm.c    |    5 +
 arch/arm/mach-omap2/board-omap3beagle.c |    7 +
 arch/arm/mach-omap2/board-omap3evm.c    |    6 +-
 drivers/i2c/chips/Kconfig               |   16 --
 drivers/i2c/chips/twl4030-core.c        |   27 +++
 drivers/i2c/chips/twl4030-usb.c         |  328 ++++++++++++++-----------------
 include/linux/i2c/twl4030.h             |   10 +
 10 files changed, 217 insertions(+), 200 deletions(-)

diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 8c4c9dd..f35c252 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -344,12 +344,18 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
 	{OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
 };
 
+
+static struct twl4030_usb_data sdp2430_usb_data = {
+	.usb_mode	= T2_MODE_ULPI,
+};
+
 static struct twl4030_platform_data sdp2430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &sdp2430_kp_data,
+	.usb		= &sdp2430_usb_data,
 };
 
 static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index fe1ba4e..e0c39c2 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -300,12 +300,17 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
 	{ OMAP_TAG_LCD,		&sdp3430_lcd_config },
 };
 
+static struct twl4030_usb_data sdp3430_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
 static struct twl4030_platform_data sdp3430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &sdp3430_kp_data,
+	.usb		= &sdp3430_usb_data,
 };
 
 static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index c07c712..219579b 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -183,9 +183,16 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
 	{ OMAP_TAG_UART,	&ldp_uart_config },
 };
 
+static struct twl4030_usb_data ldp_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.usb		= &ldp_usb_data,
 };
 
 static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index d2a3743..be8348d 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -226,12 +226,17 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
 	{ OMAP_TAG_LCD,		&omap2_evm_lcd_config },
 };
 
+static struct twl4030_usb_data omap2evm_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
 static struct twl4030_platform_data omap2evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &omap2evm_kp_data,
+	.usb		= &omap2evm_usb_data,
 };
 
 static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index fa8f5f6..ae677b9 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -110,9 +110,16 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_usb_data beagle_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
 static struct twl4030_platform_data beagle_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.usb		= &beagle_usb_data,
 };
 
 static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index c4a969d..158138c 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,6 +90,10 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_usb_data omap3evm_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
 static int omap3evm_keymap[] = {
 	KEY(0, 0, KEY_LEFT),
 	KEY(0, 1, KEY_RIGHT),
@@ -118,13 +122,13 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
-
 static struct twl4030_platform_data omap3evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &omap3evm_kp_data,
+	.usb		= &omap3evm_usb_data,
 };
 
 static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index e91be60..121aec9 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -186,22 +186,6 @@ config TWL4030_USB
 	tristate "TWL4030 USB Transceiver Driver"
 	depends on TWL4030_CORE
 
-choice
-	prompt "Transceiver mode"
-	depends on TWL4030_USB
-	help
-	  TWL4030 USB transceiver can operate in various
-	  mutually-exclusive modes. Select one of them.
-
-config TWL4030_USB_HS_ULPI
-	depends on TWL4030_USB
-	bool "High-speed ULPI"
-	help
-	  Say Y here if the TWL4030 is connected to high-speed USB
-	  controller through a ULPI interface.
-
-endchoice
-
 config TWL4030_PWRBUTTON
 	tristate "TWL4030 Power button Driver"
 	depends on TWL4030_CORE
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 0a2d8fe..02be771 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -57,6 +57,12 @@
 #define twl_has_keypad()	false
 #endif
 
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb()	true
+#else
+#define twl_has_usb()	false
+#endif
+
 /* Primary Interrupt Handler on TWL4030 Registers */
 
 /* Register Definitions */
@@ -701,6 +707,27 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
+	if (twl_has_usb() && pdata->usb) {
+		pdev = platform_device_alloc("twl4030_usb", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+			status = platform_device_add_data(pdev, pdata->usb,
+					sizeof(*pdata->usb));
+			if (status < 0) {
+				platform_device_put(pdev);
+				goto err;
+			}
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
+
 err:
 	pr_err("failed to add twl4030's children\n");
 	return status;
diff --git a/drivers/i2c/chips/twl4030-usb.c b/drivers/i2c/chips/twl4030-usb.c
index 2906b82..d150805 100644
--- a/drivers/i2c/chips/twl4030-usb.c
+++ b/drivers/i2c/chips/twl4030-usb.c
@@ -2,6 +2,8 @@
  * twl4030_usb - TWL4030 USB transceiver, talking to OMAP OTG controller
  *
  * Copyright (C) 2004-2007 Texas Instruments
+ * Copyright (C) 2008 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.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
@@ -22,11 +24,11 @@
  *	- 3-pin mode support may be added in future.
  */
 
-
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
+#include <linux/platform_device.h>
 #include <linux/io.h>
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
@@ -228,14 +230,6 @@
 #define VUSB3V1_TYPE			0x78
 #define VUSB3V1_REMAP			0x79
 
-#define ID_STATUS			0x96
-#define ID_RES_FLOAT			(1 << 4) /* mini-B */
-#define ID_RES_440K			(1 << 3) /* type 2 charger */
-#define ID_RES_200K			(1 << 2) /* 5-wire carkit or
-						    type 1 charger */
-#define ID_RES_102K			(1 << 1) /* phone */
-#define ID_RES_GND			(1 << 0) /* mini-A */
-
 /* In module TWL4030_MODULE_INTBR */
 #define PMBR1				0x0D
 #define GPIO_USB_4PIN_ULPI_2430C	(3 << 0)
@@ -250,11 +244,7 @@
 #define REG_PWR_SIH_CTRL		0x07
 #define COR				(1 << 2)
 
-/* internal define on top of container_of */
-#define xceiv_to_twl(x)		container_of((x), struct twl4030_usb, otg);
-
 /* bits in OTG_CTRL */
-
 #define	OTG_XCEIV_OUTPUTS \
 	(OTG_ASESSVLD|OTG_BSESSEND|OTG_BSESSVLD|OTG_VBUSVLD|OTG_ID)
 #define	OTG_XCEIV_INPUTS \
@@ -268,22 +258,23 @@
 	OTG_CTRL_BITS)
 
 
-/*-------------------------------------------------------------------------*/
-
 struct twl4030_usb {
 	struct otg_transceiver	otg;
+	struct device		*dev;
+
+	/* pin configuration */
+	enum twl4030_usb_mode	usb_mode;
 	int			irq;
-	u8			usb_mode;	/* pin configuration */
-#define T2_USB_MODE_ULPI		1
-/* #define T2_USB_MODE_CEA2011_3PIN	2 */
 	u8			asleep;
 };
 
-static struct twl4030_usb *the_transceiver;
+/* internal define on top of container_of */
+#define xceiv_to_twl(x)		container_of((x), struct twl4030_usb, otg);
 
 /*-------------------------------------------------------------------------*/
 
-static int twl4030_i2c_write_u8_verify(u8 module, u8 data, u8 address)
+static int twl4030_i2c_write_u8_verify(struct twl4030_usb *twl,
+		u8 module, u8 data, u8 address)
 {
 	u8 check;
 
@@ -297,46 +288,51 @@ static int twl4030_i2c_write_u8_verify(u8 module, u8 data, u8 address)
 						(check == data))
 		return 0;
 	/* Failed again: Return error */
+
 	return -EBUSY;
 }
 
-#define twl4030_usb_write_verify(address, data)	\
-	twl4030_i2c_write_u8_verify(TWL4030_MODULE_USB, (data), (address))
+#define twl4030_usb_write_verify(twl, address, data)	\
+	twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_USB, (data), (address))
 
-static inline int twl4030_usb_write(u8 address, u8 data)
+static inline int twl4030_usb_write(struct twl4030_usb *twl,
+		u8 address, u8 data)
 {
 	int ret = 0;
+
 	ret = twl4030_i2c_write_u8(TWL4030_MODULE_USB, data, address);
 	if (ret >= 0) {
 #if 0	/* debug */
 		u8 data1;
 		if (twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data1,
 					address) < 0)
-			printk(KERN_ERR "re-read failed\n");
+			dev_err(twl->dev, "re-read failed\n");
 		else
-			printk(KERN_INFO
+			dev_dbg(twl->dev,
 			       "Write %s wrote %x read %x from reg %x\n",
 			       (data1 == data) ? "succeed" : "mismatch",
 			       data, data1, address);
 #endif
 	} else {
-		printk(KERN_WARNING
+		dev_warn(twl->dev,
 			"TWL4030:USB:Write[0x%x] Error %d\n", address, ret);
 	}
+
 	return ret;
 }
 
-static inline int twl4030_usb_read(u8 address)
+static inline int twl4030_usb_read(struct twl4030_usb *twl, u8 address)
 {
 	u8 data;
 	int ret = 0;
+
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_USB, &data, address);
-	if (ret >= 0) {
+	if (ret >= 0)
 		ret = data;
-	} else {
-		printk(KERN_WARNING
+	else
+		dev_warn(twl->dev,
 			"TWL4030:USB:Read[0x%x] Error %d\n", address, ret);
-	}
+
 	return ret;
 }
 
@@ -345,14 +341,13 @@ static inline int twl4030_usb_read(u8 address)
 static inline int
 twl4030_usb_set_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 {
-	return twl4030_usb_write(reg + 1, bits);
+	return twl4030_usb_write(twl, reg + 1, bits);
 }
 
 static inline int
 twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 {
-	return twl4030_usb_write(reg + 2, bits);
-
+	return twl4030_usb_write(twl, reg + 2, bits);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -380,185 +375,130 @@ static void twl4030_usb_set_mode(struct twl4030_usb *twl, int mode)
 	};
 }
 
-#ifdef CONFIG_TWL4030_USB_HS_ULPI
-static void hs_usb_init(struct twl4030_usb *twl)
-{
-	twl->usb_mode = T2_USB_MODE_ULPI;
-	return;
-}
-
-#endif
-
-static void twl4030_i2c_access(int on)
+static void twl4030_i2c_access(struct twl4030_usb *twl, int on)
 {
 	unsigned long timeout;
-	int val = twl4030_usb_read(PHY_CLK_CTRL);
+	int val = twl4030_usb_read(twl, PHY_CLK_CTRL);
 
 	if (val >= 0) {
 		if (on) {
 			/* enable DPLL to access PHY registers over I2C */
 			val |= REQ_PHY_DPLL_CLK;
-			if (twl4030_usb_write_verify(PHY_CLK_CTRL,
-								(u8)val) < 0) {
-				printk(KERN_ERR "twl4030_usb: i2c write failed,"
-						" line %d\n", __LINE__);
-				return;
-			}
+			WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+						(u8)val) < 0);
 
 			timeout = jiffies + HZ;
-			while (!(twl4030_usb_read(PHY_CLK_CTRL_STS) &
+			while (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
 							PHY_DPLL_CLK)
 				&& time_before(jiffies, timeout))
 					udelay(10);
-			if (!(twl4030_usb_read(PHY_CLK_CTRL_STS) &
+			if (!(twl4030_usb_read(twl, PHY_CLK_CTRL_STS) &
 							PHY_DPLL_CLK))
-				printk(KERN_ERR "Timeout setting T2 HSUSB "
+				dev_err(twl->dev, "Timeout setting T2 HSUSB "
 						"PHY DPLL clock\n");
 		} else {
 			/* let ULPI control the DPLL clock */
 			val &= ~REQ_PHY_DPLL_CLK;
-			if (twl4030_usb_write_verify(PHY_CLK_CTRL,
-								(u8)val) < 0) {
-				printk(KERN_ERR "twl4030_usb: i2c write failed,"
-						" line %d\n", __LINE__);
-			}
+			WARN_ON(twl4030_usb_write_verify(twl, PHY_CLK_CTRL,
+						(u8)val) < 0);
 		}
 	}
-	return;
 }
 
-static void usb_irq_enable(int rising, int falling)
+static void usb_irq_enable(struct twl4030_usb *twl, int rising, int falling)
 {
 	u8 val;
 
 	/* edge setup */
-	if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c read failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&val, REG_PWR_EDR1) < 0);
+
 	val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
 	if (rising)
 		val = val | USB_PRES_RISING;
 	if (falling)
 		val = val | USB_PRES_FALLING;
-	if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
-							REG_PWR_EDR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c write failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+				val, REG_PWR_EDR1) < 0);
 
 	/* un-mask interrupt */
-	if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_IMR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c read failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&val, REG_PWR_IMR1) < 0);
+
 	val &= ~USB_PRES;
-	if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
-							REG_PWR_IMR1) < 0)
-		printk(KERN_ERR "twl4030_usb: i2c write failed,"
-				" line %d\n", __LINE__);
 
-	return;
+	WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+				val, REG_PWR_IMR1) < 0);
 }
 
-static void usb_irq_disable(void)
+static void usb_irq_disable(struct twl4030_usb *twl)
 {
 	u8 val;
 
 	/* undo edge setup */
-	if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c read failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&val, REG_PWR_EDR1) < 0);
 	val &= ~(USB_PRES_RISING | USB_PRES_FALLING);
-	if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
-							REG_PWR_EDR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c write failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+				val, REG_PWR_EDR1) < 0);
 
 	/* mask interrupt */
-	if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_IMR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c read failed,"
-				" line %d\n", __LINE__);
-		return;
-	}
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&val, REG_PWR_IMR1) < 0);
 	val |= USB_PRES;
-	if (twl4030_i2c_write_u8_verify(TWL4030_MODULE_INT, val,
-							REG_PWR_IMR1) < 0)
-		printk(KERN_ERR "twl4030_usb: i2c write failed,"
-				" line %d\n", __LINE__);
 
-	return;
+	WARN_ON(twl4030_i2c_write_u8_verify(twl, TWL4030_MODULE_INT,
+				val, REG_PWR_IMR1) < 0);
 }
 
 static void twl4030_phy_power(struct twl4030_usb *twl, int on)
 {
 	u8 pwr;
 
-	pwr = twl4030_usb_read(PHY_PWR_CTRL);
+	pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
 	if (on) {
 		pwr &= ~PHY_PWR_PHYPWD;
-		if (twl4030_usb_write_verify(PHY_PWR_CTRL, pwr) < 0) {
-			printk(KERN_ERR "twl4030_usb: i2c write failed,"
-					" line %d\n", __LINE__);
-			return;
-		}
-		twl4030_usb_write(PHY_CLK_CTRL,
-				  twl4030_usb_read(PHY_CLK_CTRL) |
+		WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+		twl4030_usb_write(twl, PHY_CLK_CTRL,
+				  twl4030_usb_read(twl, PHY_CLK_CTRL) |
 					(PHY_CLK_CTRL_CLOCKGATING_EN |
 						PHY_CLK_CTRL_CLK32K_EN));
 	} else  {
 		pwr |= PHY_PWR_PHYPWD;
-		if (twl4030_usb_write_verify(PHY_PWR_CTRL, pwr) < 0) {
-			printk(KERN_ERR "twl4030_usb: i2c write failed,"
-					" line %d\n", __LINE__);
-		}
+		WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
 	}
-	return;
 }
 
-static void twl4030_phy_suspend(int controller_off)
+static void twl4030_phy_suspend(struct twl4030_usb *twl, int controller_off)
 {
-	struct twl4030_usb *twl = the_transceiver;
-
 	if (controller_off)
-		usb_irq_disable();
+		usb_irq_disable(twl);
 
 	if (twl->asleep)
 		return;
 
 	if (!controller_off)
 		/* enable rising edge interrupt to detect cable attach */
-		usb_irq_enable(1, 0);
+		usb_irq_enable(twl, 1, 0);
 
 	twl4030_phy_power(twl, 0);
 	twl->asleep = 1;
-	return;
 }
 
-static void twl4030_phy_resume(void)
+static void twl4030_phy_resume(struct twl4030_usb *twl)
 {
-	struct twl4030_usb *twl = the_transceiver;
-
 	if (!twl->asleep)
 		return;
 
 	/* enable falling edge interrupt to detect cable detach */
-	usb_irq_enable(0, 1);
+	usb_irq_enable(twl, 0, 1);
 
 	twl4030_phy_power(twl, 1);
-	twl4030_i2c_access(1);
+	twl4030_i2c_access(twl, 1);
 	twl4030_usb_set_mode(twl, twl->usb_mode);
 	if (twl->usb_mode == T2_USB_MODE_ULPI)
-		twl4030_i2c_access(0);
+		twl4030_i2c_access(twl, 0);
 	twl->asleep = 0;
-	return;
 }
 
 static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
@@ -591,59 +531,57 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
 
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
-	int ret = IRQ_NONE;
+	struct twl4030_usb *twl = _twl;
 	u8 val;
 
 	/* action based on cable attach or detach */
-	if (twl4030_i2c_read_u8(TWL4030_MODULE_INT, &val, REG_PWR_EDR1) < 0) {
-		printk(KERN_ERR "twl4030_usb: i2c read failed,"
-				" line %d\n", __LINE__);
-		goto done;
-	}
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&val, REG_PWR_EDR1) < 0);
 
 	if (val & USB_PRES_RISING) {
-		twl4030_phy_resume();
+		twl4030_phy_resume(twl);
 		twl4030charger_usb_en(1);
 	} else {
 		twl4030charger_usb_en(0);
-		twl4030_phy_suspend(0);
+		twl4030_phy_suspend(twl, 0);
 	}
 
-	ret = IRQ_HANDLED;
-
-done:
-	return ret;
+	return IRQ_HANDLED;
 }
 
 static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
 {
+	struct twl4030_usb *twl = xceiv_to_twl(x);
+
 	if (suspend)
-		twl4030_phy_suspend(1);
+		twl4030_phy_suspend(twl, 1);
 	else
-		twl4030_phy_resume();
+		twl4030_phy_resume(twl);
 
 	return 0;
 }
 
-static int twl4030_set_peripheral(struct otg_transceiver *xceiv,
+static int twl4030_set_peripheral(struct otg_transceiver *x,
 		struct usb_gadget *gadget)
 {
+	struct twl4030_usb *twl;
 	u32 l;
-	struct twl4030_usb *twl = xceiv_to_twl(xceiv);
 
-	if (!xceiv)
+	if (!x)
 		return -ENODEV;
 
+	twl = xceiv_to_twl(x);
+
 	if (!gadget) {
 		omap_writew(0, OTG_IRQ_EN);
-		twl4030_phy_suspend(1);
+		twl4030_phy_suspend(twl, 1);
 		twl->otg.gadget = NULL;
 
 		return -ENODEV;
 	}
 
 	twl->otg.gadget = gadget;
-	twl4030_phy_resume();
+	twl4030_phy_resume(twl);
 
 	l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
 	l &= ~(OTG_XCEIV_OUTPUTS|OTG_CTRL_BITS);
@@ -660,23 +598,25 @@ static int twl4030_set_peripheral(struct otg_transceiver *xceiv,
 	return 0;
 }
 
-static int twl4030_set_host(struct otg_transceiver *xceiv, struct usb_bus *host)
+static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
 {
-	struct twl4030_usb *twl = xceiv_to_twl(xceiv);
+	struct twl4030_usb *twl;
 
-	if (!xceiv)
+	if (!x)
 		return -ENODEV;
 
+	twl = xceiv_to_twl(x);
+
 	if (!host) {
 		omap_writew(0, OTG_IRQ_EN);
-		twl4030_phy_suspend(1);
+		twl4030_phy_suspend(twl, 1);
 		twl->otg.host = NULL;
 
 		return -ENODEV;
 	}
 
 	twl->otg.host = host;
-	twl4030_phy_resume();
+	twl4030_phy_resume(twl);
 
 	twl4030_usb_set_bits(twl, TWL4030_OTG_CTRL,
 			TWL4030_OTG_CTRL_DMPULLDOWN
@@ -689,63 +629,65 @@ static int twl4030_set_host(struct otg_transceiver *xceiv, struct usb_bus *host)
 	return 0;
 }
 
-static int __init twl4030_usb_init(void)
+static int __init twl4030_usb_probe(struct platform_device *pdev)
 {
+	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
 	struct twl4030_usb	*twl;
 	int status;
 
-	if (the_transceiver)
-		return 0;
-
 	twl = kzalloc(sizeof *twl, GFP_KERNEL);
 	if (!twl)
-		return 0;
-
-	the_transceiver = twl;
+		return -ENOMEM;
 
+	twl->dev		= &pdev->dev;
 	twl->irq		= TWL4030_PWRIRQ_USB_PRES;
 	twl->otg.set_host	= twl4030_set_host;
 	twl->otg.set_peripheral	= twl4030_set_peripheral;
 	twl->otg.set_suspend	= twl4030_set_suspend;
 
-	usb_irq_disable();
+	if (!pdata) {
+		dev_info(&pdev->dev, "platform_data not available, defaulting"
+				" to ULPI mode\n");
+		twl->usb_mode		= T2_USB_MODE_ULPI;
+	} else {
+		twl->usb_mode	= pdata->usb_mode;
+	}
+
+	usb_irq_disable(twl);
 	status = request_irq(twl->irq, twl4030_usb_irq, 0, "twl4030_usb", twl);
 	if (status < 0) {
-		printk(KERN_DEBUG "can't get IRQ %d, err %d\n",
+		dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
 			twl->irq, status);
 		kfree(twl);
-		return -ENODEV;
+		return status;
 	}
 
-#if defined(CONFIG_TWL4030_USB_HS_ULPI)
-	hs_usb_init(twl);
-#endif
+
 	twl4030_usb_ldo_init(twl);
 	twl4030_phy_power(twl, 1);
-	twl4030_i2c_access(1);
+	twl4030_i2c_access(twl, 1);
 	twl4030_usb_set_mode(twl, twl->usb_mode);
-	if (twl->usb_mode == T2_USB_MODE_ULPI)
-		twl4030_i2c_access(0);
 
 	twl->asleep = 0;
 
-	if (twl->usb_mode == T2_USB_MODE_ULPI)
-		twl4030_phy_suspend(1);
+	if (twl->usb_mode == T2_USB_MODE_ULPI) {
+		twl4030_i2c_access(twl, 0);
+		twl4030_phy_suspend(twl, 0);
+	}
 
 	otg_set_transceiver(&twl->otg);
-
-	printk(KERN_INFO "Initialized TWL4030 USB module\n");
+	platform_set_drvdata(pdev, twl);
+	dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
 
 	return 0;
 }
 
-
-static void __exit twl4030_usb_exit(void)
+static int __exit twl4030_usb_remove(struct platform_device *pdev)
 {
-	struct twl4030_usb *twl = the_transceiver;
+	struct twl4030_usb *twl = platform_get_drvdata(pdev);
 	int val;
 
-	usb_irq_disable();
+	usb_irq_disable(twl);
 	free_irq(twl->irq, twl);
 
 	/* set transceiver mode to power on defaults */
@@ -755,11 +697,11 @@ static void __exit twl4030_usb_exit(void)
 	 * clear dpll clock request for i2c access,
 	 * disable 32KHz
 	 */
-	val = twl4030_usb_read(PHY_CLK_CTRL);
+	val = twl4030_usb_read(twl, PHY_CLK_CTRL);
 	if (val >= 0) {
 		val |= PHY_CLK_CTRL_CLOCKGATING_EN;
 		val &= ~(PHY_CLK_CTRL_CLK32K_EN | REQ_PHY_DPLL_CLK);
-		twl4030_usb_write(PHY_CLK_CTRL, (u8)val);
+		twl4030_usb_write(twl, PHY_CLK_CTRL, (u8)val);
 	}
 
 	/* disable complete OTG block */
@@ -768,12 +710,32 @@ static void __exit twl4030_usb_exit(void)
 	twl4030_phy_power(twl, 0);
 
 	kfree(twl);
+
+	return 0;
 }
 
-subsys_initcall(twl4030_usb_init);
+static struct platform_driver twl4030_driver = {
+	.probe		= twl4030_usb_probe,
+	.remove		= __exit_p(twl4030_remove),
+	.driver		= {
+		.name	= "twl4030_usb",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init twl4030_usb_init(void)
+{
+	return platform_driver_register(&twl4030_driver);
+}
+module_init(twl4030_usb_init);
+
+static void __exit twl4030_usb_exit(void)
+{
+	platform_driver_unregister(&twl4030_driver);
+}
 module_exit(twl4030_usb_exit);
 
-MODULE_ALIAS("i2c:twl4030-usb");
-MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_ALIAS("platform:twl4030_usb");
+MODULE_AUTHOR("Texas Instruments, Inc, Nokia Corporation");
 MODULE_DESCRIPTION("TWL4030 USB transceiver driver");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 0ac417c..8a12ff0 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -61,9 +61,19 @@ struct twl4030_keypad_data {
 	unsigned int rep:1;
 };
 
+enum twl4030_usb_mode {
+	T2_USB_MODE_ULPI = 1,
+	T2_USB_MODE_CEA2011_3PIN = 2,
+};
+
+struct twl4030_usb_data {
+	enum twl4030_usb_mode	usb_mode;
+};
+
 struct twl4030_platform_data {
 	unsigned	irq_base, irq_end;
 	struct twl4030_keypad_data *keypad;
+	struct twl4030_usb_data *usb;
 
 	/* REVISIT more to come ... _nothing_ should be hard-wired */
 };
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 6/9] i2c: twl4030-usb: add 'vbus' sysfs file
  2008-09-26 11:19         ` [PATCH 5/9] i2c: move twl4030-usb to platform_device Felipe Balbi
@ 2008-09-26 11:19           ` Felipe Balbi
  2008-09-26 11:19             ` [PATCH 7/9] twl4030 gpio platform data Felipe Balbi
  2008-09-28  1:01           ` [PATCH 5/9] i2c: move twl4030-usb to platform_device David Brownell
  1 sibling, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

vbus sysfs file will report the state of vbus irq coming from
twl4030-usb.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/twl4030-usb.c |   51 ++++++++++++++++++++++++++++++++++++++-
 1 files changed, 50 insertions(+), 1 deletions(-)

diff --git a/drivers/i2c/chips/twl4030-usb.c b/drivers/i2c/chips/twl4030-usb.c
index d150805..3a5aa52 100644
--- a/drivers/i2c/chips/twl4030-usb.c
+++ b/drivers/i2c/chips/twl4030-usb.c
@@ -29,6 +29,8 @@
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
 #include <linux/io.h>
 #include <linux/usb.h>
 #include <linux/usb/ch9.h>
@@ -259,11 +261,17 @@
 
 
 struct twl4030_usb {
+	struct work_struct	irq_work;
 	struct otg_transceiver	otg;
 	struct device		*dev;
 
+	/* for vbus reporting with irqs disabled */
+	spinlock_t		lock;
+
 	/* pin configuration */
 	enum twl4030_usb_mode	usb_mode;
+
+	unsigned		vbus:1;
 	int			irq;
 	u8			asleep;
 };
@@ -529,6 +537,29 @@ static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
 }
 
+static ssize_t twl4030_usb_vbus_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct twl4030_usb *twl = dev_get_drvdata(dev);
+	unsigned long flags;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&twl->lock, flags);
+	ret = sprintf(buf, "%s\n", twl->vbus ? "on" : "off");
+	spin_unlock_irqrestore(&twl->lock, flags);
+
+	return ret;
+}
+static DEVICE_ATTR(vbus, 0444, twl4030_usb_vbus_show, NULL);
+
+static void twl4030_usb_irq_work(struct work_struct *work)
+{
+	struct twl4030_usb *twl = container_of(work,
+			struct twl4030_usb, irq_work);
+
+	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
+}
+
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
 	struct twl4030_usb *twl = _twl;
@@ -541,10 +572,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 	if (val & USB_PRES_RISING) {
 		twl4030_phy_resume(twl);
 		twl4030charger_usb_en(1);
+		twl->vbus = 1;
 	} else {
 		twl4030charger_usb_en(0);
+		twl->vbus = 0;
 		twl4030_phy_suspend(twl, 0);
 	}
+	schedule_work(&twl->irq_work);
 
 	return IRQ_HANDLED;
 }
@@ -634,16 +668,22 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
 	struct twl4030_usb	*twl;
 	int status;
+	u8			vbus;
 
 	twl = kzalloc(sizeof *twl, GFP_KERNEL);
 	if (!twl)
 		return -ENOMEM;
 
+	WARN_ON(twl4030_i2c_read_u8(TWL4030_MODULE_INT,
+				&vbus, REG_PWR_EDR1) < 0);
+	vbus &= USB_PRES_RISING;
+
 	twl->dev		= &pdev->dev;
 	twl->irq		= TWL4030_PWRIRQ_USB_PRES;
 	twl->otg.set_host	= twl4030_set_host;
 	twl->otg.set_peripheral	= twl4030_set_peripheral;
 	twl->otg.set_suspend	= twl4030_set_suspend;
+	twl->vbus		= vbus ? 1 : 0;
 
 	if (!pdata) {
 		dev_info(&pdev->dev, "platform_data not available, defaulting"
@@ -653,6 +693,12 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 		twl->usb_mode	= pdata->usb_mode;
 	}
 
+	/* init spinlock for workqueue */
+	spin_lock_init(&twl->lock);
+
+	/* init irq workqueue before request_irq */
+	INIT_WORK(&twl->irq_work, twl4030_usb_irq_work);
+
 	usb_irq_disable(twl);
 	status = request_irq(twl->irq, twl4030_usb_irq, 0, "twl4030_usb", twl);
 	if (status < 0) {
@@ -662,7 +708,6 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 		return status;
 	}
 
-
 	twl4030_usb_ldo_init(twl);
 	twl4030_phy_power(twl, 1);
 	twl4030_i2c_access(twl, 1);
@@ -679,6 +724,9 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 	platform_set_drvdata(pdev, twl);
 	dev_info(&pdev->dev, "Initialized TWL4030 USB module\n");
 
+	if (device_create_file(&pdev->dev, &dev_attr_vbus))
+		dev_warn(&pdev->dev, "could not create sysfs file\n");
+
 	return 0;
 }
 
@@ -689,6 +737,7 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
 
 	usb_irq_disable(twl);
 	free_irq(twl->irq, twl);
+	device_remove_file(twl->dev, &dev_attr_vbus);
 
 	/* set transceiver mode to power on defaults */
 	twl4030_usb_set_mode(twl, -1);
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 7/9] twl4030 gpio platform data
  2008-09-26 11:19           ` [PATCH 6/9] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-26 11:19             ` Felipe Balbi
  2008-09-26 11:19               ` [PATCH 8/9] twl4030 uses gpiolib Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

From: David Brownell <dbrownell@users.sourceforge.net>

Define platform data for configuring TWL4030 GPIOs,
and provide it for all boards using these chips.

For now all boards use the same fixed assignments for
GPIO and IRQ numbers.  Eventually we should be able
to shuffle them without changing platform headers.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 arch/arm/mach-omap2/board-2430sdp.c     |    7 +++++++
 arch/arm/mach-omap2/board-3430sdp.c     |    7 +++++++
 arch/arm/mach-omap2/board-ldp.c         |    7 +++++++
 arch/arm/mach-omap2/board-omap2evm.c    |    7 +++++++
 arch/arm/mach-omap2/board-omap3beagle.c |   12 ++++++++++++
 arch/arm/mach-omap2/board-omap3evm.c    |    7 +++++++
 arch/arm/mach-omap2/board-overo.c       |    7 +++++++
 include/linux/i2c/twl4030.h             |   24 +++++++++++++++++++++---
 8 files changed, 75 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index f35c252..0deaf09 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -345,6 +345,12 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
 };
 
 
+static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_usb_data sdp2430_usb_data = {
 	.usb_mode	= T2_MODE_ULPI,
 };
@@ -354,6 +360,7 @@ static struct twl4030_platform_data sdp2430_twldata = {
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
+	.gpio		= &sdp2430_gpio_data,
 	.keypad		= &sdp2430_kp_data,
 	.usb		= &sdp2430_usb_data,
 };
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index e0c39c2..66f0f98 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -300,6 +300,12 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
 	{ OMAP_TAG_LCD,		&sdp3430_lcd_config },
 };
 
+static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_usb_data sdp3430_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
@@ -309,6 +315,7 @@ static struct twl4030_platform_data sdp3430_twldata = {
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
+	.gpio		= &sdp3430_gpio_data,
 	.keypad		= &sdp3430_kp_data,
 	.usb		= &sdp3430_usb_data,
 };
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 219579b..48342f4 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -187,12 +187,19 @@ static struct twl4030_usb_data ldp_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_gpio_platform_data ldp_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.usb		= &ldp_usb_data,
+	.gpio		= &ldp_gpio_data,
 };
 
 static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index be8348d..a921cf1 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -226,6 +226,12 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
 	{ OMAP_TAG_LCD,		&omap2_evm_lcd_config },
 };
 
+static struct twl4030_gpio_platform_data omap2evm_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_usb_data omap2evm_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
@@ -237,6 +243,7 @@ static struct twl4030_platform_data omap2evm_twldata = {
 	/* platform_data for children goes here */
 	.keypad		= &omap2evm_kp_data,
 	.usb		= &omap2evm_usb_data,
+	.gpio		= &omap2evm_gpio_data,
 };
 
 static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index ae677b9..aa5e9a6 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -114,12 +114,24 @@ static struct twl4030_usb_data beagle_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_gpio_platform_data beagle_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+
+	/* REVISIT:  setup() should use twl gpio index
+	 *  - 0 as MMC card detect,
+	 *  - 1 as EHCI port overcurrent (active low)
+	 */
+};
+
 static struct twl4030_platform_data beagle_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.usb		= &beagle_usb_data,
+	.gpio		= &beagle_gpio_data,
 };
 
 static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 158138c..2c1d76f 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,6 +90,12 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_usb_data omap3evm_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
@@ -129,6 +135,7 @@ static struct twl4030_platform_data omap3evm_twldata = {
 	/* platform_data for children goes here */
 	.keypad		= &omap3evm_kp_data,
 	.usb		= &omap3evm_usb_data,
+	.gpio		= &omap3evm_gpio_data,
 };
 
 static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index a41e6fa..9c1709a 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -146,9 +146,16 @@ static struct omap_uart_config overo_uart_config __initdata = {
 	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2)),
 };
 
+static struct twl4030_gpio_platform_data overo_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+};
+
 static struct twl4030_platform_data overo_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
+	.gpio		= &overo_gpio_data,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 8a12ff0..b80e8b6 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -52,6 +52,21 @@
 #define TWL4030_MODULE_RTC		0x14
 #define TWL4030_MODULE_SECURED_REG	0x15
 
+
+/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
+struct twl4030_gpio_platform_data {
+	int		gpio_base;
+	unsigned	irq_base, irq_end;
+
+	/* for gpio-N, bit (1 << N) is set if pullup should be used */
+	u32		pullups;
+
+	int		(*setup)(struct device *dev,
+				unsigned gpio, unsigned ngpio);
+	int		(*teardown)(struct device *dev,
+				unsigned gpio, unsigned ngpio);
+};
+
 struct twl4030_keypad_data {
 	int rows;
 	int cols;
@@ -71,9 +86,10 @@ struct twl4030_usb_data {
 };
 
 struct twl4030_platform_data {
-	unsigned	irq_base, irq_end;
-	struct twl4030_keypad_data *keypad;
-	struct twl4030_usb_data *usb;
+	unsigned				irq_base, irq_end;
+	struct twl4030_gpio_platform_data	*gpio;
+	struct twl4030_keypad_data		*keypad;
+	struct twl4030_usb_data			*usb;
 
 	/* REVISIT more to come ... _nothing_ should be hard-wired */
 };
@@ -151,6 +167,8 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
 
 /*
  * Exported TWL4030 GPIO APIs
+ *
+ * WARNING -- use standard GPIO and IRQ calls instead; these will vanish.
  */
 int twl4030_get_gpio_datain(int gpio);
 int twl4030_request_gpio(int gpio);
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 8/9] twl4030 uses gpiolib
  2008-09-26 11:19             ` [PATCH 7/9] twl4030 gpio platform data Felipe Balbi
@ 2008-09-26 11:19               ` Felipe Balbi
  2008-09-26 11:19                 ` [PATCH 9/9] i2c: move twl4030-madc to new registration style Felipe Balbi
  2008-09-26 17:10                 ` [PATCH 8/9] twl4030 uses gpiolib David Brownell
  0 siblings, 2 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren

From: David Brownell <dbrownell@users.sourceforge.net>

Make the twl4030 core create a platform device to which its
GPIO code will bind, with platform_data used to configure
board-specific behaviors and configuration.

Update the twl4030 GPIO code:

  - Morph its gpio function code into a platform driver.

  - Move away from IRQ (and GPIO) numbers hard-wired in headers.

  - Hook up the twl4030 GPIO code to gpiolib.

  - Start phasing out the older TWL-specific calls ... currently
    those are used only by arch/arm/mach-omap2/hsmmc.c setup code.

  - Use a mutex for locking, not a binary semaphore.

NOTE:  more patches pending:  (a) this doesn't use pdata->pullups
to initialize (currently hsmmc code always sets GPIO-0 pullup even
if the board has an external pullup);  (b) there's a new gpio
request/free hook forthcoming in 2.6.28, which this should use;
(c) likewise there's a new gpio_to_irq() hook; (d) the irq_chip
set_type() mechanism needs to be supported; (e) needs to move over
to drivers/gpio; (f) upcoming threaded IRQ infrastructure should
be used, when that merges.

NYET-Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
NYET-Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/Kconfig        |    2 +-
 drivers/i2c/chips/twl4030-core.c |   44 ++++++
 drivers/i2c/chips/twl4030-gpio.c |  273 +++++++++++++++++++++++++++-----------
 3 files changed, 238 insertions(+), 81 deletions(-)

diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 121aec9..1a21388 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -159,7 +159,7 @@ config TWL4030_CORE
 
 config TWL4030_GPIO
 	bool "TWL4030 GPIO Driver"
-	depends on TWL4030_CORE
+	depends on TWL4030_CORE && GPIOLIB
 
 config TWL4030_MADC
 	tristate "TWL4030 MADC Driver"
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 02be771..c9460f7 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -63,6 +63,12 @@
 #define twl_has_usb()	false
 #endif
 
+#ifdef CONFIG_TWL4030_GPIO
+#define twl_has_gpio()	true
+#else
+#define twl_has_gpio()	false
+#endif
+
 /* Primary Interrupt Handler on TWL4030 Registers */
 
 /* Register Definitions */
@@ -656,6 +662,44 @@ static int add_children(struct twl4030_platform_data *pdata)
 	struct twl4030_client	*twl = NULL;
 	int			status = 0;
 
+	if (twl_has_gpio() && pdata->gpio) {
+		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM1];
+
+		pdev = platform_device_alloc("twl4030_gpio", -1);
+		if (!pdev)
+			status = -ENOMEM;
+
+		/* more driver model init */
+		if (status == 0) {
+			pdev->dev.parent = &twl->client->dev;
+			/* device_init_wakeup(&pdev->dev, 1); */
+
+			status = platform_device_add_data(pdev, pdata->gpio,
+					sizeof(*pdata->gpio));
+		}
+
+		/* GPIO module IRQ */
+		if (status == 0) {
+			struct resource	r = {
+				.start = pdata->irq_base + 0,
+				.flags = IORESOURCE_IRQ,
+			};
+
+			status = platform_device_add_resources(pdev, &r, 1);
+		}
+
+		if (status == 0)
+			status = platform_device_add(pdev);
+
+		if (status < 0) {
+			platform_device_put(pdev);
+			dev_dbg(&twl->client->dev,
+					"can't create gpio dev, %d\n",
+					status);
+			goto err;
+		}
+	}
+
 	if (twl_has_rtc()) {
 		pdev = platform_device_alloc("twl4030_rtc", -1);
 		if (pdev) {
diff --git a/drivers/i2c/chips/twl4030-gpio.c b/drivers/i2c/chips/twl4030-gpio.c
index b51bed0..0d4dd28 100644
--- a/drivers/i2c/chips/twl4030-gpio.c
+++ b/drivers/i2c/chips/twl4030-gpio.c
@@ -31,22 +31,31 @@
 #include <linux/init.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
-#include <linux/random.h>
-#include <linux/syscalls.h>
+#include <linux/device.h>
 #include <linux/kthread.h>
 #include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
 
-#include <linux/i2c.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/i2c/twl4030-gpio.h>
-#include <linux/slab.h>
 
 #include <mach/irqs.h>
 #include <asm/mach/irq.h>
 #include <mach/gpio.h>
 #include <mach/mux.h>
 
-#include <linux/device.h>
+
+/* REVISIT when these symbols vanish elsewhere, remove them here too */
+#undef TWL4030_GPIO_IRQ_BASE
+#undef TWL4030_GPIO_IRQ_END
+#undef TWL4030_MODIRQ_GPIO
+
+static struct gpio_chip twl_gpiochip;
+static int twl4030_gpio_irq_base;
+static int twl4030_gpio_irq_end;
+
 
 /* BitField Definitions */
 
@@ -130,7 +139,7 @@
 #define GPIO_32_MASK			0x0003ffff
 
 /* Data structures */
-static struct semaphore gpio_sem;
+static DEFINE_MUTEX(gpio_lock);
 
 /* store usage of each GPIO. - each bit represents one GPIO */
 static unsigned int gpio_usage_count;
@@ -147,7 +156,7 @@ static struct task_struct *gpio_unmask_thread;
 /*
  * Helper functions to read and write the GPIO ISR and IMR registers as
  * 32-bit integers. Functions return 0 on success, non-zero otherwise.
- * The caller must hold a lock on gpio_sem.
+ * The caller must hold gpio_lock.
  */
 
 static int gpio_read_isr(unsigned int *isr)
@@ -197,25 +206,25 @@ static int gpio_write_imr(unsigned int imr)
  */
 static void twl4030_gpio_mask_and_ack(unsigned int irq)
 {
-	int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+	int gpio = irq - twl4030_gpio_irq_base;
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	/* mask */
 	gpio_imr_shadow |= (1 << gpio);
 	gpio_write_imr(gpio_imr_shadow);
 	/* ack */
 	gpio_write_isr(1 << gpio);
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 }
 
 static void twl4030_gpio_unmask(unsigned int irq)
 {
-	int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+	int gpio = irq - twl4030_gpio_irq_base;
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	gpio_imr_shadow &= ~(1 << gpio);
 	gpio_write_imr(gpio_imr_shadow);
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 }
 
 /*
@@ -234,7 +243,7 @@ static void twl4030_gpio_mask_irqchip(unsigned int irq) {}
 
 static void twl4030_gpio_unmask_irqchip(unsigned int irq)
 {
-	int gpio = irq - TWL4030_GPIO_IRQ_BASE;
+	int gpio = irq - twl4030_gpio_irq_base;
 
 	gpio_pending_unmask |= (1 << gpio);
 	if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
@@ -242,7 +251,7 @@ static void twl4030_gpio_unmask_irqchip(unsigned int irq)
 }
 
 static struct irq_chip twl4030_gpio_irq_chip = {
-	.name	= "twl4030-gpio",
+	.name	= "twl4030",
 	.ack	= twl4030_gpio_mask_and_ack_irqchip,
 	.mask	= twl4030_gpio_mask_irqchip,
 	.unmask	= twl4030_gpio_unmask_irqchip,
@@ -297,21 +306,26 @@ int twl4030_request_gpio(int gpio)
 	if (unlikely(gpio >= TWL4030_GPIO_MAX))
 		return -EPERM;
 
-	down(&gpio_sem);
-	if (gpio_usage_count & (0x1 << gpio))
+	ret = gpio_request(twl_gpiochip.base + gpio, NULL);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&gpio_lock);
+	if (gpio_usage_count & (0x1 << gpio)) {
 		ret = -EBUSY;
-	else {
+	} else {
 		/* First time usage? - switch on GPIO module */
 		if (!gpio_usage_count) {
-			ret =
-			gpio_twl4030_write(REG_GPIO_CTRL,
+			ret = gpio_twl4030_write(REG_GPIO_CTRL,
 					MASK_GPIO_CTRL_GPIO_ON);
 			ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
 		}
 		if (!ret)
 			gpio_usage_count |= (0x1 << gpio);
+		else
+			gpio_free(twl_gpiochip.base + gpio);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
 EXPORT_SYMBOL(twl4030_request_gpio);
@@ -326,18 +340,20 @@ int twl4030_free_gpio(int gpio)
 	if (unlikely(gpio >= TWL4030_GPIO_MAX))
 		return -EPERM;
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 
-	if ((gpio_usage_count & (0x1 << gpio)) == 0)
+	if ((gpio_usage_count & (0x1 << gpio)) == 0) {
 		ret = -EPERM;
-	else
+	} else {
 		gpio_usage_count &= ~(0x1 << gpio);
+		gpio_free(twl_gpiochip.base + gpio);
+	}
 
 	/* Last time usage? - switch off GPIO module */
-	if (!gpio_usage_count)
+	if (ret == 0 && !gpio_usage_count)
 		ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
 
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
 EXPORT_SYMBOL(twl4030_free_gpio);
@@ -345,21 +361,18 @@ EXPORT_SYMBOL(twl4030_free_gpio);
 /*
  * Set direction for TWL4030 GPIO
  */
-int twl4030_set_gpio_direction(int gpio, int is_input)
+static int twl4030_set_gpio_direction(int gpio, int is_input)
 {
 	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
 	u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
 	u8 reg = 0;
-	u8 base = 0;
+	u8 base = REG_GPIODATADIR1 + d_bnk;
 	int ret = 0;
 
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))))
+	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
 		return -EPERM;
 
-	base = REG_GPIODATADIR1 + d_bnk;
-
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(base);
 	if (ret >= 0) {
 		if (is_input)
@@ -369,23 +382,21 @@ int twl4030_set_gpio_direction(int gpio, int is_input)
 
 		ret = gpio_twl4030_write(base, reg);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
-EXPORT_SYMBOL(twl4030_set_gpio_direction);
 
 /*
  * To enable/disable GPIO pin on TWL4030
  */
-int twl4030_set_gpio_dataout(int gpio, int enable)
+static int twl4030_set_gpio_dataout(int gpio, int enable)
 {
 	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
 	u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
 	u8 base = 0;
 	int ret = 0;
 
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))))
+	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
 		return -EPERM;
 
 	if (enable)
@@ -393,12 +404,11 @@ int twl4030_set_gpio_dataout(int gpio, int enable)
 	else
 		base = REG_CLEARGPIODATAOUT1 + d_bnk;
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_write(base, d_msk);
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
-EXPORT_SYMBOL(twl4030_set_gpio_dataout);
 
 /*
  * To get the status of a GPIO pin on TWL4030
@@ -415,9 +425,9 @@ int twl4030_get_gpio_datain(int gpio)
 		return -EPERM;
 
 	base = REG_GPIODATAIN1 + d_bnk;
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(base);
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	if (ret > 0)
 		ret = (ret >> d_off) & 0x1;
 
@@ -425,6 +435,7 @@ int twl4030_get_gpio_datain(int gpio)
 }
 EXPORT_SYMBOL(twl4030_get_gpio_datain);
 
+#if 0
 /*
  * Configure PULL type for a GPIO pin on TWL4030
  */
@@ -447,7 +458,7 @@ int twl4030_set_gpio_pull(int gpio, int pull_dircn)
 	else if (pull_dircn == TWL4030_GPIO_PULL_UP)
 		c_msk = MASK_GPIOPUPDCTR1_GPIOxPU(c_off);
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(base);
 	if (ret >= 0) {
 		/* clear the previous up/down values */
@@ -457,13 +468,15 @@ int twl4030_set_gpio_pull(int gpio, int pull_dircn)
 		reg |= c_msk;
 		ret = gpio_twl4030_write(base, reg);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
-EXPORT_SYMBOL(twl4030_set_gpio_pull);
+#endif
 
 /*
  * Configure Edge control for a GPIO pin on TWL4030
+ *
+ * FIXME this should just be the irq_chip.set_type() method
  */
 int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
 {
@@ -486,7 +499,7 @@ int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
 	if (edge & TWL4030_GPIO_EDGE_FALLING)
 		c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(base);
 	if (ret >= 0) {
 		/* clear the previous rising/falling values */
@@ -497,7 +510,7 @@ int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
 		reg |= c_msk;
 		ret = gpio_twl4030_write(base, reg);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
 EXPORT_SYMBOL(twl4030_set_gpio_edge_ctrl);
@@ -518,7 +531,7 @@ int twl4030_set_gpio_debounce(int gpio, int enable)
 		return -EPERM;
 
 	base = REG_GPIO_DEBEN1 + d_bnk;
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(base);
 	if (ret >= 0) {
 		if (enable)
@@ -528,11 +541,12 @@ int twl4030_set_gpio_debounce(int gpio, int enable)
 
 		ret = gpio_twl4030_write(base, reg);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return ret;
 }
 EXPORT_SYMBOL(twl4030_set_gpio_debounce);
 
+#if 0
 /*
  * Configure Card detect for GPIO pin on TWL4030
  */
@@ -549,7 +563,7 @@ int twl4030_set_gpio_card_detect(int gpio, int enable)
 		return -EPERM;
 	}
 
-	down(&gpio_sem);
+	mutex_lock(&gpio_lock);
 	ret = gpio_twl4030_read(REG_GPIO_CTRL);
 	if (ret >= 0) {
 		if (enable)
@@ -559,10 +573,10 @@ int twl4030_set_gpio_card_detect(int gpio, int enable)
 
 		ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
 	}
-	up(&gpio_sem);
+	mutex_unlock(&gpio_lock);
 	return (ret);
 }
-EXPORT_SYMBOL(twl4030_set_gpio_card_detect);
+#endif
 
 /* MODULE FUNCTIONS */
 
@@ -590,7 +604,7 @@ static int twl4030_gpio_unmask_thread(void *data)
 		gpio_pending_unmask = 0;
 		local_irq_enable();
 
-		for (irq = TWL4030_GPIO_IRQ_BASE; 0 != gpio_unmask;
+		for (irq = twl4030_gpio_irq_base; 0 != gpio_unmask;
 				gpio_unmask >>= 1, irq++) {
 			if (gpio_unmask & 0x1)
 				twl4030_gpio_unmask(irq);
@@ -677,12 +691,12 @@ static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
 		kstat_cpu(cpu).irqs[irq]++;
 		local_irq_enable();
 
-		down(&gpio_sem);
+		mutex_lock(&gpio_lock);
 		if (gpio_read_isr(&gpio_isr))
 			gpio_isr = 0;
-		up(&gpio_sem);
+		mutex_unlock(&gpio_lock);
 
-		for (gpio_irq = TWL4030_GPIO_IRQ_BASE; 0 != gpio_isr;
+		for (gpio_irq = twl4030_gpio_irq_base; 0 != gpio_isr;
 			gpio_isr >>= 1, gpio_irq++) {
 			if (gpio_isr & 0x1) {
 				irq_desc_t *d = irq_desc + gpio_irq;
@@ -698,19 +712,60 @@ static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
 	}
 }
 
-/* TWL4030 Initialization module */
-static int __init gpio_twl4030_init(void)
+/*----------------------------------------------------------------------*/
+
+static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	return twl4030_set_gpio_direction(offset, 1);
+}
+
+static int twl_get(struct gpio_chip *chip, unsigned offset)
+{
+	int status = twl4030_get_gpio_datain(offset);
+
+	return (status < 0) ? 0 : status;
+}
+
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	twl4030_set_gpio_dataout(offset, value);
+	return twl4030_set_gpio_direction(offset, 0);
+}
+
+static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
 {
+	twl4030_set_gpio_dataout(offset, value);
+}
+
+static struct gpio_chip twl_gpiochip = {
+	.label			= "twl4030",
+	.owner			= THIS_MODULE,
+	.direction_input	= twl_direction_in,
+	.get			= twl_get,
+	.direction_output	= twl_direction_out,
+	.set			= twl_set,
+	.can_sleep		= 1,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int gpio_twl4030_remove(struct platform_device *pdev);
+
+static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
+{
+	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
 	int ret;
 	int irq = 0;
 
-	/* init the global locking sem */
-	sema_init(&gpio_sem, 1);
-
 	/* All GPIO interrupts are initially masked */
 	gpio_pending_unmask = 0;
 	gpio_imr_shadow = GPIO_32_MASK;
 	ret = gpio_write_imr(gpio_imr_shadow);
+
+	twl4030_gpio_irq_base = pdata->irq_base;
+	twl4030_gpio_irq_end = pdata->irq_end;
+
+	/* REVISIT skip most of this if the irq range is empty... */
 	if (!ret) {
 		/*
 		 * Create a kernel thread to handle deferred unmasking of gpio
@@ -719,50 +774,88 @@ static int __init gpio_twl4030_init(void)
 		gpio_unmask_thread = kthread_create(twl4030_gpio_unmask_thread,
 			NULL, "twl4030 gpio");
 		if (!gpio_unmask_thread) {
-			printk(KERN_ERR
-				"%s: could not create twl4030 gpio unmask"
-				" thread!\n", __func__);
+			dev_err(&pdev->dev,
+				"could not create twl4030 gpio unmask"
+				" thread!\n");
 			ret = -ENOMEM;
 		}
 	}
 
 	if (!ret) {
 		/* install an irq handler for each of the gpio interrupts */
-		for (irq = TWL4030_GPIO_IRQ_BASE; irq < TWL4030_GPIO_IRQ_END;
-			irq++) {
+		for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end;
+				irq++) {
 			set_irq_chip(irq, &twl4030_gpio_irq_chip);
 			set_irq_handler(irq, do_twl4030_gpio_irq);
 			set_irq_flags(irq, IRQF_VALID);
 		}
 
+		/* gpio module IRQ */
+		irq = platform_get_irq(pdev, 0);
+
 		/*
 		 * Install an irq handler to demultiplex the gpio module
 		 * interrupt.
 		 */
-		set_irq_chip(TWL4030_MODIRQ_GPIO,
-			&twl4030_gpio_module_irq_chip);
-		set_irq_chained_handler(TWL4030_MODIRQ_GPIO,
-			do_twl4030_gpio_module_irq);
+		set_irq_chip(irq, &twl4030_gpio_module_irq_chip);
+		set_irq_chained_handler(irq, do_twl4030_gpio_module_irq);
 		wake_up_process(gpio_unmask_thread);
+
+		dev_info(&pdev->dev, "IRQ %d chains IRQs %d..%d\n", irq,
+			twl4030_gpio_irq_base, twl4030_gpio_irq_end - 1);
+	}
+
+	if (!ret) {
+		twl_gpiochip.base = pdata->gpio_base;
+		twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
+		twl_gpiochip.dev = &pdev->dev;
+
+		ret = gpiochip_add(&twl_gpiochip);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+					"could not register gpiochip, %d\n",
+					ret);
+			twl_gpiochip.ngpio = 0;
+			gpio_twl4030_remove(pdev);
+		} else if (pdata->setup) {
+			int status;
+
+			status = pdata->setup(&pdev->dev,
+					pdata->gpio_base, TWL4030_GPIO_MAX);
+			if (status)
+				dev_dbg(&pdev->dev, "setup --> %d\n", status);
+		}
 	}
 
-	printk(KERN_INFO "TWL4030 GPIO Demux: IRQ Range %d to %d,"
-		" Initialization %s\n", TWL4030_GPIO_IRQ_BASE,
-		TWL4030_GPIO_IRQ_END, (ret) ? "Failed" : "Success");
 	return ret;
 }
 
-/* TWL GPIO exit module */
-static void __exit gpio_twl4030_exit(void)
+static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
 {
+	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+	int status;
 	int irq;
 
+	if (pdata->teardown) {
+		status = pdata->teardown(&pdev->dev,
+				pdata->gpio_base, TWL4030_GPIO_MAX);
+		if (status) {
+			dev_dbg(&pdev->dev, "teardown --> %d\n", status);
+			return status;
+		}
+	}
+
+	status = gpiochip_remove(&twl_gpiochip);
+	if (status < 0)
+		return status;
+
 	/* uninstall the gpio demultiplexing interrupt handler */
-	set_irq_handler(TWL4030_MODIRQ_GPIO, NULL);
-	set_irq_flags(TWL4030_MODIRQ_GPIO, 0);
+	irq = platform_get_irq(pdev, 0);
+	set_irq_handler(irq, NULL);
+	set_irq_flags(irq, 0);
 
 	/* uninstall the irq handler for each of the gpio interrupts */
-	for (irq = TWL4030_GPIO_IRQ_BASE; irq < TWL4030_GPIO_IRQ_END; irq++) {
+	for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end; irq++) {
 		set_irq_handler(irq, NULL);
 		set_irq_flags(irq, 0);
 	}
@@ -772,12 +865,32 @@ static void __exit gpio_twl4030_exit(void)
 		kthread_stop(gpio_unmask_thread);
 		gpio_unmask_thread = NULL;
 	}
+
+	return 0;
 }
 
+/* Note:  this hardware lives inside an I2C-based multi-function device. */
+MODULE_ALIAS("platform:twl4030_gpio");
+
+static struct platform_driver gpio_twl4030_driver = {
+	.driver.name	= "twl4030_gpio",
+	.driver.owner	= THIS_MODULE,
+	.probe		= gpio_twl4030_probe,
+	.remove		= __devexit_p(gpio_twl4030_remove),
+};
+
+static int __init gpio_twl4030_init(void)
+{
+	return platform_driver_register(&gpio_twl4030_driver);
+}
 module_init(gpio_twl4030_init);
+
+static void __exit gpio_twl4030_exit(void)
+{
+	platform_driver_unregister(&gpio_twl4030_driver);
+}
 module_exit(gpio_twl4030_exit);
 
-MODULE_ALIAS("i2c:twl4030-gpio");
 MODULE_AUTHOR("Texas Instruments, Inc.");
 MODULE_DESCRIPTION("GPIO interface for TWL4030");
 MODULE_LICENSE("GPL");
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 11:19               ` [PATCH 8/9] twl4030 uses gpiolib Felipe Balbi
@ 2008-09-26 11:19                 ` Felipe Balbi
  2008-09-26 17:09                   ` David Brownell
  2008-09-26 19:50                   ` David Brownell
  2008-09-26 17:10                 ` [PATCH 8/9] twl4030 uses gpiolib David Brownell
  1 sibling, 2 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 11:19 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi, Mikko Ylinen

Moving twl4030-madc to new style registration just like
the other twl4030 children.

Cc: Mikko Ylinen <mikko.k.ylinen@nokia.com>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 arch/arm/mach-omap2/board-2430sdp.c     |    6 +
 arch/arm/mach-omap2/board-3430sdp.c     |    6 +
 arch/arm/mach-omap2/board-ldp.c         |    6 +
 arch/arm/mach-omap2/board-omap2evm.c    |    6 +
 arch/arm/mach-omap2/board-omap3beagle.c |    6 +
 arch/arm/mach-omap2/board-omap3evm.c    |    6 +
 arch/arm/mach-omap2/board-overo.c       |    6 +
 drivers/i2c/chips/twl4030-core.c        |   27 ++++
 drivers/i2c/chips/twl4030-madc.c        |  243 +++++++++++++++++++------------
 include/linux/i2c/twl4030.h             |    6 +
 10 files changed, 227 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 0deaf09..d7f2bb9 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -355,12 +355,18 @@ static struct twl4030_usb_data sdp2430_usb_data = {
 	.usb_mode	= T2_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data sdp2430_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data sdp2430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.gpio		= &sdp2430_gpio_data,
+	.madc		= &sdp2430_madc_data,
 	.keypad		= &sdp2430_kp_data,
 	.usb		= &sdp2430_usb_data,
 };
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 66f0f98..096550a 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -310,12 +310,18 @@ static struct twl4030_usb_data sdp3430_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data sdp3430_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data sdp3430_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.gpio		= &sdp3430_gpio_data,
+	.madc		= &sdp3430_madc_data,
 	.keypad		= &sdp3430_kp_data,
 	.usb		= &sdp3430_usb_data,
 };
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 48342f4..8b92f0d 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -193,11 +193,17 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = {
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 };
 
+static struct twl4030_madc_platform_data ldp_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data ldp_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
+	.madc		= &ldp_madc_data,
 	.usb		= &ldp_usb_data,
 	.gpio		= &ldp_gpio_data,
 };
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index a921cf1..9f57fe0 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -236,12 +236,18 @@ static struct twl4030_usb_data omap2evm_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data omap2evm_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data omap2evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &omap2evm_kp_data,
+	.madc		= &omap2evm_madc_data,
 	.usb		= &omap2evm_usb_data,
 	.gpio		= &omap2evm_gpio_data,
 };
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index aa5e9a6..ba6e87a 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -114,6 +114,11 @@ static struct twl4030_usb_data beagle_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data beagle_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_gpio_platform_data beagle_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -130,6 +135,7 @@ static struct twl4030_platform_data beagle_twldata = {
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
+	.madc		= &beagle_madc_data,
 	.usb		= &beagle_usb_data,
 	.gpio		= &beagle_gpio_data,
 };
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 2c1d76f..865c585 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -128,12 +128,18 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data omap3evm_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
 	.keypad		= &omap3evm_kp_data,
+	.madc		= &omap3evm_madc_data,
 	.usb		= &omap3evm_usb_data,
 	.gpio		= &omap3evm_gpio_data,
 };
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index 9c1709a..e0fd1d8 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -152,10 +152,16 @@ static struct twl4030_gpio_platform_data overo_gpio_data = {
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 };
 
+static struct twl4030_madc_platform_data overo_madc_data = {
+	.imr		= TWL4030_MADC_IMR1,
+	.isr		= TWL4030_MADC_ISR1,
+};
+
 static struct twl4030_platform_data overo_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 	.gpio		= &overo_gpio_data,
+	.madc		= &overo_madc_data,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index c9460f7..79d4d82 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -69,6 +69,12 @@
 #define twl_has_gpio()	false
 #endif
 
+#if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
+#define twl_has_madc()	true
+#else
+#define twl_has_madc()	false
+#endif
+
 /* Primary Interrupt Handler on TWL4030 Registers */
 
 /* Register Definitions */
@@ -772,6 +778,27 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
+	if (twl_has_madc() && pdata->madc) {
+		pdev = platform_device_alloc("twl4030_madc", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+			status = platform_device_add_data(pdev, pdata->madc,
+					sizeof(*pdata->madc));
+			if (status < 0) {
+				platform_device_put(pdev);
+				goto err;
+			}
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
+
 err:
 	pr_err("failed to add twl4030's children\n");
 	return status;
diff --git a/drivers/i2c/chips/twl4030-madc.c b/drivers/i2c/chips/twl4030-madc.c
index 743db74..6cd8669 100644
--- a/drivers/i2c/chips/twl4030-madc.c
+++ b/drivers/i2c/chips/twl4030-madc.c
@@ -29,6 +29,7 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/fs.h>
+#include <linux/platform_device.h>
 #include <linux/miscdevice.h>
 #include <linux/i2c/twl4030.h>
 #include <linux/i2c/twl4030-madc.h>
@@ -37,13 +38,16 @@
 
 #define TWL4030_MADC_PFX	"twl4030-madc: "
 
-static struct twl4030_madc_data {
+struct twl4030_madc_data {
+	struct device		*dev;
 	struct mutex		lock;
 	struct work_struct	ws;
 	struct twl4030_madc_request	requests[TWL4030_MADC_NUM_METHODS];
-} twl4030_madc;
+	int imr;
+	int isr;
+};
 
-static const char irq_pin = 1; /* XXX Read from platfrom data */
+static struct twl4030_madc_data *the_madc;
 
 static
 const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
@@ -66,35 +70,43 @@ const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
 	},
 };
 
-static void twl4030_madc_read(u8 reg, u8 *val)
+static int twl4030_madc_read(struct twl4030_madc_data *madc, u8 reg)
 {
-	int ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, val, reg);
-	if (ret)
-		printk(KERN_ERR TWL4030_MADC_PFX
-		       "unable to read register 0x%X\n", reg);
+	int ret;
+	u8 val;
+
+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MADC, &val, reg);
+	if (ret) {
+		dev_dbg(madc->dev, "unable to read register 0x%X\n", reg);
+		return ret;
+	}
+
+	return val;
 }
 
-static void twl4030_madc_write(u8 reg, u8 val)
+static void twl4030_madc_write(struct twl4030_madc_data *madc, u8 reg, u8 val)
 {
-	int ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
+	int ret;
+
+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_MADC, val, reg);
 	if (ret)
-		printk(KERN_ERR TWL4030_MADC_PFX
-		       "unable to write register 0x%X\n", reg);
+		dev_err(madc->dev, "unable to write register 0x%X\n", reg);
 }
 
-static int twl4030_madc_channel_raw_read(u8 reg)
+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
 {
 	u8 msb, lsb;
 
 	/* For each ADC channel, we have MSB and LSB register pair. MSB address
 	 * is always LSB address+1. reg parameter is the addr of LSB register */
-	twl4030_madc_read(reg+1, &msb);
-	twl4030_madc_read(reg, &lsb);
+	msb = twl4030_madc_read(madc, reg + 1);
+	lsb = twl4030_madc_read(madc, reg);
 
 	return (int)(((msb << 8) | lsb) >> 6);
 }
 
-static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf)
+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
+		u8 reg_base, u16 channels, int *buf)
 {
 	int count = 0;
 	u8 reg, i;
@@ -105,47 +117,40 @@ static int twl4030_madc_read_channels(u8 reg_base, u16 channels, int *buf)
 	for (i = 0; i < TWL4030_MADC_MAX_CHANNELS; i++) {
 		if (channels & (1<<i)) {
 			reg = reg_base + 2*i;
-			buf[i] = twl4030_madc_channel_raw_read(reg);
+			buf[i] = twl4030_madc_channel_raw_read(madc, reg);
 			count++;
 		}
 	}
 	return count;
 }
 
-static void twl4030_madc_enable_irq(int id)
+static void twl4030_madc_enable_irq(struct twl4030_madc_data *madc, int id)
 {
 	u8 val;
 
-	static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
-
-	twl4030_madc_read(imr, &val);
+	val = twl4030_madc_read(madc, madc->imr);
 	val &= ~(1 << id);
-	twl4030_madc_write(imr, val);
+	twl4030_madc_write(madc, madc->imr, val);
 }
 
-static void twl4030_madc_disable_irq(int id)
+static void twl4030_madc_disable_irq(struct twl4030_madc_data *madc, int id)
 {
 	u8 val;
 
-	static u8 imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
-
-	twl4030_madc_read(imr, &val);
+	val = twl4030_madc_read(madc, madc->imr);
 	val |= (1 << id);
-	twl4030_madc_write(imr, val);
+	twl4030_madc_write(madc, madc->imr, val);
 }
 
-static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
+static irqreturn_t twl4030_madc_irq_handler(int irq, void *_madc)
 {
+	struct twl4030_madc_data *madc = _madc;
 	u8 isr_val, imr_val;
-	static u8 isr, imr;
 	int i;
 
-	imr = (irq_pin == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
-	isr = (irq_pin == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
-
 	/* Use COR to ack interrupts since we have no shared IRQs in ISRx */
-	twl4030_madc_read(isr, &isr_val);
-	twl4030_madc_read(imr, &imr_val);
+	isr_val = twl4030_madc_read(madc, madc->isr);
+	imr_val = twl4030_madc_read(madc, madc->imr);
 
 	isr_val &= ~imr_val;
 
@@ -154,11 +159,11 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
 		if (!(isr_val & (1<<i)))
 			continue;
 
-		twl4030_madc_disable_irq(i);
-		twl4030_madc.requests[i].result_pending = 1;
+		twl4030_madc_disable_irq(madc, i);
+		madc->requests[i].result_pending = 1;
 	}
 
-	schedule_work(&twl4030_madc.ws);
+	schedule_work(&madc->ws);
 
 	return IRQ_HANDLED;
 }
@@ -166,14 +171,16 @@ static irqreturn_t twl4030_madc_irq_handler(int irq, void *madc_dev)
 static void twl4030_madc_work(struct work_struct *ws)
 {
 	const struct twl4030_madc_conversion_method *method;
+	struct twl4030_madc_data *madc;
 	struct twl4030_madc_request *r;
 	int len, i;
 
-	mutex_lock(&twl4030_madc.lock);
+	madc = container_of(ws, struct twl4030_madc_data, ws);
+	mutex_lock(&madc->lock);
 
 	for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
 
-		r = &twl4030_madc.requests[i];
+		r = &madc->requests[i];
 
 		/* No pending results for this method, move to next one */
 		if (!r->result_pending)
@@ -182,7 +189,7 @@ static void twl4030_madc_work(struct work_struct *ws)
 		method = &twl4030_conversion_methods[r->method];
 
 		/* Read results */
-		len = twl4030_madc_read_channels(method->rbase,
+		len = twl4030_madc_read_channels(madc, method->rbase,
 						 r->channels, r->rbuf);
 
 		/* Return results to caller */
@@ -196,23 +203,25 @@ static void twl4030_madc_work(struct work_struct *ws)
 		r->active	  = 0;
 	}
 
-	mutex_unlock(&twl4030_madc.lock);
+	mutex_unlock(&madc->lock);
 }
 
-static int twl4030_madc_set_irq(struct twl4030_madc_request *req)
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+		struct twl4030_madc_request *req)
 {
 	struct twl4030_madc_request *p;
 
-	p = &twl4030_madc.requests[req->method];
+	p = &madc->requests[req->method];
 
 	memcpy(p, req, sizeof *req);
 
-	twl4030_madc_enable_irq(req->method);
+	twl4030_madc_enable_irq(madc, req->method);
 
 	return 0;
 }
 
-static inline void twl4030_madc_start_conversion(int conv_method)
+static inline void twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+		int conv_method)
 {
 	const struct twl4030_madc_conversion_method *method;
 
@@ -221,7 +230,7 @@ static inline void twl4030_madc_start_conversion(int conv_method)
 	switch (conv_method) {
 	case TWL4030_MADC_SW1:
 	case TWL4030_MADC_SW2:
-		twl4030_madc_write(method->ctrl, TWL4030_MADC_SW_START);
+		twl4030_madc_write(madc, method->ctrl, TWL4030_MADC_SW_START);
 		break;
 	case TWL4030_MADC_RT:
 	default:
@@ -229,14 +238,16 @@ static inline void twl4030_madc_start_conversion(int conv_method)
 	}
 }
 
-static void twl4030_madc_wait_conversion_ready_ms(u8 *time, u8 status_reg)
+static void twl4030_madc_wait_conversion_ready_ms(
+		struct twl4030_madc_data *madc,
+		u8 *time, u8 status_reg)
 {
 	u8 reg = 0;
 
 	do {
 		msleep(1);
 		(*time)--;
-		twl4030_madc_read(status_reg, &reg);
+		reg = twl4030_madc_read(madc, status_reg);
 	} while (((reg & TWL4030_MADC_BUSY) && !(reg & TWL4030_MADC_EOC_SW)) &&
 		  (*time != 0));
 }
@@ -251,7 +262,7 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
 		return -EINVAL;
 
 	/* Do we have a conversion request ongoing */
-	if (twl4030_madc.requests[req->method].active)
+	if (the_madc->requests[req->method].active)
 		return -EBUSY;
 
 	ch_msb = (req->channels >> 8) & 0xff;
@@ -259,22 +270,22 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
 
 	method = &twl4030_conversion_methods[req->method];
 
-	mutex_lock(&twl4030_madc.lock);
+	mutex_lock(&the_madc->lock);
 
 	/* Select channels to be converted */
-	twl4030_madc_write(method->sel + 1, ch_msb);
-	twl4030_madc_write(method->sel, ch_lsb);
+	twl4030_madc_write(the_madc, method->sel + 1, ch_msb);
+	twl4030_madc_write(the_madc, method->sel, ch_lsb);
 
 	/* Select averaging for all channels if do_avg is set */
 	if (req->do_avg) {
-		twl4030_madc_write(method->avg + 1, ch_msb);
-		twl4030_madc_write(method->avg, ch_lsb);
+		twl4030_madc_write(the_madc, method->avg + 1, ch_msb);
+		twl4030_madc_write(the_madc, method->avg, ch_lsb);
 	}
 
 	if ((req->type == TWL4030_MADC_IRQ_ONESHOT) && (req->func_cb != NULL)) {
-		twl4030_madc_set_irq(req);
-		twl4030_madc_start_conversion(req->method);
-		twl4030_madc.requests[req->method].active = 1;
+		twl4030_madc_set_irq(the_madc, req);
+		twl4030_madc_start_conversion(the_madc, req->method);
+		the_madc->requests[req->method].active = 1;
 		ret = 0;
 		goto out;
 	}
@@ -285,32 +296,33 @@ int twl4030_madc_conversion(struct twl4030_madc_request *req)
 		goto out;
 	}
 
-	twl4030_madc_start_conversion(req->method);
-	twl4030_madc.requests[req->method].active = 1;
+	twl4030_madc_start_conversion(the_madc, req->method);
+	the_madc->requests[req->method].active = 1;
 
 	/* Wait until conversion is ready (ctrl register returns EOC) */
 	wait_time = 50;
-	twl4030_madc_wait_conversion_ready_ms(&wait_time, method->ctrl);
+	twl4030_madc_wait_conversion_ready_ms(the_madc,
+			&wait_time, method->ctrl);
 	if (wait_time == 0) {
-		printk(KERN_ERR TWL4030_MADC_PFX "conversion timeout!\n");
+		dev_dbg(the_madc->dev, "conversion timeout!\n");
 		ret = -EAGAIN;
 		goto out;
 	}
 
-	ret = twl4030_madc_read_channels(method->rbase, req->channels,
+	ret = twl4030_madc_read_channels(the_madc, method->rbase, req->channels,
 					 req->rbuf);
 
-	twl4030_madc.requests[req->method].active = 0;
+	the_madc->requests[req->method].active = 0;
 
 out:
-	mutex_unlock(&twl4030_madc.lock);
+	mutex_unlock(&the_madc->lock);
 
 	return ret;
 }
-
 EXPORT_SYMBOL(twl4030_madc_conversion);
 
-static int twl4030_madc_set_current_generator(int chan, int on)
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+		int chan, int on)
 {
 	int ret;
 	u8 regval;
@@ -332,16 +344,16 @@ static int twl4030_madc_set_current_generator(int chan, int on)
 	return ret;
 }
 
-static int twl4030_madc_set_power(int on)
+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
 {
 	u8 regval;
 
-	twl4030_madc_read(TWL4030_MADC_CTRL1, &regval);
+	regval = twl4030_madc_read(madc, TWL4030_MADC_CTRL1);
 	if (on)
 		regval |= TWL4030_MADC_MADCON;
 	else
 		regval &= ~TWL4030_MADC_MADCON;
-	twl4030_madc_write(TWL4030_MADC_CTRL1, regval);
+	twl4030_madc_write(madc, TWL4030_MADC_CTRL1, regval);
 
 	return 0;
 }
@@ -354,7 +366,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
 
 	ret = copy_from_user(&par, (void __user *) arg, sizeof(par));
 	if (ret) {
-		printk(KERN_ERR TWL4030_MADC_PFX "copy_from_user: %d\n", ret);
+		dev_dbg(the_madc->dev, "copy_from_user: %d\n", ret);
 		return -EACCES;
 	}
 
@@ -364,7 +376,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
 		if (par.channel >= TWL4030_MADC_MAX_CHANNELS)
 			return -EINVAL;
 
-		req.channels = (1<<par.channel);
+		req.channels = (1 << par.channel);
 		req.do_avg	= par.average;
 		req.method	= TWL4030_MADC_SW1;
 		req.func_cb	= NULL;
@@ -384,7 +396,7 @@ static int twl4030_madc_ioctl(struct inode *inode, struct file *filp,
 
 	ret = copy_to_user((void __user *) arg, &par, sizeof(par));
 	if (ret) {
-		printk(KERN_ERR TWL4030_MADC_PFX "copy_to_user: %d\n", ret);
+		dev_dbg(the_madc->dev, "copy_to_user: %d\n", ret);
 		return -EACCES;
 	}
 
@@ -398,22 +410,37 @@ static struct file_operations twl4030_madc_fileops = {
 
 static struct miscdevice twl4030_madc_device = {
 	.minor = MISC_DYNAMIC_MINOR,
-	.name = "twl4030-adc",
+	.name = "twl4030-madc",
 	.fops = &twl4030_madc_fileops
 };
 
-static int __init twl4030_madc_init(void)
+static int __init twl4030_madc_probe(struct platform_device *pdev)
 {
+	struct twl4030_madc_data *madc;
+	struct twl4030_madc_platform_data *pdata = pdev->dev.platform_data;
 	int ret;
 	u8 regval;
 
+	madc = kzalloc(sizeof *madc, GFP_KERNEL);
+	if (!madc)
+		return -ENOMEM;
+
+	if (!pdata) {
+		dev_dbg(&pdev->dev, "platform_data not available\n");
+		ret = -EINVAL;
+		goto err_pdata;
+	}
+
+	madc->imr = pdata->imr;
+	madc->isr = pdata->isr;
+
 	ret = misc_register(&twl4030_madc_device);
-	if (ret == -1) {
-		printk(KERN_ERR TWL4030_MADC_PFX "misc_register() failed!\n");
-		return ret;
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not register misc_device\n");
+		goto err_misc;
 	}
-	twl4030_madc_set_power(1);
-	twl4030_madc_set_current_generator(0, 1);
+	twl4030_madc_set_power(madc, 1);
+	twl4030_madc_set_current_generator(madc, 0, 1);
 
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
 				  &regval, TWL4030_BCI_BCICTL1);
@@ -424,32 +451,66 @@ static int __init twl4030_madc_init(void)
 				   regval, TWL4030_BCI_BCICTL1);
 
 	ret = request_irq(TWL4030_MODIRQ_MADC, twl4030_madc_irq_handler,
-			  IRQF_DISABLED, "twl4030_madc", &twl4030_madc);
-	if (ret)
-		printk(KERN_ERR TWL4030_MADC_PFX "request_irq: %d\n", ret);
+			  IRQF_DISABLED, "twl4030_madc", madc);
+	if (ret) {
+		dev_dbg(&pdev->dev, "could not request irq\n");
+		goto err_irq;
+	}
 
-	mutex_init(&twl4030_madc.lock);
+	platform_set_drvdata(pdev, madc);
+	mutex_init(&madc->lock);
+	INIT_WORK(&madc->ws, twl4030_madc_work);
 
-	INIT_WORK(&twl4030_madc.ws, twl4030_madc_work);
+	the_madc = madc;
 
-	printk(KERN_INFO TWL4030_MADC_PFX "initialised\n");
+	return 0;
+
+err_irq:
+	misc_deregister(&twl4030_madc_device);
+
+err_misc:
+err_pdata:
+	kfree(madc);
 
 	return ret;
 }
 
-static void __exit twl4030_madc_exit(void)
+static int __exit twl4030_madc_remove(struct platform_device *pdev)
 {
-	twl4030_madc_set_power(0);
-	twl4030_madc_set_current_generator(0, 0);
-	free_irq(TWL4030_MODIRQ_MADC, &twl4030_madc);
-	cancel_work_sync(&twl4030_madc.ws);
+	struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
+
+	twl4030_madc_set_power(madc, 0);
+	twl4030_madc_set_current_generator(madc, 0, 0);
+	free_irq(TWL4030_MODIRQ_MADC, madc);
+	cancel_work_sync(&madc->ws);
 	misc_deregister(&twl4030_madc_device);
+
+	return 0;
 }
 
+static struct platform_driver twl4030_madc_driver = {
+	.probe		= twl4030_madc_probe,
+	.remove		= __exit_p(twl4030_madc_remove),
+	.driver		= {
+		.name	= "twl4030_madc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init twl4030_madc_init(void)
+{
+	return platform_driver_register(&twl4030_madc_driver);
+}
 module_init(twl4030_madc_init);
+
+static void __exit twl4030_madc_exit(void)
+{
+	platform_driver_unregister(&twl4030_madc_driver);
+}
 module_exit(twl4030_madc_exit);
 
-MODULE_ALIAS("i2c:twl4030-adc");
+MODULE_ALIAS("platform:twl4030-madc");
 MODULE_AUTHOR("Nokia Corporation");
 MODULE_DESCRIPTION("twl4030 ADC driver");
 MODULE_LICENSE("GPL");
+
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index b80e8b6..4084564 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -67,6 +67,11 @@ struct twl4030_gpio_platform_data {
 				unsigned gpio, unsigned ngpio);
 };
 
+struct twl4030_madc_platform_data {
+	int		imr;
+	int		isr;
+};
+
 struct twl4030_keypad_data {
 	int rows;
 	int cols;
@@ -88,6 +93,7 @@ struct twl4030_usb_data {
 struct twl4030_platform_data {
 	unsigned				irq_base, irq_end;
 	struct twl4030_gpio_platform_data	*gpio;
+	struct twl4030_madc_platform_data	*madc;
 	struct twl4030_keypad_data		*keypad;
 	struct twl4030_usb_data			*usb;
 
-- 
1.6.0.2.307.gc427


^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 11:19                 ` [PATCH 9/9] i2c: move twl4030-madc to new registration style Felipe Balbi
@ 2008-09-26 17:09                   ` David Brownell
  2008-09-26 17:46                     ` Felipe Balbi
  2008-09-26 19:50                   ` David Brownell
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-26 17:09 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren, Mikko Ylinen

On Friday 26 September 2008, Felipe Balbi wrote:
>  arch/arm/mach-omap2/board-2430sdp.c     |    6 +
>  arch/arm/mach-omap2/board-3430sdp.c     |    6 +
>  arch/arm/mach-omap2/board-ldp.c         |    6 +
>  arch/arm/mach-omap2/board-omap2evm.c    |    6 +
>  arch/arm/mach-omap2/board-omap3beagle.c |    6 +
>  arch/arm/mach-omap2/board-omap3evm.c    |    6 +
>  arch/arm/mach-omap2/board-overo.c       |    6 +

The MADC stuff gave me:

arch/arm/mach-omap2/board-omap3beagle.c:118: error: 'TWL4030_MADC_IMR1' undeclared here (not in a function)
arch/arm/mach-omap2/board-omap3beagle.c:119: error: 'TWL4030_MADC_ISR1' undeclared here (not in a function)
make[1]: *** [arch/arm/mach-omap2/board-omap3beagle.o] Error 1
make[1]: *** Waiting for unfinished jobs....
make: *** [arch/arm/mach-omap2] Error 2
  CC      kernel/panic.o

Ditto for Overo.


Passing those registers in platform data seems bizarre.
Doesn't the MADC code know its own register offsets??

The platform data should probably say which ADC channels
are wired up...

And no ADC lines are even hooked up on Beagle, so the right
fix is just to not provide madc platform data on beagle.
Probably the same is true on some other boards.

Plus:  MADC is just a set of ADC channels, right?
If so, the driver should have a comment saying that.

- Dave
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 8/9] twl4030 uses gpiolib
  2008-09-26 11:19               ` [PATCH 8/9] twl4030 uses gpiolib Felipe Balbi
  2008-09-26 11:19                 ` [PATCH 9/9] i2c: move twl4030-madc to new registration style Felipe Balbi
@ 2008-09-26 17:10                 ` David Brownell
  2008-09-26 17:47                   ` Felipe Balbi
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-26 17:10 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

On Friday 26 September 2008, Felipe Balbi wrote:
> NYET-Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> NYET-Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>

Err, strike the "NYET-" for me.  Editing mistake, that
should have been removed before.  ;)


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 11:19 [PATCH 0/9] twl4030 updates Felipe Balbi
  2008-09-26 11:19 ` [PATCH 1/9] twl4030: fix potential null pointer dereference Felipe Balbi
@ 2008-09-26 17:12 ` David Brownell
  2008-09-26 17:50   ` Felipe Balbi
  2008-09-26 19:00   ` David Brownell
  2008-09-27 19:14 ` David Brownell
  2008-09-27 21:41 ` [PATCH 11/9] move twl4030-gpio to drivers/gpio David Brownell
  3 siblings, 2 replies; 48+ messages in thread
From: David Brownell @ 2008-09-26 17:12 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

Let's apply the following patch 10/9 on top of this though.
And probably update the board files similarly (alpha order).

As an FYI, if you look at the "MFD core" you'll observe that
if some crap gets stripped away, the *useful* bit is a utility
making some of this create-a-child-node easier.  It's not worth
using now.  But a little bird told me that some of that crap
may be getting stripped away soon, so add_children() could
become simpler.  Wouldn't affect the function drivers (the
OTG transceiver, keypad, GPIO, RTC, etc) because we have, with
foresight, been using platform_device already.  ;)

- Dave

======= SNIP!
From: David Brownell <dbrownell@users.sourceforge.net>

Minor twl4030-core cleanups:  alphabetize the creation of the
new sub-function nodes; wrap an #if around the OMAP-only part
(to get more general build testing when this goes upstream);
remove reference to undocumented "twl3040" variant.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
 drivers/i2c/chips/twl4030-core.c |  115 ++++++++++++++++++-------------------
 1 file changed, 59 insertions(+), 56 deletions(-)

--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -45,24 +45,12 @@
 
 #define DRIVER_NAME			"twl4030"
 
-#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
-#define twl_has_rtc()	true
-#else
-#define twl_has_rtc()	false
-#endif
-
 #if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
 #define twl_has_keypad()	true
 #else
 #define twl_has_keypad()	false
 #endif
 
-#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
-#define twl_has_usb()	true
-#else
-#define twl_has_usb()	false
-#endif
-
 #ifdef CONFIG_TWL4030_GPIO
 #define twl_has_gpio()	true
 #else
@@ -75,6 +63,18 @@
 #define twl_has_madc()	false
 #endif
 
+#if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
+#define twl_has_rtc()	true
+#else
+#define twl_has_rtc()	false
+#endif
+
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb()	true
+#else
+#define twl_has_usb()	false
+#endif
+
 /* Primary Interrupt Handler on TWL4030 Registers */
 
 /* Register Definitions */
@@ -668,6 +668,27 @@ static int add_children(struct twl4030_p
 	struct twl4030_client	*twl = NULL;
 	int			status = 0;
 
+	if (twl_has_keypad() && pdata->keypad) {
+		pdev = platform_device_alloc("twl4030_keypad", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+			status = platform_device_add_data(pdev, pdata->keypad,
+					sizeof(*pdata->keypad));
+			if (status < 0) {
+				platform_device_put(pdev);
+				goto err;
+			}
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
+
 	if (twl_has_gpio() && pdata->gpio) {
 		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM1];
 
@@ -706,6 +727,27 @@ static int add_children(struct twl4030_p
 		}
 	}
 
+	if (twl_has_madc() && pdata->madc) {
+		pdev = platform_device_alloc("twl4030_madc", -1);
+		if (pdev) {
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+			pdev->dev.parent = &twl->client->dev;
+			device_init_wakeup(&pdev->dev, 1);
+			status = platform_device_add_data(pdev, pdata->madc,
+					sizeof(*pdata->madc));
+			if (status < 0) {
+				platform_device_put(pdev);
+				goto err;
+			}
+			status = platform_device_add(pdev);
+			if (status < 0)
+				platform_device_put(pdev);
+		} else {
+			status = -ENOMEM;
+			goto err;
+		}
+	}
+
 	if (twl_has_rtc()) {
 		pdev = platform_device_alloc("twl4030_rtc", -1);
 		if (pdev) {
@@ -736,27 +778,6 @@ static int add_children(struct twl4030_p
 		}
 	}
 
-	if (twl_has_keypad() && pdata->keypad) {
-		pdev = platform_device_alloc("twl4030_keypad", -1);
-		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
-			pdev->dev.parent = &twl->client->dev;
-			device_init_wakeup(&pdev->dev, 1);
-			status = platform_device_add_data(pdev, pdata->keypad,
-					sizeof(*pdata->keypad));
-			if (status < 0) {
-				platform_device_put(pdev);
-				goto err;
-			}
-			status = platform_device_add(pdev);
-			if (status < 0)
-				platform_device_put(pdev);
-		} else {
-			status = -ENOMEM;
-			goto err;
-		}
-	}
-
 	if (twl_has_usb() && pdata->usb) {
 		pdev = platform_device_alloc("twl4030_usb", -1);
 		if (pdev) {
@@ -778,27 +799,6 @@ static int add_children(struct twl4030_p
 		}
 	}
 
-	if (twl_has_madc() && pdata->madc) {
-		pdev = platform_device_alloc("twl4030_madc", -1);
-		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
-			pdev->dev.parent = &twl->client->dev;
-			device_init_wakeup(&pdev->dev, 1);
-			status = platform_device_add_data(pdev, pdata->madc,
-					sizeof(*pdata->madc));
-			if (status < 0) {
-				platform_device_put(pdev);
-				goto err;
-			}
-			status = platform_device_add(pdev);
-			if (status < 0)
-				platform_device_put(pdev);
-		} else {
-			status = -ENOMEM;
-			goto err;
-		}
-	}
-
 err:
 	pr_err("failed to add twl4030's children\n");
 	return status;
@@ -844,17 +844,19 @@ static int __init unprotect_pm_master(vo
 
 static int __init power_companion_init(void)
 {
+	int e = 0;
+
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 	struct clk *osc;
 	u32 rate;
 	u8 ctrl = HFCLK_FREQ_26_MHZ;
-	int e = 0;
 
 	if (cpu_is_omap2430())
 		osc = clk_get(NULL, "osc_ck");
 	else
 		osc = clk_get(NULL, "osc_sys_ck");
 	if (IS_ERR(osc)) {
-		printk(KERN_WARNING "Skipping twl3040 internal clock init and "
+		printk(KERN_WARNING "Skipping twl4030 internal clock init and "
 				"using bootloader value (unknown osc rate)\n");
 		return 0;
 	}
@@ -879,6 +881,7 @@ static int __init power_companion_init(v
 	/* effect->MADC+USB ck en */
 	e |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
 	e |= protect_pm_master();
+#endif	/* OMAP */
 
 	return e;
 }


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 17:09                   ` David Brownell
@ 2008-09-26 17:46                     ` Felipe Balbi
  2008-09-27  7:37                       ` Mikko Ylinen
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 17:46 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Mikko Ylinen

On Fri, Sep 26, 2008 at 10:09:12AM -0700, David Brownell wrote:
> On Friday 26 September 2008, Felipe Balbi wrote:
> >  arch/arm/mach-omap2/board-2430sdp.c     |    6 +
> >  arch/arm/mach-omap2/board-3430sdp.c     |    6 +
> >  arch/arm/mach-omap2/board-ldp.c         |    6 +
> >  arch/arm/mach-omap2/board-omap2evm.c    |    6 +
> >  arch/arm/mach-omap2/board-omap3beagle.c |    6 +
> >  arch/arm/mach-omap2/board-omap3evm.c    |    6 +
> >  arch/arm/mach-omap2/board-overo.c       |    6 +
> 
> The MADC stuff gave me:
> 
> arch/arm/mach-omap2/board-omap3beagle.c:118: error: 'TWL4030_MADC_IMR1' undeclared here (not in a function)
> arch/arm/mach-omap2/board-omap3beagle.c:119: error: 'TWL4030_MADC_ISR1' undeclared here (not in a function)
> make[1]: *** [arch/arm/mach-omap2/board-omap3beagle.o] Error 1
> make[1]: *** Waiting for unfinished jobs....
> make: *** [arch/arm/mach-omap2] Error 2
>   CC      kernel/panic.o
> 
> Ditto for Overo.
> 
> 
> Passing those registers in platform data seems bizarre.
> Doesn't the MADC code know its own register offsets??

there two of them. i[ms]r[12].

> The platform data should probably say which ADC channels
> are wired up...
> 
> And no ADC lines are even hooked up on Beagle, so the right
> fix is just to not provide madc platform data on beagle.
> Probably the same is true on some other boards.

Yeah, i wasn't sure if beagle and overo were using them, so I put
anyways.

> Plus:  MADC is just a set of ADC channels, right?
> If so, the driver should have a comment saying that.

Mikko should comment on that as he wrote the driver.

-- 
balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 8/9] twl4030 uses gpiolib
  2008-09-26 17:10                 ` [PATCH 8/9] twl4030 uses gpiolib David Brownell
@ 2008-09-26 17:47                   ` Felipe Balbi
  2008-09-26 18:57                     ` David Brownell
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 17:47 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Fri, Sep 26, 2008 at 10:10:50AM -0700, David Brownell wrote:
> On Friday 26 September 2008, Felipe Balbi wrote:
> > NYET-Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> > NYET-Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
> 
> Err, strike the "NYET-" for me.  Editing mistake, that
> should have been removed before.  ;)

There were a few comments in the patch header that sugested me this
patch wasn't finished yet :-)

I'll stryke it out, np.

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 17:12 ` [PATCH 0/9] twl4030 updates David Brownell
@ 2008-09-26 17:50   ` Felipe Balbi
  2008-09-26 18:55     ` David Brownell
  2008-09-26 19:00   ` David Brownell
  1 sibling, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 17:50 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Fri, Sep 26, 2008 at 10:12:27AM -0700, David Brownell wrote:
> Let's apply the following patch 10/9 on top of this though.
> And probably update the board files similarly (alpha order).
> 
> As an FYI, if you look at the "MFD core" you'll observe that
> if some crap gets stripped away, the *useful* bit is a utility
> making some of this create-a-child-node easier.  It's not worth
> using now.  But a little bird told me that some of that crap
> may be getting stripped away soon, so add_children() could
> become simpler.  Wouldn't affect the function drivers (the
> OTG transceiver, keypad, GPIO, RTC, etc) because we have, with
> foresight, been using platform_device already.  ;)

I was trying to organize by order of importance to a running system. If
we run out of memory when registering the madc child, that should be ok,
but if we run out of memory when registering rtc, that might cause some
problems, right ?

If you prefer in alphabetic order, it's no problem, I'll fix that ;-)

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 17:50   ` Felipe Balbi
@ 2008-09-26 18:55     ` David Brownell
  0 siblings, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-09-26 18:55 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Friday 26 September 2008, Felipe Balbi wrote:
> I was trying to organize by order of importance to a running system. If
> we run out of memory when registering the madc child, that should be ok,
> but if we run out of memory when registering rtc, that might cause some
> problems, right ?

If we run out of memory *that early* it'll be a miracle if 
the system can run at all...


> If you prefer in alphabetic order, it's no problem, I'll fix that ;-)

Alphabetical should be the default assumption.  It makes
things easier to maintain ... when you're trying to find
something, it's easy to figure out where it should be.



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 8/9] twl4030 uses gpiolib
  2008-09-26 17:47                   ` Felipe Balbi
@ 2008-09-26 18:57                     ` David Brownell
  0 siblings, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-09-26 18:57 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Friday 26 September 2008, Felipe Balbi wrote:
> 
> > Err, strike the "NYET-" for me.  Editing mistake, that
> > should have been removed before.  ;)
> 
> There were a few comments in the patch header that sugested me this
> patch wasn't finished yet :-)

This patch is done.  The other work will be done later.

For example, all the existing users of these APIs are
in the hsmmc init logic.  That's kind of in flux now
(at least semi-broken).  When it works again, several
parts will change.

Likewise there are dependencies on some gpiolib features
that aren't yet merged.

- Dave

--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 17:12 ` [PATCH 0/9] twl4030 updates David Brownell
  2008-09-26 17:50   ` Felipe Balbi
@ 2008-09-26 19:00   ` David Brownell
  2008-09-26 19:10     ` Steve Sakoman
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-26 19:00 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

On Friday 26 September 2008, David Brownell wrote:
> Let's apply the following patch 10/9 on top of this though.

And after applying this, and removing MADC config from
the Beagle and Overo board setup files, things worked!!

Moreover ... the USB host code worked, at least partially.
(Finally!  RC7.)  It enumerated the external hub, and the
Ethernet adapter hooked up to it.

But there were problems reading some chip registers via
control requests, and with MII read/write.  So it's not
all there yet.

- Dave


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 19:00   ` David Brownell
@ 2008-09-26 19:10     ` Steve Sakoman
  2008-09-26 19:23       ` Felipe Balbi
  2008-09-26 19:45       ` David Brownell
  0 siblings, 2 replies; 48+ messages in thread
From: Steve Sakoman @ 2008-09-26 19:10 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Fri, Sep 26, 2008 at 12:00 PM, David Brownell <david-b@pacbell.net> wrote:
> And after applying this, and removing MADC config from
> the Beagle and Overo board setup files, things worked!!

That's really great news!

> Moreover ... the USB host code worked, at least partially.
> (Finally!  RC7.)  It enumerated the external hub, and the
> Ethernet adapter hooked up to it.

Just to clarify -- you are referring to musb host code, correct?

Steve

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 19:10     ` Steve Sakoman
@ 2008-09-26 19:23       ` Felipe Balbi
  2008-09-26 19:45       ` David Brownell
  1 sibling, 0 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-26 19:23 UTC (permalink / raw)
  To: Steve Sakoman; +Cc: David Brownell, Felipe Balbi, linux-omap, Tony Lindgren

On Fri, Sep 26, 2008 at 12:10:41PM -0700, Steve Sakoman wrote:
> On Fri, Sep 26, 2008 at 12:00 PM, David Brownell <david-b@pacbell.net> wrote:
> > And after applying this, and removing MADC config from
> > the Beagle and Overo board setup files, things worked!!
> 
> That's really great news!
> 
> > Moreover ... the USB host code worked, at least partially.
> > (Finally!  RC7.)  It enumerated the external hub, and the
> > Ethernet adapter hooked up to it.
> 
> Just to clarify -- you are referring to musb host code, correct?

He's actually refering to twl4030-usb being able to understand id pin is
grounded and start sourcing vbus. Without it, musb would never know it's
supposed to work as host ;-)

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 19:10     ` Steve Sakoman
  2008-09-26 19:23       ` Felipe Balbi
@ 2008-09-26 19:45       ` David Brownell
  1 sibling, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-09-26 19:45 UTC (permalink / raw)
  To: Steve Sakoman; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Friday 26 September 2008, Steve Sakoman wrote:
> On Fri, Sep 26, 2008 at 12:00 PM, David Brownell <david-b@pacbell.net> wrote:
> > And after applying this, and removing MADC config from
> > the Beagle and Overo board setup files, things worked!!
> 
> That's really great news!

Yeah ... once Tony merges these ten patches, and the core
gets relocated (I'll do that patch) we're nearly ready to
submit the core upstream.  For the 2.6.28 merge window!
(Then the other function drivers can follow...)


> > Moreover ... the USB host code worked, at least partially.
> > (Finally!  RC7.)  It enumerated the external hub, and the
> > Ethernet adapter hooked up to it.
> 
> Just to clarify -- you are referring to musb host code, correct?

Yes.  Plus a few minor cleanup patches, none changing MUSB
behavior except in terms of diagnostics (unless you're faced
with a bogus board config).

- Dave


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 11:19                 ` [PATCH 9/9] i2c: move twl4030-madc to new registration style Felipe Balbi
  2008-09-26 17:09                   ` David Brownell
@ 2008-09-26 19:50                   ` David Brownell
  2008-09-26 20:01                     ` Steve Sakoman
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-26 19:50 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren, Mikko Ylinen, Steve Sakoman

On Friday 26 September 2008, Felipe Balbi wrote:
>  arch/arm/mach-omap2/board-omap3beagle.c |    6 +
>  arch/arm/mach-omap2/board-overo.c       |    6 +

For the record:  this reverts those two little evil additions;
build fix, and correctness update for at least Beagle.

Steve, if Overo wires out any of the ADC channels on that
one connector, you may want to come up with a better fox.

- Dave

====== SNIP!
--- beagle.orig/arch/arm/mach-omap2/board-omap3beagle.c	2008-09-26 12:47:36.000000000 -0700
+++ beagle/arch/arm/mach-omap2/board-omap3beagle.c	2008-09-26 09:55:50.000000000 -0700
@@ -114,11 +114,6 @@ static struct twl4030_usb_data beagle_us
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
-static struct twl4030_madc_platform_data beagle_madc_data = {
-	.imr		= TWL4030_MADC_IMR1,
-	.isr		= TWL4030_MADC_ISR1,
-};
-
 static struct twl4030_gpio_platform_data beagle_gpio_data = {
 	.gpio_base	= OMAP_MAX_GPIO_LINES,
 	.irq_base	= TWL4030_GPIO_IRQ_BASE,
@@ -135,7 +130,6 @@ static struct twl4030_platform_data beag
 	.irq_end	= TWL4030_IRQ_END,
 
 	/* platform_data for children goes here */
-	.madc		= &beagle_madc_data,
 	.usb		= &beagle_usb_data,
 	.gpio		= &beagle_gpio_data,
 };
--- beagle.orig/arch/arm/mach-omap2/board-overo.c	2008-09-26 12:47:36.000000000 -0700
+++ beagle/arch/arm/mach-omap2/board-overo.c	2008-09-26 10:02:29.000000000 -0700
@@ -152,16 +152,10 @@ static struct twl4030_gpio_platform_data
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 };
 
-static struct twl4030_madc_platform_data overo_madc_data = {
-	.imr		= TWL4030_MADC_IMR1,
-	.isr		= TWL4030_MADC_ISR1,
-};
-
 static struct twl4030_platform_data overo_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
 	.gpio		= &overo_gpio_data,
-	.madc		= &overo_madc_data,
 };
 
 static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 19:50                   ` David Brownell
@ 2008-09-26 20:01                     ` Steve Sakoman
  0 siblings, 0 replies; 48+ messages in thread
From: Steve Sakoman @ 2008-09-26 20:01 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Mikko Ylinen

On Fri, Sep 26, 2008 at 12:50 PM, David Brownell <david-b@pacbell.net> wrote:
> Steve, if Overo wires out any of the ADC channels on that
> one connector, you may want to come up with a better fox.

Overo does bring out the ADC channels to one of the 2 70 pin connectors.

Let's go ahead with your proposed patch for now.  I will revisit it
when I get an Overo "buddy" board that actually makes the ADC channels
accessible.  At that point I can prepare a patch that includes all
changes required to get the ADC stuff functioning.

Steve

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-26 17:46                     ` Felipe Balbi
@ 2008-09-27  7:37                       ` Mikko Ylinen
  2008-09-27 15:04                         ` David Brownell
  0 siblings, 1 reply; 48+ messages in thread
From: Mikko Ylinen @ 2008-09-27  7:37 UTC (permalink / raw)
  To: me, David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

Hi,

Felipe Balbi wrote:
> On Fri, Sep 26, 2008 at 10:09:12AM -0700, David Brownell wrote:
>> Passing those registers in platform data seems bizarre.
>> Doesn't the MADC code know its own register offsets??
> 
> there two of them. i[ms]r[12].

twl4030 has two interrupt lines. For INT1 and INT2
lines you should use I[MS]R1 and I[MS]R2, respectively.

This is board specific information. Beagleboard uses
INT1.

>> The platform data should probably say which ADC channels
>> are wired up...

Yeah, I thought about this at the time of writing the driver
but dropped the idea because of problems with twl4030-core.

I think this is a good idea and should be re-considered now.

>> And no ADC lines are even hooked up on Beagle, so the right
>> fix is just to not provide madc platform data on beagle.
>> Probably the same is true on some other boards.
> 
> Yeah, i wasn't sure if beagle and overo were using them, so I put
> anyways.

Not completely true. MADC has 16 channels out of which only 6
are truly general purpose channels. Some channels are reserved
for battery charger interface (BCI) and some for chip's internal
purposes.

Boards having twl4030 should have at least VBAT (ch 12),
V backup battery (ch 9), and VBUS (ch 8) measurement available.

On Beagleboard you can measure these three channels.

>> Plus:  MADC is just a set of ADC channels, right?
>> If so, the driver should have a comment saying that.
> 
> Mikko should comment on that as he wrote the driver.

How detailed information would you like to have here?

-- 
Regards, Mikko

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-27  7:37                       ` Mikko Ylinen
@ 2008-09-27 15:04                         ` David Brownell
  2008-09-27 15:40                           ` Steve Sakoman
  2008-10-01 14:20                           ` Mikko Ylinen
  0 siblings, 2 replies; 48+ messages in thread
From: David Brownell @ 2008-09-27 15:04 UTC (permalink / raw)
  To: Mikko Ylinen; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren

On Saturday 27 September 2008, Mikko Ylinen wrote:
> Hi,
> 
> Felipe Balbi wrote:
> > On Fri, Sep 26, 2008 at 10:09:12AM -0700, David Brownell wrote:
> >> Passing those registers in platform data seems bizarre.
> >> Doesn't the MADC code know its own register offsets??
> > 
> > there two of them. i[ms]r[12].
> 
> twl4030 has two interrupt lines. For INT1 and INT2
> lines you should use I[MS]R1 and I[MS]R2, respectively.
> 
> This is board specific information. Beagleboard uses
> INT1.

So IMO it would make more sense to pass "1" or "2" in
the platform_data -- possibly for other sub-chips too --
and have the driver use that to figure out which set of
registers to use.  If both were wired up, it would be
a board policy which sub-chips used which IRQs, right?
(Haven't read the whole manual yet.)


> >> And no ADC lines are even hooked up on Beagle, so the right
> >> fix is just to not provide madc platform data on beagle.
> >> Probably the same is true on some other boards.
> > 
> > Yeah, i wasn't sure if beagle and overo were using them, so I put
> > anyways.
> 
> Not completely true. MADC has 16 channels out of which only 6
> are truly general purpose channels. Some channels are reserved
> for battery charger interface (BCI) and some for chip's internal
> purposes.
> 
> Boards having twl4030 should have at least VBAT (ch 12),
> V backup battery (ch 9), and VBUS (ch 8) measurement available.
> 
> On Beagleboard you can measure these three channels.

I stand not-completely-corrected, then!  No channels are wired
on the beagle; but some are wired internally to its T2 chip.  ;)


The first two being more or less fixed values (4.2V, GND);
no battery.  In general, I can imagine it would be good to
export those for hwmon usage (sysfs) or as part of the power
management infrastructure.

Without disentangling things I've not looked at before ...
is the USB support using that VBUS measurement?  Should it?
The MUSB interface exposes VBUS comparators, so I think that
it's not expected to need these additional values.

In short:  it doesn't seem like non-battery systems (like
Beagle and Overo) would need those channels.  Agree?


A question that may well come up when this heads upstream:
why is this exporting a miscdev, for an ioctl, when this
could all be done using sysfs and hwmon rules?  That is,
was this the "appropriate" way to export ADC channels?

And a slightly more pragmatic question:  does Nokia have
tools that would break if this were switched to hwmon style?


> >> Plus:  MADC is just a set of ADC channels, right?
> >> If so, the driver should have a comment saying that.
> > 
> > Mikko should comment on that as he wrote the driver.
> 
> How detailed information would you like to have here?

Enough to answer the question "what's a MADC?" for someone
who doesn't have TWL specs and hasn't read even any kind
of summary data sheet.  Three sentences would likely be
excessive; one good sentence might suffice.

- Dave

> 
> -- 
> Regards, Mikko
> 
> 



^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-27 15:04                         ` David Brownell
@ 2008-09-27 15:40                           ` Steve Sakoman
  2008-09-27 17:17                             ` David Brownell
  2008-10-01 14:20                           ` Mikko Ylinen
  1 sibling, 1 reply; 48+ messages in thread
From: Steve Sakoman @ 2008-09-27 15:40 UTC (permalink / raw)
  To: David Brownell; +Cc: Mikko Ylinen, me, Felipe Balbi, linux-omap, Tony Lindgren

On Sat, Sep 27, 2008 at 8:04 AM, David Brownell <david-b@pacbell.net> wrote:

> I stand not-completely-corrected, then!  No channels are wired
> on the beagle; but some are wired internally to its T2 chip.  ;)

On Overo, ADC channels 2-7 are brought out on one of the 2 70 pin
expansion connectors.

Steve

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-27 15:40                           ` Steve Sakoman
@ 2008-09-27 17:17                             ` David Brownell
  0 siblings, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-09-27 17:17 UTC (permalink / raw)
  To: Steve Sakoman; +Cc: Mikko Ylinen, me, Felipe Balbi, linux-omap, Tony Lindgren

On Saturday 27 September 2008, Steve Sakoman wrote:
> On Sat, Sep 27, 2008 at 8:04 AM, David Brownell <david-b@pacbell.net> wrote:
> 
> > I stand not-completely-corrected, then!  No channels are wired
> > on the beagle; but some are wired internally to its T2 chip.  ;)
> 
> On Overo, ADC channels 2-7 are brought out on one of the 2 70 pin
> expansion connectors.

Right; you mentioned that before.

Have you had thoughts on how they might best be exposed?
Would sysfs work?  Are kernel-to-kernel interfaces needed?


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-26 11:19 [PATCH 0/9] twl4030 updates Felipe Balbi
  2008-09-26 11:19 ` [PATCH 1/9] twl4030: fix potential null pointer dereference Felipe Balbi
  2008-09-26 17:12 ` [PATCH 0/9] twl4030 updates David Brownell
@ 2008-09-27 19:14 ` David Brownell
  2008-09-27 21:17   ` Felipe Balbi
  2008-09-27 21:41 ` [PATCH 11/9] move twl4030-gpio to drivers/gpio David Brownell
  3 siblings, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-27 19:14 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

Here are some more cleanups to consider including ... these
should apply on top of all nine patches.


======= SNIP HERE!
Provide detailed diagnostics in add_children() when DEBUG is
defined ... and fix the non-DEBUG message to include minimal
status, and not appear unless there was actually an error.

Update the IRQ message; have it match what the GPIO subchip
says, and as a precaution, make it only appear if the IRQs
have been initialized.

--- beagle.orig/drivers/i2c/chips/twl4030-core.c
+++ beagle/drivers/i2c/chips/twl4030-core.c
@@ -677,6 +677,9 @@ static int add_children(struct twl4030_p
 			status = platform_device_add_data(pdev, pdata->keypad,
 					sizeof(*pdata->keypad));
 			if (status < 0) {
+				dev_dbg(&twl->client->dev,
+					"can't add keypad data, %d\n",
+					status);
 				platform_device_put(pdev);
 				goto err;
 			}
@@ -684,6 +687,7 @@ static int add_children(struct twl4030_p
 			if (status < 0)
 				platform_device_put(pdev);
 		} else {
+			pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
@@ -693,8 +697,10 @@ static int add_children(struct twl4030_p
 		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM1];
 
 		pdev = platform_device_alloc("twl4030_gpio", -1);
-		if (!pdev)
+		if (!pdev) {
+			pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
 			status = -ENOMEM;
+		}
 
 		/* more driver model init */
 		if (status == 0) {
@@ -703,6 +709,10 @@ static int add_children(struct twl4030_p
 
 			status = platform_device_add_data(pdev, pdata->gpio,
 					sizeof(*pdata->gpio));
+			if (status < 0)
+				dev_dbg(&twl->client->dev,
+					"can't add gpio data, %d\n",
+				status);
 		}
 
 		/* GPIO module IRQ */
@@ -737,12 +747,16 @@ static int add_children(struct twl4030_p
 					sizeof(*pdata->madc));
 			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+					"can't add madc data, %d\n",
+					status);
 				goto err;
 			}
 			status = platform_device_add(pdev);
 			if (status < 0)
 				platform_device_put(pdev);
 		} else {
+			pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
@@ -788,19 +802,24 @@ static int add_children(struct twl4030_p
 					sizeof(*pdata->usb));
 			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+					"can't add usb data, %d\n",
+					status);
 				goto err;
 			}
 			status = platform_device_add(pdev);
 			if (status < 0)
 				platform_device_put(pdev);
 		} else {
+			pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
 	}
 
 err:
-	pr_err("failed to add twl4030's children\n");
+	if (status)
+		pr_err("failed to add twl4030's children (status %d)\n", status);
 	return status;
 }
 
@@ -1084,13 +1103,12 @@ twl4030_probe(struct i2c_client *client,
 			&& twl4030_irq_base == 0
 			&& client->irq
 			&& pdata->irq_base
-			&& pdata->irq_end > pdata->irq_base)
+			&& pdata->irq_end > pdata->irq_base) {
 		twl_init_irq(client->irq, pdata->irq_base, pdata->irq_end);
+		dev_info(&client->dev, "IRQ %d chains IRQs %d..%d\n",
+				client->irq, pdata->irq_base, pdata->irq_end - 1);
+	}
 
-	dev_info(&client->dev, "chaining %d irqs\n",
-			twl4030_irq_base
-				? (pdata->irq_end - pdata->irq_base)
-				: 0);
 	return 0;
 
 fail:

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-27 19:14 ` David Brownell
@ 2008-09-27 21:17   ` Felipe Balbi
  2008-09-27 21:45     ` David Brownell
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-27 21:17 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Sat, Sep 27, 2008 at 12:14:29PM -0700, David Brownell wrote:
> Here are some more cleanups to consider including ... these
> should apply on top of all nine patches.

You want me to keep it on top of the other 9 (10) patches or meld it
together ? I think it'd be better to meld on the previous patches so
we introduce the patches the way they should look like. Right ?

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-26 11:19 [PATCH 0/9] twl4030 updates Felipe Balbi
                   ` (2 preceding siblings ...)
  2008-09-27 19:14 ` David Brownell
@ 2008-09-27 21:41 ` David Brownell
  2008-09-27 22:29   ` Felipe Balbi
  3 siblings, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-27 21:41 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren, Jean Delvare

From: David Brownell <dbrownell@users.sourceforge.net>

Move the twl4030 GPIO support from drivers/i2c/chips to drivers/gpio,
which is a more appropriate home for this code.

The Kconfig symbol name is changed to match the GPIO_* convention for
such symbols, so config files must change in the obvious ways (Kconfig
will prompt you).  There's now some helptext.

It can now be compiled as a module, should anyone really want to
do that; that'll be mostly useful for test builds.  Sanity check the
IRQ range we're given.

Initialization order needed a bit of work too:  core add_children()
called only after IRQs get set up, gpio uses subsys_initcall.  This
depends on a patch making i2c driver model init use postcore_initcall.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
---
NOTE:  requires an I2C patch:

  http://marc.info/?l=i2c&m=122227316012577&w=2

I CC'd Jean since that doesn't seem to be in his queue yet, and
that's pretty essential to moving such TWL stuff out of the
i2c/chips directory into more appropriate locations.

 arch/arm/plat-omap/include/mach/irqs.h |    2 
 drivers/gpio/Kconfig                   |    7 
 drivers/gpio/Makefile                  |    1 
 drivers/gpio/twl4030-gpio.c            |  921 +++++++++++++++++++++++++++++++
 drivers/i2c/chips/Kconfig              |    4 
 drivers/i2c/chips/Makefile             |    1 
 drivers/i2c/chips/twl4030-core.c       |   12 
 drivers/i2c/chips/twl4030-gpio.c       |  896 ------------------------------
 8 files changed, 934 insertions(+), 910 deletions(-)

--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -369,7 +369,7 @@
 
 /* External TWL4030 gpio interrupts are optional */
 #define TWL4030_GPIO_IRQ_BASE	TWL4030_PWR_IRQ_END
-#ifdef	CONFIG_TWL4030_GPIO
+#ifdef	CONFIG_GPIO_TWL4030
 #define TWL4030_GPIO_NR_IRQS	18
 #else
 #define	TWL4030_GPIO_NR_IRQS	0
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -127,6 +127,13 @@ config GPIO_PCF857X
 	  This driver provides an in-kernel interface to those GPIOs using
 	  platform-neutral GPIO calls.
 
+config GPIO_TWL4030
+	tristate "TWL4030/TPS659x0 GPIO Driver"
+	depends on TWL4030_CORE && GPIOLIB
+	help
+	  Say yes here to access the GPIO signals of various multi-function
+	  power management chips from Texas Instruments.
+
 comment "PCI GPIO expanders:"
 
 config GPIO_BT8XX
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -9,4 +9,5 @@ obj-$(CONFIG_GPIO_MAX732X)	+= max732x.o
 obj-$(CONFIG_GPIO_MCP23S08)	+= mcp23s08.o
 obj-$(CONFIG_GPIO_PCA953X)	+= pca953x.o
 obj-$(CONFIG_GPIO_PCF857X)	+= pcf857x.o
+obj-$(CONFIG_GPIO_TWL4030)	+= twl4030-gpio.o
 obj-$(CONFIG_GPIO_BT8XX)	+= bt8xxgpio.o
--- /dev/null
+++ b/drivers/gpio/twl4030-gpio.c
@@ -0,0 +1,921 @@
+/*
+ * twl4030_gpio.c -- access to GPIOs on TWL4030/TPS659x0 chips
+ *
+ * Copyright (C) 2006-2007 Texas Instruments, Inc.
+ * Copyright (C) 2006 MontaVista Software, Inc.
+ *
+ * Code re-arranged and cleaned up by:
+ *	Syed Mohammed Khasim <x0khasim@ti.com>
+ *
+ * Initial Code:
+ *	Andy Lowe / Nishanth Menon
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/module.h>
+#include <linux/kernel_stat.h>
+#include <linux/init.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/kthread.h>
+#include <linux/irq.h>
+#include <linux/gpio.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <linux/i2c/twl4030.h>
+#include <linux/i2c/twl4030-gpio.h>
+
+#include <mach/irqs.h>
+#include <asm/mach/irq.h>
+#include <mach/gpio.h>
+#include <mach/mux.h>
+
+
+/* REVISIT when these symbols vanish elsewhere, remove them here too */
+/* #undef TWL4030_GPIO_IRQ_BASE */
+/* #undef TWL4030_GPIO_IRQ_END */
+#undef TWL4030_MODIRQ_GPIO
+
+static struct gpio_chip twl_gpiochip;
+static int twl4030_gpio_irq_base;
+static int twl4030_gpio_irq_end;
+
+#ifdef MODULE
+#define is_module()	true
+#else
+#define is_module()	false
+#endif
+
+/* BitField Definitions */
+
+/* Data banks : 3 banks for 8 gpios each */
+#define DATA_BANK_MAX				8
+#define GET_GPIO_DATA_BANK(x)			((x)/DATA_BANK_MAX)
+#define GET_GPIO_DATA_OFF(x)			((x)%DATA_BANK_MAX)
+
+/* GPIODATADIR Fields each block 0-7 */
+#define BIT_GPIODATADIR_GPIOxDIR(x)		(x)
+#define MASK_GPIODATADIR_GPIOxDIR(x)		(0x01 << (x))
+
+/* GPIODATAIN Fields each block 0-7 */
+#define BIT_GPIODATAIN_GPIOxIN(x)		(x)
+#define MASK_GPIODATAIN_GPIOxIN(x)		(0x01 << (x))
+
+/* GPIODATAOUT Fields each block 0-7 */
+#define BIT_GPIODATAOUT_GPIOxOUT(x)		(x)
+#define MASK_GPIODATAOUT_GPIOxOUT(x)		(0x01 << (x))
+
+/* CLEARGPIODATAOUT Fields */
+#define BIT_CLEARGPIODATAOUT_GPIOxOUT(x)	(x)
+#define MASK_CLEARGPIODATAOUT_GPIOxOUT(x)	(0x01 << (x))
+
+/* SETGPIODATAOUT Fields */
+#define BIT_SETGPIODATAOUT_GPIOxOUT(x)		(x)
+#define MASK_SETGPIODATAOUT_GPIOxOUT(x)		(0x01 << (x))
+
+/* GPIO_DEBEN Fields */
+#define BIT_GPIO_DEBEN_GPIOxDEB(x)		(x)
+#define MASK_GPIO_DEBEN_GPIOxDEB(x)		(0x01 << (x))
+
+/* GPIO_ISR1A Fields */
+#define BIT_GPIO_ISR_GPIOxISR(x)		(x)
+#define MASK_GPIO_ISR_GPIOxISR(x)		(0x01 << (x))
+
+/* GPIO_IMR1A Fields */
+#define BIT_GPIO_IMR1A_GPIOxIMR(x)		(x)
+#define MASK_GPIO_IMR1A_GPIOxIMR(x)		(0x01 << (x))
+
+/* GPIO_SIR1 Fields */
+#define BIT_GPIO_SIR1_GPIOxSIR(x)		(x)
+#define MASK_GPIO_SIR1_GPIO0SIR			(0x01 << (x))
+
+
+/* Control banks : 5 banks for 4 gpios each */
+#define DATA_CTL_MAX			4
+#define GET_GPIO_CTL_BANK(x)		((x)/DATA_CTL_MAX)
+#define GET_GPIO_CTL_OFF(x)		((x)%DATA_CTL_MAX)
+#define GPIO_BANK_MAX			GET_GPIO_CTL_BANK(TWL4030_GPIO_MAX)
+
+/* GPIOPUPDCTRx Fields 5 banks of 4 gpios each */
+#define BIT_GPIOPUPDCTR1_GPIOxPD(x)	(2 * (x))
+#define MASK_GPIOPUPDCTR1_GPIOxPD(x)	(0x01 << (2 * (x)))
+#define BIT_GPIOPUPDCTR1_GPIOxPU(x)	((x) + 1)
+#define MASK_GPIOPUPDCTR1_GPIOxPU(x)	(0x01 << (((2 * (x)) + 1)))
+
+/* GPIO_EDR1 Fields */
+#define BIT_GPIO_EDR1_GPIOxFALLING(x)	(2 * (x))
+#define MASK_GPIO_EDR1_GPIOxFALLING(x)	(0x01 << (2 * (x)))
+#define BIT_GPIO_EDR1_GPIOxRISING(x)	((x) + 1)
+#define MASK_GPIO_EDR1_GPIOxRISING(x)	(0x01 << (((2 * (x)) + 1)))
+
+/* GPIO_SIH_CTRL Fields */
+#define BIT_GPIO_SIH_CTRL_EXCLEN	(0x000)
+#define MASK_GPIO_SIH_CTRL_EXCLEN	(0x00000001)
+#define BIT_GPIO_SIH_CTRL_PENDDIS	(0x001)
+#define MASK_GPIO_SIH_CTRL_PENDDIS	(0x00000002)
+#define BIT_GPIO_SIH_CTRL_COR		(0x002)
+#define MASK_GPIO_SIH_CTRL_COR		(0x00000004)
+
+/* GPIO_CTRL Fields */
+#define BIT_GPIO_CTRL_GPIO0CD1		(0x000)
+#define MASK_GPIO_CTRL_GPIO0CD1		(0x00000001)
+#define BIT_GPIO_CTRL_GPIO1CD2		(0x001)
+#define MASK_GPIO_CTRL_GPIO1CD2		(0x00000002)
+#define BIT_GPIO_CTRL_GPIO_ON		(0x002)
+#define MASK_GPIO_CTRL_GPIO_ON		(0x00000004)
+
+/* Mask for GPIO registers when aggregated into a 32-bit integer */
+#define GPIO_32_MASK			0x0003ffff
+
+/* Data structures */
+static DEFINE_MUTEX(gpio_lock);
+
+/* store usage of each GPIO. - each bit represents one GPIO */
+static unsigned int gpio_usage_count;
+
+/* shadow the imr register */
+static unsigned int gpio_imr_shadow;
+
+/* bitmask of pending requests to unmask gpio interrupts */
+static unsigned int gpio_pending_unmask;
+
+/* pointer to gpio unmask thread struct */
+static struct task_struct *gpio_unmask_thread;
+
+/*
+ * Helper functions to read and write the GPIO ISR and IMR registers as
+ * 32-bit integers. Functions return 0 on success, non-zero otherwise.
+ * The caller must hold gpio_lock.
+ */
+
+static int gpio_read_isr(unsigned int *isr)
+{
+	int ret;
+
+	*isr = 0;
+	ret = twl4030_i2c_read(TWL4030_MODULE_GPIO, (u8 *) isr,
+			REG_GPIO_ISR1A, 3);
+	le32_to_cpup(isr);
+	*isr &= GPIO_32_MASK;
+
+	return ret;
+}
+
+static int gpio_write_isr(unsigned int isr)
+{
+	isr &= GPIO_32_MASK;
+	/*
+	 * The buffer passed to the twl4030_i2c_write() routine must have an
+	 * extra byte at the beginning reserved for its internal use.
+	 */
+	isr <<= 8;
+	isr = cpu_to_le32(isr);
+	return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &isr,
+				REG_GPIO_ISR1A, 3);
+}
+
+static int gpio_write_imr(unsigned int imr)
+{
+	imr &= GPIO_32_MASK;
+	/*
+	 * The buffer passed to the twl4030_i2c_write() routine must have an
+	 * extra byte at the beginning reserved for its internal use.
+	 */
+	imr <<= 8;
+	imr = cpu_to_le32(imr);
+	return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &imr,
+				REG_GPIO_IMR1A, 3);
+}
+
+/*
+ * These routines are analagous to the irqchip methods, but they are designed
+ * to be called from thread context with cpu interrupts enabled and with no
+ * locked spinlocks.  We call these routines from our custom IRQ handler
+ * instead of the usual irqchip methods.
+ */
+static void twl4030_gpio_mask_and_ack(unsigned int irq)
+{
+	int gpio = irq - twl4030_gpio_irq_base;
+
+	mutex_lock(&gpio_lock);
+	/* mask */
+	gpio_imr_shadow |= (1 << gpio);
+	gpio_write_imr(gpio_imr_shadow);
+	/* ack */
+	gpio_write_isr(1 << gpio);
+	mutex_unlock(&gpio_lock);
+}
+
+static void twl4030_gpio_unmask(unsigned int irq)
+{
+	int gpio = irq - twl4030_gpio_irq_base;
+
+	mutex_lock(&gpio_lock);
+	gpio_imr_shadow &= ~(1 << gpio);
+	gpio_write_imr(gpio_imr_shadow);
+	mutex_unlock(&gpio_lock);
+}
+
+/*
+ * These are the irqchip methods for the TWL4030 GPIO interrupts.
+ * Our IRQ handle method doesn't call these, but they will be called by
+ * other routines such as setup_irq() and enable_irq().  They are called
+ * with cpu interrupts disabled and with a lock on the irq_controller_lock
+ * spinlock.  This complicates matters, because accessing the TWL4030 GPIO
+ * interrupt controller requires I2C bus transactions that can't be initiated
+ * in this context.  Our solution is to defer accessing the interrupt
+ * controller to a kernel thread.  We only need to support the unmask method.
+ */
+
+static void twl4030_gpio_mask_and_ack_irqchip(unsigned int irq) {}
+static void twl4030_gpio_mask_irqchip(unsigned int irq) {}
+
+static void twl4030_gpio_unmask_irqchip(unsigned int irq)
+{
+	int gpio = irq - twl4030_gpio_irq_base;
+
+	gpio_pending_unmask |= (1 << gpio);
+	if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
+		wake_up_process(gpio_unmask_thread);
+}
+
+static struct irq_chip twl4030_gpio_irq_chip = {
+	.name	= "twl4030",
+	.ack	= twl4030_gpio_mask_and_ack_irqchip,
+	.mask	= twl4030_gpio_mask_irqchip,
+	.unmask	= twl4030_gpio_unmask_irqchip,
+};
+
+/*
+ * These are the irqchip methods for the TWL4030 PIH GPIO module interrupt.
+ * The PIH module doesn't have interrupt masking capability, so these
+ * methods are NULL.
+ */
+static void twl4030_gpio_module_ack(unsigned int irq) {}
+static void twl4030_gpio_module_mask(unsigned int irq) {}
+static void twl4030_gpio_module_unmask(unsigned int irq) {}
+static struct irq_chip twl4030_gpio_module_irq_chip = {
+	.ack	= twl4030_gpio_module_ack,
+	.mask	= twl4030_gpio_module_mask,
+	.unmask	= twl4030_gpio_module_unmask,
+};
+
+/*
+ * To configure TWL4030 GPIO module registers
+ */
+static inline int gpio_twl4030_write(u8 address, u8 data)
+{
+	int ret = 0;
+
+	ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
+	return ret;
+}
+
+/*
+ * To read a TWL4030 GPIO module register
+ */
+static inline int gpio_twl4030_read(u8 address)
+{
+	u8 data;
+	int ret = 0;
+
+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
+	if (ret >= 0)
+		ret = data;
+	return ret;
+}
+
+/*
+ * twl4030 GPIO request function
+ */
+int twl4030_request_gpio(int gpio)
+{
+	int ret = 0;
+
+	if (unlikely(gpio >= TWL4030_GPIO_MAX))
+		return -EPERM;
+
+	ret = gpio_request(twl_gpiochip.base + gpio, NULL);
+	if (ret < 0)
+		return ret;
+
+	mutex_lock(&gpio_lock);
+	if (gpio_usage_count & (0x1 << gpio)) {
+		ret = -EBUSY;
+	} else {
+		/* First time usage? - switch on GPIO module */
+		if (!gpio_usage_count) {
+			ret = gpio_twl4030_write(REG_GPIO_CTRL,
+					MASK_GPIO_CTRL_GPIO_ON);
+			ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
+		}
+		if (!ret)
+			gpio_usage_count |= (0x1 << gpio);
+		else
+			gpio_free(twl_gpiochip.base + gpio);
+	}
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_request_gpio);
+
+/*
+ * TWL4030 GPIO free module
+ */
+int twl4030_free_gpio(int gpio)
+{
+	int ret = 0;
+
+	if (unlikely(gpio >= TWL4030_GPIO_MAX))
+		return -EPERM;
+
+	mutex_lock(&gpio_lock);
+
+	if ((gpio_usage_count & (0x1 << gpio)) == 0) {
+		ret = -EPERM;
+	} else {
+		gpio_usage_count &= ~(0x1 << gpio);
+		gpio_free(twl_gpiochip.base + gpio);
+	}
+
+	/* Last time usage? - switch off GPIO module */
+	if (ret == 0 && !gpio_usage_count)
+		ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
+
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_free_gpio);
+
+/*
+ * Set direction for TWL4030 GPIO
+ */
+static int twl4030_set_gpio_direction(int gpio, int is_input)
+{
+	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+	u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
+	u8 reg = 0;
+	u8 base = REG_GPIODATADIR1 + d_bnk;
+	int ret = 0;
+
+	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(base);
+	if (ret >= 0) {
+		if (is_input)
+			reg = (u8) ((ret) & ~(d_msk));
+		else
+			reg = (u8) ((ret) | (d_msk));
+
+		ret = gpio_twl4030_write(base, reg);
+	}
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+
+/*
+ * To enable/disable GPIO pin on TWL4030
+ */
+static int twl4030_set_gpio_dataout(int gpio, int enable)
+{
+	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+	u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
+	u8 base = 0;
+	int ret = 0;
+
+	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	if (enable)
+		base = REG_SETGPIODATAOUT1 + d_bnk;
+	else
+		base = REG_CLEARGPIODATAOUT1 + d_bnk;
+
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_write(base, d_msk);
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+
+/*
+ * To get the status of a GPIO pin on TWL4030
+ */
+int twl4030_get_gpio_datain(int gpio)
+{
+	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+	u8 d_off = BIT_GPIODATAIN_GPIOxIN(GET_GPIO_DATA_OFF(gpio));
+	u8 base = 0;
+	int ret = 0;
+
+	if (unlikely((gpio >= TWL4030_GPIO_MAX)
+		|| !(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	base = REG_GPIODATAIN1 + d_bnk;
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(base);
+	mutex_unlock(&gpio_lock);
+	if (ret > 0)
+		ret = (ret >> d_off) & 0x1;
+
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_get_gpio_datain);
+
+#if 0
+/*
+ * Configure PULL type for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_pull(int gpio, int pull_dircn)
+{
+	u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+	u8 c_off = GET_GPIO_CTL_OFF(gpio);
+	u8 c_msk = 0;
+	u8 reg = 0;
+	u8 base = 0;
+	int ret = 0;
+
+	if (unlikely((gpio >= TWL4030_GPIO_MAX)	||
+		!(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	base = REG_GPIOPUPDCTR1 + c_bnk;
+	if (pull_dircn == TWL4030_GPIO_PULL_DOWN)
+		c_msk = MASK_GPIOPUPDCTR1_GPIOxPD(c_off);
+	else if (pull_dircn == TWL4030_GPIO_PULL_UP)
+		c_msk = MASK_GPIOPUPDCTR1_GPIOxPU(c_off);
+
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(base);
+	if (ret >= 0) {
+		/* clear the previous up/down values */
+		reg = (u8) (ret);
+		reg &= ~(MASK_GPIOPUPDCTR1_GPIOxPU(c_off) |
+			MASK_GPIOPUPDCTR1_GPIOxPD(c_off));
+		reg |= c_msk;
+		ret = gpio_twl4030_write(base, reg);
+	}
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+#endif
+
+/*
+ * Configure Edge control for a GPIO pin on TWL4030
+ *
+ * FIXME this should just be the irq_chip.set_type() method
+ */
+int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
+{
+	u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
+	u8 c_off = GET_GPIO_CTL_OFF(gpio);
+	u8 c_msk = 0;
+	u8 reg = 0;
+	u8 base = 0;
+	int ret = 0;
+
+	if (unlikely((gpio >= TWL4030_GPIO_MAX)
+		|| !(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	base = REG_GPIO_EDR1 + c_bnk;
+
+	if (edge & TWL4030_GPIO_EDGE_RISING)
+		c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
+
+	if (edge & TWL4030_GPIO_EDGE_FALLING)
+		c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
+
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(base);
+	if (ret >= 0) {
+		/* clear the previous rising/falling values */
+		reg =
+		(u8) (ret &
+			~(MASK_GPIO_EDR1_GPIOxFALLING(c_off) |
+			MASK_GPIO_EDR1_GPIOxRISING(c_off)));
+		reg |= c_msk;
+		ret = gpio_twl4030_write(base, reg);
+	}
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_edge_ctrl);
+
+/*
+ * Configure debounce timing value for a GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_debounce(int gpio, int enable)
+{
+	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
+	u8 d_msk = MASK_GPIO_DEBEN_GPIOxDEB(GET_GPIO_DATA_OFF(gpio));
+	u8 reg = 0;
+	u8 base = 0;
+	int ret = 0;
+
+	if (unlikely((gpio >= TWL4030_GPIO_MAX)
+		|| !(gpio_usage_count & (0x1 << gpio))))
+		return -EPERM;
+
+	base = REG_GPIO_DEBEN1 + d_bnk;
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(base);
+	if (ret >= 0) {
+		if (enable)
+			reg = (u8) ((ret) | (d_msk));
+		else
+			reg = (u8) ((ret) & ~(d_msk));
+
+		ret = gpio_twl4030_write(base, reg);
+	}
+	mutex_unlock(&gpio_lock);
+	return ret;
+}
+EXPORT_SYMBOL(twl4030_set_gpio_debounce);
+
+#if 0
+/*
+ * Configure Card detect for GPIO pin on TWL4030
+ */
+int twl4030_set_gpio_card_detect(int gpio, int enable)
+{
+	u8 reg = 0;
+	u8 msk = (1 << gpio);
+	int ret = 0;
+
+	/* Only GPIO 0 or 1 can be used for CD feature.. */
+	if (unlikely((gpio >= TWL4030_GPIO_MAX)
+		|| !(gpio_usage_count & (0x1 << gpio))
+		|| (gpio >= TWL4030_GPIO_MAX_CD))) {
+		return -EPERM;
+	}
+
+	mutex_lock(&gpio_lock);
+	ret = gpio_twl4030_read(REG_GPIO_CTRL);
+	if (ret >= 0) {
+		if (enable)
+			reg = (u8) (ret | msk);
+		else
+			reg = (u8) (ret & ~msk);
+
+		ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
+	}
+	mutex_unlock(&gpio_lock);
+	return (ret);
+}
+#endif
+
+/* MODULE FUNCTIONS */
+
+/*
+ * gpio_unmask_thread() runs as a kernel thread.  It is awakened by the unmask
+ * method for the GPIO interrupts.  It unmasks all of the GPIO interrupts
+ * specified in the gpio_pending_unmask bitmask.  We have to do the unmasking
+ * in a kernel thread rather than directly in the unmask method because of the
+ * need to access the TWL4030 via the I2C bus.  Note that we don't need to be
+ * concerned about race conditions where the request to unmask a GPIO interrupt
+ * has already been cancelled before this thread does the unmasking.  If a GPIO
+ * interrupt is improperly unmasked, then the IRQ handler for it will mask it
+ * when an interrupt occurs.
+ */
+static int twl4030_gpio_unmask_thread(void *data)
+{
+	current->flags |= PF_NOFREEZE;
+
+	while (!kthread_should_stop()) {
+		int irq;
+		unsigned int gpio_unmask;
+
+		local_irq_disable();
+		gpio_unmask = gpio_pending_unmask;
+		gpio_pending_unmask = 0;
+		local_irq_enable();
+
+		for (irq = twl4030_gpio_irq_base; 0 != gpio_unmask;
+				gpio_unmask >>= 1, irq++) {
+			if (gpio_unmask & 0x1)
+				twl4030_gpio_unmask(irq);
+		}
+
+		local_irq_disable();
+		if (!gpio_pending_unmask)
+			set_current_state(TASK_INTERRUPTIBLE);
+		local_irq_enable();
+
+		schedule();
+	}
+	set_current_state(TASK_RUNNING);
+	return 0;
+}
+
+/*
+ * do_twl4030_gpio_irq() is the desc->handle method for each of the twl4030
+ * gpio interrupts.  It executes in kernel thread context.
+ * On entry, cpu interrupts are enabled.
+ */
+static void do_twl4030_gpio_irq(unsigned int irq, irq_desc_t *desc)
+{
+	struct irqaction *action;
+	const unsigned int cpu = smp_processor_id();
+
+	desc->status |= IRQ_LEVEL;
+
+	/*
+	 * Acknowledge, clear _AND_ disable the interrupt.
+	 */
+	twl4030_gpio_mask_and_ack(irq);
+
+	if (!desc->depth) {
+		kstat_cpu(cpu).irqs[irq]++;
+
+		action = desc->action;
+		if (action) {
+			int ret;
+			int status = 0;
+			int retval = 0;
+			do {
+				/* Call the ISR with cpu interrupts enabled. */
+				ret = action->handler(irq, action->dev_id);
+				if (ret == IRQ_HANDLED)
+					status |= action->flags;
+				retval |= ret;
+				action = action->next;
+			} while (action);
+
+			if (retval != IRQ_HANDLED)
+				printk(KERN_ERR "ISR for TWL4030 GPIO"
+					" irq %d can't handle interrupt\n",
+					irq);
+
+			if (!desc->depth)
+				twl4030_gpio_unmask(irq);
+		}
+	}
+}
+
+/*
+ * do_twl4030_gpio_module_irq() is the desc->handle method for the twl4030 gpio
+ * module interrupt.  It executes in kernel thread context.
+ * This is a chained interrupt, so there is no desc->action method for it.
+ * We query the gpio module interrupt controller in the twl4030 to determine
+ * which gpio lines are generating interrupt requests, and then call the
+ * desc->handle method for each gpio that needs service.
+ * On entry, cpu interrupts are disabled.
+ */
+static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
+{
+	const unsigned int cpu = smp_processor_id();
+
+	desc->status |= IRQ_LEVEL;
+	/*
+	* The desc->handle method would normally call the desc->chip->ack
+	* method here, but we won't bother since our ack method is NULL.
+	*/
+	if (!desc->depth) {
+		int gpio_irq;
+		unsigned int gpio_isr;
+
+		kstat_cpu(cpu).irqs[irq]++;
+		local_irq_enable();
+
+		mutex_lock(&gpio_lock);
+		if (gpio_read_isr(&gpio_isr))
+			gpio_isr = 0;
+		mutex_unlock(&gpio_lock);
+
+		for (gpio_irq = twl4030_gpio_irq_base; 0 != gpio_isr;
+			gpio_isr >>= 1, gpio_irq++) {
+			if (gpio_isr & 0x1) {
+				irq_desc_t *d = irq_desc + gpio_irq;
+				d->handle_irq(gpio_irq, d);
+			}
+		}
+
+		local_irq_disable();
+		/*
+		 * Here is where we should call the unmask method, but again we
+		 * won't bother since it is NULL.
+		 */
+	}
+}
+
+/*----------------------------------------------------------------------*/
+
+static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
+{
+	return twl4030_set_gpio_direction(offset, 1);
+}
+
+static int twl_get(struct gpio_chip *chip, unsigned offset)
+{
+	int status = twl4030_get_gpio_datain(offset);
+
+	return (status < 0) ? 0 : status;
+}
+
+static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
+{
+	twl4030_set_gpio_dataout(offset, value);
+	return twl4030_set_gpio_direction(offset, 0);
+}
+
+static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	twl4030_set_gpio_dataout(offset, value);
+}
+
+static struct gpio_chip twl_gpiochip = {
+	.label			= "twl4030",
+	.owner			= THIS_MODULE,
+	.direction_input	= twl_direction_in,
+	.get			= twl_get,
+	.direction_output	= twl_direction_out,
+	.set			= twl_set,
+	.can_sleep		= 1,
+};
+
+/*----------------------------------------------------------------------*/
+
+static int gpio_twl4030_remove(struct platform_device *pdev);
+
+static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
+{
+	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+	int ret;
+	int irq = 0;
+
+	/* All GPIO interrupts are initially masked */
+	gpio_pending_unmask = 0;
+	gpio_imr_shadow = GPIO_32_MASK;
+	ret = gpio_write_imr(gpio_imr_shadow);
+
+	twl4030_gpio_irq_base = pdata->irq_base;
+	twl4030_gpio_irq_end = pdata->irq_end;
+
+	if ((twl4030_gpio_irq_end - twl4030_gpio_irq_base) > 0) {
+		if (is_module()) {
+			dev_err(&pdev->dev,
+				"can't dispatch IRQs from modules\n");
+			goto no_irqs;
+		}
+		if (twl4030_gpio_irq_end > NR_IRQS) {
+			dev_err(&pdev->dev,
+				"last IRQ is too large: %d\n",
+				twl4030_gpio_irq_end);
+			return -EINVAL;
+		}
+	} else {
+		dev_notice(&pdev->dev,
+			"no IRQs being dispatched\n");
+		goto no_irqs;
+	}
+
+	if (!ret) {
+		/*
+		 * Create a kernel thread to handle deferred unmasking of gpio
+		 * interrupts.
+		 */
+		gpio_unmask_thread = kthread_create(twl4030_gpio_unmask_thread,
+			NULL, "twl4030 gpio");
+		if (!gpio_unmask_thread) {
+			dev_err(&pdev->dev,
+				"could not create twl4030 gpio unmask"
+				" thread!\n");
+			ret = -ENOMEM;
+		}
+	}
+
+	if (!ret) {
+		/* install an irq handler for each of the gpio interrupts */
+		for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end;
+				irq++) {
+			set_irq_chip(irq, &twl4030_gpio_irq_chip);
+			set_irq_handler(irq, do_twl4030_gpio_irq);
+			set_irq_flags(irq, IRQF_VALID);
+		}
+
+		/* gpio module IRQ */
+		irq = platform_get_irq(pdev, 0);
+
+		/*
+		 * Install an irq handler to demultiplex the gpio module
+		 * interrupt.
+		 */
+		set_irq_chip(irq, &twl4030_gpio_module_irq_chip);
+		set_irq_chained_handler(irq, do_twl4030_gpio_module_irq);
+		wake_up_process(gpio_unmask_thread);
+
+		dev_info(&pdev->dev, "IRQ %d chains IRQs %d..%d\n", irq,
+			twl4030_gpio_irq_base, twl4030_gpio_irq_end - 1);
+	}
+
+no_irqs:
+	if (!ret) {
+		twl_gpiochip.base = pdata->gpio_base;
+		twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
+		twl_gpiochip.dev = &pdev->dev;
+
+		ret = gpiochip_add(&twl_gpiochip);
+		if (ret < 0) {
+			dev_err(&pdev->dev,
+					"could not register gpiochip, %d\n",
+					ret);
+			twl_gpiochip.ngpio = 0;
+			gpio_twl4030_remove(pdev);
+		} else if (pdata->setup) {
+			int status;
+
+			status = pdata->setup(&pdev->dev,
+					pdata->gpio_base, TWL4030_GPIO_MAX);
+			if (status)
+				dev_dbg(&pdev->dev, "setup --> %d\n", status);
+		}
+	}
+
+	return ret;
+}
+
+static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
+{
+	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
+	int status;
+	int irq;
+
+	if (pdata->teardown) {
+		status = pdata->teardown(&pdev->dev,
+				pdata->gpio_base, TWL4030_GPIO_MAX);
+		if (status) {
+			dev_dbg(&pdev->dev, "teardown --> %d\n", status);
+			return status;
+		}
+	}
+
+	status = gpiochip_remove(&twl_gpiochip);
+	if (status < 0)
+		return status;
+
+	if (is_module() || (twl4030_gpio_irq_end - twl4030_gpio_irq_base) <= 0)
+		return 0;
+
+	/* uninstall the gpio demultiplexing interrupt handler */
+	irq = platform_get_irq(pdev, 0);
+	set_irq_handler(irq, NULL);
+	set_irq_flags(irq, 0);
+
+	/* uninstall the irq handler for each of the gpio interrupts */
+	for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end; irq++) {
+		set_irq_handler(irq, NULL);
+		set_irq_flags(irq, 0);
+	}
+
+	/* stop the gpio unmask kernel thread */
+	if (gpio_unmask_thread) {
+		kthread_stop(gpio_unmask_thread);
+		gpio_unmask_thread = NULL;
+	}
+
+	return 0;
+}
+
+/* Note:  this hardware lives inside an I2C-based multi-function device. */
+MODULE_ALIAS("platform:twl4030_gpio");
+
+static struct platform_driver gpio_twl4030_driver = {
+	.driver.name	= "twl4030_gpio",
+	.driver.owner	= THIS_MODULE,
+	.probe		= gpio_twl4030_probe,
+	.remove		= __devexit_p(gpio_twl4030_remove),
+};
+
+static int __init gpio_twl4030_init(void)
+{
+	return platform_driver_register(&gpio_twl4030_driver);
+}
+subsys_initcall(gpio_twl4030_init);
+
+static void __exit gpio_twl4030_exit(void)
+{
+	platform_driver_unregister(&gpio_twl4030_driver);
+}
+module_exit(gpio_twl4030_exit);
+
+MODULE_AUTHOR("Texas Instruments, Inc.");
+MODULE_DESCRIPTION("GPIO interface for TWL4030");
+MODULE_LICENSE("GPL");
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -157,10 +157,6 @@ config TWL4030_CORE
 	help
 	  Say yes here if you have TWL4030 chip on your board
 
-config TWL4030_GPIO
-	bool "TWL4030 GPIO Driver"
-	depends on TWL4030_CORE && GPIOLIB
-
 config TWL4030_MADC
 	tristate "TWL4030 MADC Driver"
 	depends on TWL4030_CORE
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -25,7 +25,6 @@ obj-$(CONFIG_MENELAUS)		+= menelaus.o
 obj-$(CONFIG_SENSORS_TSL2550)	+= tsl2550.o
 obj-$(CONFIG_SENSORS_TSL2563)	+= tsl2563.o
 obj-$(CONFIG_TWL4030_CORE)	+= twl4030-core.o twl4030-pwrirq.o twl4030-power.o
-obj-$(CONFIG_TWL4030_GPIO)	+= twl4030-gpio.o
 obj-$(CONFIG_TWL4030_USB)	+= twl4030-usb.o
 obj-$(CONFIG_TWL4030_POWEROFF)	+= twl4030-poweroff.o
 obj-$(CONFIG_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -51,7 +51,7 @@
 #define twl_has_keypad()	false
 #endif
 
-#ifdef CONFIG_TWL4030_GPIO
+#if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
 #define twl_has_gpio()	true
 #else
 #define twl_has_gpio()	false
@@ -1091,10 +1091,6 @@ twl4030_probe(struct i2c_client *client,
 		mutex_init(&twl->xfer_lock);
 	}
 
-	status = add_children(pdata);
-	if (status < 0)
-		goto fail;
-
 	/*
 	 * Check if the PIH module is initialized, if yes, then init
 	 * the T2 Interrupt subsystem
@@ -1109,10 +1105,10 @@ twl4030_probe(struct i2c_client *client,
 				client->irq, pdata->irq_base, pdata->irq_end - 1);
 	}
 
-	return 0;
-
+	status = add_children(pdata);
 fail:
-	twl4030_remove(client);
+	if (status < 0)
+		twl4030_remove(client);
 	return status;
 }
 
--- a/drivers/i2c/chips/twl4030-gpio.c
+++ /dev/null
@@ -1,896 +0,0 @@
-/*
- * linux/drivers/i2c/chips/twl4030_gpio.c
- *
- * Copyright (C) 2006-2007 Texas Instruments, Inc.
- * Copyright (C) 2006 MontaVista Software, Inc.
- *
- * Code re-arranged and cleaned up by:
- *	Syed Mohammed Khasim <x0khasim@ti.com>
- *
- * Initial Code:
- *	Andy Lowe / Nishanth Menon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel_stat.h>
-#include <linux/init.h>
-#include <linux/time.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/kthread.h>
-#include <linux/irq.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-#include <linux/i2c/twl4030.h>
-#include <linux/i2c/twl4030-gpio.h>
-
-#include <mach/irqs.h>
-#include <asm/mach/irq.h>
-#include <mach/gpio.h>
-#include <mach/mux.h>
-
-
-/* REVISIT when these symbols vanish elsewhere, remove them here too */
-#undef TWL4030_GPIO_IRQ_BASE
-#undef TWL4030_GPIO_IRQ_END
-#undef TWL4030_MODIRQ_GPIO
-
-static struct gpio_chip twl_gpiochip;
-static int twl4030_gpio_irq_base;
-static int twl4030_gpio_irq_end;
-
-
-/* BitField Definitions */
-
-/* Data banks : 3 banks for 8 gpios each */
-#define DATA_BANK_MAX				8
-#define GET_GPIO_DATA_BANK(x)			((x)/DATA_BANK_MAX)
-#define GET_GPIO_DATA_OFF(x)			((x)%DATA_BANK_MAX)
-
-/* GPIODATADIR Fields each block 0-7 */
-#define BIT_GPIODATADIR_GPIOxDIR(x)		(x)
-#define MASK_GPIODATADIR_GPIOxDIR(x)		(0x01 << (x))
-
-/* GPIODATAIN Fields each block 0-7 */
-#define BIT_GPIODATAIN_GPIOxIN(x)		(x)
-#define MASK_GPIODATAIN_GPIOxIN(x)		(0x01 << (x))
-
-/* GPIODATAOUT Fields each block 0-7 */
-#define BIT_GPIODATAOUT_GPIOxOUT(x)		(x)
-#define MASK_GPIODATAOUT_GPIOxOUT(x)		(0x01 << (x))
-
-/* CLEARGPIODATAOUT Fields */
-#define BIT_CLEARGPIODATAOUT_GPIOxOUT(x)	(x)
-#define MASK_CLEARGPIODATAOUT_GPIOxOUT(x)	(0x01 << (x))
-
-/* SETGPIODATAOUT Fields */
-#define BIT_SETGPIODATAOUT_GPIOxOUT(x)		(x)
-#define MASK_SETGPIODATAOUT_GPIOxOUT(x)		(0x01 << (x))
-
-/* GPIO_DEBEN Fields */
-#define BIT_GPIO_DEBEN_GPIOxDEB(x)		(x)
-#define MASK_GPIO_DEBEN_GPIOxDEB(x)		(0x01 << (x))
-
-/* GPIO_ISR1A Fields */
-#define BIT_GPIO_ISR_GPIOxISR(x)		(x)
-#define MASK_GPIO_ISR_GPIOxISR(x)		(0x01 << (x))
-
-/* GPIO_IMR1A Fields */
-#define BIT_GPIO_IMR1A_GPIOxIMR(x)		(x)
-#define MASK_GPIO_IMR1A_GPIOxIMR(x)		(0x01 << (x))
-
-/* GPIO_SIR1 Fields */
-#define BIT_GPIO_SIR1_GPIOxSIR(x)		(x)
-#define MASK_GPIO_SIR1_GPIO0SIR			(0x01 << (x))
-
-
-/* Control banks : 5 banks for 4 gpios each */
-#define DATA_CTL_MAX			4
-#define GET_GPIO_CTL_BANK(x)		((x)/DATA_CTL_MAX)
-#define GET_GPIO_CTL_OFF(x)		((x)%DATA_CTL_MAX)
-#define GPIO_BANK_MAX			GET_GPIO_CTL_BANK(TWL4030_GPIO_MAX)
-
-/* GPIOPUPDCTRx Fields 5 banks of 4 gpios each */
-#define BIT_GPIOPUPDCTR1_GPIOxPD(x)	(2 * (x))
-#define MASK_GPIOPUPDCTR1_GPIOxPD(x)	(0x01 << (2 * (x)))
-#define BIT_GPIOPUPDCTR1_GPIOxPU(x)	((x) + 1)
-#define MASK_GPIOPUPDCTR1_GPIOxPU(x)	(0x01 << (((2 * (x)) + 1)))
-
-/* GPIO_EDR1 Fields */
-#define BIT_GPIO_EDR1_GPIOxFALLING(x)	(2 * (x))
-#define MASK_GPIO_EDR1_GPIOxFALLING(x)	(0x01 << (2 * (x)))
-#define BIT_GPIO_EDR1_GPIOxRISING(x)	((x) + 1)
-#define MASK_GPIO_EDR1_GPIOxRISING(x)	(0x01 << (((2 * (x)) + 1)))
-
-/* GPIO_SIH_CTRL Fields */
-#define BIT_GPIO_SIH_CTRL_EXCLEN	(0x000)
-#define MASK_GPIO_SIH_CTRL_EXCLEN	(0x00000001)
-#define BIT_GPIO_SIH_CTRL_PENDDIS	(0x001)
-#define MASK_GPIO_SIH_CTRL_PENDDIS	(0x00000002)
-#define BIT_GPIO_SIH_CTRL_COR		(0x002)
-#define MASK_GPIO_SIH_CTRL_COR		(0x00000004)
-
-/* GPIO_CTRL Fields */
-#define BIT_GPIO_CTRL_GPIO0CD1		(0x000)
-#define MASK_GPIO_CTRL_GPIO0CD1		(0x00000001)
-#define BIT_GPIO_CTRL_GPIO1CD2		(0x001)
-#define MASK_GPIO_CTRL_GPIO1CD2		(0x00000002)
-#define BIT_GPIO_CTRL_GPIO_ON		(0x002)
-#define MASK_GPIO_CTRL_GPIO_ON		(0x00000004)
-
-/* Mask for GPIO registers when aggregated into a 32-bit integer */
-#define GPIO_32_MASK			0x0003ffff
-
-/* Data structures */
-static DEFINE_MUTEX(gpio_lock);
-
-/* store usage of each GPIO. - each bit represents one GPIO */
-static unsigned int gpio_usage_count;
-
-/* shadow the imr register */
-static unsigned int gpio_imr_shadow;
-
-/* bitmask of pending requests to unmask gpio interrupts */
-static unsigned int gpio_pending_unmask;
-
-/* pointer to gpio unmask thread struct */
-static struct task_struct *gpio_unmask_thread;
-
-/*
- * Helper functions to read and write the GPIO ISR and IMR registers as
- * 32-bit integers. Functions return 0 on success, non-zero otherwise.
- * The caller must hold gpio_lock.
- */
-
-static int gpio_read_isr(unsigned int *isr)
-{
-	int ret;
-
-	*isr = 0;
-	ret = twl4030_i2c_read(TWL4030_MODULE_GPIO, (u8 *) isr,
-			REG_GPIO_ISR1A, 3);
-	le32_to_cpup(isr);
-	*isr &= GPIO_32_MASK;
-
-	return ret;
-}
-
-static int gpio_write_isr(unsigned int isr)
-{
-	isr &= GPIO_32_MASK;
-	/*
-	 * The buffer passed to the twl4030_i2c_write() routine must have an
-	 * extra byte at the beginning reserved for its internal use.
-	 */
-	isr <<= 8;
-	isr = cpu_to_le32(isr);
-	return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &isr,
-				REG_GPIO_ISR1A, 3);
-}
-
-static int gpio_write_imr(unsigned int imr)
-{
-	imr &= GPIO_32_MASK;
-	/*
-	 * The buffer passed to the twl4030_i2c_write() routine must have an
-	 * extra byte at the beginning reserved for its internal use.
-	 */
-	imr <<= 8;
-	imr = cpu_to_le32(imr);
-	return twl4030_i2c_write(TWL4030_MODULE_GPIO, (u8 *) &imr,
-				REG_GPIO_IMR1A, 3);
-}
-
-/*
- * These routines are analagous to the irqchip methods, but they are designed
- * to be called from thread context with cpu interrupts enabled and with no
- * locked spinlocks.  We call these routines from our custom IRQ handler
- * instead of the usual irqchip methods.
- */
-static void twl4030_gpio_mask_and_ack(unsigned int irq)
-{
-	int gpio = irq - twl4030_gpio_irq_base;
-
-	mutex_lock(&gpio_lock);
-	/* mask */
-	gpio_imr_shadow |= (1 << gpio);
-	gpio_write_imr(gpio_imr_shadow);
-	/* ack */
-	gpio_write_isr(1 << gpio);
-	mutex_unlock(&gpio_lock);
-}
-
-static void twl4030_gpio_unmask(unsigned int irq)
-{
-	int gpio = irq - twl4030_gpio_irq_base;
-
-	mutex_lock(&gpio_lock);
-	gpio_imr_shadow &= ~(1 << gpio);
-	gpio_write_imr(gpio_imr_shadow);
-	mutex_unlock(&gpio_lock);
-}
-
-/*
- * These are the irqchip methods for the TWL4030 GPIO interrupts.
- * Our IRQ handle method doesn't call these, but they will be called by
- * other routines such as setup_irq() and enable_irq().  They are called
- * with cpu interrupts disabled and with a lock on the irq_controller_lock
- * spinlock.  This complicates matters, because accessing the TWL4030 GPIO
- * interrupt controller requires I2C bus transactions that can't be initiated
- * in this context.  Our solution is to defer accessing the interrupt
- * controller to a kernel thread.  We only need to support the unmask method.
- */
-
-static void twl4030_gpio_mask_and_ack_irqchip(unsigned int irq) {}
-static void twl4030_gpio_mask_irqchip(unsigned int irq) {}
-
-static void twl4030_gpio_unmask_irqchip(unsigned int irq)
-{
-	int gpio = irq - twl4030_gpio_irq_base;
-
-	gpio_pending_unmask |= (1 << gpio);
-	if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
-		wake_up_process(gpio_unmask_thread);
-}
-
-static struct irq_chip twl4030_gpio_irq_chip = {
-	.name	= "twl4030",
-	.ack	= twl4030_gpio_mask_and_ack_irqchip,
-	.mask	= twl4030_gpio_mask_irqchip,
-	.unmask	= twl4030_gpio_unmask_irqchip,
-};
-
-/*
- * These are the irqchip methods for the TWL4030 PIH GPIO module interrupt.
- * The PIH module doesn't have interrupt masking capability, so these
- * methods are NULL.
- */
-static void twl4030_gpio_module_ack(unsigned int irq) {}
-static void twl4030_gpio_module_mask(unsigned int irq) {}
-static void twl4030_gpio_module_unmask(unsigned int irq) {}
-static struct irq_chip twl4030_gpio_module_irq_chip = {
-	.ack	= twl4030_gpio_module_ack,
-	.mask	= twl4030_gpio_module_mask,
-	.unmask	= twl4030_gpio_module_unmask,
-};
-
-/*
- * To configure TWL4030 GPIO module registers
- */
-static inline int gpio_twl4030_write(u8 address, u8 data)
-{
-	int ret = 0;
-
-	ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, data, address);
-	return ret;
-}
-
-/*
- * To read a TWL4030 GPIO module register
- */
-static inline int gpio_twl4030_read(u8 address)
-{
-	u8 data;
-	int ret = 0;
-
-	ret = twl4030_i2c_read_u8(TWL4030_MODULE_GPIO, &data, address);
-	if (ret >= 0)
-		ret = data;
-	return ret;
-}
-
-/*
- * twl4030 GPIO request function
- */
-int twl4030_request_gpio(int gpio)
-{
-	int ret = 0;
-
-	if (unlikely(gpio >= TWL4030_GPIO_MAX))
-		return -EPERM;
-
-	ret = gpio_request(twl_gpiochip.base + gpio, NULL);
-	if (ret < 0)
-		return ret;
-
-	mutex_lock(&gpio_lock);
-	if (gpio_usage_count & (0x1 << gpio)) {
-		ret = -EBUSY;
-	} else {
-		/* First time usage? - switch on GPIO module */
-		if (!gpio_usage_count) {
-			ret = gpio_twl4030_write(REG_GPIO_CTRL,
-					MASK_GPIO_CTRL_GPIO_ON);
-			ret = gpio_twl4030_write(REG_GPIO_SIH_CTRL, 0x00);
-		}
-		if (!ret)
-			gpio_usage_count |= (0x1 << gpio);
-		else
-			gpio_free(twl_gpiochip.base + gpio);
-	}
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-EXPORT_SYMBOL(twl4030_request_gpio);
-
-/*
- * TWL4030 GPIO free module
- */
-int twl4030_free_gpio(int gpio)
-{
-	int ret = 0;
-
-	if (unlikely(gpio >= TWL4030_GPIO_MAX))
-		return -EPERM;
-
-	mutex_lock(&gpio_lock);
-
-	if ((gpio_usage_count & (0x1 << gpio)) == 0) {
-		ret = -EPERM;
-	} else {
-		gpio_usage_count &= ~(0x1 << gpio);
-		gpio_free(twl_gpiochip.base + gpio);
-	}
-
-	/* Last time usage? - switch off GPIO module */
-	if (ret == 0 && !gpio_usage_count)
-		ret = gpio_twl4030_write(REG_GPIO_CTRL, 0x0);
-
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-EXPORT_SYMBOL(twl4030_free_gpio);
-
-/*
- * Set direction for TWL4030 GPIO
- */
-static int twl4030_set_gpio_direction(int gpio, int is_input)
-{
-	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
-	u8 d_msk = MASK_GPIODATADIR_GPIOxDIR(GET_GPIO_DATA_OFF(gpio));
-	u8 reg = 0;
-	u8 base = REG_GPIODATADIR1 + d_bnk;
-	int ret = 0;
-
-	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(base);
-	if (ret >= 0) {
-		if (is_input)
-			reg = (u8) ((ret) & ~(d_msk));
-		else
-			reg = (u8) ((ret) | (d_msk));
-
-		ret = gpio_twl4030_write(base, reg);
-	}
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-
-/*
- * To enable/disable GPIO pin on TWL4030
- */
-static int twl4030_set_gpio_dataout(int gpio, int enable)
-{
-	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
-	u8 d_msk = MASK_GPIODATAOUT_GPIOxOUT(GET_GPIO_DATA_OFF(gpio));
-	u8 base = 0;
-	int ret = 0;
-
-	if (unlikely(!(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	if (enable)
-		base = REG_SETGPIODATAOUT1 + d_bnk;
-	else
-		base = REG_CLEARGPIODATAOUT1 + d_bnk;
-
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_write(base, d_msk);
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-
-/*
- * To get the status of a GPIO pin on TWL4030
- */
-int twl4030_get_gpio_datain(int gpio)
-{
-	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
-	u8 d_off = BIT_GPIODATAIN_GPIOxIN(GET_GPIO_DATA_OFF(gpio));
-	u8 base = 0;
-	int ret = 0;
-
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	base = REG_GPIODATAIN1 + d_bnk;
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(base);
-	mutex_unlock(&gpio_lock);
-	if (ret > 0)
-		ret = (ret >> d_off) & 0x1;
-
-	return ret;
-}
-EXPORT_SYMBOL(twl4030_get_gpio_datain);
-
-#if 0
-/*
- * Configure PULL type for a GPIO pin on TWL4030
- */
-int twl4030_set_gpio_pull(int gpio, int pull_dircn)
-{
-	u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
-	u8 c_off = GET_GPIO_CTL_OFF(gpio);
-	u8 c_msk = 0;
-	u8 reg = 0;
-	u8 base = 0;
-	int ret = 0;
-
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)	||
-		!(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	base = REG_GPIOPUPDCTR1 + c_bnk;
-	if (pull_dircn == TWL4030_GPIO_PULL_DOWN)
-		c_msk = MASK_GPIOPUPDCTR1_GPIOxPD(c_off);
-	else if (pull_dircn == TWL4030_GPIO_PULL_UP)
-		c_msk = MASK_GPIOPUPDCTR1_GPIOxPU(c_off);
-
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(base);
-	if (ret >= 0) {
-		/* clear the previous up/down values */
-		reg = (u8) (ret);
-		reg &= ~(MASK_GPIOPUPDCTR1_GPIOxPU(c_off) |
-			MASK_GPIOPUPDCTR1_GPIOxPD(c_off));
-		reg |= c_msk;
-		ret = gpio_twl4030_write(base, reg);
-	}
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-#endif
-
-/*
- * Configure Edge control for a GPIO pin on TWL4030
- *
- * FIXME this should just be the irq_chip.set_type() method
- */
-int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
-{
-	u8 c_bnk = GET_GPIO_CTL_BANK(gpio);
-	u8 c_off = GET_GPIO_CTL_OFF(gpio);
-	u8 c_msk = 0;
-	u8 reg = 0;
-	u8 base = 0;
-	int ret = 0;
-
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	base = REG_GPIO_EDR1 + c_bnk;
-
-	if (edge & TWL4030_GPIO_EDGE_RISING)
-		c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
-
-	if (edge & TWL4030_GPIO_EDGE_FALLING)
-		c_msk |= MASK_GPIO_EDR1_GPIOxFALLING(c_off);
-
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(base);
-	if (ret >= 0) {
-		/* clear the previous rising/falling values */
-		reg =
-		(u8) (ret &
-			~(MASK_GPIO_EDR1_GPIOxFALLING(c_off) |
-			MASK_GPIO_EDR1_GPIOxRISING(c_off)));
-		reg |= c_msk;
-		ret = gpio_twl4030_write(base, reg);
-	}
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-EXPORT_SYMBOL(twl4030_set_gpio_edge_ctrl);
-
-/*
- * Configure debounce timing value for a GPIO pin on TWL4030
- */
-int twl4030_set_gpio_debounce(int gpio, int enable)
-{
-	u8 d_bnk = GET_GPIO_DATA_BANK(gpio);
-	u8 d_msk = MASK_GPIO_DEBEN_GPIOxDEB(GET_GPIO_DATA_OFF(gpio));
-	u8 reg = 0;
-	u8 base = 0;
-	int ret = 0;
-
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))))
-		return -EPERM;
-
-	base = REG_GPIO_DEBEN1 + d_bnk;
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(base);
-	if (ret >= 0) {
-		if (enable)
-			reg = (u8) ((ret) | (d_msk));
-		else
-			reg = (u8) ((ret) & ~(d_msk));
-
-		ret = gpio_twl4030_write(base, reg);
-	}
-	mutex_unlock(&gpio_lock);
-	return ret;
-}
-EXPORT_SYMBOL(twl4030_set_gpio_debounce);
-
-#if 0
-/*
- * Configure Card detect for GPIO pin on TWL4030
- */
-int twl4030_set_gpio_card_detect(int gpio, int enable)
-{
-	u8 reg = 0;
-	u8 msk = (1 << gpio);
-	int ret = 0;
-
-	/* Only GPIO 0 or 1 can be used for CD feature.. */
-	if (unlikely((gpio >= TWL4030_GPIO_MAX)
-		|| !(gpio_usage_count & (0x1 << gpio))
-		|| (gpio >= TWL4030_GPIO_MAX_CD))) {
-		return -EPERM;
-	}
-
-	mutex_lock(&gpio_lock);
-	ret = gpio_twl4030_read(REG_GPIO_CTRL);
-	if (ret >= 0) {
-		if (enable)
-			reg = (u8) (ret | msk);
-		else
-			reg = (u8) (ret & ~msk);
-
-		ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
-	}
-	mutex_unlock(&gpio_lock);
-	return (ret);
-}
-#endif
-
-/* MODULE FUNCTIONS */
-
-/*
- * gpio_unmask_thread() runs as a kernel thread.  It is awakened by the unmask
- * method for the GPIO interrupts.  It unmasks all of the GPIO interrupts
- * specified in the gpio_pending_unmask bitmask.  We have to do the unmasking
- * in a kernel thread rather than directly in the unmask method because of the
- * need to access the TWL4030 via the I2C bus.  Note that we don't need to be
- * concerned about race conditions where the request to unmask a GPIO interrupt
- * has already been cancelled before this thread does the unmasking.  If a GPIO
- * interrupt is improperly unmasked, then the IRQ handler for it will mask it
- * when an interrupt occurs.
- */
-static int twl4030_gpio_unmask_thread(void *data)
-{
-	current->flags |= PF_NOFREEZE;
-
-	while (!kthread_should_stop()) {
-		int irq;
-		unsigned int gpio_unmask;
-
-		local_irq_disable();
-		gpio_unmask = gpio_pending_unmask;
-		gpio_pending_unmask = 0;
-		local_irq_enable();
-
-		for (irq = twl4030_gpio_irq_base; 0 != gpio_unmask;
-				gpio_unmask >>= 1, irq++) {
-			if (gpio_unmask & 0x1)
-				twl4030_gpio_unmask(irq);
-		}
-
-		local_irq_disable();
-		if (!gpio_pending_unmask)
-			set_current_state(TASK_INTERRUPTIBLE);
-		local_irq_enable();
-
-		schedule();
-	}
-	set_current_state(TASK_RUNNING);
-	return 0;
-}
-
-/*
- * do_twl4030_gpio_irq() is the desc->handle method for each of the twl4030
- * gpio interrupts.  It executes in kernel thread context.
- * On entry, cpu interrupts are enabled.
- */
-static void do_twl4030_gpio_irq(unsigned int irq, irq_desc_t *desc)
-{
-	struct irqaction *action;
-	const unsigned int cpu = smp_processor_id();
-
-	desc->status |= IRQ_LEVEL;
-
-	/*
-	 * Acknowledge, clear _AND_ disable the interrupt.
-	 */
-	twl4030_gpio_mask_and_ack(irq);
-
-	if (!desc->depth) {
-		kstat_cpu(cpu).irqs[irq]++;
-
-		action = desc->action;
-		if (action) {
-			int ret;
-			int status = 0;
-			int retval = 0;
-			do {
-				/* Call the ISR with cpu interrupts enabled. */
-				ret = action->handler(irq, action->dev_id);
-				if (ret == IRQ_HANDLED)
-					status |= action->flags;
-				retval |= ret;
-				action = action->next;
-			} while (action);
-
-			if (retval != IRQ_HANDLED)
-				printk(KERN_ERR "ISR for TWL4030 GPIO"
-					" irq %d can't handle interrupt\n",
-					irq);
-
-			if (!desc->depth)
-				twl4030_gpio_unmask(irq);
-		}
-	}
-}
-
-/*
- * do_twl4030_gpio_module_irq() is the desc->handle method for the twl4030 gpio
- * module interrupt.  It executes in kernel thread context.
- * This is a chained interrupt, so there is no desc->action method for it.
- * We query the gpio module interrupt controller in the twl4030 to determine
- * which gpio lines are generating interrupt requests, and then call the
- * desc->handle method for each gpio that needs service.
- * On entry, cpu interrupts are disabled.
- */
-static void do_twl4030_gpio_module_irq(unsigned int irq, irq_desc_t *desc)
-{
-	const unsigned int cpu = smp_processor_id();
-
-	desc->status |= IRQ_LEVEL;
-	/*
-	* The desc->handle method would normally call the desc->chip->ack
-	* method here, but we won't bother since our ack method is NULL.
-	*/
-	if (!desc->depth) {
-		int gpio_irq;
-		unsigned int gpio_isr;
-
-		kstat_cpu(cpu).irqs[irq]++;
-		local_irq_enable();
-
-		mutex_lock(&gpio_lock);
-		if (gpio_read_isr(&gpio_isr))
-			gpio_isr = 0;
-		mutex_unlock(&gpio_lock);
-
-		for (gpio_irq = twl4030_gpio_irq_base; 0 != gpio_isr;
-			gpio_isr >>= 1, gpio_irq++) {
-			if (gpio_isr & 0x1) {
-				irq_desc_t *d = irq_desc + gpio_irq;
-				d->handle_irq(gpio_irq, d);
-			}
-		}
-
-		local_irq_disable();
-		/*
-		 * Here is where we should call the unmask method, but again we
-		 * won't bother since it is NULL.
-		 */
-	}
-}
-
-/*----------------------------------------------------------------------*/
-
-static int twl_direction_in(struct gpio_chip *chip, unsigned offset)
-{
-	return twl4030_set_gpio_direction(offset, 1);
-}
-
-static int twl_get(struct gpio_chip *chip, unsigned offset)
-{
-	int status = twl4030_get_gpio_datain(offset);
-
-	return (status < 0) ? 0 : status;
-}
-
-static int twl_direction_out(struct gpio_chip *chip, unsigned offset, int value)
-{
-	twl4030_set_gpio_dataout(offset, value);
-	return twl4030_set_gpio_direction(offset, 0);
-}
-
-static void twl_set(struct gpio_chip *chip, unsigned offset, int value)
-{
-	twl4030_set_gpio_dataout(offset, value);
-}
-
-static struct gpio_chip twl_gpiochip = {
-	.label			= "twl4030",
-	.owner			= THIS_MODULE,
-	.direction_input	= twl_direction_in,
-	.get			= twl_get,
-	.direction_output	= twl_direction_out,
-	.set			= twl_set,
-	.can_sleep		= 1,
-};
-
-/*----------------------------------------------------------------------*/
-
-static int gpio_twl4030_remove(struct platform_device *pdev);
-
-static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
-{
-	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-	int ret;
-	int irq = 0;
-
-	/* All GPIO interrupts are initially masked */
-	gpio_pending_unmask = 0;
-	gpio_imr_shadow = GPIO_32_MASK;
-	ret = gpio_write_imr(gpio_imr_shadow);
-
-	twl4030_gpio_irq_base = pdata->irq_base;
-	twl4030_gpio_irq_end = pdata->irq_end;
-
-	/* REVISIT skip most of this if the irq range is empty... */
-	if (!ret) {
-		/*
-		 * Create a kernel thread to handle deferred unmasking of gpio
-		 * interrupts.
-		 */
-		gpio_unmask_thread = kthread_create(twl4030_gpio_unmask_thread,
-			NULL, "twl4030 gpio");
-		if (!gpio_unmask_thread) {
-			dev_err(&pdev->dev,
-				"could not create twl4030 gpio unmask"
-				" thread!\n");
-			ret = -ENOMEM;
-		}
-	}
-
-	if (!ret) {
-		/* install an irq handler for each of the gpio interrupts */
-		for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end;
-				irq++) {
-			set_irq_chip(irq, &twl4030_gpio_irq_chip);
-			set_irq_handler(irq, do_twl4030_gpio_irq);
-			set_irq_flags(irq, IRQF_VALID);
-		}
-
-		/* gpio module IRQ */
-		irq = platform_get_irq(pdev, 0);
-
-		/*
-		 * Install an irq handler to demultiplex the gpio module
-		 * interrupt.
-		 */
-		set_irq_chip(irq, &twl4030_gpio_module_irq_chip);
-		set_irq_chained_handler(irq, do_twl4030_gpio_module_irq);
-		wake_up_process(gpio_unmask_thread);
-
-		dev_info(&pdev->dev, "IRQ %d chains IRQs %d..%d\n", irq,
-			twl4030_gpio_irq_base, twl4030_gpio_irq_end - 1);
-	}
-
-	if (!ret) {
-		twl_gpiochip.base = pdata->gpio_base;
-		twl_gpiochip.ngpio = TWL4030_GPIO_MAX;
-		twl_gpiochip.dev = &pdev->dev;
-
-		ret = gpiochip_add(&twl_gpiochip);
-		if (ret < 0) {
-			dev_err(&pdev->dev,
-					"could not register gpiochip, %d\n",
-					ret);
-			twl_gpiochip.ngpio = 0;
-			gpio_twl4030_remove(pdev);
-		} else if (pdata->setup) {
-			int status;
-
-			status = pdata->setup(&pdev->dev,
-					pdata->gpio_base, TWL4030_GPIO_MAX);
-			if (status)
-				dev_dbg(&pdev->dev, "setup --> %d\n", status);
-		}
-	}
-
-	return ret;
-}
-
-static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
-{
-	struct twl4030_gpio_platform_data *pdata = pdev->dev.platform_data;
-	int status;
-	int irq;
-
-	if (pdata->teardown) {
-		status = pdata->teardown(&pdev->dev,
-				pdata->gpio_base, TWL4030_GPIO_MAX);
-		if (status) {
-			dev_dbg(&pdev->dev, "teardown --> %d\n", status);
-			return status;
-		}
-	}
-
-	status = gpiochip_remove(&twl_gpiochip);
-	if (status < 0)
-		return status;
-
-	/* uninstall the gpio demultiplexing interrupt handler */
-	irq = platform_get_irq(pdev, 0);
-	set_irq_handler(irq, NULL);
-	set_irq_flags(irq, 0);
-
-	/* uninstall the irq handler for each of the gpio interrupts */
-	for (irq = twl4030_gpio_irq_base; irq < twl4030_gpio_irq_end; irq++) {
-		set_irq_handler(irq, NULL);
-		set_irq_flags(irq, 0);
-	}
-
-	/* stop the gpio unmask kernel thread */
-	if (gpio_unmask_thread) {
-		kthread_stop(gpio_unmask_thread);
-		gpio_unmask_thread = NULL;
-	}
-
-	return 0;
-}
-
-/* Note:  this hardware lives inside an I2C-based multi-function device. */
-MODULE_ALIAS("platform:twl4030_gpio");
-
-static struct platform_driver gpio_twl4030_driver = {
-	.driver.name	= "twl4030_gpio",
-	.driver.owner	= THIS_MODULE,
-	.probe		= gpio_twl4030_probe,
-	.remove		= __devexit_p(gpio_twl4030_remove),
-};
-
-static int __init gpio_twl4030_init(void)
-{
-	return platform_driver_register(&gpio_twl4030_driver);
-}
-module_init(gpio_twl4030_init);
-
-static void __exit gpio_twl4030_exit(void)
-{
-	platform_driver_unregister(&gpio_twl4030_driver);
-}
-module_exit(gpio_twl4030_exit);
-
-MODULE_AUTHOR("Texas Instruments, Inc.");
-MODULE_DESCRIPTION("GPIO interface for TWL4030");
-MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-27 21:17   ` Felipe Balbi
@ 2008-09-27 21:45     ` David Brownell
  2008-09-27 21:46       ` Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-27 21:45 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Saturday 27 September 2008, Felipe Balbi wrote:
> On Sat, Sep 27, 2008 at 12:14:29PM -0700, David Brownell wrote:
> > Here are some more cleanups to consider including ... these
> > should apply on top of all nine patches.
> 
> You want me to keep it on top of the other 9 (10) patches or meld it
> together ? I think it'd be better to meld on the previous patches so
> we introduce the patches the way they should look like. Right ?

Not sure it matters in this case; if we were talking about patches
that will merge upstream, I'd agree.

But what merges upstream will look like a brand new twl4030 core,
in drivers/mfd, so all this OMAP history will be gone.

So the issue here is just what's easiest for you and Tony.

- Dave

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/9] twl4030 updates
  2008-09-27 21:45     ` David Brownell
@ 2008-09-27 21:46       ` Felipe Balbi
  0 siblings, 0 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-27 21:46 UTC (permalink / raw)
  To: David Brownell; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren

On Sat, Sep 27, 2008 at 02:45:06PM -0700, David Brownell wrote:
> On Saturday 27 September 2008, Felipe Balbi wrote:
> > On Sat, Sep 27, 2008 at 12:14:29PM -0700, David Brownell wrote:
> > > Here are some more cleanups to consider including ... these
> > > should apply on top of all nine patches.
> > 
> > You want me to keep it on top of the other 9 (10) patches or meld it
> > together ? I think it'd be better to meld on the previous patches so
> > we introduce the patches the way they should look like. Right ?
> 
> Not sure it matters in this case; if we were talking about patches
> that will merge upstream, I'd agree.
> 
> But what merges upstream will look like a brand new twl4030 core,
> in drivers/mfd, so all this OMAP history will be gone.
> 
> So the issue here is just what's easiest for you and Tony.

Cool, Tony, what do you say ?

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-27 21:41 ` [PATCH 11/9] move twl4030-gpio to drivers/gpio David Brownell
@ 2008-09-27 22:29   ` Felipe Balbi
  2008-09-27 23:09     ` Felipe Balbi
  2008-09-27 23:29     ` David Brownell
  0 siblings, 2 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-27 22:29 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Sat, Sep 27, 2008 at 02:41:40PM -0700, David Brownell wrote:
> From: David Brownell <dbrownell@users.sourceforge.net>
> 
> Move the twl4030 GPIO support from drivers/i2c/chips to drivers/gpio,
> which is a more appropriate home for this code.
> 
> The Kconfig symbol name is changed to match the GPIO_* convention for
> such symbols, so config files must change in the obvious ways (Kconfig
> will prompt you).  There's now some helptext.
> 
> It can now be compiled as a module, should anyone really want to
> do that; that'll be mostly useful for test builds.  Sanity check the
> IRQ range we're given.
> 
> Initialization order needed a bit of work too:  core add_children()
> called only after IRQs get set up, gpio uses subsys_initcall.  This
> depends on a patch making i2c driver model init use postcore_initcall.
> 
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> ---
> NOTE:  requires an I2C patch:
> 
>   http://marc.info/?l=i2c&m=122227316012577&w=2
> 
> I CC'd Jean since that doesn't seem to be in his queue yet, and
> that's pretty essential to moving such TWL stuff out of the
> i2c/chips directory into more appropriate locations.

This patch breaks hsmmc.c:
arch/arm/mach-omap2/built-in.o: In function `hsmmc_card_detect':
/home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:51: undefined reference to `twl4030_get_gpio_datain'
arch/arm/mach-omap2/built-in.o: In function `hsmmc_cleanup':
/home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:93: undefined reference to `twl4030_free_gpio'
arch/arm/mach-omap2/built-in.o: In function `hsmmc_late_init':
/home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:64: undefined reference to `twl4030_request_gpio'
/home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:68: undefined reference to `twl4030_set_gpio_edge_ctrl'
/home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:78: undefined reference to `twl4030_set_gpio_debounce'

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-27 22:29   ` Felipe Balbi
@ 2008-09-27 23:09     ` Felipe Balbi
  2008-09-27 23:45       ` David Brownell
  2008-09-27 23:29     ` David Brownell
  1 sibling, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-27 23:09 UTC (permalink / raw)
  To: Felipe Balbi
  Cc: David Brownell, Felipe Balbi, linux-omap, Tony Lindgren,
	Jean Delvare

On Sun, Sep 28, 2008 at 01:29:05AM +0300, Felipe Balbi wrote:
> On Sat, Sep 27, 2008 at 02:41:40PM -0700, David Brownell wrote:
> > From: David Brownell <dbrownell@users.sourceforge.net>
> > 
> > Move the twl4030 GPIO support from drivers/i2c/chips to drivers/gpio,
> > which is a more appropriate home for this code.
> > 
> > The Kconfig symbol name is changed to match the GPIO_* convention for
> > such symbols, so config files must change in the obvious ways (Kconfig
> > will prompt you).  There's now some helptext.
> > 
> > It can now be compiled as a module, should anyone really want to
> > do that; that'll be mostly useful for test builds.  Sanity check the
> > IRQ range we're given.
> > 
> > Initialization order needed a bit of work too:  core add_children()
> > called only after IRQs get set up, gpio uses subsys_initcall.  This
> > depends on a patch making i2c driver model init use postcore_initcall.

We need something like the patch below (I can't find a substitute
to twl4030_set_gpio_edge_ctrl and twl4030_set_gpio_debounce):

==== patch 1 (desired) ====

diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 32b517b..3ca43aa 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -16,6 +16,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/gpio.h>
 #include <mach/hardware.h>
 #include <mach/mmc.h>
 #include <mach/board.h>
@@ -48,7 +49,7 @@
 
 static int hsmmc_card_detect(int irq)
 {
-	return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
+	return gpio_get_value(irq - TWL4030_GPIO_IRQ_BASE);
 }
 
 /*
@@ -61,7 +62,7 @@ static int hsmmc_late_init(struct device *dev)
 	/*
 	 * Configure TWL4030 GPIO parameters for MMC hotplug irq
 	 */
-	ret = twl4030_request_gpio(MMC1_CD_IRQ);
+	ret = gpio_request(MMC1_CD_IRQ, "mmc_card_detect");
 	if (ret)
 		goto err;
 
@@ -88,11 +89,7 @@ err:
 
 static void hsmmc_cleanup(struct device *dev)
 {
-	int ret = 0;
-
-	ret = twl4030_free_gpio(MMC1_CD_IRQ);
-	if (ret)
-		dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
+	gpio_free(MMC1_CD_IRQ);
 }
 
 #ifdef CONFIG_PM


> > 
> > Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
> > ---
> > NOTE:  requires an I2C patch:
> > 
> >   http://marc.info/?l=i2c&m=122227316012577&w=2
> > 
> > I CC'd Jean since that doesn't seem to be in his queue yet, and
> > that's pretty essential to moving such TWL stuff out of the
> > i2c/chips directory into more appropriate locations.
> 
> This patch breaks hsmmc.c:
> arch/arm/mach-omap2/built-in.o: In function `hsmmc_card_detect':
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:51: undefined reference to `twl4030_get_gpio_datain'
> arch/arm/mach-omap2/built-in.o: In function `hsmmc_cleanup':
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:93: undefined reference to `twl4030_free_gpio'
> arch/arm/mach-omap2/built-in.o: In function `hsmmc_late_init':
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:64: undefined reference to `twl4030_request_gpio'
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:68: undefined reference to `twl4030_set_gpio_edge_ctrl'
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:78: undefined reference to `twl4030_set_gpio_debounce'
> 
> -- 
> balbi
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
balbi

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-27 22:29   ` Felipe Balbi
  2008-09-27 23:09     ` Felipe Balbi
@ 2008-09-27 23:29     ` David Brownell
  1 sibling, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-09-27 23:29 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Saturday 27 September 2008, Felipe Balbi wrote:
> This patch breaks hsmmc.c:
> arch/arm/mach-omap2/built-in.o: In function `hsmmc_card_detect':
> /home/underline/workspace/linux-omap-2.6/arch/arm/mach-omap2/hsmmc.c:51: undefined reference to `twl4030_get_gpio_datain'
> 	... etc

Could you verify that still happens with a build-from-scratch?
Like, one in which you made sure to enable CONFIG_GPIO_TWL4030?

I certainly don't get those errors.  That's exactly why those
few TWL-specific symbols are left in that driver:  because that
file still uses them.  They get removed later, before this gets
sent upstream.

- Dave

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-27 23:09     ` Felipe Balbi
@ 2008-09-27 23:45       ` David Brownell
  2008-09-28  3:14         ` Felipe Balbi
  0 siblings, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-27 23:45 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Saturday 27 September 2008, Felipe Balbi wrote:
> We need something like the patch below (I can't find a substitute
> to twl4030_set_gpio_edge_ctrl and twl4030_set_gpio_debounce):

Something like that, yes.  I have other patches queued up though.

And meanwhile, your build seems goofed ... fix that first.

For the moment I'm waiting until HSMMC works again in the OMAP
tree before I submit patches for any of those issues ... and
some of them imply updates from upstream.  Like these two:

  http://marc.info/?l=linux-kernel&m=122239480403730&w=2
  http://marc.info/?l=linux-kernel&m=122239472903349&w=2

For the "edge control" thing, I have a patch pushing that into
the standard IRQF_TRIGGER_{RISING,FALLING} and set_irq_type()
calls ... there was never a need for a twl-specific call here.

For debouncing, see this LKML RFC:

  http://marc.info/?l=linux-kernel&m=122228602206108&w=2

I have a twl4030 patch using that mechanism, and that patch
covers four processor families.  (OMAP2, OMAP3, AT91, AVR32.)
The OMAP1 MPUIO lines have debouncing too, but it's ganged
(all sixteen MPUIO lines get debounced, or none do).  I know
of a few more chips with built-in debouncing... so the RFC is
IMO more "are there blocking problems doing it this way" than
"should it be done at all".

- Dave



> ==== patch 1 (desired) ====
> 
> diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
> index 32b517b..3ca43aa 100644
> --- a/arch/arm/mach-omap2/hsmmc.c
> +++ b/arch/arm/mach-omap2/hsmmc.c
> @@ -16,6 +16,7 @@
>  #include <linux/interrupt.h>
>  #include <linux/delay.h>
>  #include <linux/i2c/twl4030.h>
> +#include <linux/gpio.h>
>  #include <mach/hardware.h>
>  #include <mach/mmc.h>
>  #include <mach/board.h>
> @@ -48,7 +49,7 @@
>  
>  static int hsmmc_card_detect(int irq)
>  {
> -       return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
> +       return gpio_get_value(irq - TWL4030_GPIO_IRQ_BASE);

That's a non-portable version of irq_to_gpio() ... and one
which should use gpio_get_value_cansleep().  My patches use
a simpler scheme, which among other things lets other GPIOs
be used for card detect.

(I understand that not all OMAP3 customers want to use twl4030
for their power management ... and in any case, having this kind
of needless dependency between drivers is a Bad Thing.)


>  }
>  
>  /*
> @@ -61,7 +62,7 @@ static int hsmmc_late_init(struct device *dev)
>         /*
>          * Configure TWL4030 GPIO parameters for MMC hotplug irq
>          */
> -       ret = twl4030_request_gpio(MMC1_CD_IRQ);
> +       ret = gpio_request(MMC1_CD_IRQ, "mmc_card_detect");

Another inappropriate dependency, removed in my patches.

Note also that the TWL call currently does stuff gpio_request()
can't ... so this would be incorrect right now.  (It's the right
direction obviously, but fixing that needs my other patches.)

>         if (ret)
>                 goto err;
>  
> @@ -88,11 +89,7 @@ err:
>  
>  static void hsmmc_cleanup(struct device *dev)
>  {
> -       int ret = 0;
> -
> -       ret = twl4030_free_gpio(MMC1_CD_IRQ);
> -       if (ret)
> -               dev_err(dev, "Failed to configure TWL4030 GPIO IRQ\n");
> +       gpio_free(MMC1_CD_IRQ);

(That's the same inappropriate dependency.)


>  }
>  
>  #ifdef CONFIG_PM
> 


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 5/9] i2c: move twl4030-usb to platform_device
  2008-09-26 11:19         ` [PATCH 5/9] i2c: move twl4030-usb to platform_device Felipe Balbi
  2008-09-26 11:19           ` [PATCH 6/9] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-28  1:01           ` David Brownell
  2008-09-28  3:03             ` Felipe Balbi
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-28  1:01 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

On Friday 26 Septemb.er 2008, Felipe Balbi wrote:
> +       if (twl_has_usb() && pdata->usb) {
> +               pdev = platform_device_alloc("twl4030_usb", -1);
> +               if (pdev) {
> +                       twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
> +                       pdev->dev.parent = &twl->client->dev;
> +                       device_init_wakeup(&pdev->dev, 1);
> +                       status = platform_device_add_data(pdev, pdata->usb,
> +                                       sizeof(*pdata->usb));
> +                       if (status < 0) {
> +                               platform_device_put(pdev);
> +                               goto err;
> +                       }
> +                       status = platform_device_add(pdev);
> +                       if (status < 0)
> +                               platform_device_put(pdev);
> +               } else {
> +                       status = -ENOMEM;
> +                       goto err;
> +               }
> +       }

I notice that here -- and elsewhere! -- you're not adding an IRQ
resource.  We should get rid of the TWL4030_MODIRQ_* and *_PWRIRQ_*
symbols ... I think you'll observe that the twl_has_gpio() branch
is a slightly better model than the original twl_has_rtc() code,
in terms of how to add each child that uses interrupts.

In this case you can add an IRQ resource 4 more than the base IRQ
(GPIO using 0 more), switch the relevant USB code over so that it's
using platform_get_irq(), and comment out TWL4030_MODIRQ_USB in
the header (now that nobody's using it).

I'll send a small IRQ cleanup patch doing that for the RTC in a
bit, after I sanity check it.

- Dave


--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 5/9] i2c: move twl4030-usb to platform_device
  2008-09-28  1:01           ` [PATCH 5/9] i2c: move twl4030-usb to platform_device David Brownell
@ 2008-09-28  3:03             ` Felipe Balbi
  0 siblings, 0 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-09-28  3:03 UTC (permalink / raw)
  To: David Brownell; +Cc: Felipe Balbi, linux-omap, Tony Lindgren

On Sat, Sep 27, 2008 at 06:01:13PM -0700, David Brownell wrote:
> On Friday 26 Septemb.er 2008, Felipe Balbi wrote:
> > +       if (twl_has_usb() && pdata->usb) {
> > +               pdev = platform_device_alloc("twl4030_usb", -1);
> > +               if (pdev) {
> > +                       twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
> > +                       pdev->dev.parent = &twl->client->dev;
> > +                       device_init_wakeup(&pdev->dev, 1);
> > +                       status = platform_device_add_data(pdev, pdata->usb,
> > +                                       sizeof(*pdata->usb));
> > +                       if (status < 0) {
> > +                               platform_device_put(pdev);
> > +                               goto err;
> > +                       }
> > +                       status = platform_device_add(pdev);
> > +                       if (status < 0)
> > +                               platform_device_put(pdev);
> > +               } else {
> > +                       status = -ENOMEM;
> > +                       goto err;
> > +               }
> > +       }
> 
> I notice that here -- and elsewhere! -- you're not adding an IRQ
> resource.  We should get rid of the TWL4030_MODIRQ_* and *_PWRIRQ_*
> symbols ... I think you'll observe that the twl_has_gpio() branch
> is a slightly better model than the original twl_has_rtc() code,
> in terms of how to add each child that uses interrupts.
> 
> In this case you can add an IRQ resource 4 more than the base IRQ
> (GPIO using 0 more), switch the relevant USB code over so that it's
> using platform_get_irq(), and comment out TWL4030_MODIRQ_USB in
> the header (now that nobody's using it).
> 
> I'll send a small IRQ cleanup patch doing that for the RTC in a
> bit, after I sanity check it.

Sure, I'll update soonish, I'll mail for you only a new series so you
can work on top of that. I changed a few bits, but i'm not keen to flood
linux-omap with unfinished patches again :-p

-- 
balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-27 23:45       ` David Brownell
@ 2008-09-28  3:14         ` Felipe Balbi
  2008-09-28  5:16           ` David Brownell
  0 siblings, 1 reply; 48+ messages in thread
From: Felipe Balbi @ 2008-09-28  3:14 UTC (permalink / raw)
  To: David Brownell; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Sat, Sep 27, 2008 at 04:45:20PM -0700, David Brownell wrote:
> On Saturday 27 September 2008, Felipe Balbi wrote:
> > We need something like the patch below (I can't find a substitute
> > to twl4030_set_gpio_edge_ctrl and twl4030_set_gpio_debounce):
> 
> Something like that, yes.  I have other patches queued up though.
> 
> And meanwhile, your build seems goofed ... fix that first.

Yeah, it only happens when both mmc and twl4030-gpio are built as
modules. Still sounds weird since we have EXPORT_SYMBOL() for those
twl-specific crap.

Basically I'm using 3040sdp defconfig changing twl4030-gpio and mmc to
modules.

> For the moment I'm waiting until HSMMC works again in the OMAP
> tree before I submit patches for any of those issues ... and
> some of them imply updates from upstream.  Like these two:
> 
>   http://marc.info/?l=linux-kernel&m=122239480403730&w=2
>   http://marc.info/?l=linux-kernel&m=122239472903349&w=2
> 
> For the "edge control" thing, I have a patch pushing that into
> the standard IRQF_TRIGGER_{RISING,FALLING} and set_irq_type()
> calls ... there was never a need for a twl-specific call here.
> 
> For debouncing, see this LKML RFC:
> 
>   http://marc.info/?l=linux-kernel&m=122228602206108&w=2

the debouncing mechanism looks really good :-)

> > @@ -48,7 +49,7 @@
> >  
> >  static int hsmmc_card_detect(int irq)
> >  {
> > -       return twl4030_get_gpio_datain(irq - TWL4030_GPIO_IRQ_BASE);
> > +       return gpio_get_value(irq - TWL4030_GPIO_IRQ_BASE);
> 
> That's a non-portable version of irq_to_gpio() ... and one
> which should use gpio_get_value_cansleep().  My patches use
> a simpler scheme, which among other things lets other GPIOs
> be used for card detect.
> 
> (I understand that not all OMAP3 customers want to use twl4030
> for their power management ... and in any case, having this kind
> of needless dependency between drivers is a Bad Thing.)

That's true. Didn't got that at first look. We should use something
like:

return gpio_get_value_cansleep(irq_to_gpio(irq));

right ??

it's good that you've been playing with twl4030-gpio. You've written
gpiolib anyways, so you might better than I do where stuff should go.

-- 
balbi
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-28  3:14         ` Felipe Balbi
@ 2008-09-28  5:16           ` David Brownell
  2008-10-01 13:46             ` Felipe Contreras
  0 siblings, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-09-28  5:16 UTC (permalink / raw)
  To: me; +Cc: Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Saturday 27 September 2008, Felipe Balbi wrote:
> On Sat, Sep 27, 2008 at 04:45:20PM -0700, David Brownell wrote:
> > On Saturday 27 September 2008, Felipe Balbi wrote:
> > > We need something like the patch below (I can't find a substitute
> > > to twl4030_set_gpio_edge_ctrl and twl4030_set_gpio_debounce):
> > 
> > Something like that, yes.  I have other patches queued up though.
> > 
> > And meanwhile, your build seems goofed ... fix that first.
> 
> Yeah, it only happens when both mmc and twl4030-gpio are built as
> modules. Still sounds weird since we have EXPORT_SYMBOL() for those
> twl-specific crap.

Don't yet build twl4030 as a module.  The vmlinux object can't
link against symbols in other objects.  ;)

As I noted, the modular option is for build testing; when this
goes to mainline, this code should be able to build on most any
platform.  (Not just OMAP; not just ARM.)  I don't think any of
the OMAP boards which actually use this code will be able to use
that as a module, though.

When hsmmc.c behaves again, I've got patches to get rid of its
use of those twl-specific symbols.  Then that linkage issue
will go away.


> > For debouncing, see this LKML RFC:
> > 
> >   http://marc.info/?l=linux-kernel&m=122228602206108&w=2
> 
> the debouncing mechanism looks really good :-)

Kind of brainless ... except for the observation that
we pretty much need one of those.  ;)


> That's true. Didn't got that at first look. We should use something
> like:
> 
> return gpio_get_value_cansleep(irq_to_gpio(irq));
> 
> right ??

I want to avoid the irq_to_gpio() bit.   Eventually the whole
MMC/SD initialization needs reworking ... I doubt Overo will be
the only board using one SD for storage, and an SDIO for WLAN.


> it's good that you've been playing with twl4030-gpio. You've written
> gpiolib anyways, so you might better than I do where stuff should go.

Or in some cases:  where it's about time to add mechanisms
to gpiolib.  ;)

- dave


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-09-28  5:16           ` David Brownell
@ 2008-10-01 13:46             ` Felipe Contreras
  2008-10-01 13:52               ` Felipe Balbi
  2008-10-01 15:58               ` David Brownell
  0 siblings, 2 replies; 48+ messages in thread
From: Felipe Contreras @ 2008-10-01 13:46 UTC (permalink / raw)
  To: David Brownell; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Sun, Sep 28, 2008 at 8:16 AM, David Brownell <david-b@pacbell.net> wrote:
> On Saturday 27 September 2008, Felipe Balbi wrote:
>> On Sat, Sep 27, 2008 at 04:45:20PM -0700, David Brownell wrote:
>> > On Saturday 27 September 2008, Felipe Balbi wrote:
>> > > We need something like the patch below (I can't find a substitute
>> > > to twl4030_set_gpio_edge_ctrl and twl4030_set_gpio_debounce):
>> >
>> > Something like that, yes.  I have other patches queued up though.
>> >
>> > And meanwhile, your build seems goofed ... fix that first.
>>
>> Yeah, it only happens when both mmc and twl4030-gpio are built as
>> modules. Still sounds weird since we have EXPORT_SYMBOL() for those
>> twl-specific crap.
>
> Don't yet build twl4030 as a module.  The vmlinux object can't
> link against symbols in other objects.  ;)
>
> As I noted, the modular option is for build testing; when this
> goes to mainline, this code should be able to build on most any
> platform.  (Not just OMAP; not just ARM.)  I don't think any of
> the OMAP boards which actually use this code will be able to use
> that as a module, though.
>
> When hsmmc.c behaves again, I've got patches to get rid of its
> use of those twl-specific symbols.  Then that linkage issue
> will go away.

Hmm, I'm seeing two different configs:
CONFIG_TWL4030_GPIO
CONFIG_GPIO_TWL4030

I guess the defconfigs are wrong.

-- 
Felipe Contreras

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-10-01 13:46             ` Felipe Contreras
@ 2008-10-01 13:52               ` Felipe Balbi
  2008-10-01 15:58               ` David Brownell
  1 sibling, 0 replies; 48+ messages in thread
From: Felipe Balbi @ 2008-10-01 13:52 UTC (permalink / raw)
  To: ext Felipe Contreras
  Cc: David Brownell, me, Felipe Balbi, linux-omap, Tony Lindgren,
	Jean Delvare

On Wed, Oct 01, 2008 at 04:46:14PM +0300, ext Felipe Contreras wrote:
> Hmm, I'm seeing two different configs:
> CONFIG_TWL4030_GPIO

dropped

> CONFIG_GPIO_TWL4030

new one.

-- 
balbi

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-09-27 15:04                         ` David Brownell
  2008-09-27 15:40                           ` Steve Sakoman
@ 2008-10-01 14:20                           ` Mikko Ylinen
  2008-10-01 16:13                             ` David Brownell
  1 sibling, 1 reply; 48+ messages in thread
From: Mikko Ylinen @ 2008-10-01 14:20 UTC (permalink / raw)
  To: ext David Brownell; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren

Hi,

David Brownell wrote:
> A question that may well come up when this heads upstream:
> why is this exporting a miscdev, for an ioctl, when this
> could all be done using sysfs and hwmon rules?  That is,
> was this the "appropriate" way to export ADC channels?

We could still do both, right?

> And a slightly more pragmatic question:  does Nokia have
> tools that would break if this were switched to hwmon style?

We've used ioctl() mechanism to get ADC readings to user space quite
some time already.

I believe this is still a better option compared with hwmon/sysfs
approach (Reason: sometimes we do those readings very often and
for many channels. Instead of doing all that fd magic and atoi(),
we just call ioctl() to get raw ADC data available for further
processing).

>> How detailed information would you like to have here?
> 
> Enough to answer the question "what's a MADC?" for someone
> who doesn't have TWL specs and hasn't read even any kind
> of summary data sheet.  Three sentences would likely be
> excessive; one good sentence might suffice.

Perhaps duplicate the comments we have in Kconfig to .c?

-- 
Regards, Mikko

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-10-01 13:46             ` Felipe Contreras
  2008-10-01 13:52               ` Felipe Balbi
@ 2008-10-01 15:58               ` David Brownell
  2008-10-01 16:05                 ` Jean Delvare
  1 sibling, 1 reply; 48+ messages in thread
From: David Brownell @ 2008-10-01 15:58 UTC (permalink / raw)
  To: Felipe Contreras
  Cc: me, Felipe Balbi, linux-omap, Tony Lindgren, Jean Delvare

On Wednesday 01 October 2008, Felipe Contreras wrote:
> Hmm, I'm seeing two different configs:
> CONFIG_TWL4030_GPIO
> CONFIG_GPIO_TWL4030
> 
> I guess the defconfigs are wrong.

Right, they should get fixed.

The same issue will come when drivers/i2c/chips/twl4030-core.c
moves to drivers/mfd/twl4030-core.c I suspect ... it might be
simpler to hold off on that change for a bit.  (No big deal
either way.)

- Dave


^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-10-01 15:58               ` David Brownell
@ 2008-10-01 16:05                 ` Jean Delvare
  2008-10-01 16:32                   ` David Brownell
  0 siblings, 1 reply; 48+ messages in thread
From: Jean Delvare @ 2008-10-01 16:05 UTC (permalink / raw)
  To: David Brownell
  Cc: Felipe Contreras, me, Felipe Balbi, linux-omap, Tony Lindgren

On Wed, 1 Oct 2008 08:58:12 -0700, David Brownell wrote:
> On Wednesday 01 October 2008, Felipe Contreras wrote:
> > Hmm, I'm seeing two different configs:
> > CONFIG_TWL4030_GPIO
> > CONFIG_GPIO_TWL4030
> > 
> > I guess the defconfigs are wrong.
> 
> Right, they should get fixed.
> 
> The same issue will come when drivers/i2c/chips/twl4030-core.c
> moves to drivers/mfd/twl4030-core.c (...)

Yes, please! I think I'll kill drivers/i2c/chips soon.

-- 
Jean Delvare

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 9/9] i2c: move twl4030-madc to new registration style
  2008-10-01 14:20                           ` Mikko Ylinen
@ 2008-10-01 16:13                             ` David Brownell
  0 siblings, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-10-01 16:13 UTC (permalink / raw)
  To: Mikko Ylinen; +Cc: me, Felipe Balbi, linux-omap, Tony Lindgren

On Wednesday 01 October 2008, Mikko Ylinen wrote:
> Hi,
> 
> David Brownell wrote:
> > A question that may well come up when this heads upstream:
> > why is this exporting a miscdev, for an ioctl, when this
> > could all be done using sysfs and hwmon rules?  That is,
> > was this the "appropriate" way to export ADC channels?
> 
> We could still do both, right?

Are you pointing out another question that may be raised?
Or asking me for an answer?  ;)

I *suspect* supporting both would be frowned on.  However,
the whole issue of how userspace sensor interaction should
work doesn't IMO have good answers yet.  It all depends on
polling -- no alert/alarm/interrupt framework, no streaming
of event data -- so apps newer than the stone age all need
to invent better interface models.


> > And a slightly more pragmatic question:  does Nokia have
> > tools that would break if this were switched to hwmon style?
> 
> We've used ioctl() mechanism to get ADC readings to user space quite
> some time already.
> 
> I believe this is still a better option compared with hwmon/sysfs
> approach (Reason: sometimes we do those readings very often and
> for many channels. Instead of doing all that fd magic and atoi(),
> we just call ioctl() to get raw ADC data available for further
> processing).

Sounds to me like that's a reason to expect the current
interface to stick around for a while ... and a use case
to push towards eventual "hwmon" improvements.

Although:  what's "very often"?  And why wouldn't library
code handle "all that fd magic"?

 
> >> How detailed information would you like to have here?
> > 
> > Enough to answer the question "what's a MADC?" for someone
> > who doesn't have TWL specs and hasn't read even any kind
> > of summary data sheet.  Three sentences would likely be
> > excessive; one good sentence might suffice.
> 
> Perhaps duplicate the comments we have in Kconfig to .c?

(Reads Kconfig comments.)  Yes, that'd be more than enough.
I think a number of those features aren't yet supported in
the driver though.  Maybe you should do that too.  ;)

- Dave

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 11/9] move twl4030-gpio to drivers/gpio
  2008-10-01 16:05                 ` Jean Delvare
@ 2008-10-01 16:32                   ` David Brownell
  0 siblings, 0 replies; 48+ messages in thread
From: David Brownell @ 2008-10-01 16:32 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Felipe Contreras, me, Felipe Balbi, linux-omap, Tony Lindgren

On Wednesday 01 October 2008, Jean Delvare wrote:
> On Wed, 1 Oct 2008 08:58:12 -0700, David Brownell wrote:
> > On Wednesday 01 October 2008, Felipe Contreras wrote:
> > > Hmm, I'm seeing two different configs:
> > > CONFIG_TWL4030_GPIO
> > > CONFIG_GPIO_TWL4030
> > > 
> > > I guess the defconfigs are wrong.
> > 
> > Right, they should get fixed.
> > 
> > The same issue will come when drivers/i2c/chips/twl4030-core.c
> > moves to drivers/mfd/twl4030-core.c (...)
> 
> Yes, please! I think I'll kill drivers/i2c/chips soon.

But in the OMAP tree it's still chock-full of goodness:

~/kernel/beagle/drivers/i2c/chips$ ls
at24.c                Kconfig     pca9539.c      tps65010.c      twl4030-power.c
ds1682.c              lp5521.c    pcf8574.c      tsl2550.c       twl4030-poweroff.c
eeprom.c              Makefile    pcf8575.c      tsl2563.c       twl4030-pwrbutton.c
gpio_expander_omap.c  max6875.c   pcf8591.c      twl4030-core.c  twl4030-pwrirq.c
isp1301_omap.c        menelaus.c  tlv320aic23.c  twl4030-madc.c  twl4030-usb.c
~/kernel/beagle/drivers/i2c/chips$ 

So it's not yet ready to be removed ... at least there.  ;)

Although I certainly agree all that twl4030 [1] stuff should move.
It just takes time.

(Quick audit:   the AIC23 seems nearly ready to move to ALSA.
pcf8574/pcf8575/pca9539 have drivers/gpio versions, and that
gpio_expander_omap is yet another pcf8574 helper.  I'm not
sure the LED framework is ready for lp5521 yet (programmable
RGB led support).

- Dave

[1] same as http://focus.ti.com/docs/prod/folders/print/tps65950.html
    fyi ... programming manuals not yet public, but that data sheet
    may be interesting to you for a quick skim (8 pages).  As I2C
    chips go, it's quite powerful; block diagram on page 2.  ;)



^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2008-10-01 16:32 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-26 11:19 [PATCH 0/9] twl4030 updates Felipe Balbi
2008-09-26 11:19 ` [PATCH 1/9] twl4030: fix potential null pointer dereference Felipe Balbi
2008-09-26 11:19   ` [PATCH 2/9] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
2008-09-26 11:19     ` [PATCH 3/9] i2c: clean add_children a bit Felipe Balbi
2008-09-26 11:19       ` [PATCH 4/9] i2c: move twl4030_keypad to new style registration Felipe Balbi
2008-09-26 11:19         ` [PATCH 5/9] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-26 11:19           ` [PATCH 6/9] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
2008-09-26 11:19             ` [PATCH 7/9] twl4030 gpio platform data Felipe Balbi
2008-09-26 11:19               ` [PATCH 8/9] twl4030 uses gpiolib Felipe Balbi
2008-09-26 11:19                 ` [PATCH 9/9] i2c: move twl4030-madc to new registration style Felipe Balbi
2008-09-26 17:09                   ` David Brownell
2008-09-26 17:46                     ` Felipe Balbi
2008-09-27  7:37                       ` Mikko Ylinen
2008-09-27 15:04                         ` David Brownell
2008-09-27 15:40                           ` Steve Sakoman
2008-09-27 17:17                             ` David Brownell
2008-10-01 14:20                           ` Mikko Ylinen
2008-10-01 16:13                             ` David Brownell
2008-09-26 19:50                   ` David Brownell
2008-09-26 20:01                     ` Steve Sakoman
2008-09-26 17:10                 ` [PATCH 8/9] twl4030 uses gpiolib David Brownell
2008-09-26 17:47                   ` Felipe Balbi
2008-09-26 18:57                     ` David Brownell
2008-09-28  1:01           ` [PATCH 5/9] i2c: move twl4030-usb to platform_device David Brownell
2008-09-28  3:03             ` Felipe Balbi
2008-09-26 17:12 ` [PATCH 0/9] twl4030 updates David Brownell
2008-09-26 17:50   ` Felipe Balbi
2008-09-26 18:55     ` David Brownell
2008-09-26 19:00   ` David Brownell
2008-09-26 19:10     ` Steve Sakoman
2008-09-26 19:23       ` Felipe Balbi
2008-09-26 19:45       ` David Brownell
2008-09-27 19:14 ` David Brownell
2008-09-27 21:17   ` Felipe Balbi
2008-09-27 21:45     ` David Brownell
2008-09-27 21:46       ` Felipe Balbi
2008-09-27 21:41 ` [PATCH 11/9] move twl4030-gpio to drivers/gpio David Brownell
2008-09-27 22:29   ` Felipe Balbi
2008-09-27 23:09     ` Felipe Balbi
2008-09-27 23:45       ` David Brownell
2008-09-28  3:14         ` Felipe Balbi
2008-09-28  5:16           ` David Brownell
2008-10-01 13:46             ` Felipe Contreras
2008-10-01 13:52               ` Felipe Balbi
2008-10-01 15:58               ` David Brownell
2008-10-01 16:05                 ` Jean Delvare
2008-10-01 16:32                   ` David Brownell
2008-09-27 23:29     ` David Brownell

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