diff --git a/drivers/misc/hisi_hikey_usb.c b/drivers/misc/hisi_hikey_usb.c index 5951bbda91f5..592f3023929a 100644 --- a/drivers/misc/hisi_hikey_usb.c +++ b/drivers/misc/hisi_hikey_usb.c @@ -18,6 +18,7 @@ #include #include #include +#include #define DEVICE_DRIVER_NAME "hisi_hikey_usb" @@ -39,6 +40,8 @@ struct gpio_hub_info { int typec_vbus_gpio; int typec_vbus_enable_val; int hub_vbus_gpio; + int hub_reset_en_gpio; + struct regulator *hub_regu; }; static struct gpio_hub_info gpio_hub_driver_info = { @@ -46,28 +49,43 @@ static struct gpio_hub_info gpio_hub_driver_info = { .typec_vbus_gpio = -1, .typec_vbus_enable_val = -1, .hub_vbus_gpio = -1, + .hub_regu = NULL, }; 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); + int gpio = gpio_hub_driver_info.hub_vbus_gpio; + int ret; + + if (gpio_is_valid(gpio)) { + gpio_set_value(gpio, GPIO_HUB_VBUS_NO_POWER); pr_info("%s: gpio hub hub vbus no power set success", __func__); - } else - pr_err("%s: gpio hub hub vbus no power set err", - __func__); + } + if (gpio_hub_driver_info.hub_regu && + regulator_is_enabled(gpio_hub_driver_info.hub_regu)) { + ret = regulator_disable(gpio_hub_driver_info.hub_regu); + if (ret) + pr_err("disable hub regulator failed"); + } } 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 - pr_err("%s: gpio hub hub vbus set err", __func__); + int gpio = gpio_hub_driver_info.hub_vbus_gpio; + int ret; + + if (gpio_is_valid(gpio)) + gpio_set_value(gpio, GPIO_HUB_VBUS_POWER); + + if (gpio_hub_driver_info.hub_regu && + !regulator_is_enabled(gpio_hub_driver_info.hub_regu)) { + pr_err("%s:regulator_enable\n", __func__); + ret = regulator_enable(gpio_hub_driver_info.hub_regu); + if (ret) + pr_err("enable hub regulator failed"); + } } void gpio_hub_switch_to_hub(void) @@ -147,24 +165,64 @@ 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; + struct regulator *hub_regu; pr_info("%s: step in\n", __func__); info->pdev = pdev; - info->hub_vbus_gpio = of_get_named_gpio(root, "hub_vdd33_en_gpio", 0); - if (!gpio_is_valid(info->hub_vbus_gpio)) { - pr_err("%s: hub_vbus_gpio is err\n", __func__); - return -EINVAL; - } - ret = gpio_request(info->hub_vbus_gpio, "hub_vbus_int_gpio"); - if (ret) { - pr_err("%s: request hub_vbus_gpio err\n", __func__); - return ret; + if (!pdev) + return -EBUSY; + + if (of_device_is_compatible(root, "hisilicon,kirin970_hikey_usbhub")) { + hub_regu = devm_regulator_get(&pdev->dev, "hub-vdd"); + if (IS_ERR(hub_regu)) { + dev_err(&pdev->dev, "get hub-vdd-supply failed\n"); + return PTR_ERR(hub_regu); + } + info->hub_regu = hub_regu; + ret = regulator_set_voltage(info->hub_regu, 3300000, 3300000); + if (ret) + dev_err(&pdev->dev, "set hub-vdd-supply voltage failed\n"); + + info->hub_reset_en_gpio = of_get_named_gpio(root, "hub_reset_en_gpio", 0); + if (!gpio_is_valid(info->hub_reset_en_gpio)) { + pr_err("%s: hub_reset_en_gpio is err\n", __func__); + return info->hub_reset_en_gpio; + } + + ret = gpio_request(info->hub_reset_en_gpio, "hub_reset_en_gpio"); + if (ret) { + pr_err("%s: request hub_reset_en_gpio err\n", __func__); + return ret; + } + ret = gpio_direction_output(info->hub_reset_en_gpio, 1); + if (ret) { + pr_err("%s: set hub_reset_en_gpio 1 err\n", __func__); + goto free_gpio1; + } + } else { + info->hub_vbus_gpio = of_get_named_gpio(root, "hub_vdd33_en_gpio", 0); + if (!gpio_is_valid(info->hub_vbus_gpio)) { + pr_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) { + pr_err("%s: request hub_vbus_gpio err\n", __func__); + return ret; + } + + ret = gpio_direction_output(info->hub_vbus_gpio, GPIO_HUB_VBUS_POWER); + if (ret) { + pr_err("%s: power on hub vbus err\n", __func__); + goto free_gpio1; + } } info->typec_vbus_gpio = of_get_named_gpio(root, "typc_vbus_int_gpio,typec-gpios", 0); - if (!gpio_is_valid(info->hub_vbus_gpio)) { + if (!gpio_is_valid(info->typec_vbus_gpio)) { pr_err("%s: typec_vbus_gpio is err\n", __func__); ret = info->typec_vbus_gpio; goto free_gpio1; @@ -181,21 +239,9 @@ static int gpio_hub_probe(struct platform_device *pdev) pr_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)) { - pr_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) { - pr_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) { @@ -203,19 +249,40 @@ static int gpio_hub_probe(struct platform_device *pdev) goto free_gpio2; } + if (!of_device_is_compatible(root, "hisilicon,gpio_hubv1")) { + info->otg_switch_gpio = of_get_named_gpio(root, "otg_gpio", 0); + if (!gpio_is_valid(info->otg_switch_gpio)) { + pr_info("%s: otg_switch_gpio is err\n", __func__); + info->otg_switch_gpio = -1; + } + + ret = gpio_request(info->otg_switch_gpio, "otg_switch_gpio"); + if (ret) { + pr_err("%s: request typec_vbus_gpio err\n", __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; + if (gpio_is_valid(info->hub_vbus_gpio)) { + gpio_free(info->hub_vbus_gpio); + info->hub_vbus_gpio = -1; + } + + if (gpio_is_valid(info->hub_reset_en_gpio)) { + gpio_free(info->hub_reset_en_gpio); + info->hub_reset_en_gpio= -1; + } return ret; } -static int gpio_hub_remove(struct platform_device *pdev) +static int gpio_hub_remove(struct platform_device *pdev) { struct gpio_hub_info *info = &gpio_hub_driver_info; @@ -239,6 +306,7 @@ static int gpio_hub_remove(struct platform_device *pdev) static const struct of_device_id id_table_for_gpio_hub[] = { {.compatible = "hisilicon,gpio_hubv1"}, {.compatible = "hisilicon,gpio_hubv2"}, + {.compatible = "hisilicon,kirin970_hikey_usbhub"}, {} }; @@ -269,5 +337,5 @@ module_init(gpio_hub_init); module_exit(gpio_hub_exit); MODULE_AUTHOR("wangbinghui"); -MODULE_DESCRIPTION("HUB GPIO FOR OTG ID driver"); +MODULE_DESCRIPTION("Driver Support for USB functionality of Hikey"); MODULE_LICENSE("GPL v2");