目录
- 看这篇博文前请先掌握下面这些博文中的知识
- 需要的PDF资料
- 完整源代码
- 程序设计思想和文件结构
- 实现分层思想的具体方法
- 本篇博文略去对驱动程序代码的分析,重点分析底层对硬件操作的代码
- 驱动程序代码虽然略去分析,但是模块初始化函数中注册驱动程序的方法和之前的有所不同【函数register_chrdev()的介绍】
- 在硬件层面操作的代码的分析(`board_fire_imx6ull-pro.c`中的代码)
- Makfile文件的编写
- 交叉编译
- 上板测试
- 附工程压缩文件和PDF文档
看这篇博文前请先掌握下面这些博文中的知识
https://blog.youkuaiyun.com/wenhao_ir/article/details/144888989
https://blog.youkuaiyun.com/wenhao_ir/article/details/144901797
https://blog.youkuaiyun.com/wenhao_ir/article/details/144881830
需要的PDF资料
开发板的原理图文件:
https://pan.baidu.com/s/1CEwPbcNUIicA1HVGwG6e5A?pwd=m9wb
IMX6ULL-CPU芯片的操作手册:
https://pan.baidu.com/s/1hZWmgmvYAA9mvzAHsPiw4g?pwd=eiuh
完整源代码
board_fire_imx6ull-pro.c中的代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include <asm/io.h>
#include "led_opr.h"
static volatile unsigned int *CCM_CCGR1 ;
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
static volatile unsigned int *GPIO5_GDIR ;
static volatile unsigned int *GPIO5_DR ;
static int board_demo_led_init (int which) /* 初始化LED, which-哪个LED */
{
unsigned int val;
//printk("%s %s line %d, led %d\n", __FILE__, __FUNCTION__, __LINE__, which);
if (which == 0)
{
if (!CCM_CCGR1)
{
CCM_CCGR1 = ioremap(0x20C406C, 4);
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x2290014, 4);
GPIO5_GDIR = ioremap(0x020AC000 + 0x4, 4);
GPIO5_DR = ioremap(0x020AC000 + 0, 4);
}
/* GPIO5_IO03 */
/* a. 使能GPIO5的时钟信号
* set CCM to enable GPIO5
* CCM_CCGR1[CG15] 0x20C406C
* bit[31:30] = 0b11
*/
*CCM_CCGR1 |= (3<<30);
/* b. 设置GPIO5_IO03用于GPIO
* set IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3
* to configure GPIO5_IO03 as GPIO
* IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 0x2290014
* bit[3:0] = 0b0101 alt5
*/
val = *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;
val &= ~(0xf);
val |= (5); //5的二进制表示为0101
*IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = val;
/* b. 设置GPIO5_IO03作为output引脚
* set GPIO5_GDIR to configure GPIO5_IO03 as output
* GPIO5_GDIR 0x020AC000 + 0x4
* bit[3] = 0b1
*/
*GPIO5_GDIR |= (1<<3);
}
return 0;
}
static int board_demo_led_ctl (int which, char status) /* 控制LED, which-哪个LED, status:1-亮,0-灭 */
{
//printk("%s %s line %d, led %d, %s\n", __FILE__, __FUNCTION__, __LINE__, which, status ? "on" : "off");
if (which == 0)
{
if (status) /* on: output 0*/
{
/* d. 设置GPIO5_DR输出低电平
* set GPIO5_DR to configure GPIO5_IO03 output 0
* GPIO5_DR 0x020AC000 + 0
* bit[3] = 0b0
*/
*GPIO5_DR &= ~(1<<3);
}
else /* off: output 1*/
{
/* e. 设置GPIO5_IO3输出高电平
* set GPIO5_DR to configure GPIO5_IO03 output 1
* GPIO5_DR 0x020AC000 + 0
* bit[3] = 0b1
*/
*GPIO5_DR |= (1<<3);
}
}
return 0;
}
static int board_demo_led_close(int which) /* whice表示具体是要操作哪个LED*/
{
if (which == 0)
{
if (CCM_CCGR1) {
iounmap(CCM_CCGR1);
CCM_CCGR1 = NULL;
}
if (IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3) {
iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = NULL;
}
if (GPIO5_GDIR) {
iounmap(GPIO5_GDIR);
GPIO5_GDIR = NULL;
}
if (GPIO5_DR) {
iounmap(GPIO5_DR);
GPIO5_DR = NULL;
}
}
return 0;
}
static struct led_operations board_demo_led_opr = {
.num = 1,
.init = board_demo_led_init,
.ctl = board_demo_led_ctl,
.close = board_demo_led_close,
};
struct led_operations *get_board_led_opr(void)
{
return &board_demo_led_opr;
}
leddrv.c中的代码
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/miscdevice.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/mutex.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/tty.h>
#include <linux/kmod.h>
#include <linux/gfp.h>
#include "led_opr.h"
/* 1. 确定主设备号 */
static int major = 0;
static struct class *led_class;
struct led_operations *p_led_opr;
#define MIN(a, b) (a < b ? a : b)
/* 3. 实现对应的open/read/write等函数,填入file_operations结构体 */
static ssize_t led_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{
printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
/* write(fd, &val, 1); */
static ssize_t led_drv_write (struct file *file, const char __user *buf, size_t size, loff_t *offset)
{
int err;
char status;
struct inode *inode = file_inode(file);
int minor = iminor(inode)