Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751953AbcDZCID (ORCPT ); Mon, 25 Apr 2016 22:08:03 -0400 Received: from mail-am1on0055.outbound.protection.outlook.com ([157.56.112.55]:34304 "EHLO emea01-am1-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750817AbcDZCIA convert rfc822-to-8bit (ORCPT ); Mon, 25 Apr 2016 22:08:00 -0400 From: Jun Li To: Roger Quadros , "stern@rowland.harvard.edu" , "balbi@kernel.org" , "gregkh@linuxfoundation.org" , "peter.chen@freescale.com" CC: "dan.j.williams@intel.com" , "jun.li@freescale.com" , "mathias.nyman@linux.intel.com" , "tony@atomide.com" , "Joao.Pinto@synopsys.com" , "abrestic@chromium.org" , "r.baldyga@samsung.com" , "linux-usb@vger.kernel.org" , "linux-kernel@vger.kernel.org" , "linux-omap@vger.kernel.org" Subject: RE: [PATCH v6 07/12] usb: otg: add OTG/dual-role core Thread-Topic: [PATCH v6 07/12] usb: otg: add OTG/dual-role core Thread-Index: AQHRj0RO5BWWFaE5xk2PoA2IY651xp+bkXwg Date: Tue, 26 Apr 2016 02:07:56 +0000 Message-ID: References: <1459865117-7032-1-git-send-email-rogerq@ti.com> <1459865117-7032-8-git-send-email-rogerq@ti.com> In-Reply-To: <1459865117-7032-8-git-send-email-rogerq@ti.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: authentication-results: ti.com; dkim=none (message not signed) header.d=none;ti.com; dmarc=none action=none header.from=nxp.com; x-originating-ip: [123.151.195.53] x-ms-office365-filtering-correlation-id: 5cb62b46-c9f6-4a48-72a3-08d36d779579 x-microsoft-exchange-diagnostics: 1;AM4PR04MB2130;5:JAq/xfvauU3OhJVQsq6MyN6l7q/7Vzy1gUVQbNNp8hqCvuUl4MiLFhvxBMA0pHIPI/bW21k4gZ+oiqu4B8RufzpbJefA6gds2uFZQRN8EngbNPpp5AB+Ma6plsV5cVYVOLBRZuMCoZyJg8XnPMssSg==;24:kfrxcuPya86uMQelbFLkVIQXjlu6V6Wy9Q8IoTdVJAUctbOpOKBJmn7HxssrLewSF8x2DrMX6dV2mLUyWg+7iHCzdP3vQ4cfmfAWHli9LRw=;7:8Mw4Hzn01hvG9nCM57LNzL0g5D/Wj2unx//7W0e9ufbMZc9BCQFWNb44yIr0JXHOg670Xk1sCt9Zha4kA7dely9A4aiHxk1pY6zpWhzC3B181rC8V/DwHsrh4s2Jz/FCDnAZXyIOTWk6acYhFJsOn2NsSRck30hcKZa5OBViaqgXe0mKmNm3FxC4xNZkxgh4 x-microsoft-antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:AM4PR04MB2130; x-microsoft-antispam-prvs: x-exchange-antispam-report-test: UriScan:; x-exchange-antispam-report-cfa-test: BCL:0;PCL:0;RULEID:(9101521072)(601004)(2401047)(8121501046)(5005006)(10201501046)(3002001)(6055026);SRVR:AM4PR04MB2130;BCL:0;PCL:0;RULEID:;SRVR:AM4PR04MB2130; x-forefront-prvs: 0924C6A0D5 x-forefront-antispam-report: SFV:NSPM;SFS:(10009020)(6009001)(13464003)(377454003)(2171001)(586003)(76576001)(6116002)(3846002)(102836003)(76176999)(54356999)(87936001)(50986999)(74316001)(9686002)(189998001)(3660700001)(2501003)(19580405001)(3280700002)(5890100001)(106116001)(33656002)(10400500002)(81166005)(19580395003)(2906002)(5004730100002)(92566002)(5008740100001)(2201001)(1220700001)(1096002)(122556002)(77096005)(11100500001)(86362001)(66066001)(5001770100001)(5003600100002)(5002640100001)(2950100001)(2900100001)(7059030);DIR:OUT;SFP:1101;SCL:1;SRVR:AM4PR04MB2130;H:AM4PR04MB2130.eurprd04.prod.outlook.com;FPR:;SPF:None;MLV:sfv;LANG:en; spamdiagnosticoutput: 1:23 spamdiagnosticmetadata: NSPM Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 8BIT MIME-Version: 1.0 X-OriginatorOrg: nxp.com X-MS-Exchange-CrossTenant-originalarrivaltime: 26 Apr 2016 02:07:56.4422 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 686ea1d3-bc2b-4c6f-a92c-d99c5c301635 X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM4PR04MB2130 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9003 Lines: 331 Hi Roger > -----Original Message----- > From: Roger Quadros [mailto:rogerq@ti.com] > Sent: Tuesday, April 05, 2016 10:05 PM > To: stern@rowland.harvard.edu; balbi@kernel.org; > gregkh@linuxfoundation.org; peter.chen@freescale.com > Cc: dan.j.williams@intel.com; jun.li@freescale.com; > mathias.nyman@linux.intel.com; tony@atomide.com; Joao.Pinto@synopsys.com; > abrestic@chromium.org; r.baldyga@samsung.com; linux-usb@vger.kernel.org; > linux-kernel@vger.kernel.org; linux-omap@vger.kernel.org; Roger Quadros > > Subject: [PATCH v6 07/12] usb: otg: add OTG/dual-role core > > It provides APIs for the following tasks > > - Registering an OTG/dual-role capable controller > - Registering Host and Gadget controllers to OTG core > - Providing inputs to and kicking the OTG state machine > > Provide a dual-role device (DRD) state machine. > DRD mode is a reduced functionality OTG mode. In this mode we don't > support SRP, HNP and dynamic role-swap. > > In DRD operation, the controller mode (Host or Peripheral) is decided > based on the ID pin status. Once a cable plug (Type-A or Type-B) is > attached the controller selects the state and doesn't change till the > cable in unplugged and a different cable type is inserted. > > As we don't need most of the complex OTG states and OTG timers we > implement a lean DRD state machine in usb-otg.c. > The DRD state machine is only interested in 2 hardware inputs 'id' and > 'b_sess_vld'. > > Signed-off-by: Roger Quadros > --- ... > +/** > + * Register pending host/gadget and remove entry from wait list */ > +static void usb_otg_flush_wait(struct device *otg_dev) { > + struct otg_wait_data *wait; > + struct otg_hcd *host; > + struct otg_gcd *gadget; > + > + mutex_lock(&wait_list_mutex); > + > + wait = usb_otg_get_wait(otg_dev); > + if (!wait) > + goto done; > + > + dev_dbg(otg_dev, "otg: registering pending host/gadget\n"); > + gadget = &wait->gcd; > + if (gadget) If (gadget->gadget) > + usb_otg_register_gadget(gadget->gadget, gadget->ops); > + > + host = &wait->primary_hcd; > + if (host->hcd) > + usb_otg_register_hcd(host->hcd, host->irqnum, host->irqflags, > + host->ops); > + > + host = &wait->shared_hcd; > + if (host->hcd) > + usb_otg_register_hcd(host->hcd, host->irqnum, host->irqflags, > + host->ops); > + > + list_del(&wait->list); > + kfree(wait); > + > +done: > + mutex_unlock(&wait_list_mutex); > +} > + > +/** > + * Check if the OTG device is in our OTG list and return > + * usb_otg data, else NULL. > + * > + * otg_list_mutex must be held. > + */ > +static struct usb_otg *usb_otg_get_data(struct device *otg_dev) { > + struct usb_otg *otg; > + > + if (!otg_dev) > + return NULL; > + > + list_for_each_entry(otg, &otg_list, list) { > + if (otg->dev == otg_dev) > + return otg; > + } > + > + return NULL; > +} Could you export it to be a public API, we may need access usb_otg in common host driver for handling of enumeration of otg test device. ... > +/** > + * Called when entering a DRD state. > + * fsm->lock must be held. > + */ > +static void drd_set_state(struct otg_fsm *fsm, enum usb_otg_state > +new_state) { > + struct usb_otg *otg = container_of(fsm, struct usb_otg, fsm); > + > + if (otg->state == new_state) > + return; > + > + fsm->state_changed = 1; > + dev_dbg(otg->dev, "otg: set state: %s\n", > + usb_otg_state_string(new_state)); > + switch (new_state) { > + case OTG_STATE_B_IDLE: > + drd_set_protocol(fsm, PROTO_UNDEF); > + otg_drv_vbus(otg, 0); > + break; > + case OTG_STATE_B_PERIPHERAL: > + drd_set_protocol(fsm, PROTO_GADGET); > + otg_drv_vbus(otg, 0); > + break; > + case OTG_STATE_A_HOST: > + drd_set_protocol(fsm, PROTO_HOST); > + otg_drv_vbus(otg, 1); > + break; > + case OTG_STATE_UNDEFINED: > + case OTG_STATE_B_SRP_INIT: > + case OTG_STATE_B_WAIT_ACON: > + case OTG_STATE_B_HOST: > + case OTG_STATE_A_IDLE: > + case OTG_STATE_A_WAIT_VRISE: > + case OTG_STATE_A_WAIT_BCON: > + case OTG_STATE_A_SUSPEND: > + case OTG_STATE_A_PERIPHERAL: > + case OTG_STATE_A_WAIT_VFALL: > + case OTG_STATE_A_VBUS_ERR: Remove above unused states. > + default: > + dev_warn(otg->dev, "%s: otg: invalid state: %s\n", > + __func__, usb_otg_state_string(new_state)); > + break; > + } > + > + otg->state = new_state; > +} > + > +/** > + * DRD state change judgement > + * > + * For DRD we're only interested in some of the OTG states > + * i.e. OTG_STATE_B_IDLE: both peripheral and host are stopped > + * OTG_STATE_B_PERIPHERAL: peripheral active > + * OTG_STATE_A_HOST: host active > + * we're only interested in the following inputs > + * fsm->id, fsm->b_sess_vld > + */ > +int drd_statemachine(struct usb_otg *otg) { > + struct otg_fsm *fsm = &otg->fsm; > + enum usb_otg_state state; > + int ret; > + > + mutex_lock(&fsm->lock); > + > + fsm->state_changed = 0; > + state = otg->state; > + > + switch (state) { > + case OTG_STATE_UNDEFINED: > + if (!fsm->id) > + drd_set_state(fsm, OTG_STATE_A_HOST); > + else if (fsm->id && fsm->b_sess_vld) > + drd_set_state(fsm, OTG_STATE_B_PERIPHERAL); > + else > + drd_set_state(fsm, OTG_STATE_B_IDLE); > + break; > + case OTG_STATE_B_IDLE: > + if (!fsm->id) > + drd_set_state(fsm, OTG_STATE_A_HOST); > + else if (fsm->b_sess_vld) > + drd_set_state(fsm, OTG_STATE_B_PERIPHERAL); > + break; > + case OTG_STATE_B_PERIPHERAL: > + if (!fsm->id) > + drd_set_state(fsm, OTG_STATE_A_HOST); > + else if (!fsm->b_sess_vld) > + drd_set_state(fsm, OTG_STATE_B_IDLE); > + break; > + case OTG_STATE_A_HOST: > + if (fsm->id && fsm->b_sess_vld) > + drd_set_state(fsm, OTG_STATE_B_PERIPHERAL); > + else if (fsm->id && !fsm->b_sess_vld) > + drd_set_state(fsm, OTG_STATE_B_IDLE); > + break; > + > + /* invalid states for DRD */ > + case OTG_STATE_B_SRP_INIT: > + case OTG_STATE_B_WAIT_ACON: > + case OTG_STATE_B_HOST: > + case OTG_STATE_A_IDLE: > + case OTG_STATE_A_WAIT_VRISE: > + case OTG_STATE_A_WAIT_BCON: > + case OTG_STATE_A_SUSPEND: > + case OTG_STATE_A_PERIPHERAL: > + case OTG_STATE_A_WAIT_VFALL: > + case OTG_STATE_A_VBUS_ERR: Remove above unused states and add a default: > + dev_err(otg->dev, "%s: otg: invalid usb-drd state: %s\n", > + __func__, usb_otg_state_string(state)); > + drd_set_state(fsm, OTG_STATE_UNDEFINED); > + break; > + } > + > + ret = fsm->state_changed; > + mutex_unlock(&fsm->lock); > + dev_dbg(otg->dev, "otg: quit statemachine, changed %d\n", > + fsm->state_changed); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(drd_statemachine); > + > +/** > + * OTG FSM/DRD work function DRD work function > + */ > +static void usb_otg_work(struct work_struct *work) { usb_drd_work() name is better as it's only for drd. > + struct usb_otg *otg = container_of(work, struct usb_otg, work); > + > + pm_runtime_get_sync(otg->dev); > + drd_statemachine(otg); > + pm_runtime_put_sync(otg->dev); > +} > + > +/** > + * usb_otg_register() - Register the OTG/dual-role device to OTG core > + * @dev: OTG/dual-role controller device. > + * @config: OTG configuration. > + * > + * Registers the OTG/dual-role controller device with the USB OTG core. > + * > + * Return: struct usb_otg * if success, ERR_PTR() if error. > + */ > +struct usb_otg *usb_otg_register(struct device *dev, > + struct usb_otg_config *config) > +{ > + struct usb_otg *otg; > + struct otg_wait_data *wait; > + int ret = 0; > + > + if (!dev || !config || !config->fsm_ops) > + return ERR_PTR(-EINVAL); > + > + /* already in list? */ > + mutex_lock(&otg_list_mutex); > + if (usb_otg_get_data(dev)) { > + dev_err(dev, "otg: %s: device already in otg list\n", > + __func__); > + ret = -EINVAL; > + goto unlock; > + } > + > + /* allocate and add to list */ > + otg = kzalloc(sizeof(*otg), GFP_KERNEL); > + if (!otg) { > + ret = -ENOMEM; > + goto unlock; > + } > + > + otg->dev = dev; > + otg->caps = config->otg_caps; > + > + if ((otg->caps->hnp_support || otg->caps->srp_support || > + otg->caps->adp_support) && !config->otg_work) > + dev_info(dev, "otg: limiting to dual-role\n"); dev_err, this should be an error. > + > + if (config->otg_work) /* custom otg_work ? */ > + INIT_WORK(&otg->work, config->otg_work); > + else > + INIT_WORK(&otg->work, usb_otg_work); > + > + otg->wq = create_singlethread_workqueue("usb_otg"); > + if (!otg->wq) { > + dev_err(dev, "otg: %s: can't create workqueue\n", > + __func__); > + ret = -ENOMEM; > + goto err_wq; > + } > + > + /* set otg ops */ > + otg->fsm.ops = config->fsm_ops; > + > + mutex_init(&otg->fsm.lock); > + > + list_add_tail(&otg->list, &otg_list); > + mutex_unlock(&otg_list_mutex); > + > + /* were we in wait list? */ > + mutex_lock(&wait_list_mutex); > + wait = usb_otg_get_wait(dev); > + mutex_unlock(&wait_list_mutex); > + if (wait) { > + /* register pending host/gadget and flush from list */ > + usb_otg_flush_wait(dev); > + } > + > + return otg; > + > +err_wq: > + kfree(otg); > +unlock: > + mutex_unlock(&otg_list_mutex); > + return ERR_PTR(ret); > +} > +EXPORT_SYMBOL_GPL(usb_otg_register); > +