From patchwork Wed Nov 23 03:46:47 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: John Stultz X-Patchwork-Id: 83527 Delivered-To: patches@linaro.org Received: by 10.140.97.165 with SMTP id m34csp2443986qge; Tue, 22 Nov 2016 19:46:54 -0800 (PST) X-Received: by 10.84.217.18 with SMTP id o18mr2355755pli.45.1479872814574; Tue, 22 Nov 2016 19:46:54 -0800 (PST) Return-Path: Received: from mail-pg0-x22e.google.com (mail-pg0-x22e.google.com. [2607:f8b0:400e:c05::22e]) by mx.google.com with ESMTPS id 59si2979363plp.46.2016.11.22.19.46.54 for (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 Nov 2016 19:46:54 -0800 (PST) Received-SPF: pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c05::22e as permitted sender) client-ip=2607:f8b0:400e:c05::22e; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org; spf=pass (google.com: domain of john.stultz@linaro.org designates 2607:f8b0:400e:c05::22e as permitted sender) smtp.mailfrom=john.stultz@linaro.org; dmarc=pass (p=NONE dis=NONE) header.from=linaro.org Received: by mail-pg0-x22e.google.com with SMTP id f188so720790pgc.3 for ; Tue, 22 Nov 2016 19:46:54 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=XJUWn54qw94eQexr1osJoI7AhqlaOVaVMY5wGde2DCk=; b=Q5s1AXrbichVljspohcKZaN3Z5I9xotGc7hgwL4wvMVM4p3xaYzycd24zp6oCiM+Oe wfcYNxcaKGqkS/5IwePaA+9ubqXEddRZ0MfEiP9a4MyceeDvHgh0PClSHMjJtxROCOhG zXfjf2i8qr12ZG50iS6GvI6mAyEG1ewQAp2Fg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=XJUWn54qw94eQexr1osJoI7AhqlaOVaVMY5wGde2DCk=; b=WSfbvv4hjWHsX0gUuN58vA8qAXEvgTajUcyn6sAgm9WOt/uHAYvuCQGZgU+pOT1XMj Nuvlpog/ZNFRwAONG6L22gVt7wsXM1bfp4M8Db/9fIUa9mzKohfkUa2bUy3uyW3PQDrv p/6mnur+IQZNlglu9u9E19afnqHfw63g/dmIxlXAttUfqMaZxOwMTzNRldzpB4SvxphF TcGoIxwvWLmCf1SoMLkczcfeMGk+VTdSB1gq5MZDAe4rON1Cc9nGfvsYxlTC0GbsY/N7 V9+lMoplKpmSLQXd182aztqTbUw5l0kPozaEjl/pr9QNbQW/ios7zCY0E0kwHfTgAIPn etJQ== X-Gm-Message-State: AKaTC00akmWjfVW3qyA6nizTDoR9ZkXpDIvrgiB3nSPJ87wWzTEezSZtB7VjGt6V+MUS+CMZsSA= X-Received: by 10.99.112.13 with SMTP id l13mr1863478pgc.7.1479872814243; Tue, 22 Nov 2016 19:46:54 -0800 (PST) Return-Path: Received: from localhost.localdomain ([2601:1c2:1002:83f0:4e72:b9ff:fe99:466a]) by smtp.gmail.com with ESMTPSA id l11sm48282533pfb.28.2016.11.22.19.46.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 22 Nov 2016 19:46:53 -0800 (PST) From: John Stultz To: lkml Cc: John Stultz , Wei Xu , Guodong Xu , Amit Pundir , Rob Herring , John Youn , Douglas Anderson , Chen Yu , Kishon Vijay Abraham I , Felipe Balbi , Greg Kroah-Hartman , linux-usb@vger.kernel.org Subject: [RFC][PATCH 1/3] phy: phy-hi6220-usb: Wire up extconn support to hikey's phy driver Date: Tue, 22 Nov 2016 19:46:47 -0800 Message-Id: <1479872809-11958-2-git-send-email-john.stultz@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1479872809-11958-1-git-send-email-john.stultz@linaro.org> References: <1479872809-11958-1-git-send-email-john.stultz@linaro.org> This wires extconn support to hikey's phy driver, and connects it to the usb UDC layer via a usb_phy structure. Not sure if this is the right way to connect phy -> UDC, but I'm lacking a clear example. Cc: Wei Xu Cc: Guodong Xu Cc: Amit Pundir Cc: Rob Herring Cc: John Youn Cc: Douglas Anderson Cc: Chen Yu Cc: Kishon Vijay Abraham I Cc: Felipe Balbi Cc: Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org Signed-off-by: John Stultz --- arch/arm64/boot/dts/hisilicon/hi6220.dtsi | 11 +++ drivers/phy/Kconfig | 2 + drivers/phy/phy-hi6220-usb.c | 139 ++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) -- 2.7.4 diff --git a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi index 17839db..171fbb2 100644 --- a/arch/arm64/boot/dts/hisilicon/hi6220.dtsi +++ b/arch/arm64/boot/dts/hisilicon/hi6220.dtsi @@ -732,10 +732,21 @@ regulator-always-on; }; + usb_vbus: usb-vbus { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&gpio2 6 1>; + }; + + usb_id: usb-id { + compatible = "linux,extcon-usb-gpio"; + id-gpio = <&gpio2 5 1>; + }; + usb_phy: usbphy { compatible = "hisilicon,hi6220-usb-phy"; #phy-cells = <0>; phy-supply = <&fixed_5v_hub>; + extcon = <&usb_vbus>, <&usb_id>; hisilicon,peripheral-syscon = <&sys_ctrl>; }; diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index fe00f91..76f4f17 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -254,8 +254,10 @@ config PHY_MT65XX_USB3 config PHY_HI6220_USB tristate "hi6220 USB PHY support" depends on (ARCH_HISI && ARM64) || COMPILE_TEST + depends on EXTCON select GENERIC_PHY select MFD_SYSCON + select USB_PHY help Enable this to support the HISILICON HI6220 USB PHY. diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c index b2141cb..89d8475 100644 --- a/drivers/phy/phy-hi6220-usb.c +++ b/drivers/phy/phy-hi6220-usb.c @@ -12,7 +12,12 @@ #include #include #include +#include +#include +#include +#include #include +#include #define SC_PERIPH_CTRL4 0x00c @@ -44,9 +49,21 @@ #define EYE_PATTERN_PARA 0x7053348c + +struct hi6220_usb_cable { + struct notifier_block nb; + struct extcon_dev *extcon; + int state; +}; + struct hi6220_priv { struct regmap *reg; struct device *dev; + struct usb_phy phy; + + struct delayed_work work; + struct hi6220_usb_cable vbus; + struct hi6220_usb_cable id; }; static void hi6220_phy_init(struct hi6220_priv *priv) @@ -112,23 +129,85 @@ static int hi6220_phy_exit(struct phy *phy) return hi6220_phy_setup(priv, false); } + static struct phy_ops hi6220_phy_ops = { .init = hi6220_phy_start, .exit = hi6220_phy_exit, .owner = THIS_MODULE, }; +static void hi6220_detect_work(struct work_struct *work) +{ + struct hi6220_priv *priv = + container_of(to_delayed_work(work), struct hi6220_priv, work); + struct usb_otg *otg = priv->phy.otg; + + if (!IS_ERR(priv->vbus.extcon)) + priv->vbus.state = extcon_get_cable_state_(priv->vbus.extcon, + EXTCON_USB); + if (!IS_ERR(priv->id.extcon)) + priv->id.state = extcon_get_cable_state_(priv->id.extcon, + EXTCON_USB_HOST); + if (otg->gadget) { + if (priv->id.state) + usb_gadget_vbus_connect(otg->gadget); + else + usb_gadget_vbus_disconnect(otg->gadget); + } +} + +static int hi6220_otg_vbus_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct hi6220_usb_cable *vbus = container_of(nb, + struct hi6220_usb_cable, nb); + struct hi6220_priv *priv = container_of(vbus, + struct hi6220_priv, vbus); + + schedule_delayed_work(&priv->work, msecs_to_jiffies(100)); + return NOTIFY_DONE; +} + +static int hi6220_otg_id_notifier(struct notifier_block *nb, + unsigned long event, void *ptr) +{ + struct hi6220_usb_cable *id = container_of(nb, + struct hi6220_usb_cable, nb); + struct hi6220_priv *priv = container_of(id, struct hi6220_priv, id); + + schedule_delayed_work(&priv->work, msecs_to_jiffies(100)); + return NOTIFY_DONE; +} + +static int hi6220_otg_set_host(struct usb_otg *otg, struct usb_bus *host) +{ + otg->host = host; + return 0; +} + +static int hi6220_otg_set_peripheral(struct usb_otg *otg, + struct usb_gadget *gadget) +{ + otg->gadget = gadget; + return 0; +} + static int hi6220_phy_probe(struct platform_device *pdev) { struct phy_provider *phy_provider; struct device *dev = &pdev->dev; struct phy *phy; + struct usb_otg *otg; struct hi6220_priv *priv; + struct extcon_dev *ext_id, *ext_vbus; + int ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; + INIT_DELAYED_WORK(&priv->work, hi6220_detect_work); + priv->dev = dev; priv->reg = syscon_regmap_lookup_by_phandle(dev->of_node, "hisilicon,peripheral-syscon"); @@ -137,13 +216,73 @@ static int hi6220_phy_probe(struct platform_device *pdev) return PTR_ERR(priv->reg); } + + ext_id = ERR_PTR(-ENODEV); + ext_vbus = ERR_PTR(-ENODEV); + if (of_property_read_bool(dev->of_node, "extcon")) { + /* Each one of them is not mandatory */ + ext_vbus = extcon_get_edev_by_phandle(&pdev->dev, 0); + if (IS_ERR(ext_vbus) && PTR_ERR(ext_vbus) != -ENODEV) + return PTR_ERR(ext_vbus); + + ext_id = extcon_get_edev_by_phandle(&pdev->dev, 1); + if (IS_ERR(ext_id) && PTR_ERR(ext_id) != -ENODEV) + return PTR_ERR(ext_id); + } + + priv->vbus.extcon = ext_vbus; + if (!IS_ERR(ext_vbus)) { + priv->vbus.nb.notifier_call = hi6220_otg_vbus_notifier; + ret = extcon_register_notifier(ext_vbus, EXTCON_USB, + &priv->vbus.nb); + if (ret < 0) { + dev_err(&pdev->dev, "register VBUS notifier failed\n"); + return ret; + } + + priv->vbus.state = extcon_get_cable_state_(ext_vbus, + EXTCON_USB); + } + + priv->id.extcon = ext_id; + if (!IS_ERR(ext_id)) { + priv->id.nb.notifier_call = hi6220_otg_id_notifier; + ret = extcon_register_notifier(ext_id, EXTCON_USB_HOST, + &priv->id.nb); + if (ret < 0) { + dev_err(&pdev->dev, "register ID notifier failed\n"); + return ret; + } + + priv->id.state = extcon_get_cable_state_(ext_id, + EXTCON_USB_HOST); + } + hi6220_phy_init(priv); phy = devm_phy_create(dev, NULL, &hi6220_phy_ops); if (IS_ERR(phy)) return PTR_ERR(phy); + otg = devm_kzalloc(&pdev->dev, sizeof(*otg), GFP_KERNEL); + if (!otg) + return -ENOMEM; + + priv->dev = &pdev->dev; + priv->phy.dev = priv->dev; + priv->phy.label = "hi6220_usb_phy"; + priv->phy.otg = otg; + priv->phy.type = USB_PHY_TYPE_USB2; + otg->set_host = hi6220_otg_set_host; + otg->set_peripheral = hi6220_otg_set_peripheral; + otg->usb_phy = &priv->phy; + + platform_set_drvdata(pdev, priv); + phy_set_drvdata(phy, priv); + + usb_add_phy_dev(&priv->phy); + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); return PTR_ERR_OR_ZERO(phy_provider); }