// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Western Digital Corporation
#include <linux/err.h>
#include <linux/string.h>
#include <linux/bitfield.h>
#include <asm/unaligned.h>
#include <ufs/ufs.h>
#include "ufs-sysfs.h"
#include "ufshcd-priv.h"
static const char *ufshcd_uic_link_state_to_string(
enum uic_link_state state)
{
switch (state) {
case UIC_LINK_OFF_STATE: return "OFF";
case UIC_LINK_ACTIVE_STATE: return "ACTIVE";
case UIC_LINK_HIBERN8_STATE: return "HIBERN8";
case UIC_LINK_BROKEN_STATE: return "BROKEN";
default: return "UNKNOWN";
}
}
static const char *ufshcd_ufs_dev_pwr_mode_to_string(
enum ufs_dev_pwr_mode state)
{
switch (state) {
case UFS_ACTIVE_PWR_MODE: return "ACTIVE";
case UFS_SLEEP_PWR_MODE: return "SLEEP";
case UFS_POWERDOWN_PWR_MODE: return "POWERDOWN";
case UFS_DEEPSLEEP_PWR_MODE: return "DEEPSLEEP";
default: return "UNKNOWN";
}
}
static inline ssize_t ufs_sysfs_pm_lvl_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count,
bool rpm)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
struct ufs_dev_info *dev_info = &hba->dev_info;
unsigned long flags, value;
if (kstrtoul(buf, 0, &value))
return -EINVAL;
if (value >= UFS_PM_LVL_MAX)
return -EINVAL;
if (ufs_pm_lvl_states[value].dev_state == UFS_DEEPSLEEP_PWR_MODE &&
(!(hba->caps & UFSHCD_CAP_DEEPSLEEP) ||
!(dev_info->wspecversion >= 0x310)))
return -EINVAL;
spin_lock_irqsave(hba->host->host_lock, flags);
if (rpm)
hba->rpm_lvl = value;
else
hba->spm_lvl = value;
spin_unlock_irqrestore(hba->host->host_lock, flags);
return count;
}
static ssize_t rpm_lvl_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ufs_hba *hba = dev_get_drvdata(dev);
return sysfs_emit