From patchwork Fri Sep 4 19:18:29 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jagan Teki X-Patchwork-Id: 11758435 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 22AF2618 for ; Fri, 4 Sep 2020 19:20:49 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D2069206B8 for ; Fri, 4 Sep 2020 19:20:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="AaVNvu4k"; dkim=fail reason="signature verification failed" (1024-bit key) header.d=amarulasolutions.com header.i=@amarulasolutions.com header.b="Js+dMC2y" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D2069206B8 Authentication-Results: mail.kernel.org; dmarc=none (p=none dis=none) header.from=amarulasolutions.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=zbOTAIcvA9XOlCvVVhL9Rnniu8t6k29h8Qtjtpm51do=; b=AaVNvu4kEA2bT2xtAJ0aOoop2 i2y8Q9uzq76oa+zbF+csqsUmrNNEzVKFvIQ3PwY4gdVK5Loap1KSuqGDzmLPyq1/tWxcGHhl0Xh9E DZaZlG+BBtS4KySG1lrCUsmqvoMBiIvo7nBg0PO0XLGLDGU6zHeCmzVwd1+ES947FV1CM7JMzbuWx +OIHoZNMSm81hVca7JvpHtvT5B5BYHWxKzNHvc36j1iDDw5wFMfF03sPNFph50Ey3aRTuFq0x6I0K hKWJ7F1C5eVv3Pmg4qW2UGrh+q1J6wbPM5rUbrgOb1GeVu7yGU7CZqwbl1F/utRFsZ+6QYgXdnZB4 gM1MyS6+Q==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEHEz-00058q-HQ; Fri, 04 Sep 2020 19:19:17 +0000 Received: from mail-pf1-x442.google.com ([2607:f8b0:4864:20::442]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1kEHEh-000530-3n for linux-arm-kernel@lists.infradead.org; Fri, 04 Sep 2020 19:19:06 +0000 Received: by mail-pf1-x442.google.com with SMTP id w7so5141030pfi.4 for ; Fri, 04 Sep 2020 12:18:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amarulasolutions.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=+0r4W9mwB3hElBdfBrvtjd4X0q5DQJLDeKjMbcplMDU=; b=Js+dMC2y6bJOPfgi+dpPWCdzalyDqvjHxyFNDwMUi825KGhHDJI1Ytib81Zz86k6fH QK6do1e81kvyEHJvPtSMRRA6NEoB51cFZHAzoUMfgMZwIi9++wQiqIPG4ONZluvE3hPf zIV0UTmQ9bHzSJk31E9ibifexitYDo7hzHx98= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=+0r4W9mwB3hElBdfBrvtjd4X0q5DQJLDeKjMbcplMDU=; b=KBbyhx3mWSl+iP3OJs8tMvcvwkUyBTr4peqDib0LiJS2Yl48zNv3AgyTbGX0o0tE4F m+Fojvv+6wFsW5Zk++JNME1tASVx8cSOv57O6fUz3ChCbpHsrgifgUcXVVmuxb4hYae2 1+4RiR0KNExt64DxHl1rPvJUNKH0XKnoIk+sW4NxIqbRC0979rAXaVc1m0vz1O+mJw5V +7gAPCwBQEWquHmA/lztvkSDMc6BijZxO9WlKvG80H+MrJURdjS1Sz4vyxRzKKriA2Hl KLPsW+4DUUW9lRNdrLA6wsiJEuMUrq7Tk5QiSwH5hlDqpHWBistT5F37/8lf7LGb5FhO LqkQ== X-Gm-Message-State: AOAM532EFzTHGouWaz4wmMArhNnqDUqbDPoNRXvyta0/bmsaM21S5/2H V0/X5KXA8AQzohYjsj6e70Xmog== X-Google-Smtp-Source: ABdhPJwPFAeSEqozQ2oq/5q8jmzdSVhlRwP56anlVHCYZpX7bRboVFg0gwDr5Qiwv41Zg6sEsTBtew== X-Received: by 2002:a63:6fc6:: with SMTP id k189mr8132738pgc.165.1599247136913; Fri, 04 Sep 2020 12:18:56 -0700 (PDT) Received: from localhost.localdomain ([2405:201:c809:c7d5:b9ea:24bf:6b2b:1eee]) by smtp.gmail.com with ESMTPSA id t4sm5986001pje.56.2020.09.04.12.18.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 04 Sep 2020 12:18:56 -0700 (PDT) From: Jagan Teki To: MyungJoo Ham , Chanwoo Choi , Rob Herring , Heiko Stuebner Subject: [PATCH 2/3] extcon: Add Type-C Virtual PD driver Date: Sat, 5 Sep 2020 00:48:29 +0530 Message-Id: <20200904191830.387296-3-jagan@amarulasolutions.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20200904191830.387296-1-jagan@amarulasolutions.com> References: <20200904191830.387296-1-jagan@amarulasolutions.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200904_151859_533790_A69497A0 X-CRM114-Status: GOOD ( 26.92 ) X-Spam-Score: -0.2 (/) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-0.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:442 listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: devicetree@vger.kernel.org, Tom Cubie , linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, Jagan Teki , linux-amarula@amarulasolutions.com, linux-arm-kernel@lists.infradead.org Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org USB Type-C protocol supports various modes of operations includes PD, USB3, and Altmode. If the platform design supports a Type-C connector then configuring these modes can be done via enumeration. However, there are some platforms that design these modes of operations as separate protocol connectors like design Display Port from on-chip USB3 controller. So accessing Type-C Altmode Display Port via onboard Display Port connector instead of a Type-C connector. These kinds of platforms require an explicit extcon driver in order to handle Power Delivery and Port Detection. Add extcon driver for it. Signed-off-by: Jagan Teki --- MAINTAINERS | 6 + drivers/extcon/Kconfig | 10 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-usbc-virtual-pd.c | 285 ++++++++++++++++++++++++ 4 files changed, 302 insertions(+) create mode 100644 drivers/extcon/extcon-usbc-virtual-pd.c diff --git a/MAINTAINERS b/MAINTAINERS index 68f21d46614c..aeb161b19dae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6466,6 +6466,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git F: Documentation/filesystems/ext4/ F: fs/ext4/ +EXTCON DRIVER FOR TYPE-C VIRTUAL PD +M: Jagan Teki +S: Maintained +F: Documentation/devicetree/bindings/extcon/extcon-usbc-virtual-pd.yaml +F: drivers/extcon/extcon-usbc-virtual-pd.c + Extended Verification Module (EVM) M: Mimi Zohar L: linux-integrity@vger.kernel.org diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index aac507bff135..edd6c3c52699 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -186,4 +186,14 @@ config EXTCON_USBC_CROS_EC Say Y here to enable USB Type C cable detection extcon support when using Chrome OS EC based USB Type-C ports. +config EXTCON_USBC_VIRTUAL_PD + tristate "Virtual Type-C PD EXTCON support" + depends on GPIOLIB || COMPILE_TEST + help + Say Y here to enable Virtual Type-C PD extcon driver support, if + hardware platform designed Type-C modes separately. + + Example, of designing Display Port separately from Type-C Altmode + instead of accessing Altmode Display Port in Type-C connector. + endif diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile index 52096fd8a216..c35191eef0e1 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_RT8973A) += extcon-rt8973a.o obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o +obj-$(CONFIG_EXTCON_USBC_VIRTUAL_PD) += extcon-usbc-virtual-pd.o diff --git a/drivers/extcon/extcon-usbc-virtual-pd.c b/drivers/extcon/extcon-usbc-virtual-pd.c new file mode 100644 index 000000000000..e0713670e33d --- /dev/null +++ b/drivers/extcon/extcon-usbc-virtual-pd.c @@ -0,0 +1,285 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Type-C Virtual PD Extcon driver + * + * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd + * Copyright (c) 2019 Radxa Limited + * Copyright (c) 2019 Amarula Solutions(India) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static const unsigned int vpd_cable[] = { + EXTCON_USB, + EXTCON_USB_HOST, + EXTCON_DISP_DP, + EXTCON_NONE, +}; + +enum vpd_data_role { + DR_NONE, + DR_HOST, + DR_DEVICE, + DR_DISPLAY_PORT, +}; + +enum vpd_polarity { + POLARITY_NORMAL, + POLARITY_FLIP, +}; + +enum vpd_usb_ss { + USB_SS_USB2, + USB_SS_USB3, +}; + +struct vpd_extcon { + struct device *dev; + struct extcon_dev *extcon; + struct gpio_desc *det_gpio; + + u8 polarity; + u8 usb_ss; + enum vpd_data_role data_role; + + int irq; + bool enable_irq; + struct work_struct work; + struct delayed_work irq_work; +}; + +static void vpd_extcon_irq_work(struct work_struct *work) +{ + struct vpd_extcon *vpd = container_of(work, struct vpd_extcon, irq_work.work); + bool host_connected = false, device_connected = false, dp_connected = false; + union extcon_property_value property; + int det; + + det = vpd->det_gpio ? gpiod_get_raw_value(vpd->det_gpio) : 0; + if (det) { + device_connected = (vpd->data_role == DR_DEVICE) ? true : false; + host_connected = (vpd->data_role == DR_HOST) ? true : false; + dp_connected = (vpd->data_role == DR_DISPLAY_PORT) ? true : false; + } + + extcon_set_state(vpd->extcon, EXTCON_USB, host_connected); + extcon_set_state(vpd->extcon, EXTCON_USB_HOST, device_connected); + extcon_set_state(vpd->extcon, EXTCON_DISP_DP, dp_connected); + + property.intval = vpd->polarity; + extcon_set_property(vpd->extcon, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY, property); + extcon_set_property(vpd->extcon, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY, property); + extcon_set_property(vpd->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY, property); + + property.intval = vpd->usb_ss; + extcon_set_property(vpd->extcon, EXTCON_USB, + EXTCON_PROP_USB_SS, property); + extcon_set_property(vpd->extcon, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS, property); + extcon_set_property(vpd->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_SS, property); + + extcon_sync(vpd->extcon, EXTCON_USB); + extcon_sync(vpd->extcon, EXTCON_USB_HOST); + extcon_sync(vpd->extcon, EXTCON_DISP_DP); +} + +static irqreturn_t vpd_extcon_irq_handler(int irq, void *dev_id) +{ + struct vpd_extcon *vpd = dev_id; + + schedule_delayed_work(&vpd->irq_work, msecs_to_jiffies(10)); + + return IRQ_HANDLED; +} + +static enum vpd_data_role vpd_extcon_data_role(struct vpd_extcon *vpd) +{ + const char *const data_roles[] = { + [DR_NONE] = "NONE", + [DR_HOST] = "host", + [DR_DEVICE] = "device", + [DR_DISPLAY_PORT] = "display-port", + }; + struct device *dev = vpd->dev; + int ret; + const char *dr; + + ret = device_property_read_string(dev, "vpd-data-role", &dr); + if (ret < 0) + return DR_NONE; + + ret = match_string(data_roles, ARRAY_SIZE(data_roles), dr); + + return (ret < 0) ? DR_NONE : ret; +} + +static int vpd_extcon_parse_dts(struct vpd_extcon *vpd) +{ + struct device *dev = vpd->dev; + bool val = false; + int ret; + + val = device_property_read_bool(dev, "vpd-polarity"); + if (val) + vpd->polarity = POLARITY_FLIP; + else + vpd->polarity = POLARITY_NORMAL; + + val = device_property_read_bool(dev, "vpd-super-speed"); + if (val) + vpd->usb_ss = USB_SS_USB3; + else + vpd->usb_ss = USB_SS_USB2; + + vpd->data_role = vpd_extcon_data_role(vpd); + + vpd->det_gpio = devm_gpiod_get_optional(dev, "det", GPIOD_OUT_LOW); + if (IS_ERR(vpd->det_gpio)) { + ret = PTR_ERR(vpd->det_gpio); + dev_warn(dev, "failed to get det gpio: %d\n", ret); + return ret; + } + + vpd->irq = gpiod_to_irq(vpd->det_gpio); + if (vpd->irq < 0) { + dev_err(dev, "failed to get irq for gpio: %d\n", vpd->irq); + return vpd->irq; + } + + ret = devm_request_threaded_irq(dev, vpd->irq, NULL, + vpd_extcon_irq_handler, + IRQF_TRIGGER_FALLING | + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + NULL, vpd); + if (ret) + dev_err(dev, "failed to request gpio irq\n"); + + return ret; +} + +static int vpd_extcon_probe(struct platform_device *pdev) +{ + struct vpd_extcon *vpd; + struct device *dev = &pdev->dev; + int ret; + + vpd = devm_kzalloc(dev, sizeof(*vpd), GFP_KERNEL); + if (!vpd) + return -ENOMEM; + + vpd->dev = dev; + ret = vpd_extcon_parse_dts(vpd); + if (ret) + return ret; + + INIT_DELAYED_WORK(&vpd->irq_work, vpd_extcon_irq_work); + + vpd->extcon = devm_extcon_dev_allocate(dev, vpd_cable); + if (IS_ERR(vpd->extcon)) { + dev_err(dev, "allocat extcon failed\n"); + return PTR_ERR(vpd->extcon); + } + + ret = devm_extcon_dev_register(dev, vpd->extcon); + if (ret) { + dev_err(dev, "register extcon failed: %d\n", ret); + return ret; + } + + extcon_set_property_capability(vpd->extcon, EXTCON_USB, + EXTCON_PROP_USB_VBUS); + extcon_set_property_capability(vpd->extcon, EXTCON_USB_HOST, + EXTCON_PROP_USB_VBUS); + + extcon_set_property_capability(vpd->extcon, EXTCON_USB, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(vpd->extcon, EXTCON_USB_HOST, + EXTCON_PROP_USB_TYPEC_POLARITY); + extcon_set_property_capability(vpd->extcon, EXTCON_USB, + EXTCON_PROP_USB_SS); + extcon_set_property_capability(vpd->extcon, EXTCON_USB_HOST, + EXTCON_PROP_USB_SS); + + extcon_set_property_capability(vpd->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_SS); + extcon_set_property_capability(vpd->extcon, EXTCON_DISP_DP, + EXTCON_PROP_USB_TYPEC_POLARITY); + + platform_set_drvdata(pdev, vpd); + + vpd_extcon_irq_work(&vpd->irq_work.work); + + return 0; +} + +static int vpd_extcon_remove(struct platform_device *pdev) +{ + struct vpd_extcon *vpd = platform_get_drvdata(pdev); + + cancel_delayed_work_sync(&vpd->irq_work); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int vpd_extcon_suspend(struct device *dev) +{ + struct vpd_extcon *vpd = dev_get_drvdata(dev); + + if (!vpd->enable_irq) { + disable_irq_nosync(vpd->irq); + vpd->enable_irq = true; + } + + return 0; +} + +static int vpd_extcon_resume(struct device *dev) +{ + struct vpd_extcon *vpd = dev_get_drvdata(dev); + + if (vpd->enable_irq) { + enable_irq(vpd->irq); + vpd->enable_irq = false; + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(vpd_extcon_pm_ops, + vpd_extcon_suspend, vpd_extcon_resume); + +static const struct of_device_id vpd_extcon_dt_match[] = { + { .compatible = "linux,extcon-usbc-virtual-pd", }, + { /* sentinel */ } +}; + +static struct platform_driver vpd_extcon_driver = { + .probe = vpd_extcon_probe, + .remove = vpd_extcon_remove, + .driver = { + .name = "extcon-usbc-virtual-pd", + .pm = &vpd_extcon_pm_ops, + .of_match_table = vpd_extcon_dt_match, + }, +}; + +module_platform_driver(vpd_extcon_driver); + +MODULE_AUTHOR("Jagan Teki "); +MODULE_DESCRIPTION("Type-C Virtual PD extcon driver"); +MODULE_LICENSE("GPL v2");