#include <linux/delay.h>
#include <linux/device.h>
#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mutex.h>
#include <linux/sched.h>
#include <linux/sizes.h>
#include <linux/spi/flash.h>
#include <linux/spi/spi.h>
#include <linux/of.h>
struct mchp48_caps { … };
struct mchp48l640_flash { … };
#define MCHP48L640_CMD_WREN …
#define MCHP48L640_CMD_WRDI …
#define MCHP48L640_CMD_WRITE …
#define MCHP48L640_CMD_READ …
#define MCHP48L640_CMD_WRSR …
#define MCHP48L640_CMD_RDSR …
#define MCHP48L640_STATUS_RDY …
#define MCHP48L640_STATUS_WEL …
#define MCHP48L640_STATUS_BP0 …
#define MCHP48L640_STATUS_BP1 …
#define MCHP48L640_STATUS_SWM …
#define MCHP48L640_STATUS_PRO …
#define MCHP48L640_STATUS_ASE …
#define MCHP48L640_TIMEOUT …
#define MAX_CMD_SIZE …
#define to_mchp48l640_flash(x) …
static int mchp48l640_mkcmd(struct mchp48l640_flash *flash, u8 cmd, loff_t addr, char *buf)
{ … }
static int mchp48l640_read_status(struct mchp48l640_flash *flash, int *status)
{ … }
static int mchp48l640_waitforbit(struct mchp48l640_flash *flash, int bit, bool set)
{ … }
static int mchp48l640_write_prepare(struct mchp48l640_flash *flash, bool enable)
{ … }
static int mchp48l640_set_mode(struct mchp48l640_flash *flash)
{ … }
static int mchp48l640_wait_rdy(struct mchp48l640_flash *flash)
{
return mchp48l640_waitforbit(flash, MCHP48L640_STATUS_RDY, false);
};
static int mchp48l640_write_page(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const unsigned char *buf)
{
struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
unsigned char *cmd;
int ret;
int cmdlen;
cmd = kmalloc((3 + len), GFP_KERNEL | GFP_DMA);
if (!cmd)
return -ENOMEM;
ret = mchp48l640_wait_rdy(flash);
if (ret)
goto fail;
ret = mchp48l640_write_prepare(flash, true);
if (ret)
goto fail;
mutex_lock(&flash->lock);
cmdlen = mchp48l640_mkcmd(flash, MCHP48L640_CMD_WRITE, to, cmd);
memcpy(&cmd[cmdlen], buf, len);
ret = spi_write(flash->spi, cmd, cmdlen + len);
mutex_unlock(&flash->lock);
if (!ret)
*retlen += len;
else
goto fail;
ret = mchp48l640_waitforbit(flash, MCHP48L640_STATUS_WEL, false);
if (ret)
goto fail;
kfree(cmd);
return 0;
fail:
kfree(cmd);
dev_err(&flash->spi->dev, "write fail with: %d", ret);
return ret;
};
static int mchp48l640_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const unsigned char *buf)
{ … }
static int mchp48l640_read_page(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, unsigned char *buf)
{ … }
static int mchp48l640_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, unsigned char *buf)
{
struct mchp48l640_flash *flash = to_mchp48l640_flash(mtd);
int ret;
size_t wlen = 0;
loff_t woff = from;
size_t ws;
size_t page_sz = flash->caps->page_size;
while (wlen < len) {
ws = min((len - wlen), page_sz);
ret = mchp48l640_read_page(mtd, woff, ws, retlen, &buf[wlen]);
if (ret)
return ret;
wlen += ws;
woff += ws;
}
return 0;
};
static const struct mchp48_caps mchp48l640_caps = …;
static int mchp48l640_probe(struct spi_device *spi)
{ … }
static void mchp48l640_remove(struct spi_device *spi)
{ … }
static const struct of_device_id mchp48l640_of_table[] = …;
MODULE_DEVICE_TABLE(of, mchp48l640_of_table);
static const struct spi_device_id mchp48l640_spi_ids[] = …;
MODULE_DEVICE_TABLE(spi, mchp48l640_spi_ids);
static struct spi_driver mchp48l640_driver = …;
module_spi_driver(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_AUTHOR(…) …;
MODULE_LICENSE(…) …;
MODULE_ALIAS(…) …;