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: Bjorn Andersson <bjorn.andersson@linaro.org>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Avri Altman <Avri.Altman@wdc.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
This commit is contained in:
Bjorn Andersson 2019-08-28 12:17:55 -07:00 committed by Martin K. Petersen
parent d8d9f7931a
commit b8416b2fed
3 changed files with 42 additions and 0 deletions

View File

@ -54,6 +54,8 @@ Optional properties:
PHY reset from the UFS controller. PHY reset from the UFS controller.
- resets : reset node register - resets : reset node register
- reset-names : describe reset node register, the "rst" corresponds to reset the whole UFS IP. - 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 Note: If above properties are not defined it can be assumed that the supply
regulators or clocks are always on. regulators or clocks are always on.

View File

@ -8,6 +8,7 @@
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/gpio/consumer.h>
#include <linux/reset-controller.h> #include <linux/reset-controller.h>
#include "ufshcd.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); err = ufs_qcom_bus_register(host);
if (err) if (err)
goto out_variant_clear; goto out_variant_clear;
@ -1542,6 +1552,31 @@ static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
usleep_range(1000, 1100); 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 * 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, .suspend = ufs_qcom_suspend,
.resume = ufs_qcom_resume, .resume = ufs_qcom_resume,
.dbg_register_dump = ufs_qcom_dump_dbg_regs, .dbg_register_dump = ufs_qcom_dump_dbg_regs,
.device_reset = ufs_qcom_device_reset,
}; };
/** /**

View File

@ -195,6 +195,8 @@ struct ufs_qcom_testbus {
u8 select_minor; u8 select_minor;
}; };
struct gpio_desc;
struct ufs_qcom_host { struct ufs_qcom_host {
/* /*
* Set this capability if host controller supports the QUniPro mode * Set this capability if host controller supports the QUniPro mode
@ -232,6 +234,8 @@ struct ufs_qcom_host {
struct ufs_qcom_testbus testbus; struct ufs_qcom_testbus testbus;
struct reset_controller_dev rcdev; struct reset_controller_dev rcdev;
struct gpio_desc *device_reset;
}; };
static inline u32 static inline u32