Skip to contentSkip to conversation

Add tested id switch and vbus connect detect support for Chipidea

PATCH Superseded Peter Chen 3 participants 26 messages Feb 17, 2013 – Mar 1, 2013

Subsystems (3)

v9 of 15 Superseded Latest is v15 →

lore
Share & tools
lore

Peter Chen

author
#0 lore raw

v9 cover Add tested id switch and vbus connect detect support for Chipidea

Changes for v9:
- Some small comments from Alex like: variable comment for otg event additional newline. [3/9]
- Import function tell show if the controller has otg capable, if the controller supports both host and device, we think it is otg capable, and can read OTGSC. [3/9]
- Merge two otg patches [v8 3/8] and [v8 4/8] to one [v9 3/9]. [3/9]
- Add inline to ci_hdrc_gadget_destroy if CONFIG_USB_CHIPIDEA_UDC is not defined, it can fix one build warning "defined but not used" [3/9]
- One comment from Felipe about changing calling gadget disconnect API at chipidea's udc driver. I move calling ci->driver->disconnect from _gadget_stop_activity to which calls _gadget_stop_activity except ci13xxx_stop, as udc core will call disconnect when do rmmod gadget. [7/9]
- Add ci core probe's return value to ci's platform_data, we do this for getting core's probe's result at platform layer, and quit it if the core's probe fails. [8/9] [9/9]

Changes for v8:
- Add ci_supports_gadget helper to know if the controller supports gadget, if the controller supports gadget, it needs to read otgsc to know the vbus value, basically, if the controller supports gadget, it will support host as well [3/8]
- At ci_hdrc_probe, it needs to add free memory at error path [3/8]
- Cosolidate ci->driver = NULL at ci13xxx_stop [8/8]

Changes for v7:
For Patch 8/8, we only need to set ci->driver to NULL when usb cable is not connected, for other changes, it will case some runtime pm unmatch and un-align with udc-core & composite driver problems.

Changes for v6:
- Add Alex comments for init/destroy function [3/8] [4/8]
- Remove memset(&ci->gadget, 0, sizeof(ci->gadget)) at destory function [4/8]
- Add Kishon's comment: Change the format of struct usb_otg otg at drivers/usb/chipidea/ci.h [1/8]
- Add comments for CI_VBUS_STABLE_TIMEOUT [3/8]
- Change the otg_set_peripheral return value check as the fully
chipidea driver users don't need it. [4/8]
- Fix one bug that the oops when re-plug in usb cable after
rmmod gadget [8/8]

Anyone who has tested this patchset, please give a tested-by, thanks.

This patchset adds tested otg id switch function and vbus connect/disconnect detection for chipidea driver. The mainly design of id/vbus handling follows msm otg driver. I hope the msm usb maintainer can have a look of this patchset, and give some comments, and move the whole msm usb driver to chipidea framework if possible in the future.

This patch is fully tested at imx6 sabresd platform.
My chipidea repo: https://github.com/hzpeterchen/linux-usb.git
which is rebased of Sascha's git
(git://git.pengutronix.de/git/imx/linux-2.6.git tags/usb-chipidea-otg-for-next)

At sascha's tag, it finishes some dr_mode and phy_type patches, in that way, we can choose host-only and gadget-only function at dts file as well as we can choose different phy setting.

Besides sascha's work, there are some Michael Grzeschik/Marc Kleine-Budde usbmisc patch, imx chipidea suspend/resume patch, and one pin control patch for imx6

Peter Chen (9):
Revert "USB: chipidea: add vbus detect for udc"
usb: chipidea: add otg file
usb: chipidea: add otg id switch and vbus connect/disconnect detect
usb: chipidea: udc: add pullup/pulldown dp at hw_device_state
usb: chipidea: udc: retire the flag CI13_PULLUP_ON_VBUS
usb: chipidea: imx: add internal vbus regulator control
usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod
gadget
usb: chipidea: tell platform layer the ci core probe's result
usb: chipidea: imx: fix the error that using uninitialized pointer

 drivers/usb/chipidea/Makefile      |    2 +-
 drivers/usb/chipidea/bits.h        |   10 ++
 drivers/usb/chipidea/ci.h          |   14 +++-
 drivers/usb/chipidea/ci13xxx_imx.c |   85 ++++++++++++----
 drivers/usb/chipidea/ci13xxx_msm.c |    1 -
 drivers/usb/chipidea/core.c        |  192 ++++++++++++++++++++++++++++++++----
 drivers/usb/chipidea/host.c        |    6 +
 drivers/usb/chipidea/host.h        |    6 +-
 drivers/usb/chipidea/otg.c         |   68 +++++++++++++
 drivers/usb/chipidea/otg.h         |    9 ++
 drivers/usb/chipidea/udc.c         |  118 ++++++++++------------
 drivers/usb/chipidea/udc.h         |    4 +
 include/linux/usb/chipidea.h       |    2 +-
 13 files changed, 405 insertions(+), 112 deletions(-)
 create mode 100644 drivers/usb/chipidea/otg.c
 create mode 100644 drivers/usb/chipidea/otg.h
author
#1 lore raw

PATCH v9 1/9 Revert "USB: chipidea: add vbus detect for udc"

vbus register is at otgsc, and vbus detect does not belong to device function. Revert this patch, and will move vbus detect function to drivers/usb/chipidea/udc.c

This reverts commit 8c4fc031954b4eb72daf13d3c907a985a3eee208.

---
 drivers/usb/chipidea/ci.h  |    1 -
 drivers/usb/chipidea/udc.c |   39 +--------------------------------------
 2 files changed, 1 insertions(+), 39 deletions(-)
drivers/usb/chipidea/ci.h +0 -1
index e25d126..d738603 100644
@@ -139,7 +139,6 @@ struct ci13xxx {
 	enum ci_role			role;
 	bool				is_otg;
 	struct work_struct		work;
-	struct work_struct		vbus_work;
 	struct workqueue_struct		*wq;
 
 	struct dma_pool			*qh_pool;
drivers/usb/chipidea/udc.c +1 -38
index 2f45bba..d214448 100644
@@ -305,18 +305,6 @@ static u32 hw_test_and_clear_intr_active(struct ci13xxx *ci)
 	return reg;
 }
 
-static void hw_enable_vbus_intr(struct ci13xxx *ci)
-{
-	hw_write(ci, OP_OTGSC, OTGSC_AVVIS, OTGSC_AVVIS);
-	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, OTGSC_AVVIE);
-	queue_work(ci->wq, &ci->vbus_work);
-}
-
-static void hw_disable_vbus_intr(struct ci13xxx *ci)
-{
-	hw_write(ci, OP_OTGSC, OTGSC_AVVIE, 0);
-}
-
 /**
  * hw_test_and_clear_setup_guard: test & clear setup guard (execute without
  *                                interruption)
@@ -383,16 +371,6 @@ static int hw_usb_reset(struct ci13xxx *ci)
 	return 0;
 }
 
-static void vbus_work(struct work_struct *work)
-{
-	struct ci13xxx *ci = container_of(work, struct ci13xxx, vbus_work);
-
-	if (hw_read(ci, OP_OTGSC, OTGSC_AVV))
-		usb_gadget_vbus_connect(&ci->gadget);
-	else
-		usb_gadget_vbus_disconnect(&ci->gadget);
-}
-
 /******************************************************************************
  * UTIL block
  *****************************************************************************/
@@ -1392,7 +1370,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 		if (is_active) {
 			pm_runtime_get_sync(&_gadget->dev);
 			hw_device_reset(ci, USBMODE_CM_DC);
-			hw_enable_vbus_intr(ci);
 			hw_device_state(ci, ci->ep0out->qh.dma);
 		} else {
 			hw_device_state(ci, 0);
@@ -1567,10 +1544,8 @@ static int ci13xxx_start(struct usb_gadget *gadget,
 	pm_runtime_get_sync(&ci->gadget.dev);
 	if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
 		if (ci->vbus_active) {
-			if (ci->platdata->flags & CI13XXX_REGS_SHARED) {
+			if (ci->platdata->flags & CI13XXX_REGS_SHARED)
 				hw_device_reset(ci, USBMODE_CM_DC);
-				hw_enable_vbus_intr(ci);
-			}
 		} else {
 			pm_runtime_put_sync(&ci->gadget.dev);
 			goto done;
@@ -1676,13 +1651,6 @@ static irqreturn_t udc_irq(struct ci13xxx *ci)
 	} else {
 		retval = IRQ_NONE;
 	}
-
-	intr = hw_read(ci, OP_OTGSC, ~0);
-	hw_write(ci, OP_OTGSC, ~0, intr);
-
-	if (intr & (OTGSC_AVVIE & OTGSC_AVVIS))
-		queue_work(ci->wq, &ci->vbus_work);
-
 	spin_unlock(&ci->lock);
 
 	return retval;
@@ -1758,7 +1726,6 @@ static int udc_start(struct ci13xxx *ci)
 		retval = hw_device_reset(ci, USBMODE_CM_DC);
 		if (retval)
 			goto put_transceiver;
-		hw_enable_vbus_intr(ci);
 	}
 
 	retval = device_register(&ci->gadget.dev);
@@ -1821,9 +1788,6 @@ static void udc_stop(struct ci13xxx *ci)
 	if (ci == NULL)
 		return;
 
-	hw_disable_vbus_intr(ci);
-	cancel_work_sync(&ci->vbus_work);
-
 	usb_del_gadget_udc(&ci->gadget);
 
 	destroy_eps(ci);
@@ -1864,7 +1828,6 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
 	ci->roles[CI_ROLE_GADGET] = rdrv;
-	INIT_WORK(&ci->vbus_work, vbus_work);
 
 	return 0;
 }
Signature · 1 line
1.7.0.4
author
#2 lore raw

PATCH v9 2/9 usb: chipidea: add otg file

In reply to Peter Chen

Implement struct usb_otg, In that way, calling otg_set_peripheral will not be failed at udc.c.

---
 drivers/usb/chipidea/Makefile |    2 +-
 drivers/usb/chipidea/ci.h     |    2 +
 drivers/usb/chipidea/otg.c    |   60 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/chipidea/otg.h    |    6 ++++
 4 files changed, 69 insertions(+), 1 deletions(-)
 create mode 100644 drivers/usb/chipidea/otg.c
 create mode 100644 drivers/usb/chipidea/otg.h
drivers/usb/chipidea/Makefile +1 -1
index d92ca32..11f513c 100644
@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 
-ci_hdrc-y				:= core.o
+ci_hdrc-y				:= core.o otg.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
drivers/usb/chipidea/ci.h +2 -0
index d738603..697e369 100644
@@ -129,6 +129,7 @@ struct hw_bank {
  * @vbus_active: is VBUS active
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
+ * @otg: for otg support
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -164,6 +165,7 @@ struct ci13xxx {
 	bool				global_phy;
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
+	struct usb_otg      		otg;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
drivers/usb/chipidea/otg.c new file +60 -0

60 lines not on this page · raw message

drivers/usb/chipidea/otg.h new file +6 -0
new file mode 100644
index 0000000..b4c6b3e
@@ -0,0 +1,6 @@
+#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H
+#define __DRIVERS_USB_CHIPIDEA_OTG_H
+
+int ci_hdrc_otg_init(struct ci13xxx *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
Signature · 1 line
1.7.0.4
author
#3 lore raw

PATCH v9 3/9 usb: chipidea: add otg id switch and vbus connect/disconnect detect

In reply to Peter Chen

The main design flow is the same with msm otg driver, that is the id and vbus interrupt are handled at core driver, others are handled by individual drivers.

- At former design, when switch usb role from device->host, it will call udc_stop, it will remove the gadget driver, so when switch role from host->device, it can't add gadget driver any more.
At new design, when role switch occurs, the gadget just calls usb_gadget_vbus_disconnect/usb_gadget_vbus_connect as well as reset controller, it will not free any device/gadget structure

- Add vbus connect and disconnect to core interrupt handler, it can notify udc driver by calling usb_gadget_vbus_disconnect /usb_gadget_vbus_connect.

- vbus interrupt needs to be handled when gadget function is enabled

- Create/destroy the gadget at udc's init and destory function

- start/stop API are used at otg id switch and probe routine

- Defer some gadget operations at ci's delayed work queue

---
 drivers/usb/chipidea/bits.h        |   10 ++
 drivers/usb/chipidea/ci.h          |    9 ++-
 drivers/usb/chipidea/ci13xxx_imx.c |    3 +-
 drivers/usb/chipidea/core.c        |  190 ++++++++++++++++++++++++++++++++----
 drivers/usb/chipidea/host.c        |    6 +
 drivers/usb/chipidea/host.h        |    6 +-
 drivers/usb/chipidea/otg.c         |   28 ++++--
 drivers/usb/chipidea/otg.h         |    3 +
 drivers/usb/chipidea/udc.c         |   39 ++++++--
 drivers/usb/chipidea/udc.h         |    4 +
 10 files changed, 256 insertions(+), 42 deletions(-)
drivers/usb/chipidea/bits.h +10 -0
index d8ffc2f..58ef56c 100644
@@ -77,11 +77,21 @@
 #define OTGSC_ASVIS	      BIT(18)
 #define OTGSC_BSVIS	      BIT(19)
 #define OTGSC_BSEIS	      BIT(20)
+#define OTGSC_1MSIS	      BIT(21)
+#define OTGSC_DPIS	      BIT(22)
 #define OTGSC_IDIE	      BIT(24)
 #define OTGSC_AVVIE	      BIT(25)
 #define OTGSC_ASVIE	      BIT(26)
 #define OTGSC_BSVIE	      BIT(27)
 #define OTGSC_BSEIE	      BIT(28)
+#define OTGSC_1MSIE	      BIT(29)
+#define OTGSC_DPIE	      BIT(30)
+#define OTGSC_INT_EN_BITS	(OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \
+				| OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \
+				| OTGSC_DPIE)
+#define OTGSC_INT_STATUS_BITS	(OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS	\
+				| OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \
+				| OTGSC_DPIS)
 
 /* USBMODE */
 #define USBMODE_CM            (0x03UL <<  0)
drivers/usb/chipidea/ci.h +8 -1
index 697e369..0bd17a5 100644
@@ -130,6 +130,9 @@ struct hw_bank {
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
  * @otg: for otg support
+ * @id_event: indicates there is a id event, and handled at ci_otg_work
+ * @b_sess_valid_event: indicates there is a vbus event, and handled
+ *@ci_otg_work
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -140,6 +143,7 @@ struct ci13xxx {
 	enum ci_role			role;
 	bool				is_otg;
 	struct work_struct		work;
+	struct delayed_work		dwork;
 	struct workqueue_struct		*wq;
 
 	struct dma_pool			*qh_pool;
@@ -166,6 +170,8 @@ struct ci13xxx {
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
 	struct usb_otg      		otg;
+	bool				id_event;
+	bool				b_sess_valid_event;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -201,7 +207,6 @@ static inline void ci_role_stop(struct ci13xxx *ci)
 
 	ci->roles[role]->stop(ci);
 }
-
 /******************************************************************************
  * REGISTERS
  *****************************************************************************/
@@ -314,4 +319,6 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode);
 
 u8 hw_port_test_get(struct ci13xxx *ci);
 
+void ci_handle_vbus_change(struct ci13xxx *ci);
+
 #endif	/* __DRIVERS_USB_CHIPIDEA_CI_H */
drivers/usb/chipidea/ci13xxx_imx.c +2 -1
index 136869b..793fdba 100644
@@ -110,7 +110,8 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 	pdata->capoffset = DEF_CAPOFFSET;
 	pdata->flags = CI13XXX_REQUIRE_TRANSCEIVER |
 		       CI13XXX_PULLUP_ON_VBUS |
-		       CI13XXX_DISABLE_STREAMING;
+		       CI13XXX_DISABLE_STREAMING | 
+		       CI13XXX_REGS_SHARED;
 
 	pdata->phy_mode = of_usb_get_phy_mode(pdev->dev.of_node);
 	pdata->dr_mode = of_usb_get_dr_mode(pdev->dev.of_node);
drivers/usb/chipidea/core.c +170 -20

276 lines not on this page · raw message

drivers/usb/chipidea/host.c +6 -0
index 8e9d312..ead3158 100644
@@ -105,3 +105,9 @@ int ci_hdrc_host_init(struct ci13xxx *ci)
 
 	return 0;
 }
+
+void ci_hdrc_host_destroy(struct ci13xxx *ci)
+{
+	if (ci->role == CI_ROLE_HOST)
+		host_stop(ci);
+}
drivers/usb/chipidea/host.h +5 -1
index 761fb1f..19cc72d 100644
@@ -4,13 +4,17 @@
 #ifdef CONFIG_USB_CHIPIDEA_HOST
 
 int ci_hdrc_host_init(struct ci13xxx *ci);
-
+void ci_hdrc_host_destroy(struct ci13xxx *ci);
 #else
 
 static inline int ci_hdrc_host_init(struct ci13xxx *ci)
 {
 	return -ENXIO;
 }
+static inline void ci_hdrc_host_destroy(struct ci13xxx *ci)
+{
+
+}
 
 #endif
 
drivers/usb/chipidea/otg.c +18 -10
index 7dea3b3..2986d91 100644
@@ -10,21 +10,28 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/chipidea.h>
 
 #include "ci.h"
-#include "udc.h"
 #include "bits.h"
-#include "host.h"
-#include "debug.h"
+
+void ci_clear_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	/* Only clear request bits */
+	hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits);
+}
+
+void ci_enable_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, bits);
+}
+
+void ci_disable_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, 0);
+}
 
 static int ci_otg_set_peripheral(struct usb_otg *otg,
 		struct usb_gadget *periph)
@@ -55,6 +62,7 @@ int ci_hdrc_otg_init(struct ci13xxx *ci)
 	ci->otg.set_host = ci_otg_set_host;
 	if (!IS_ERR_OR_NULL(ci->transceiver))
 		ci->transceiver->otg = &ci->otg;
+	ci_enable_otg_interrupt(ci, OTGSC_IDIE);
 
 	return 0;
 }
drivers/usb/chipidea/otg.h +3 -0
index b4c6b3e..fa30428 100644
@@ -2,5 +2,8 @@
 #define __DRIVERS_USB_CHIPIDEA_OTG_H
 
 int ci_hdrc_otg_init(struct ci13xxx *ci);
+void ci_clear_otg_interrupt(struct ci13xxx *ci, u32 bits);
+void ci_enable_otg_interrupt(struct ci13xxx *ci, u32 bits);
+void ci_disable_otg_interrupt(struct ci13xxx *ci, u32 bits);
 
 #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
drivers/usb/chipidea/udc.c +30 -9
index d214448..e82dae4 100644
@@ -31,6 +31,7 @@
 
 #include "ci.h"
 #include "udc.h"
+#include "otg.h"
 #include "bits.h"
 #include "debug.h"
 
@@ -1371,6 +1372,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 			pm_runtime_get_sync(&_gadget->dev);
 			hw_device_reset(ci, USBMODE_CM_DC);
 			hw_device_state(ci, ci->ep0out->qh.dma);
+			dev_dbg(ci->dev, "Connected to host\n");
 		} else {
 			hw_device_state(ci, 0);
 			if (ci->platdata->notify_event)
@@ -1378,6 +1380,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 				CI13XXX_CONTROLLER_STOPPED_EVENT);
 			_gadget_stop_activity(&ci->gadget);
 			pm_runtime_put_sync(&_gadget->dev);
+			dev_dbg(ci->dev, "Disconnected from host\n");
 		}
 	}
 
@@ -1741,7 +1744,12 @@ static int udc_start(struct ci13xxx *ci)
 	if (!IS_ERR_OR_NULL(ci->transceiver)) {
 		retval = otg_set_peripheral(ci->transceiver->otg,
 						&ci->gadget);
-		if (retval)
+		/* 
+		 * If we implement all USB functions using chipidea drivers,
+		 * it doesn't need to call above API, meanwhile, if we only
+		 * use gadget function, calling above API is useless.
+		 */
+		if (retval && retval != -ENOTSUPP)
 			goto remove_dbg;
 	}
 
@@ -1778,12 +1786,27 @@ free_qh_pool:
 	return retval;
 }
 
+static int udc_id_switch_for_device(struct ci13xxx *ci)
+{
+	ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+	ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+
+	return 0;
+}
+
+static void udc_id_switch_for_host(struct ci13xxx *ci)
+{
+	/* host doesn't care B_SESSION_VALID event */
+	ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+	ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+}
+
 /**
- * udc_remove: parent remove must call this to remove UDC
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
  *
  * No interrupts active, the IRQ has been released
  */
-static void udc_stop(struct ci13xxx *ci)
+void ci_hdrc_gadget_destroy(struct ci13xxx *ci)
 {
 	if (ci == NULL)
 		return;
@@ -1802,15 +1825,13 @@ static void udc_stop(struct ci13xxx *ci)
 	}
 	dbg_remove_files(&ci->gadget.dev);
 	device_unregister(&ci->gadget.dev);
-	/* my kobject is dynamic, I swear! */
-	memset(&ci->gadget, 0, sizeof(ci->gadget));
 }
 
 /**
  * ci_hdrc_gadget_init - initialize device related bits
  * ci: the controller
  *
- * This function enables the gadget role, if the device is "device capable".
+ * This function initializes gadget, if the device is "device capable".
  */
 int ci_hdrc_gadget_init(struct ci13xxx *ci)
 {
@@ -1823,11 +1844,11 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
 	if (!rdrv)
 		return -ENOMEM;
 
-	rdrv->start	= udc_start;
-	rdrv->stop	= udc_stop;
+	rdrv->start	= udc_id_switch_for_device;
+	rdrv->stop	= udc_id_switch_for_host;
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
 	ci->roles[CI_ROLE_GADGET] = rdrv;
 
-	return 0;
+	return udc_start(ci);
 }
drivers/usb/chipidea/udc.h +4 -0
index 4ff2384..6553e4d 100644
@@ -80,6 +80,7 @@ struct ci13xxx_req {
 #ifdef CONFIG_USB_CHIPIDEA_UDC
 
 int ci_hdrc_gadget_init(struct ci13xxx *ci);
+void ci_hdrc_gadget_destroy(struct ci13xxx *ci);
 
 #else
 
@@ -87,7 +88,10 @@ static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
 {
 	return -ENXIO;
 }
+static inline void ci_hdrc_gadget_destroy(struct ci13xxx *ci)
+{
 
+}
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
Signature · 1 line
1.7.0.4
author
#4 lore raw

PATCH v9 4/9 usb: chipidea: udc: add pullup/pulldown dp at hw_device_state

In reply to Peter Chen

- During the connect/disconnect host, we need to pullup and pulldown dp
- Make sure the dp is not pullup until the vbus is on when flag CI13XXX_PULLUP_ON_VBUS is set
- Using hw_device_state when set run/stop bit

---
 drivers/usb/chipidea/udc.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)
drivers/usb/chipidea/udc.c +8 -2
index e82dae4..597ae64 100644
@@ -91,8 +91,10 @@ static int hw_device_state(struct ci13xxx *ci, u32 dma)
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_write(ci, OP_USBINTR, ~0,
 			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
 	} else {
 		hw_write(ci, OP_USBINTR, ~0, 0);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
 	}
 	return 0;
 }
@@ -1424,10 +1426,14 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
 {
 	struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
 
+	if ((ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) &&
+			!ci->vbus_active)
+		return -ENOTSUPP;
+
 	if (is_on)
-		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+		hw_device_state(ci, ci->ep0out->qh.dma);
 	else
-		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+		hw_device_state(ci, 0);
 
 	return 0;
 }
Signature · 1 line
1.7.0.4
author
#5 lore raw

PATCH v9 5/9 usb: chipidea: udc: retire the flag CI13_PULLUP_ON_VBUS

In reply to Peter Chen

(change CI13XXX to CI13 to avoid junk email check)
Now, we have handled vbus session in core driver when the vbus interrupt occurs, so our pullup operations are all according to vbus.
Of cource, the software can still call .pullup when device connects to host if it wants to connect/disconnect with host.

---
 drivers/usb/chipidea/ci13xxx_imx.c |    1 -
 drivers/usb/chipidea/ci13xxx_msm.c |    1 -
 drivers/usb/chipidea/udc.c         |   23 ++++++++---------------
 include/linux/usb/chipidea.h       |    1 -
 4 files changed, 8 insertions(+), 18 deletions(-)
drivers/usb/chipidea/ci13xxx_imx.c +0 -1
index 793fdba..3ed119e 100644
@@ -109,7 +109,6 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 	pdata->name = "ci13xxx_imx";
 	pdata->capoffset = DEF_CAPOFFSET;
 	pdata->flags = CI13XXX_REQUIRE_TRANSCEIVER |
-		       CI13XXX_PULLUP_ON_VBUS |
 		       CI13XXX_DISABLE_STREAMING | 
 		       CI13XXX_REGS_SHARED;
 
drivers/usb/chipidea/ci13xxx_msm.c +0 -1
index 7d16681..5755ee8 100644
@@ -49,7 +49,6 @@ static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
 	.name			= "ci13xxx_msm",
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
-				  CI13XXX_PULLUP_ON_VBUS |
 				  CI13XXX_DISABLE_STREAMING,
 
 	.notify_event		= ci13xxx_msm_notify_event,
drivers/usb/chipidea/udc.c +8 -15
index 597ae64..b57b735 100644
@@ -1360,9 +1360,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 	unsigned long flags;
 	int gadget_ready = 0;
 
-	if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS))
-		return -EOPNOTSUPP;
-
 	spin_lock_irqsave(&ci->lock, flags);
 	ci->vbus_active = is_active;
 	if (ci->driver)
@@ -1426,8 +1423,7 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
 {
 	struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
 
-	if ((ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) &&
-			!ci->vbus_active)
+	if (!ci->vbus_active)
 		return -ENOTSUPP;
 
 	if (is_on)
@@ -1551,14 +1547,12 @@ static int ci13xxx_start(struct usb_gadget *gadget,
 
 	ci->driver = driver;
 	pm_runtime_get_sync(&ci->gadget.dev);
-	if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
-		if (ci->vbus_active) {
-			if (ci->platdata->flags & CI13XXX_REGS_SHARED)
-				hw_device_reset(ci, USBMODE_CM_DC);
-		} else {
-			pm_runtime_put_sync(&ci->gadget.dev);
-			goto done;
-		}
+	if (ci->vbus_active) {
+		if (ci->platdata->flags & CI13XXX_REGS_SHARED)
+			hw_device_reset(ci, USBMODE_CM_DC);
+	} else {
+		pm_runtime_put_sync(&ci->gadget.dev);
+		goto done;
 	}
 
 	retval = hw_device_state(ci, ci->ep0out->qh.dma);
@@ -1581,8 +1575,7 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
 
 	spin_lock_irqsave(&ci->lock, flags);
 
-	if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) ||
-			ci->vbus_active) {
+	if (ci->vbus_active) {
 		hw_device_state(ci, 0);
 		if (ci->platdata->notify_event)
 			ci->platdata->notify_event(ci,
include/linux/usb/chipidea.h +0 -1
index b314647..d543e4a 100644
@@ -18,7 +18,6 @@ struct ci13xxx_platform_data {
 	unsigned long	 flags;
 #define CI13XXX_REGS_SHARED		BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
-#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 	enum usb_dr_mode	dr_mode;
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
Signature · 1 line
1.7.0.4
author
#6 lore raw

PATCH v9 6/9 usb: chipidea: imx: add internal vbus regulator control

In reply to Peter Chen

- For host, the vbus should always be on.
- For otg, the vbus is off defaultly, the vbus needs to be turned on/off when usb role switches.

---
 drivers/usb/chipidea/ci.h          |    2 +
 drivers/usb/chipidea/ci13xxx_imx.c |   76 ++++++++++++++++++++++++++++--------
 2 files changed, 61 insertions(+), 17 deletions(-)
drivers/usb/chipidea/ci.h +2 -0
index 0bd17a5..5663092 100644
@@ -133,6 +133,7 @@ struct hw_bank {
  * @id_event: indicates there is a id event, and handled at ci_otg_work
  * @b_sess_valid_event: indicates there is a vbus event, and handled
  * at ci_otg_work
+ * @reg_vbus: used to control internal vbus regulator
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -172,6 +173,7 @@ struct ci13xxx {
 	struct usb_otg      		otg;
 	bool				id_event;
 	bool				b_sess_valid_event;
+	struct regulator		*reg_vbus;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
drivers/usb/chipidea/ci13xxx_imx.c +59 -17

124 lines not on this page · raw message

Signature · 1 line
1.7.0.4
author
#7 lore raw

PATCH v9 7/9 usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget

In reply to Peter Chen

When we rmmod gadget, the ci->driver needs to be cleared. Otherwise, we plug in usb cable again, the driver will consider gadget is there, in fact, it is removed.

Besides, consolidate the calling of ci->driver->disconnect, when we do rmmod gadget, the gadget's disconnect should be called from udc core.

Below is the oops this patch fixes.

root at freescale ~$ ci_hdrc ci_hdrc.0: Connected to host

Unable to handle kernel paging request at virtual address 7f01171c
pgd = 80004000
[7f01171c] *pgd=4fa1e811, *pte=00000000, *ppte=00000000
Internal error: Oops: 7 [#1] SMP ARM
Modules linked in: f_acm libcomposite u_serial [last unloaded: g_serial]
CPU: 0    Not tainted  (3.8.0-rc5+ #221)
	PC is at _gadget_stop_activity+0xbc/0x128
	LR is at ep_fifo_flush+0x68/0xa0
	pc : [<803634cc>]    lr : [<80363938>]    psr: 20000193
	sp : 806c7dc8  ip : 00000000  fp : 806c7de4
	r10: 00000000  r9 : 80710ea4  r8 : 00000000
	r7 : bf834094  r6 : bf834098  r5 : bf834010  r4 : bf8340a0
	r3 : 7f011708  r2 : 01940194  r1 : a0000193  r0 : bf834014
	Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
	Control: 10c53c7d  Table: 4f06404a  DAC: 00000017
	Process swapper/0 (pid: 0, stack limit = 0x806c6238)
	Stack: (0x806c7dc8 to 0x806c8000)
	7dc0:                   bf834010 bf809950 bf834010 0000004b 806c7e44 806c7de8
	7de0: 80365400 8036341c 0000ec1c 00000000 0000ec1c 00000040 fff5ede0 bf834014
	7e00: 000a1220 00000000 0000002e ffffd958 806c7e3c 806c7e20 8004e870 bf834010
	7e20: bf809950 0000004b 0000004b 00000000 80710ea4 00000000 806c7e5c 806c7e48
	7e40: 80362888 80365154 bfb35180 bf809950 806c7e9c 806c7e60 8008111c 803627f4
	7e60: 00989680 00000000 bf809900 bf809964 812df8c0 bf809900 bf809950 806c3f2c
	7e80: 0000004b 00000000 412fc09a 00000000 806c7eb4 806c7ea0 80081368 800810b8
	7ea0: bf809900 bf809950 806c7ecc 806c7eb8 800843c8 8008130c 0000004b 806cf748
	7ec0: 806c7ee4 806c7ed0 80081088 8008432c 806c6000 806cf748 806c7f0c 806c7ee8
	7ee0: 8000fa44 8008105c f400010c 806ce974 806c7f30 f4000110 806d29e8 412fc09a
	7f00: 806c7f2c 806c7f10 80008584 8000f9f4 8000fbd0 60000013 ffffffff 806c7f64
	7f20: 806c7f84 806c7f30 8000eac0 80008554 00000000 00000000 0000000f 8001aea0
	7f40: 806c6000 80712a48 804f0040 00000000 806d29e8 412fc09a 00000000 806c7f84
	7f60: 806c7f88 806c7f78 8000fbcc 8000fbd0 60000013 ffffffff 806c7fac 806c7f88
	7f80: 8001015c 8000fb9c 806cf5b0 80712980 806a4528 8fffffff 1000406a 412fc09a
	7fa0: 806c7fbc 806c7fb0 804e5334 800100ac 806c7ff4 806c7fc0 80668940 804e52d4
	7fc0: ffffffff ffffffff 806684bc 00000000 00000000 806a4528 10c53c7d 806ce94c
	7fe0: 806a4524 806d29dc 00000000 806c7ff8 10008078 806686b0 00000000 00000000
	Backtrace:
	[<80363410>] (_gadget_stop_activity+0x0/0x128) from [<80365400>] (udc_irq+0x2b8/0xf38)
	 r7:0000004b r6:bf834010 r5:bf809950 r4:bf834010
	 [<80365148>] (udc_irq+0x0/0xf38) from [<80362888>] (ci_irq+0xa0/0xf4)
	[<803627e8>] (ci_irq+0x0/0xf4) from [<8008111c>] (handle_irq_event_percpu+0x70/0x254)
	 r5:bf809950 r4:bfb35180
	 [<800810ac>] (handle_irq_event_percpu+0x0/0x254) from [<80081368>] (handle_irq_event+0x68/0x88)
	[<80081300>] (handle_irq_event+0x0/0x88) from [<800843c8>] (handle_fasteoi_irq+0xa8/0x178)
	 r5:bf809950 r4:bf809900
	 [<80084320>] (handle_fasteoi_irq+0x0/0x178) from [<80081088>] (generic_handle_irq+0x38/0x40)
	 r5:806cf748 r4:0000004b
	 [<80081050>] (generic_handle_irq+0x0/0x40) from [<8000fa44>] (handle_IRQ+0x5c/0xbc)
	 r5:806cf748 r4:806c6000
	 [<8000f9e8>] (handle_IRQ+0x0/0xbc) from [<80008584>] (gic_handle_irq+0x3c/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:806c7f30 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0x806c7f30 to 0x806c7f78)
	7f20:                                     00000000 00000000 0000000f 8001aea0
	7f40: 806c6000 80712a48 804f0040 00000000 806d29e8 412fc09a 00000000 806c7f84
	7f60: 806c7f88 806c7f78 8000fbcc 8000fbd0 60000013 ffffffff
	 r7:806c7f64 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e5334>] (rest_init+0x6c/0x84)
	 r9:412fc09a r8:1000406a r7:8fffffff r6:806a4528 r5:80712980
	 r4:806cf5b0
	 [<804e52c8>] (rest_init+0x0/0x84) from [<80668940>] (start_kernel+0x29c/0x2ec)
	[<806686a4>] (start_kernel+0x0/0x2ec) from [<10008078>] (0x10008078)
	Code: e12fff33 e5953200 e3530000 0a000002 (e5933014)
	---[ end trace aade28ad434062bd ]---
	Kernel panic - not syncing: 0xbf8bdfa8)
	df60: 00000000 00000000 0000000f 8001aea0 bf8bc000 80712a48 804f0040 00000000
	df80: 806d29e8 412fc09a 00000000 bf8bdfb4 bf8bdfb8 bf8bdfa8 8000fbcc 8000fbd0
	dfa0: 60000013 ffffffff
	 r7:bf8bdf94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000002
	 r4:806e2008
	 [<804e7810>] (secondary_start_kernel+0x0/0x148) from [<104e7148>] (0x104e7148)
	 r5:0000001f r4:4f8a806a
	 CPU3: stopping
	 Backtrace:
	 [<800132e8>] (dump_backtrace+0x0/0x114) from [<804ea684>] (dump_stack+0x20/0x24)
	 r7:00000000 r6:806c3f2c r5:806cf748 r4:80712d18
	 [<804ea664>] (dump_stack+0x0/0x24) from [<80014adc>] (handle_IPI+0x140/0x18c)
	[<8001499c>] (handle_IPI+0x0/0x18c) from [<800085b0>] (gic_handle_irq+0x68/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bff60 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0xbf8bff60 to 0xbf8bffa8)
	ff60: 00000000 00000000 0000000f 8001aea0 bf8be000 80712a48 804f0040 00000000
	ff80: 806d29e8 412fc09a 00000000 bf8bffb4 bf8bffb8 bf8bffa8 8000fbcc 8000fbd0
	ffa0: 60000013 ffffffff
	 r7:bf8bff94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000003
	 r4:806e2008
	 [<804e7810>] (secondary_start_kernel+0x0/0x148) from [<104e7148>] (0x104e7148)
	 r5:0000001f r4:4f8a806a
	 CPU1: stopping
	 Backtrace:
	 [<800132e8>] (dump_backtrace+0x0/0x114) from [<804ea684>] (dump_stack+0x20/0x24)
	 r7:00000000 r6:806c3f2c r5:806cf748 r4:80712d18
	 [<804ea664>] (dump_stack+0x0/0x24) from [<80014adc>] (handle_IPI+0x140/0x18c)
	[<8001499c>] (handle_IPI+0x0/0x18c) from [<800085b0>] (gic_handle_irq+0x68/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bbf60 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0xbf8bbf60 to 0xbf8bbfa8)
	bf60: 00000000 00000000 0000000f 8001aea0 bf8ba000 80712a48 804f0040 00000000
	bf80: 806d29e8 412fc09a 00000000 bf8bbfb4 bf8bbfb8 bf8bbfa8 8000fbcc 8000fbd0
	bfa0: 60000013 ffffffff
	 r7:bf8bbf94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000001
	 r4:806e2008
---
 drivers/usb/chipidea/udc.c |   13 +++++++++----
 1 files changed, 9 insertions(+), 4 deletions(-)
drivers/usb/chipidea/udc.c +9 -4
index b57b735..e355914 100644
@@ -579,9 +579,6 @@ static int _gadget_stop_activity(struct usb_gadget *gadget)
 	usb_ep_fifo_flush(&ci->ep0out->ep);
 	usb_ep_fifo_flush(&ci->ep0in->ep);
 
-	if (ci->driver)
-		ci->driver->disconnect(gadget);
-
 	/* make sure to disable all endpoints */
 	gadget_for_each_ep(ep, gadget) {
 		usb_ep_disable(ep);
@@ -612,6 +609,11 @@ __acquires(ci->lock)
 
 	dbg_event(0xFF, "BUS RST", 0);
 
+	if (ci->gadget.speed != USB_SPEED_UNKNOWN) {
+		if (ci->driver)
+			ci->driver->disconnect(&ci->gadget);
+	}
+
 	spin_unlock(&ci->lock);
 	retval = _gadget_stop_activity(&ci->gadget);
 	if (retval)
@@ -1373,6 +1375,8 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 			hw_device_state(ci, ci->ep0out->qh.dma);
 			dev_dbg(ci->dev, "Connected to host\n");
 		} else {
+			if (ci->driver)
+				ci->driver->disconnect(&ci->gadget);
 			hw_device_state(ci, 0);
 			if (ci->platdata->notify_event)
 				ci->platdata->notify_event(ci,
@@ -1580,13 +1584,14 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
 		if (ci->platdata->notify_event)
 			ci->platdata->notify_event(ci,
 			CI13XXX_CONTROLLER_STOPPED_EVENT);
-		ci->driver = NULL;
 		spin_unlock_irqrestore(&ci->lock, flags);
 		_gadget_stop_activity(&ci->gadget);
 		spin_lock_irqsave(&ci->lock, flags);
 		pm_runtime_put(&ci->gadget.dev);
 	}
 
+	ci->driver = NULL;
+
 	spin_unlock_irqrestore(&ci->lock, flags);
 
 	return 0;
Signature · 1 line
1.7.0.4
author
#8 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

In reply to Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

---
 drivers/usb/chipidea/core.c  |    2 ++
 include/linux/usb/chipidea.h |    1 +
 2 files changed, 3 insertions(+), 0 deletions(-)
drivers/usb/chipidea/core.c +2 -0
index 6cc6069..45fa227 100644
@@ -689,6 +689,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	/* Defer some operations */
 	queue_delayed_work(ci->wq, &ci->dwork, msecs_to_jiffies(200));
 
+	ci->platdata->probe_retval = ret;
 	return ret;
 
 free_irq:
@@ -704,6 +705,7 @@ rm_wq:
 	flush_workqueue(ci->wq);
 	destroy_workqueue(ci->wq);
 
+	ci->platdata->probe_retval = ret;
 	return ret;
 }
 
include/linux/usb/chipidea.h +1 -0
index d543e4a..8f61e97 100644
@@ -23,6 +23,7 @@ struct ci13xxx_platform_data {
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
 #define CI13XXX_CONTROLLER_STOPPED_EVENT	1
 	void	(*notify_event) (struct ci13xxx *ci, unsigned event);
+	int probe_retval; /* tell platform layer ci core probe's result */
 };
 
 /* Default offset of capability registers */
Signature · 1 line
1.7.0.4
#9 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 11 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130226/b1d050bd/attachment.sig>
author
#10 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 11 lines · Felipe Balbi
Quoted 10 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

Quoted 5 lines
Quoted 1 line

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?
At dwc3-exynos.c, it has code "exynos->dwc3 = dwc3;", so the exynos
platform code may will use struct dwc3 in future. Besides, if the dwc3 core driver's probe fails, the exynos platform code will not know it, the usb clk will be on on the usb can't be used.

If you suggest like above, we may need to add lots of notify function at core driver as there are many platform specific things, eg, special init/ shutdown, suspend/resume, board layer gpio setting for vbus control (used at id switch), probe fail, etc.

Signature · 2 lines
Best Regards,
Peter Chen
#11 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Hi,

Quoted 14 lines · Peter Chen
Quoted 13 lines · Felipe Balbi
Quoted 11 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

Quoted 7 lines
Quoted 3 lines

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

Quoted 2 lines

At dwc3-exynos.c, it has code "exynos->dwc3 = dwc3;", so the exynos
platform code may will use struct dwc3 in future. Besides, if the dwc3

nonsense. That's a structure platform_device which was created by the glue, it has nothing to do with struct dwc3. struct platform_device belongs to the glue, but there's an easy way to prevent that by using device_for_each_child() on your ->remove() method.

Quoted 2 lines

core driver's probe fails, the exynos platform code will not know it, the usb clk will be on on the usb can't be used.

so ? If the clock belongs to the glue, then the glue should enable it in order to have access to its registers; if the clock belongs to the dwc3 core, then the glue is buggy; if the clock is shared between glue and dwc3 core, then that's another bug, since nobody added clk handling code to dwc3.

Quoted 1 line

If you suggest like above, we may need to add lots of notify function at

wrong. There's no need for any notification at all. A driver failing to probe is just normal life. DWC3 is releasing all resources it allocated, but the glue still needs the clock, then that's just the way it is.

There are many error messages which will tell the user that e.g. dwc3 failed to probe and user will just try again. If clocks are left enabled, that's a bug in either core driver or glue layer which needs fixing.

Quoted 2 lines

core driver as there are many platform specific things, eg, special init/ shutdown, suspend/resume, board layer gpio setting for vbus control (used

gpio handling should be done at board-file, that's a bug. You need to add a fixed regulator which is toggled by a GPIO.

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130227/a5bfa1e1/attachment.sig>
author
#12 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 27 lines · Felipe Balbi

Hi,

Quoted 14 lines · Peter Chen
Quoted 13 lines · Felipe Balbi
Quoted 11 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

Quoted 7 lines
Quoted 3 lines

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

Quoted 7 lines
Quoted 2 lines

At dwc3-exynos.c, it has code "exynos->dwc3 = dwc3;", so the exynos
platform code may will use struct dwc3 in future. Besides, if the dwc3

nonsense. That's a structure platform_device which was created by the glue, it has nothing to do with struct dwc3. struct platform_device belongs to the glue, but there's an easy way to prevent that by using device_for_each_child() on your ->remove() method.

Sorry, I just thought it may use platform_get_drvdata(exynos->dwc3) to get core data if exynos has special suspend/resume routine, and need to visit dwc3 register.

Quoted 4 lines

wrong. There's no need for any notification at all. A driver failing to probe is just normal life. DWC3 is releasing all resources it allocated, but the glue still needs the clock, then that's just the way it is.

Here, we just talk the controller core clk, if the core fails to probe, any meaningful for platform layer still alive?

Quoted 6 lines

There are many error messages which will tell the user that e.g. dwc3 failed to probe and user will just try again. If clocks are left enabled, that's a bug in either core driver or glue layer which needs fixing.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 5 lines
Quoted 2 lines

core driver as there are many platform specific things, eg, special init/ shutdown, suspend/resume, board layer gpio setting for vbus control (used

gpio handling should be done at board-file, that's a bug. You need to add a fixed regulator which is toggled by a GPIO.

I think I need to move vbus regulator from platform code to core code as we have struct otg at core data, and vbus operation is common operation.

Quoted 3 lines
Signature · 2 lines
-- 
balbi
Signature · 2 lines
Best Regards,
Peter Chen
#13 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Hi,

Quoted 31 lines · Peter Chen
Quoted 30 lines · Felipe Balbi

Hi,

Quoted 14 lines · Peter Chen
Quoted 13 lines · Felipe Balbi
Quoted 11 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

Quoted 7 lines
Quoted 3 lines

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

Quoted 2 lines

At dwc3-exynos.c, it has code "exynos->dwc3 = dwc3;", so the exynos
platform code may will use struct dwc3 in future. Besides, if the dwc3

Quoted 8 lines
Quoted 4 lines

nonsense. That's a structure platform_device which was created by the glue, it has nothing to do with struct dwc3. struct platform_device belongs to the glue, but there's an easy way to prevent that by using device_for_each_child() on your ->remove() method.

Sorry, I just thought it may use platform_get_drvdata(exynos->dwc3) to get core data if exynos has special suspend/resume routine, and need to visit dwc3 register.

that would be utterly wrong and has caused many issues before (see MUSB). Glue shouldn't know anything about the core IP.

Quoted 8 lines
Quoted 5 lines

There are many error messages which will tell the user that e.g. dwc3 failed to probe and user will just try again. If clocks are left enabled, that's a bug in either core driver or glue layer which needs fixing.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Quoted 4 lines
Quoted 4 lines
Quoted 2 lines

core driver as there are many platform specific things, eg, special init/ shutdown, suspend/resume, board layer gpio setting for vbus control (used

gpio handling should be done at board-file, that's a bug. You need to

I mean "shouldn't"

Quoted 4 lines
Quoted 1 line

add a fixed regulator which is toggled by a GPIO.

I think I need to move vbus regulator from platform code to core code as we have struct otg at core data, and vbus operation is common operation.

right

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130228/45becb7a/attachment.sig>
author
#14 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 32 lines · Felipe Balbi

Hi,

Quoted 29 lines · Peter Chen
Quoted 27 lines · Felipe Balbi

Hi,

Quoted 14 lines · Peter Chen
Quoted 13 lines · Felipe Balbi
Quoted 11 lines · Peter Chen

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

Quoted 7 lines
Quoted 3 lines

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

Quoted 7 lines
Quoted 2 lines

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Signature · 2 lines
Best Regards,
Peter Chen
#15 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Hi,

Quoted 26 lines · Peter Chen
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

Just because dwc3/core.c doesn't know about clocks, it doesn't mean it's correct to hack it into the glue layer if that doesn't need the clock.

Now that we know that's a bug, who's going to send me tested patches to teach dwc3/core.c about struct clk in a way that doesn't break PCIe, nor OMAP5 ?

cheers

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130228/fd6a9b2f/attachment.sig>
#16 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 48 lines · Felipe Balbi

Hi,

Quoted 26 lines · Peter Chen
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

Quoted 8 lines

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers? Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

It seems totally unreasonable and messy to add notion of clocks to drivers just because some platforms can't get their PM right.

Quoted 6 lines

Just because dwc3/core.c doesn't know about clocks, it doesn't mean it's correct to hack it into the glue layer if that doesn't need the clock.

Now that we know that's a bug, who's going to send me tested patches to teach dwc3/core.c about struct clk in a way that doesn't break PCIe, nor OMAP5 ?

So are you sure that's what you want?

Regards,
--
Alex

author
#17 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 59 lines · Alexander Shishkin
Quoted 48 lines · Felipe Balbi

Hi,

Quoted 26 lines · Peter Chen
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

Quoted 8 lines

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

Quoted 6 lines

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers? Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

I agree, clock stuffs should be handled at platform layer. For this corner case (core probe fails), if all of us
agree with clock needs to be closed, we may need add some special handling.
For runtime pm enabled, it is easy. we can set runtime pm active at fail path, as platform is parent of core, it will call platform's runtime suspend to do low power handling.
For runtime pm disabled, we may had to add some ugly things, like notify core probe fail, and platform layer needs to handle this failed notify.

Quoted 17 lines

It seems totally unreasonable and messy to add notion of clocks to drivers just because some platforms can't get their PM right.

Quoted 6 lines

Just because dwc3/core.c doesn't know about clocks, it doesn't mean it's correct to hack it into the glue layer if that doesn't need the clock.

Now that we know that's a bug, who's going to send me tested patches to teach dwc3/core.c about struct clk in a way that doesn't break PCIe, nor OMAP5 ?

So are you sure that's what you want?

Regards,
--
Alex

Signature · 2 lines
Best Regards,
Peter Chen
#18 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Hi,

Quoted 61 lines · Peter Chen
Quoted 54 lines
Quoted 45 lines
Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

Quoted 8 lines

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

Quoted 6 lines

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers? Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

Quoted 7 lines

I agree, clock stuffs should be handled at platform layer. For this corner case (core probe fails), if all of us agree with clock needs to be closed, we may need add some special handling.
For runtime pm enabled, it is easy. we can set runtime pm active at fail path, as platform is parent of core, it will call platform's runtime suspend to do low power handling.

if core probe fails, we should still call pm_runtime_put_sync() and pm_runtime_disable() and that should be enough to trigger your ->pm_domain->runtime_suspend() which can be used to turn off unnecessary clocks.

Quoted 3 lines

For runtime pm disabled, we may had to add some ugly things, like notify core probe fail, and platform layer needs to handle this failed notify.

Please stop talking about about "notify core probe fail" that will never happen. Not today, not ever. Forget that idea.

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130228/d2a08220/attachment.sig>
author
#19 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 10 lines · Felipe Balbi

Hi,

Quoted 3 lines · Peter Chen

For runtime pm disabled, we may had to add some ugly things, like notify core probe fail, and platform layer needs to handle this failed notify.

Please stop talking about about "notify core probe fail" that will never happen. Not today, not ever. Forget that idea.

Of course, it is ugly way, I just thought if it will affect power, eg dvfs, bus freq if the usb clock is on. Maybe the user will find USB core init fails case causes runtime power rise, and fix the core init fail bug.

Quoted 3 lines
Signature · 2 lines
-- 
balbi
Signature · 2 lines
Best Regards,
Peter Chen
#20 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 9 lines · Peter Chen
Quoted 8 lines · Felipe Balbi

Hi,

Quoted 3 lines · Peter Chen

For runtime pm disabled, we may had to add some ugly things, like notify core probe fail, and platform layer needs to handle this failed notify.

Quoted 6 lines
Quoted 2 lines

Please stop talking about about "notify core probe fail" that will never happen. Not today, not ever. Forget that idea.

Of course, it is ugly way, I just thought if it will affect power, eg dvfs, bus freq if the usb clock is on. Maybe the user will find USB core init fails case causes runtime power rise, and fix the core init fail bug.

right, we need to fix the bug, but hiding it under some obscure way of passing return values back to glue layer isn't correct. We should fix the real issue, always, instead of hacking around buggy code.

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130301/5a467e76/attachment.sig>
#21 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

In reply to Alexander Shishkin

Hi,

Quoted 50 lines · Alexander Shishkin
Quoted 50 lines
Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Quoted 7 lines
Quoted 3 lines

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers?

that's what OMAP does.

Quoted 3 lines

Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

it might seem that way, but it's not that obvious ;-) Some platforms have a single clock, some will split interface and functional clocks, in some cases, you have extra optional clocks which might be needed during certain use cases or to implement erratas at locations that only driver knows.

It's a tradeoff, of course.

Quoted 2 lines

It seems totally unreasonable and messy to add notion of clocks to drivers just because some platforms can't get their PM right.

it's not that simple ;-)

Quoted 8 lines
Quoted 6 lines

Just because dwc3/core.c doesn't know about clocks, it doesn't mean it's correct to hack it into the glue layer if that doesn't need the clock.

Now that we know that's a bug, who's going to send me tested patches to teach dwc3/core.c about struct clk in a way that doesn't break PCIe, nor OMAP5 ?

So are you sure that's what you want?

Well, how quickly can Exynos be changed to handle clocks without driver's knowledge ?

Also, I'm a lot more 'at ease' when I see the driver explicitly handling all of its resources. The whole "let's hide XYZ from driver because driver authors never get things right" always causes problems. Specially in the ARM land where there's no standardization at all.

When you think solely about x86 platforms, where you have ACPI properly standardized and anyone wanting to build an x86 processor needs to implement ACPI, it's a lot easier :-)

I'm sure the new "get default pinctrl state before driver probe()" will cause issues down the road (think silicon erratas, shared balls on the BGA packaging).

So, if they can hide clock handling from driver easily, good, let's do just that. Otherwise, meanwhile we need to cope with the extra power consumption that error condition would cause.

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130228/0b60a4ad/attachment.sig>
#22 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Quoted 67 lines · Felipe Balbi

Hi,

Quoted 50 lines · Alexander Shishkin
Quoted 50 lines
Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Quoted 7 lines
Quoted 3 lines

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers?

that's what OMAP does.

Quoted 3 lines

Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

Quoted 5 lines

it might seem that way, but it's not that obvious ;-) Some platforms have a single clock, some will split interface and functional clocks, in some cases, you have extra optional clocks which might be needed during certain use cases or to implement erratas at locations that only driver knows.

Then drivers could use platform fixup callbacks. Curious how many drivers out there do proper handling of interface vs functional clocks. Something tells me that the common pattern will be "enable all clocks with lots of line of boilerplate copied from that other driver" in probe() and "disable all" in remove().

Quoted 10 lines

It's a tradeoff, of course.

Quoted 2 lines

It seems totally unreasonable and messy to add notion of clocks to drivers just because some platforms can't get their PM right.

it's not that simple ;-)

Quoted 3 lines
Quoted 3 lines

Just because dwc3/core.c doesn't know about clocks, it doesn't mean it's correct to hack it into the glue layer if that doesn't need the clock.

Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

Now that we know that's a bug, who's going to send me tested patches to teach dwc3/core.c about struct clk in a way that doesn't break PCIe, nor OMAP5 ?

So are you sure that's what you want?

Well, how quickly can Exynos be changed to handle clocks without driver's knowledge ?

Motivation for the platforms to change should come from the general direction of linux kernel maintainers, in order for the change to happen. :)

But yes, for the time being, you're right, we'll probably have to just cope with it.

Quoted 4 lines

Also, I'm a lot more 'at ease' when I see the driver explicitly handling all of its resources. The whole "let's hide XYZ from driver because driver authors never get things right" always causes problems. Specially in the ARM land where there's no standardization at all.

I think it's going to be like that as long as developers are working in "hack it and ship it and let somebody else figure out APIs" routine. I understand that some drivers will always need to call into clock framework directly, but other should have an option not to if their operation doesn't depend on it.

Regards,
--
Alex

#23 lore raw

PATCH v9 8/9 usb: chipidea: tell platform layer the ci core probe's result

Hi,

Quoted 64 lines · Alexander Shishkin
Quoted 64 lines
Quoted 50 lines
Quoted 50 lines
Quoted 26 lines
Quoted 26 lines
Quoted 25 lines
Quoted 16 lines
Quoted 16 lines
Quoted 15 lines
Quoted 11 lines

If the probe fails, the ci13xxx_add_device will not return error, (bus_probe_device doesn't has return value)
therefore, the platform layer can't know whether core's probe is successful or not, if platform layer goes on using core's struct which is initialized at core's probe, the error will occur.

This error is showed when I only compile gadget, the host-only controller reports "no supported roles", and fails probe, but imx platform code doesn't know it, and goes on using core's private data.

this just tells you that platform code shouldn't be using the driver directly. passing probe_retval via platform_data is an abomination, fix the real problem instead, whatever it is.

Quoted 6 lines
Quoted 3 lines

So you suggest the platform glue layer should not use core driver's data directly, eg, for your dwc3, the platform glue layer should not use struct dwc3 *dwc directly?

yes, and it doesn't. Ever.

If the dwc3 core fails to probe, but controller core clk is still on, is it a valid case?

Quoted 8 lines
Quoted 4 lines

of course not, but then again, core clk shouldn't be handled by glue layer. You need to figure out who owns the clock, if it feeds DWC3 why would you clk_get() and clk_prepare_enable() from glue ? Makes no sense.

Sorry? I can't find clk_prepare_enable at dwc3/core.c, but at dwc3 core, it try to access register at probe, unless platform layer open the clock, how can the core visit the core register.

Is it really this difficult to figure out ? Fair enough, below are all the details:

To understand the reason why dwc3/core.c doesn't know about struct clk, you need to consider where the driver was originally written; it was written on an OMAP platform (actually first on a virtual model OMAP - somewhat like QEMU -, than on a PCIe FPGA prototype of the IP, then ARM-based FPGA prototype, then OMAP5, none of which needed explicit clock control, see below).

OMAP's PM is written in such a way that a pm_runtime_get() will enable the device the all clocks necessary to be usable. Since OMAP would never need to use clocks directly and I would never be able to test that code, I decided not to add it.

Quoted 7 lines
Quoted 3 lines

Now, if dwc3-exynos needs it, the sane thing to do would be add struct clk knowledge to dwc3/core.c but make it optional. If there are no clocks available, don't bail out.

I'm not too familiar with the multitudes of platforms out there, but my simple question is: why can't we have pm runtime take care of enabling/disabling the clocks so that we don't have to do it in drivers?

that's what OMAP does.

Quoted 3 lines

Seems obvious that a platform/SoC/board should know about it's clock tree structure, so why doesn't the platform code then take care of all the dirty details?

Quoted 7 lines
Quoted 5 lines

it might seem that way, but it's not that obvious ;-) Some platforms have a single clock, some will split interface and functional clocks, in some cases, you have extra optional clocks which might be needed during certain use cases or to implement erratas at locations that only driver knows.

Then drivers could use platform fixup callbacks. Curious how many

ugh, I just puked in my mouth a little bit...

Quoted 2 lines

drivers out there do proper handling of interface vs functional clocks. Something tells me that the common pattern will be "enable all

that, in itself, is no argument against explicitly handling clocks. Bugs are bugs and will always exist, instead of hiding the problem, we should fix them ;-)

Quoted 2 lines

clocks with lots of line of boilerplate copied from that other driver" in probe() and "disable all" in remove().

for a first iteration, you're likely right. When we get to a point where driver is really stable we can start trying to optimize runtime power consumption by fiddling with clocks.

If we're not going to access a device's register, why would you keep interface clock running ? That's where e.g. runtime_pm fails to give us a good solution. There's no (easy) way to tell pm_domain code that it can gate interface clock but not functional clock.

Quoted 9 lines
Quoted 2 lines

Well, how quickly can Exynos be changed to handle clocks without driver's knowledge ?

Motivation for the platforms to change should come from the general direction of linux kernel maintainers, in order for the change to happen. :)

But yes, for the time being, you're right, we'll probably have to just cope with it.

exactly. Just because XYZ wants clocks to be handled all via pm_domain, it doesn't mean we can switch to that overnight. On top of that there are situations such as the one describe above.

Quoted 7 lines
Quoted 4 lines

Also, I'm a lot more 'at ease' when I see the driver explicitly handling all of its resources. The whole "let's hide XYZ from driver because driver authors never get things right" always causes problems. Specially in the ARM land where there's no standardization at all.

I think it's going to be like that as long as developers are working in "hack it and ship it and let somebody else figure out APIs" routine. I

that's why we need capable maintainers. Sometimes things will fall through the cracks, sure, but in most cases we should be blocking "hack and ship" during code review ;-)

Quoted 3 lines

understand that some drivers will always need to call into clock framework directly, but other should have an option not to if their operation doesn't depend on it.

right, so that's why I asked to add struct clk knowledge to dwc3 but make it optional: OMAP doesn't need it, PCIe doesn't need it; only exynos (currently) needs it.

cheers

Signature · 8 lines
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20130301/da110f05/attachment-0001.sig>
author
#24 lore raw

PATCH v9 9/9 usb: chipidea: imx: fix the error that using uninitialized pointer

In reply to Peter Chen

If the core's probe fails, the platform layer may not get core's private data, if the platform tries to use struct ci13xxx, it will use uninitialized pointer. Besides, if the core's probe fails, the platform layer should know it, and let its probe fail too.

---
 drivers/usb/chipidea/ci13xxx_imx.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)
drivers/usb/chipidea/ci13xxx_imx.c +3 -2
index 5499cf8..8352679 100644
@@ -227,8 +227,9 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 	plat_ci = ci13xxx_add_device(&pdev->dev,
 				pdev->resource, pdev->num_resources,
 				pdata);
-	if (IS_ERR(plat_ci)) {
-		ret = PTR_ERR(plat_ci);
+	pdata = plat_ci->dev.platform_data;
+	ret = pdata->probe_retval;
+	if (ret) {
 		dev_err(&pdev->dev,
 			"Can't register ci_hdrc platform device, err=%d\n",
 			ret);
Signature · 1 line
1.7.0.4
author
#25 lore raw

v9 cover Add tested id switch and vbus connect detect support for Chipidea

In reply to Peter Chen

On Sun, Feb 17, 2013 at 05:24:34PM +0800, Peter Chen wrote:

Hi Alex,

Ping............

Quoted 102 lines

Changes for v9:
- Some small comments from Alex like: variable comment for otg event additional newline. [3/9]
- Import function tell show if the controller has otg capable, if the controller supports both host and device, we think it is otg capable, and can read OTGSC. [3/9]
- Merge two otg patches [v8 3/8] and [v8 4/8] to one [v9 3/9]. [3/9]
- Add inline to ci_hdrc_gadget_destroy if CONFIG_USB_CHIPIDEA_UDC is not defined, it can fix one build warning "defined but not used" [3/9]
- One comment from Felipe about changing calling gadget disconnect API at chipidea's udc driver. I move calling ci->driver->disconnect from _gadget_stop_activity to which calls _gadget_stop_activity except ci13xxx_stop, as udc core will call disconnect when do rmmod gadget. [7/9]
- Add ci core probe's return value to ci's platform_data, we do this for getting core's probe's result at platform layer, and quit it if the core's probe fails. [8/9] [9/9]

Changes for v8:
- Add ci_supports_gadget helper to know if the controller supports gadget, if the controller supports gadget, it needs to read otgsc to know the vbus value, basically, if the controller supports gadget, it will support host as well [3/8]
- At ci_hdrc_probe, it needs to add free memory at error path [3/8]
- Cosolidate ci->driver = NULL at ci13xxx_stop [8/8]

Changes for v7:
For Patch 8/8, we only need to set ci->driver to NULL when usb cable is not connected, for other changes, it will case some runtime pm unmatch and un-align with udc-core & composite driver problems.

Changes for v6:
- Add Alex comments for init/destroy function [3/8] [4/8]
- Remove memset(&ci->gadget, 0, sizeof(ci->gadget)) at destory function [4/8]
- Add Kishon's comment: Change the format of struct usb_otg otg at drivers/usb/chipidea/ci.h [1/8]
- Add comments for CI_VBUS_STABLE_TIMEOUT [3/8]
- Change the otg_set_peripheral return value check as the fully
chipidea driver users don't need it. [4/8]
- Fix one bug that the oops when re-plug in usb cable after
rmmod gadget [8/8]

Anyone who has tested this patchset, please give a tested-by, thanks.

This patchset adds tested otg id switch function and vbus connect/disconnect detection for chipidea driver. The mainly design of id/vbus handling follows msm otg driver. I hope the msm usb maintainer can have a look of this patchset, and give some comments, and move the whole msm usb driver to chipidea framework if possible in the future.

This patch is fully tested at imx6 sabresd platform.
My chipidea repo: https://github.com/hzpeterchen/linux-usb.git
which is rebased of Sascha's git
(git://git.pengutronix.de/git/imx/linux-2.6.git tags/usb-chipidea-otg-for-next)

At sascha's tag, it finishes some dr_mode and phy_type patches, in that way, we can choose host-only and gadget-only function at dts file as well as we can choose different phy setting.

Besides sascha's work, there are some Michael Grzeschik/Marc Kleine-Budde usbmisc patch, imx chipidea suspend/resume patch, and one pin control patch for imx6

Peter Chen (9):
Revert "USB: chipidea: add vbus detect for udc"
usb: chipidea: add otg file
usb: chipidea: add otg id switch and vbus connect/disconnect detect
usb: chipidea: udc: add pullup/pulldown dp at hw_device_state
usb: chipidea: udc: retire the flag CI13_PULLUP_ON_VBUS
usb: chipidea: imx: add internal vbus regulator control
usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod
gadget
usb: chipidea: tell platform layer the ci core probe's result
usb: chipidea: imx: fix the error that using uninitialized pointer

 drivers/usb/chipidea/Makefile      |    2 +-
 drivers/usb/chipidea/bits.h        |   10 ++
 drivers/usb/chipidea/ci.h          |   14 +++-
 drivers/usb/chipidea/ci13xxx_imx.c |   85 ++++++++++++----
 drivers/usb/chipidea/ci13xxx_msm.c |    1 -
 drivers/usb/chipidea/core.c        |  192 ++++++++++++++++++++++++++++++++----
 drivers/usb/chipidea/host.c        |    6 +
 drivers/usb/chipidea/host.h        |    6 +-
 drivers/usb/chipidea/otg.c         |   68 +++++++++++++
 drivers/usb/chipidea/otg.h         |    9 ++
 drivers/usb/chipidea/udc.c         |  118 ++++++++++------------
 drivers/usb/chipidea/udc.h         |    4 +
 include/linux/usb/chipidea.h       |    2 +-
 13 files changed, 405 insertions(+), 112 deletions(-)
 create mode 100644 drivers/usb/chipidea/otg.c
 create mode 100644 drivers/usb/chipidea/otg.h

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html

Signature · 2 lines
Best Regards,
Peter Chen