496 lines
15 KiB
C
496 lines
15 KiB
C
|
// SPDX-License-Identifier: GPL-2.0
|
||
|
/*
|
||
|
* Samsung Specific feature
|
||
|
*
|
||
|
* Copyright (C) 2021 Samsung Electronics Co., Ltd.
|
||
|
*
|
||
|
* Authors:
|
||
|
* Storage Driver <storage.sec@samsung.com>
|
||
|
*/
|
||
|
|
||
|
#include <linux/of.h>
|
||
|
#include <linux/of_gpio.h>
|
||
|
#include <linux/mmc/host.h>
|
||
|
#include <linux/mmc/mmc.h>
|
||
|
#include <linux/sec_class.h>
|
||
|
|
||
|
#include "dw_mmc-exynos.h"
|
||
|
#include "mmc-sec-feature.h"
|
||
|
#include "mmc-sec-sysfs.h"
|
||
|
|
||
|
static ssize_t sd_detection_cmd_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||
|
|
||
|
if (priv->sec_sd_slot_type > SEC_NO_DET_SD_SLOT && !gpio_is_valid(priv->cd_gpio))
|
||
|
goto gpio_error;
|
||
|
|
||
|
if (gpio_get_value(priv->cd_gpio) ^ (host->pdata->use_gpio_invert)
|
||
|
&& (priv->sec_sd_slot_type == SEC_HYBRID_SD_SLOT)) {
|
||
|
dev_info(host->dev, "SD slot tray Removed.\n");
|
||
|
return sprintf(buf, "Notray\n");
|
||
|
}
|
||
|
|
||
|
if (host->slot && host->slot->mmc && host->slot->mmc->card) {
|
||
|
dev_info(host->dev, "SD card inserted.\n");
|
||
|
return sprintf(buf, "Insert\n");
|
||
|
}
|
||
|
dev_info(host->dev, "SD card removed.\n");
|
||
|
return sprintf(buf, "Remove\n");
|
||
|
|
||
|
gpio_error:
|
||
|
dev_info(host->dev, "%s : External SD detect pin Error\n", __func__);
|
||
|
return sprintf(buf, "Error\n");
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_detection_cnt_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
dev_info(dev, "%s : CD count is = %u\n", __func__, sd_op_info.card_detect_cnt);
|
||
|
return sprintf(buf, "%u\n", sd_op_info.card_detect_cnt);
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_detection_maxmode_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
const char *uhs_bus_speed_mode = "";
|
||
|
struct device_node *np = host->dev->of_node;
|
||
|
|
||
|
if (of_find_property(np, "sd-uhs-sdr104", NULL))
|
||
|
uhs_bus_speed_mode = "SDR104";
|
||
|
else if (of_find_property(np, "sd-uhs-ddr50", NULL))
|
||
|
uhs_bus_speed_mode = "DDR50";
|
||
|
else if (of_find_property(np, "sd-uhs-sdr50", NULL))
|
||
|
uhs_bus_speed_mode = "SDR50";
|
||
|
else if (of_find_property(np, "sd-uhs-sdr25", NULL))
|
||
|
uhs_bus_speed_mode = "SDR25";
|
||
|
else if (of_find_property(np, "sd-uhs-sdr12", NULL))
|
||
|
uhs_bus_speed_mode = "SDR12";
|
||
|
else
|
||
|
uhs_bus_speed_mode = "HS";
|
||
|
|
||
|
dev_info(host->dev, "%s : Max supported Host Speed Mode = %s\n", __func__, uhs_bus_speed_mode);
|
||
|
return sprintf(buf, "%s\n", uhs_bus_speed_mode);
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_detection_curmode_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
|
||
|
const char *uhs_bus_speed_mode = "";
|
||
|
static const char *const uhs_speeds[] = {
|
||
|
[UHS_SDR12_BUS_SPEED] = "SDR12",
|
||
|
[UHS_SDR25_BUS_SPEED] = "SDR25",
|
||
|
[UHS_SDR50_BUS_SPEED] = "SDR50",
|
||
|
[UHS_SDR104_BUS_SPEED] = "SDR104",
|
||
|
[UHS_DDR50_BUS_SPEED] = "DDR50",
|
||
|
};
|
||
|
|
||
|
if (host->slot && host->slot->mmc && host->slot->mmc->card) {
|
||
|
if (mmc_card_uhs(host->slot->mmc->card))
|
||
|
uhs_bus_speed_mode = uhs_speeds[host->slot->mmc->card->sd_bus_speed];
|
||
|
else
|
||
|
uhs_bus_speed_mode = "HS";
|
||
|
} else
|
||
|
uhs_bus_speed_mode = "No Card";
|
||
|
|
||
|
dev_info(host->dev, "%s : Current SD Card Speed = %s\n", __func__, uhs_bus_speed_mode);
|
||
|
return sprintf(buf, "%s\n", uhs_bus_speed_mode);
|
||
|
}
|
||
|
|
||
|
static ssize_t sdcard_summary_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_card *card;
|
||
|
const char *uhs_bus_speed_mode = "";
|
||
|
static const char *const uhs_speeds[] = {
|
||
|
[UHS_SDR12_BUS_SPEED] = "SDR12",
|
||
|
[UHS_SDR25_BUS_SPEED] = "SDR25",
|
||
|
[UHS_SDR50_BUS_SPEED] = "SDR50",
|
||
|
[UHS_SDR104_BUS_SPEED] = "SDR104",
|
||
|
[UHS_DDR50_BUS_SPEED] = "DDR50",
|
||
|
};
|
||
|
static const char *const unit[] = {"KB", "MB", "GB", "TB"};
|
||
|
unsigned int size, serial;
|
||
|
int digit = 1;
|
||
|
char ret_size[6];
|
||
|
|
||
|
if (host->slot && host->slot->mmc && host->slot->mmc->card) {
|
||
|
card = host->slot->mmc->card;
|
||
|
|
||
|
/* MANID */
|
||
|
/* SERIAL */
|
||
|
serial = card->cid.serial & (0x0000FFFF);
|
||
|
|
||
|
/*SIZE*/
|
||
|
if (card->csd.read_blkbits == 9) /* 1 Sector = 512 Bytes */
|
||
|
size = (card->csd.capacity) >> 1;
|
||
|
else if (card->csd.read_blkbits == 11) /* 1 Sector = 2048 Bytes */
|
||
|
size = (card->csd.capacity) << 1;
|
||
|
else /* 1 Sector = 1024 Bytes */
|
||
|
size = card->csd.capacity;
|
||
|
|
||
|
if (size >= 380000000 && size <= 410000000) { /* QUIRK 400GB SD Card */
|
||
|
sprintf(ret_size, "400GB");
|
||
|
} else if (size >= 190000000 && size <= 210000000) { /* QUIRK 200GB SD Card */
|
||
|
sprintf(ret_size, "200GB");
|
||
|
} else {
|
||
|
while ((size >> 1) > 0) {
|
||
|
size = size >> 1;
|
||
|
digit++;
|
||
|
}
|
||
|
sprintf(ret_size, "%d%s", 1 << (digit%10), unit[digit/10]);
|
||
|
}
|
||
|
|
||
|
/* SPEEDMODE */
|
||
|
if (mmc_card_uhs(card))
|
||
|
uhs_bus_speed_mode = uhs_speeds[card->sd_bus_speed];
|
||
|
else if (mmc_card_hs(card))
|
||
|
uhs_bus_speed_mode = "HS";
|
||
|
else
|
||
|
uhs_bus_speed_mode = "DS";
|
||
|
|
||
|
/* SUMMARY */
|
||
|
dev_info(host->dev, "MANID : 0x%02X, SERIAL : %04X, SIZE : %s, SPEEDMODE : %s\n",
|
||
|
card->cid.manfid, serial, ret_size, uhs_bus_speed_mode);
|
||
|
return sprintf(buf, "\"MANID\":\"0x%02X\",\"SERIAL\":\"%04X\""\
|
||
|
",\"SIZE\":\"%s\",\"SPEEDMODE\":\"%s\",\"NOTI\":\"%d\"\n",
|
||
|
card->cid.manfid, serial, ret_size, uhs_bus_speed_mode,
|
||
|
sd_status_err_info[host->slot->mmc->index].noti_cnt);
|
||
|
} else {
|
||
|
/* SUMMARY : No SD Card Case */
|
||
|
dev_info(host->dev, "%s : No SD Card\n", __func__);
|
||
|
return sprintf(buf, "\"MANID\":\"NoCard\",\"SERIAL\":\"NoCard\""\
|
||
|
",\"SIZE\":\"NoCard\",\"SPEEDMODE\":\"NoCard\",\"NOTI\":\"NoCard\"\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_count_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int host_idx = mmc->index;
|
||
|
struct mmc_sec_err_info *err_log = sd_err_info[host_idx];
|
||
|
u64 total_cnt = 0;
|
||
|
int len = 0;
|
||
|
int i = 0;
|
||
|
|
||
|
if (!card) {
|
||
|
len = snprintf(buf, PAGE_SIZE, "no card\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < 6; i++) {
|
||
|
if (total_cnt < U64_MAX)
|
||
|
total_cnt += err_log[i].count;
|
||
|
}
|
||
|
len = snprintf(buf, PAGE_SIZE, "%lld\n", total_cnt);
|
||
|
|
||
|
out:
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_cid_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int len = 0;
|
||
|
|
||
|
if (!card) {
|
||
|
len = snprintf(buf, PAGE_SIZE, "no card\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
len = snprintf(buf, PAGE_SIZE,
|
||
|
"%08x%08x%08x%08x\n",
|
||
|
card->raw_cid[0], card->raw_cid[1],
|
||
|
card->raw_cid[2], card->raw_cid[3]);
|
||
|
out:
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static inline void mmc_check_error_count(struct mmc_sec_err_info *err_log,
|
||
|
unsigned long long *total_c_cnt, unsigned long long *total_t_cnt)
|
||
|
{
|
||
|
int i = 0;
|
||
|
//Only sbc(0,1)/cmd(2,3)/data(4,5) is checked.
|
||
|
for (i = 0; i < 6; i++) {
|
||
|
if (err_log[i].err_type == -EILSEQ && *total_c_cnt < U64_MAX)
|
||
|
*total_c_cnt += err_log[i].count;
|
||
|
if (err_log[i].err_type == -ETIMEDOUT && *total_t_cnt < U64_MAX)
|
||
|
*total_t_cnt += err_log[i].count;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_health_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int host_idx = mmc->index;
|
||
|
struct mmc_sec_err_info *err_log = sd_err_info[host_idx];
|
||
|
u64 total_c_cnt = 0;
|
||
|
u64 total_t_cnt = 0;
|
||
|
int len = 0;
|
||
|
|
||
|
if (!card) {
|
||
|
//There should be no spaces in 'No Card'(Vold Team).
|
||
|
len = snprintf(buf, PAGE_SIZE, "NOCARD\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
mmc_check_error_count(err_log, &total_c_cnt, &total_t_cnt);
|
||
|
|
||
|
if (sd_status_err_info[host_idx].ge_cnt > 100 ||
|
||
|
sd_status_err_info[host_idx].ecc_cnt > 0 ||
|
||
|
sd_status_err_info[host_idx].wp_cnt > 0 ||
|
||
|
sd_status_err_info[host_idx].oor_cnt > 10 ||
|
||
|
total_t_cnt > 100 || total_c_cnt > 100)
|
||
|
len = snprintf(buf, PAGE_SIZE, "BAD\n");
|
||
|
else
|
||
|
len = snprintf(buf, PAGE_SIZE, "GOOD\n");
|
||
|
|
||
|
out:
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
#define SEC_MMC_STATUS_ERR_INFO_GET_VALUE(member) ({ \
|
||
|
err_status_info->member = err_status->member - err_status_backup->member; })
|
||
|
|
||
|
static inline void mmc_check_error_count_calc_current(int host_idx,
|
||
|
unsigned long long *total_c_cnt, unsigned long long *total_t_cnt,
|
||
|
struct mmc_sec_status_err_info *err_status_info)
|
||
|
{
|
||
|
struct mmc_sec_err_info *err_log = sd_err_info[host_idx];
|
||
|
struct mmc_sec_err_info *err_log_backup = sd_err_info_backup[host_idx];
|
||
|
struct mmc_sec_status_err_info *err_status = &sd_status_err_info[host_idx];
|
||
|
struct mmc_sec_status_err_info *err_status_backup = &sd_status_err_info_backup[host_idx];
|
||
|
int i = 0;
|
||
|
|
||
|
//Only sbc(0,1)/cmd(2,3)/data(4,5) is checked.
|
||
|
for (i = 0; i < 6; i++) {
|
||
|
if (err_log[i].err_type == -EILSEQ && *total_c_cnt < U64_MAX)
|
||
|
*total_c_cnt += (err_log[i].count - err_log_backup[i].count);
|
||
|
if (err_log[i].err_type == -ETIMEDOUT && *total_t_cnt < U64_MAX)
|
||
|
*total_t_cnt += (err_log[i].count - err_log_backup[i].count);
|
||
|
}
|
||
|
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(ge_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(cc_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(ecc_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(wp_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(oor_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(halt_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(cq_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(rpmb_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_GET_VALUE(noti_cnt);
|
||
|
}
|
||
|
|
||
|
#define SEC_MMC_STATUS_ERR_INFO_BACKUP(member) ({ \
|
||
|
err_status_backup->member = err_status->member; })
|
||
|
|
||
|
static inline void mmc_backup_err_info(int host_idx)
|
||
|
{
|
||
|
struct mmc_sec_err_info *err_log = sd_err_info[host_idx];
|
||
|
struct mmc_sec_err_info *err_log_backup = sd_err_info_backup[host_idx];
|
||
|
struct mmc_sec_status_err_info *err_status = &sd_status_err_info[host_idx];
|
||
|
struct mmc_sec_status_err_info *err_status_backup = &sd_status_err_info_backup[host_idx];
|
||
|
int i = 0;
|
||
|
|
||
|
// save current error count
|
||
|
for (i = 0; i < MAX_ERR_LOG_INDEX; i++)
|
||
|
err_log_backup[i].count = err_log[i].count;
|
||
|
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(ge_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(cc_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(ecc_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(wp_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(oor_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(halt_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(cq_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(rpmb_cnt);
|
||
|
SEC_MMC_STATUS_ERR_INFO_BACKUP(noti_cnt);
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_data_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int host_idx = mmc->index;
|
||
|
struct mmc_sec_status_err_info status_err_info;
|
||
|
u64 total_c_cnt = 0;
|
||
|
u64 total_t_cnt = 0;
|
||
|
int len = 0;
|
||
|
|
||
|
memset(&status_err_info, 0, sizeof(struct mmc_sec_status_err_info));
|
||
|
|
||
|
if (!card) {
|
||
|
len = snprintf(buf, PAGE_SIZE,
|
||
|
"\"GE\":\"0\",\"CC\":\"0\",\"ECC\":\"0\",\"WP\":\"0\"," \
|
||
|
"\"OOR\":\"0\",\"CRC\":\"0\",\"TMO\":\"0\"\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
mmc_check_error_count_calc_current(host_idx, &total_c_cnt, &total_t_cnt, &status_err_info);
|
||
|
|
||
|
len = snprintf(buf, PAGE_SIZE,
|
||
|
"\"GE\":\"%d\",\"CC\":\"%d\",\"ECC\":\"%d\",\"WP\":\"%d\"," \
|
||
|
"\"OOR\":\"%d\",\"CRC\":\"%lld\",\"TMO\":\"%lld\"\n",
|
||
|
status_err_info.ge_cnt,
|
||
|
status_err_info.cc_cnt,
|
||
|
status_err_info.ecc_cnt,
|
||
|
status_err_info.wp_cnt,
|
||
|
status_err_info.oor_cnt,
|
||
|
total_c_cnt, total_t_cnt);
|
||
|
out:
|
||
|
return len;
|
||
|
}
|
||
|
|
||
|
static ssize_t sd_data_store(struct device *dev, struct device_attribute *attr,
|
||
|
const char *buf, size_t count)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int host_idx = mmc->index;
|
||
|
|
||
|
if (!card)
|
||
|
return -ENODEV;
|
||
|
|
||
|
if ((buf[0] != 'C' && buf[0] != 'c') || (count != 1))
|
||
|
return -EINVAL;
|
||
|
|
||
|
mmc_backup_err_info(host_idx);
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
static ssize_t mmc_error_count_show(struct device *dev,
|
||
|
struct device_attribute *attr, char *buf)
|
||
|
{
|
||
|
struct dw_mci *host = dev_get_drvdata(dev);
|
||
|
struct mmc_host *mmc = host->slot->mmc;
|
||
|
struct mmc_card *card = mmc->card;
|
||
|
int host_idx = mmc->index;
|
||
|
struct mmc_sec_err_info *err_log = sd_err_info[host_idx];
|
||
|
u64 total_c_cnt = 0;
|
||
|
u64 total_t_cnt = 0;
|
||
|
int total_len = 0;
|
||
|
int i = 0;
|
||
|
|
||
|
if (!card) {
|
||
|
total_len = snprintf(buf, PAGE_SIZE, "It's no card error..\n");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
total_len += snprintf(buf, PAGE_SIZE,
|
||
|
"type : err status: first_issue_time: last_issue_time: count\n");
|
||
|
|
||
|
for (i = 0; i < MAX_ERR_LOG_INDEX; i++) {
|
||
|
total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
|
||
|
"%5s:%4d 0x%08x %16llu, %16llu, %10d\n",
|
||
|
err_log[i].type, err_log[i].err_type,
|
||
|
err_log[i].status,
|
||
|
err_log[i].first_issue_time,
|
||
|
err_log[i].last_issue_time,
|
||
|
err_log[i].count);
|
||
|
}
|
||
|
|
||
|
mmc_check_error_count(err_log, &total_c_cnt, &total_t_cnt);
|
||
|
|
||
|
total_len += snprintf(buf + total_len, PAGE_SIZE - total_len,
|
||
|
"GE:%d,CC:%d,ECC:%d,WP:%d,OOR:%d,CRC:%lld,TMO:%lld,HALT:%d,CQEN:%d,RPMB:%d\n",
|
||
|
sd_status_err_info[host_idx].ge_cnt,
|
||
|
sd_status_err_info[host_idx].cc_cnt,
|
||
|
sd_status_err_info[host_idx].ecc_cnt,
|
||
|
sd_status_err_info[host_idx].wp_cnt,
|
||
|
sd_status_err_info[host_idx].oor_cnt,
|
||
|
total_c_cnt, total_t_cnt,
|
||
|
sd_status_err_info[host_idx].halt_cnt,
|
||
|
sd_status_err_info[host_idx].cq_cnt,
|
||
|
sd_status_err_info[host_idx].rpmb_cnt);
|
||
|
|
||
|
out:
|
||
|
return total_len;
|
||
|
}
|
||
|
|
||
|
static DEVICE_ATTR(status, 0444, sd_detection_cmd_show, NULL);
|
||
|
static DEVICE_ATTR(cd_cnt, 0444, sd_detection_cnt_show, NULL);
|
||
|
static DEVICE_ATTR(max_mode, 0444, sd_detection_maxmode_show, NULL);
|
||
|
static DEVICE_ATTR(current_mode, 0444, sd_detection_curmode_show, NULL);
|
||
|
static DEVICE_ATTR(sdcard_summary, 0444, sdcard_summary_show, NULL);
|
||
|
static DEVICE_ATTR(sd_count, 0444, sd_count_show, NULL);
|
||
|
static DEVICE_ATTR(data, 0444, sd_cid_show, NULL);
|
||
|
static DEVICE_ATTR(fc, 0444, sd_health_show, NULL);
|
||
|
static DEVICE_ATTR(sd_data, 0664, sd_data_show, sd_data_store);
|
||
|
static DEVICE_ATTR(err_count, 0444, mmc_error_count_show, NULL);
|
||
|
|
||
|
static void mmc_sec_device_create_file(struct device *dev,
|
||
|
const struct device_attribute *dev_attr)
|
||
|
{
|
||
|
if (device_create_file(dev, dev_attr) < 0)
|
||
|
pr_err("%s : Failed to create device file(%s)!\n",
|
||
|
__func__, dev_attr->attr.name);
|
||
|
}
|
||
|
|
||
|
void mmc_sec_init_sysfs(struct dw_mci *host)
|
||
|
{
|
||
|
struct dw_mci_exynos_priv_data *priv = host->priv;
|
||
|
|
||
|
/* Initialize cd_cnt to 0. */
|
||
|
sd_op_info.card_detect_cnt = 0;
|
||
|
|
||
|
if ((priv->sec_sd_slot_type) >= SEC_NO_DET_SD_SLOT) {
|
||
|
if (!sd_detection_cmd_dev) {
|
||
|
sd_detection_cmd_dev = sec_device_create(host, "sdcard");
|
||
|
if (IS_ERR(sd_detection_cmd_dev)) {
|
||
|
pr_err("Fail to create sysfs dev\n");
|
||
|
goto failed_sdcard;
|
||
|
}
|
||
|
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_status);
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_max_mode);
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_current_mode);
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_cd_cnt);
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_sdcard_summary);
|
||
|
mmc_sec_device_create_file(sd_detection_cmd_dev, &dev_attr_err_count);
|
||
|
}
|
||
|
failed_sdcard:
|
||
|
if (!sd_info_cmd_dev) {
|
||
|
sd_info_cmd_dev = sec_device_create(host, "sdinfo");
|
||
|
if (IS_ERR(sd_info_cmd_dev)) {
|
||
|
pr_err("Fail to create sysfs dev\n");
|
||
|
goto failed_sdinfo;
|
||
|
}
|
||
|
|
||
|
mmc_sec_device_create_file(sd_info_cmd_dev, &dev_attr_sd_count);
|
||
|
mmc_sec_device_create_file(sd_info_cmd_dev, &dev_attr_data);
|
||
|
mmc_sec_device_create_file(sd_info_cmd_dev, &dev_attr_fc);
|
||
|
}
|
||
|
failed_sdinfo:
|
||
|
if (!sd_data_cmd_dev) {
|
||
|
sd_data_cmd_dev = sec_device_create(host, "sddata");
|
||
|
if (IS_ERR(sd_data_cmd_dev)) {
|
||
|
pr_err("Fail to create sysfs dev\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
mmc_sec_device_create_file(sd_data_cmd_dev, &dev_attr_sd_data);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|