linux-omap.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 00/22] twl4030 patches
@ 2008-09-29 13:14 Felipe Balbi
  2008-09-29 13:14 ` [PATCH 01/22] twl4030: fix potential null pointer dereference Felipe Balbi
  2008-09-29 18:39 ` [PATCH 00/22] twl4030 patches David Brownell
  0 siblings, 2 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

I think now things are in pretty good shape and should be applied
to linux-omap mailing list.

With this patchset, we're moving twl4030 forward to a new registration
method and several children were already moved to this new style.

There are plenty of bug fixes as well, mainly to gpio and core modules
and still a lot of stuff to go.

I'd ask people to test the card detect features since I don't have
(damn it) the expansion board for 3430sdp but it looks fine as long
as Dave's tests can say.

This series was boot tested on 3430sdp and beagle B5 (couldn't mount fs
since hsmmc.c is broken on current l-o) and compile tested for all
omap3-based defconfigs plus 2430sdp.

We have a list of TODO so if people wanna help, go for it:

- twl4030-pwrirq.c needs atention. Probably get merged into
  twl4030-core.c

- twl4030_bci_battery.c needs rework as well. Move to new style
  registration is a must now.

- twl4030-power.c needs to get rid of the board specific calls

- twl4030-pwrbutton.c could move to drivers/input/misc

- mmc card detect should be stress tested since we've been
  playing with the edge control stuff. If that's working
  we can probaly switch hsmmc.c to standard gpio calls soon.

- there are too many header files for twl4030, we could merge them
  into one, maybe.

- twl4030-keypad.h should vanish. It's small and all those register
  definitions are used only by the keypad driver. Moving all that
  stuff should be simple.

- sound/soc/codecs/twl4030.c will probably need some attention as
  well.

- twl4030-madc.c could move to sysfs files and hwmon rules (??)

This list will probably grow as we continue doing stuff. Dave
has another queue waiting some other patches to get merged
upstream. After that, I'd say twl4030-core.c could go
upstream as well.

As these patches are quite important, give it a good review
and test so we avoid surprises later.

All-in-all, I'd say we can apply these patches and fix hsmmc.c
in the road. What say you Dave ? I put a few printk to hsmmc.c
and could see that the request_irq for card_detect is the one
which is failing. Maybe that TWL4030_GPIO_IRQ_NO() crap should
be changed. Better, removed.

David Brownell (11):
  twl4030 gpio platform data
  twl4030 uses gpiolib
  minor twl4030-core cleanups
  provide detailed diagnostics in add_children()
  move twl4030-gpio to drivers/gpio
  minor irq-related cleanups
  Move I2C driver model init earlier in the boot sequence
  twl4030-gpio irq_chip.set_type
  twl4030-gpio: remove legacy irq triggering calls and user
  twl4030-gpio: irq and other cleanup
  twl4030-core: portability updates

Felipe Balbi (10):
  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
  i2c: added a few missing gotos to add_children()
  twl4030: move pm_power_off initialization to twl4030-core.c
  i2c: switch twl4030-usb to use a resource for irq
  i2c: minor cleanups to twl4030-pwrbutton.c

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

 arch/arm/mach-omap2/board-2430sdp.c         |   32 +-
 arch/arm/mach-omap2/board-3430sdp.c         |   31 +-
 arch/arm/mach-omap2/board-ldp.c             |   19 +
 arch/arm/mach-omap2/board-omap2evm.c        |   33 +-
 arch/arm/mach-omap2/board-omap3beagle.c     |   19 +
 arch/arm/mach-omap2/board-omap3evm.c        |   85 ++-
 arch/arm/mach-omap2/board-overo.c           |    7 +
 arch/arm/mach-omap2/hsmmc.c                 |    5 -
 arch/arm/plat-omap/include/mach/irqs.h      |    2 +-
 drivers/gpio/Kconfig                        |    7 +
 drivers/gpio/Makefile                       |    1 +
 drivers/gpio/twl4030-gpio.c                 |  951 +++++++++++++++++++++++++++
 drivers/i2c/chips/Kconfig                   |   24 -
 drivers/i2c/chips/Makefile                  |    2 -
 drivers/i2c/chips/twl4030-core.c            |  311 ++++++++--
 drivers/i2c/chips/twl4030-gpio.c            |  788 ----------------------
 drivers/i2c/chips/twl4030-madc.c            |  243 +++++---
 drivers/i2c/chips/twl4030-poweroff.c        |   76 ---
 drivers/i2c/chips/twl4030-pwrbutton.c       |   10 +-
 drivers/i2c/chips/twl4030-usb.c             |  375 ++++++-----
 drivers/i2c/i2c-core.c                      |    2 +-
 drivers/input/keyboard/omap-twl4030keypad.c |   10 +-
 drivers/mmc/host/omap_hsmmc.c               |    4 +-
 drivers/rtc/rtc-twl4030.c                   |   11 +-
 include/linux/i2c/twl4030.h                 |   59 ++-
 25 files changed, 1796 insertions(+), 1311 deletions(-)
 create mode 100644 drivers/gpio/twl4030-gpio.c
 delete mode 100644 drivers/i2c/chips/twl4030-gpio.c
 delete mode 100644 drivers/i2c/chips/twl4030-poweroff.c


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

* [PATCH 01/22] twl4030: fix potential null pointer dereference
  2008-09-29 13:14 [PATCH 00/22] twl4030 patches Felipe Balbi
@ 2008-09-29 13:14 ` Felipe Balbi
  2008-09-29 13:14   ` [PATCH 02/22] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
  2008-09-29 18:39 ` [PATCH 00/22] twl4030 patches David Brownell
  1 sibling, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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] 28+ messages in thread

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

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>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.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] 28+ messages in thread

* [PATCH 03/22] i2c: clean add_children a bit
  2008-09-29 13:14   ` [PATCH 02/22] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
@ 2008-09-29 13:14     ` Felipe Balbi
  2008-09-29 13:14       ` [PATCH 04/22] i2c: move twl4030_keypad to new style registration Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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] 28+ messages in thread

* [PATCH 04/22] i2c: move twl4030_keypad to new style registration
  2008-09-29 13:14     ` [PATCH 03/22] i2c: clean add_children a bit Felipe Balbi
@ 2008-09-29 13:14       ` Felipe Balbi
  2008-09-29 13:14         ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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 |    8 ++--
 include/linux/i2c/twl4030.h                 |   10 ++++
 7 files changed, 86 insertions(+), 72 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..e6b34be 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,
 	},
 };
@@ -409,7 +409,7 @@ static void __exit omap_kp_exit(void)
 
 module_init(omap_kp_init);
 module_exit(omap_kp_exit);
-MODULE_ALIAS("platform:omap_twl4030keypad");
+MODULE_ALIAS("platform:twl4030_keypad");
 MODULE_AUTHOR("Texas Instruments");
 MODULE_DESCRIPTION("OMAP TWL4030 Keypad Driver");
 MODULE_LICENSE("GPL");
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] 28+ messages in thread

* [PATCH 05/22] i2c: move twl4030-usb to platform_device
  2008-09-29 13:14       ` [PATCH 04/22] i2c: move twl4030_keypad to new style registration Felipe Balbi
@ 2008-09-29 13:14         ` Felipe Balbi
  2008-09-29 13:14           ` [PATCH 06/22] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
  2008-09-29 15:02           ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Steve Sakoman
  0 siblings, 2 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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..3073528 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_USB_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] 28+ messages in thread

* [PATCH 06/22] i2c: twl4030-usb: add 'vbus' sysfs file
  2008-09-29 13:14         ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Felipe Balbi
@ 2008-09-29 13:14           ` Felipe Balbi
  2008-09-29 13:14             ` [PATCH 07/22] twl4030 gpio platform data Felipe Balbi
  2008-09-29 15:02           ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Steve Sakoman
  1 sibling, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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] 28+ messages in thread

* [PATCH 07/22] twl4030 gpio platform data
  2008-09-29 13:14           ` [PATCH 06/22] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-29 13:14             ` Felipe Balbi
  2008-09-29 13:14               ` [PATCH 08/22] twl4030 uses gpiolib Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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 3073528..7842110 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_USB_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] 28+ messages in thread

* [PATCH 08/22] twl4030 uses gpiolib
  2008-09-29 13:14             ` [PATCH 07/22] twl4030 gpio platform data Felipe Balbi
@ 2008-09-29 13:14               ` Felipe Balbi
  2008-09-29 13:14                 ` [PATCH 09/22] i2c: move twl4030-madc to new registration style Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
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] 28+ messages in thread

* [PATCH 09/22] i2c: move twl4030-madc to new registration style
  2008-09-29 13:14               ` [PATCH 08/22] twl4030 uses gpiolib Felipe Balbi
@ 2008-09-29 13:14                 ` Felipe Balbi
  2008-09-29 13:14                   ` [PATCH 10/22] minor twl4030-core cleanups Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 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  |    5 +
 arch/arm/mach-omap2/board-3430sdp.c  |    5 +
 arch/arm/mach-omap2/board-ldp.c      |    5 +
 arch/arm/mach-omap2/board-omap2evm.c |    5 +
 arch/arm/mach-omap2/board-omap3evm.c |    5 +
 drivers/i2c/chips/twl4030-core.c     |   27 ++++
 drivers/i2c/chips/twl4030-madc.c     |  243 +++++++++++++++++++++-------------
 include/linux/i2c/twl4030.h          |    5 +
 8 files changed, 209 insertions(+), 91 deletions(-)

diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 7842110..cea2540 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -355,12 +355,17 @@ static struct twl4030_usb_data sdp2430_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data sdp2430_madc_data = {
+	.irq_line	= 1,
+};
+
 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..661d5d0 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -310,12 +310,17 @@ static struct twl4030_usb_data sdp3430_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data sdp3430_madc_data = {
+	.irq_line	= 1,
+};
+
 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..a0e2c7a 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -193,11 +193,16 @@ static struct twl4030_gpio_platform_data ldp_gpio_data = {
 	.irq_end	= TWL4030_GPIO_IRQ_END,
 };
 
+static struct twl4030_madc_platform_data ldp_madc_data = {
+	.irq_line	= 1,
+};
+
 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..9f19c34 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -236,12 +236,17 @@ static struct twl4030_usb_data omap2evm_usb_data = {
 	.usb_mode	= T2_USB_MODE_ULPI,
 };
 
+static struct twl4030_madc_platform_data omap2evm_madc_data = {
+	.irq_line	= 1,
+};
+
 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-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 2c1d76f..a9ff8d1 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -128,12 +128,17 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
 	.irq		= TWL4030_MODIRQ_KEYPAD,
 };
 
+static struct twl4030_madc_platform_data omap3evm_madc_data = {
+	.irq_line	= 1,
+};
+
 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/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..bff2554 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->irq_line == 1) ? TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
+	madc->isr = (pdata->irq_line == 1) ? TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
+
 	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..404300c 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -67,6 +67,10 @@ struct twl4030_gpio_platform_data {
 				unsigned gpio, unsigned ngpio);
 };
 
+struct twl4030_madc_platform_data {
+	int		irq_line;
+};
+
 struct twl4030_keypad_data {
 	int rows;
 	int cols;
@@ -88,6 +92,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] 28+ messages in thread

* [PATCH 10/22] minor twl4030-core cleanups
  2008-09-29 13:14                 ` [PATCH 09/22] i2c: move twl4030-madc to new registration style Felipe Balbi
@ 2008-09-29 13:14                   ` Felipe Balbi
  2008-09-29 13:14                     ` [PATCH 11/22] provide detailed diagnostics in add_children() Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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>

Moved gpio before keypad driver due to alphabetic order.

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

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 79d4d82..22850a8 100644
--- 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 */
@@ -706,27 +706,18 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
-	if (twl_has_rtc()) {
-		pdev = platform_device_alloc("twl4030_rtc", -1);
+	if (twl_has_keypad() && pdata->keypad) {
+		pdev = platform_device_alloc("twl4030_keypad", -1);
 		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
 			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_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);
@@ -736,14 +727,14 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
-	if (twl_has_keypad() && pdata->keypad) {
-		pdev = platform_device_alloc("twl4030_keypad", -1);
+	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->keypad,
-					sizeof(*pdata->keypad));
+			status = platform_device_add_data(pdev, pdata->madc,
+					sizeof(*pdata->madc));
 			if (status < 0) {
 				platform_device_put(pdev);
 				goto err;
@@ -757,18 +748,27 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
-	if (twl_has_usb() && pdata->usb) {
-		pdev = platform_device_alloc("twl4030_usb", -1);
+	if (twl_has_rtc()) {
+		pdev = platform_device_alloc("twl4030_rtc", -1);
 		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
+			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
 			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;
-			}
+
+			/*
+			 * 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);
@@ -778,14 +778,14 @@ static int add_children(struct twl4030_platform_data *pdata)
 		}
 	}
 
-	if (twl_has_madc() && pdata->madc) {
-		pdev = platform_device_alloc("twl4030_madc", -1);
+	if (twl_has_usb() && pdata->usb) {
+		pdev = platform_device_alloc("twl4030_usb", -1);
 		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+			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->madc,
-					sizeof(*pdata->madc));
+			status = platform_device_add_data(pdev, pdata->usb,
+					sizeof(*pdata->usb));
 			if (status < 0) {
 				platform_device_put(pdev);
 				goto err;
@@ -844,17 +844,19 @@ static int __init unprotect_pm_master(void)
 
 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(void)
 	/* 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;
 }
-- 
1.6.0.2.307.gc427


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

* [PATCH 11/22] provide detailed diagnostics in add_children()
  2008-09-29 13:14                   ` [PATCH 10/22] minor twl4030-core cleanups Felipe Balbi
@ 2008-09-29 13:14                     ` Felipe Balbi
  2008-09-29 13:14                       ` [PATCH 12/22] move twl4030-gpio to drivers/gpio Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

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.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Added a few more diagnostics when platform_device_add() fails.

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

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 22850a8..5dcc3b1 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -672,8 +672,10 @@ static int add_children(struct twl4030_platform_data *pdata)
 		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) {
@@ -682,6 +684,12 @@ static int add_children(struct twl4030_platform_data *pdata)
 
 			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);
+				goto err;
+			}
 		}
 
 		/* GPIO module IRQ */
@@ -715,13 +723,21 @@ static int add_children(struct twl4030_platform_data *pdata)
 			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;
 			}
 			status = platform_device_add(pdev);
-			if (status < 0)
+			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+						"can't create keypad dev, %d\n",
+						status);
+			}
 		} else {
+			pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
@@ -737,12 +753,20 @@ static int add_children(struct twl4030_platform_data *pdata)
 					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)
+			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+						"can't create madc dev, %d\n",
+						status);
+			}
 		} else {
+			pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
@@ -770,9 +794,14 @@ static int add_children(struct twl4030_platform_data *pdata)
 			 */
 
 			status = platform_device_add(pdev);
-			if (status < 0)
+			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+						"can't create rtc dev, %d\n",
+						status);
+			}
 		} else {
+			pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
 			status = -ENOMEM;
 			goto err;
 		}
@@ -788,19 +817,28 @@ static int add_children(struct twl4030_platform_data *pdata)
 					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)
+			if (status < 0) {
 				platform_device_put(pdev);
+				dev_dbg(&twl->client->dev,
+						"can't create usb dev, %d\n",
+						status);
+			}
 		} 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 +1122,12 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
 			&& 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:
-- 
1.6.0.2.307.gc427


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

* [PATCH 12/22] move twl4030-gpio to drivers/gpio
  2008-09-29 13:14                     ` [PATCH 11/22] provide detailed diagnostics in add_children() Felipe Balbi
@ 2008-09-29 13:14                       ` Felipe Balbi
  2008-09-29 13:14                         ` [PATCH 13/22] i2c: added a few missing gotos to add_children() Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 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(-)
 create mode 100644 drivers/gpio/twl4030-gpio.c
 delete mode 100644 drivers/i2c/chips/twl4030-gpio.c

diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index 29c92c9..8a4473e 100644
--- 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
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index dbd42d6..293b4a7 100644
--- 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
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 01b4bbd..6aafdeb 100644
--- 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
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
new file mode 100644
index 0000000..2949da1
--- /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");
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 1a21388..e6ac6a2 100644
--- 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
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index ad5f5db..75c531a 100644
--- 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
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 5dcc3b1..4ea6444 100644
--- 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
@@ -1110,10 +1110,6 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		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
@@ -1128,10 +1124,10 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
 				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;
 }
 
diff --git a/drivers/i2c/chips/twl4030-gpio.c b/drivers/i2c/chips/twl4030-gpio.c
deleted file mode 100644
index 0d4dd28..0000000
--- 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");
-- 
1.6.0.2.307.gc427


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

* [PATCH 13/22] i2c: added a few missing gotos to add_children()
  2008-09-29 13:14                       ` [PATCH 12/22] move twl4030-gpio to drivers/gpio Felipe Balbi
@ 2008-09-29 13:14                         ` Felipe Balbi
  2008-09-29 13:14                           ` [PATCH 14/22] minor irq-related cleanups Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

Previously we were failing platform_device_add_data()
and returning from add_children but trying to keep going
when platform_device_add() fails.

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

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 4ea6444..80cf231 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -675,6 +675,7 @@ static int add_children(struct twl4030_platform_data *pdata)
 		if (!pdev) {
 			pr_debug("%s: can't alloc gpio dev\n", DRIVER_NAME);
 			status = -ENOMEM;
+			goto err;
 		}
 
 		/* more driver model init */
@@ -735,6 +736,7 @@ static int add_children(struct twl4030_platform_data *pdata)
 				dev_dbg(&twl->client->dev,
 						"can't create keypad dev, %d\n",
 						status);
+				goto err;
 			}
 		} else {
 			pr_debug("%s: can't alloc keypad dev\n", DRIVER_NAME);
@@ -764,6 +766,7 @@ static int add_children(struct twl4030_platform_data *pdata)
 				dev_dbg(&twl->client->dev,
 						"can't create madc dev, %d\n",
 						status);
+				goto err;
 			}
 		} else {
 			pr_debug("%s: can't alloc madc dev\n", DRIVER_NAME);
@@ -799,6 +802,7 @@ static int add_children(struct twl4030_platform_data *pdata)
 				dev_dbg(&twl->client->dev,
 						"can't create rtc dev, %d\n",
 						status);
+				goto err;
 			}
 		} else {
 			pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
@@ -832,7 +836,6 @@ static int add_children(struct twl4030_platform_data *pdata)
 		} else {
 			pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
 			status = -ENOMEM;
-			goto err;
 		}
 	}
 
-- 
1.6.0.2.307.gc427


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

* [PATCH 14/22] minor irq-related cleanups
  2008-09-29 13:14                         ` [PATCH 13/22] i2c: added a few missing gotos to add_children() Felipe Balbi
@ 2008-09-29 13:14                           ` Felipe Balbi
  2008-09-29 13:14                             ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
  2008-10-01  6:53                             ` [PATCH 14/22] minor irq-related cleanups Pakaravoor, Jagadeesh
  0 siblings, 2 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

Minor IRQ-related cleanups:  comment out the no-longer-used
GPIO irq symbol (more to come, eventually); create RTC IRQ
resource; and use that RTC IRQ resource.

And incidentally, make the RTC code free the correct IRQ;
it was pretty goofed up...

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/gpio/twl4030-gpio.c      |    1 -
 drivers/i2c/chips/twl4030-core.c |   57 +++++++++++++++++++++----------------
 drivers/rtc/rtc-twl4030.c        |   11 +++++--
 include/linux/i2c/twl4030.h      |    2 +-
 4 files changed, 41 insertions(+), 30 deletions(-)

diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
index 2949da1..b65d476 100644
--- a/drivers/gpio/twl4030-gpio.c
+++ b/drivers/gpio/twl4030-gpio.c
@@ -49,7 +49,6 @@
 /* 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;
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 80cf231..e0a6ef4 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -776,37 +776,44 @@ static int add_children(struct twl4030_platform_data *pdata)
 	}
 
 	if (twl_has_rtc()) {
+		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
+
 		pdev = platform_device_alloc("twl4030_rtc", -1);
-		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM3];
+		if (!pdev) {
+			pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
+			status = -ENOMEM;
+		} else {
 			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.
-			 */
+		/*
+		 * REVISIT platform_data here currently might use of
+		 * "msecure" line ... but for now we just expect board
+		 * setup to tell the chip "we are secure" at all times.
+		 * Eventually, Linux might become more aware of such
+		 * HW security concerns, and "least privilege".
+		 */
+
+		/* RTC module IRQ */
+		if (status == 0) {
+			struct resource	r = {
+				/* REVISIT don't hard-wire this stuff */
+				.start = TWL4030_PWRIRQ_RTC,
+				.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 rtc dev, %d\n",
-						status);
-				goto err;
-			}
-		} else {
-			pr_debug("%s: can't alloc rtc dev\n", DRIVER_NAME);
-			status = -ENOMEM;
+
+		if (status < 0) {
+			platform_device_put(pdev);
+			dev_dbg(&twl->client->dev,
+					"can't create rtc dev, %d\n",
+					status);
 			goto err;
 		}
 	}
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
index 98aea07..b19151a 100644
--- a/drivers/rtc/rtc-twl4030.c
+++ b/drivers/rtc/rtc-twl4030.c
@@ -353,8 +353,12 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
 	struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data;
 	struct rtc_device *rtc;
 	int ret = 0;
+	int irq = platform_get_irq(pdev, 0);
 	u8 rd_reg;
 
+	if (irq < 0)
+		return irq;
+
 	if (pdata != NULL && pdata->init != NULL) {
 		ret = pdata->init();
 		if (ret < 0)
@@ -389,7 +393,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto out1;
 
-	ret = request_irq(TWL4030_PWRIRQ_RTC, twl4030_rtc_interrupt,
+	ret = request_irq(irq, twl4030_rtc_interrupt,
 				0, rtc->dev.bus_id, rtc);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "IRQ is not free.\n");
@@ -438,7 +442,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)
 
 
 out2:
-	free_irq(TWL4030_MODIRQ_PWR, rtc);
+	free_irq(irq, rtc);
 out1:
 	rtc_device_unregister(rtc);
 out0:
@@ -457,11 +461,12 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev)
 	/* leave rtc running, but disable irqs */
 	struct twl4030rtc_platform_data *pdata = pdev->dev.platform_data;
 	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	int irq = platform_get_irq(pdev, 0);
 
 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
 	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
 
-	free_irq(TWL4030_MODIRQ_PWR, rtc);
+	free_irq(irq, rtc);
 
 	if (pdata != NULL && pdata->exit != NULL)
 		pdata->exit();
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 404300c..5828485 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -108,7 +108,7 @@ struct twl4030_platform_data {
 #include <mach/irqs.h>
 /* TWL4030 interrupts */
 
-#define TWL4030_MODIRQ_GPIO		(TWL4030_IRQ_BASE + 0)
+/* #define TWL4030_MODIRQ_GPIO		(TWL4030_IRQ_BASE + 0) */
 #define TWL4030_MODIRQ_KEYPAD		(TWL4030_IRQ_BASE + 1)
 #define TWL4030_MODIRQ_BCI		(TWL4030_IRQ_BASE + 2)
 #define TWL4030_MODIRQ_MADC		(TWL4030_IRQ_BASE + 3)
-- 
1.6.0.2.307.gc427


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

* [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c
  2008-09-29 13:14                           ` [PATCH 14/22] minor irq-related cleanups Felipe Balbi
@ 2008-09-29 13:14                             ` Felipe Balbi
  2008-09-29 13:14                               ` [PATCH 16/22] i2c: switch twl4030-usb to use a resource for irq Felipe Balbi
  2008-09-29 15:42                               ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
  2008-10-01  6:53                             ` [PATCH 14/22] minor irq-related cleanups Pakaravoor, Jagadeesh
  1 sibling, 2 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

We don't really need a whole new driver just for initializing
one pointer. Move it to core initialization.

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/Kconfig            |    4 --
 drivers/i2c/chips/Makefile           |    1 -
 drivers/i2c/chips/twl4030-core.c     |   32 ++++++++++++++-
 drivers/i2c/chips/twl4030-poweroff.c |   76 ----------------------------------
 4 files changed, 31 insertions(+), 82 deletions(-)
 delete mode 100644 drivers/i2c/chips/twl4030-poweroff.c

diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index e6ac6a2..819df47 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -186,10 +186,6 @@ config TWL4030_PWRBUTTON
 	tristate "TWL4030 Power button Driver"
 	depends on TWL4030_CORE
 
-config TWL4030_POWEROFF
-	tristate "TWL4030 device poweroff"
-	depends on TWL4030_CORE
-
 config SENSORS_MAX6875
 	tristate "Maxim MAX6875 Power supply supervisor"
 	depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 75c531a..221d929 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -26,7 +26,6 @@ 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_USB)	+= twl4030-usb.o
-obj-$(CONFIG_TWL4030_POWEROFF)	+= twl4030-poweroff.o
 obj-$(CONFIG_TWL4030_PWRBUTTON)	+= twl4030-pwrbutton.o
 obj-$(CONFIG_TWL4030_MADC)	+= twl4030-madc.o
 obj-$(CONFIG_RTC_X1205_I2C)	+= x1205.o
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index e0a6ef4..6f06b8b 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -165,6 +165,10 @@
 
 #define TWL4030_SIH_CTRL_COR_MASK	(1 << 2)
 
+/* for pm_power_off */
+#define PWR_P1_SW_EVENTS	0x10
+#define PWR_DEVOFF	(1<<0)
+
 /**
  * struct twl4030_mod_iregs - TWL module IMR/ISR regs to mask/clear at init
  * @mod_no: TWL4030 module number (e.g., TWL4030_MODULE_GPIO)
@@ -1032,7 +1036,6 @@ static void twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 				 ARRAY_SIZE(twl4030_mod_regs));
 
 	twl4030_irq_base = irq_base;
-
 	/* install an irq handler for each of the PIH modules */
 	for (i = irq_base; i < irq_end; i++) {
 		set_irq_chip(i, &twl4030_irq_chip);
@@ -1050,6 +1053,30 @@ static void twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 		pr_err("%s: %s[%d]\n", DRIVER_NAME, msg, res);
 }
 
+static void twl4030_poweroff(void)
+{
+	int err;
+	u8 val;
+
+	err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+				  PWR_P1_SW_EVENTS);
+	if (err) {
+		pr_err("%s: i2c error %d while reading TWL4030"
+					"PM_MASTER P1_SW_EVENTS\n",
+					DRIVER_NAME, err);
+		return;
+	}
+
+	val |= PWR_DEVOFF;
+
+	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+				   PWR_P1_SW_EVENTS);
+	if (err)
+		pr_err("%s: i2c error %d while writing TWL4030"
+				"PM_MASTER P1_SW_EVENTS\n",
+				DRIVER_NAME, err);
+}
+
 /*----------------------------------------------------------------------*/
 
 static int twl4030_remove(struct i2c_client *client)
@@ -1134,6 +1161,9 @@ twl4030_probe(struct i2c_client *client, const struct i2c_device_id *id)
 				client->irq, pdata->irq_base, pdata->irq_end - 1);
 	}
 
+	/* initialize pm_power_off routine */
+	pm_power_off = twl4030_poweroff;
+
 	status = add_children(pdata);
 fail:
 	if (status < 0)
diff --git a/drivers/i2c/chips/twl4030-poweroff.c b/drivers/i2c/chips/twl4030-poweroff.c
deleted file mode 100644
index 0ebab0b..0000000
--- a/drivers/i2c/chips/twl4030-poweroff.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * linux/drivers/i2c/chips/twl4030_poweroff.c
- *
- * Power off device
- *
- * Copyright (C) 2008 Nokia Corporation
- *
- * Written by Peter De Schrijver <peter.de-schrijver@nokia.com>
- *
- * This file is subject to the terms and conditions of the GNU General
- * Public License. See the file "COPYING" in the main directory of this
- * archive for more details.
- *
- * 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/pm.h>
-#include <linux/i2c/twl4030.h>
-
-#define PWR_P1_SW_EVENTS	0x10
-#define PWR_DEVOFF	(1<<0)
-
-static void twl4030_poweroff(void)
-{
-	u8 val;
-	int err;
-
-	err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
-				  PWR_P1_SW_EVENTS);
-	if (err) {
-		printk(KERN_WARNING "I2C error %d while reading TWL4030"
-					"PM_MASTER P1_SW_EVENTS\n", err);
-		return ;
-	}
-
-	val |= PWR_DEVOFF;
-
-	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
-				   PWR_P1_SW_EVENTS);
-
-	if (err) {
-		printk(KERN_WARNING "I2C error %d while writing TWL4030"
-					"PM_MASTER P1_SW_EVENTS\n", err);
-		return ;
-	}
-
-	return;
-}
-
-static int __init twl4030_poweroff_init(void)
-{
-	pm_power_off = twl4030_poweroff;
-
-	return 0;
-}
-
-static void __exit twl4030_poweroff_exit(void)
-{
-	pm_power_off = NULL;
-}
-
-module_init(twl4030_poweroff_init);
-module_exit(twl4030_poweroff_exit);
-
-MODULE_ALIAS("i2c:twl4030-poweroff");
-MODULE_DESCRIPTION("Triton2 device power off");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Peter De Schrijver");
-- 
1.6.0.2.307.gc427


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

* [PATCH 16/22] i2c: switch twl4030-usb to use a resource for irq
  2008-09-29 13:14                             ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
@ 2008-09-29 13:14                               ` Felipe Balbi
  2008-09-29 13:14                                 ` [PATCH 17/22] Move I2C driver model init earlier in the boot sequence Felipe Balbi
  2008-09-29 15:42                               ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
  1 sibling, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

use platform_get_irq() for getting irq number passed
to twl4030-usb via twl4030-core.c:add_children()

Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/twl4030-core.c |   38 +++++++++++++++++++++++++++-----------
 drivers/i2c/chips/twl4030-usb.c  |    2 +-
 include/linux/i2c/twl4030.h      |    2 +-
 3 files changed, 29 insertions(+), 13 deletions(-)

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 6f06b8b..6941360 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -823,9 +823,16 @@ static int add_children(struct twl4030_platform_data *pdata)
 	}
 
 	if (twl_has_usb() && pdata->usb) {
+		twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
+
 		pdev = platform_device_alloc("twl4030_usb", -1);
-		if (pdev) {
-			twl = &twl4030_modules[TWL4030_SLAVENUM_NUM0];
+		if (!pdev) {
+			pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
+			status = -ENOMEM;
+			goto err;
+		}
+
+		if (status == 0) {
 			pdev->dev.parent = &twl->client->dev;
 			device_init_wakeup(&pdev->dev, 1);
 			status = platform_device_add_data(pdev, pdata->usb,
@@ -837,16 +844,25 @@ static int add_children(struct twl4030_platform_data *pdata)
 					status);
 				goto err;
 			}
+		}
+
+		if (status == 0) {
+			struct resource r = {
+				.start = TWL4030_PWRIRQ_USB_PRES,
+				.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 usb dev, %d\n",
-						status);
-			}
-		} else {
-			pr_debug("%s: can't alloc usb dev\n", DRIVER_NAME);
-			status = -ENOMEM;
+
+		if (status < 0) {
+			platform_device_put(pdev);
+			dev_dbg(&twl->client->dev,
+					"can't create usb dev, %d\n",
+					status);
 		}
 	}
 
diff --git a/drivers/i2c/chips/twl4030-usb.c b/drivers/i2c/chips/twl4030-usb.c
index 3a5aa52..e9cb19b 100644
--- a/drivers/i2c/chips/twl4030-usb.c
+++ b/drivers/i2c/chips/twl4030-usb.c
@@ -679,7 +679,7 @@ static int __init twl4030_usb_probe(struct platform_device *pdev)
 	vbus &= USB_PRES_RISING;
 
 	twl->dev		= &pdev->dev;
-	twl->irq		= TWL4030_PWRIRQ_USB_PRES;
+	twl->irq		= platform_get_irq(pdev, 0);
 	twl->otg.set_host	= twl4030_set_host;
 	twl->otg.set_peripheral	= twl4030_set_peripheral;
 	twl->otg.set_suspend	= twl4030_set_suspend;
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 5828485..1c79c89 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -112,7 +112,7 @@ struct twl4030_platform_data {
 #define TWL4030_MODIRQ_KEYPAD		(TWL4030_IRQ_BASE + 1)
 #define TWL4030_MODIRQ_BCI		(TWL4030_IRQ_BASE + 2)
 #define TWL4030_MODIRQ_MADC		(TWL4030_IRQ_BASE + 3)
-#define TWL4030_MODIRQ_USB		(TWL4030_IRQ_BASE + 4)
+/* #define TWL4030_MODIRQ_USB		(TWL4030_IRQ_BASE + 4) */
 #define TWL4030_MODIRQ_PWR		(TWL4030_IRQ_BASE + 5)
 
 #define TWL4030_PWRIRQ_PWRBTN		(TWL4030_PWR_IRQ_BASE + 0)
-- 
1.6.0.2.307.gc427


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

* [PATCH 17/22] Move I2C driver model init earlier in the boot sequence
  2008-09-29 13:14                               ` [PATCH 16/22] i2c: switch twl4030-usb to use a resource for irq Felipe Balbi
@ 2008-09-29 13:14                                 ` Felipe Balbi
  2008-09-29 13:14                                   ` [PATCH 18/22] i2c: minor cleanups to twl4030-pwrbutton.c Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

This avoids oopsing in statically linked systems when some
subsystems register I2C drivers in subsys_initcall() code,
but those subsystems are linked (and initialized) before I2C.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/i2c-core.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b346a68..f520108 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -978,7 +978,7 @@ static void __exit i2c_exit(void)
 	bus_unregister(&i2c_bus_type);
 }
 
-subsys_initcall(i2c_init);
+postcore_initcall(i2c_init);
 module_exit(i2c_exit);
 
 /* ----------------------------------------------------
-- 
1.6.0.2.307.gc427


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

* [PATCH 18/22] i2c: minor cleanups to twl4030-pwrbutton.c
  2008-09-29 13:14                                 ` [PATCH 17/22] Move I2C driver model init earlier in the boot sequence Felipe Balbi
@ 2008-09-29 13:14                                   ` Felipe Balbi
  2008-09-29 13:14                                     ` [PATCH 19/22] twl4030-gpio irq_chip.set_type Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

Trivial brainless fixes, a few unused headers removed,
changed one printk to pr_err() and removed one comment.

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

diff --git a/drivers/i2c/chips/twl4030-pwrbutton.c b/drivers/i2c/chips/twl4030-pwrbutton.c
index d86d489..9a361b3 100644
--- a/drivers/i2c/chips/twl4030-pwrbutton.c
+++ b/drivers/i2c/chips/twl4030-pwrbutton.c
@@ -26,9 +26,6 @@
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/input.h>
-#include <linux/timer.h>
-#include <linux/jiffies.h>
-#include <linux/kthread.h>
 #include <linux/interrupt.h>
 #include <linux/i2c/twl4030.h>
 
@@ -47,11 +44,6 @@
 
 static struct input_dev *powerbutton_dev;
 
-/*
- * Note : the following function runs in kernel thread context
- * with IRQs enabled
- */
-
 static irqreturn_t powerbutton_irq(int irq, void *dev_id)
 {
 	int err;
@@ -63,7 +55,7 @@ static irqreturn_t powerbutton_irq(int irq, void *dev_id)
 		input_report_key(powerbutton_dev, KEY_POWER,
 				 value & PWR_PWRON_IRQ);
 	} else {
-		printk(KERN_WARNING "I2C error %d while reading TWL4030"
+		pr_err("twl4030: i2c error %d while reading TWL4030"
 			" PM_MASTER STS_HW_CONDITIONS register\n", err);
 	}
 
-- 
1.6.0.2.307.gc427


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

* [PATCH 19/22] twl4030-gpio irq_chip.set_type
  2008-09-29 13:14                                   ` [PATCH 18/22] i2c: minor cleanups to twl4030-pwrbutton.c Felipe Balbi
@ 2008-09-29 13:14                                     ` Felipe Balbi
  2008-09-29 13:14                                       ` [PATCH 20/22] twl4030-gpio: remove legacy irq triggering calls and user Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

Make twl4030 GPIO support set_type() request.
Plus a bit of cleanup for the simple functions.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/gpio/twl4030-gpio.c |   84 +++++++++++++++++++++++++++++++++++++-----
 1 files changed, 74 insertions(+), 10 deletions(-)

diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
index b65d476..e709fbb 100644
--- a/drivers/gpio/twl4030-gpio.c
+++ b/drivers/gpio/twl4030-gpio.c
@@ -153,6 +153,9 @@ static unsigned int gpio_imr_shadow;
 /* bitmask of pending requests to unmask gpio interrupts */
 static unsigned int gpio_pending_unmask;
 
+/* bitmask of requests to set gpio irq trigger type */
+static unsigned int gpio_pending_trigger;
+
 /* pointer to gpio unmask thread struct */
 static struct task_struct *gpio_unmask_thread;
 
@@ -241,10 +244,15 @@ static void twl4030_gpio_unmask(unsigned int irq)
  * 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_irq_mask_and_ack(unsigned int irq)
+{
+}
+
+static void twl4030_gpio_irq_mask(unsigned int irq)
+{
+}
 
-static void twl4030_gpio_unmask_irqchip(unsigned int irq)
+static void twl4030_gpio_irq_unmask(unsigned int irq)
 {
 	int gpio = irq - twl4030_gpio_irq_base;
 
@@ -253,11 +261,36 @@ static void twl4030_gpio_unmask_irqchip(unsigned int irq)
 		wake_up_process(gpio_unmask_thread);
 }
 
+static int twl4030_gpio_irq_set_type(unsigned int irq, unsigned trigger)
+{
+	struct irq_desc *desc = irq_desc + irq;
+	int gpio = irq - twl4030_gpio_irq_base;
+
+	trigger &= IRQ_TYPE_SENSE_MASK;
+	if (trigger & ~IRQ_TYPE_EDGE_BOTH)
+		return -EINVAL;
+	if ((desc->status & IRQ_TYPE_SENSE_MASK) == trigger)
+		return 0;
+
+	desc->status &= ~IRQ_TYPE_SENSE_MASK;
+	desc->status |= trigger;
+
+	/* REVISIT This makes the "unmask" thread do double duty,
+	 * updating IRQ trigger modes too.  Rename appropriately...
+	 */
+	gpio_pending_trigger |= (1 << gpio);
+	if (gpio_unmask_thread && gpio_unmask_thread->state != TASK_RUNNING)
+		wake_up_process(gpio_unmask_thread);
+
+	return 0;
+}
+
 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,
+	.name		= "twl4030",
+	.ack		= twl4030_gpio_irq_mask_and_ack,
+	.mask		= twl4030_gpio_irq_mask,
+	.unmask		= twl4030_gpio_irq_unmask,
+	.set_type	= twl4030_gpio_irq_set_type,
 };
 
 /*
@@ -478,8 +511,6 @@ int twl4030_set_gpio_pull(int gpio, int pull_dircn)
 
 /*
  * 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)
 {
@@ -601,10 +632,14 @@ static int twl4030_gpio_unmask_thread(void *data)
 	while (!kthread_should_stop()) {
 		int irq;
 		unsigned int gpio_unmask;
+		unsigned int gpio_trigger;
 
 		local_irq_disable();
 		gpio_unmask = gpio_pending_unmask;
 		gpio_pending_unmask = 0;
+
+		gpio_trigger = gpio_pending_trigger;
+		gpio_pending_trigger = 0;
 		local_irq_enable();
 
 		for (irq = twl4030_gpio_irq_base; 0 != gpio_unmask;
@@ -613,8 +648,37 @@ static int twl4030_gpio_unmask_thread(void *data)
 				twl4030_gpio_unmask(irq);
 		}
 
+		for (irq = twl4030_gpio_irq_base;
+				gpio_trigger;
+				gpio_trigger >>= 1, irq++) {
+			struct irq_desc *desc;
+			unsigned type, edge;
+
+			if (!(gpio_trigger & 0x1))
+				continue;
+
+			desc = irq_desc + irq;
+			spin_lock_irq(&desc->lock);
+			type = desc->status & IRQ_TYPE_SENSE_MASK;
+			spin_unlock_irq(&desc->lock);
+
+			switch (type) {
+			case IRQ_TYPE_EDGE_RISING:
+				edge = TWL4030_GPIO_EDGE_RISING;
+				break;
+			case IRQ_TYPE_EDGE_FALLING:
+				edge = TWL4030_GPIO_EDGE_FALLING;
+				break;
+			default:
+				edge = TWL4030_GPIO_EDGE_RISING
+					| TWL4030_GPIO_EDGE_FALLING;
+				break;
+			}
+			twl4030_set_gpio_edge_ctrl(irq, edge);
+		}
+
 		local_irq_disable();
-		if (!gpio_pending_unmask)
+		if (!gpio_pending_unmask && !gpio_pending_trigger)
 			set_current_state(TASK_INTERRUPTIBLE);
 		local_irq_enable();
 
-- 
1.6.0.2.307.gc427


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

* [PATCH 20/22] twl4030-gpio: remove legacy irq triggering calls and user
  2008-09-29 13:14                                     ` [PATCH 19/22] twl4030-gpio irq_chip.set_type Felipe Balbi
@ 2008-09-29 13:14                                       ` Felipe Balbi
  2008-09-29 13:14                                         ` [PATCH 21/22] twl4030-gpio: irq and other cleanup Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

Make the hsmmc code use genirq interfaces to make sure the
card detect IRQ triggers on both edges.  Remove the older
TWL-specific infrastructure for making that happen.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 arch/arm/mach-omap2/hsmmc.c   |    5 -----
 drivers/gpio/twl4030-gpio.c   |   38 ++++++++------------------------------
 drivers/mmc/host/omap_hsmmc.c |    4 +++-
 include/linux/i2c/twl4030.h   |    4 ----
 4 files changed, 11 insertions(+), 40 deletions(-)

diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 7334d86..2ba9986 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -65,11 +65,6 @@ static int hsmmc_late_init(struct device *dev)
 	if (ret)
 		goto err;
 
-	ret = twl4030_set_gpio_edge_ctrl(MMC1_CD_IRQ,
-			TWL4030_GPIO_EDGE_RISING | TWL4030_GPIO_EDGE_FALLING);
-	if (ret)
-		goto err;
-
 	ret = twl4030_i2c_write_u8(TWL4030_MODULE_GPIO, 0x02,
 						TWL_GPIO_PUPDCTR1);
 	if (ret)
diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
index e709fbb..404cb34 100644
--- a/drivers/gpio/twl4030-gpio.c
+++ b/drivers/gpio/twl4030-gpio.c
@@ -509,10 +509,7 @@ int twl4030_set_gpio_pull(int gpio, int pull_dircn)
 }
 #endif
 
-/*
- * Configure Edge control for a GPIO pin on TWL4030
- */
-int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
+static 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);
@@ -521,33 +518,26 @@ int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
 	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)
+	if (edge & IRQ_TYPE_EDGE_RISING)
 		c_msk |= MASK_GPIO_EDR1_GPIOxRISING(c_off);
-
-	if (edge & TWL4030_GPIO_EDGE_FALLING)
+	if (edge & IRQ_TYPE_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 = (u8) ret;
+		reg &= ~( 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
@@ -652,7 +642,7 @@ static int twl4030_gpio_unmask_thread(void *data)
 				gpio_trigger;
 				gpio_trigger >>= 1, irq++) {
 			struct irq_desc *desc;
-			unsigned type, edge;
+			unsigned type;
 
 			if (!(gpio_trigger & 0x1))
 				continue;
@@ -662,19 +652,7 @@ static int twl4030_gpio_unmask_thread(void *data)
 			type = desc->status & IRQ_TYPE_SENSE_MASK;
 			spin_unlock_irq(&desc->lock);
 
-			switch (type) {
-			case IRQ_TYPE_EDGE_RISING:
-				edge = TWL4030_GPIO_EDGE_RISING;
-				break;
-			case IRQ_TYPE_EDGE_FALLING:
-				edge = TWL4030_GPIO_EDGE_FALLING;
-				break;
-			default:
-				edge = TWL4030_GPIO_EDGE_RISING
-					| TWL4030_GPIO_EDGE_FALLING;
-				break;
-			}
-			twl4030_set_gpio_edge_ctrl(irq, edge);
+			twl4030_set_gpio_edge_ctrl(irq, type);
 		}
 
 		local_irq_disable();
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 7744669..4f5c0ab 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -918,7 +918,9 @@ static int __init omap_mmc_probe(struct platform_device *pdev)
 	/* Request IRQ for card detect */
 	if ((mmc_slot(host).card_detect_irq) && (mmc_slot(host).card_detect)) {
 		ret = request_irq(mmc_slot(host).card_detect_irq,
-				  omap_mmc_cd_handler, IRQF_DISABLED,
+				  omap_mmc_cd_handler,
+				  IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
+					  | IRQF_DISABLED,
 				  mmc_hostname(mmc), host);
 		if (ret) {
 			dev_dbg(mmc_dev(host->mmc),
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 1c79c89..f26fda1 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -149,9 +149,6 @@ struct twl4030_platform_data {
 #define TWL4030_GPIO_PULL_UP		0
 #define TWL4030_GPIO_PULL_DOWN		1
 #define TWL4030_GPIO_PULL_NONE		2
-#define TWL4030_GPIO_EDGE_NONE		0
-#define TWL4030_GPIO_EDGE_RISING	1
-#define TWL4030_GPIO_EDGE_FALLING	2
 
 /* Functions to read and write from TWL4030 */
 
@@ -177,7 +174,6 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
  */
 int twl4030_get_gpio_datain(int gpio);
 int twl4030_request_gpio(int gpio);
-int twl4030_set_gpio_edge_ctrl(int gpio, int edge);
 int twl4030_set_gpio_debounce(int gpio, int enable);
 int twl4030_free_gpio(int gpio);
 
-- 
1.6.0.2.307.gc427


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

* [PATCH 21/22] twl4030-gpio: irq and other cleanup
  2008-09-29 13:14                                       ` [PATCH 20/22] twl4030-gpio: remove legacy irq triggering calls and user Felipe Balbi
@ 2008-09-29 13:14                                         ` Felipe Balbi
  2008-09-29 13:14                                           ` [PATCH 22/22] twl4030-core: portability updates Felipe Balbi
  0 siblings, 1 reply; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

Remove some ARM and OMAP specific stuff from the twl4030 GPIO code,
and some unused/undesirable CPP symbols.  Add minor checkpatch fixes.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/gpio/twl4030-gpio.c |   27 ++++++++-------------------
 include/linux/i2c/twl4030.h |    6 ------
 2 files changed, 8 insertions(+), 25 deletions(-)

diff --git a/drivers/gpio/twl4030-gpio.c b/drivers/gpio/twl4030-gpio.c
index 404cb34..cb83ff3 100644
--- a/drivers/gpio/twl4030-gpio.c
+++ b/drivers/gpio/twl4030-gpio.c
@@ -40,20 +40,12 @@
 #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 */
-
-static struct gpio_chip twl_gpiochip;
 static int twl4030_gpio_irq_base;
 static int twl4030_gpio_irq_end;
+static struct gpio_chip twl_gpiochip;
 
+/* genirq interfaces are not available to modules */
 #ifdef MODULE
 #define is_module()	true
 #else
@@ -530,7 +522,7 @@ static int twl4030_set_gpio_edge_ctrl(int gpio, int edge)
 	if (ret >= 0) {
 		/* clear the previous rising/falling values */
 		reg = (u8) ret;
-		reg &= ~( MASK_GPIO_EDR1_GPIOxFALLING(c_off)
+		reg &= ~(MASK_GPIO_EDR1_GPIOxFALLING(c_off)
 			| MASK_GPIO_EDR1_GPIOxRISING(c_off));
 		reg |= c_msk;
 		ret = gpio_twl4030_write(base, reg);
@@ -598,7 +590,7 @@ int twl4030_set_gpio_card_detect(int gpio, int enable)
 		ret = gpio_twl4030_write(REG_GPIO_CTRL, reg);
 	}
 	mutex_unlock(&gpio_lock);
-	return (ret);
+	return ret;
 }
 #endif
 
@@ -847,9 +839,9 @@ static int __devinit gpio_twl4030_probe(struct platform_device *pdev)
 		/* 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);
+			set_irq_noprobe(irq);
+			set_irq_chip_and_handler(irq, &twl4030_gpio_irq_chip,
+					do_twl4030_gpio_irq);
 		}
 
 		/* gpio module IRQ */
@@ -918,13 +910,10 @@ static int __devexit gpio_twl4030_remove(struct platform_device *pdev)
 	/* 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++) {
+	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) {
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index f26fda1..56a9415 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -138,17 +138,11 @@ struct twl4030_platform_data {
 
 /* TWL4030 GPIO interrupt definitions */
 
-#define TWL4030_GPIO_MIN		0
 #define TWL4030_GPIO_MAX		18
-#define TWL4030_GPIO_MAX_CD		2
 #define TWL4030_GPIO_IRQ_NO(n)		(TWL4030_GPIO_IRQ_BASE + (n))
-#define TWL4030_GPIO_IS_INPUT		1
-#define TWL4030_GPIO_IS_OUTPUT		0
 #define TWL4030_GPIO_IS_ENABLE		1
-#define TWL4030_GPIO_IS_DISABLE		0
 #define TWL4030_GPIO_PULL_UP		0
 #define TWL4030_GPIO_PULL_DOWN		1
-#define TWL4030_GPIO_PULL_NONE		2
 
 /* Functions to read and write from TWL4030 */
 
-- 
1.6.0.2.307.gc427


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

* [PATCH 22/22] twl4030-core: portability updates
  2008-09-29 13:14                                         ` [PATCH 21/22] twl4030-gpio: irq and other cleanup Felipe Balbi
@ 2008-09-29 13:14                                           ` Felipe Balbi
  0 siblings, 0 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 13:14 UTC (permalink / raw)
  To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi

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

Improve handling of the OMAP-specific setup in twl4030-core,
and remove various warnings on non-OMAP builds.

The main remaining portability problem for this core code (from
a build perspective) is needing symbols like TWL4030_PWR_IRQ_BASE
which are undesirable and platform-specific.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
 drivers/i2c/chips/twl4030-core.c |   21 +++++++++++----------
 1 files changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 6941360..bcd2a3c 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -588,7 +588,7 @@ static unsigned twl4030_irq_base;
  */
 static int twl4030_irq_thread(void *data)
 {
-	int irq = (int)data;
+	long irq = (long)data;
 	irq_desc_t *desc = irq_desc + irq;
 	static unsigned i2c_errors;
 	const static unsigned max_i2c_errors = 100;
@@ -872,15 +872,15 @@ err:
 	return status;
 }
 
-static struct task_struct * __init start_twl4030_irq_thread(int irq)
+static struct task_struct * __init start_twl4030_irq_thread(long irq)
 {
 	struct task_struct *thread;
 
 	init_completion(&irq_event);
 	thread = kthread_run(twl4030_irq_thread, (void *)irq,
-			     "twl4030 irq %d", irq);
+			     "twl4030 irq %ld", irq);
 	if (!thread)
-		pr_err("%s: could not create twl4030 irq %d thread!\n",
+		pr_err("%s: could not create twl4030 irq %ld thread!\n",
 		       DRIVER_NAME, irq);
 
 	return thread;
@@ -913,16 +913,18 @@ static int __init unprotect_pm_master(void)
 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;
 
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 	if (cpu_is_omap2430())
 		osc = clk_get(NULL, "osc_ck");
 	else
 		osc = clk_get(NULL, "osc_sys_ck");
+#else
+	osc = ERR_PTR(-EIO);
+#endif
 	if (IS_ERR(osc)) {
 		printk(KERN_WARNING "Skipping twl4030 internal clock init and "
 				"using bootloader value (unknown osc rate)\n");
@@ -949,7 +951,6 @@ static int __init power_companion_init(void)
 	/* 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;
 }
@@ -1054,9 +1055,9 @@ static void twl_init_irq(int irq_num, unsigned irq_base, unsigned irq_end)
 	twl4030_irq_base = irq_base;
 	/* install an irq handler for each of the PIH modules */
 	for (i = irq_base; i < irq_end; i++) {
-		set_irq_chip(i, &twl4030_irq_chip);
-		set_irq_handler(i, do_twl4030_module_irq);
-		set_irq_flags(i, IRQF_VALID);
+		set_irq_noprobe(i);
+		set_irq_chip_and_handler(i, &twl4030_irq_chip,
+				do_twl4030_module_irq);
 	}
 
 	/* install an irq handler to demultiplex the TWL4030 interrupt */
-- 
1.6.0.2.307.gc427


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

* Re: [PATCH 05/22] i2c: move twl4030-usb to platform_device
  2008-09-29 13:14         ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Felipe Balbi
  2008-09-29 13:14           ` [PATCH 06/22] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-29 15:02           ` Steve Sakoman
  2008-09-29 15:43             ` Felipe Balbi
  1 sibling, 1 reply; 28+ messages in thread
From: Steve Sakoman @ 2008-09-29 15:02 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, David Brownell, Tony Lindgren

On Mon, Sep 29, 2008 at 6:14 AM, Felipe Balbi <felipe.balbi@nokia.com> wrote:
> 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 +-

Still missing Overo in this patch.  I'll make the required changes
locally and test this morning.

Steve


>  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..3073528 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_USB_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
>
> --
> 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] 28+ messages in thread

* Re: [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c
  2008-09-29 13:14                             ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
  2008-09-29 13:14                               ` [PATCH 16/22] i2c: switch twl4030-usb to use a resource for irq Felipe Balbi
@ 2008-09-29 15:42                               ` Felipe Balbi
  1 sibling, 0 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 15:42 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, David Brownell, Tony Lindgren

On Mon, Sep 29, 2008 at 04:14:32PM +0300, Felipe Balbi wrote:
> We don't really need a whole new driver just for initializing
> one pointer. Move it to core initialization.

I'll refactor this patch. We (me and Dave) agreed this code doesn't
belong to twl4030-core.c. For now, let's keep it the way it is and we
touch this when we go for twl4030-power.c and twl4030-pwrirq.c rework.

Resending the series soon.

-- 
balbi

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

* Re: [PATCH 05/22] i2c: move twl4030-usb to platform_device
  2008-09-29 15:02           ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Steve Sakoman
@ 2008-09-29 15:43             ` Felipe Balbi
  0 siblings, 0 replies; 28+ messages in thread
From: Felipe Balbi @ 2008-09-29 15:43 UTC (permalink / raw)
  To: Steve Sakoman; +Cc: Felipe Balbi, linux-omap, David Brownell, Tony Lindgren

On Mon, Sep 29, 2008 at 08:02:21AM -0700, Steve Sakoman wrote:
> On Mon, Sep 29, 2008 at 6:14 AM, Felipe Balbi <felipe.balbi@nokia.com> wrote:
> > 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 +-
> 
> Still missing Overo in this patch.  I'll make the required changes
> locally and test this morning.

Cool, I'll make the changes here and update the patch as well :-)

> 
> Steve
> 
> 
> >  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..3073528 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_USB_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
> >
> > --
> > 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
> >
> --
> 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	[flat|nested] 28+ messages in thread

* Re: [PATCH 00/22] twl4030 patches
  2008-09-29 13:14 [PATCH 00/22] twl4030 patches Felipe Balbi
  2008-09-29 13:14 ` [PATCH 01/22] twl4030: fix potential null pointer dereference Felipe Balbi
@ 2008-09-29 18:39 ` David Brownell
  1 sibling, 0 replies; 28+ messages in thread
From: David Brownell @ 2008-09-29 18:39 UTC (permalink / raw)
  To: Felipe Balbi; +Cc: linux-omap, Tony Lindgren

I seem to have gotten four copies of these patches ... I'll assume
that one of the "v3" sets is the way to go!  :)


On Monday 29 September 2008, Felipe Balbi wrote:
> I think now things are in pretty good shape and should be applied
> to linux-omap mailing list.

I'll verify that on my test setup, including some testing
for the new gpio irq_chip.set_type() methods.  (It's mostly
used for SD card insert/removal IRQs.  Awkward to test that
when your root FS is on an SD card!)


Granted that works OK I'll say it's time to merge the "v3"
patches so a few remaining things can be done in preparation
for submitting *parts* of the twl4030 for mainline.  Starting
with the core; then the other pieces as they become ready.

If anyone has issues to raise with that plan, do so quickly!


> With this patchset, we're moving twl4030 forward to a new registration
> method and several children were already moved to this new style.
> 
> There are plenty of bug fixes as well, mainly to gpio and core modules
> and still a lot of stuff to go.

Well, I'm not sure how much of it is actually "bug fixes" as
opposed to making it ready for upstream ... which involves

 * code cleanup, not limited to small checkpatch.pl stuff
 * some restructuring, to be more drivers/mfd-ish
 * moving things out of the drivers/i2c/chips directory
 * using standard interfaces not TWL-specific ones
 * ...etc...

Although it's true some bugs are getting found and fixed as part
of this.  Like at least two instances of freeing the primary
"power IRQ" instead of the relevant secondary IRQ, which is a
child of that primary one.  Looks like some folk were copying
code that was a bit goofy ... good thing that code rarely runs! :)


> We have a list of TODO so if people wanna help, go for it:

Let us know if you're going to help push part of the twl
code upstream though ... and if you're not going to need to
touch the core, then I suggest you wait for the the dust to
settle after all this "merge the core!" work.

And of course, Felipe's list isn't meant to be exhaustive...

Briefly, after the core moves to mainline, it'll be time to
move remaining TWL bits (a) out of drivers/i2c, and (b) to
mainline.


> This list will probably grow as we continue doing stuff. Dave
> has another queue waiting some other patches to get merged
> upstream. After that, I'd say twl4030-core.c could go
> upstream as well.

My queue is mostly for GPIO stuff, getting rid of twl-private
calls used by the hsmmc init code.  The "core" seems mostly
ready, except as I noted above.

 
> As these patches are quite important, give it a good review
> and test so we avoid surprises later.

>From what I can tell so far, these patches are ready for
merge now.  But review and test is always valuable.


> All-in-all, I'd say we can apply these patches and fix hsmmc.c
> in the road. What say you Dave ?

I'm sure I've said the same thing before.  :)

The hsmmc init logic is *currently* the only real user of
twl4030-gpio private interfaces.  Those interfaces can't
yet be removed ... but I'm working on it.


> I put a few printk to hsmmc.c 
> and could see that the request_irq for card_detect is the one
> which is failing. Maybe that TWL4030_GPIO_IRQ_NO() crap should
> be changed. Better, removed.

That's one of a bunch of global #defines that should vanish, yes.

- Dave

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

* RE: [PATCH 14/22] minor irq-related cleanups
  2008-09-29 13:14                           ` [PATCH 14/22] minor irq-related cleanups Felipe Balbi
  2008-09-29 13:14                             ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
@ 2008-10-01  6:53                             ` Pakaravoor, Jagadeesh
  1 sibling, 0 replies; 28+ messages in thread
From: Pakaravoor, Jagadeesh @ 2008-10-01  6:53 UTC (permalink / raw)
  To: Felipe Balbi, linux-omap@vger.kernel.org; +Cc: David Brownell, Tony Lindgren

> -	ret = request_irq(TWL4030_PWRIRQ_RTC, twl4030_rtc_interrupt,
> +	ret = request_irq(irq, twl4030_rtc_interrupt,
>  				0, rtc->dev.bus_id, rtc);

RTC was requesting "TWL4030_PWRIRQ_RTC".

>  out2:
> -	free_irq(TWL4030_MODIRQ_PWR, rtc);
> +	free_irq(irq, rtc);

And, like BCI, was freeing a different IRQ no - "TWL4030_MODIRQ_PWR". Yet another great fix. ACK for this part too.

--
Jagadeesh

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

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

Thread overview: 28+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-29 13:14 [PATCH 00/22] twl4030 patches Felipe Balbi
2008-09-29 13:14 ` [PATCH 01/22] twl4030: fix potential null pointer dereference Felipe Balbi
2008-09-29 13:14   ` [PATCH 02/22] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
2008-09-29 13:14     ` [PATCH 03/22] i2c: clean add_children a bit Felipe Balbi
2008-09-29 13:14       ` [PATCH 04/22] i2c: move twl4030_keypad to new style registration Felipe Balbi
2008-09-29 13:14         ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-29 13:14           ` [PATCH 06/22] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
2008-09-29 13:14             ` [PATCH 07/22] twl4030 gpio platform data Felipe Balbi
2008-09-29 13:14               ` [PATCH 08/22] twl4030 uses gpiolib Felipe Balbi
2008-09-29 13:14                 ` [PATCH 09/22] i2c: move twl4030-madc to new registration style Felipe Balbi
2008-09-29 13:14                   ` [PATCH 10/22] minor twl4030-core cleanups Felipe Balbi
2008-09-29 13:14                     ` [PATCH 11/22] provide detailed diagnostics in add_children() Felipe Balbi
2008-09-29 13:14                       ` [PATCH 12/22] move twl4030-gpio to drivers/gpio Felipe Balbi
2008-09-29 13:14                         ` [PATCH 13/22] i2c: added a few missing gotos to add_children() Felipe Balbi
2008-09-29 13:14                           ` [PATCH 14/22] minor irq-related cleanups Felipe Balbi
2008-09-29 13:14                             ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
2008-09-29 13:14                               ` [PATCH 16/22] i2c: switch twl4030-usb to use a resource for irq Felipe Balbi
2008-09-29 13:14                                 ` [PATCH 17/22] Move I2C driver model init earlier in the boot sequence Felipe Balbi
2008-09-29 13:14                                   ` [PATCH 18/22] i2c: minor cleanups to twl4030-pwrbutton.c Felipe Balbi
2008-09-29 13:14                                     ` [PATCH 19/22] twl4030-gpio irq_chip.set_type Felipe Balbi
2008-09-29 13:14                                       ` [PATCH 20/22] twl4030-gpio: remove legacy irq triggering calls and user Felipe Balbi
2008-09-29 13:14                                         ` [PATCH 21/22] twl4030-gpio: irq and other cleanup Felipe Balbi
2008-09-29 13:14                                           ` [PATCH 22/22] twl4030-core: portability updates Felipe Balbi
2008-09-29 15:42                               ` [PATCH 15/22] twl4030: move pm_power_off initialization to twl4030-core.c Felipe Balbi
2008-10-01  6:53                             ` [PATCH 14/22] minor irq-related cleanups Pakaravoor, Jagadeesh
2008-09-29 15:02           ` [PATCH 05/22] i2c: move twl4030-usb to platform_device Steve Sakoman
2008-09-29 15:43             ` Felipe Balbi
2008-09-29 18:39 ` [PATCH 00/22] twl4030 patches David Brownell

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).