From patchwork Mon Nov 26 09:11:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Chen X-Patchwork-Id: 1801101 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 25D41DF2F9 for ; Mon, 26 Nov 2012 09:16:09 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1TcukU-0006WF-5T; Mon, 26 Nov 2012 09:13:06 +0000 Received: from ch1ehsobe003.messaging.microsoft.com ([216.32.181.183] helo=ch1outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1Tcuj4-00062Y-LE for linux-arm-kernel@lists.infradead.org; Mon, 26 Nov 2012 09:11:42 +0000 Received: from mail108-ch1-R.bigfish.com (10.43.68.229) by CH1EHSOBE005.bigfish.com (10.43.70.55) with Microsoft SMTP Server id 14.1.225.23; Mon, 26 Nov 2012 09:11:37 +0000 Received: from mail108-ch1 (localhost [127.0.0.1]) by mail108-ch1-R.bigfish.com (Postfix) with ESMTP id 2A99C300207; Mon, 26 Nov 2012 09:11:37 +0000 (UTC) X-Forefront-Antispam-Report: CIP:70.37.183.190; KIP:(null); UIP:(null); IPV:NLI; H:mail.freescale.net; RD:none; EFVD:NLI X-SpamScore: 0 X-BigFish: VS0(zzzz1de0h1202h1d1ah1d2ahzz8275bhz2dh2a8h668h839hd24he5bhf0ah1288h12a5h12a9h12bdh12e5h1354h137ah139eh13b6h1441h1504h1537h162dh1631h1155h) Received: from mail108-ch1 (localhost.localdomain [127.0.0.1]) by mail108-ch1 (MessageSwitch) id 1353921095490304_25646; Mon, 26 Nov 2012 09:11:35 +0000 (UTC) Received: from CH1EHSMHS027.bigfish.com (snatpool1.int.messaging.microsoft.com [10.43.68.241]) by mail108-ch1.bigfish.com (Postfix) with ESMTP id 72269160060; Mon, 26 Nov 2012 09:11:35 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by CH1EHSMHS027.bigfish.com (10.43.70.27) with Microsoft SMTP Server (TLS) id 14.1.225.23; Mon, 26 Nov 2012 09:11:32 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-005.039d.mgd.msft.net (10.84.1.17) with Microsoft SMTP Server (TLS) id 14.2.318.3; Mon, 26 Nov 2012 09:11:31 +0000 Received: from localhost.localdomain (nchen-desktop.ap.freescale.net [10.192.242.40]) by tx30smr01.am.freescale.net (8.14.3/8.14.0) with ESMTP id qAQ9B9mP026936; Mon, 26 Nov 2012 02:11:28 -0700 From: Peter Chen To: , Subject: [PATCH v3 4/7] usb: chipidea: consolidate ci_role_driver's API for both roles Date: Mon, 26 Nov 2012 17:11:05 +0800 Message-ID: <1353921068-15673-5-git-send-email-peter.chen@freescale.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1353921068-15673-1-git-send-email-peter.chen@freescale.com> References: <1353921068-15673-1-git-send-email-peter.chen@freescale.com> MIME-Version: 1.0 X-OriginatorOrg: freescale.com X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20121126_041138_939543_4C7B824C X-CRM114-Status: GOOD ( 17.54 ) X-Spam-Score: 0.4 (/) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (0.4 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [216.32.181.183 listed in list.dnswl.org] 3.0 KHOP_BIG_TO_CC Sent to 10+ recipients instaed of Bcc or a list -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: marex@denx.de, m.grzeschik@pengutronix.de, gregkh@linuxfoundation.org, linux-usb@vger.kernel.org, balbi@ti.com, mkl@pengutronix.de, kernel@pengutronix.de, shawn.guo@linaro.org, festevam@gmail.com, linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org - Create init/destroy API for probe and remove - start/stop API are only used otg id switch process - Create the gadget at ci_hdrc_probe if the gadget is supported at that port, the main purpose for this is to avoid gadget module load fail at init.rc Signed-off-by: Peter Chen --- Changes for v3: - Create init/destroy API for probe and remove - start/stop API are only used otg id switch process drivers/usb/chipidea/ci.h | 19 ++++++++++- drivers/usb/chipidea/core.c | 75 +++++++++++++++++++++---------------------- drivers/usb/chipidea/host.c | 2 + drivers/usb/chipidea/udc.c | 22 +++++++++++- 4 files changed, 76 insertions(+), 42 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 12665fa..bc9e4e1 100644 --- a/drivers/usb/chipidea/ci.h +++ b/drivers/usb/chipidea/ci.h @@ -67,14 +67,18 @@ enum ci_role { /** * struct ci_role_driver - host/gadget role driver - * start: start this role - * stop: stop this role + * init: init this role (used at module probe) + * start: start this role (used at id switch) + * stop: stop this role (used at id switch) + * destroy: destroy this role (used at module remove) * irq: irq handler for this role * name: role name string (host/gadget) */ struct ci_role_driver { + int (*init)(struct ci13xxx *); int (*start)(struct ci13xxx *); void (*stop)(struct ci13xxx *); + void (*destroy)(struct ci13xxx *); irqreturn_t (*irq)(struct ci13xxx *); const char *name; }; @@ -207,6 +211,17 @@ static inline void ci_role_stop(struct ci13xxx *ci) ci->roles[role]->stop(ci); } +static inline void ci_role_destroy(struct ci13xxx *ci) +{ + enum ci_role role = ci->role; + + if (role == CI_ROLE_END) + return; + + ci->role = CI_ROLE_END; + + ci->roles[role]->destroy(ci); +} /****************************************************************************** * REGISTERS *****************************************************************************/ diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c index e0392fa..f0d3691 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -307,27 +307,16 @@ static void ci_handle_id_switch(struct ci13xxx *ci) ci_role(ci)->name, ci->roles[role]->name); /* 1. Finish the current role */ - if (ci->role == CI_ROLE_GADGET) { - usb_gadget_vbus_disconnect(&ci->gadget); - /* host doesn't care B_SESSION_VALID event */ - hw_write(ci, OP_OTGSC, OTGSC_BSVIE, ~OTGSC_BSVIE); - hw_write(ci, OP_OTGSC, OTGSC_BSVIS, OTGSC_BSVIS); - ci->role = CI_ROLE_END; - /* reset controller */ - hw_device_reset(ci, USBMODE_CM_IDLE); - } else if (ci->role == CI_ROLE_HOST) { - ci_role_stop(ci); - /* reset controller */ - hw_device_reset(ci, USBMODE_CM_IDLE); - } + ci_role_stop(ci); + hw_device_reset(ci, USBMODE_CM_IDLE); /* 2. Turn on/off vbus according to coming role */ - if (ci_otg_role(ci) == CI_ROLE_GADGET) { + if (role == CI_ROLE_GADGET) { otg_set_vbus(&ci->otg, false); /* wait vbus lower than OTGSC_BSV */ hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0, CI_VBUS_STABLE_TIMEOUT); - } else if (ci_otg_role(ci) == CI_ROLE_HOST) { + } else if (role == CI_ROLE_HOST) { otg_set_vbus(&ci->otg, true); /* wait vbus higher than OTGSC_AVV */ hw_wait_reg(ci, OP_OTGSC, OTGSC_AVV, OTGSC_AVV, @@ -335,13 +324,7 @@ static void ci_handle_id_switch(struct ci13xxx *ci) } /* 3. Begin the new role */ - if (ci_otg_role(ci) == CI_ROLE_GADGET) { - ci->role = role; - hw_write(ci, OP_OTGSC, OTGSC_BSVIS, OTGSC_BSVIS); - hw_write(ci, OP_OTGSC, OTGSC_BSVIE, OTGSC_BSVIE); - } else if (ci_otg_role(ci) == CI_ROLE_HOST) { - ci_role_start(ci, role); - } + ci_role_start(ci, role); } } @@ -584,7 +567,7 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev) ret = ci_hdrc_gadget_init(ci); if (ret) - dev_info(dev, "doesn't support gadget\n"); + dev_info(dev, "doesn't support gadget, ret=%d\n", ret); if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) { dev_err(dev, "no supported roles\n"); @@ -608,23 +591,39 @@ static int __devinit ci_hdrc_probe(struct platform_device *pdev) /* if otg is supported, create struct usb_otg */ ci_hdrc_otg_init(ci); - ret = ci_role_start(ci, ci->role); - if (ret) { - dev_err(dev, "can't start %s role, ret=%d\n", - ci_role(ci)->name, ret); - ret = -ENODEV; - goto rm_wq; - } - otgsc = hw_read(ci, OP_OTGSC, ~0); + /* - * if it is device mode: - * - Enable vbus detect - * - If it has already connected to host, notify udc + * If the gadget is supported, call its init unconditionally, + * We need to support load gadget module at init.rc. */ - if (ci->role == CI_ROLE_GADGET) { - hw_write(ci, OP_OTGSC, OTGSC_BSVIE, OTGSC_BSVIE); - ci_handle_vbus_change(ci); + if (ci->roles[CI_ROLE_GADGET]) { + ret = ci->roles[CI_ROLE_GADGET]->init(ci); + if (ret) { + dev_err(dev, "can't init %s role, ret=%d\n", + ci_role(ci)->name, ret); + ret = -ENODEV; + goto rm_wq; + } + /* + * if it is device mode: + * - Enable vbus detect + * - If it has already connected to host, notify udc + */ + if (ci->role == CI_ROLE_GADGET) { + hw_write(ci, OP_OTGSC, OTGSC_BSVIE, OTGSC_BSVIE); + ci_handle_vbus_change(ci); + } + } + + if (ci->role == CI_ROLE_HOST) { + ret = ci->roles[CI_ROLE_HOST]->init(ci); + if (ret) { + dev_err(dev, "can't init %s role, ret=%d\n", + ci_role(ci)->name, ret); + ret = -ENODEV; + goto rm_wq; + } } platform_set_drvdata(pdev, ci); @@ -662,7 +661,7 @@ static int __devexit ci_hdrc_remove(struct platform_device *pdev) destroy_workqueue(ci->wq); device_remove_file(ci->dev, &dev_attr_role); free_irq(ci->irq, ci); - ci_role_stop(ci); + ci_role_destroy(ci); return 0; } diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c index caecad9..6024a4f 100644 --- a/drivers/usb/chipidea/host.c +++ b/drivers/usb/chipidea/host.c @@ -92,8 +92,10 @@ int ci_hdrc_host_init(struct ci13xxx *ci) if (!rdrv) return -ENOMEM; + rdrv->init = host_start; rdrv->start = host_start; rdrv->stop = host_stop; + rdrv->destroy = host_stop; rdrv->irq = host_irq; rdrv->name = "host"; ci->roles[CI_ROLE_HOST] = rdrv; diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c index b52cb10..ae4755c 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -1780,6 +1780,22 @@ free_qh_pool: return retval; } +static int udc_id_switch_for_device(struct ci13xxx *ci) +{ + hw_write(ci, OP_OTGSC, OTGSC_BSVIS, OTGSC_BSVIS); + hw_write(ci, OP_OTGSC, OTGSC_BSVIE, OTGSC_BSVIE); + + return 0; +} + +static void udc_id_switch_for_host(struct ci13xxx *ci) +{ + usb_gadget_vbus_disconnect(&ci->gadget); + /* host doesn't care B_SESSION_VALID event */ + hw_write(ci, OP_OTGSC, OTGSC_BSVIE, ~OTGSC_BSVIE); + hw_write(ci, OP_OTGSC, OTGSC_BSVIS, OTGSC_BSVIS); +} + /** * udc_remove: parent remove must call this to remove UDC * @@ -1825,8 +1841,10 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci) if (!rdrv) return -ENOMEM; - rdrv->start = udc_start; - rdrv->stop = udc_stop; + rdrv->init = udc_start; + rdrv->start = udc_id_switch_for_device; + rdrv->stop = udc_id_switch_for_host; + rdrv->destroy = udc_stop; rdrv->irq = udc_irq; rdrv->name = "gadget"; ci->roles[CI_ROLE_GADGET] = rdrv;