From patchwork Thu Dec 27 07:00:00 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Chen X-Patchwork-Id: 1912291 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 B3B4CDF2A2 for ; Thu, 27 Dec 2012 07:04:45 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1To7TO-0001cd-7H; Thu, 27 Dec 2012 07:01:46 +0000 Received: from va3ehsobe002.messaging.microsoft.com ([216.32.180.12] helo=va3outboundpool.messaging.microsoft.com) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1To7SS-0001QG-KM for linux-arm-kernel@lists.infradead.org; Thu, 27 Dec 2012 07:00:51 +0000 Received: from mail216-va3-R.bigfish.com (10.7.14.247) by VA3EHSOBE001.bigfish.com (10.7.40.21) with Microsoft SMTP Server id 14.1.225.23; Thu, 27 Dec 2012 07:00:42 +0000 Received: from mail216-va3 (localhost [127.0.0.1]) by mail216-va3-R.bigfish.com (Postfix) with ESMTP id 67BB18402AD; Thu, 27 Dec 2012 07:00:42 +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(zzzz1de0h1202h1e76h1d1ah1d2ahzz8275bhz2dh2a8h668h839hd24he5bhf0ah1288h12a5h12a9h12bdh12e5h1354h137ah139eh13b6h1441h1504h1537h162dh1631h1758h1155h) Received: from mail216-va3 (localhost.localdomain [127.0.0.1]) by mail216-va3 (MessageSwitch) id 135659164192897_24923; Thu, 27 Dec 2012 07:00:41 +0000 (UTC) Received: from VA3EHSMHS005.bigfish.com (unknown [10.7.14.250]) by mail216-va3.bigfish.com (Postfix) with ESMTP id 12CE7180064; Thu, 27 Dec 2012 07:00:41 +0000 (UTC) Received: from mail.freescale.net (70.37.183.190) by VA3EHSMHS005.bigfish.com (10.7.99.15) with Microsoft SMTP Server (TLS) id 14.1.225.23; Thu, 27 Dec 2012 07:00:38 +0000 Received: from tx30smr01.am.freescale.net (10.81.153.31) by 039-SN1MMR1-003.039d.mgd.msft.net (10.84.1.16) with Microsoft SMTP Server (TLS) id 14.2.318.3; Thu, 27 Dec 2012 07:00:38 +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 qBR704hX008443; Thu, 27 Dec 2012 00:00:33 -0700 From: Peter Chen To: , Subject: [PATCH v4 4/7] usb: chipidea: consolidate ci_role_driver's API for both roles Date: Thu, 27 Dec 2012 15:00:00 +0800 Message-ID: <1356591603-23323-5-git-send-email-peter.chen@freescale.com> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: <1356591603-23323-1-git-send-email-peter.chen@freescale.com> References: <1356591603-23323-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-20121227_020048_869773_921B1915 X-CRM114-Status: GOOD ( 18.11 ) 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.180.12 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, matt@genesi-usa.com, linux-usb@vger.kernel.org, balbi@ti.com, mkl@pengutronix.de, kernel@pengutronix.de, gregkh@linuxfoundation.org, 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 v4: - Move some udc operation from core to udc->init 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 | 65 ++++++++++++++++++------------------------ drivers/usb/chipidea/host.c | 2 + drivers/usb/chipidea/udc.c | 33 ++++++++++++++++++++- 4 files changed, 78 insertions(+), 41 deletions(-) diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h index 325d790..00939e6 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; }; @@ -206,6 +210,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 f8f8484..a5adf1a 100644 --- a/drivers/usb/chipidea/core.c +++ b/drivers/usb/chipidea/core.c @@ -315,27 +315,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 */ - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_disable_otg_interrupt(ci, OTGSC_BSVIE); - 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, @@ -343,13 +332,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; - ci_clear_otg_interrupt(ci, OTGSC_BSVIS); - ci_enable_otg_interrupt(ci, OTGSC_BSVIE); - } else if (ci_otg_role(ci) == CI_ROLE_HOST) { - ci_role_start(ci, role); - } + ci_role_start(ci, role); } } @@ -585,7 +568,7 @@ static int 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"); @@ -607,22 +590,30 @@ static int ci_hdrc_probe(struct platform_device *pdev) : CI_ROLE_GADGET; } - ret = ci_role_start(ci, ci->role); - if (ret) { - dev_err(dev, "can't start %s role\n", ci_role(ci)->name); - 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) { - ci_enable_otg_interrupt(ci, 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 (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); @@ -660,7 +651,7 @@ static int 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..1ac6321 100644 --- a/drivers/usb/chipidea/udc.c +++ b/drivers/usb/chipidea/udc.c @@ -31,6 +31,7 @@ #include "ci.h" #include "udc.h" +#include "otg.h" #include "bits.h" #include "debug.h" @@ -1754,6 +1755,16 @@ static int udc_start(struct ci13xxx *ci) pm_runtime_no_callbacks(&ci->gadget.dev); pm_runtime_enable(&ci->gadget.dev); + /* + * if it is device mode: + * - Enable vbus detect + * - If it has already connected to host, notify udc + */ + if (ci->role == CI_ROLE_GADGET) { + ci_enable_otg_interrupt(ci, OTGSC_BSVIE); + ci_handle_vbus_change(ci); + } + return retval; remove_trans: @@ -1780,6 +1791,22 @@ 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) +{ + usb_gadget_vbus_disconnect(&ci->gadget); + /* 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 * @@ -1825,8 +1852,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;