#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/cdev.h>
#include <linux/of.h>
#include <linux/of_address.h>
struct str_mioled{
int major;
dev_t devid;
struct class *class;
struct device *device;
struct cdev cdev;
struct device_node *nd;
} mioled;
//mio
/*
#define ZYNQ_GPIO_REG_BASE 0xE000A000
#define DATA_OFFSET (0+0x40)
#define DIRM_OFFSET (0+0x204)
#define OUTEN_OFFSET (0+0x208)
#define INTDIS_OFFSET (0+0x214)
#define APER_CLK_CTRL (0xF800012C)
*/
/* 映射后的寄存器虚拟地址指针 */
static void __iomem *data_addr;
static void __iomem *dirm_addr;
static void __iomem *outen_addr;
static void __iomem *intdis_addr;
static void __iomem *aper_clk_ctrl_addr;
static inline void led_ioremap(void)
{
data_addr = of_iomap(mioled.nd, 0);
dirm_addr = of_iomap(mioled.nd, 1);
outen_addr = of_iomap(mioled.nd, 2);
intdis_addr = of_iomap(mioled.nd, 3);
aper_clk_ctrl_addr = of_iomap(mioled.nd, 4);
}
int mio_from_dts(void)
{
int ret;
const char *str;
/* 1.获取led设备节点 */
mioled.nd = of_find_node_by_path("/led_mio_ioremap");
if(NULL == mioled.nd) {
printk(KERN_ERR "led_mio_ioremap node can not found!\r\n");
return -1;
}
/* 2.读取status属性 */
ret = of_property_read_string(mioled.nd, "status", &str);
if(!ret) {
if (strcmp(str, "okay"))
return -1;
}
/* 2、获取compatible属性值并进行匹配 */
ret = of_property_read_string(mioled.nd, "compatible", &str);
if(0 > ret)
return -1;
if (strcmp(str, "xhl,led_mio_ioremap"))
return -1;
printk(KERN_ERR "led device matching successful!\r\n");
led_ioremap();
return ret;
}
static int mio_init(void)
{
u32 val;
//int ret;
/* 1.寄存器地址映射 */
/*
data_addr = ioremap(ZYNQ_GPIO_REG_BASE + DATA_OFFSET, 4);
dirm_addr = ioremap(ZYNQ_GPIO_REG_BASE + DIRM_OFFSET, 4);
outen_addr = ioremap(ZYNQ_GPIO_REG_BASE + OUTEN_OFFSET, 4);
intdis_addr = ioremap(ZYNQ_GPIO_REG_BASE + INTDIS_OFFSET, 4);
aper_clk_ctrl_addr = ioremap(APER_CLK_CTRL, 4);
*/
mio_from_dts();
/* 2.使能GPIO时钟 */
val = readl(aper_clk_ctrl_addr);
val |= (0x1U << 22);
writel(val, aper_clk_ctrl_addr);
/* 3.关闭中断功能 */
val |= (0x1U << 7);
writel(val, intdis_addr);
/* 4.设置GPIO为输出功能 */
val = readl(dirm_addr);
val |= (0x1U << 7);
writel(val, dirm_addr);
/* 5.使能GPIO输出功能 */
val = readl(outen_addr);
val |= (0x1U << 7);
writel(val, outen_addr);
/* 6.默认关闭LED */
val = readl(data_addr);
val &= ~(0x1U << 7);
writel(val, data_addr);
return 0;
}
static int mio_set(int value)
{
u32 val;
//int ret;
/* 6.默认关闭LED */
val = readl(data_addr);
if(value==0)
{
val &= ~(0x1U << 7);
}
else
{
val |= (0x1U << 7);
}
writel(val, data_addr);
return 0;
}
#define MIOLED_NUM 1
#define MIOLED_NAME "mioled"
int mioled_open(struct inode *inode,struct file *file)
{
int ret=0;
printk("kernel:mioled_open\r\n");
return ret;
}
int mioled_close(struct inode *inode,struct file *file)
{
int ret=0;
printk("kernel:mioled_close\r\n");
return ret;
}
ssize_t mioled_write(struct file *file, const char __user *buf,
size_t len, loff_t *ppos)
{
int ret=0;
char *write_buf;
write_buf=(char *)kmalloc(len,GFP_KERNEL);
if(write_buf==NULL)
return -1;
ret=copy_from_user(write_buf,buf,1);
if(ret<0)
return -1;
if(write_buf[0]==0)
mio_set(0);
else
{
mio_set(1);
}
//printk("kernel:mioled_write,buf=%s\r\n",write_buf);
kfree(write_buf);
return ret;
}
ssize_t mioled_read(struct file *file, char __user *buf,
size_t len, loff_t *ppos)
{
int ret=0;
char read_buf[]="data from user!";
ret=copy_to_user(buf,read_buf,sizeof(read_buf));
if(ret<0)
return -1;
printk("kernel:mioled_read,len=%d,ret=%d\r\n",sizeof(read_buf),ret);
return ret;
}
/*
ssize_t led_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
{
return 0;
}
*/
struct file_operations ops={
.owner =THIS_MODULE,
.open =mioled_open,
.write =mioled_write,
.read =mioled_read,
.release=mioled_close,
};
static int __init mioled_init(void)
{
int ret=0;
//1.设备号
mioled.major=0;
if(mioled.major)
{
mioled.devid=MKDEV(mioled.major,0);
ret=register_chrdev_region(mioled.devid,MIOLED_NUM,MIOLED_NAME);
}
else
{
ret=alloc_chrdev_region(&mioled.devid,0,MIOLED_NUM,MIOLED_NAME);
mioled.major=MAJOR(mioled.devid);
}
printk("major=%d\r\n",mioled.major);
//2.
mioled.class=class_create(THIS_MODULE,MIOLED_NAME);
if(IS_ERR(mioled.class))
{
printk("error:class_create\r\n");
ret=PTR_ERR(mioled.class);
goto error_class_create;
}
//3.
mioled.device=device_create(mioled.class,NULL,mioled.devid,NULL,MIOLED_NAME);
if(IS_ERR(mioled.device))
{
printk("error:device_create\r\n");
ret=PTR_ERR(mioled.device);
goto error_device_create;
}
//4.添加设备
cdev_init(&mioled.cdev,&ops);
ret=cdev_add(&mioled.cdev,mioled.devid,MIOLED_NUM);
if(ret<0)
{
printk("error:cdev_add\r\n");
goto error_cdev_add;
}
printk("mioled_init\r\n");
mio_init();
return ret;
error_cdev_add:
device_destroy(mioled.class, mioled.devid);
error_device_create:
class_destroy(mioled.class);
error_class_create:
unregister_chrdev_region(mioled.devid,MIOLED_NUM);
return ret;
}
static void __exit mioled_exit(void)
{
/* 2.取消内存映射 */
iounmap(data_addr);
iounmap(dirm_addr);
iounmap(outen_addr);
iounmap(intdis_addr);
iounmap(aper_clk_ctrl_addr);
cdev_del(&mioled.cdev);
device_destroy(mioled.class, mioled.devid);
class_destroy(mioled.class);
unregister_chrdev_region(mioled.devid,MIOLED_NUM);
printk("mioled_exit\r\n");
//return 0;
}
module_init(mioled_init);
module_exit(mioled_exit);
MODULE_LICENSE("GPL");