当前位置:   article > 正文

使用DM368的GPIO控制NANDFLASH的WP_nand wp#pin 寄存器操作代码

nand wp#pin 寄存器操作代码

0.问题描述

最近需要使用DM368的GPIO控制NandFlash的WP引脚实现写保护功能,只在需要写入和擦除时才放开写保护。

1.DM368的GPIO操作

DM368的GPIO操作主要分为下面三步实现:

  1. gpio_request申请GPIO引脚
  2. 修改IOMUX寄存器,设置端口复用为GPIO模式
  3. 操作GPIO引脚

1.1 gpio_request申请和冲突分析

1.1.1 申请

在内核中申请GPIO,就是给GPIO进行加锁处理,防止被其他程序进行占用。

gpio_request的范例代码如下:

ret = gpio_request(gpioport[i],GPIO_REQ_NAME);
if(ret < 0)
{
	printk(KERN_EMERG "GPIO #%d req Fail,ret = %d\n",i,ret);
	return ret;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

第一个参数是GPIO号,是一个整型数据。

第二个是锁的名称,方便后续debug和分析。

1.1.2 释放

释放GPIO使用gpio_free函数,函数参数是GPIO号。

gpio_free(gpionum);
  • 1

1.1.3 gpio_request冲突处理

gpio_request申请gpio的时候,可能会申请失败。如果失败的返回值是-16,即Device or resource busy,说明这个GPIO被占用了。

这种时候可以使用debugfs进行分析。

首先,需要保证Kernel编译配置中打开了DEBUGFS选项(一般在Kernel hacking→Debug Filesystem),如下:

在目标板上查看/sys/kernel/debug/,如果是空白的则说明debugfs没有挂载上,使用下面命令挂载

mount -t debugfs debug /sys/kernel/debug/
  • 1

挂载成功后可以看到debugfs文件系统的文件如下:

在这里插入图片描述

gpio文件中就是当前的gpio占用情况和电平输出情况:

在这里插入图片描述

如果自己使用的gpio被占用了,可以在kernel中找到占用的模块取消之,或使用别的端口。

1.2 IOMUX的配置

端口复用iomux的配置有两种方式。

  1. 直接使用寄存器进行修改(通用)
  2. 使用dm368内核中的davinci_cfg_reg函数配置(平台限定)

1.2.1 修改iomux寄存器

直接修改寄存器需要查阅DataSheet,定位到要修改的寄存器地址和要修改的位,修改即可。

首先查阅相关的DataSheet,这部分的内容在官方文档TMS320DM36x Digital Media System-on-Chip(DMSoC) ARM Subsystem User’s Guide中。

以修改GPIO35为例,可以看到,GPIO35位于PINMUX4的BIT16&BIT17:

在这里插入图片描述

配置为00时,作为GPIO使用:

在这里插入图片描述

从Datasheet中得知,我们要修改的是System Module Registers(简称SMR)的PINMUX4,地址是SMR基地址+0x10:

在这里插入图片描述

基地址可查阅Table 7:

在这里插入图片描述

则可得到实际地址为0x01C40000 + 0x10 = 0x01C40010。

之后只要将物理地址ioremap映射为虚拟地址,再对寄存器的相关值(BIT16-17)进行修改即可,这里不再展开说明。

volatile static unsigned long virt_addr = (unsigned long)ioremap(0x01C40010,0x20);
data = (unsigned long *)virt_addr;
data = xxxx; //要修改的值
  • 1
  • 2
  • 3

1.2.2 通过davinci_cfg_reg函数配置

参考资料如下:

https://blog.csdn.net/xiufu004/article/details/7704823

简单来说,davinci_cfg_reg函数就是把dm365.c里的dm365_pins数组中对应位置的管脚复用信息转换成对PINMUX寄存器的操作。

以修改GPIO35为普通IO口为例子:

在dm365_pins数组中找到对应的引脚:

在这里插入图片描述

结合上一节分析,GPIO35在PINMUX4,BIT16-17,2位(mask = 0000 0011b = 3),设置为0时为GPIO。

即本行配置为

MUX_CFG(DM365,	SPI4_SDO,	4,   16,    3,    0,	 false)
  • 1

之后再在初始化中调用davinci_cfg_reg(DM365_SPI4_SDO)即可。其中DM365_SPI4_SDO是上行配置在dm365_pins数组中的下标。

1.3 IO的操作

主要API:

设置为输出:

gpio_direction_output(GPIONUM,level);  //将GPIONUM的电平设置为level(0/1)
  • 1

设置为输入:

 gpio_direction_input(GPIONUM);  //设置GPIONUM为输入
  • 1

读取电平值

int level = gpio_get_value(GPIONUM);//读取GPIONUM的电平,返回给level
  • 1

这些操作可以和ioctl/read/write等接口配合供上层调用测试。

2.在Nand写入擦除操作中增加对WP的操作

2.1 初始化、读写保护操作的定义

在nand_base.c中增加如下代码:

//NAND WP PART
#define WP_GPIO_PIN 35   //写保护的GPIO为GPIO 35
static int NAND_WP = 0;

#define WP_ENABLE()  do {if(NAND_WP!=0) gpio_direction_output(NAND_WP,0); } while(0)   //写保护启用,拉低WP引脚
#define WP_DISABLE()  do {if(NAND_WP!=0) gpio_direction_output(NAND_WP,1); } while(0)  //写保护禁用,拉高WP引脚

static void init_wp_pin()
{
	int ret;
	ret = gpio_request(WP_GPIO_PIN,"NAND WP"); //申请NAND的写保护引脚
	if(ret < 0)
	{
		printk(KERN_EMERG "GPIO WP req Fail,ret = %d\n",ret);
		return ret;
	}
	davinci_cfg_reg(DM365_SPI4_SDO);  //设置IOMUX为DM365.c中dm365_pins的值,修改引脚的话需要改结构体或者自行配置IOMUX寄存器
	NAND_WP = WP_GPIO_PIN;   //申请到GPIO才走这里
	WP_ENABLE();   //默认开启写保护
	printk(KERN_EMERG "GPIO WP Init Success!!!!\n");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

这段代码中实现了GPIO的申请操作,只有成功申请了GPIO35,才会给NAND_WP变量赋值。NAND_WP不为0时,说明初始化成功,可以进行GPIO控制WP的操作。

初始化代码需要在nand模块被装载时执行,放在module_init执行的函数中即可:

在这里插入图片描述

2.2 WP引脚的操作

查看对NAND FLASH操作的函数,发现操作开始之前会先执行nand_get_device,操作之后执行nand_release_device。

因此对该引脚的操作主要是在nand_release_device函数中增加写保护,在nand_get_device中判断操作为FL_WRITING或FL_ERASING时去掉写保护。

写保护解除:(看下方代码的START和END之间的部分)

/**
 * nand_get_device - [GENERIC] Get chip for selected access
 * @chip:	the nand chip descriptor
 * @mtd:	MTD device structure
 * @new_state:	the state which is requested
 *
 * Get the device and lock it for exclusive access
 */
static int
nand_get_device(struct nand_chip *chip, struct mtd_info *mtd, int new_state)
{
	spinlock_t *lock = &chip->controller->lock;
	wait_queue_head_t *wq = &chip->controller->wq;
	DECLARE_WAITQUEUE(wait, current);
 retry:
	spin_lock(lock);
	
	/* Hardware controller shared among independent devices */
	if (!chip->controller->active)
		chip->controller->active = chip;
//------------------START-----------------------------
	if(NAND_WP == 0)  //检查是否初始化WP,未初始化则再次初始化
	{
		init_wp_pin();
	}
	if(new_state == FL_WRITING || new_state == FL_ERASING) //只在写入和擦除时关闭写保护
		WP_DISABLE();
//------------------END-----------------------------
	if (chip->controller->active == chip && chip->state == FL_READY) {
		chip->state = new_state;
		spin_unlock(lock);
		return 0;
	}
	if (new_state == FL_PM_SUSPENDED) {
		spin_unlock(lock);
		return (chip->state == FL_PM_SUSPENDED) ? 0 : -EAGAIN;
	}
	set_current_state(TASK_UNINTERRUPTIBLE);
	add_wait_queue(wq, &wait);
	spin_unlock(lock);
	schedule();
	remove_wait_queue(wq, &wait);
	goto retry;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

写保护开启:

/**
 * nand_release_device - [GENERIC] release chip
 * @mtd:	MTD device structure
 *
 * Deselect, release chip lock and wake up anyone waiting on the device
 */
static void nand_release_device(struct mtd_info *mtd)
{
	struct nand_chip *chip = mtd->priv;

	/* De-select the NAND device */
	chip->select_chip(mtd, -1);

	/* Release the controller and the chip */
	spin_lock(&chip->controller->lock);
	chip->controller->active = NULL;
	chip->state = FL_READY;
//---------------START--------------------------
	if(NAND_WP == 0)
	{
		init_wp_pin();
	}
	WP_ENABLE();  //写保护开启
//--------------END----------------------
	wake_up(&chip->controller->wq);
	spin_unlock(&chip->controller->lock);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

2.3 测试是否生效

  1. 查看开机的串口输出,是否出现了WP申请成功的Log:

在这里插入图片描述

  1. 万用表测量WP脚,平时是否一直为低电平。

  2. 在目标板Linux Shell中进行文件读写删除操作,操作不报错,重启后文件仍然存在,说明修改成功。

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号