mtd: spi-nor: core: Support misc devices

Calling ioctl PCIE_DMA_GET_FLASH_INFO to get spi nor id.

Change-Id: I1ecfdd527f18c0c323fba9673546c167032d1726
Signed-off-by: Jon Lin <jon.lin@rock-chips.com>
This commit is contained in:
Jon Lin
2022-10-24 20:30:54 +08:00
committed by Tao Huang
parent 5083234249
commit b7cf98650b
4 changed files with 114 additions and 0 deletions

View File

@@ -24,6 +24,13 @@ config MTD_SPI_NOR_USE_4K_SECTORS
Please note that some tools/drivers/filesystems may not work with
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
config MTD_SPI_NOR_MISC
bool "Support SPI NOR misc device"
default n
help
Support obtaining flash information through the ioctl interface
of the misc device.
source "drivers/mtd/spi-nor/controllers/Kconfig"
endif # MTD_SPI_NOR

View File

@@ -21,9 +21,17 @@
#include <linux/sched/task_stack.h>
#include <linux/spi/flash.h>
#include <linux/mtd/spi-nor.h>
#include <linux/miscdevice.h>
#include <uapi/linux/spi_nor_misc.h>
#include "core.h"
struct spi_nor_misc_dev {
struct miscdevice dev;
struct spi_nor *nor;
};
/* Define max times to check status register before we give up. */
/*
@@ -3462,6 +3470,78 @@ static int spi_nor_create_write_dirmap(struct spi_nor *nor)
return PTR_ERR_OR_ZERO(nor->dirmap.wdesc);
}
static int spi_nor_misc_open(struct inode *inode, struct file *file)
{
struct miscdevice *miscdev = file->private_data;
struct spi_nor_misc_dev *nor_dev;
nor_dev = container_of(miscdev, struct spi_nor_misc_dev, dev);
file->private_data = nor_dev->nor;
return 0;
}
static long spi_nor_misc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct spi_nor *nor = (struct spi_nor *)file->private_data;
struct nor_flash_user_info info;
void __user *uarg = (void __user *)arg;
int i, ret;
switch (cmd) {
case NOR_GET_FLASH_INFO:
for (i = 0; i < SPI_NOR_MAX_ID_LEN; i++)
info.id[i] = nor->info->id[i];
ret = copy_to_user(uarg, &info, sizeof(info));
if (ret) {
dev_err(nor->dev, "failed to get elbi data\n");
return -EFAULT;
}
break;
default:
break;
}
return 0;
}
static const struct file_operations spi_nor_misc_ops = {
.owner = THIS_MODULE,
.open = spi_nor_misc_open,
.unlocked_ioctl = spi_nor_misc_ioctl,
};
static int spi_nor_add_misc(struct spi_nor *nor)
{
int ret;
struct spi_nor_misc_dev *nor_dev;
char name[24];
nor_dev = devm_kzalloc(nor->dev, sizeof(struct spi_nor_misc_dev),
GFP_KERNEL);
if (!nor_dev)
return -ENOMEM;
nor_dev->dev.minor = MISC_DYNAMIC_MINOR;
snprintf(name, sizeof(name), "%s%s", "nor_misc_", dev_name(nor->dev));
nor_dev->dev.name = devm_kstrdup(nor->dev, name, GFP_KERNEL);
nor_dev->dev.fops = &spi_nor_misc_ops;
nor_dev->dev.parent = nor->dev;
ret = misc_register(&nor_dev->dev);
if (ret) {
dev_err(nor->dev, "failed to register misc device.\n");
return ret;
}
nor_dev->nor = nor;
nor->misc_dev = &nor_dev->dev;
dev_info(nor->dev, "register misc device\n");
return 0;
}
static int spi_nor_probe(struct spi_mem *spimem)
{
struct spi_device *spi = spimem->spi;
@@ -3531,6 +3611,9 @@ static int spi_nor_probe(struct spi_mem *spimem)
if (ret)
return ret;
if (IS_ENABLED(CONFIG_MTD_SPI_NOR_MISC))
spi_nor_add_misc(nor);
return mtd_device_register(&nor->mtd, data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
@@ -3541,6 +3624,9 @@ static int spi_nor_remove(struct spi_mem *spimem)
spi_nor_restore(nor);
if (IS_ENABLED(CONFIG_MTD_SPI_NOR_MISC) && nor->misc_dev)
misc_deregister(nor->misc_dev);
/* Clean up MTD stuff. */
return mtd_device_unregister(&nor->mtd);
}

View File

@@ -388,6 +388,7 @@ struct spi_nor {
struct spi_mem_dirmap_desc *wdesc;
} dirmap;
struct miscdevice *misc_dev;
void *priv;
};

View File

@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*/
#ifndef _UAPI__SPI_NOR_MISC_H__
#define _UAPI__SPI_NOR_MISC_H__
#include <linux/types.h>
#define SPI_NOR_MAX_ID_LEN 6
struct nor_flash_user_info {
__u8 id[SPI_NOR_MAX_ID_LEN];
};
#define NOR_BASE 'P'
#define NOR_GET_FLASH_INFO _IOR(NOR_BASE, 0, struct nor_flash_user_info)
#endif