#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_address.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_gpio.h>
#define USING_REGISTER_CHRDRV //
#define AXI_GPIO_ADDR 0x41210000
#define AXI_GPIO_ADDR4 0x41210004
void __iomem *led_addr;
void __iomem *led_addr4;
void led_ioremap(void)
{
int a,b;
led_addr=ioremap(AXI_GPIO_ADDR,4);
led_addr4=ioremap(AXI_GPIO_ADDR4,4);
a=(int)led_addr;
b=(int)led_addr4;
printk("a=%x,b=%x\r\n",a,b);
writel(0xff,led_addr);
}
char buf_read[100]={"data from kernel"};
char buf_write[100]={"data to kernel"};
#define CHRDEV_NAME "chrdev"
#define CHRDEV_COUNT 1
typedef struct{
dev_t devid;
int major;
int minor;
struct cdev cdev;
struct class *class;
struct device *device;
struct device_node *nd;
int gpio;
} chrdev_struct;
chrdev_struct led;
void led_tree(void)
{
int ret;
led.nd=of_find_node_by_path("/led-axi-gpio-ioremap");
if(NULL==led.nd)
{
printk("error,of_find_node_by_path\r\n");
}
led_addr=of_iomap(led.nd,0);
/*led.gpio=of_get_named_gpio(led.nd,"gpios",1);
if(!gpio_is_valid(led.gpio))
{
printk("error,led.gpio\r\n");
}
printk("gpio1=%d\r\n",led.gpio);
led.gpio=of_get_named_gpio(led.nd,"gpios",0);
if(!gpio_is_valid(led.gpio))
{
printk("error,led.gpio\r\n");
}
printk("gpio=%d\r\n",led.gpio);
ret=gpio_request(led.gpio,"LED-GPIO");
if(ret)
{
printk("error,gpio_request\r\n");
}
gpio_direction_output(led.gpio,0);
gpio_set_value(led.gpio,1);
*/
}
static int led_open(struct inode *inode, struct file *filp)
{
filp->private_data = &led; /* 设置私有数据 */
return 0;
}
static ssize_t led_read(struct file *filp, char __user *buf,
size_t cnt, loff_t *offt)
{
copy_to_user(buf,buf_read,cnt);
return 0;
}
static ssize_t led_write(struct file *filp, const char __user *buf,
size_t cnt, loff_t *offt)
{
int data;
copy_from_user(&data,buf,4);
writel(data,led_addr);
// gpio_set_value(led.gpio,data);
printk("led_write,data=%d\r\n",data);
return 0;
}
static int led_close(struct inode *inode, struct file *filp)
{
return 0;
}
struct file_operations led_fops={
.owner=THIS_MODULE,
.open=led_open,
.write=led_write,
.read=led_read,
.release=led_close,
};
static int __init chardrv_init(void)
{
int ret;
//led_ioremap();
led_tree();
#ifdef USING_REGISTER_CHRDRV
//1.device id
led.major=register_chrdev(0,CHRDEV_NAME,&led_fops);
printk("major=%d,minor=%d\r\n",led.major,0);
led.devid=MKDEV(led.major,0);
#else
//1.alloc device id
ret=alloc_chrdev_region(&led.devid,0,CHRDEV_COUNT,CHRDEV_NAME);
if(ret)
goto error1;
led.major=MAJOR(led.devid);
led.minor=MINOR(led.devid);
printk("major=%d,minor=%d\r\n",led.major,led.minor);
//2.init cdev
led.cdev.owner=THIS_MODULE;
cdev_init(&led.cdev,&led_fops);
ret=cdev_add(&led.cdev,led.devid,CHRDEV_COUNT);
if(ret)
goto error2;
printk("chardev_init\n");
#endif
//3.create class
led.class=class_create(THIS_MODULE,"led_class_name");
if(IS_ERR(led.class))
{
goto error3;
}
//4.create device
led.device=device_create(
led.class,
NULL,
led.devid,
NULL,
"led_device"
);
if(IS_ERR(led.device))
{
goto error4;
}
return 0;
error4:
class_destroy(led.class);
error3:
#ifdef USING_REGISTER_CHRDRV
#else
cdev_del(&led.cdev);
#endif
error2:
#ifdef USING_REGISTER_CHRDRV
unregister_chrdev(led.major,CHRDEV_NAME);
#else
unregister_chrdev_region(led.devid,CHRDEV_COUNT);
#endif
error1:
iounmap(led_addr);
//iounmap(led_addr4);
//gpio_free(led.gpio);
return -1;
}
static void __exit chardrv_exit(void)
{
//writeb(0x0,led_addr);
device_destroy(led.class,led.devid);
class_destroy(led.class);
#ifdef USING_REGISTER_CHRDRV
cdev_del(&led.cdev);
unregister_chrdev(led.major,CHRDEV_NAME);
#else
unregister_chrdev_region(led.devid,CHRDEV_COUNT);
#endif
iounmap(led_addr);
//gpio_free(led.gpio);
//iounmap(led_addr4);
printk("chardev_exit\n");
//return 0;
}
module_init(chardrv_init);
module_exit(chardrv_exit);
MODULE_LICENSE("GPL");