[RK3399][Android7.1]驱动FLASH(W25Q128)

平台 内核版本 安卓版本
RK3399 Linux4.4 Android7.1

W25Q128介绍

W25Q128阵列将16M 的容量分为 256个块(Block)每个块大小为 64K字节,每个块又分为16个扇区(Sector),每个扇区 4K个字节。 W25Q128的最少擦除单位为一个扇区,也就是每次必须擦除4K个字节。操作需要给 W25Q128 开辟一个至少 4K的缓存区,对 SRAM 要求比较高,要求芯片必须有 4K 以上 SRAM 才能很好的操作。
在这里插入图片描述


软件基础

在设备树中每一个spi节点对应一个SPI控制器(一般情况下软件将bus和控制器配置成如下对应关系)

spi0 <==> bus 0
spi1 <==> bus 1
spi2 <==> bus 2

其中每个SPI控制器上片选数有一个或多个,具体看芯片

SPI0_CSN0
SPI0_CSN1

SPI1_CSN0

SPI2_CSN0
SPI2_CSN1

SPI工作方式

SPI以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线

管脚 解释
CS 片选信号
SCLK 时钟信号
MOSI 主设备数据输出,从设备数据输入
MISO 主设备数据输入,从设备数据输出

Linux内核用CPOLCPHA的组合来表示当前SPI的四种工作模式

CPOL=0,CPHA=0		SPI_MODE_0
CPOL=0,CPHA=1		SPI_MODE_1
CPOL=1,CPHA=0		SPI_MODE_2
CPOL=1,CPHA=1		SPI_MODE_3

CPOL:表示时钟信号的初始电平的状态,为低电平,为高电平

CPHA:表示在哪个时钟沿采样,为第一个时钟沿采样,为第二个时钟沿采样

SPI的四种工作模式波形图如下
在这里插入图片描述


硬件连接(以W25Q128FV为例子介绍)

w25q128fv Firefly-RK3399
CS SPI1_CSN0
VCC VCC3V3_SYS
DO SPI1_RXD
DI SPI1_TXD
GND GND
HOLD TP_RST(需要拉高到3V)
CLK SPI1_CLK

DeviceTree

	&spi1 {
		status = "okay";
		max-freq = <48000000>;
		dev-port = <1>;

		w25q128fv@10{
			status = "okay";
			compatible = "firefly,w25q128fv";
			reg = <0x0>;
			spi-max-frequency = <48000000>;
		};
	};
字段 解释
dev-port 表示bus_num,因为这里用的是spi1,所以配置为1
@10 1表示bus_num,需要和dev-port一致, 0表示spi设备使用CSN0作为片选
reg = <0x0> 表示spi设备使用的片选,需要和上面一致,即CSN0

驱动

static struct of_device_id firefly_match_table[] = {
	{ .compatible = "firefly,w25q128fv",},
	{},
};
static struct spi_driver w25q128fv_spi_driver = {
	.driver = {
		.name = "firefly-spi",
		.owner = THIS_MODULE,
		.of_match_table = firefly_match_table,
	},
	.probe = w25q128fv_spi_probe,
};
static int w25q128fv_spi_init(void)
{
	return spi_register_driver(&w25q128fv_spi_driver);
}
module_init(w25q128fv_spi_init);

当驱动匹配后

扫描二维码关注公众号,回复: 9339979 查看本文章
static int w25q128fv_spi_probe(struct spi_device *spi)
{
    int ret = 0;
    struct device_node __maybe_unused *np = spi->dev.of_node;

    dev_dbg(&spi->dev, "Firefly SPI demo program\n");

	if(!spi)
		return -ENOMEM;

	dev_err(&spi->dev, "w25q128fv_spi_probe: setup mode %d, %s%s%s%s%u bits/w, %u Hz max\n",
			(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
			(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
			(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
			(spi->mode & SPI_3WIRE) ? "3wire, " : "",
			(spi->mode & SPI_LOOP) ? "loopback, " : "",
			spi->bits_per_word, spi->max_speed_hz);

#ifdef USE_TIMER
	/* init timer */
	init_timer(&g_sds.timer);

	/* setup the timer */
	g_sds.timer.expires = jiffies + EXPIRES_PERIOD;
	g_sds.timer.function = timeout_handler;
	g_sds.timer.data = (unsigned long)spi;

	/* add to system */
	add_timer(&g_sds.timer);
#else
#endif
    return ret;
}

定时时间到

#ifdef USE_TIMER
struct self_define_struct {
	struct timer_list timer;
};

struct self_define_struct g_sds;
#define EXPIRES_PERIOD	(5*HZ)

static void timeout_handler(unsigned long tdata)
{
	struct spi_device *spi = (struct spi_device *)tdata;

	g_sds.timer.expires = jiffies + EXPIRES_PERIOD;
	add_timer(&g_sds.timer);
	w25q128fv_spi_read_w25x_id_0(spi);
	w25q128fv_spi_read_w25x_id_1(spi);
}
#endif

static int w25q128fv_spi_read_w25x_id_1(struct spi_device *spi)
{
	int	status;
	char tbuf[] = {FIREFLY_SPI_READ_ID_CMD};
	char rbuf[5];

	/* 先发送写数据后读回数据 */
	status = spi_write_then_read(spi, tbuf, sizeof(tbuf), rbuf, sizeof(rbuf));
	dev_err(&spi->dev, "%s: ID = %02x %02x %02x %02x %02x\n", __FUNCTION__, rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4]);

	return status;
}
static int w25q128fv_spi_read_w25x_id_0(struct spi_device *spi)
{
	int	status;
	char tbuf[]={FIREFLY_SPI_READ_ID_CMD};
	char rbuf[5];

	struct spi_transfer	t = {
		.tx_buf		= tbuf,
		.len		= sizeof(tbuf),
	};

	struct spi_transfer     r = {
		.rx_buf         = rbuf,
		.len            = sizeof(rbuf),
	};
	struct spi_message      m;

	/* 初始化message */
	spi_message_init(&m);

	/* 将tx rx buffer加入到message */
	spi_message_add_tail(&t, &m);
	spi_message_add_tail(&r, &m);

	/* 发送message */
	status = spi_sync(spi, &m);
	dev_err(&spi->dev, "%s: ID = %02x %02x %02x %02x %02x\n", __FUNCTION__, rbuf[0], rbuf[1], rbuf[2], rbuf[3], rbuf[4]);

	return status;
}
发布了270 篇原创文章 · 获赞 95 · 访问量 13万+

猜你喜欢

转载自blog.csdn.net/qq_33487044/article/details/104416462