赞
踩
最近需要使用DM368的GPIO控制NandFlash的WP引脚实现写保护功能,只在需要写入和擦除时才放开写保护。
DM368的GPIO操作主要分为下面三步实现:
在内核中申请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;
}
第一个参数是GPIO号,是一个整型数据。
第二个是锁的名称,方便后续debug和分析。
释放GPIO使用gpio_free函数,函数参数是GPIO号。
gpio_free(gpionum);
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/
挂载成功后可以看到debugfs文件系统的文件如下:
gpio文件中就是当前的gpio占用情况和电平输出情况:
如果自己使用的gpio被占用了,可以在kernel中找到占用的模块取消之,或使用别的端口。
端口复用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; //要修改的值
参考资料如下:
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)
之后再在初始化中调用davinci_cfg_reg(DM365_SPI4_SDO)即可。其中DM365_SPI4_SDO是上行配置在dm365_pins数组中的下标。
主要API:
设置为输出:
gpio_direction_output(GPIONUM,level); //将GPIONUM的电平设置为level(0/1)
设置为输入:
gpio_direction_input(GPIONUM); //设置GPIONUM为输入
读取电平值
int level = gpio_get_value(GPIONUM);//读取GPIONUM的电平,返回给level
这些操作可以和ioctl/read/write等接口配合供上层调用测试。
在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"); }
这段代码中实现了GPIO的申请操作,只有成功申请了GPIO35,才会给NAND_WP变量赋值。NAND_WP不为0时,说明初始化成功,可以进行GPIO控制WP的操作。
初始化代码需要在nand模块被装载时执行,放在module_init执行的函数中即可:
查看对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; }
写保护开启:
/** * 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); }
万用表测量WP脚,平时是否一直为低电平。
在目标板Linux Shell中进行文件读写删除操作,操作不报错,重启后文件仍然存在,说明修改成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。