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

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.orgSigned-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
......@@ -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.
......
......@@ -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,
};
/**
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment