Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f412722a authored by Tarun Gupta's avatar Tarun Gupta
Browse files

usb: gadget: Add snapshot of ChipIdea MSM driver



Add the snapshot ChipIdea-based UDC drivers for MSM chipsets for
USB. This snapshot is taken from msm-3.10 'commit f62f95b715a5
("Merge "dwc3-msm: Turn on 1.8V LDO before turning on 3.3V LDO"")'.

Also remove ACA and SRP/HNP related code which is no longer used

Changes were also made to allow successful compiliation:
 - Omitted qcom/usb_trace.h and removed references to ebi_erp
 - converted usleep() to usleep_range()

Change-Id: Ibdc0ce840b36ee8b76ab1ab3fc7230088bbf5a5d
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
Signed-off-by: default avatarTarun Gupta <tarung@codeaurora.org>
parent 497ce229
Loading
Loading
Loading
Loading
+152 −4
Original line number Diff line number Diff line
/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2010-2015, The Linux Foundation. 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 version 2 and
@@ -11,6 +11,7 @@
#include <linux/usb/msm_hsusb_hw.h>
#include <linux/usb/ulpi.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>

#include "ci13xxx_udc.c"

@@ -24,6 +25,7 @@ struct ci13xxx_udc_context {
	int wake_gpio;
	int wake_irq;
	bool wake_irq_state;
	struct pinctrl *ci13xxx_pinctrl;
};

static struct ci13xxx_udc_context _udc_ctxt;
@@ -62,11 +64,27 @@ static void ci13xxx_msm_disconnect(void)
	struct ci13xxx *udc = _udc;
	struct usb_phy *phy = udc->transceiver;

	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
	if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
		u32 temp;

		usb_phy_io_write(phy,
				ULPI_MISC_A_VBUSVLDEXT |
				ULPI_MISC_A_VBUSVLDEXTSEL,
				ULPI_CLR(ULPI_MISC_A));

		/* Notify LINK of VBUS LOW */
		temp = readl_relaxed(USB_USBCMD);
		temp &= ~USBCMD_SESS_VLD_CTRL;
		writel_relaxed(temp, USB_USBCMD);

		/*
		 * Add memory barrier as it is must to complete
		 * above USB PHY and Link register writes before
		 * moving ahead with USB peripheral mode enumeration,
		 * otherwise USB peripheral mode may not work.
		 */
		mb();
	}
}

/* Link power management will reduce power consumption by
@@ -125,10 +143,16 @@ static void ci13xxx_msm_reset(void)
	struct ci13xxx *udc = _udc;
	struct usb_phy *phy = udc->transceiver;
	struct device *dev = udc->gadget.dev.parent;
	int	temp;

	writel_relaxed(0, USB_AHBBURST);
	writel_relaxed(0x08, USB_AHBMODE);

	/* workaround for rx buffer collision issue */
	temp = readl_relaxed(USB_GENCONFIG);
	temp &= ~GENCONFIG_TXFIFO_IDLE_FORCE_DISABLE;
	writel_relaxed(temp, USB_GENCONFIG);

	if (udc->gadget.l1_supported)
		ci13xxx_msm_set_l1(udc);

@@ -149,6 +173,23 @@ static void ci13xxx_msm_reset(void)
	}
}

static void ci13xxx_msm_mark_err_event(void)
{
	struct ci13xxx *udc = _udc;
	struct msm_otg *otg;

	if (udc == NULL)
		return;

	if (udc->transceiver == NULL)
		return;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	/* This will trigger hardware reset before next connection */
	otg->err_event_seen = true;
}

static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
{
	struct device *dev = udc->gadget.dev.parent;
@@ -175,6 +216,10 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
		dev_info(dev, "CI13XXX_CONTROLLER_RESUME_EVENT received\n");
		ci13xxx_msm_resume();
		break;
	case CI13XXX_CONTROLLER_ERROR_EVENT:
		dev_info(dev, "CI13XXX_CONTROLLER_ERROR_EVENT received\n");
		ci13xxx_msm_mark_err_event();
		break;

	default:
		dev_dbg(dev, "unknown ci13xxx_udc event\n");
@@ -182,6 +227,51 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
	}
}

static bool ci13xxx_cancel_pending_suspend(struct ci13xxx *udc)
{
	struct msm_otg *otg;

	if (udc == NULL)
		return false;

	if (udc->transceiver == NULL)
		return false;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	return cancel_delayed_work_sync(&otg->suspend_work);
}

static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
{
	struct msm_otg *otg;

	if (udc == NULL)
		return false;

	if (udc->transceiver == NULL)
		return false;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	return (atomic_read(&otg->in_lpm) != 0);
}

static void ci13xxx_msm_set_fpr_flag(struct ci13xxx *udc)
{
	struct msm_otg *otg;

	if (udc == NULL)
		return;

	if (udc->transceiver == NULL)
		return;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	atomic_set(&otg->set_fpr_with_lpm_exit, 1);
}

static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
{
	struct ci13xxx *udc = _udc;
@@ -200,10 +290,12 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
				  CI13XXX_REQUIRE_TRANSCEIVER |
				  CI13XXX_PULLUP_ON_VBUS |
				  CI13XXX_ZERO_ITC |
				  CI13XXX_DISABLE_STREAMING |
				  CI13XXX_IS_OTG,
				  CI13XXX_DISABLE_STREAMING,
	.nz_itc			= 0,
	.notify_event		= ci13xxx_msm_notify_event,
	.cancel_pending_suspend = ci13xxx_cancel_pending_suspend,
	.in_lpm                 = ci13xxx_msm_in_lpm,
	.set_fpr_flag           = ci13xxx_msm_set_fpr_flag,
};

static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
@@ -211,10 +303,20 @@ static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
{
	int wake_irq;
	int ret;
	struct pinctrl_state *set_state;

	dev_dbg(&pdev->dev, "ci13xxx_msm_install_wake_gpio\n");

	_udc_ctxt.wake_gpio = res->start;
	if (_udc_ctxt.ci13xxx_pinctrl) {
		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
				"ci13xxx_active");
		if (IS_ERR(set_state)) {
			pr_err("cannot get ci13xxx pinctrl active state\n");
			return PTR_ERR(set_state);
		}
		pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl, set_state);
	}
	gpio_request(_udc_ctxt.wake_gpio, "USB_RESUME");
	gpio_direction_input(_udc_ctxt.wake_gpio);
	wake_irq = gpio_to_irq(_udc_ctxt.wake_gpio);
@@ -238,16 +340,36 @@ static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,

gpio_free:
	gpio_free(_udc_ctxt.wake_gpio);
	if (_udc_ctxt.ci13xxx_pinctrl) {
		set_state = pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
				"ci13xxx_sleep");
		if (IS_ERR(set_state))
			pr_err("cannot get ci13xxx pinctrl sleep state\n");
		else
			pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
					set_state);
	}
	_udc_ctxt.wake_gpio = 0;
	return ret;
}

static void ci13xxx_msm_uninstall_wake_gpio(struct platform_device *pdev)
{
	struct pinctrl_state *set_state;
	dev_dbg(&pdev->dev, "ci13xxx_msm_uninstall_wake_gpio\n");

	if (_udc_ctxt.wake_gpio) {
		gpio_free(_udc_ctxt.wake_gpio);
		if (_udc_ctxt.ci13xxx_pinctrl) {
			set_state =
				pinctrl_lookup_state(_udc_ctxt.ci13xxx_pinctrl,
						"ci13xxx_sleep");
			if (IS_ERR(set_state))
				pr_err("cannot get ci13xxx pinctrl sleep state\n");
			else
				pinctrl_select_state(_udc_ctxt.ci13xxx_pinctrl,
						set_state);
		}
		_udc_ctxt.wake_gpio = 0;
	}
}
@@ -271,6 +393,15 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
				1 << (pdata->log2_itc-1);

		is_l1_supported = pdata->l1_supported;
		/* Set ahb2ahb bypass flag if it is requested. */
		if (pdata->enable_ahb2ahb_bypass)
			ci13xxx_msm_udc_driver.flags |=
				CI13XXX_ENABLE_AHB2AHB_BYPASS;

		/* Clear disable streaming flag if is requested. */
		if (pdata->enable_streaming)
			ci13xxx_msm_udc_driver.flags &=
						~CI13XXX_DISABLE_STREAMING;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -301,6 +432,17 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_IO, "USB_RESUME");
	/* Get pinctrl if target uses pinctrl */
	_udc_ctxt.ci13xxx_pinctrl = devm_pinctrl_get(&pdev->dev);
	if (IS_ERR(_udc_ctxt.ci13xxx_pinctrl)) {
		if (of_property_read_bool(pdev->dev.of_node, "pinctrl-names")) {
			dev_err(&pdev->dev, "Error encountered while getting pinctrl");
			ret = PTR_ERR(_udc_ctxt.ci13xxx_pinctrl);
			goto udc_remove;
		}
		dev_dbg(&pdev->dev, "Target does not use pinctrl\n");
		_udc_ctxt.ci13xxx_pinctrl = NULL;
	}
	if (res) {
		ret = ci13xxx_msm_install_wake_gpio(pdev, res);
		if (ret < 0) {
@@ -341,6 +483,11 @@ int ci13xxx_msm_remove(struct platform_device *pdev)
	return 0;
}

void ci13xxx_msm_shutdown(struct platform_device *pdev)
{
	ci13xxx_pullup(&_udc->gadget, 0);
}

void msm_hw_bam_disable(bool bam_disable)
{
	u32 val;
@@ -360,6 +507,7 @@ static struct platform_driver ci13xxx_msm_driver = {
		.name = "msm_hsusb",
	},
	.remove = ci13xxx_msm_remove,
	.shutdown = ci13xxx_msm_shutdown,
};
MODULE_ALIAS("platform:msm_hsusb");

+530 −376

File changed.

Preview size limit exceeded, changes collapsed.

+20 −5
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@ struct ci13xxx_ep {
		struct ci13xxx_qh *ptr;
		dma_addr_t         dma;
	}                                      qh;
	struct list_head                       rw_queue;
	int                                    wedge;

	/* global resources */
@@ -135,7 +136,7 @@ struct ci13xxx_udc_driver {
#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
#define CI13XXX_DISABLE_STREAMING	BIT(3)
#define CI13XXX_ZERO_ITC		BIT(4)
#define CI13XXX_IS_OTG			BIT(5)
#define CI13XXX_ENABLE_AHB2AHB_BYPASS	BIT(6)

#define CI13XXX_CONTROLLER_RESET_EVENT			0
#define CI13XXX_CONTROLLER_CONNECT_EVENT		1
@@ -144,8 +145,13 @@ struct ci13xxx_udc_driver {
#define CI13XXX_CONTROLLER_RESUME_EVENT		4
#define CI13XXX_CONTROLLER_DISCONNECT_EVENT		5
#define CI13XXX_CONTROLLER_UDC_STARTED_EVENT		6
#define CI13XXX_CONTROLLER_ERROR_EVENT			7

	void	(*notify_event)(struct ci13xxx *udc, unsigned event);
	bool (*cancel_pending_suspend)(struct ci13xxx *udc);
	bool    (*in_lpm)(struct ci13xxx *udc);
	void    (*set_fpr_flag)(struct ci13xxx *udc);
	struct clk *system_clk;
};

/* CI13XXX UDC descriptor & global resources */
@@ -163,12 +169,10 @@ struct ci13xxx {
	u32                        ep0_dir;    /* ep0 direction */
#define ep0out ci13xxx_ep[0]
#define ep0in  ci13xxx_ep[hw_ep_max / 2]
	u8                         remote_wakeup; /* Is remote wakeup feature
							enabled by the host? */
	u8                         suspended;  /* suspended by the host */
	u8                         configured;  /* is device configured */
	u8                         test_mode;  /* the selected test mode */

	bool                       rw_pending; /* Remote wakeup pending flag */
	struct delayed_work        rw_work;    /* remote wakeup delayed work */
	struct usb_gadget_driver  *driver;     /* 3rd party gadget driver */
	struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
@@ -176,9 +180,16 @@ struct ci13xxx {
	int                        softconnect; /* is pull-up enable allowed */
	unsigned long dTD_update_fail_count;
	struct usb_phy            *transceiver; /* Transceiver struct */
	struct clk                *system_clk;
	bool                      skip_flush; /* skip flushing remaining EP
						upon flush timeout for the
						first EP. */
	u32			  max_nominal_system_clk_rate;	/* max freq to
						be voted for system clock in
						streaming mode */;
	u32			  default_system_clk_rate;	/* max freq at
						which system clock should run
						in non streaming mode */;
};

/******************************************************************************
@@ -197,6 +208,9 @@ struct ci13xxx {
/* TESTMODE */
#define TESTMODE_FORCE        BIT(0)

/* AHB_MODE */
#define AHB2AHB_BYPASS	      BIT(31)

/* USBCMD */
#define USBCMD_RS             BIT(0)
#define USBCMD_RST            BIT(1)
@@ -217,6 +231,7 @@ struct ci13xxx {
/* PORTSC */
#define PORTSC_FPR            BIT(6)
#define PORTSC_SUSP           BIT(7)
#define PORTSC_PR             BIT(8)
#define PORTSC_HSP            BIT(9)
#define PORTSC_PTC            (0x0FUL << 16)

+4 −0
Original line number Diff line number Diff line
@@ -542,6 +542,10 @@ struct ci13xxx_platform_data {
	void *prv_data;
	bool l1_supported;
	bool enable_ahb2ahb_bypass;
	bool enable_streaming;
	struct clk *system_clk;
	u32 max_nominal_system_clk_rate;
	u32 default_system_clk_rate;
};

/**