#include <linux/workqueue.h>
#include <asm/irq.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/gpio.h>
#include <asm/arch/usb.h>
+#include <asm/arch/mux.h>
#ifndef DEBUG
#define DRIVER_VERSION "24 August 2004"
-#define DRIVER_NAME (isp1301_driver.name)
+#define DRIVER_NAME (isp1301_driver.driver.name)
MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
MODULE_LICENSE("GPL");
void (*i2c_release)(struct device *dev);
int irq;
+ int irq_type;
u32 last_otg_ctrl;
unsigned working:1;
/* use keventd context to change the state for us */
struct work_struct work;
-
+
unsigned long todo;
# define WORK_UPDATE_ISP 0 /* update ISP from OTG */
# define WORK_UPDATE_OTG 1 /* update OTG from ISP */
/*-------------------------------------------------------------------------*/
-#ifdef CONFIG_MACH_OMAP_H2
+#if defined(CONFIG_MACH_OMAP_H2) || \
+ defined(CONFIG_MACH_OMAP_H3)
/* board-specific PM hooks */
-#include <asm/arch/gpio.h>
-#include <asm/arch/mux.h>
-#include <asm/mach-types.h>
-
#if defined(CONFIG_TPS65010) || defined(CONFIG_TPS65010_MODULE)
}
-/* products will deliver OTG messages with LEDs, GUI, etc */
-static inline void notresponding(struct isp1301 *isp)
+#else
+
+static void enable_vbus_draw(struct isp1301 *isp, unsigned mA)
{
- printk(KERN_NOTICE "OTG device not responding.\n");
+ pr_debug("%s UNIMPL\n", __FUNCTION__);
}
+static void enable_vbus_source(struct isp1301 *isp)
+{
+ pr_debug("%s UNIMPL\n", __FUNCTION__);
+}
#endif
/*-------------------------------------------------------------------------*/
+/* products will deliver OTG messages with LEDs, GUI, etc */
+static inline void notresponding(struct isp1301 *isp)
+{
+ printk(KERN_NOTICE "OTG device not responding.\n");
+}
+
+/*-------------------------------------------------------------------------*/
+
/* only two addresses possible */
#define ISP_BASE 0x2c
static unsigned short normal_i2c[] = {
{
// isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND_REG);
-
+
/* do this only when cpu is driving transceiver,
* so host won't see a low speed device...
*/
static void update_otg1(struct isp1301 *isp, u8 int_src)
{
u32 otg_ctrl;
+ u8 int_id;
otg_ctrl = OTG_CTRL_REG
& OTG_CTRL_MASK
}
if (int_src & INTR_VBUS_VLD)
otg_ctrl |= OTG_VBUSVLD;
- if (int_src & INTR_ID_GND) { /* default-A */
+
+ int_id = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
+
+ if (int_id & INTR_ID_GND) { /* default-A */
if (isp->otg.state == OTG_STATE_B_IDLE
|| isp->otg.state == OTG_STATE_UNDEFINED) {
a_idle(isp, "init");
/* role is host */
} else {
if (!(otg_ctrl & OTG_ID)) {
- otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
+ otg_ctrl &= OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
OTG_CTRL_REG = otg_ctrl | OTG_A_BUSREQ;
}
/* update the OTG controller state to match the isp1301; may
* trigger OPRT_CHG irqs for changes going to the isp1301.
*/
- update_otg1(isp, isp_stat);
+ update_otg1(isp, stat); // pass the actual interrupt latch status
update_otg2(isp, isp_bstat);
check_state(isp, __FUNCTION__);
#endif
}
static void
-isp1301_work(void *data)
+isp1301_work(struct work_struct *work)
{
- struct isp1301 *isp = data;
+ struct isp1301 *isp = container_of(work, struct isp1301, work);
int stop;
/* implicit lock: we're the only task using this device */
if (machine_is_omap_h2())
omap_free_gpio(2);
+ if (machine_is_omap_h3())
+ omap_free_gpio(14);
+
+ if (machine_is_omap_h4())
+ omap_free_gpio(125);
+
isp->timer.data = 0;
set_bit(WORK_STOP, &isp->todo);
del_timer_sync(&isp->timer);
* - DEVICE mode, for when there's a B/Mini-B (device) connector
*
* As a rule, you won't have an isp1301 chip unless it's there to
- * support the OTG mode. Other modes help testing USB controllers
+ * support the OTG mode. Other modes help testing USB controllers
* in isolation from (full) OTG support, or maybe so later board
* revisions can help to support those feature.
*/
* a few more interrupts than are strictly needed.
*/
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+ INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
+ INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
power_up(isp);
- if (machine_is_omap_h2())
+// XXX h4 too?
+ if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
dev_info(&isp->client.dev, "A-Host sessions ok\n");
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_ID_GND);
+ INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_ID_GND);
+ INTR_ID_GND);
/* If this has a Mini-AB connector, this mode is highly
* nonstandard ... but can be handy for testing, especially with
power_up(isp);
isp->otg.state = OTG_STATE_B_IDLE;
- if (machine_is_omap_h2())
+// XXX h4 too?
+ if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
- INTR_SESS_VLD);
+ INTR_SESS_VLD | INTR_VBUS_VLD);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
- INTR_VBUS_VLD);
+ INTR_VBUS_VLD | INTR_SESS_VLD);
dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __FUNCTION__);
* So do this part as early as possible...
*/
switch (isp->otg.state) {
+ case OTG_STATE_B_PERIPHERAL:
+ isp->otg.state = OTG_STATE_B_WAIT_ACON;
+ isp1301_defer_work(isp, WORK_UPDATE_ISP);
+ break;
case OTG_STATE_B_HOST:
isp->otg.state = OTG_STATE_B_PERIPHERAL;
/* caller will suspend next */
if (!isp)
return 0;
- INIT_WORK(&isp->work, isp1301_work, isp);
+ INIT_WORK(&isp->work, isp1301_work);
init_timer(&isp->timer);
isp->timer.function = isp1301_timer;
isp->timer.data = (unsigned long) isp;
isp->irq = -1;
+ isp->irq_type = 0;
isp->client.addr = address;
i2c_set_clientdata(&isp->client, isp);
isp->client.adapter = bus;
}
#endif
- if (machine_is_omap_h2()) {
+// XXX h4 too?
+ if (machine_is_omap_h2() || machine_is_omap_h3()) {
/* full speed signaling by default */
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1,
MC1_SPEED_REG);
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2,
MC2_SPD_SUSP_CTRL);
+ }
+ if (machine_is_omap_h2()) {
/* IRQ wired at M14 */
omap_cfg_reg(M14_1510_GPIO2);
isp->irq = OMAP_GPIO_IRQ(2);
omap_request_gpio(2);
omap_set_gpio_direction(2, 1);
- omap_set_gpio_edge_ctrl(2, OMAP_GPIO_FALLING_EDGE);
+ isp->irq_type = IRQF_TRIGGER_FALLING;
+ }
+
+ if (machine_is_omap_h3()) {
+ /* IRQ wired at N21 */
+ omap_cfg_reg(N21_1710_GPIO14);
+ isp->irq = OMAP_GPIO_IRQ(14);
+ omap_request_gpio(14);
+ omap_set_gpio_direction(14, 1);
+ isp->irq_type = IRQF_TRIGGER_FALLING;
+ }
+
+ if (machine_is_omap_h4()) {
+ /* IRQ wired at P14 */
+ omap_cfg_reg(P14_24XX_GPIO125);
+ isp->irq = OMAP_GPIO_IRQ(125);
+ omap_request_gpio(125);
+ omap_set_gpio_direction(125, 1);
+ isp->irq_type = IRQF_TRIGGER_LOW;
}
status = request_irq(isp->irq, isp1301_irq,
- IRQF_SAMPLE_RANDOM, DRIVER_NAME, isp);
+ isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
isp->irq, status);