From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 3 Mar 2021 07:59:25 +0100 Subject: [ARCHEOLOGY] RK3399 Typec DP (#2676) > X-Git-Archeology: > recovered message: > * RK3399 NanoPC-T4 Add Type-C alt mode DP > X-Git-Archeology: > recovered message: > * rk3399 rockpi 4C add mini-DP (WIP) > X-Git-Archeology: > recovered message: > * [ rockchip64 ] revert rockPi 4C DP patch > X-Git-Archeology: > recovered message: > Add an extension to disable it, but leave for future work. > X-Git-Archeology: - Revision 4971535c774a1f49a811baebc083ea028ced0300: https://github.com/armbian/build/commit/4971535c774a1f49a811baebc083ea028ced0300 > X-Git-Archeology: Date: Wed, 03 Mar 2021 07:59:25 +0100 > X-Git-Archeology: From: Tony > X-Git-Archeology: Subject: RK3399 Typec DP (#2676) > X-Git-Archeology: > X-Git-Archeology: - Revision 0cdffb29b07305209efb12cf3b5ac6032d3a1153: https://github.com/armbian/build/commit/0cdffb29b07305209efb12cf3b5ac6032d3a1153 > X-Git-Archeology: Date: Wed, 24 Mar 2021 19:01:53 +0100 > X-Git-Archeology: From: Igor Pecovnik > X-Git-Archeology: Subject: Renaming DEV branch to EDGE (#2704) > X-Git-Archeology: > X-Git-Archeology: - Revision ac8fc4385594d59257ee9dffd9efa85e3497fa7d: https://github.com/armbian/build/commit/ac8fc4385594d59257ee9dffd9efa85e3497fa7d > X-Git-Archeology: Date: Sat, 26 Feb 2022 07:46:44 +0100 > X-Git-Archeology: From: Piotr Szczepanik > X-Git-Archeology: Subject: Switch rockchip64 current to linux 5.15.y (#3489) > X-Git-Archeology: > X-Git-Archeology: - Revision 897674aa74bce0326ed7fe06f5336bf4709a8a1f: https://github.com/armbian/build/commit/897674aa74bce0326ed7fe06f5336bf4709a8a1f > X-Git-Archeology: Date: Tue, 03 May 2022 08:27:32 +0200 > X-Git-Archeology: From: Igor Pecovnik > X-Git-Archeology: Subject: Bump and freeze kernel at last known working versions (#3736) > X-Git-Archeology: > X-Git-Archeology: - Revision 597d2dac11f00d9070a4e49d6bad1b2244e36cb3: https://github.com/armbian/build/commit/597d2dac11f00d9070a4e49d6bad1b2244e36cb3 > X-Git-Archeology: Date: Sat, 28 May 2022 07:56:22 +0200 > X-Git-Archeology: From: Jianfeng Liu > X-Git-Archeology: Subject: update rockchip64-edge to 5.18 (#3814) > X-Git-Archeology: > X-Git-Archeology: - Revision 8c6641e7b79f0d50acdc306d140e586a4e923cf0: https://github.com/armbian/build/commit/8c6641e7b79f0d50acdc306d140e586a4e923cf0 > X-Git-Archeology: Date: Wed, 03 Aug 2022 22:22:55 +0200 > X-Git-Archeology: From: Jianfeng Liu > X-Git-Archeology: Subject: update rockchip64 edge to 5.19 (#4039) > X-Git-Archeology: > X-Git-Archeology: - Revision 6765f734cc4a22aeaa9f99a3ad28c8c322de26f6: https://github.com/armbian/build/commit/6765f734cc4a22aeaa9f99a3ad28c8c322de26f6 > X-Git-Archeology: Date: Tue, 25 Oct 2022 11:26:51 +0200 > X-Git-Archeology: From: Igor Pecovnik > X-Git-Archeology: Subject: Bump rockchip64 edge to 6.0.y (#4337) > X-Git-Archeology: > X-Git-Archeology: - Revision 92f1a22d76b987afa7ba555d5b509adc51d689e7: https://github.com/armbian/build/commit/92f1a22d76b987afa7ba555d5b509adc51d689e7 > X-Git-Archeology: Date: Fri, 16 Dec 2022 13:38:13 +0100 > X-Git-Archeology: From: Igor Pecovnik > X-Git-Archeology: Subject: Re-add rockchip64 6.0 patches (#4575) > X-Git-Archeology: > X-Git-Archeology: - Revision 34ae84fac5d0b66a1ab2d1e51534b7beb13ef245: https://github.com/armbian/build/commit/34ae84fac5d0b66a1ab2d1e51534b7beb13ef245 > X-Git-Archeology: Date: Fri, 05 May 2023 14:22:00 +0200 > X-Git-Archeology: From: amazingfate > X-Git-Archeology: Subject: bump rockchip64 edge to v6.3 > X-Git-Archeology: --- drivers/extcon/Kconfig | 10 + drivers/extcon/Makefile | 1 + drivers/extcon/extcon-usbc-virtual-pd.c | 285 ++++++++++ 3 files changed, 296 insertions(+) diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig index 290186e44e6b..ac0b6164d88e 100644 --- a/drivers/extcon/Kconfig +++ b/drivers/extcon/Kconfig @@ -189,4 +189,14 @@ config EXTCON_USBC_TUSB320 Say Y here to enable support for USB Type C cable detection extcon support using a TUSB320. +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 1b390d934ca9..57c1e65bfcfd 100644 --- a/drivers/extcon/Makefile +++ b/drivers/extcon/Makefile @@ -25,3 +25,4 @@ 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_TUSB320) += extcon-usbc-tusb320.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"); -- Armbian