usb: renesas_usbhs: add autonomy mode

Current renesas_usbhs was designed to save power when USB is not connected.
And it assumed platform uses callback to notify connection/disconnection
by external interrupt.

But some SuperH / platform board doesn't have such feature.

This patch adds autonomy mode which detect USB connection/disconnection
by internal interrupt.
But power will be always ON when autonomy mode is selected.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index d0f5f67..a577f8f 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -20,6 +20,48 @@
 #include "./mod.h"
 
 #define usbhs_priv_to_modinfo(priv) (&priv->mod_info)
+#define usbhs_mod_info_call(priv, func, param...)	\
+({						\
+	struct usbhs_mod_info *info;		\
+	info = usbhs_priv_to_modinfo(priv);	\
+	!info->func ? 0 :			\
+	 info->func(param);			\
+})
+
+/*
+ *		autonomy
+ *
+ * these functions are used if platform doesn't have external phy.
+ *  -> there is no "notify_hotplug" callback from platform
+ *  -> call "notify_hotplug" by itself
+ *  -> use own interrupt to connect/disconnect
+ *  -> it mean module clock is always ON
+ *             ~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+static int usbhsm_autonomy_get_vbus(struct platform_device *pdev)
+{
+	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
+
+	return  VBSTS & usbhs_read(priv, INTSTS0);
+}
+
+static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
+				    struct usbhs_irq_state *irq_state)
+{
+	struct platform_device *pdev = usbhs_priv_to_pdev(priv);
+
+	return usbhsc_drvcllbck_notify_hotplug(pdev);
+}
+
+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;
+
+	usbhs_irq_callback_update(priv, NULL);
+}
 
 /*
  *		host / gadget functions
@@ -227,6 +269,9 @@
 	 * see also
 	 *	usbhs_irq_setting_update
 	 */
+	if (irq_state.intsts0 & VBINT)
+		usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);
+
 	if (irq_state.intsts0 & DVST)
 		usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
 
@@ -245,6 +290,7 @@
 void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
 {
 	u16 intenb0 = 0;
+	struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
 
 	usbhs_write(priv, INTENB0, 0);
 
@@ -260,6 +306,8 @@
 	 * it don't enable DVSE (intenb0) here
 	 * but "mod->irq_dev_state" will be called.
 	 */
+	if (info->irq_vbus)
+		intenb0 |= VBSE;
 
 	if (mod) {
 		if (mod->irq_ctrl_stage)