Commit 3b68e7ca authored by Yoshihiro Shimoda's avatar Yoshihiro Shimoda Committed by Felipe Balbi

usb: gadget: udc: renesas_usb3: add extcon support

This patch adds extcon support to see VBUS/ID signal states.
Signed-off-by: default avatarYoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 77172a1f
...@@ -191,6 +191,7 @@ config USB_RENESAS_USBHS_UDC ...@@ -191,6 +191,7 @@ config USB_RENESAS_USBHS_UDC
config USB_RENESAS_USB3 config USB_RENESAS_USB3
tristate 'Renesas USB3.0 Peripheral controller' tristate 'Renesas USB3.0 Peripheral controller'
depends on ARCH_RENESAS || COMPILE_TEST depends on ARCH_RENESAS || COMPILE_TEST
depends on EXTCON
help help
Renesas USB3.0 Peripheral controller is a USB peripheral controller Renesas USB3.0 Peripheral controller is a USB peripheral controller
that supports super, high, and full speed USB 3.0 data transfers. that supports super, high, and full speed USB 3.0 data transfers.
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/extcon.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -263,6 +264,8 @@ struct renesas_usb3 { ...@@ -263,6 +264,8 @@ struct renesas_usb3 {
struct usb_gadget gadget; struct usb_gadget gadget;
struct usb_gadget_driver *driver; struct usb_gadget_driver *driver;
struct extcon_dev *extcon;
struct work_struct extcon_work;
struct renesas_usb3_ep *usb3_ep; struct renesas_usb3_ep *usb3_ep;
int num_usb3_eps; int num_usb3_eps;
...@@ -275,6 +278,8 @@ struct renesas_usb3 { ...@@ -275,6 +278,8 @@ struct renesas_usb3 {
u8 ep0_buf[USB3_EP0_BUF_SIZE]; u8 ep0_buf[USB3_EP0_BUF_SIZE];
bool softconnect; bool softconnect;
bool workaround_for_vbus; bool workaround_for_vbus;
bool extcon_host; /* check id and set EXTCON_USB_HOST */
bool extcon_usb; /* check vbus and set EXTCON_USB */
}; };
#define gadget_to_renesas_usb3(_gadget) \ #define gadget_to_renesas_usb3(_gadget) \
...@@ -338,6 +343,15 @@ static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask, ...@@ -338,6 +343,15 @@ static int usb3_wait(struct renesas_usb3 *usb3, u32 reg, u32 mask,
return -EBUSY; return -EBUSY;
} }
static void renesas_usb3_extcon_work(struct work_struct *work)
{
struct renesas_usb3 *usb3 = container_of(work, struct renesas_usb3,
extcon_work);
extcon_set_state_sync(usb3->extcon, EXTCON_USB_HOST, usb3->extcon_host);
extcon_set_state_sync(usb3->extcon, EXTCON_USB, usb3->extcon_usb);
}
static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits) static void usb3_enable_irq_1(struct renesas_usb3 *usb3, u32 bits)
{ {
usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1); usb3_set_bit(usb3, bits, USB3_USB_INT_ENA_1);
...@@ -533,10 +547,14 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3) ...@@ -533,10 +547,14 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
if (usb3->workaround_for_vbus) { if (usb3->workaround_for_vbus) {
usb3_connect(usb3); usb3_connect(usb3);
} else { } else {
if (usb3_read(usb3, USB3_USB_STA) & USB_STA_VBUS_STA) usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
USB_STA_VBUS_STA);
if (usb3->extcon_usb)
usb3_connect(usb3); usb3_connect(usb3);
else else
usb3_disconnect(usb3); usb3_disconnect(usb3);
schedule_work(&usb3->extcon_work);
} }
} }
...@@ -569,10 +587,14 @@ static bool usb3_is_a_device(struct renesas_usb3 *usb3) ...@@ -569,10 +587,14 @@ static bool usb3_is_a_device(struct renesas_usb3 *usb3)
static void usb3_check_id(struct renesas_usb3 *usb3) static void usb3_check_id(struct renesas_usb3 *usb3)
{ {
if (usb3_is_a_device(usb3)) usb3->extcon_host = usb3_is_a_device(usb3);
if (usb3->extcon_host)
usb3_mode_config(usb3, true, true); usb3_mode_config(usb3, true, true);
else else
usb3_mode_config(usb3, false, false); usb3_mode_config(usb3, false, false);
schedule_work(&usb3->extcon_work);
} }
static void renesas_usb3_init_controller(struct renesas_usb3 *usb3) static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
...@@ -1953,6 +1975,12 @@ static const struct of_device_id usb3_of_match[] = { ...@@ -1953,6 +1975,12 @@ static const struct of_device_id usb3_of_match[] = {
}; };
MODULE_DEVICE_TABLE(of, usb3_of_match); MODULE_DEVICE_TABLE(of, usb3_of_match);
static const unsigned int renesas_usb3_cable[] = {
EXTCON_USB,
EXTCON_USB_HOST,
EXTCON_NONE,
};
static int renesas_usb3_probe(struct platform_device *pdev) static int renesas_usb3_probe(struct platform_device *pdev)
{ {
struct renesas_usb3 *usb3; struct renesas_usb3 *usb3;
...@@ -1996,6 +2024,17 @@ static int renesas_usb3_probe(struct platform_device *pdev) ...@@ -1996,6 +2024,17 @@ static int renesas_usb3_probe(struct platform_device *pdev)
if (ret < 0) if (ret < 0)
return ret; return ret;
INIT_WORK(&usb3->extcon_work, renesas_usb3_extcon_work);
usb3->extcon = devm_extcon_dev_allocate(&pdev->dev, renesas_usb3_cable);
if (IS_ERR(usb3->extcon))
return PTR_ERR(usb3->extcon);
ret = devm_extcon_dev_register(&pdev->dev, usb3->extcon);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to register extcon\n");
return ret;
}
/* for ep0 handling */ /* for ep0 handling */
usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL); usb3->ep0_req = __renesas_usb3_ep_alloc_request(GFP_KERNEL);
if (!usb3->ep0_req) if (!usb3->ep0_req)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment