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

Commit 945af2ab authored by Pratham Pratap's avatar Pratham Pratap
Browse files

usb: phy-msm-qusb-v2: Add chip version check for errata



There was a hardware fix for Chirp Voltage Dp and Dm violation
leading to SSD enumeration failure. The fix is on 1.1 version
of the SoC.

This is a method to distinguish between the two different versions
of the SoC by reading the minor revision number as:
00 : rev 1.0
01 : rev 1.1

Using this method this errata can be worked around for the specific
chip version.

Change-Id: I34435d6b630e6f6e844493ebf4034fa6e3556df8
Signed-off-by: default avatarPratham Pratap <prathampratap@codeaurora.org>
parent 11f2cc4d
Loading
Loading
Loading
Loading
+4 −0
Original line number Original line Diff line number Diff line
@@ -184,6 +184,10 @@ Optional properties:
   state when attached in host mode and "suspend" state when detached.
   state when attached in host mode and "suspend" state when detached.
 - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
 - qcom,tune2-efuse-correction: The value to be adjusted from fused value for
   improved rise/fall times.
   improved rise/fall times.
 - nvmem-cells: specifies the handle to represent the SoC revision.
   usually it is defined by qfprom device node.
 - nvmem-cell-names: specifies the given nvmem cell name as defined in
   qfprom node.


Example:
Example:
	qusb_phy: qusb@f9b39000 {
	qusb_phy: qusb@f9b39000 {
+72 −2
Original line number Original line Diff line number Diff line
/*
/*
 * Copyright (c) 2014-2017, The Linux Foundation. All rights reserved.
 * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved.
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * 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
 * it under the terms of the GNU General Public License version 2 and
@@ -26,6 +26,7 @@
#include <linux/regulator/machine.h>
#include <linux/regulator/machine.h>
#include <linux/usb/phy.h>
#include <linux/usb/phy.h>
#include <linux/reset.h>
#include <linux/reset.h>
#include <linux/nvmem-consumer.h>
#include <linux/debugfs.h>
#include <linux/debugfs.h>
#include <linux/hrtimer.h>
#include <linux/hrtimer.h>


@@ -146,8 +147,65 @@ struct qusb_phy {
	u8			tune[5];
	u8			tune[5];


	struct hrtimer		timer;
	struct hrtimer		timer;
	int			soc_min_rev;
};
};


#ifdef CONFIG_NVMEM
/* Parse qfprom data for deciding on errata work-arounds */
static long qfprom_read(struct device *dev, const char *name)
{
	struct nvmem_cell *cell;
	ssize_t len = 0;
	u32 *buf, val = 0;
	long err = 0;

	cell = nvmem_cell_get(dev, name);
	if (IS_ERR(cell)) {
		err = PTR_ERR(cell);
		dev_err(dev, "failed opening nvmem cell err : %ld\n", err);
		/* If entry does not exist, then that is not an error */
		if (err == -ENOENT)
			err = 0;
		return err;
	}

	buf = (u32 *)nvmem_cell_read(cell, &len);
	if (IS_ERR(buf) || !len) {
		dev_err(dev, "Failed reading nvmem cell, err: %u, bytes fetched: %zd\n",
				*buf, len);
		if (!IS_ERR(buf)) {
			kfree(buf);
			err = -EINVAL;
		} else {
			err = PTR_ERR(buf);
		}
	} else {
		val = *buf;
		kfree(buf);
	}

	nvmem_cell_put(cell);
	return err ? err : (long) val;
}

/* Reads the SoC version */
static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
{
	qphy->soc_min_rev  = qfprom_read(dev, "minor_rev");
	if (qphy->soc_min_rev < 0)
		dev_err(dev, "failed getting soc_min_rev, err : %d\n",
				qphy->soc_min_rev);

	return qphy->soc_min_rev;
};
#else
/* Reads the SoC version */
static int qusb_phy_get_socrev(struct device *dev, struct qusb_phy *qphy)
{
	return 0;
}
#endif

static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
{
{
	dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d on:%d\n",
	dev_dbg(qphy->phy.dev, "%s(): clocks_enabled:%d on:%d\n",
@@ -1125,6 +1183,11 @@ static int qusb_phy_probe(struct platform_device *pdev)
		return PTR_ERR(qphy->vdda18);
		return PTR_ERR(qphy->vdda18);
	}
	}


	ret = qusb_phy_get_socrev(&pdev->dev, qphy);
	if (ret == -EPROBE_DEFER) {
		dev_err(&pdev->dev, "SoC version rd: fail: defer for now\n");
		return ret;
	}
	qphy->pinctrl = devm_pinctrl_get(dev);
	qphy->pinctrl = devm_pinctrl_get(dev);
	if (IS_ERR(qphy->pinctrl)) {
	if (IS_ERR(qphy->pinctrl)) {
		ret = PTR_ERR(qphy->pinctrl);
		ret = PTR_ERR(qphy->pinctrl);
@@ -1159,7 +1222,14 @@ static int qusb_phy_probe(struct platform_device *pdev)
	qphy->phy.type			= USB_PHY_TYPE_USB2;
	qphy->phy.type			= USB_PHY_TYPE_USB2;
	qphy->phy.notify_connect        = qusb_phy_notify_connect;
	qphy->phy.notify_connect        = qusb_phy_notify_connect;
	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;

	/*
	 * qusb_phy_disable_chirp is not required if soc version is
	 * mentioned and is not base version.
	 */
	if (qphy->soc_min_rev == 0)
		qphy->phy.disable_chirp	= qusb_phy_disable_chirp;
		qphy->phy.disable_chirp	= qusb_phy_disable_chirp;

	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;
	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;


	ret = usb_add_phy_dev(&qphy->phy);
	ret = usb_add_phy_dev(&qphy->phy);