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

Commit b8416b2f authored by Bjorn Andersson's avatar Bjorn Andersson Committed by Martin K. Petersen
Browse files

scsi: ufs-qcom: Implement device_reset vops

The UFS_RESET pin on Qualcomm SoCs are controlled by TLMM and exposed
through the GPIO framework. Acquire the device-reset GPIO and use this to
implement the device_reset vops, to allow resetting the attached memory.

Based on downstream support implemented by Subhash Jadavani
<subhashj@codeaurora.org>.

Link: https://lore.kernel.org/r/20190828191756.24312-3-bjorn.andersson@linaro.org


Signed-off-by: default avatarBjorn Andersson <bjorn.andersson@linaro.org>
Acked-by: default avatarRob Herring <robh@kernel.org>
Acked-by: default avatarAvri Altman <Avri.Altman@wdc.com>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
parent d8d9f793
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -54,6 +54,8 @@ Optional properties:
			  PHY reset from the UFS controller.
- resets            : reset node register
- reset-names       : describe reset node register, the "rst" corresponds to reset the whole UFS IP.
- reset-gpios       : A phandle and gpio specifier denoting the GPIO connected
		      to the RESET pin of the UFS memory device.

Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on.
+36 −0
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/gpio/consumer.h>
#include <linux/reset-controller.h>

#include "ufshcd.h"
@@ -1137,6 +1138,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
		}
	}

	host->device_reset = devm_gpiod_get_optional(dev, "reset",
						     GPIOD_OUT_HIGH);
	if (IS_ERR(host->device_reset)) {
		err = PTR_ERR(host->device_reset);
		if (err != -EPROBE_DEFER)
			dev_err(dev, "failed to acquire reset gpio: %d\n", err);
		goto out_variant_clear;
	}

	err = ufs_qcom_bus_register(host);
	if (err)
		goto out_variant_clear;
@@ -1542,6 +1552,31 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
	usleep_range(1000, 1100);
}

/**
 * ufs_qcom_device_reset() - toggle the (optional) device reset line
 * @hba: per-adapter instance
 *
 * Toggles the (optional) reset line to reset the attached device.
 */
static void ufs_qcom_device_reset(struct ufs_hba *hba)
{
	struct ufs_qcom_host *host = ufshcd_get_variant(hba);

	/* reset gpio is optional */
	if (!host->device_reset)
		return;

	/*
	 * The UFS device shall detect reset pulses of 1us, sleep for 10us to
	 * be on the safe side.
	 */
	gpiod_set_value_cansleep(host->device_reset, 1);
	usleep_range(10, 15);

	gpiod_set_value_cansleep(host->device_reset, 0);
	usleep_range(10, 15);
}

/**
 * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
 *
@@ -1562,6 +1597,7 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
	.suspend		= ufs_qcom_suspend,
	.resume			= ufs_qcom_resume,
	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
	.device_reset		= ufs_qcom_device_reset,
};

/**
+4 −0
Original line number Diff line number Diff line
@@ -195,6 +195,8 @@ struct ufs_qcom_testbus {
	u8 select_minor;
};

struct gpio_desc;

struct ufs_qcom_host {
	/*
	 * Set this capability if host controller supports the QUniPro mode
@@ -232,6 +234,8 @@ struct ufs_qcom_host {
	struct ufs_qcom_testbus testbus;

	struct reset_controller_dev rcdev;

	struct gpio_desc *device_reset;
};

static inline u32