前言
先写代码,然后再一个问题,一个问题分析。不是应该先分析问题,再写代码吗?因为笨呗。分析不明白。只有看到现象,才能明白手册上说的是啥意思。
实例1 主要完成以下几个事情
1 创建一个misc驱动
2 在驱动中将寄存器remap过来,需要映射的寄存器的列表,不要怕,代码都有。
3 配置寄存器的值,然后在1秒定时器中输出TEMP_CNT值
一 使用到的函数
映射和解除映射函数
如下,ioremap其实是一个宏,但是宏看起来不好理解,所以,我就把它当成一个下面这样的函数来用,好理解,ioremap的返回值,可以作为iounmap的参数,ioremap的第一个参数paddr就是前面列表中的寄存器地址,例如0x20c 8180,它是32位寄存器,4个字节,所以参数byte_count传入4。
#include <asm/io.h>
volatile void __iomem *ioremap(void *paddr,int byte_count);
void iounmap (volatile void __iomem *addr)
读寄存器函数
u8 readb ( const volatile void __iomem * addr )u16 readw ( const volatile void __iomem * addr )u32 readl ( const volatile void __iomem * addr )readb 、 readw 和 readl 这三个函数分别对应 8bit 、 16bit 和 32bit 读操作,参数 addr 就是要读取写内存地址,返回值就是读取到的数据。
写寄存器函数
void writeb ( u8 value , volatile void __iomem * addr )void writew ( u16 value , volatile void __iomem * addr )void writel ( u32 value , volatile void __iomem * addr )writeb 、 writew 和 writel 这三个函数分别对应 8bit 、 16bit 和 32bit 写操作,参数 value 是要写入的数值, addr 是要写入的地址。
本次实例,我们使用writel 和readl ;
二 实例代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#define DEBUG_TEMP(format,...) printk("%s,%d:"format"\n", \
__func__,__LINE__,##__VA_ARGS__)
/* 寄存器物理地址 */
#define TEMPMON_TEMPSENSE0 (0x020C8180)
#define TEMPMON_TEMPSENSE0_SET (0x020C8184)
#define TEMPMON_TEMPSENSE0_CLR (0x020C8188)
#define TEMPMON_TEMPSENSE0_TOG (0x020C818C)
#define TEMPMON_TEMPSENSE1 (0x020C8190)
#define TEMPMON_TEMPSENSE1_SET (0x020C8184)
#define TEMPMON_TEMPSENSE1_CLR (0x020C8198)
#define TEMPMON_TEMPSENSE1_TOG (0x020C819C)
#define TEMPMON_TEMPSENSE2 (0x020C8290)
#define TEMPMON_TEMPSENSE2_SET (0x020C8294)
#define TEMPMON_TEMPSENSE2_CLR (0x020C8298)
#define TEMPMON_TEMPSENSE2_TOG (0x020C829C)
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_TEMPMON_TEMPSENSE0;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE0_SET;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE0_CLR;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE0_TOG;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE1;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE1_SET;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE1_CLR;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE1_TOG;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE2;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE2_SET;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE2_CLR;
static void __iomem *IMX6U_TEMPMON_TEMPSENSE2_TOG;
struct temperature_register{
void __iomem *ctrl;
void __iomem *set;
void __iomem *clr;
void __iomem *tog;
};
struct _temperature_sensor_{
struct miscdevice misc;
struct file_operations fops;
struct temperature_register reg[3];
struct timer_list timer;
};
#define IMX6U_TEMPMON_TEMPSENSE(num) (IMX6U_TEMPMON_TEMPSENSE##num)
#define IMX6U_TEMPMON_TEMPSENSE_XXX(num,text) (IMX6U_TEMPMON_TEMPSENSE##num##text)
static int imx_temperature_monitor_init(struct _temperature_sensor_ *p)
{
int i = 0;
u32 val;
IMX6U_TEMPMON_TEMPSENSE0 = ioremap(TEMPMON_TEMPSENSE0,4);
IMX6U_TEMPMON_TEMPSENSE0_SET = ioremap(TEMPMON_TEMPSENSE0_SET,4);
IMX6U_TEMPMON_TEMPSENSE0_CLR = ioremap(TEMPMON_TEMPSENSE0_CLR,4);
IMX6U_TEMPMON_TEMPSENSE0_TOG = ioremap(TEMPMON_TEMPSENSE0_TOG,4);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE0);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE0_SET);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE0_CLR);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE0_TOG);
IMX6U_TEMPMON_TEMPSENSE1 = ioremap(TEMPMON_TEMPSENSE1,4);
IMX6U_TEMPMON_TEMPSENSE1_SET = ioremap(TEMPMON_TEMPSENSE1_SET,4);
IMX6U_TEMPMON_TEMPSENSE1_CLR = ioremap(TEMPMON_TEMPSENSE1_CLR,4);
IMX6U_TEMPMON_TEMPSENSE1_TOG = ioremap(TEMPMON_TEMPSENSE1_TOG,4);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE1);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE1_SET);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE1_CLR);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE1_TOG);
IMX6U_TEMPMON_TEMPSENSE2 = ioremap(TEMPMON_TEMPSENSE2,4);
IMX6U_TEMPMON_TEMPSENSE2_SET = ioremap(TEMPMON_TEMPSENSE2_SET,4);
IMX6U_TEMPMON_TEMPSENSE2_CLR = ioremap(TEMPMON_TEMPSENSE2_CLR,4);
IMX6U_TEMPMON_TEMPSENSE2_TOG = ioremap(TEMPMON_TEMPSENSE2_TOG,4);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE2);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE2_SET);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE2_CLR);
DEBUG_TEMP("%p",IMX6U_TEMPMON_TEMPSENSE2_TOG);
p->reg[0].ctrl = IMX6U_TEMPMON_TEMPSENSE(0);
p->reg[0].set = IMX6U_TEMPMON_TEMPSENSE_XXX(0,_SET);
p->reg[0].clr = IMX6U_TEMPMON_TEMPSENSE_XXX(0,_CLR);
p->reg[0].tog = IMX6U_TEMPMON_TEMPSENSE_XXX(0,_TOG);
p->reg[1].ctrl = IMX6U_TEMPMON_TEMPSENSE(1);
p->reg[1].set = IMX6U_TEMPMON_TEMPSENSE_XXX(1,_SET);
p->reg[1].clr = IMX6U_TEMPMON_TEMPSENSE_XXX(1,_CLR);
p->reg[1].tog = IMX6U_TEMPMON_TEMPSENSE_XXX(1,_TOG);
p->reg[2].ctrl = IMX6U_TEMPMON_TEMPSENSE(2);
p->reg[2].set = IMX6U_TEMPMON_TEMPSENSE_XXX(2,_SET);
p->reg[2].clr = IMX6U_TEMPMON_TEMPSENSE_XXX(2,_CLR);
p->reg[2].tog = IMX6U_TEMPMON_TEMPSENSE_XXX(2,_TOG);
for(i = 0;i < 3;i++){
DEBUG_TEMP("p->reg[%d].ctrl = %p",i,p->reg[i].ctrl);
DEBUG_TEMP("p->reg[%d].set = %p",i,p->reg[i].set);
DEBUG_TEMP("p->reg[%d].clr = %p",i,p->reg[i].clr);
DEBUG_TEMP("p->reg[%d].tog = %p",i,p->reg[i].tog);
}
DEBUG_TEMP("");
DEBUG_TEMP("");
for(i = 0;i < 3;i++){
DEBUG_TEMP("p->reg[%d].ctrl = %08x",i,readl(p->reg[i].ctrl));
DEBUG_TEMP("p->reg[%d].set = %08x",i,readl(p->reg[i].set));
DEBUG_TEMP("p->reg[%d].clr = %08x",i,readl(p->reg[i].clr));
DEBUG_TEMP("p->reg[%d].tog = %08x",i,readl(p->reg[i].tog));
}
writel(1 << 0,p->reg[0].clr);
writel(2 << 0,p->reg[0].clr);
writel(1 << 1,p->reg[0].set);
writel(1,p->reg[1].clr);
return 0;
}
static long imx_temperature_unlocked_ioctl (
struct file *file, unsigned int cmd, unsigned long arg)
{
DEBUG_TEMP("");
return 0;
}
struct _temperature_sensor_ imx_temperature_sensor = {
.fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = imx_temperature_unlocked_ioctl,
},
.misc = {
.name = "imx_temp",
.minor = MISC_DYNAMIC_MINOR,
},
};
void temperature_timer_function(unsigned long arg)
{
struct _temperature_sensor_ *p = (struct _temperature_sensor_ *)arg;
u32 val = readl(p->reg[0].ctrl);
static int last_val = 0;
while(1){
if((val & 0x04) == 0){
break;
}
DEBUG_TEMP("val = %08x,%d,%d,temperature = %d",val,val-last_val,(val&0xfff00000)>>20,(val&0xfff00)>>8);
last_val = val;
writel(1 << 0,p->reg[0].clr);
writel(2 << 0,p->reg[0].clr);
writel(1 << 1,p->reg[0].set);
break;
}
mod_timer(&p->timer,msecs_to_jiffies(1000) + jiffies);
}
static int __init temperature_init(void)
{
struct _temperature_sensor_ *p = &imx_temperature_sensor;
p->misc.fops = &p->fops;
imx_temperature_monitor_init(p);
if(misc_register(&p->misc) != 0){
DEBUG_TEMP("misc_register error");
return -EINVAL;
}
init_timer(&p->timer);
p->timer.data = (unsigned long)p;
p->timer.function = temperature_timer_function;
mod_timer(&p->timer,msecs_to_jiffies(1000) + jiffies);
DEBUG_TEMP("");
return 0;
}
static void __exit temperature_exit(void)
{
struct _temperature_sensor_ *p = &imx_temperature_sensor;
int i = 0;
del_timer_sync(&p->timer);
for(i = 0;i < 3;i++){
iounmap(p->reg[i].ctrl);
iounmap(p->reg[i].set);
iounmap(p->reg[i].clr);
iounmap(p->reg[i].tog);
}
misc_deregister(&p->misc);
DEBUG_TEMP("");
}
module_init(temperature_init);
module_exit(temperature_exit);
MODULE_LICENSE("GPL");
Makefile
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
KERN_DIR = /home/lkmao/imx/linux/linux-imx
FILE_NAME=temperature
obj-m += $(FILE_NAME).o
all:
make -C $(KERN_DIR) M=$(shell pwd) modules
sudo cp $(FILE_NAME).ko /big/nfsroot/buildrootfs/home/root/
sudo scp $(FILE_NAME).ko root@192.168.0.3:/home/root/
.PHONY:clean
clean:
make -C $(KERN_DIR) M=$(shell pwd) clean
rm app -rf
测试结果
[ 1428.046419] temperature_timer_function,166:val = 49a4d006,256,1178,temperature = 1232
[ 1429.046419] temperature_timer_function,166:val = 49a4cf06,-256,1178,temperature = 1231
[ 1430.046420] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1431.046419] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1432.046418] temperature_timer_function,166:val = 49a4d006,256,1178,temperature = 1232
[ 1433.046425] temperature_timer_function,166:val = 49a4d006,0,1178,temperature = 1232
[ 1434.046415] temperature_timer_function,166:val = 49a4cf06,-256,1178,temperature = 1231
[ 1435.046418] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1436.046420] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1437.046420] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1438.046419] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1439.046418] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1440.046419] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231
[ 1441.046421] temperature_timer_function,166:val = 49a4cf06,0,1178,temperature = 1231