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:
parent
d8d9f7931a
commit
b8416b2fed
@ -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.
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user