From patchwork Sun Jun 16 13:35:10 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaro Koskinen X-Patchwork-Id: 2728311 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id BB18D9F472 for ; Sun, 16 Jun 2013 13:38:16 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id AB9872016D for ; Sun, 16 Jun 2013 13:38:15 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 5294A2015F for ; Sun, 16 Jun 2013 13:38:14 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1UoD9A-0006gl-BH; Sun, 16 Jun 2013 13:37:32 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UoD8b-0003iD-3l; Sun, 16 Jun 2013 13:36:57 +0000 Received: from filtteri1.pp.htv.fi ([213.243.153.184]) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1UoD7u-0003dm-9G for linux-arm-kernel@lists.infradead.org; Sun, 16 Jun 2013 13:36:20 +0000 Received: from localhost (localhost [127.0.0.1]) by filtteri1.pp.htv.fi (Postfix) with ESMTP id 4649D21B8EA; Sun, 16 Jun 2013 16:35:49 +0300 (EEST) X-Virus-Scanned: Debian amavisd-new at pp.htv.fi Received: from smtp4.welho.com ([213.243.153.38]) by localhost (filtteri1.pp.htv.fi [213.243.153.184]) (amavisd-new, port 10024) with ESMTP id htFetAeNcXKV; Sun, 16 Jun 2013 16:35:44 +0300 (EEST) Received: from blackmetal.pp.htv.fi (cs181064211.pp.htv.fi [82.181.64.211]) by smtp4.welho.com (Postfix) with ESMTP id 49C8B5BC016; Sun, 16 Jun 2013 16:35:44 +0300 (EEST) From: Aaro Koskinen To: linux-usb@vger.kernel.org, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Felipe Balbi , Tony Lindgren Subject: [PATCH v2 3/5] USB: OMAP1: OTG controller driver Date: Sun, 16 Jun 2013 16:35:10 +0300 Message-Id: <1371389712-29516-4-git-send-email-aaro.koskinen@iki.fi> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1371389712-29516-1-git-send-email-aaro.koskinen@iki.fi> References: <1371389712-29516-1-git-send-email-aaro.koskinen@iki.fi> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20130616_093614_684080_A7603B56 X-CRM114-Status: GOOD ( 18.23 ) X-Spam-Score: -1.9 (-) Cc: Aaro Koskinen X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-5.3 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Transceivers need to manage OTG controller state on OMAP1 to enable switching between peripheral and host modes. Provide a driver for that. Signed-off-by: Aaro Koskinen --- drivers/usb/phy/Kconfig | 10 +++ drivers/usb/phy/Makefile | 1 + drivers/usb/phy/phy-omap-otg.c | 171 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 drivers/usb/phy/phy-omap-otg.c diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig index 7ef3eb8..14a50bd 100644 --- a/drivers/usb/phy/Kconfig +++ b/drivers/usb/phy/Kconfig @@ -135,6 +135,16 @@ config USB_GPIO_VBUS optionally control of a D+ pullup GPIO as well as a VBUS current limit regulator. +config OMAP_OTG + tristate "OMAP USB OTG controller driver" + depends on ARCH_OMAP_OTG && EXTCON + help + Enable this to support some transceivers on OMAP1 platforms. OTG + controller is needed to switch between host and peripheral modes. + + This driver can also be built as a module. If so, the module + will be called omap-otg. + config USB_ISP1301 tristate "NXP ISP1301 USB transceiver support" depends on USB || USB_GADGET diff --git a/drivers/usb/phy/Makefile b/drivers/usb/phy/Makefile index a9169cb..c7f391b 100644 --- a/drivers/usb/phy/Makefile +++ b/drivers/usb/phy/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_ISP1301_OMAP) += phy-isp1301-omap.o obj-$(CONFIG_MV_U3D_PHY) += phy-mv-u3d-usb.o obj-$(CONFIG_NOP_USB_XCEIV) += phy-nop.o obj-$(CONFIG_OMAP_CONTROL_USB) += phy-omap-control.o +obj-$(CONFIG_OMAP_OTG) += phy-omap-otg.o obj-$(CONFIG_OMAP_USB2) += phy-omap-usb2.o obj-$(CONFIG_OMAP_USB3) += phy-omap-usb3.o obj-$(CONFIG_SAMSUNG_USBPHY) += phy-samsung-usb.o diff --git a/drivers/usb/phy/phy-omap-otg.c b/drivers/usb/phy/phy-omap-otg.c new file mode 100644 index 0000000..2a8c674 --- /dev/null +++ b/drivers/usb/phy/phy-omap-otg.c @@ -0,0 +1,171 @@ +/* + * OMAP OTG controller driver + * + * Based on code from tahvo-usb.c and isp1301_omap.c drivers. + * + * Copyright (C) 2005-2006 Nokia Corporation + * Copyright (C) 2004 Texas Instruments + * Copyright (C) 2004 David Brownell + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct otg_device { + void __iomem *base; + bool id; + bool vbus; + struct extcon_specific_cable_nb vbus_dev; + struct extcon_specific_cable_nb id_dev; + struct notifier_block vbus_nb; + struct notifier_block id_nb; +}; + +#define OMAP_OTG_CTRL 0x0c +#define OMAP_OTG_ASESSVLD (1 << 20) +#define OMAP_OTG_BSESSEND (1 << 19) +#define OMAP_OTG_BSESSVLD (1 << 18) +#define OMAP_OTG_VBUSVLD (1 << 17) +#define OMAP_OTG_ID (1 << 16) +#define OMAP_OTG_XCEIV_OUTPUTS \ + (OMAP_OTG_ASESSVLD | OMAP_OTG_BSESSEND | OMAP_OTG_BSESSVLD | \ + OMAP_OTG_VBUSVLD | OMAP_OTG_ID) + +static void omap_otg_ctrl(struct otg_device *otg_dev, u32 outputs) +{ + u32 l; + + l = readl(otg_dev->base + OMAP_OTG_CTRL); + l &= ~OMAP_OTG_XCEIV_OUTPUTS; + l |= outputs; + writel(l, otg_dev->base + OMAP_OTG_CTRL); +} + +static void omap_otg_set_mode(struct otg_device *otg_dev) +{ + if (!otg_dev->id && otg_dev->vbus) + /* Set B-session valid. */ + omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSVLD); + else if (otg_dev->vbus) + /* Set A-session valid. */ + omap_otg_ctrl(otg_dev, OMAP_OTG_ASESSVLD); + else if (!otg_dev->id) + /* Set B-session end to indicate no VBUS. */ + omap_otg_ctrl(otg_dev, OMAP_OTG_ID | OMAP_OTG_BSESSEND); +} + +static int omap_otg_id_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct otg_device *otg_dev = container_of(nb, struct otg_device, id_nb); + + otg_dev->id = event; + omap_otg_set_mode(otg_dev); + + return NOTIFY_DONE; +} + +static int omap_otg_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct otg_device *otg_dev = container_of(nb, struct otg_device, + vbus_nb); + + otg_dev->vbus = event; + omap_otg_set_mode(otg_dev); + + return NOTIFY_DONE; +} + +static int omap_otg_probe(struct platform_device *pdev) +{ + const struct omap_usb_config *config = pdev->dev.platform_data; + struct otg_device *otg_dev; + struct extcon_dev *extcon; + int ret; + u32 rev; + + if (!config || !config->extcon) + return -ENODEV; + + extcon = extcon_get_extcon_dev(config->extcon); + if (!extcon) + return -EPROBE_DEFER; + + otg_dev = devm_kzalloc(&pdev->dev, sizeof(*otg_dev), GFP_KERNEL); + if (!otg_dev) + return -ENOMEM; + + otg_dev->base = devm_ioremap_resource(&pdev->dev, &pdev->resource[0]); + if (IS_ERR(otg_dev->base)) + return PTR_ERR(otg_dev->base); + + otg_dev->id_nb.notifier_call = omap_otg_id_notifier; + otg_dev->vbus_nb.notifier_call = omap_otg_vbus_notifier; + + ret = extcon_register_interest(&otg_dev->id_dev, config->extcon, + "USB-HOST", &otg_dev->id_nb); + if (ret) + return ret; + + ret = extcon_register_interest(&otg_dev->vbus_dev, config->extcon, + "USB", &otg_dev->vbus_nb); + if (ret) { + extcon_unregister_interest(&otg_dev->id_dev); + return ret; + } + + otg_dev->id = extcon_get_cable_state(extcon, "USB-HOST"); + otg_dev->vbus = extcon_get_cable_state(extcon, "USB"); + omap_otg_set_mode(otg_dev); + + rev = readl(otg_dev->base); + + dev_info(&pdev->dev, + "OMAP USB OTG controller rev %d.%d (%s, id=%d, vbus=%d)\n", + (rev >> 4) & 0xf, rev & 0xf, config->extcon, otg_dev->id, + otg_dev->vbus); + + return 0; +} + +static int omap_otg_remove(struct platform_device *pdev) +{ + struct otg_device *otg_dev = platform_get_drvdata(pdev); + + extcon_unregister_interest(&otg_dev->id_dev); + extcon_unregister_interest(&otg_dev->vbus_dev); + + return 0; +} + +static struct platform_driver omap_otg_driver = { + .probe = omap_otg_probe, + .remove = omap_otg_remove, + .driver = { + .owner = THIS_MODULE, + .name = "omap_otg", + }, +}; +module_platform_driver(omap_otg_driver); + +MODULE_DESCRIPTION("OMAP USB OTG controller driver"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Aaro Koskinen ");