ret;
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
ret = copy_to_user(buf, &kernel_val, count);
if(ret > 0)
{
printk("failed copy_to_user\r\n");
return -EFAULT;
}
return 0;
}
ssize_t chr_drv_write (struct file *filp, const char __user *buf, size_t count, loff_t *fops)
{
int ret;
int value;
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
ret = copy_from_user(&value, buf, count);
if(ret > 0)
{
printk("failed copy_from_user\r\n");
return -EFAULT;
}
if(value){
*GPIO1_DR |= (1 << 3);
}else{
*GPIO1_DR &= ~(1 << 3);
}
return 0;
}
int chr_drv_open (struct inode *inode, struct file *filp)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
int chr_drv_close (struct inode *inode, struct file *filp)
{
printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
return 0;
}
const struct file_operations my_fops = {
.open = chr_drv_open,
.read = chr_drv_read,
.write = chr_drv_write,
.release = chr_drv_close,
};
/*
②在模块加载入口函数中
a 申请主设备号(内核中用于区分和管理不同字符设备)
register_chrdev()
b 创建设备节点文件(为用户提供一个可操作到文件接口--open())
struct class *class_create()
struct device *device)create()
c 硬件初始化
1.地址映射
2.中断申请
3.实现硬件的寄存器的初始化
d 实现file_operation
*/
static int __init chr_dev_init(void)
{
int ret;
//0 实例化全局的设备对象
led_dev = kzalloc(sizeof(struct led_desc), GFP_KERNEL);
if(led_dev == NULL);
{
printk("kmalloc failed\r\n");
return -ENOMEM;
}
//一般都是申请设备号资源
//1.申请设备号
led_dev->dev_major = register_chrdev(0, "chr_dev_test", &my_fops);
if(led_dev->dev_major < 0){
printk(KERN_ERR"register_chrdev failed\n");
ret = -ENODEV;
goto err_0;
}
//2.创建设备文件
led_dev->cls = class_create(THIS_MODULE, "chr_cls");
if(IS_ERR(led_dev->cls))
{
printk(KERN_ERR"class_create failed\n");
ret = PTR_ERR(led_dev->cls);//将指针出错原因转换为一个出错码
goto err_1;
}
// /dev/led0
led_dev->dev = device_create(led_dev->cls, NULL, MKDEV(led_dev->dev_major, 0), NULL, "led%d", 0);
if(IS_ERR(led_dev->dev))
{
printk(KERN_ERR"device_create failed\n");
ret = PTR_ERR(led_dev->dev);//将指针出错原因转换为一个出错码
goto err_2;
}
//3,硬件初始化
/* 初始化LED */
/* 1、寄存器地址映射 */
IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);
/* enable GPIO1
* configure GPIO1_io3 as gpio
* configure GPIO1_io3 as output
*/
*IMX6U_CCM_CCGR1 |= 0x0C000000;
*SW_MUX_GPIO1_IO03 &= 0xfffffff0;
*SW_MUX_GPIO1_IO03 |= 0x5;
*SW_PAD_GPIO1_IO03 &= 0xfffffff0;
*SW_PAD_GPIO1_IO03 |= 0x10B0;
*GPIO1_GDIR &= 0xfffffff0;
*GPIO1_GDIR |= 0x8;
/*
readl writel
static inline u32 readl(const volatile void __iomem *addr)
static inline void writel(u32 value, void *addr)
2、使能GPIO1时钟
val = readl(IMX6U_CCM_CCGR1);
val &= ~(3 << 26); 清楚以前的设置
val |= (3 << 26); 设置新值
writel(val, IMX6U_CCM_CCGR1);
3、设置GPIO1_IO03的复用功能,将其复用为
GPIO1_IO03,最后设置IO属性 |