usb: add hub_usb5734 driver for hikey960
authorFan Ning <fanning4@hisilicon.com>
Tue, 6 Jun 2017 08:59:32 +0000 (16:59 +0800)
committerDouglas RAILLARD <douglas.raillard@arm.com>
Tue, 14 Aug 2018 15:32:09 +0000 (16:32 +0100)
Signed-off-by: Fan Ning <fanning4@hisilicon.com>
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/microchip/Kconfig [new file with mode: 0644]
drivers/misc/microchip/Makefile [new file with mode: 0644]
drivers/misc/microchip/hub/Kconfig [new file with mode: 0644]
drivers/misc/microchip/hub/Makefile [new file with mode: 0644]
drivers/misc/microchip/hub/hub_usb5734.c [new file with mode: 0644]
include/linux/hisi/usb/hub/hisi_hub.h [new file with mode: 0644]

index 3726eacdf65de2470ba83c6a91dc3351f69ea713..5862580b759cbcec886d06a368e71b78493a8571 100644 (file)
@@ -527,4 +527,5 @@ source "drivers/misc/echo/Kconfig"
 source "drivers/misc/cxl/Kconfig"
 source "drivers/misc/ocxl/Kconfig"
 source "drivers/misc/cardreader/Kconfig"
+source "drivers/misc/microchip/Kconfig"
 endmenu
index af22bbc3d00cbcd248c4e10247b87bbb46ecab3f..e16bb8f48116d72985efe6e1c33a41e7c0d70642 100644 (file)
@@ -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-y       += microchip/
diff --git a/drivers/misc/microchip/Kconfig b/drivers/misc/microchip/Kconfig
new file mode 100644 (file)
index 0000000..9e4e4cd
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Microchip devices
+#
+
+menu "Microchip devices"
+source "drivers/misc/microchip/hub/Kconfig"
+endmenu
diff --git a/drivers/misc/microchip/Makefile b/drivers/misc/microchip/Makefile
new file mode 100644 (file)
index 0000000..cc71719
--- /dev/null
@@ -0,0 +1,4 @@
+#
+# Makefile for microchip devices that really don't fit anywhere else.
+#
+obj-y          += hub/
\ No newline at end of file
diff --git a/drivers/misc/microchip/hub/Kconfig b/drivers/misc/microchip/hub/Kconfig
new file mode 100644 (file)
index 0000000..258be00
--- /dev/null
@@ -0,0 +1,6 @@
+config HUB_USB5734
+    tristate "HUB_USB5734"
+    depends on GPIOLIB
+    default n
+    help
+       If you say yes here you get support for HUB_USB5734.
diff --git a/drivers/misc/microchip/hub/Makefile b/drivers/misc/microchip/hub/Makefile
new file mode 100644 (file)
index 0000000..3ff884c
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_HUB_USB5734) +=hub_usb5734.o
diff --git a/drivers/misc/microchip/hub/hub_usb5734.c b/drivers/misc/microchip/hub/hub_usb5734.c
new file mode 100644 (file)
index 0000000..e71c993
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * otgid_gpio_hub.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/i2c.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/timer.h>
+#include <linux/param.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/workqueue.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/hisi/log/hisi_log.h>
+#include <linux/hisi/usb/hisi_usb.h>
+#include <linux/tifm.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/hisi/usb/hub/hisi_hub.h>
+#define DEVICE_DRIVER_NAME "gpio_hub_for_usb5734"
+
+#define GPIO_HUB_OTG_HOST 1
+#define GPIO_HUB_OTG_DEVICE 0
+#define GPIO_TYPEC_VBUS_POWER 1
+#define GPIO_TYPEC_NO_POWER 0
+#define GPIO_HUB_VBUS_POWER 1
+#define GPIO_HUB_VBUS_NO_POWER 0
+#define GPIO_HUB_HUB_VBUS_POWER 1
+
+/* SOC_CRGPERIPH_PEREN1_UNION */
+#define SOC_CRGPERIPH_PEREN1_ADDR(base)               ((base) + (0x010))
+
+#define HISILOG_TAG GPIO_HUB
+HISILOG_REGIST();
+
+struct gpio_hub_info {
+       struct platform_device *pdev;
+       int otg_switch_gpio;
+       int typec_vbus_gpio;
+       int typec_vbus_enable_val;
+       int hub_vbus_gpio;
+};
+
+static struct gpio_hub_info gpio_hub_driver_info = {
+       .otg_switch_gpio = -1,
+       .typec_vbus_gpio = -1,
+       .typec_vbus_enable_val = -1,
+       .hub_vbus_gpio = -1,
+};
+
+void gpio_hub_power_off(void)
+{
+       if (gpio_is_valid(gpio_hub_driver_info.hub_vbus_gpio)) {
+               gpio_set_value(gpio_hub_driver_info.hub_vbus_gpio,
+                              GPIO_HUB_VBUS_NO_POWER);
+               hisilog_info("%s: gpio hub hub vbus no power set success",
+                            __func__);
+       } else {
+               hisilog_err("%s: gpio hub hub vbus no power set err",
+                           __func__);
+       }
+}
+
+void gpio_hub_power_on(void)
+{
+       if (gpio_is_valid(gpio_hub_driver_info.hub_vbus_gpio))
+               gpio_set_value(gpio_hub_driver_info.hub_vbus_gpio,
+                              GPIO_HUB_VBUS_POWER);
+       else
+               hisilog_err("%s: gpio hub hub vbus set err", __func__);
+}
+
+void gpio_hub_switch_to_hub(void)
+{
+       int gpio = gpio_hub_driver_info.otg_switch_gpio;
+
+       if (!gpio_is_valid(gpio)) {
+               hisilog_err("%s: otg_switch_gpio is err\n", __func__);
+               return;
+       }
+
+       if (gpio_get_value(gpio)) {
+               hisilog_info("%s: already switch to hub\n", __func__);
+               return;
+       }
+
+       gpio_direction_output(gpio, 1);
+       hisilog_err("%s: switch to hub\n", __func__);
+}
+EXPORT_SYMBOL_GPL(gpio_hub_switch_to_hub);
+
+void gpio_hub_switch_to_typec(void)
+{
+       int gpio = gpio_hub_driver_info.otg_switch_gpio;
+
+       if (!gpio_is_valid(gpio)) {
+               hisilog_err("%s: otg_switch_gpio is err\n", __func__);
+               return;
+       }
+
+       if (!gpio_get_value(gpio)) {
+               hisilog_info("%s: already switch to typec\n", __func__);
+               return;
+       }
+
+       gpio_direction_output(gpio, 0);
+       hisilog_err("%s: switch to typec\n", __func__);
+}
+EXPORT_SYMBOL_GPL(gpio_hub_switch_to_typec);
+
+static void gpio_hub_change_typec_power(int gpio, int on)
+{
+       if (!gpio_is_valid(gpio)) {
+               hisilog_err("%s: typec power gpio is err\n", __func__);
+               return;
+       }
+
+       if (gpio_get_value(gpio) == on) {
+               hisilog_info("%s: typec power no change\n", __func__);
+               return;
+       }
+
+       gpio_direction_output(gpio, on);
+       hisilog_info("%s: set typec vbus gpio to %d\n", __func__, on);
+}
+
+void gpio_hub_typec_power_on(void)
+{
+       struct gpio_hub_info *info = &gpio_hub_driver_info;
+
+       gpio_hub_change_typec_power(info->typec_vbus_gpio,
+                                   info->typec_vbus_enable_val);
+}
+EXPORT_SYMBOL_GPL(gpio_hub_typec_power_on);
+
+void gpio_hub_typec_power_off(void)
+{
+       struct gpio_hub_info *info = &gpio_hub_driver_info;
+
+       gpio_hub_change_typec_power(info->typec_vbus_gpio,
+                                   !info->typec_vbus_enable_val);
+}
+EXPORT_SYMBOL_GPL(gpio_hub_typec_power_off);
+
+static int gpio_hub_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct device_node *root = pdev->dev.of_node;
+       struct gpio_hub_info *info = &gpio_hub_driver_info;
+
+       hisilog_info("%s: step in\n", __func__);
+
+       info->pdev = pdev;
+       if (!pdev)
+               return -EBUSY;
+
+       info->hub_vbus_gpio = of_get_named_gpio(root, "hub_vdd33_en_gpio", 0);
+       if (!gpio_is_valid(info->hub_vbus_gpio)) {
+               hisilog_err("%s: hub_vbus_gpio is err\n", __func__);
+               return info->hub_vbus_gpio;
+       }
+       ret = gpio_request(info->hub_vbus_gpio, "hub_vbus_int_gpio");
+       if (ret) {
+               hisilog_err("%s: request hub_vbus_gpio err\n", __func__);
+               return ret;
+       }
+
+       info->typec_vbus_gpio = of_get_named_gpio(root,
+               "typc_vbus_int_gpio,typec-gpios", 0);
+       if (!gpio_is_valid(info->hub_vbus_gpio)) {
+               hisilog_err("%s: typec_vbus_gpio is err\n", __func__);
+               ret = info->typec_vbus_gpio;
+               goto free_gpio1;
+       }
+       ret = gpio_request(info->typec_vbus_gpio, "typc_vbus_int_gpio");
+       if (ret) {
+               hisilog_err("%s: request typec_vbus_gpio err\n", __func__);
+               goto free_gpio1;
+       }
+
+       ret = of_property_read_u32(root, "typc_vbus_enable_val",
+                                  &info->typec_vbus_enable_val);
+       if (ret) {
+               hisilog_err("%s: typc_vbus_enable_val can't get\n", __func__);
+               goto free_gpio2;
+       }
+       info->typec_vbus_enable_val = !!info->typec_vbus_enable_val;
+
+       /* only for v2 */
+       info->otg_switch_gpio = of_get_named_gpio(root, "otg_gpio", 0);
+       if (!gpio_is_valid(info->otg_switch_gpio)) {
+               hisilog_info("%s: otg_switch_gpio is err\n", __func__);
+               info->otg_switch_gpio = -1;
+       }
+
+       ret = gpio_direction_output(info->hub_vbus_gpio, GPIO_HUB_VBUS_POWER);
+       if (ret) {
+               hisilog_err("%s: power on hub vbus err\n", __func__);
+               goto free_gpio2;
+       }
+
+       ret = gpio_direction_output(info->typec_vbus_gpio,
+                                   info->typec_vbus_enable_val);
+       if (ret) {
+               hisilog_err("%s: power on typec vbus err", __func__);
+               goto free_gpio2;
+       }
+
+       return 0;
+
+free_gpio2:
+       gpio_free(info->typec_vbus_gpio);
+       info->typec_vbus_gpio = -1;
+free_gpio1:
+       gpio_free(info->hub_vbus_gpio);
+       info->hub_vbus_gpio = -1;
+
+       return ret;
+}
+
+static int  gpio_hub_remove(struct platform_device *pdev)
+{
+       struct gpio_hub_info *info = &gpio_hub_driver_info;
+
+       if (gpio_is_valid(info->otg_switch_gpio)) {
+               gpio_free(info->otg_switch_gpio);
+               info->otg_switch_gpio = -1;
+       }
+
+       if (gpio_is_valid(info->typec_vbus_gpio)) {
+               gpio_free(info->typec_vbus_gpio);
+               info->typec_vbus_gpio = -1;
+       }
+
+       if (gpio_is_valid(info->hub_vbus_gpio)) {
+               gpio_free(info->hub_vbus_gpio);
+               info->hub_vbus_gpio = -1;
+       }
+       return 0;
+}
+
+static const struct of_device_id id_table_for_gpio_hub[] = {
+       {.compatible = "hisilicon,gpio_hubv1"},
+       {.compatible = "hisilicon,gpio_hubv2"},
+       {}
+};
+
+static struct platform_driver gpio_hub_driver = {
+       .probe = gpio_hub_probe,
+       .remove = gpio_hub_remove,
+       .driver = {
+               .name = DEVICE_DRIVER_NAME,
+               .of_match_table = of_match_ptr(id_table_for_gpio_hub),
+
+       },
+};
+
+static int __init gpio_hub_init(void)
+{
+       int ret = platform_driver_register(&gpio_hub_driver);
+
+       hisilog_info("%s:gpio hub init status:%d\n", __func__, ret);
+       return ret;
+}
+
+static void __exit gpio_hub_exit(void)
+{
+       platform_driver_unregister(&gpio_hub_driver);
+}
+
+module_init(gpio_hub_init);
+module_exit(gpio_hub_exit);
+
+MODULE_AUTHOR("wangbinghui<wangbinghui@hisilicon.com>");
+MODULE_DESCRIPTION("HUB GPIO FOR OTG ID driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/hisi/usb/hub/hisi_hub.h b/include/linux/hisi/usb/hub/hisi_hub.h
new file mode 100644 (file)
index 0000000..99df577
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * hub_usb5734.h
+ *
+ * Copyright (c) Hisilicon Tech. Co., Ltd. All rights reserved.
+ *
+ * Chenjun <chenjun@hisilicon.com>
+ *
+ * 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.
+ *
+ */
+void gpio_hub_power_on(void);
+void gpio_hub_power_off(void);
+void gpio_hub_switch_to_hub(void);
+void gpio_hub_switch_to_typec(void);
+void gpio_hub_typec_power_off(void);
+void gpio_hub_typec_power_on(void);