All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yu Chen <chenyu56@huawei.com>
To: <linux-usb@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>
Cc: <suzhuangluan@hisilicon.com>, <kongfei@hisilicon.com>,
	Yu Chen <chenyu56@huawei.com>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	John Stultz <john.stultz@linaro.org>,
	"Binghui Wang" <wangbinghui@hisilicon.com>,
	Heikki Krogerus <heikki.krogerus@linux.intel.com>
Subject: [PATCH v1 10/12] hikey960: Support usb functionality of Hikey960
Date: Mon, 3 Dec 2018 11:45:13 +0800	[thread overview]
Message-ID: <20181203034515.91412-11-chenyu56@huawei.com> (raw)
In-Reply-To: <20181203034515.91412-1-chenyu56@huawei.com>

This driver handles usb hub power on and typeC port event of HiKey960 board:
1)DP&DM switching between usb hub and typeC port base on typeC port
state
2)Control power of usb hub on Hikey960
3)Control vbus of typeC port

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Binghui Wang <wangbinghui@hisilicon.com>
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Yu Chen <chenyu56@huawei.com>

--
v1:
1) Using gpiod API with the gpios.
2) Removing registering usb role switch.
3) Registering usb role switch notifier.
--
---
 drivers/misc/Kconfig          |   7 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/hisi_hikey_usb.c | 198 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 drivers/misc/hisi_hikey_usb.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3726eacdf65d..8e04fc87b685 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -513,6 +513,13 @@ config MISC_RTSX
 	tristate
 	default MISC_RTSX_PCI || MISC_RTSX_USB
 
+config HISI_HIKEY_USB
+	tristate "USB functionality of HiSilicon Hikey Platform"
+	depends on GPIOLIB
+	default n
+	help
+	  If you say yes here you get support for usb functionality of HiSilicon Hikey Platform.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af22bbc3d00c..387dd302815c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c
new file mode 100644
index 000000000000..f320ed878e44
--- /dev/null
+++ b/drivers/misc/hisi_hikey_usb.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hisi_hikey_usb.c
+ *
+ * Copyright (c) Hisilicon Tech. Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/usb/role.h>
+#include <linux/notifier.h>
+
+#define DEVICE_DRIVER_NAME "hisi_hikey_usb"
+
+#define HUB_VBUS_POWER_ON 1
+#define HUB_VBUS_POWER_OFF 0
+#define USB_SWITCH_TO_HUB 1
+#define USB_SWITCH_TO_TYPEC 0
+
+struct hisi_hikey_usb {
+	struct gpio_desc *otg_switch;
+	struct gpio_desc *typec_vbus;
+	struct gpio_desc *hub_vbus;
+	int typec_vbus_enable_val;
+
+	struct usb_role_switch *role_sw;
+	struct notifier_block nb;
+};
+
+static void hub_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, int value)
+{
+	pr_debug("%s: set hub power %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->hub_vbus, value);
+}
+
+static void usb_switch_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int switch_to)
+{
+	const char *switch_to_str = (switch_to == USB_SWITCH_TO_HUB) ?
+		"hub" : "typec";
+
+	pr_debug("%s: switch to %s\n", __func__, switch_to_str);
+	gpiod_set_value_cansleep(hisi_hikey_usb->otg_switch, switch_to);
+}
+
+static void usb_typec_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int value)
+{
+	pr_debug("%s: set typec vbus gpio to %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->typec_vbus, value);
+}
+
+static int hisi_hikey_role_switch(struct notifier_block *nb,
+			unsigned long state, void *data)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb;
+
+	if (!nb)
+		return -EINVAL;
+
+	hisi_hikey_usb = container_of(nb, struct hisi_hikey_usb, nb);
+
+	pr_info("%s:set typec state to %lu\n", __func__, state);
+	switch (state) {
+	case USB_ROLE_NONE:
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_HUB);
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_ON);
+		break;
+	case USB_ROLE_HOST:
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				hisi_hikey_usb->typec_vbus_enable_val);
+		break;
+	case USB_ROLE_DEVICE:
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hisi_hikey_usb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *root = dev->of_node;
+	struct hisi_hikey_usb *hisi_hikey_usb;
+	int ret;
+
+	hisi_hikey_usb = devm_kzalloc(dev, sizeof(*hisi_hikey_usb), GFP_KERNEL);
+	if (!hisi_hikey_usb)
+		return -ENOMEM;
+
+	hisi_hikey_usb->nb.notifier_call = hisi_hikey_role_switch;
+
+	ret = of_property_read_u32(root, "typc-vbus-enable-val",
+				   &hisi_hikey_usb->typec_vbus_enable_val);
+	if (ret) {
+		pr_info("%s: typc_vbus_enable_val can't get\n", __func__);
+		hisi_hikey_usb->typec_vbus_enable_val = 1;
+	}
+
+	hisi_hikey_usb->typec_vbus = devm_gpiod_get(dev, "typec-vbus",
+			hisi_hikey_usb->typec_vbus_enable_val ?
+			GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->typec_vbus)) {
+		if (!hisi_hikey_usb->typec_vbus)
+			ret = -EINVAL;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->typec_vbus);
+		return ret;
+	}
+
+	hisi_hikey_usb->otg_switch = devm_gpiod_get(dev, "otg-switch", GPIOD_IN);
+	if (IS_ERR(hisi_hikey_usb->otg_switch))
+		return PTR_ERR(hisi_hikey_usb->otg_switch);
+
+	hisi_hikey_usb->hub_vbus = devm_gpiod_get(dev, "hub-vdd33-en",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(hisi_hikey_usb->hub_vbus))
+		return PTR_ERR(hisi_hikey_usb->hub_vbus);
+
+	hisi_hikey_usb->role_sw = usb_role_switch_get(dev);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->role_sw)) {
+		pr_err("%s: usb_role_switch_get failed\n", __func__);
+		if (!hisi_hikey_usb->role_sw)
+			ret = -ENOENT;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	ret = usb_role_switch_register_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+	if (ret) {
+		usb_role_switch_put(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, hisi_hikey_usb);
+
+	return 0;
+}
+
+static int  hisi_hikey_usb_remove(struct platform_device *pdev)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb = platform_get_drvdata(pdev);
+
+	usb_role_switch_unregister_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+
+	usb_role_switch_put(hisi_hikey_usb->role_sw);
+
+	return 0;
+}
+
+static const struct of_device_id id_table_hisi_hikey_usb[] = {
+	{.compatible = "hisilicon,gpio_hubv1"},
+	{.compatible = "hisilicon,hikey960_usb"},
+	{}
+};
+
+static struct platform_driver  hisi_hikey_usb_driver = {
+	.probe = hisi_hikey_usb_probe,
+	.remove = hisi_hikey_usb_remove,
+	.driver = {
+		.name = DEVICE_DRIVER_NAME,
+		.of_match_table = of_match_ptr(id_table_hisi_hikey_usb),
+
+	},
+};
+
+module_platform_driver(hisi_hikey_usb_driver);
+
+MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
+MODULE_DESCRIPTION("Driver Support for USB functionality of Hikey");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0-rc2


WARNING: multiple messages have this Message-ID (diff)
From: Yu Chen <chenyu56@huawei.com>
To: linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Cc: suzhuangluan@hisilicon.com, kongfei@hisilicon.com,
	Yu Chen <chenyu56@huawei.com>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	John Stultz <john.stultz@linaro.org>,
	Binghui Wang <wangbinghui@hisilicon.com>,
	Heikki Krogerus <heikki.krogerus@linux.intel.com>
Subject: [PATCH v1 10/12] hikey960: Support usb functionality of Hikey960
Date: Mon, 3 Dec 2018 11:45:13 +0800	[thread overview]
Message-ID: <20181203034515.91412-11-chenyu56@huawei.com> (raw)
In-Reply-To: <20181203034515.91412-1-chenyu56@huawei.com>

This driver handles usb hub power on and typeC port event of HiKey960 board:
1)DP&DM switching between usb hub and typeC port base on typeC port
state
2)Control power of usb hub on Hikey960
3)Control vbus of typeC port

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Binghui Wang <wangbinghui@hisilicon.com>
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Yu Chen <chenyu56@huawei.com>

--
v1:
1) Using gpiod API with the gpios.
2) Removing registering usb role switch.
3) Registering usb role switch notifier.
--
---
 drivers/misc/Kconfig          |   7 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/hisi_hikey_usb.c | 198 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 drivers/misc/hisi_hikey_usb.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3726eacdf65d..8e04fc87b685 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -513,6 +513,13 @@ config MISC_RTSX
 	tristate
 	default MISC_RTSX_PCI || MISC_RTSX_USB
 
+config HISI_HIKEY_USB
+	tristate "USB functionality of HiSilicon Hikey Platform"
+	depends on GPIOLIB
+	default n
+	help
+	  If you say yes here you get support for usb functionality of HiSilicon Hikey Platform.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af22bbc3d00c..387dd302815c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c
new file mode 100644
index 000000000000..f320ed878e44
--- /dev/null
+++ b/drivers/misc/hisi_hikey_usb.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hisi_hikey_usb.c
+ *
+ * Copyright (c) Hisilicon Tech. Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/usb/role.h>
+#include <linux/notifier.h>
+
+#define DEVICE_DRIVER_NAME "hisi_hikey_usb"
+
+#define HUB_VBUS_POWER_ON 1
+#define HUB_VBUS_POWER_OFF 0
+#define USB_SWITCH_TO_HUB 1
+#define USB_SWITCH_TO_TYPEC 0
+
+struct hisi_hikey_usb {
+	struct gpio_desc *otg_switch;
+	struct gpio_desc *typec_vbus;
+	struct gpio_desc *hub_vbus;
+	int typec_vbus_enable_val;
+
+	struct usb_role_switch *role_sw;
+	struct notifier_block nb;
+};
+
+static void hub_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, int value)
+{
+	pr_debug("%s: set hub power %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->hub_vbus, value);
+}
+
+static void usb_switch_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int switch_to)
+{
+	const char *switch_to_str = (switch_to == USB_SWITCH_TO_HUB) ?
+		"hub" : "typec";
+
+	pr_debug("%s: switch to %s\n", __func__, switch_to_str);
+	gpiod_set_value_cansleep(hisi_hikey_usb->otg_switch, switch_to);
+}
+
+static void usb_typec_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int value)
+{
+	pr_debug("%s: set typec vbus gpio to %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->typec_vbus, value);
+}
+
+static int hisi_hikey_role_switch(struct notifier_block *nb,
+			unsigned long state, void *data)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb;
+
+	if (!nb)
+		return -EINVAL;
+
+	hisi_hikey_usb = container_of(nb, struct hisi_hikey_usb, nb);
+
+	pr_info("%s:set typec state to %lu\n", __func__, state);
+	switch (state) {
+	case USB_ROLE_NONE:
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_HUB);
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_ON);
+		break;
+	case USB_ROLE_HOST:
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				hisi_hikey_usb->typec_vbus_enable_val);
+		break;
+	case USB_ROLE_DEVICE:
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hisi_hikey_usb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *root = dev->of_node;
+	struct hisi_hikey_usb *hisi_hikey_usb;
+	int ret;
+
+	hisi_hikey_usb = devm_kzalloc(dev, sizeof(*hisi_hikey_usb), GFP_KERNEL);
+	if (!hisi_hikey_usb)
+		return -ENOMEM;
+
+	hisi_hikey_usb->nb.notifier_call = hisi_hikey_role_switch;
+
+	ret = of_property_read_u32(root, "typc-vbus-enable-val",
+				   &hisi_hikey_usb->typec_vbus_enable_val);
+	if (ret) {
+		pr_info("%s: typc_vbus_enable_val can't get\n", __func__);
+		hisi_hikey_usb->typec_vbus_enable_val = 1;
+	}
+
+	hisi_hikey_usb->typec_vbus = devm_gpiod_get(dev, "typec-vbus",
+			hisi_hikey_usb->typec_vbus_enable_val ?
+			GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->typec_vbus)) {
+		if (!hisi_hikey_usb->typec_vbus)
+			ret = -EINVAL;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->typec_vbus);
+		return ret;
+	}
+
+	hisi_hikey_usb->otg_switch = devm_gpiod_get(dev, "otg-switch", GPIOD_IN);
+	if (IS_ERR(hisi_hikey_usb->otg_switch))
+		return PTR_ERR(hisi_hikey_usb->otg_switch);
+
+	hisi_hikey_usb->hub_vbus = devm_gpiod_get(dev, "hub-vdd33-en",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(hisi_hikey_usb->hub_vbus))
+		return PTR_ERR(hisi_hikey_usb->hub_vbus);
+
+	hisi_hikey_usb->role_sw = usb_role_switch_get(dev);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->role_sw)) {
+		pr_err("%s: usb_role_switch_get failed\n", __func__);
+		if (!hisi_hikey_usb->role_sw)
+			ret = -ENOENT;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	ret = usb_role_switch_register_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+	if (ret) {
+		usb_role_switch_put(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, hisi_hikey_usb);
+
+	return 0;
+}
+
+static int  hisi_hikey_usb_remove(struct platform_device *pdev)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb = platform_get_drvdata(pdev);
+
+	usb_role_switch_unregister_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+
+	usb_role_switch_put(hisi_hikey_usb->role_sw);
+
+	return 0;
+}
+
+static const struct of_device_id id_table_hisi_hikey_usb[] = {
+	{.compatible = "hisilicon,gpio_hubv1"},
+	{.compatible = "hisilicon,hikey960_usb"},
+	{}
+};
+
+static struct platform_driver  hisi_hikey_usb_driver = {
+	.probe = hisi_hikey_usb_probe,
+	.remove = hisi_hikey_usb_remove,
+	.driver = {
+		.name = DEVICE_DRIVER_NAME,
+		.of_match_table = of_match_ptr(id_table_hisi_hikey_usb),
+
+	},
+};
+
+module_platform_driver(hisi_hikey_usb_driver);
+
+MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
+MODULE_DESCRIPTION("Driver Support for USB functionality of Hikey");
+MODULE_LICENSE("GPL v2");
-- 
2.15.0-rc2

WARNING: multiple messages have this Message-ID (diff)
From: Yu Chen <chenyu56@huawei.com>
To: linux-usb@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
Cc: suzhuangluan@hisilicon.com, kongfei@hisilicon.com,
	Yu Chen <chenyu56@huawei.com>, Arnd Bergmann <arnd@arndb.de>,
	Greg Kroah-Hartman <gregkh@linuxfoundation.org>,
	John Stultz <john.stultz@linaro.org>,
	Binghui Wang <wangbinghui@hisilicon.com>,
	Heikki Krogerus <heikki.krogerus@linux.intel.com>
Subject: [v1,10/12] hikey960: Support usb functionality of Hikey960
Date: Mon, 3 Dec 2018 11:45:13 +0800	[thread overview]
Message-ID: <20181203034515.91412-11-chenyu56@huawei.com> (raw)

This driver handles usb hub power on and typeC port event of HiKey960 board:
1)DP&DM switching between usb hub and typeC port base on typeC port
state
2)Control power of usb hub on Hikey960
3)Control vbus of typeC port

Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: John Stultz <john.stultz@linaro.org>
Cc: Binghui Wang <wangbinghui@hisilicon.com>
Cc: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Signed-off-by: Yu Chen <chenyu56@huawei.com>
---
v1:
1) Using gpiod API with the gpios.
2) Removing registering usb role switch.
3) Registering usb role switch notifier.
--
---
 drivers/misc/Kconfig          |   7 ++
 drivers/misc/Makefile         |   1 +
 drivers/misc/hisi_hikey_usb.c | 198 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 206 insertions(+)
 create mode 100644 drivers/misc/hisi_hikey_usb.c

diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 3726eacdf65d..8e04fc87b685 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -513,6 +513,13 @@ config MISC_RTSX
 	tristate
 	default MISC_RTSX_PCI || MISC_RTSX_USB
 
+config HISI_HIKEY_USB
+	tristate "USB functionality of HiSilicon Hikey Platform"
+	depends on GPIOLIB
+	default n
+	help
+	  If you say yes here you get support for usb functionality of HiSilicon Hikey Platform.
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
 source "drivers/misc/cb710/Kconfig"
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index af22bbc3d00c..387dd302815c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -58,3 +58,4 @@ obj-$(CONFIG_ASPEED_LPC_SNOOP)	+= aspeed-lpc-snoop.o
 obj-$(CONFIG_PCI_ENDPOINT_TEST)	+= pci_endpoint_test.o
 obj-$(CONFIG_OCXL)		+= ocxl/
 obj-$(CONFIG_MISC_RTSX)		+= cardreader/
+obj-$(CONFIG_HISI_HIKEY_USB)	+= hisi_hikey_usb.o
diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c
new file mode 100644
index 000000000000..f320ed878e44
--- /dev/null
+++ b/drivers/misc/hisi_hikey_usb.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * hisi_hikey_usb.c
+ *
+ * Copyright (c) Hisilicon Tech. Co., Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/gpio/consumer.h>
+#include <linux/usb/role.h>
+#include <linux/notifier.h>
+
+#define DEVICE_DRIVER_NAME "hisi_hikey_usb"
+
+#define HUB_VBUS_POWER_ON 1
+#define HUB_VBUS_POWER_OFF 0
+#define USB_SWITCH_TO_HUB 1
+#define USB_SWITCH_TO_TYPEC 0
+
+struct hisi_hikey_usb {
+	struct gpio_desc *otg_switch;
+	struct gpio_desc *typec_vbus;
+	struct gpio_desc *hub_vbus;
+	int typec_vbus_enable_val;
+
+	struct usb_role_switch *role_sw;
+	struct notifier_block nb;
+};
+
+static void hub_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb, int value)
+{
+	pr_debug("%s: set hub power %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->hub_vbus, value);
+}
+
+static void usb_switch_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int switch_to)
+{
+	const char *switch_to_str = (switch_to == USB_SWITCH_TO_HUB) ?
+		"hub" : "typec";
+
+	pr_debug("%s: switch to %s\n", __func__, switch_to_str);
+	gpiod_set_value_cansleep(hisi_hikey_usb->otg_switch, switch_to);
+}
+
+static void usb_typec_power_ctrl(struct hisi_hikey_usb *hisi_hikey_usb,
+		int value)
+{
+	pr_debug("%s: set typec vbus gpio to %d\n", __func__, value);
+	gpiod_set_value_cansleep(hisi_hikey_usb->typec_vbus, value);
+}
+
+static int hisi_hikey_role_switch(struct notifier_block *nb,
+			unsigned long state, void *data)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb;
+
+	if (!nb)
+		return -EINVAL;
+
+	hisi_hikey_usb = container_of(nb, struct hisi_hikey_usb, nb);
+
+	pr_info("%s:set typec state to %lu\n", __func__, state);
+	switch (state) {
+	case USB_ROLE_NONE:
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_HUB);
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_ON);
+		break;
+	case USB_ROLE_HOST:
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				hisi_hikey_usb->typec_vbus_enable_val);
+		break;
+	case USB_ROLE_DEVICE:
+		hub_power_ctrl(hisi_hikey_usb, HUB_VBUS_POWER_OFF);
+		usb_typec_power_ctrl(hisi_hikey_usb,
+				!hisi_hikey_usb->typec_vbus_enable_val);
+		usb_switch_ctrl(hisi_hikey_usb, USB_SWITCH_TO_TYPEC);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static int hisi_hikey_usb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *root = dev->of_node;
+	struct hisi_hikey_usb *hisi_hikey_usb;
+	int ret;
+
+	hisi_hikey_usb = devm_kzalloc(dev, sizeof(*hisi_hikey_usb), GFP_KERNEL);
+	if (!hisi_hikey_usb)
+		return -ENOMEM;
+
+	hisi_hikey_usb->nb.notifier_call = hisi_hikey_role_switch;
+
+	ret = of_property_read_u32(root, "typc-vbus-enable-val",
+				   &hisi_hikey_usb->typec_vbus_enable_val);
+	if (ret) {
+		pr_info("%s: typc_vbus_enable_val can't get\n", __func__);
+		hisi_hikey_usb->typec_vbus_enable_val = 1;
+	}
+
+	hisi_hikey_usb->typec_vbus = devm_gpiod_get(dev, "typec-vbus",
+			hisi_hikey_usb->typec_vbus_enable_val ?
+			GPIOD_OUT_LOW : GPIOD_OUT_HIGH);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->typec_vbus)) {
+		if (!hisi_hikey_usb->typec_vbus)
+			ret = -EINVAL;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->typec_vbus);
+		return ret;
+	}
+
+	hisi_hikey_usb->otg_switch = devm_gpiod_get(dev, "otg-switch", GPIOD_IN);
+	if (IS_ERR(hisi_hikey_usb->otg_switch))
+		return PTR_ERR(hisi_hikey_usb->otg_switch);
+
+	hisi_hikey_usb->hub_vbus = devm_gpiod_get(dev, "hub-vdd33-en",
+			GPIOD_OUT_LOW);
+	if (IS_ERR(hisi_hikey_usb->hub_vbus))
+		return PTR_ERR(hisi_hikey_usb->hub_vbus);
+
+	hisi_hikey_usb->role_sw = usb_role_switch_get(dev);
+	if (IS_ERR_OR_NULL(hisi_hikey_usb->role_sw)) {
+		pr_err("%s: usb_role_switch_get failed\n", __func__);
+		if (!hisi_hikey_usb->role_sw)
+			ret = -ENOENT;
+		else
+			ret = PTR_ERR(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	ret = usb_role_switch_register_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+	if (ret) {
+		usb_role_switch_put(hisi_hikey_usb->role_sw);
+		return ret;
+	}
+
+	platform_set_drvdata(pdev, hisi_hikey_usb);
+
+	return 0;
+}
+
+static int  hisi_hikey_usb_remove(struct platform_device *pdev)
+{
+	struct hisi_hikey_usb *hisi_hikey_usb = platform_get_drvdata(pdev);
+
+	usb_role_switch_unregister_notifier(hisi_hikey_usb->role_sw,
+			&hisi_hikey_usb->nb);
+
+	usb_role_switch_put(hisi_hikey_usb->role_sw);
+
+	return 0;
+}
+
+static const struct of_device_id id_table_hisi_hikey_usb[] = {
+	{.compatible = "hisilicon,gpio_hubv1"},
+	{.compatible = "hisilicon,hikey960_usb"},
+	{}
+};
+
+static struct platform_driver  hisi_hikey_usb_driver = {
+	.probe = hisi_hikey_usb_probe,
+	.remove = hisi_hikey_usb_remove,
+	.driver = {
+		.name = DEVICE_DRIVER_NAME,
+		.of_match_table = of_match_ptr(id_table_hisi_hikey_usb),
+
+	},
+};
+
+module_platform_driver(hisi_hikey_usb_driver);
+
+MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
+MODULE_DESCRIPTION("Driver Support for USB functionality of Hikey");
+MODULE_LICENSE("GPL v2");

  parent reply	other threads:[~2018-12-03  3:46 UTC|newest]

Thread overview: 130+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-12-03  3:45 [PATCH v1 00/12] Add support for usb on Hikey960 Yu Chen
2018-12-03  3:45 ` Yu Chen
2018-12-03  3:45 ` [PATCH v1 01/12] dt-bindings: usb: add support for dwc3 controller on HiSilicon SoCs Yu Chen
2018-12-03  3:45   ` [v1,01/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 01/12] " Yu Chen
2018-12-03  8:35   ` Sergei Shtylyov
2018-12-03  8:35     ` [v1,01/12] " Sergei Shtylyov
2018-12-03  8:51     ` [PATCH v1 01/12] " Chen Yu
2018-12-03  8:51       ` [v1,01/12] " Yu Chen
2018-12-03  8:51       ` [PATCH v1 01/12] " Chen Yu
2018-12-03  8:59       ` Sergei Shtylyov
2018-12-03  8:59         ` [v1,01/12] " Sergei Shtylyov
2018-12-03  9:28         ` [PATCH v1 01/12] " Chen Yu
2018-12-03  9:28           ` [v1,01/12] " Yu Chen
2018-12-03  9:28           ` [PATCH v1 01/12] " Chen Yu
2018-12-19 14:09           ` Rob Herring
2018-12-19 14:09             ` [v1,01/12] " Rob Herring
2018-12-20  1:33             ` [PATCH v1 01/12] " Chen Yu
2018-12-20  1:33               ` [v1,01/12] " Yu Chen
2018-12-20  1:33               ` [PATCH v1 01/12] " Chen Yu
2018-12-20  6:46             ` Felipe Balbi
2018-12-20  6:46               ` [v1,01/12] " Felipe Balbi
2018-12-20 13:48               ` [PATCH v1 01/12] " Rob Herring
2018-12-20 13:48                 ` [v1,01/12] " Rob Herring
2018-12-03  3:45 ` [PATCH v1 02/12] dt-bindings: phy: Add support for HiSilicon's hi3660 USB PHY Yu Chen
2018-12-03  3:45   ` [v1,02/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 02/12] " Yu Chen
2018-12-19 14:14   ` Rob Herring
2018-12-19 14:14     ` [v1,02/12] " Rob Herring
2018-12-20  1:52     ` [PATCH v1 02/12] " Chen Yu
2018-12-20  1:52       ` [v1,02/12] " Yu Chen
2018-12-20  1:52       ` [PATCH v1 02/12] " Chen Yu
2018-12-03  3:45 ` [PATCH v1 03/12] dt-bindings: misc: Add bindings for HiSilicon usb hub and data role switch functionality on HiKey960 Yu Chen
2018-12-03  3:45   ` [v1,03/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 03/12] " Yu Chen
2018-12-19 14:21   ` Rob Herring
2018-12-19 14:21     ` [v1,03/12] " Rob Herring
2018-12-20  2:02     ` [PATCH v1 03/12] " Chen Yu
2018-12-20  2:02       ` [v1,03/12] " Yu Chen
2018-12-20  2:02       ` [PATCH v1 03/12] " Chen Yu
2018-12-03  3:45 ` [PATCH v1 04/12] usb: dwc3: dwc3-hisi: Add code for dwc3 of Hisilicon Soc Platform Yu Chen
2018-12-03  3:45   ` [v1,04/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 04/12] " Yu Chen
2018-12-03  8:12   ` Andy Shevchenko
2018-12-03  8:12     ` [v1,04/12] " Andy Shevchenko
2018-12-03  8:30     ` [PATCH v1 04/12] " Chen Yu
2018-12-03  8:30       ` [v1,04/12] " Yu Chen
2018-12-03  8:30       ` [PATCH v1 04/12] " Chen Yu
2018-12-03  3:45 ` [PATCH v1 05/12] usb: dwc3: Add two quirks for Hisilicon Kirin " Yu Chen
2018-12-03  3:45   ` [v1,05/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 05/12] " Yu Chen
2018-12-03  8:02   ` Andy Shevchenko
2018-12-03  8:02     ` [v1,05/12] " Andy Shevchenko
2018-12-03  8:23     ` [PATCH v1 05/12] " Chen Yu
2018-12-03  8:23       ` [v1,05/12] " Yu Chen
2018-12-03  8:23       ` [PATCH v1 05/12] " Chen Yu
2018-12-03  3:45 ` [PATCH v1 06/12] phy: Add usb phy support for hi3660 Soc of Hisilicon Yu Chen
2018-12-03  3:45   ` [v1,06/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 06/12] " Yu Chen
2018-12-03  8:14   ` Andy Shevchenko
2018-12-03  8:14     ` [v1,06/12] " Andy Shevchenko
2018-12-03  3:45 ` [PATCH v1 07/12] usb: roles: Find the usb role switch by also matching against the device node Yu Chen
2018-12-03  3:45   ` [v1,07/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 07/12] " Yu Chen
2018-12-03  8:17   ` Andy Shevchenko
2018-12-03  8:17     ` [v1,07/12] " Andy Shevchenko
2018-12-03 12:25     ` [PATCH v1 07/12] " Heikki Krogerus
2018-12-03 12:25       ` [v1,07/12] " Heikki Krogerus
2019-01-21  8:36       ` [PATCH v1 07/12] " Chen Yu
2019-01-21  8:36         ` [v1,07/12] " Yu Chen
2019-01-21  8:36         ` [PATCH v1 07/12] " Chen Yu
2019-01-21 13:51         ` Heikki Krogerus
2019-01-21 13:51           ` [v1,07/12] " Heikki Krogerus
2019-01-25 12:35           ` [PATCH v1 07/12] " Heikki Krogerus
2019-01-25 12:35             ` [v1,07/12] " Heikki Krogerus
2018-12-03  3:45 ` [PATCH v1 08/12] usb: roles: Add usb role switch notifier Yu Chen
2018-12-03  3:45   ` [v1,08/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 08/12] " Yu Chen
2018-12-03 12:38   ` Heikki Krogerus
2018-12-03 12:38     ` [v1,08/12] " Heikki Krogerus
2018-12-04  1:07     ` [PATCH v1 08/12] " Chen Yu
2018-12-04  1:07       ` [v1,08/12] " Yu Chen
2018-12-04  1:07       ` [PATCH v1 08/12] " Chen Yu
2018-12-03  3:45 ` [PATCH v1 09/12] usb: dwc3: Registering a role switch in the DRD code Yu Chen
2018-12-03  3:45   ` [v1,09/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 09/12] " Yu Chen
2018-12-03  9:15   ` Andy Shevchenko
2018-12-03  9:15     ` [v1,09/12] " Andy Shevchenko
2018-12-03  9:30     ` [PATCH v1 09/12] " Chen Yu
2018-12-03  9:30       ` [v1,09/12] " Yu Chen
2018-12-03  9:30       ` [PATCH v1 09/12] " Chen Yu
2018-12-03 12:43   ` Heikki Krogerus
2018-12-03 12:43     ` [v1,09/12] " Heikki Krogerus
2018-12-04 10:54   ` [PATCH v1 09/12] " Heikki Krogerus
2018-12-04 10:54     ` [v1,09/12] " Heikki Krogerus
2018-12-05  0:56     ` [PATCH v1 09/12] " Chen Yu
2018-12-05  0:56       ` [v1,09/12] " Yu Chen
2018-12-05  0:56       ` [PATCH v1 09/12] " Chen Yu
2018-12-03  3:45 ` Yu Chen [this message]
2018-12-03  3:45   ` [v1,10/12] hikey960: Support usb functionality of Hikey960 Yu Chen
2018-12-03  3:45   ` [PATCH v1 10/12] " Yu Chen
2018-12-03  9:23   ` Andy Shevchenko
2018-12-03  9:23     ` [v1,10/12] " Andy Shevchenko
2018-12-04  1:40     ` [PATCH v1 10/12] " Chen Yu
2018-12-04  1:40       ` [v1,10/12] " Yu Chen
2018-12-04  1:40       ` [PATCH v1 10/12] " Chen Yu
2018-12-04 17:47       ` Andy Shevchenko
2018-12-04 17:47         ` [v1,10/12] " Andy Shevchenko
2018-12-05  1:57         ` [PATCH v1 10/12] " Chen Yu
2018-12-05  1:57           ` [v1,10/12] " Yu Chen
2018-12-05  1:57           ` [PATCH v1 10/12] " Chen Yu
2018-12-05  8:44           ` Andy Shevchenko
2018-12-05  8:44             ` [v1,10/12] " Andy Shevchenko
2018-12-03  3:45 ` [PATCH v1 11/12] usb: gadget: Add configfs attribuite for controling match_existing_only Yu Chen
2018-12-03  3:45   ` [v1,11/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 11/12] " Yu Chen
2018-12-03  9:25   ` Andy Shevchenko
2018-12-03  9:25     ` [v1,11/12] " Andy Shevchenko
2018-12-04  1:22     ` [PATCH v1 11/12] " Chen Yu
2018-12-04  1:22       ` [v1,11/12] " Yu Chen
2018-12-04  1:22       ` [PATCH v1 11/12] " Chen Yu
2018-12-03  9:53   ` Krzysztof Opasiak
2018-12-03  9:53     ` [v1,11/12] " Krzysztof Opasiak
2018-12-03  3:45 ` [PATCH v1 12/12] dts: hi3660: Add support for usb on Hikey960 Yu Chen
2018-12-03  3:45   ` Yu Chen
2018-12-03  3:45   ` [v1,12/12] " Yu Chen
2018-12-03  3:45   ` [PATCH v1 12/12] " Yu Chen
2018-12-04 12:45   ` Heikki Krogerus
2018-12-04 12:45     ` Heikki Krogerus
2018-12-04 12:45     ` [v1,12/12] " Heikki Krogerus

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20181203034515.91412-11-chenyu56@huawei.com \
    --to=chenyu56@huawei.com \
    --cc=arnd@arndb.de \
    --cc=devicetree@vger.kernel.org \
    --cc=gregkh@linuxfoundation.org \
    --cc=heikki.krogerus@linux.intel.com \
    --cc=john.stultz@linaro.org \
    --cc=kongfei@hisilicon.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=suzhuangluan@hisilicon.com \
    --cc=wangbinghui@hisilicon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.