All of lore.kernel.org
 help / color / mirror / Atom feed
* [V2,7/8] usb: gadget: Add UDC driver for tegra XUSB device mode controller
@ 2019-05-03 14:22 ` Thierry Reding
  0 siblings, 0 replies; 27+ messages in thread
From: Thierry Reding @ 2019-05-03 14:22 UTC (permalink / raw)
  To: Nagarjuna Kristam; +Cc: balbi, gregkh, jonathanh, linux-tegra, linux-usb

On Mon, Mar 11, 2019 at 04:41:55PM +0530, Nagarjuna Kristam wrote:
> This patch adds UDC driver for tegra XUSB 3.0 device mode controller.

s/tegra/Tegra/

> XUSB device mode controller support SS, HS and FS modes

s/support/supports/ and terminate the sentence with a full-stop.

> 
> Based on work by:
>   Mark Kuo <mkuo@nvidia.com>
>   Andrew Bresticker <abrestic@chromium.org>
> 
> Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
> ---
>  drivers/usb/gadget/udc/Kconfig      |   10 +
>  drivers/usb/gadget/udc/Makefile     |    1 +
>  drivers/usb/gadget/udc/tegra_xudc.c | 3702 +++++++++++++++++++++++++++++++++++
>  3 files changed, 3713 insertions(+)
>  create mode 100644 drivers/usb/gadget/udc/tegra_xudc.c
> 
> diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
> index 0a16cbd..f6f469c 100644
> --- a/drivers/usb/gadget/udc/Kconfig
> +++ b/drivers/usb/gadget/udc/Kconfig
> @@ -439,6 +439,16 @@ config USB_GADGET_XILINX
>  	  dynamically linked module called "udc-xilinx" and force all
>  	  gadget drivers to also be dynamically linked.
>  
> +config USB_TEGRA_XUDC
> +	tristate "NVIDIA Superspeed USB 3.0 Device Controller"

NVIDIA Tegra? Not sure if this is available anywhere else.

> +	depends on ARCH_TEGRA
> +	help
> +	 Enables TEGRA USB 3.0 device mode controller driver.

NVIDIA Tegra here, too.

> +
> +	 Say "y" to link the driver statically, or "m" to build a
> +	 dynamically linked module called "tegra_xudc" and force all
> +	 gadget drivers to also be dynamically linked.
> +
>  source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig"
>  
>  #
> diff --git a/drivers/usb/gadget/udc/Makefile b/drivers/usb/gadget/udc/Makefile
> index 897f648..1c55c96 100644
> --- a/drivers/usb/gadget/udc/Makefile
> +++ b/drivers/usb/gadget/udc/Makefile
> @@ -24,6 +24,7 @@ obj-$(CONFIG_USB_BCM63XX_UDC)	+= bcm63xx_udc.o
>  obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
>  fsl_usb2_udc-y			:= fsl_udc_core.o
>  fsl_usb2_udc-$(CONFIG_ARCH_MXC)	+= fsl_mxc_udc.o
> +obj-$(CONFIG_USB_TEGRA_XUDC)	+= tegra_xudc.o
>  obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
>  obj-$(CONFIG_USB_R8A66597)	+= r8a66597-udc.o
>  obj-$(CONFIG_USB_RENESAS_USB3)	+= renesas_usb3.o
> diff --git a/drivers/usb/gadget/udc/tegra_xudc.c b/drivers/usb/gadget/udc/tegra_xudc.c
> new file mode 100644
> index 0000000..70beda0
> --- /dev/null
> +++ b/drivers/usb/gadget/udc/tegra_xudc.c
> @@ -0,0 +1,3702 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * NVIDIA XUSB device mode controller

Again, perhaps mention that this is for Tegra.

I didn't find anything that stood out in most of the driver. Below are a
couple of things towards the end that I think you should look at.

Generally I thought it was fairly difficult to read. You may want to see
if you can improve readability by adding a bit of whitespace where
appropriate. For example, try to leave a blank line above and below
block elements, such as conditionals or loops. I find that that helps a
lot in making the code easier to read.

See below for an example.

[...]
> +static int tegra_xudc_probe(struct platform_device *pdev)
> +{
> +	struct tegra_xudc *xudc;
> +	struct resource *res;
> +	unsigned int i;
> +	int err;
> +
> +	xudc = devm_kzalloc(&pdev->dev, sizeof(*xudc), GFP_ATOMIC);
> +	if (!xudc)
> +		return -ENOMEM;
> +	xudc->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, xudc);

This, for example, would be easier to read as:

	xudc = devm_kzalloc(&pdev->dev, sizeof(*xudc), GFP_ATOMIC);
	if (!xudc)
		return -ENOMEM;

	platform_set_drvdata(pdev, xudc);
	xudc->dev = &pdev->dev;

> +
> +	xudc->soc = of_device_get_match_data(&pdev->dev);
> +	if (!xudc->soc)
> +		return -ENODEV;

This situation can never happen. The driver is only ever instantiated
from device tree, in which case xudc->soc will be a valid pointer to the
correct SoC data structure.

> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	xudc->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(xudc->base))
> +		return PTR_ERR(xudc->base);
> +	xudc->phys_base = res->start;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
> +	xudc->fpci = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(xudc->fpci))
> +		return PTR_ERR(xudc->fpci);
> +
> +	if (xudc->soc->has_ipfs) {
> +		res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
> +		xudc->ipfs = devm_ioremap_resource(&pdev->dev, res);
> +		if (IS_ERR(xudc->ipfs))
> +			return PTR_ERR(xudc->ipfs);
> +	}
> +
> +	xudc->irq = platform_get_irq(pdev, 0);
> +	if (xudc->irq < 0) {
> +		dev_err(xudc->dev, "failed to get IRQ: %d\n",
> +				xudc->irq);
> +		return xudc->irq;
> +	}
> +	err = devm_request_irq(&pdev->dev, xudc->irq, tegra_xudc_irq, 0,
> +			       dev_name(&pdev->dev), xudc);
> +	if (err < 0) {
> +		dev_err(xudc->dev, "failed to claim IRQ#%u: %d\n", xudc->irq,
> +			err);
> +		return err;
> +	}
> +
> +	xudc->clks = devm_kcalloc(&pdev->dev, xudc->soc->num_clks,
> +				      sizeof(*xudc->clks), GFP_KERNEL);
> +	if (!xudc->clks)
> +		return -ENOMEM;
> +	for (i = 0; i < xudc->soc->num_clks; i++)
> +		xudc->clks[i].id = xudc->soc->clock_names[i];
> +	err = devm_clk_bulk_get(&pdev->dev, xudc->soc->num_clks,
> +				      xudc->clks);
> +	if (err) {
> +		dev_err(xudc->dev, "failed to request clks %d\n", err);
> +		return err;
> +	}
> +
> +	xudc->supplies = devm_kcalloc(&pdev->dev, xudc->soc->num_supplies,
> +				      sizeof(*xudc->supplies), GFP_KERNEL);
> +	if (!xudc->supplies)
> +		return -ENOMEM;
> +	for (i = 0; i < xudc->soc->num_supplies; i++)
> +		xudc->supplies[i].supply = xudc->soc->supply_names[i];
> +	err = devm_regulator_bulk_get(&pdev->dev, xudc->soc->num_supplies,
> +				      xudc->supplies);
> +	if (err) {
> +		dev_err(xudc->dev, "failed to request regulators %d\n", err);
> +		return err;
> +	}
> +
> +	xudc->padctl = tegra_xusb_padctl_get(&pdev->dev);
> +	if (IS_ERR(xudc->padctl))
> +		return PTR_ERR(xudc->padctl);
> +
> +	err = regulator_bulk_enable(xudc->soc->num_supplies, xudc->supplies);
> +	if (err) {
> +		dev_err(xudc->dev, "failed to enable regulators %d\n", err);
> +		goto put_padctl;
> +	}
> +
> +	xudc->usb3_phy = devm_phy_optional_get(&pdev->dev, "usb3");
> +	if (IS_ERR(xudc->usb3_phy)) {
> +		err = PTR_ERR(xudc->usb3_phy);
> +		dev_err(xudc->dev, "failed to get usb3 phy: %d\n", err);
> +		goto disable_regulator;
> +	}
> +	xudc->utmi_phy = devm_phy_optional_get(&pdev->dev, "usb2");
> +	if (IS_ERR(xudc->utmi_phy)) {
> +		err = PTR_ERR(xudc->utmi_phy);
> +		dev_err(xudc->dev, "failed to get usb2 phy: %d\n", err);
> +		goto disable_regulator;
> +	}
> +
> +	xudc->data_role_extcon = extcon_get_edev_by_phandle(&pdev->dev, 0);
> +	if (IS_ERR(xudc->data_role_extcon)) {
> +		err = PTR_ERR(xudc->data_role_extcon);
> +		dev_err(xudc->dev, "extcon_get_edev_by_phandle failed %d\n",
> +				err);
> +		goto disable_regulator;
> +	}
> +
> +	err = tegra_xudc_powerdomain_init(xudc);
> +	if (err)
> +		goto put_powerdomains;
> +
> +	err = tegra_xudc_phy_init(xudc);
> +	if (err)
> +		goto put_powerdomains;
> +
> +	err = tegra_xudc_alloc_event_ring(xudc);
> +	if (err)
> +		goto disable_phy;
> +
> +	err = tegra_xudc_alloc_eps(xudc);
> +	if (err)
> +		goto free_event_ring;
> +
> +	spin_lock_init(&xudc->lock);
> +	init_completion(&xudc->disconnect_complete);
> +
> +	INIT_WORK(&xudc->data_role_work, tegra_xudc_data_role_work);
> +	xudc->data_role_nb.notifier_call = tegra_xudc_data_role_notifier;
> +	extcon_register_notifier(xudc->data_role_extcon, EXTCON_USB,
> +				 &xudc->data_role_nb);
> +
> +	INIT_DELAYED_WORK(&xudc->plc_reset_work, tegra_xudc_plc_reset_work);
> +
> +	INIT_DELAYED_WORK(&xudc->port_reset_war_work,
> +				tegra_xudc_port_reset_war_work);
> +
> +	pm_runtime_enable(&pdev->dev);
> +
> +	xudc->gadget.ops = &tegra_xudc_gadget_ops;
> +	xudc->gadget.ep0 = &xudc->ep[0].usb_ep;
> +	xudc->gadget.name = "tegra-xudc";
> +	xudc->gadget.max_speed = USB_SPEED_SUPER;
> +
> +	err = usb_add_gadget_udc(&pdev->dev, &xudc->gadget);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to add USB gadget: %d\n", err);
> +		goto free_eps;
> +	}
> +
> +	tegra_xudc_update_data_role(xudc);
> +
> +	return 0;
> +
> +free_eps:
> +	tegra_xudc_free_eps(xudc);
> +free_event_ring:
> +	tegra_xudc_free_event_ring(xudc);
> +disable_phy:
> +	tegra_xudc_phy_exit(xudc);
> +put_powerdomains:
> +	tegra_xudc_powerdomain_remove(xudc);
> +disable_regulator:
> +	regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
> +put_padctl:
> +	tegra_xusb_padctl_put(xudc->padctl);
> +
> +	return err;
> +}
> +
> +static int tegra_xudc_remove(struct platform_device *pdev)
> +{
> +	struct tegra_xudc *xudc = platform_get_drvdata(pdev);
> +
> +	pm_runtime_get_sync(xudc->dev);
> +
> +	cancel_delayed_work(&xudc->plc_reset_work);
> +	if (xudc->data_role_extcon) {
> +		extcon_unregister_notifier(xudc->data_role_extcon, EXTCON_USB,
> +				&xudc->data_role_nb);
> +		cancel_work_sync(&xudc->data_role_work);
> +	}
> +	usb_del_gadget_udc(&xudc->gadget);
> +	tegra_xudc_free_eps(xudc);
> +	tegra_xudc_free_event_ring(xudc);
> +	tegra_xudc_powerdomain_remove(xudc);
> +
> +	regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
> +
> +	phy_power_off(xudc->utmi_phy);
> +	phy_power_off(xudc->usb3_phy);
> +	tegra_xudc_phy_exit(xudc);
> +	pm_runtime_disable(xudc->dev);
> +	pm_runtime_put(xudc->dev);
> +
> +	tegra_xusb_padctl_put(xudc->padctl);
> +
> +	return 0;
> +}
> +
> +#if IS_ENABLED(CONFIG_PM_SLEEP) || IS_ENABLED(CONFIG_PM)

I'd drop these and instead annotate with __maybe_unused. We no longer
support building Tegra without PM, so this is mostly academic anyway.

> +static int tegra_xudc_powergate(struct tegra_xudc *xudc)
> +{
> +	unsigned long flags;
> +
> +	dev_info(xudc->dev, "entering ELPG\n");

There's a couple of dev_info() calls throughout the driver that I think
are too noisy. I think most of those should be dev_dbg() so that users
aren't bothered with them. In cases where you really want to highlight
an error or something, make them dev_err() or dev_warn().

> +	spin_lock_irqsave(&xudc->lock, flags);
> +	xudc->powergated = true;
> +	xudc->saved_regs.ctrl = xudc_readl(xudc, CTRL);
> +	xudc->saved_regs.portpm = xudc_readl(xudc, PORTPM);
> +	xudc_writel(xudc, 0, CTRL);
> +	spin_unlock_irqrestore(&xudc->lock, flags);
> +
> +	clk_bulk_disable_unprepare(xudc->soc->num_clks, xudc->clks);
> +	regulator_bulk_disable(xudc->soc->num_supplies, xudc->supplies);
> +
> +	dev_info(xudc->dev, "entering ELPG done\n");
> +	return 0;
> +}
> +
> +static int tegra_xudc_unpowergate(struct tegra_xudc *xudc)
> +{
> +	unsigned long flags;
> +	int err;
> +
> +	dev_info(xudc->dev, "exiting ELPG\n");
> +
> +	err = regulator_bulk_enable(xudc->soc->num_supplies,
> +			xudc->supplies);
> +	if (err < 0)
> +		return err;
> +
> +

Gratuituous blank line.

> +	err = clk_bulk_prepare_enable(xudc->soc->num_clks, xudc->clks);
> +	if (err < 0)
> +		return err;
> +
> +	tegra_xudc_fpci_ipfs_init(xudc);
> +	tegra_xudc_device_params_init(xudc);
> +
> +	tegra_xudc_init_event_ring(xudc);
> +	tegra_xudc_init_eps(xudc);
> +
> +	xudc_writel(xudc, xudc->saved_regs.portpm, PORTPM);
> +	xudc_writel(xudc, xudc->saved_regs.ctrl, CTRL);
> +
> +	spin_lock_irqsave(&xudc->lock, flags);
> +	xudc->powergated = false;
> +	spin_unlock_irqrestore(&xudc->lock, flags);
> +
> +	dev_info(xudc->dev, "exiting ELPG done\n");
> +	return 0;
> +}
> +#endif
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int tegra_xudc_suspend(struct device *dev)
> +{
> +	struct tegra_xudc *xudc = dev_get_drvdata(dev);
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&xudc->lock, flags);
> +	xudc->suspended = true;
> +	spin_unlock_irqrestore(&xudc->lock, flags);
> +
> +	if (xudc->data_role_extcon)
> +		flush_work(&xudc->data_role_work);
> +
> +	/* Forcibly disconnect before powergating. */
> +	tegra_xudc_device_mode_off(xudc);
> +
> +	if (!pm_runtime_status_suspended(dev))
> +		tegra_xudc_powergate(xudc);
> +
> +	pm_runtime_disable(dev);
> +
> +	return 0;
> +}
> +
> +static int tegra_xudc_resume(struct device *dev)
> +{
> +	struct tegra_xudc *xudc = dev_get_drvdata(dev);
> +	unsigned long flags;
> +	int err;
> +
> +	err = tegra_xudc_unpowergate(xudc);
> +	if (err < 0)
> +		return err;
> +
> +	spin_lock_irqsave(&xudc->lock, flags);
> +	xudc->suspended = false;
> +	spin_unlock_irqrestore(&xudc->lock, flags);
> +
> +	tegra_xudc_update_data_role(xudc);
> +
> +	pm_runtime_enable(dev);
> +
> +	return 0;
> +}
> +#endif
> +
> +#ifdef CONFIG_PM
> +static int tegra_xudc_runtime_suspend(struct device *dev)
> +{
> +	struct tegra_xudc *xudc = dev_get_drvdata(dev);
> +
> +	return tegra_xudc_powergate(xudc);
> +}
> +
> +static int tegra_xudc_runtime_resume(struct device *dev)
> +{
> +	struct tegra_xudc *xudc = dev_get_drvdata(dev);
> +
> +	return tegra_xudc_unpowergate(xudc);
> +}
> +#endif

__maybe_unused for these as well.

Thierry

> +
> +static const struct dev_pm_ops tegra_xudc_pm_ops = {
> +	SET_SYSTEM_SLEEP_PM_OPS(tegra_xudc_suspend, tegra_xudc_resume)
> +	SET_RUNTIME_PM_OPS(tegra_xudc_runtime_suspend,
> +			   tegra_xudc_runtime_resume, NULL)
> +};
> +
> +static struct platform_driver tegra_xudc_driver = {
> +	.probe = tegra_xudc_probe,
> +	.remove = tegra_xudc_remove,
> +	.driver = {
> +		.name = "tegra-xudc",
> +		.pm = &tegra_xudc_pm_ops,
> +		.of_match_table = tegra_xudc_of_match,
> +	},
> +};
> +module_platform_driver(tegra_xudc_driver);
> +
> +MODULE_DESCRIPTION("NVIDIA Tegra XUSB Device Controller");
> +MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
> +MODULE_AUTHOR("Hui Fu");
> +MODULE_LICENSE("GPL v2");
> -- 
> 2.7.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread
* [V2,1/8] phy: tegra: xusb: t210: add XUSB dual mode support
@ 2019-04-25 14:13 ` Thierry Reding
  0 siblings, 0 replies; 27+ messages in thread
From: Thierry Reding @ 2019-04-25 14:13 UTC (permalink / raw)
  To: Nagarjuna Kristam; +Cc: balbi, gregkh, jonathanh, linux-tegra, linux-usb

On Mon, Mar 11, 2019 at 04:41:49PM +0530, Nagarjuna Kristam wrote:
> The device tree bindings document the "mode" property of "ports"
> subnodes, but the driver was not parsing the property. In preparation
> for adding role switching, parse the property at probe time and
> confgiure the port capabilities accordingly
> 
> Based on work by JC Kuo <jckuo@nvidia.com>.
> 
> Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
> ---
>  drivers/phy/tegra/xusb-tegra210.c | 22 +++++++++++++++++++---
>  drivers/phy/tegra/xusb.c          | 24 +++++++++++++++++++++++-
>  drivers/phy/tegra/xusb.h          |  4 +++-
>  3 files changed, 45 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
> index 05bee32..4beebcc 100644
> --- a/drivers/phy/tegra/xusb-tegra210.c
> +++ b/drivers/phy/tegra/xusb-tegra210.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
>   * Copyright (C) 2015 Google, Inc.
>   *
>   * This program is free software; you can redistribute it and/or modify it
> @@ -47,7 +47,10 @@
>  #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1
>  
>  #define XUSB_PADCTL_USB2_PORT_CAP 0x008
> +#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4))
>  #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4))
> +#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4))
> +#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4))
>  #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4))
>  
>  #define XUSB_PADCTL_SS_PORT_MAP 0x014
> @@ -72,6 +75,7 @@
>  #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40)
>  #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7
>  #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3
> +#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1
>  #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6)
>  
>  #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40)
> @@ -965,7 +969,14 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  
>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
>  	value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index);
> -	value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
> +	if (port->mode == USB_DR_MODE_UNKNOWN)
> +		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index);
> +	else if (port->mode == USB_DR_MODE_PERIPHERAL)
> +		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index);
> +	else if (port->mode == USB_DR_MODE_HOST)
> +		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
> +	else if (port->mode == USB_DR_MODE_OTG)
> +		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index);
>  	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
>  
>  	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
> @@ -997,7 +1008,12 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
>  			     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
>  	value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK <<
>  		   XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT);
> -	value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
> +	if (port->mode == USB_DR_MODE_HOST)
> +		value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
> +	else
> +		value |=
> +		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL <<
> +		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT;
>  	padctl_writel(padctl, value,
>  		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
>  
> diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
> index 5b3b886..c6178a0 100644
> --- a/drivers/phy/tegra/xusb.c
> +++ b/drivers/phy/tegra/xusb.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
> @@ -542,13 +542,35 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
>  	device_unregister(&port->dev);
>  }
>  
> +static const char *const modes[] = {
> +	[USB_DR_MODE_UNKNOWN] = "",
> +	[USB_DR_MODE_HOST] = "host",
> +	[USB_DR_MODE_PERIPHERAL] = "peripheral",
> +	[USB_DR_MODE_OTG] = "otg",
> +};
> +
>  static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
>  {
>  	struct tegra_xusb_port *port = &usb2->base;
>  	struct device_node *np = port->dev.of_node;
> +	const char *mode;
>  
>  	usb2->internal = of_property_read_bool(np, "nvidia,internal");
>  
> +	if (!of_property_read_string(np, "mode", &mode)) {
> +		int err = match_string(modes, ARRAY_SIZE(modes), mode);
> +
> +		if (err < 0) {
> +			dev_err(&port->dev, "invalid value %s for \"mode\"\n",
> +				mode);
> +			usb2->mode = USB_DR_MODE_UNKNOWN;
> +		} else {
> +			usb2->mode = err;
> +		}
> +	} else {
> +		usb2->mode = USB_DR_MODE_HOST;
> +	}
> +
>  	usb2->supply = devm_regulator_get(&port->dev, "vbus");
>  	return PTR_ERR_OR_ZERO(usb2->supply);
>  }

This hunk has now been merged as part of commit 5311a7b89502 ("phy:
tegra: xusb: Parse dual-role mode property"), which is now in linux-next
as of next-20190418. So you may want to rebase.

Thierry

> diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
> index b49dbc3..17cc8dc 100644
> --- a/drivers/phy/tegra/xusb.h
> +++ b/drivers/phy/tegra/xusb.h
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
> + * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
>   * Copyright (c) 2015, Google Inc.
>   *
>   * This program is free software; you can redistribute it and/or modify it
> @@ -18,6 +18,7 @@
>  #include <linux/io.h>
>  #include <linux/mutex.h>
>  #include <linux/workqueue.h>
> +#include <linux/usb/otg.h>
>  
>  /* legacy entry points for backwards-compatibility */
>  int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
> @@ -272,6 +273,7 @@ struct tegra_xusb_usb2_port {
>  
>  	struct regulator *supply;
>  	bool internal;
> +	enum usb_dr_mode mode;
>  };
>  
>  static inline struct tegra_xusb_usb2_port *
> -- 
> 2.7.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread
* [V2,4/8] dt-bindings: usb: Add NVIDIA Tegra XUSB device mode controller binding
@ 2019-04-25 13:57 ` Thierry Reding
  0 siblings, 0 replies; 27+ messages in thread
From: Thierry Reding @ 2019-04-25 13:57 UTC (permalink / raw)
  To: Nagarjuna Kristam; +Cc: balbi, gregkh, jonathanh, linux-tegra, linux-usb

On Mon, Mar 11, 2019 at 04:41:52PM +0530, Nagarjuna Kristam wrote:
> Add device-tree binding documentation for the XUSB device mode controller
> present on tegra210 SoC. This controller supports USB 3.0 specification
> 
> Based on work by Andrew Bresticker <abrestic@chromium.org>.
> 
> Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
> ---
>  .../devicetree/bindings/usb/nvidia,tegra-xudc.txt  | 105 +++++++++++++++++++++
>  1 file changed, 105 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.txt

Hi Nagarjuna,

when you resend this, make sure to Cc devicetree@vger.kernel.org on this
patch. We need review from one of the device tree bindings maintainers
before this can be applied, and they won't review if they don't receive
the patch. =)

Thierry

> 
> diff --git a/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.txt b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.txt
> new file mode 100644
> index 0000000..990655d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/nvidia,tegra-xudc.txt
> @@ -0,0 +1,105 @@
> +Device tree binding for NVIDIA Tegra XUSB device mode controller (XUDC)
> +=======================================================================
> +
> +The Tegra XUDC controller supports both USB 2.0 HighSpeed/FullSpeed and
> +USB 3.0 SuperSpeed protocols.
> +
> +Required properties:
> +--------------------
> +- compatible: For Tegra210, must contain "nvidia,tegra210-xudc".
> +- reg: Must contain the base and length of the XUSB device registers, XUSB device
> +  PCI Config registers and XUSB device controller registers.
> +- interrupts: Must contain the XUSB device interrupt
> +- clocks: Must contain an entry for ell clocks used.
> +  See ../clock/clock-bindings.txt for details.
> +- clock-names: Must include the following entries:
> +   - xusb_device
> +   - xusb_ss
> +   - xusb_ss_src
> +   - xusb_hs_src
> +   - xusb_fs_src
> +- nvidia,xusb-padctl: phandle to the XUSB pad controller that is used to
> +  configure the USB pads used by the XUDC controller
> +- power-domains: A list of PM domain specifiers that reference each power-domain
> +  used by the XUSB device mode controller. This list must comprise of a specifier
> +  for the XUSBA and XUSBB power-domains. See ../power/power_domain.txt and
> +  ../arm/tegra/nvidia,tegra20-pmc.txt for details.
> +- power-domain-names: A list of names that represent each of the specifiers in
> +  the 'power-domains' property. Must include 'xusb_ss' and 'xusb_device'
> +
> +For Tegra210:
> +- avddio-usb-supply: PCIe/USB3 analog logic power supply. Must supply 1.05 V.
> +- hvdd-usb-supply: USB controller power supply. Must supply 3.3 V.
> +- avdd-pll-utmip-supply: UTMI PLL power supply. Must supply 1.8 V.
> +
> +- phys: Must contain an entry for each entry in phy-names.
> +  See ../phy/phy-bindings.txt for details.
> +- extcon-usb: Must contains an extcon-usb entry which detects
> +  USB VBUS pin. See ../extcon/extcon-usb-gpio.txt for details.
> +
> +Optional properties:
> +--------------------
> +- phy-names: Should include an entry for each PHY used by the controller.
> +  Names must be "usb2", and "usb3" if support SuperSpeed device mode.
> +  - "usb3" phy, SuperSpeed (SSTX+/SSTX-/SSRX+/SSRX-) data lines
> +  - "usb2" phy, USB 2.0 (D+/D-) data lines
> +
> +Example:
> +--------
> +	pmc: pmc@7000e400 {
> +		compatible = "nvidia,tegra210-pmc";
> +		reg = <0x0 0x7000e400 0x0 0x400>;
> +		clocks = <&tegra_car TEGRA210_CLK_PCLK>, <&clk32k_in>;
> +		clock-names = "pclk", "clk32k_in";
> +
> +		powergates {
> +			pd_xusbss: xusba {
> +				clocks = <&tegra_car TEGRA210_CLK_XUSB_SS>;
> +				resets = <&tegra_car TEGRA210_CLK_XUSB_SS>;
> +				#power-domain-cells = <0>;
> +			};
> +
> +			pd_xusbdev: xusbb {
> +				clocks = <&tegra_car TEGRA210_CLK_XUSB_DEV>;
> +				resets = <&tegra_car 95>;
> +				#power-domain-cells = <0>;
> +			};
> +		};
> +	};
> +
> +	xudc@700d0000 {
> +		compatible = "nvidia,tegra210-xudc";
> +		reg = <0x0 0x700d0000 0x0 0x8000>,
> +			<0x0 0x700d8000 0x0 0x1000>,
> +			<0x0 0x700d9000 0x0 0x1000>;
> +
> +		interrupts = <0 44 0x4>;
> +
> +		clocks = <&tegra_car TEGRA210_CLK_XUSB_DEV>,
> +			<&tegra_car TEGRA210_CLK_XUSB_SS>,
> +			<&tegra_car TEGRA210_CLK_XUSB_SSP_SRC>,
> +			<&tegra_car TEGRA210_CLK_XUSB_HS_SRC>,
> +			<&tegra_car TEGRA210_CLK_XUSB_FS_SRC>;
> +		clock-names = "xusb_device", "xusb_ss", "xusb_ss_src",
> +			      "xusb_hs_src", "xusb_fs_src";
> +
> +		power-domains = <&pd_xusbdev>, <&pd_xusbss>;
> +		power-domain-names = "xusb_device", "xusb_ss";
> +
> +		nvidia,xusb-padctl = <&padctl>;
> +
> +		phys = <&{/padctl@7009f000/pads/usb2/lanes/usb2-0}>;
> +		phy-names = "usb2;
> +
> +		avddio-usb-supply = <&vdd_pex_1v05>;
> +		hvdd-usb-supply = <&vdd_3v3_sys>;
> +		avdd-pll-utmip-supply = <&vdd_1v8>;
> +
> +		extcon = <&extcon_usb>;
> +	};
> +
> +	extcon_usb: extcon_vbus {
> +		compatible = "linux,extcon-usb-gpio";
> +		vbus-gpio = <&gpio TEGRA_GPIO(Z, 0) GPIO_ACTIVE_LOW>;
> +	};
> +
> -- 
> 2.7.4
>

^ permalink raw reply	[flat|nested] 27+ messages in thread
* [V2,1/8] phy: tegra: xusb: t210: add XUSB dual mode support
@ 2019-03-11 11:11 Nagarjuna Kristam
  0 siblings, 0 replies; 27+ messages in thread
From: Nagarjuna Kristam @ 2019-03-11 11:11 UTC (permalink / raw)
  To: balbi, gregkh, thierry.reding, jonathanh
  Cc: linux-tegra, linux-usb, Nagarjuna Kristam

The device tree bindings document the "mode" property of "ports"
subnodes, but the driver was not parsing the property. In preparation
for adding role switching, parse the property at probe time and
confgiure the port capabilities accordingly

Based on work by JC Kuo <jckuo@nvidia.com>.

Signed-off-by: Nagarjuna Kristam <nkristam@nvidia.com>
---
 drivers/phy/tegra/xusb-tegra210.c | 22 +++++++++++++++++++---
 drivers/phy/tegra/xusb.c          | 24 +++++++++++++++++++++++-
 drivers/phy/tegra/xusb.h          |  4 +++-
 3 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/drivers/phy/tegra/xusb-tegra210.c b/drivers/phy/tegra/xusb-tegra210.c
index 05bee32..4beebcc 100644
--- a/drivers/phy/tegra/xusb-tegra210.c
+++ b/drivers/phy/tegra/xusb-tegra210.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
  * Copyright (C) 2015 Google, Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -47,7 +47,10 @@
 #define XUSB_PADCTL_USB2_PAD_MUX_USB2_BIAS_PAD_XUSB 0x1
 
 #define XUSB_PADCTL_USB2_PORT_CAP 0x008
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(x) (0x0 << ((x) * 4))
 #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(x) (0x1 << ((x) * 4))
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(x) (0x2 << ((x) * 4))
+#define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(x) (0x3 << ((x) * 4))
 #define XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(x) (0x3 << ((x) * 4))
 
 #define XUSB_PADCTL_SS_PORT_MAP 0x014
@@ -72,6 +75,7 @@
 #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(x) (0x084 + (x) * 0x40)
 #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT 7
 #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK 0x3
+#define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL 0x1
 #define XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18 (1 << 6)
 
 #define XUSB_PADCTL_USB2_OTG_PADX_CTL0(x) (0x088 + (x) * 0x40)
@@ -965,7 +969,14 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
 
 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_PORT_CAP);
 	value &= ~XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_MASK(index);
-	value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
+	if (port->mode == USB_DR_MODE_UNKNOWN)
+		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DISABLED(index);
+	else if (port->mode == USB_DR_MODE_PERIPHERAL)
+		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_DEVICE(index);
+	else if (port->mode == USB_DR_MODE_HOST)
+		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_HOST(index);
+	else if (port->mode == USB_DR_MODE_OTG)
+		value |= XUSB_PADCTL_USB2_PORT_CAP_PORTX_CAP_OTG(index);
 	padctl_writel(padctl, value, XUSB_PADCTL_USB2_PORT_CAP);
 
 	value = padctl_readl(padctl, XUSB_PADCTL_USB2_OTG_PADX_CTL0(index));
@@ -997,7 +1008,12 @@ static int tegra210_usb2_phy_power_on(struct phy *phy)
 			     XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
 	value &= ~(XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_MASK <<
 		   XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT);
-	value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
+	if (port->mode == USB_DR_MODE_HOST)
+		value |= XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_FIX18;
+	else
+		value |=
+		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_VAL <<
+		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPAD_CTL1_VREG_LEV_SHIFT;
 	padctl_writel(padctl, value,
 		      XUSB_PADCTL_USB2_BATTERY_CHRG_OTGPADX_CTL1(index));
 
diff --git a/drivers/phy/tegra/xusb.c b/drivers/phy/tegra/xusb.c
index 5b3b886..c6178a0 100644
--- a/drivers/phy/tegra/xusb.c
+++ b/drivers/phy/tegra/xusb.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
@@ -542,13 +542,35 @@ static void tegra_xusb_port_unregister(struct tegra_xusb_port *port)
 	device_unregister(&port->dev);
 }
 
+static const char *const modes[] = {
+	[USB_DR_MODE_UNKNOWN] = "",
+	[USB_DR_MODE_HOST] = "host",
+	[USB_DR_MODE_PERIPHERAL] = "peripheral",
+	[USB_DR_MODE_OTG] = "otg",
+};
+
 static int tegra_xusb_usb2_port_parse_dt(struct tegra_xusb_usb2_port *usb2)
 {
 	struct tegra_xusb_port *port = &usb2->base;
 	struct device_node *np = port->dev.of_node;
+	const char *mode;
 
 	usb2->internal = of_property_read_bool(np, "nvidia,internal");
 
+	if (!of_property_read_string(np, "mode", &mode)) {
+		int err = match_string(modes, ARRAY_SIZE(modes), mode);
+
+		if (err < 0) {
+			dev_err(&port->dev, "invalid value %s for \"mode\"\n",
+				mode);
+			usb2->mode = USB_DR_MODE_UNKNOWN;
+		} else {
+			usb2->mode = err;
+		}
+	} else {
+		usb2->mode = USB_DR_MODE_HOST;
+	}
+
 	usb2->supply = devm_regulator_get(&port->dev, "vbus");
 	return PTR_ERR_OR_ZERO(usb2->supply);
 }
diff --git a/drivers/phy/tegra/xusb.h b/drivers/phy/tegra/xusb.h
index b49dbc3..17cc8dc 100644
--- a/drivers/phy/tegra/xusb.h
+++ b/drivers/phy/tegra/xusb.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014-2015, NVIDIA CORPORATION.  All rights reserved.
+ * Copyright (c) 2014-2019, NVIDIA CORPORATION.  All rights reserved.
  * Copyright (c) 2015, Google Inc.
  *
  * This program is free software; you can redistribute it and/or modify it
@@ -18,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
+#include <linux/usb/otg.h>
 
 /* legacy entry points for backwards-compatibility */
 int tegra_xusb_padctl_legacy_probe(struct platform_device *pdev);
@@ -272,6 +273,7 @@ struct tegra_xusb_usb2_port {
 
 	struct regulator *supply;
 	bool internal;
+	enum usb_dr_mode mode;
 };
 
 static inline struct tegra_xusb_usb2_port *

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2019-05-08 10:50 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1552302716-18554-1-git-send-email-nkristam@nvidia.com>
2019-03-11 11:11 ` [V2,2/8] phy: tegra: xusb: t210: add usb3 port fake support Nagarjuna Kristam
2019-04-25 14:55   ` Thierry Reding
2019-04-25 14:55     ` [PATCH V2 2/8] " Thierry Reding
2019-05-08  9:35     ` Nagarjuna Kristam
2019-03-11 11:11 ` [V2,3/8] phy: tegra: xusb: t210: add vbus override support Nagarjuna Kristam
2019-04-25 15:04   ` Thierry Reding
2019-04-25 15:04     ` [PATCH V2 3/8] " Thierry Reding
2019-05-08 10:21     ` Nagarjuna Kristam
2019-03-11 11:11 ` [V2,4/8] dt-bindings: usb: Add NVIDIA Tegra XUSB device mode controller binding Nagarjuna Kristam
2019-04-25 15:14   ` Thierry Reding
2019-04-25 15:14     ` [PATCH V2 4/8] " Thierry Reding
2019-05-03 14:30     ` [V2,4/8] " Thierry Reding
2019-05-03 14:30       ` [PATCH V2 4/8] " Thierry Reding
2019-05-08 10:51       ` Nagarjuna Kristam
2019-03-11 11:11 ` [V2,7/8] usb: gadget: Add UDC driver for tegra XUSB device mode controller Nagarjuna Kristam
2019-04-25 13:00   ` Felipe Balbi
2019-04-25 13:00     ` [PATCH V2 7/8] " Felipe Balbi
2019-04-25 13:55     ` [V2,7/8] " Thierry Reding
2019-04-25 13:55       ` [PATCH V2 7/8] " Thierry Reding
2019-05-07 10:09       ` Nagarjuna Kristam
2019-05-03 14:22 [V2,7/8] " Thierry Reding
2019-05-03 14:22 ` [PATCH V2 7/8] " Thierry Reding
  -- strict thread matches above, loose matches on Subject: below --
2019-04-25 14:13 [V2,1/8] phy: tegra: xusb: t210: add XUSB dual mode support Thierry Reding
2019-04-25 14:13 ` [PATCH V2 1/8] " Thierry Reding
2019-04-25 13:57 [V2,4/8] dt-bindings: usb: Add NVIDIA Tegra XUSB device mode controller binding Thierry Reding
2019-04-25 13:57 ` [PATCH V2 4/8] " Thierry Reding
2019-03-11 11:11 [V2,1/8] phy: tegra: xusb: t210: add XUSB dual mode support Nagarjuna Kristam

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.