From ca8a282a5373f96d0ea002d97a168211448e8526 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 21:58:19 -0700 Subject: usb: gadget: renesas_usbhs: add suspend/resume support Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 69 +++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 5 deletions(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index d8239e5efa66..319ed47153d7 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -203,13 +203,10 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) } /* - * notify hotplug + * hotplug */ -static void usbhsc_notify_hotplug(struct work_struct *work) +static void usbhsc_hotplug(struct usbhs_priv *priv) { - struct usbhs_priv *priv = container_of(work, - struct usbhs_priv, - notify_hotplug_work.work); struct platform_device *pdev = usbhs_priv_to_pdev(priv); struct usbhs_mod *mod = usbhs_mod_get_current(priv); int id; @@ -257,6 +254,17 @@ static void usbhsc_notify_hotplug(struct work_struct *work) } } +/* + * notify hotplug + */ +static void usbhsc_notify_hotplug(struct work_struct *work) +{ + struct usbhs_priv *priv = container_of(work, + struct usbhs_priv, + notify_hotplug_work.work); + usbhsc_hotplug(priv); +} + int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); @@ -443,9 +451,60 @@ static int __devexit usbhs_remove(struct platform_device *pdev) return 0; } +static int usbhsc_suspend(struct device *dev) +{ + struct usbhs_priv *priv = dev_get_drvdata(dev); + struct usbhs_mod *mod = usbhs_mod_get_current(priv); + + if (mod) { + usbhs_mod_call(priv, stop, priv); + usbhs_mod_change(priv, -1); + } + + if (mod || !usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) + usbhsc_power_ctrl(priv, 0); + + return 0; +} + +static int usbhsc_resume(struct device *dev) +{ + struct usbhs_priv *priv = dev_get_drvdata(dev); + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + usbhs_platform_call(priv, phy_reset, pdev); + + if (!usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) + usbhsc_power_ctrl(priv, 1); + + usbhsc_hotplug(priv); + + return 0; +} + +static int usbhsc_runtime_nop(struct device *dev) +{ + /* Runtime PM callback shared between ->runtime_suspend() + * and ->runtime_resume(). Simply returns success. + * + * This driver re-initializes all registers after + * pm_runtime_get_sync() anyway so there is no need + * to save and restore registers here. + */ + return 0; +} + +static const struct dev_pm_ops usbhsc_pm_ops = { + .suspend = usbhsc_suspend, + .resume = usbhsc_resume, + .runtime_suspend = usbhsc_runtime_nop, + .runtime_resume = usbhsc_runtime_nop, +}; + static struct platform_driver renesas_usbhs_driver = { .driver = { .name = "renesas_usbhs", + .pm = &usbhsc_pm_ops, }, .probe = usbhs_probe, .remove = __devexit_p(usbhs_remove), -- cgit v1.2.3 From 11935de5579a5d01b3c89d69b4fc7a38b4dd8eae Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:01:28 -0700 Subject: usb: gadget: renesas_usbhs: change usbhsc_bus_ctrl() to usbsc_set_buswait() renesas_usbhs will have register DVSTCTR control function for HOST support. This patch changes usbhsc_bus_ctrl() to usbsc_set_buswait(), to remove DVSTCTR access from it, Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 15 +++++---------- include/linux/usb/renesas_usbhs.h | 2 ++ 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 319ed47153d7..fd43fdd6cd81 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -149,17 +149,13 @@ int usbhs_frame_get_num(struct usbhs_priv *priv) /* * local functions */ -static void usbhsc_bus_ctrl(struct usbhs_priv *priv, int enable) +static void usbhsc_set_buswait(struct usbhs_priv *priv) { int wait = usbhs_get_dparam(priv, buswait_bwait); - u16 data = 0; - if (enable) { - /* set bus wait if platform have */ - if (wait) - usbhs_bset(priv, BUSWAIT, 0x000F, wait); - } - usbhs_write(priv, DVSTCTR, data); + /* set bus wait if platform have */ + if (wait) + usbhs_bset(priv, BUSWAIT, 0x000F, wait); } /* @@ -191,10 +187,9 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* USB on */ usbhs_sys_clock_ctrl(priv, enable); - usbhsc_bus_ctrl(priv, enable); + usbhsc_set_buswait(priv); } else { /* USB off */ - usbhsc_bus_ctrl(priv, enable); usbhs_sys_clock_ctrl(priv, enable); /* disable PM */ diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index 8977431259c6..959af02d3af6 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -101,6 +101,8 @@ struct renesas_usbhs_driver_param { * option: * * for BUSWAIT :: BWAIT + * see + * renesas_usbhs/common.c :: usbhsc_set_buswait() * */ int buswait_bwait; -- cgit v1.2.3 From 258485d9904703c4cb3a2b3ee38fe2a0cbf01f48 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:01:40 -0700 Subject: usb: gadget: renesas_usbhs: add bus control functions this patch add DVSTCTR control function for HOST support Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 35 ++++++++++++++++++++++++++++++++++- drivers/usb/renesas_usbhs/common.h | 9 +++++++++ include/linux/usb/renesas_usbhs.h | 7 +++++++ 3 files changed, 50 insertions(+), 1 deletion(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index fd43fdd6cd81..243512d93e58 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -146,6 +146,33 @@ int usbhs_frame_get_num(struct usbhs_priv *priv) return usbhs_read(priv, FRMNUM) & FRNM_MASK; } +/* + * bus/vbus functions + */ +void usbhs_bus_send_sof_enable(struct usbhs_priv *priv) +{ + usbhs_bset(priv, DVSTCTR, (USBRST | UACT), UACT); +} + +void usbhs_bus_send_reset(struct usbhs_priv *priv) +{ + usbhs_bset(priv, DVSTCTR, (USBRST | UACT), USBRST); +} + +int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable) +{ + struct platform_device *pdev = usbhs_priv_to_pdev(priv); + + return usbhs_platform_call(priv, set_vbus, pdev, enable); +} + +static void usbhsc_bus_init(struct usbhs_priv *priv) +{ + usbhs_write(priv, DVSTCTR, 0); + + usbhs_vbus_ctrl(priv, 0); +} + /* * local functions */ @@ -187,7 +214,6 @@ static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable) /* USB on */ usbhs_sys_clock_ctrl(priv, enable); - usbhsc_set_buswait(priv); } else { /* USB off */ usbhs_sys_clock_ctrl(priv, enable); @@ -229,6 +255,10 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) usbhsc_power_ctrl(priv, enable); + /* bus init */ + usbhsc_set_buswait(priv); + usbhsc_bus_init(priv); + /* module start */ usbhs_mod_call(priv, start, priv); @@ -238,6 +268,9 @@ static void usbhsc_hotplug(struct usbhs_priv *priv) /* module stop */ usbhs_mod_call(priv, stop, priv); + /* bus init */ + usbhsc_bus_init(priv); + /* power off */ if (usbhsc_flags_has(priv, USBHSF_RUNTIME_PWCTRL)) usbhsc_power_ctrl(priv, enable); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index b410463a1212..54b5924baae7 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -102,6 +102,8 @@ struct usbhs_priv; /* DVSTCTR */ #define EXTLP (1 << 10) /* Controls the EXTLP pin output state */ #define PWEN (1 << 9) /* Controls the PWEN pin output state */ +#define USBRST (1 << 6) /* Bus Reset Output */ +#define UACT (1 << 4) /* USB Bus Enable */ #define RHST (0x7) /* Reset Handshake */ #define RHST_LOW_SPEED 1 /* Low-speed connection */ #define RHST_FULL_SPEED 2 /* Full-speed connection */ @@ -257,6 +259,13 @@ void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +/* + * bus + */ +void usbhs_bus_send_sof_enable(struct usbhs_priv *priv); +void usbhs_bus_send_reset(struct usbhs_priv *priv); +int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable); + /* * frame */ diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index 959af02d3af6..040d8bb2b5a2 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -82,6 +82,13 @@ struct renesas_usbhs_platform_callback { * get VBUS status function. */ int (*get_vbus)(struct platform_device *pdev); + + /* + * option: + * + * VBUS control is needed for Host + */ + int (*set_vbus)(struct platform_device *pdev, int enable); }; /* -- cgit v1.2.3 From 75587f52c7b0d6c319515138a495a619b552a670 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:01:51 -0700 Subject: usb: gadget: renesas_usbhs: add usbhs_bus_get_speed() current mod_gadget had got usb speed on usbhsg_irq_dev_state() which is status change interrupt callback function. And the usb speed data was included in its parameter. But this style works for mod_gadget, but doesn't work for mod_host which isn't interrupted when device status was changed. This patch add usbhs_bus_get_speed() to solve this issue. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 16 ++++++++++++++++ drivers/usb/renesas_usbhs/common.h | 1 + drivers/usb/renesas_usbhs/mod.c | 16 ---------------- drivers/usb/renesas_usbhs/mod.h | 2 -- drivers/usb/renesas_usbhs/mod_gadget.c | 2 +- 5 files changed, 18 insertions(+), 19 deletions(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 243512d93e58..17abdfe53067 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -159,6 +159,22 @@ void usbhs_bus_send_reset(struct usbhs_priv *priv) usbhs_bset(priv, DVSTCTR, (USBRST | UACT), USBRST); } +int usbhs_bus_get_speed(struct usbhs_priv *priv) +{ + u16 dvstctr = usbhs_read(priv, DVSTCTR); + + switch (RHST & dvstctr) { + case RHST_LOW_SPEED: + return USB_SPEED_LOW; + case RHST_FULL_SPEED: + return USB_SPEED_FULL; + case RHST_HIGH_SPEED: + return USB_SPEED_HIGH; + } + + return USB_SPEED_UNKNOWN; +} + int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable) { struct platform_device *pdev = usbhs_priv_to_pdev(priv); diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 54b5924baae7..a5cef8160107 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -264,6 +264,7 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); */ void usbhs_bus_send_sof_enable(struct usbhs_priv *priv); void usbhs_bus_send_reset(struct usbhs_priv *priv); +int usbhs_bus_get_speed(struct usbhs_priv *priv); int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable); /* diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 74ef49e7dd5f..ab1203098931 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -168,20 +168,6 @@ void usbhs_mod_remove(struct usbhs_priv *priv) /* * status functions */ -int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state) -{ - switch (irq_state->dvstctr & RHST) { - case RHST_LOW_SPEED: - return USB_SPEED_LOW; - case RHST_FULL_SPEED: - return USB_SPEED_FULL; - case RHST_HIGH_SPEED: - return USB_SPEED_HIGH; - } - - return USB_SPEED_UNKNOWN; -} - int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) { int state = irq_state->intsts0 & DVSQ_MASK; @@ -221,8 +207,6 @@ static void usbhs_status_get_each_irq(struct usbhs_priv *priv, state->intsts0 = usbhs_read(priv, INTSTS0); state->intsts1 = usbhs_read(priv, INTSTS1); - state->dvstctr = usbhs_read(priv, DVSTCTR); - /* mask */ if (mod) { state->brdysts = usbhs_read(priv, BRDYSTS); diff --git a/drivers/usb/renesas_usbhs/mod.h b/drivers/usb/renesas_usbhs/mod.h index 5c845a28a21c..93edb1f29eb0 100644 --- a/drivers/usb/renesas_usbhs/mod.h +++ b/drivers/usb/renesas_usbhs/mod.h @@ -30,7 +30,6 @@ struct usbhs_irq_state { u16 brdysts; u16 nrdysts; u16 bempsts; - u16 dvstctr; }; struct usbhs_mod { @@ -99,7 +98,6 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv); /* * status functions */ -int usbhs_status_get_usb_speed(struct usbhs_irq_state *irq_state); int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state); int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state); diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c index babd90c979c1..ae7d816c23d9 100644 --- a/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/drivers/usb/renesas_usbhs/mod_gadget.c @@ -353,7 +353,7 @@ static int usbhsg_irq_dev_state(struct usbhs_priv *priv, struct usbhsg_gpriv *gpriv = usbhsg_priv_to_gpriv(priv); struct device *dev = usbhsg_gpriv_to_dev(gpriv); - gpriv->gadget.speed = usbhs_status_get_usb_speed(irq_state); + gpriv->gadget.speed = usbhs_bus_get_speed(priv); dev_dbg(dev, "state = %x : speed : %d\n", usbhs_status_get_device_state(irq_state), -- cgit v1.2.3 From ef8bedb9048c293dfa85ac36482a1970646a8272 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:02:33 -0700 Subject: usb: gadget: renesas_usbhs: move usbhs_usbreq_get/set_val() to common.c usbhs_usbreq_get/set_val() functions were in pipe.c file, but it is irrelevant to pipe. this patch move it to common.c Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 26 ++++++++++++++++++++++++++ drivers/usb/renesas_usbhs/common.h | 7 +++++++ drivers/usb/renesas_usbhs/pipe.c | 24 ------------------------ drivers/usb/renesas_usbhs/pipe.h | 6 ------ 4 files changed, 33 insertions(+), 30 deletions(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 17abdfe53067..b327458f5cad 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -146,6 +146,32 @@ int usbhs_frame_get_num(struct usbhs_priv *priv) return usbhs_read(priv, FRMNUM) & FRNM_MASK; } +/* + * usb request functions + */ +void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) +{ + u16 val; + + val = usbhs_read(priv, USBREQ); + req->bRequest = (val >> 8) & 0xFF; + req->bRequestType = (val >> 0) & 0xFF; + + req->wValue = usbhs_read(priv, USBVAL); + req->wIndex = usbhs_read(priv, USBINDX); + req->wLength = usbhs_read(priv, USBLENG); +} + +void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) +{ + usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); + usbhs_write(priv, USBVAL, req->wValue); + usbhs_write(priv, USBINDX, req->wIndex); + usbhs_write(priv, USBLENG, req->wLength); + + usbhs_bset(priv, DCPCTR, SUREQ, SUREQ); +} + /* * bus/vbus functions */ diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index a5cef8160107..3b233809cdaa 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -185,6 +185,7 @@ struct usbhs_priv; /* PIPEnCTR */ /* DCPCTR */ #define BSTS (1 << 15) /* Buffer Status */ +#define SUREQ (1 << 14) /* Sending SETUP Token */ #define CSSTS (1 << 12) /* CSSTS Status */ #define SQCLR (1 << 8) /* Toggle Bit Clear */ #define ACLRM (1 << 9) /* Buffer Auto-Clear Mode */ @@ -259,6 +260,12 @@ void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable); void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable); +/* + * usb request + */ +void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); +void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); + /* * bus */ diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c index 18101332eb8a..6aaa4364994e 100644 --- a/drivers/usb/renesas_usbhs/pipe.c +++ b/drivers/usb/renesas_usbhs/pipe.c @@ -39,30 +39,6 @@ static char *usbhsp_pipe_name[] = { [USB_ENDPOINT_XFER_ISOC] = "ISO", }; -/* - * usb request functions - */ -void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) -{ - u16 val; - - val = usbhs_read(priv, USBREQ); - req->bRequest = (val >> 8) & 0xFF; - req->bRequestType = (val >> 0) & 0xFF; - - req->wValue = usbhs_read(priv, USBVAL); - req->wIndex = usbhs_read(priv, USBINDX); - req->wLength = usbhs_read(priv, USBLENG); -} - -void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) -{ - usbhs_write(priv, USBREQ, (req->bRequest << 8) | req->bRequestType); - usbhs_write(priv, USBVAL, req->wValue); - usbhs_write(priv, USBINDX, req->wIndex); - usbhs_write(priv, USBLENG, req->wLength); -} - /* * DCPCTR/PIPEnCTR functions */ diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h index fc776accb1df..8120fad73b2d 100644 --- a/drivers/usb/renesas_usbhs/pipe.h +++ b/drivers/usb/renesas_usbhs/pipe.h @@ -70,12 +70,6 @@ struct usbhs_pipe_info { */ #define usbhs_priv_to_pipeinfo(pr) (&(pr)->pipe_info) -/* - * usb request - */ -void usbhs_usbreq_get_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); -void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req); - /* * pipe control */ -- cgit v1.2.3 From f427eb64f4c5433a91da5eb139970dd5cbad9082 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:06:12 -0700 Subject: usb: gadget: renesas_usbhs: support otg pin control some renesas_usbhs device is supporting OTG external device interface. In that device, it is necessary to control PWEN/EXTLP on DVSTCTR. This patch support it. But renesas_usbhs driver doesn't have OTG support for now. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- arch/arm/mach-shmobile/board-mackerel.c | 1 + drivers/usb/renesas_usbhs/common.c | 4 ++++ include/linux/usb/renesas_usbhs.h | 5 +++++ 3 files changed, 10 insertions(+) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 0ea71f8d4b89..c20612ea5d0e 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -808,6 +808,7 @@ static struct usbhs_private usbhs1_private = { }, .driver_param = { .buswait_bwait = 4, + .has_otg = 1, .pipe_type = usbhs1_pipe_cfg, .pipe_size = ARRAY_SIZE(usbhs1_pipe_cfg), }, diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index b327458f5cad..1161d78e1665 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -114,6 +114,10 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable) { u16 mask = DCFM | DRPD | DPRPU; u16 val = DCFM | DRPD; + int has_otg = usbhs_get_dparam(priv, has_otg); + + if (has_otg) + usbhs_bset(priv, DVSTCTR, (EXTLP | PWEN), (EXTLP | PWEN)); /* * if enable diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h index 040d8bb2b5a2..e5a40c318548 100644 --- a/include/linux/usb/renesas_usbhs.h +++ b/include/linux/usb/renesas_usbhs.h @@ -136,6 +136,11 @@ struct renesas_usbhs_driver_param { * pio <--> dma border. */ int pio_dma_border; /* default is 64byte */ + + /* + * option: + */ + u32 has_otg:1; /* for controlling PWEN/EXTLP */ }; /* -- cgit v1.2.3 From a9be4a45627c0eaa5f3f16987243530f4df6b514 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:06:35 -0700 Subject: usb: gadget: renesas_usbhs: make sure SOF packet sending-out control It is enabled to set SOF packet output bit when USBRST bit was set. And USBRST bit should be set 0 when SOF packet was output. Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 1161d78e1665..895eb44a1a51 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -181,6 +181,13 @@ void usbhs_usbreq_set_val(struct usbhs_priv *priv, struct usb_ctrlrequest *req) */ void usbhs_bus_send_sof_enable(struct usbhs_priv *priv) { + u16 status = usbhs_read(priv, DVSTCTR) & (USBRST | UACT); + + if (status != USBRST) { + struct device *dev = usbhs_priv_to_dev(priv); + dev_err(dev, "usbhs should be reset\n"); + } + usbhs_bset(priv, DVSTCTR, (USBRST | UACT), UACT); } -- cgit v1.2.3 From eb05191f6a9aba8344a0d5f28642b5ecf44d49a4 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Mon, 10 Oct 2011 22:06:46 -0700 Subject: usb: gadget: renesas_usbhs: add usbhs_set_device_speed() support for host mod_host needs device speed setup function Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 42 ++++++++++++++++++++++++++++++++++++++ drivers/usb/renesas_usbhs/common.h | 25 +++++++++++++++++++++++ 2 files changed, 67 insertions(+) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index 895eb44a1a51..c3aef40fa9e5 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -226,6 +226,48 @@ static void usbhsc_bus_init(struct usbhs_priv *priv) usbhs_vbus_ctrl(priv, 0); } +/* + * device configuration + */ +int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, + u16 upphub, u16 hubport, u16 speed) +{ + struct device *dev = usbhs_priv_to_dev(priv); + u16 usbspd = 0; + u32 reg = DEVADD0 + (2 * devnum); + + if (devnum > 10) { + dev_err(dev, "cannot set speed to unknown device %d\n", devnum); + return -EIO; + } + + if (upphub > 0xA) { + dev_err(dev, "unsupported hub number %d\n", upphub); + return -EIO; + } + + switch (speed) { + case USB_SPEED_LOW: + usbspd = USBSPD_SPEED_LOW; + break; + case USB_SPEED_FULL: + usbspd = USBSPD_SPEED_FULL; + break; + case USB_SPEED_HIGH: + usbspd = USBSPD_SPEED_HIGH; + break; + default: + dev_err(dev, "unsupported speed %d\n", speed); + return -EIO; + } + + usbhs_write(priv, reg, UPPHUB(upphub) | + HUBPORT(hubport)| + USBSPD(usbspd)); + + return 0; +} + /* * local functions */ diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index 7822b0b8aeed..0e867a33a46e 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -90,6 +90,17 @@ struct usbhs_priv; #define PIPE9TRN 0x00BA #define PIPEATRE 0x00BC #define PIPEATRN 0x00BE +#define DEVADD0 0x00D0 /* Device address n configuration */ +#define DEVADD1 0x00D2 +#define DEVADD2 0x00D4 +#define DEVADD3 0x00D6 +#define DEVADD4 0x00D8 +#define DEVADD5 0x00DA +#define DEVADD6 0x00DC +#define DEVADD7 0x00DE +#define DEVADD8 0x00E0 +#define DEVADD9 0x00E2 +#define DEVADDA 0x00E4 /* SYSCFG */ #define SCKE (1 << 10) /* USB Module Clock Enable */ @@ -206,6 +217,14 @@ struct usbhs_priv; /* FRMNUM */ #define FRNM_MASK (0x7FF) +/* DEVADDn */ +#define UPPHUB(x) (((x) & 0xF) << 11) /* HUB Register */ +#define HUBPORT(x) (((x) & 0x7) << 8) /* HUB Port for Target Device */ +#define USBSPD(x) (((x) & 0x3) << 6) /* Device Transfer Rate */ +#define USBSPD_SPEED_LOW 0x1 +#define USBSPD_SPEED_FULL 0x2 +#define USBSPD_SPEED_HIGH 0x3 + /* * struct */ @@ -280,6 +299,12 @@ int usbhs_vbus_ctrl(struct usbhs_priv *priv, int enable); */ int usbhs_frame_get_num(struct usbhs_priv *priv); +/* + * device config + */ +int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, + u16 hubport, u16 speed); + /* * data */ -- cgit v1.2.3 From 482982062f1bc25ffb5383ab724d73d1a7af07cf Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Wed, 12 Oct 2011 21:02:22 -0700 Subject: usb: gadget: renesas_usbhs: bugfix: don't modify platform data renesas_usbhs has default callback functions and settings. And it tried overwrite to platform private data if platform doesn't have them. So, if renesas_usbhs was compiled as module, it will be hung-up on 2nd insmod. This patch fixup it. Special thanks to Bastian Reported-by: Bastian Hecht Signed-off-by: Kuninori Morimoto Signed-off-by: Felipe Balbi --- drivers/usb/renesas_usbhs/common.c | 24 ++++++++++++++---------- drivers/usb/renesas_usbhs/common.h | 6 +++--- drivers/usb/renesas_usbhs/mod.c | 2 +- 3 files changed, 18 insertions(+), 14 deletions(-) (limited to 'drivers/usb/renesas_usbhs/common.c') diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c index c3aef40fa9e5..d2e2efaba658 100644 --- a/drivers/usb/renesas_usbhs/common.c +++ b/drivers/usb/renesas_usbhs/common.c @@ -61,8 +61,8 @@ */ #define usbhs_platform_call(priv, func, args...)\ (!(priv) ? -ENODEV : \ - !((priv)->pfunc->func) ? 0 : \ - (priv)->pfunc->func(args)) + !((priv)->pfunc.func) ? 0 : \ + (priv)->pfunc.func(args)) /* * common functions @@ -446,24 +446,28 @@ static int __devinit usbhs_probe(struct platform_device *pdev) /* * care platform info */ - priv->pfunc = &info->platform_callback; - priv->dparam = &info->driver_param; + memcpy(&priv->pfunc, + &info->platform_callback, + sizeof(struct renesas_usbhs_platform_callback)); + memcpy(&priv->dparam, + &info->driver_param, + sizeof(struct renesas_usbhs_driver_param)); /* set driver callback functions for platform */ dfunc = &info->driver_callback; dfunc->notify_hotplug = usbhsc_drvcllbck_notify_hotplug; /* set default param if platform doesn't have */ - if (!priv->dparam->pipe_type) { - priv->dparam->pipe_type = usbhsc_default_pipe_type; - priv->dparam->pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); + if (!priv->dparam.pipe_type) { + priv->dparam.pipe_type = usbhsc_default_pipe_type; + priv->dparam.pipe_size = ARRAY_SIZE(usbhsc_default_pipe_type); } - if (!priv->dparam->pio_dma_border) - priv->dparam->pio_dma_border = 64; /* 64byte */ + if (!priv->dparam.pio_dma_border) + priv->dparam.pio_dma_border = 64; /* 64byte */ /* FIXME */ /* runtime power control ? */ - if (priv->pfunc->get_vbus) + if (priv->pfunc.get_vbus) usbhsc_flags_set(priv, USBHSF_RUNTIME_PWCTRL); /* diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h index dc9490d1f42f..8729da5c3be6 100644 --- a/drivers/usb/renesas_usbhs/common.h +++ b/drivers/usb/renesas_usbhs/common.h @@ -242,8 +242,8 @@ struct usbhs_priv { void __iomem *base; unsigned int irq; - struct renesas_usbhs_platform_callback *pfunc; - struct renesas_usbhs_driver_param *dparam; + struct renesas_usbhs_platform_callback pfunc; + struct renesas_usbhs_driver_param dparam; struct delayed_work notify_hotplug_work; struct platform_device *pdev; @@ -318,7 +318,7 @@ int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, * data */ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev); -#define usbhs_get_dparam(priv, param) (priv->dparam->param) +#define usbhs_get_dparam(priv, param) (priv->dparam.param) #define usbhs_priv_to_pdev(priv) (priv->pdev) #define usbhs_priv_to_dev(priv) (&priv->pdev->dev) #define usbhs_priv_to_lock(priv) (&priv->lock) diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c index 2d3b09d0d846..053f86d70009 100644 --- a/drivers/usb/renesas_usbhs/mod.c +++ b/drivers/usb/renesas_usbhs/mod.c @@ -58,7 +58,7 @@ void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); info->irq_vbus = usbhsm_autonomy_irq_vbus; - priv->pfunc->get_vbus = usbhsm_autonomy_get_vbus; + priv->pfunc.get_vbus = usbhsm_autonomy_get_vbus; usbhs_irq_callback_update(priv, NULL); } -- cgit v1.2.3