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

Commit 5fb8b540 authored by Chandana Kishori Chiluveru's avatar Chandana Kishori Chiluveru Committed by Gerrit - the friendly Code Review server
Browse files

usb: ehci-msm-hsic: Add TLMM initialization support for HSIC HOST



HSIC strobe and data lines are routed from TLMM. Add support to
pass TLMM register map from DT along with reg, value pair to
program strobe/data pads and their calibration setting.

Change-Id: I47da1d78435b5b274a34250d2f22bb4279738208
Signed-off-by: default avatarChandana Kishori Chiluveru <cchiluve@codeaurora.org>
parent c8a944be
Loading
Loading
Loading
Loading
+0 −6
Original line number Diff line number Diff line
@@ -47,12 +47,6 @@ Optional properties :
- hsic,resume-gpio : if present then periperal connected to hsic controller
  cannot wakeup from XO shutdown using in-band hsic resume. Use resume
  gpio to wakeup peripheral
- hsic,ignore-cal-pad-config : If present then HSIC CAL PAD configuration
  using TLMM is not performed.
- hsic,strobe-pad-offset : Offset of TLMM register for configuring HSIC
  STROBE GPIO PAD.
- hsic,data-pad-offset : Offset of TLMM register for configuring HSIC
  DATA GPIO PAD.
- qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
  SOFs. All the relevant software workarounds are required for the same during
  suspend, reset and resume.
+57 −64
Original line number Diff line number Diff line
/* ehci-msm-hsic.c - HSUSB Host Controller Driver Implementation
 *
 * Copyright (c) 2011-2015, The Linux Foundation. All rights reserved.
 * Copyright (c) 2011-2016, The Linux Foundation. All rights reserved.
 *
 * Partly derived from ehci-fsl.c and ehci-hcd.c
 * Copyright (c) 2000-2004 by David Brownell
@@ -92,6 +92,7 @@ struct msm_hsic_hcd {
	int			wakeup_irq;
	bool			wakeup_irq_enabled;
	int			async_irq;
	void __iomem		*tlmm_regs;
	uint32_t		async_int_cnt;
	atomic_t		pm_usage_cnt;
	uint32_t		bus_perf_client;
@@ -642,14 +643,7 @@ static void msm_hsic_clk_reset(struct msm_hsic_hcd *mehci)
	}
}

#define IOMEM(x)        ((void __force __iomem *)(x))
#define MSM_TLMM_BASE                   IOMEM(0xFA017000)
#define HSIC_STROBE_GPIO_PAD_CTL	(MSM_TLMM_BASE+0x20C0)
#define HSIC_DATA_GPIO_PAD_CTL		(MSM_TLMM_BASE+0x20C4)
#define HSIC_CAL_PAD_CTL       (MSM_TLMM_BASE+0x20C8)
#define HSIC_LV_MODE		0x04
#define HSIC_PAD_CALIBRATION	0xA8
#define HSIC_GPIO_PAD_VAL	0x0A0AAA10
#define LINK_RESET_TIMEOUT_USEC		(250 * 1000)

static void msm_hsic_phy_reset(struct msm_hsic_hcd *mehci)
@@ -666,8 +660,8 @@ static void msm_hsic_phy_reset(struct msm_hsic_hcd *mehci)
static int msm_hsic_start(struct msm_hsic_hcd *mehci)
{
	struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
	int ret;
	void __iomem *reg;
	int ret, *seq, seq_count;
	u32 val;

	if (mehci->hsic_pinctrl) {
		ret = msm_hsic_config_pinctrl(mehci, 1);
@@ -687,13 +681,22 @@ static int msm_hsic_start(struct msm_hsic_hcd *mehci)
	}

	/* HSIC init sequence when HSIC signals (Strobe/Data) are
	routed via GPIOs */
	if (pdata && ((pdata->strobe && pdata->data) || mehci->hsic_pinctrl)) {

		if (!pdata->ignore_cal_pad_config) {
			/* Enable LV_MODE in HSIC_CAL_PAD_CTL register */
			writel_relaxed(HSIC_LV_MODE, HSIC_CAL_PAD_CTL);
			mb();
	routed via TLMM */
	if (mehci->tlmm_regs) {
		/* Program TLMM pad configuration for HSIC */
		seq = pdata->tlmm_init_seq;
		seq_count = pdata->tlmm_seq_count;
		if (seq && seq_count) {
			while (seq[0] >= 0 && seq_count > 0) {
				val = readl_relaxed(mehci->tlmm_regs + seq[0]);
				val |= seq[1];
				dev_dbg(mehci->dev, "%s: writing %x to %p\n",
						__func__,
						val, mehci->tlmm_regs + seq[0]);
				writel_relaxed(val, mehci->tlmm_regs + seq[0]);
				seq += 2;
				seq_count -= 2;
			}
		}

		/*set periodic calibration interval to ~2.048sec in
@@ -703,30 +706,13 @@ static int msm_hsic_start(struct msm_hsic_hcd *mehci)
		/* Enable periodic IO calibration in HSIC_CFG register */
		ulpi_write(mehci, HSIC_PAD_CALIBRATION, 0x30);

		if (pdata->strobe && pdata->data) {
			/* Configure GPIO pins for HSIC functionality mode */
			ret = msm_hsic_config_gpios(mehci, 1);
			if (ret) {
				dev_err(mehci->dev, " gpio configuarion failed\n");
				goto free_resume_gpio;
			}
		if (pdata->strobe_pad_offset) {
			/* Set CORE_CTL_EN in STROBE GPIO PAD_CTL register */
			reg = MSM_TLMM_BASE + pdata->strobe_pad_offset;
			writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
		} else {
			/* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
			reg = HSIC_STROBE_GPIO_PAD_CTL;
			writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
		}

		if (pdata->data_pad_offset) {
			/* Set CORE_CTL_EN in HSIC_DATA GPIO PAD_CTL register */
			reg = MSM_TLMM_BASE + pdata->data_pad_offset;
			writel_relaxed(readl_relaxed(reg) | 0x2000000, reg);
		} else {
			/* Set LV_MODE=0x1 and DCC=0x2 in STROBE GPIO PAD_CTL */
			reg = HSIC_DATA_GPIO_PAD_CTL;
			writel_relaxed(HSIC_GPIO_PAD_VAL, reg);
		}

		mb();
@@ -1628,15 +1614,6 @@ static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
	if (IS_ERR(mehci->inactivity_clk))
		dev_dbg(mehci->dev, "failed to get inactivity_clk\n");

	/*
	 * alt_core_clk is for LINK to be used during PHY RESET in
	 * targets on which link does NOT use asynchronous reset methodology.
	 * clock rate appropriately set by target specific clock driver
	 */
	mehci->alt_core_clk = devm_clk_get(mehci->dev, "alt_core_clk");
	if (IS_ERR(mehci->alt_core_clk))
		dev_dbg(mehci->dev, "failed to get alt_core_clk\n");

	ret = clk_set_rate(mehci->core_clk,
			clk_round_rate(mehci->core_clk, LONG_MAX));
	if (ret)
@@ -1647,13 +1624,6 @@ static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init)
	if (ret)
		dev_err(mehci->dev, "failed to set phy_clk rate\n");

	if (!IS_ERR(mehci->alt_core_clk)) {
		ret = clk_set_rate(mehci->alt_core_clk,
			clk_round_rate(mehci->alt_core_clk, LONG_MAX));
		if (ret)
			dev_err(mehci->dev, "failed to set_rate alt_core_clk\n");
	}

	ret = clk_set_rate(mehci->cal_clk,
			clk_round_rate(mehci->cal_clk, LONG_MAX));
	if (ret)
@@ -1989,12 +1959,6 @@ struct msm_hsic_host_platform_data *msm_hsic_dt_to_pdata(
					"qcom,phy-susp-sof-workaround");
	pdata->phy_reset_sof_workaround = of_property_read_bool(node,
					"qcom,phy-reset-sof-workaround");
	pdata->ignore_cal_pad_config = of_property_read_bool(node,
					"hsic,ignore-cal-pad-config");
	of_property_read_u32(node, "hsic,strobe-pad-offset",
					&pdata->strobe_pad_offset);
	of_property_read_u32(node, "hsic,data-pad-offset",
					&pdata->data_pad_offset);
	of_property_read_u32(node, "hsic,reset-delay",
					&pdata->reset_delay);
	of_property_read_u32(node, "hsic,log2-itc",
@@ -2028,7 +1992,7 @@ static int ehci_hsic_msm_probe(struct platform_device *pdev)
	struct msm_hsic_hcd *mehci;
	struct msm_hsic_host_platform_data *pdata;
	unsigned long wakeup_irq_flags = 0;
	int ret;
	int ret, len;

	dev_dbg(&pdev->dev, "ehci_msm-hsic probe\n");

@@ -2093,6 +2057,19 @@ static int ehci_hsic_msm_probe(struct platform_device *pdev)
	pdata = mehci->dev->platform_data;
	platform_set_drvdata(pdev, hcd);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
	if (!res && pdata->tlmm_init_seq) {
		dev_err(&pdev->dev, "Unable to get TLMM memory resource\n");
		ret = -ENODEV;
		goto unmap;
	} else if (res) {
		mehci->tlmm_regs = ioremap(res->start,	resource_size(res));
		if (IS_ERR(mehci->tlmm_regs)) {
			ret = PTR_ERR(mehci->tlmm_regs);
			goto unmap;
		}
	}

	spin_lock_init(&mehci->wakeup_lock);

	if (pdata->phy_sof_workaround) {
@@ -2145,6 +2122,22 @@ static int ehci_hsic_msm_probe(struct platform_device *pdev)
		goto unmap;
	}

	of_get_property(mehci->dev->of_node, "qcom,hsic-tlmm-init-seq", &len);
	if (len) {
		pdata->tlmm_init_seq = devm_kzalloc(&pdev->dev, len,
			GFP_KERNEL);
		if (!pdata->tlmm_init_seq)
			return -ENODEV;
		pdata->tlmm_seq_count = len / sizeof(*pdata->tlmm_init_seq);
		ret = of_property_read_u32_array(mehci->dev->of_node,
				"qcom,hsic-tlmm-init-seq",
				pdata->tlmm_init_seq, pdata->tlmm_seq_count);
		if (ret) {
			dev_err(&pdev->dev, "hsic init-seq failed:%d\n", ret);
			pdata->tlmm_seq_count = 0;
		}
	}

	ret = msm_hsic_init_vddcx(mehci, 1);
	if (ret) {
		dev_err(&pdev->dev, "unable to initialize VDDCX\n");
+2 −0
Original line number Diff line number Diff line
@@ -599,6 +599,8 @@ struct msm_hsic_host_platform_data {

	/* gpio used to resume peripheral */
	unsigned resume_gpio;
	int *tlmm_init_seq;
	int tlmm_seq_count;

	/*swfi latency is required while driving resume on to the bus */
	u32 swfi_latency;