* [PATCH 0/8] twl4030 updates
@ 2008-09-26 9:40 Felipe Balbi
2008-09-26 9:40 ` [PATCH 1/8] twl4030: fix potential null pointer dereference Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 UTC (permalink / raw)
To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi
The following series has a full set of fixes to
twl4030 drivers. This series was made of Jagadeesh's
pullup fix, my usb and keypad fixes and Dave's
gpio patches.
Dave's patches got a few failed HUNKs so Dave,
please check if I patched everything fine.
David Brownell (2):
twl4030 gpio platform data
twl4030 uses gpiolib
Felipe Balbi (5):
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
Jagadeesh Bhaskar Pakaravoor (1):
twl4030-gpio: Remove default pullup enable/disable of GPIO
arch/arm/mach-omap2/board-2430sdp.c | 27 ++-
arch/arm/mach-omap2/board-3430sdp.c | 26 ++-
arch/arm/mach-omap2/board-ldp.c | 14 +
arch/arm/mach-omap2/board-omap2evm.c | 28 ++-
arch/arm/mach-omap2/board-omap3beagle.c | 19 ++
arch/arm/mach-omap2/board-omap3evm.c | 80 +++---
arch/arm/mach-omap2/board-overo.c | 7 +
drivers/i2c/chips/Kconfig | 18 +--
drivers/i2c/chips/twl4030-core.c | 159 ++++++++++--
drivers/i2c/chips/twl4030-gpio.c | 278 ++++++++++++++------
drivers/i2c/chips/twl4030-usb.c | 373 ++++++++++++++-------------
drivers/input/keyboard/omap-twl4030keypad.c | 8 +-
include/linux/i2c/twl4030.h | 40 +++-
13 files changed, 695 insertions(+), 382 deletions(-)
^ permalink raw reply [flat|nested] 14+ messages in thread
* [PATCH 1/8] twl4030: fix potential null pointer dereference
2008-09-26 9:40 [PATCH 0/8] twl4030 updates Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:40 ` [PATCH 2/8] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 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] 14+ messages in thread
* [PATCH 2/8] twl4030-gpio: Remove default pullup enable/disable of GPIO
2008-09-26 9:40 ` [PATCH 1/8] twl4030: fix potential null pointer dereference Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:40 ` [PATCH 3/8] i2c: clean add_children a bit Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 UTC (permalink / raw)
To: linux-omap
Cc: David Brownell, Tony Lindgren, Jagadeesh Bhaskar Pakaravoor,
Girish S G
From: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
One twl4030_request_gpio() should not tamper with the pullup
enabling/disabling of the rest of the GPIOs. So removing the default
pullup values written to REG_GPIOPUPDCTR1.
Signed-off-by: Girish S G <girishsg@ti.com>
Signed-off-by: Jagadeesh Bhaskar Pakaravoor <j-pakaravoor@ti.com>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
---
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] 14+ messages in thread
* [PATCH 3/8] i2c: clean add_children a bit
2008-09-26 9:40 ` [PATCH 2/8] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:40 ` [PATCH 4/8] i2c: move twl4030_keypad to new style registration Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 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>
Acked-by: David Brownell <dbrownell@users.sourceforge.net>
---
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..75356c3 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() (1)
+#else
+#define twl_has_rtc() (0)
+#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] 14+ messages in thread
* [PATCH 4/8] i2c: move twl4030_keypad to new style registration
2008-09-26 9:40 ` [PATCH 3/8] i2c: clean add_children a bit Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 UTC (permalink / raw)
To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi
let twl4030-core.c take care of twl4030_keypad registration.
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
arch/arm/mach-omap2/board-2430sdp.c | 14 ++----
arch/arm/mach-omap2/board-3430sdp.c | 14 ++----
arch/arm/mach-omap2/board-omap2evm.c | 16 ++----
arch/arm/mach-omap2/board-omap3evm.c | 69 ++++++++++++--------------
drivers/i2c/chips/twl4030-core.c | 27 ++++++++++
drivers/input/keyboard/omap-twl4030keypad.c | 6 +-
include/linux/i2c/twl4030.h | 10 ++++
7 files changed, 85 insertions(+), 71 deletions(-)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 3649a94..8c4c9dd 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -173,7 +173,7 @@ static int sdp2430_keymap[] = {
0
};
-static struct omap_kp_platform_data sdp2430_kp_data = {
+static struct twl4030_keypad_data sdp2430_kp_data = {
.rows = 5,
.cols = 6,
.keymap = sdp2430_keymap,
@@ -182,14 +182,6 @@ static struct omap_kp_platform_data sdp2430_kp_data = {
.irq = TWL4030_MODIRQ_KEYPAD,
};
-static struct platform_device sdp2430_kp_device = {
- .name = "omap_twl4030keypad",
- .id = -1,
- .dev = {
- .platform_data = &sdp2430_kp_data,
- },
-};
-
static int __init msecure_init(void)
{
int ret = 0;
@@ -216,7 +208,6 @@ out:
static struct platform_device *sdp2430_devices[] __initdata = {
&sdp2430_smc91x_device,
&sdp2430_flash_device,
- &sdp2430_kp_device,
&sdp2430_lcd_device,
};
@@ -356,6 +347,9 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &sdp2430_kp_data,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 4c60d7b..fe1ba4e 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -110,7 +110,7 @@ static int sdp3430_keymap[] = {
0
};
-static struct omap_kp_platform_data sdp3430_kp_data = {
+static struct twl4030_keypad_data sdp3430_kp_data = {
.rows = 5,
.cols = 6,
.keymap = sdp3430_keymap,
@@ -119,14 +119,6 @@ static struct omap_kp_platform_data sdp3430_kp_data = {
.irq = TWL4030_MODIRQ_KEYPAD,
};
-static struct platform_device sdp3430_kp_device = {
- .name = "omap_twl4030keypad",
- .id = -1,
- .dev = {
- .platform_data = &sdp3430_kp_data,
- },
-};
-
static int ts_gpio;
static int __init msecure_init(void)
@@ -252,7 +244,6 @@ static struct platform_device sdp3430_lcd_device = {
static struct platform_device *sdp3430_devices[] __initdata = {
&sdp3430_smc91x_device,
- &sdp3430_kp_device,
&sdp3430_lcd_device,
};
@@ -312,6 +303,9 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
static struct twl4030_platform_data sdp3430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &sdp3430_kp_data,
};
static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index 6ce7740..d2a3743 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -200,23 +200,15 @@ static int omap2evm_keymap[] = {
KEY(3, 3, KEY_P)
};
-static struct omap_kp_platform_data omap2evm_kp_data = {
+static struct twl4030_keypad_data omap2evm_kp_data = {
.rows = 4,
.cols = 4,
- .keymap = omap2evm_keymap,
+ .keymap = omap2evm_keymap,
.keymapsize = ARRAY_SIZE(omap2evm_keymap),
.rep = 1,
.irq = TWL4030_MODIRQ_KEYPAD,
};
-static struct platform_device omap2evm_kp_device = {
- .name = "omap_twl4030keypad",
- .id = -1,
- .dev = {
- .platform_data = &omap2evm_kp_data,
- },
-};
-
static void __init omap2_evm_init_irq(void)
{
omap2_init_common_hw(NULL);
@@ -237,6 +229,9 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
static struct twl4030_platform_data omap2evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &omap2evm_kp_data,
};
static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
@@ -259,7 +254,6 @@ static int __init omap2_evm_i2c_init(void)
static struct platform_device *omap2_evm_devices[] __initdata = {
&omap2_evm_lcd_device,
&omap2evm_smc911x_device,
- &omap2evm_kp_device,
};
static void __init omap2_evm_init(void)
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 6aa7e28..c4a969d 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,9 +90,41 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static int omap3evm_keymap[] = {
+ KEY(0, 0, KEY_LEFT),
+ KEY(0, 1, KEY_RIGHT),
+ KEY(0, 2, KEY_A),
+ KEY(0, 3, KEY_B),
+ KEY(1, 0, KEY_DOWN),
+ KEY(1, 1, KEY_UP),
+ KEY(1, 2, KEY_E),
+ KEY(1, 3, KEY_F),
+ KEY(2, 0, KEY_ENTER),
+ KEY(2, 1, KEY_I),
+ KEY(2, 2, KEY_J),
+ KEY(2, 3, KEY_K),
+ KEY(3, 0, KEY_M),
+ KEY(3, 1, KEY_N),
+ KEY(3, 2, KEY_O),
+ KEY(3, 3, KEY_P)
+};
+
+static struct twl4030_keypad_data omap3evm_kp_data = {
+ .rows = 4,
+ .cols = 4,
+ .keymap = omap3evm_keymap,
+ .keymapsize = ARRAY_SIZE(omap3evm_keymap),
+ .rep = 1,
+ .irq = TWL4030_MODIRQ_KEYPAD,
+};
+
+
static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .keypad = &omap3evm_kp_data,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
@@ -168,42 +200,6 @@ struct spi_board_info omap3evm_spi_board_info[] = {
},
};
-static int omap3evm_keymap[] = {
- KEY(0, 0, KEY_LEFT),
- KEY(0, 1, KEY_RIGHT),
- KEY(0, 2, KEY_A),
- KEY(0, 3, KEY_B),
- KEY(1, 0, KEY_DOWN),
- KEY(1, 1, KEY_UP),
- KEY(1, 2, KEY_E),
- KEY(1, 3, KEY_F),
- KEY(2, 0, KEY_ENTER),
- KEY(2, 1, KEY_I),
- KEY(2, 2, KEY_J),
- KEY(2, 3, KEY_K),
- KEY(3, 0, KEY_M),
- KEY(3, 1, KEY_N),
- KEY(3, 2, KEY_O),
- KEY(3, 3, KEY_P)
-};
-
-static struct omap_kp_platform_data omap3evm_kp_data = {
- .rows = 4,
- .cols = 4,
- .keymap = omap3evm_keymap,
- .keymapsize = ARRAY_SIZE(omap3evm_keymap),
- .rep = 1,
- .irq = TWL4030_MODIRQ_KEYPAD,
-};
-
-static struct platform_device omap3evm_kp_device = {
- .name = "omap_twl4030keypad",
- .id = -1,
- .dev = {
- .platform_data = &omap3evm_kp_data,
- },
-};
-
static void __init omap3_evm_init_irq(void)
{
omap2_init_common_hw(mt46h32m32lf6_sdrc_params);
@@ -219,7 +215,6 @@ static struct omap_board_config_kernel omap3_evm_config[] __initdata = {
static struct platform_device *omap3_evm_devices[] __initdata = {
&omap3_evm_lcd_device,
- &omap3evm_kp_device,
&omap3evm_smc911x_device,
};
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 75356c3..0041d76 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -51,6 +51,12 @@
#define twl_has_rtc() (0)
#endif
+#if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
+#define twl_has_keypad() (1)
+#else
+#define twl_has_keypad() (0)
+#endif
+
/* Primary Interrupt Handler on TWL4030 Registers */
/* Register Definitions */
@@ -674,6 +680,27 @@ static int add_children(struct twl4030_platform_data *pdata)
}
}
+ if (twl_has_keypad() && pdata->keypad) {
+ pdev = platform_device_alloc("twl4030_keypad", -1);
+ if (pdev) {
+ twl = &twl4030_modules[TWL4030_SLAVENUM_NUM2];
+ pdev->dev.parent = &twl->client->dev;
+ device_init_wakeup(&pdev->dev, 1);
+ status = platform_device_add_data(pdev, pdata->keypad,
+ sizeof(*pdata->keypad));
+ if (status < 0) {
+ platform_device_put(pdev);
+ goto err;
+ }
+ status = platform_device_add(pdev);
+ if (status < 0)
+ platform_device_put(pdev);
+ } else {
+ status = -ENOMEM;
+ goto err;
+ }
+ }
+
err:
pr_err("failed to add twl4030's children\n");
return status;
diff --git a/drivers/input/keyboard/omap-twl4030keypad.c b/drivers/input/keyboard/omap-twl4030keypad.c
index 48f29d3..eefdb78 100644
--- a/drivers/input/keyboard/omap-twl4030keypad.c
+++ b/drivers/input/keyboard/omap-twl4030keypad.c
@@ -38,7 +38,6 @@
#include <linux/i2c.h>
#include <linux/i2c/twl4030.h>
#include <linux/irq.h>
-#include <mach/keypad.h>
#include "twl4030-keypad.h"
#define PTV_PRESCALER 4
@@ -46,6 +45,7 @@
#define MAX_ROWS 8 /* TWL4030 hardlimit */
#define ROWCOL_MASK 0xFF000000
#define KEYNUM_MASK 0x00FFFFFF
+#define KEY(col, row, val) (((col) << 28) | ((row) << 24) | (val))
/* Global variables */
@@ -231,7 +231,7 @@ static int __init omap_kp_probe(struct platform_device *pdev)
int i;
int ret = 0;
struct omap_keypad *kp;
- struct omap_kp_platform_data *pdata = pdev->dev.platform_data;
+ struct twl4030_keypad_data *pdata = pdev->dev.platform_data;
kp = kzalloc(sizeof(*kp), GFP_KERNEL);
if (!kp)
@@ -389,7 +389,7 @@ static struct platform_driver omap_kp_driver = {
.probe = omap_kp_probe,
.remove = __devexit_p(omap_kp_remove),
.driver = {
- .name = "omap_twl4030keypad",
+ .name = "twl4030_keypad",
.owner = THIS_MODULE,
},
};
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 2434ad0..0ac417c 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -52,8 +52,18 @@
#define TWL4030_MODULE_RTC 0x14
#define TWL4030_MODULE_SECURED_REG 0x15
+struct twl4030_keypad_data {
+ int rows;
+ int cols;
+ int *keymap;
+ int irq;
+ unsigned int keymapsize;
+ unsigned int rep:1;
+};
+
struct twl4030_platform_data {
unsigned irq_base, irq_end;
+ struct twl4030_keypad_data *keypad;
/* REVISIT more to come ... _nothing_ should be hard-wired */
};
--
1.6.0.2.307.gc427
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-26 9:40 ` [PATCH 4/8] i2c: move twl4030_keypad to new style registration Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:40 ` [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
` (3 more replies)
0 siblings, 4 replies; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 UTC (permalink / raw)
To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi
use new style twl4030-core to register a platform_device
for twl4030-usb.
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
arch/arm/mach-omap2/board-2430sdp.c | 6 +
arch/arm/mach-omap2/board-3430sdp.c | 5 +
arch/arm/mach-omap2/board-ldp.c | 7 +
arch/arm/mach-omap2/board-omap2evm.c | 5 +
arch/arm/mach-omap2/board-omap3beagle.c | 7 +
arch/arm/mach-omap2/board-omap3evm.c | 6 +-
drivers/i2c/chips/Kconfig | 16 --
drivers/i2c/chips/twl4030-core.c | 27 +++
drivers/i2c/chips/twl4030-usb.c | 328 ++++++++++++++-----------------
include/linux/i2c/twl4030.h | 10 +
10 files changed, 217 insertions(+), 200 deletions(-)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 8c4c9dd..f35c252 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -344,12 +344,18 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
{OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
};
+
+static struct twl4030_usb_data sdp2430_usb_data = {
+ .usb_mode = T2_MODE_ULPI,
+};
+
static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &sdp2430_kp_data,
+ .usb = &sdp2430_usb_data,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index fe1ba4e..e0c39c2 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -300,12 +300,17 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
{ OMAP_TAG_LCD, &sdp3430_lcd_config },
};
+static struct twl4030_usb_data sdp3430_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data sdp3430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &sdp3430_kp_data,
+ .usb = &sdp3430_usb_data,
};
static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index c07c712..219579b 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -183,9 +183,16 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_UART, &ldp_uart_config },
};
+static struct twl4030_usb_data ldp_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &ldp_usb_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index d2a3743..be8348d 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -226,12 +226,17 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
{ OMAP_TAG_LCD, &omap2_evm_lcd_config },
};
+static struct twl4030_usb_data omap2evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data omap2evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &omap2evm_kp_data,
+ .usb = &omap2evm_usb_data,
};
static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index fa8f5f6..ae677b9 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -110,9 +110,16 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_usb_data beagle_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &beagle_usb_data,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index c4a969d..158138c 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,6 +90,10 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_usb_data omap3evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static int omap3evm_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
@@ -118,13 +122,13 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
.irq = TWL4030_MODIRQ_KEYPAD,
};
-
static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &omap3evm_kp_data,
+ .usb = &omap3evm_usb_data,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index e91be60..121aec9 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -186,22 +186,6 @@ config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE
-choice
- prompt "Transceiver mode"
- depends on TWL4030_USB
- help
- TWL4030 USB transceiver can operate in various
- mutually-exclusive modes. Select one of them.
-
-config TWL4030_USB_HS_ULPI
- depends on TWL4030_USB
- bool "High-speed ULPI"
- help
- Say Y here if the TWL4030 is connected to high-speed USB
- controller through a ULPI interface.
-
-endchoice
-
config TWL4030_PWRBUTTON
tristate "TWL4030 Power button Driver"
depends on TWL4030_CORE
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 0041d76..36a6bb7 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -57,6 +57,12 @@
#define twl_has_keypad() (0)
#endif
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb() (1)
+#else
+#define twl_has_usb() (0)
+#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..e790c34 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");
+ dev_set_drvdata(&pdev->dev, 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 = dev_get_drvdata(&pdev->dev);
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] 14+ messages in thread
* [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
@ 2008-09-26 9:40 ` Felipe Balbi
2008-09-26 9:41 ` [PATCH 7/8] twl4030 gpio platform data Felipe Balbi
2008-09-26 10:32 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
` (2 subsequent siblings)
3 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:40 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 e790c34..dbd2e43 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)
dev_set_drvdata(&pdev->dev, 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] 14+ messages in thread
* [PATCH 7/8] twl4030 gpio platform data
2008-09-26 9:40 ` [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-26 9:41 ` Felipe Balbi
2008-09-26 9:41 ` [PATCH 8/8] twl4030 uses gpiolib Felipe Balbi
0 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:41 UTC (permalink / raw)
To: linux-omap; +Cc: David Brownell, Tony Lindgren, Felipe Balbi
From: David Brownell <dbrownell@users.sourceforge.net>
Define platform data for configuring TWL4030 GPIOs,
and provide it for all boards using these chips.
For now all boards use the same fixed assignments for
GPIO and IRQ numbers. Eventually we should be able
to shuffle them without changing platform headers.
Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
arch/arm/mach-omap2/board-2430sdp.c | 7 +++++++
arch/arm/mach-omap2/board-3430sdp.c | 7 +++++++
arch/arm/mach-omap2/board-ldp.c | 7 +++++++
arch/arm/mach-omap2/board-omap2evm.c | 7 +++++++
arch/arm/mach-omap2/board-omap3beagle.c | 12 ++++++++++++
arch/arm/mach-omap2/board-omap3evm.c | 7 +++++++
arch/arm/mach-omap2/board-overo.c | 7 +++++++
include/linux/i2c/twl4030.h | 24 +++++++++++++++++++++---
8 files changed, 75 insertions(+), 3 deletions(-)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index f35c252..0deaf09 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -345,6 +345,12 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
};
+static struct twl4030_gpio_platform_data sdp2430_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_usb_data sdp2430_usb_data = {
.usb_mode = T2_MODE_ULPI,
};
@@ -354,6 +360,7 @@ static struct twl4030_platform_data sdp2430_twldata = {
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
+ .gpio = &sdp2430_gpio_data,
.keypad = &sdp2430_kp_data,
.usb = &sdp2430_usb_data,
};
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index e0c39c2..66f0f98 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -300,6 +300,12 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
{ OMAP_TAG_LCD, &sdp3430_lcd_config },
};
+static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_usb_data sdp3430_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -309,6 +315,7 @@ static struct twl4030_platform_data sdp3430_twldata = {
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
+ .gpio = &sdp3430_gpio_data,
.keypad = &sdp3430_kp_data,
.usb = &sdp3430_usb_data,
};
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index 219579b..48342f4 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -187,12 +187,19 @@ static struct twl4030_usb_data ldp_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
+static struct twl4030_gpio_platform_data ldp_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.usb = &ldp_usb_data,
+ .gpio = &ldp_gpio_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index be8348d..a921cf1 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -226,6 +226,12 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
{ OMAP_TAG_LCD, &omap2_evm_lcd_config },
};
+static struct twl4030_gpio_platform_data omap2evm_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_usb_data omap2evm_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -237,6 +243,7 @@ static struct twl4030_platform_data omap2evm_twldata = {
/* platform_data for children goes here */
.keypad = &omap2evm_kp_data,
.usb = &omap2evm_usb_data,
+ .gpio = &omap2evm_gpio_data,
};
static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index ae677b9..aa5e9a6 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -114,12 +114,24 @@ static struct twl4030_usb_data beagle_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
+static struct twl4030_gpio_platform_data beagle_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+
+ /* REVISIT: setup() should use twl gpio index
+ * - 0 as MMC card detect,
+ * - 1 as EHCI port overcurrent (active low)
+ */
+};
+
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.usb = &beagle_usb_data,
+ .gpio = &beagle_gpio_data,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index 158138c..2c1d76f 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,6 +90,12 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_gpio_platform_data omap3evm_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_usb_data omap3evm_usb_data = {
.usb_mode = T2_USB_MODE_ULPI,
};
@@ -129,6 +135,7 @@ static struct twl4030_platform_data omap3evm_twldata = {
/* platform_data for children goes here */
.keypad = &omap3evm_kp_data,
.usb = &omap3evm_usb_data,
+ .gpio = &omap3evm_gpio_data,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c
index a41e6fa..9c1709a 100644
--- a/arch/arm/mach-omap2/board-overo.c
+++ b/arch/arm/mach-omap2/board-overo.c
@@ -146,9 +146,16 @@ static struct omap_uart_config overo_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_gpio_platform_data overo_gpio_data = {
+ .gpio_base = OMAP_MAX_GPIO_LINES,
+ .irq_base = TWL4030_GPIO_IRQ_BASE,
+ .irq_end = TWL4030_GPIO_IRQ_END,
+};
+
static struct twl4030_platform_data overo_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+ .gpio = &overo_gpio_data,
};
static struct i2c_board_info __initdata overo_i2c_boardinfo[] = {
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 8a12ff0..b80e8b6 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -52,6 +52,21 @@
#define TWL4030_MODULE_RTC 0x14
#define TWL4030_MODULE_SECURED_REG 0x15
+
+/* TWL4030_GPIO_MAX (18) GPIOs, with interrupts */
+struct twl4030_gpio_platform_data {
+ int gpio_base;
+ unsigned irq_base, irq_end;
+
+ /* for gpio-N, bit (1 << N) is set if pullup should be used */
+ u32 pullups;
+
+ int (*setup)(struct device *dev,
+ unsigned gpio, unsigned ngpio);
+ int (*teardown)(struct device *dev,
+ unsigned gpio, unsigned ngpio);
+};
+
struct twl4030_keypad_data {
int rows;
int cols;
@@ -71,9 +86,10 @@ struct twl4030_usb_data {
};
struct twl4030_platform_data {
- unsigned irq_base, irq_end;
- struct twl4030_keypad_data *keypad;
- struct twl4030_usb_data *usb;
+ unsigned irq_base, irq_end;
+ struct twl4030_gpio_platform_data *gpio;
+ struct twl4030_keypad_data *keypad;
+ struct twl4030_usb_data *usb;
/* REVISIT more to come ... _nothing_ should be hard-wired */
};
@@ -151,6 +167,8 @@ int twl4030_i2c_read(u8 mod_no, u8 *value, u8 reg, u8 num_bytes);
/*
* Exported TWL4030 GPIO APIs
+ *
+ * WARNING -- use standard GPIO and IRQ calls instead; these will vanish.
*/
int twl4030_get_gpio_datain(int gpio);
int twl4030_request_gpio(int gpio);
--
1.6.0.2.307.gc427
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [PATCH 8/8] twl4030 uses gpiolib
2008-09-26 9:41 ` [PATCH 7/8] twl4030 gpio platform data Felipe Balbi
@ 2008-09-26 9:41 ` Felipe Balbi
0 siblings, 0 replies; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 9:41 UTC (permalink / raw)
To: linux-omap; +Cc: David Brownell, Tony Lindgren
From: David Brownell <dbrownell@users.sourceforge.net>
Make the twl4030 core create a platform device to which its
GPIO code will bind, with platform_data used to configure
board-specific behaviors and configuration.
Update the twl4030 GPIO code:
- Morph its gpio function code into a platform driver.
- Move away from IRQ (and GPIO) numbers hard-wired in headers.
- Hook up the twl4030 GPIO code to gpiolib.
- Start phasing out the older TWL-specific calls ... currently
those are used only by arch/arm/mach-omap2/hsmmc.c setup code.
- Use a mutex for locking, not a binary semaphore.
NOTE: more patches pending: (a) this doesn't use pdata->pullups
to initialize (currently hsmmc code always sets GPIO-0 pullup even
if the board has an external pullup); (b) there's a new gpio
request/free hook forthcoming in 2.6.28, which this should use;
(c) likewise there's a new gpio_to_irq() hook; (d) the irq_chip
set_type() mechanism needs to be supported; (e) needs to move over
to drivers/gpio; (f) upcoming threaded IRQ infrastructure should
be used, when that merges.
NYET-Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
NYET-Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
drivers/i2c/chips/Kconfig | 2 +-
drivers/i2c/chips/twl4030-core.c | 44 ++++++
drivers/i2c/chips/twl4030-gpio.c | 273 +++++++++++++++++++++++++++-----------
3 files changed, 238 insertions(+), 81 deletions(-)
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 121aec9..1a21388 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -159,7 +159,7 @@ config TWL4030_CORE
config TWL4030_GPIO
bool "TWL4030 GPIO Driver"
- depends on TWL4030_CORE
+ depends on TWL4030_CORE && GPIOLIB
config TWL4030_MADC
tristate "TWL4030 MADC Driver"
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 36a6bb7..f8162de 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -63,6 +63,12 @@
#define twl_has_usb() (0)
#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] 14+ messages in thread
* Re: [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-26 9:40 ` [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
@ 2008-09-26 10:32 ` Felipe Balbi
2008-09-26 10:33 ` Felipe Balbi
2008-09-27 3:13 ` Steve Sakoman
3 siblings, 0 replies; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 10:32 UTC (permalink / raw)
To: Felipe Balbi; +Cc: linux-omap, David Brownell, Tony Lindgren
On Fri, Sep 26, 2008 at 12:40:58PM +0300, Felipe Balbi 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 +-
> drivers/i2c/chips/Kconfig | 16 --
> drivers/i2c/chips/twl4030-core.c | 27 +++
> drivers/i2c/chips/twl4030-usb.c | 328 ++++++++++++++-----------------
> include/linux/i2c/twl4030.h | 10 +
> 10 files changed, 217 insertions(+), 200 deletions(-)
>
> diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
> index 8c4c9dd..f35c252 100644
> --- a/arch/arm/mach-omap2/board-2430sdp.c
> +++ b/arch/arm/mach-omap2/board-2430sdp.c
> @@ -344,12 +344,18 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
> {OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
> };
>
> +
> +static struct twl4030_usb_data sdp2430_usb_data = {
> + .usb_mode = T2_MODE_ULPI,
> +};
> +
> static struct twl4030_platform_data sdp2430_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
>
> /* platform_data for children goes here */
> .keypad = &sdp2430_kp_data,
> + .usb = &sdp2430_usb_data,
> };
>
> static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
> diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
> index fe1ba4e..e0c39c2 100644
> --- a/arch/arm/mach-omap2/board-3430sdp.c
> +++ b/arch/arm/mach-omap2/board-3430sdp.c
> @@ -300,12 +300,17 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
> { OMAP_TAG_LCD, &sdp3430_lcd_config },
> };
>
> +static struct twl4030_usb_data sdp3430_usb_data = {
> + .usb_mode = T2_USB_MODE_ULPI,
> +};
> +
> static struct twl4030_platform_data sdp3430_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
>
> /* platform_data for children goes here */
> .keypad = &sdp3430_kp_data,
> + .usb = &sdp3430_usb_data,
> };
>
> static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
> diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
> index c07c712..219579b 100644
> --- a/arch/arm/mach-omap2/board-ldp.c
> +++ b/arch/arm/mach-omap2/board-ldp.c
> @@ -183,9 +183,16 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
> { OMAP_TAG_UART, &ldp_uart_config },
> };
>
> +static struct twl4030_usb_data ldp_usb_data = {
> + .usb_mode = T2_USB_MODE_ULPI,
> +};
> +
> static struct twl4030_platform_data ldp_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
> +
> + /* platform_data for children goes here */
> + .usb = &ldp_usb_data,
> };
>
> static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
> diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
> index d2a3743..be8348d 100644
> --- a/arch/arm/mach-omap2/board-omap2evm.c
> +++ b/arch/arm/mach-omap2/board-omap2evm.c
> @@ -226,12 +226,17 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
> { OMAP_TAG_LCD, &omap2_evm_lcd_config },
> };
>
> +static struct twl4030_usb_data omap2evm_usb_data = {
> + .usb_mode = T2_USB_MODE_ULPI,
> +};
> +
> static struct twl4030_platform_data omap2evm_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
>
> /* platform_data for children goes here */
> .keypad = &omap2evm_kp_data,
> + .usb = &omap2evm_usb_data,
> };
>
> static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
> diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
> index fa8f5f6..ae677b9 100644
> --- a/arch/arm/mach-omap2/board-omap3beagle.c
> +++ b/arch/arm/mach-omap2/board-omap3beagle.c
> @@ -110,9 +110,16 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
> .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
> };
>
> +static struct twl4030_usb_data beagle_usb_data = {
> + .usb_mode = T2_USB_MODE_ULPI,
> +};
> +
> static struct twl4030_platform_data beagle_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
> +
> + /* platform_data for children goes here */
> + .usb = &beagle_usb_data,
> };
>
> static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
> diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
> index c4a969d..158138c 100644
> --- a/arch/arm/mach-omap2/board-omap3evm.c
> +++ b/arch/arm/mach-omap2/board-omap3evm.c
> @@ -90,6 +90,10 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
> .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
> };
>
> +static struct twl4030_usb_data omap3evm_usb_data = {
> + .usb_mode = T2_USB_MODE_ULPI,
> +};
> +
> static int omap3evm_keymap[] = {
> KEY(0, 0, KEY_LEFT),
> KEY(0, 1, KEY_RIGHT),
> @@ -118,13 +122,13 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
> .irq = TWL4030_MODIRQ_KEYPAD,
> };
>
> -
> static struct twl4030_platform_data omap3evm_twldata = {
> .irq_base = TWL4030_IRQ_BASE,
> .irq_end = TWL4030_IRQ_END,
>
> /* platform_data for children goes here */
> .keypad = &omap3evm_kp_data,
> + .usb = &omap3evm_usb_data,
> };
>
> static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
> diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
> index e91be60..121aec9 100644
> --- a/drivers/i2c/chips/Kconfig
> +++ b/drivers/i2c/chips/Kconfig
> @@ -186,22 +186,6 @@ config TWL4030_USB
> tristate "TWL4030 USB Transceiver Driver"
> depends on TWL4030_CORE
>
> -choice
> - prompt "Transceiver mode"
> - depends on TWL4030_USB
> - help
> - TWL4030 USB transceiver can operate in various
> - mutually-exclusive modes. Select one of them.
> -
> -config TWL4030_USB_HS_ULPI
> - depends on TWL4030_USB
> - bool "High-speed ULPI"
> - help
> - Say Y here if the TWL4030 is connected to high-speed USB
> - controller through a ULPI interface.
> -
> -endchoice
> -
> config TWL4030_PWRBUTTON
> tristate "TWL4030 Power button Driver"
> depends on TWL4030_CORE
> diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
> index 0041d76..36a6bb7 100644
> --- a/drivers/i2c/chips/twl4030-core.c
> +++ b/drivers/i2c/chips/twl4030-core.c
> @@ -57,6 +57,12 @@
> #define twl_has_keypad() (0)
> #endif
>
> +#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
> +#define twl_has_usb() (1)
> +#else
> +#define twl_has_usb() (0)
> +#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..e790c34 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");
> + dev_set_drvdata(&pdev->dev, twl);
this can be platform_set_drvdata(pdev, twl);
I will resend this one.
> + 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 = dev_get_drvdata(&pdev->dev);
> 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
--
balbi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-26 9:40 ` [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
2008-09-26 10:32 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
@ 2008-09-26 10:33 ` Felipe Balbi
2008-09-26 10:37 ` Felipe Balbi
2008-09-27 3:13 ` Steve Sakoman
3 siblings, 1 reply; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 10:33 UTC (permalink / raw)
To: Felipe Balbi; +Cc: linux-omap, David Brownell, Tony Lindgren
From: Felipe Balbi <felipe.balbi@nokia.com>
use new style twl4030-core to register a platform_device
for twl4030-usb.
Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com>
---
arch/arm/mach-omap2/board-2430sdp.c | 6 +
arch/arm/mach-omap2/board-3430sdp.c | 5 +
arch/arm/mach-omap2/board-ldp.c | 7 +
arch/arm/mach-omap2/board-omap2evm.c | 5 +
arch/arm/mach-omap2/board-omap3beagle.c | 7 +
arch/arm/mach-omap2/board-omap3evm.c | 6 +-
drivers/i2c/chips/Kconfig | 16 --
drivers/i2c/chips/twl4030-core.c | 27 +++
drivers/i2c/chips/twl4030-usb.c | 328 ++++++++++++++-----------------
include/linux/i2c/twl4030.h | 10 +
10 files changed, 217 insertions(+), 200 deletions(-)
diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c
index 8c4c9dd..f35c252 100644
--- a/arch/arm/mach-omap2/board-2430sdp.c
+++ b/arch/arm/mach-omap2/board-2430sdp.c
@@ -344,12 +344,18 @@ static struct omap_board_config_kernel sdp2430_config[] __initdata = {
{OMAP_TAG_SERIAL_CONSOLE, &sdp2430_serial_console_config},
};
+
+static struct twl4030_usb_data sdp2430_usb_data = {
+ .usb_mode = T2_MODE_ULPI,
+};
+
static struct twl4030_platform_data sdp2430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &sdp2430_kp_data,
+ .usb = &sdp2430_usb_data,
};
static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index fe1ba4e..e0c39c2 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -300,12 +300,17 @@ static struct omap_board_config_kernel sdp3430_config[] __initdata = {
{ OMAP_TAG_LCD, &sdp3430_lcd_config },
};
+static struct twl4030_usb_data sdp3430_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data sdp3430_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &sdp3430_kp_data,
+ .usb = &sdp3430_usb_data,
};
static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c
index c07c712..219579b 100644
--- a/arch/arm/mach-omap2/board-ldp.c
+++ b/arch/arm/mach-omap2/board-ldp.c
@@ -183,9 +183,16 @@ static struct omap_board_config_kernel ldp_config[] __initdata = {
{ OMAP_TAG_UART, &ldp_uart_config },
};
+static struct twl4030_usb_data ldp_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data ldp_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &ldp_usb_data,
};
static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap2evm.c b/arch/arm/mach-omap2/board-omap2evm.c
index d2a3743..be8348d 100644
--- a/arch/arm/mach-omap2/board-omap2evm.c
+++ b/arch/arm/mach-omap2/board-omap2evm.c
@@ -226,12 +226,17 @@ static struct omap_board_config_kernel omap2_evm_config[] __initdata = {
{ OMAP_TAG_LCD, &omap2_evm_lcd_config },
};
+static struct twl4030_usb_data omap2evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data omap2evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &omap2evm_kp_data,
+ .usb = &omap2evm_usb_data,
};
static struct i2c_board_info __initdata omap2evm_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c
index fa8f5f6..ae677b9 100644
--- a/arch/arm/mach-omap2/board-omap3beagle.c
+++ b/arch/arm/mach-omap2/board-omap3beagle.c
@@ -110,9 +110,16 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_usb_data beagle_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static struct twl4030_platform_data beagle_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
+
+ /* platform_data for children goes here */
+ .usb = &beagle_usb_data,
};
static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = {
diff --git a/arch/arm/mach-omap2/board-omap3evm.c b/arch/arm/mach-omap2/board-omap3evm.c
index c4a969d..158138c 100644
--- a/arch/arm/mach-omap2/board-omap3evm.c
+++ b/arch/arm/mach-omap2/board-omap3evm.c
@@ -90,6 +90,10 @@ static struct omap_uart_config omap3_evm_uart_config __initdata = {
.enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)),
};
+static struct twl4030_usb_data omap3evm_usb_data = {
+ .usb_mode = T2_USB_MODE_ULPI,
+};
+
static int omap3evm_keymap[] = {
KEY(0, 0, KEY_LEFT),
KEY(0, 1, KEY_RIGHT),
@@ -118,13 +122,13 @@ static struct twl4030_keypad_data omap3evm_kp_data = {
.irq = TWL4030_MODIRQ_KEYPAD,
};
-
static struct twl4030_platform_data omap3evm_twldata = {
.irq_base = TWL4030_IRQ_BASE,
.irq_end = TWL4030_IRQ_END,
/* platform_data for children goes here */
.keypad = &omap3evm_kp_data,
+ .usb = &omap3evm_usb_data,
};
static struct i2c_board_info __initdata omap3evm_i2c_boardinfo[] = {
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index e91be60..121aec9 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -186,22 +186,6 @@ config TWL4030_USB
tristate "TWL4030 USB Transceiver Driver"
depends on TWL4030_CORE
-choice
- prompt "Transceiver mode"
- depends on TWL4030_USB
- help
- TWL4030 USB transceiver can operate in various
- mutually-exclusive modes. Select one of them.
-
-config TWL4030_USB_HS_ULPI
- depends on TWL4030_USB
- bool "High-speed ULPI"
- help
- Say Y here if the TWL4030 is connected to high-speed USB
- controller through a ULPI interface.
-
-endchoice
-
config TWL4030_PWRBUTTON
tristate "TWL4030 Power button Driver"
depends on TWL4030_CORE
diff --git a/drivers/i2c/chips/twl4030-core.c b/drivers/i2c/chips/twl4030-core.c
index 0041d76..36a6bb7 100644
--- a/drivers/i2c/chips/twl4030-core.c
+++ b/drivers/i2c/chips/twl4030-core.c
@@ -57,6 +57,12 @@
#define twl_has_keypad() (0)
#endif
+#if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE)
+#define twl_has_usb() (1)
+#else
+#define twl_has_usb() (0)
+#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..e790c34 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 = dev_get_drvdata(&pdev->dev);
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
--
balbi
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-26 10:33 ` Felipe Balbi
@ 2008-09-26 10:37 ` Felipe Balbi
0 siblings, 0 replies; 14+ messages in thread
From: Felipe Balbi @ 2008-09-26 10:37 UTC (permalink / raw)
To: Felipe Balbi; +Cc: linux-omap, David Brownell, Tony Lindgren
On Fri, Sep 26, 2008 at 01:33:47PM +0300, Felipe Balbi wrote:
> -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 = dev_get_drvdata(&pdev->dev);
Damn, forgot this one. I'll resend the whole series soon. I'm converting
twl4030-madc to platform_device. Ignore this series.
--
balbi
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
` (2 preceding siblings ...)
2008-09-26 10:33 ` Felipe Balbi
@ 2008-09-27 3:13 ` Steve Sakoman
2008-09-27 8:01 ` Felipe Balbi
3 siblings, 1 reply; 14+ messages in thread
From: Steve Sakoman @ 2008-09-27 3:13 UTC (permalink / raw)
To: Felipe Balbi, linux-omap@vger.kernel.org List
On Fri, Sep 26, 2008 at 2:40 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 +-
board-overo.c should have the same changes made.
Should I submit a separate patch or can you incorporate in the the
next revision?
Steve
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [PATCH 5/8] i2c: move twl4030-usb to platform_device
2008-09-27 3:13 ` Steve Sakoman
@ 2008-09-27 8:01 ` Felipe Balbi
0 siblings, 0 replies; 14+ messages in thread
From: Felipe Balbi @ 2008-09-27 8:01 UTC (permalink / raw)
To: Steve Sakoman; +Cc: Felipe Balbi, linux-omap@vger.kernel.org List
On Fri, Sep 26, 2008 at 08:13:27PM -0700, Steve Sakoman wrote:
> On Fri, Sep 26, 2008 at 2:40 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 +-
>
> board-overo.c should have the same changes made.
>
> Should I submit a separate patch or can you incorporate in the the
> next revision?
I can incorporate, no big deal. Only woring on them on monday though.
>
> Steve
> --
> 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] 14+ messages in thread
end of thread, other threads:[~2008-09-27 8:01 UTC | newest]
Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-26 9:40 [PATCH 0/8] twl4030 updates Felipe Balbi
2008-09-26 9:40 ` [PATCH 1/8] twl4030: fix potential null pointer dereference Felipe Balbi
2008-09-26 9:40 ` [PATCH 2/8] twl4030-gpio: Remove default pullup enable/disable of GPIO Felipe Balbi
2008-09-26 9:40 ` [PATCH 3/8] i2c: clean add_children a bit Felipe Balbi
2008-09-26 9:40 ` [PATCH 4/8] i2c: move twl4030_keypad to new style registration Felipe Balbi
2008-09-26 9:40 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-26 9:40 ` [PATCH 6/8] i2c: twl4030-usb: add 'vbus' sysfs file Felipe Balbi
2008-09-26 9:41 ` [PATCH 7/8] twl4030 gpio platform data Felipe Balbi
2008-09-26 9:41 ` [PATCH 8/8] twl4030 uses gpiolib Felipe Balbi
2008-09-26 10:32 ` [PATCH 5/8] i2c: move twl4030-usb to platform_device Felipe Balbi
2008-09-26 10:33 ` Felipe Balbi
2008-09-26 10:37 ` Felipe Balbi
2008-09-27 3:13 ` Steve Sakoman
2008-09-27 8:01 ` Felipe Balbi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox