#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct led_chrdev { unsigned int __iomem *va_dr; unsigned int __iomem *va_gdir; unsigned int __iomem *va_iomuxc_mux; unsigned int __iomem *va_ccm_ccgrx; unsigned int __iomem *va_iomux_pad; unsigned int led_pin; unsigned int clock_offset; struct cdev dev; dev_t my_devno; }; static struct class *led_class = NULL; static int led_open(struct inode *inode, struct file *filp) { uint32_t val = 0; struct led_chrdev *my_led_dev = NULL; printk("led open %d:%d...\n",MAJOR(inode->i_rdev),MINOR(inode->i_rdev)); my_led_dev = container_of(inode->i_cdev, struct led_chrdev, dev); filp->private_data = my_led_dev; val = ioread32(my_led_dev->va_ccm_ccgrx); val &= ~(3 << my_led_dev->clock_offset); val |= 3 << my_led_dev->clock_offset; iowrite32(val, my_led_dev->va_ccm_ccgrx); iowrite32(5, my_led_dev->va_iomuxc_mux); iowrite32(0x1F838, my_led_dev->va_iomux_pad); val = ioread32(my_led_dev->va_gdir); val &= ~(1 << my_led_dev->led_pin); val |= (1 << my_led_dev->led_pin); iowrite32(val, my_led_dev->va_gdir); val = ioread32(my_led_dev->va_dr); val |= (0x01 << my_led_dev->led_pin); iowrite32(val, my_led_dev->va_dr); return 0; } static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { return cnt; } static ssize_t led_write(struct file *filp,const char __user *buf,size_t cnt, loff_t *offt) { uint32_t val = 0; uint32_t ret = 0; struct led_chrdev *my_led_dev = NULL; printk("led write...\n"); my_led_dev = filp->private_data; kstrtoul_from_user(buf,cnt,10,&ret); //printk("ret = %u\n",ret); val = ioread32(my_led_dev->va_dr); if (ret) val &= ~(0x01 << my_led_dev->led_pin); else val |= (0x01 << my_led_dev->led_pin); iowrite32(val, my_led_dev->va_dr); *offt += cnt; return cnt; } static int led_release(struct inode *inode, struct file *filp) { return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .read = led_read, .write = led_write, .release = led_release, }; static struct platform_device_id led_pdev_ids[] = { {.name = "led_pdev"}, {} }; MODULE_DEVICE_TABLE(platform, led_pdev_ids); int led_plat_probe(struct platform_device *pdev) { uint32_t val = 0; int ret = 0; dev_t devno = 0; struct led_chrdev *my_led_dev = NULL; struct device_node *dev_node = NULL; char *compatible_str = NULL; unsigned int *led_hwinfo; dev_node = dev_of_node(&(pdev->dev)); struct resource *mem_dr; struct resource *mem_gdir; struct resource *mem_iomuxc_mux; struct resource *mem_ccm_ccgrx; struct resource *mem_iomux_pad; struct resource t_mem_dr; struct resource t_mem_gdir; struct resource t_mem_iomuxc_mux; struct resource t_mem_ccm_ccgrx; struct resource t_mem_iomux_pad; if(NULL == dev_node){ printk(KERN_INFO"probe frome normal platform device\n"); led_hwinfo = dev_get_platdata(&(pdev->dev)); mem_dr = platform_get_resource(pdev,IORESOURCE_MEM,0); mem_gdir = platform_get_resource(pdev,IORESOURCE_MEM,1); mem_iomuxc_mux = platform_get_resource(pdev,IORESOURCE_MEM,2); mem_ccm_ccgrx = platform_get_resource(pdev,IORESOURCE_MEM,3); mem_iomux_pad = platform_get_resource(pdev,IORESOURCE_MEM,4); } else{ printk(KERN_INFO"probe frome device tree\n"); led_hwinfo = devm_kzalloc(&(pdev->dev),2*sizeof(unsigned int), GFP_KERNEL); if(!led_hwinfo){ printk(KERN_ERR"devm_kzalloc failed\n"); return -ENOMEM; } if (0 != of_property_read_u32_array(dev_node, "hw_info", led_hwinfo, 2)){ printk(KERN_ERR"read hw_info err\n"); return -ENODATA; } of_address_to_resource(dev_node,3,&t_mem_dr); of_address_to_resource(dev_node,4,&t_mem_gdir); of_address_to_resource(dev_node,1,&t_mem_iomuxc_mux); of_address_to_resource(dev_node,0,&t_mem_ccm_ccgrx); of_address_to_resource(dev_node,2,&t_mem_iomux_pad); mem_dr = &t_mem_dr; mem_gdir = &t_mem_gdir; mem_iomuxc_mux = &t_mem_iomuxc_mux; mem_ccm_ccgrx = &t_mem_ccm_ccgrx; mem_iomux_pad = &t_mem_iomux_pad; if(0 != of_property_read_string(dev_node,"compatible",&compatible_str)){ printk(KERN_ERR"read compatible err\n"); return -ENODATA; } printk(KERN_INFO"compatible = %s\n",compatible_str); if(0 == strcmp(compatible_str, "fire,rgb_led_red")){ printk(KERN_INFO"red led\n"); pdev->id = 0; } else if(0 == strcmp(compatible_str, "fire,rgb_led_green")){ printk(KERN_INFO"green led\n"); pdev->id = 1; } else{ printk(KERN_INFO"blue led\n"); pdev->id = 2; } } my_led_dev = devm_kzalloc(&(pdev->dev),sizeof(struct led_chrdev), GFP_KERNEL); if(!my_led_dev) return -ENOMEM; my_led_dev->led_pin = led_hwinfo[0]; my_led_dev->clock_offset = led_hwinfo[1]; my_led_dev->va_ccm_ccgrx = ioremap(mem_ccm_ccgrx->start,4); my_led_dev->va_dr = ioremap(mem_dr->start,4); my_led_dev->va_gdir = ioremap(mem_gdir->start,4); my_led_dev->va_iomuxc_mux = ioremap(mem_iomuxc_mux->start,4); my_led_dev->va_iomux_pad = ioremap(mem_iomux_pad->start,4); printk(KERN_INFO"hw_info:%u,%d\n",my_led_dev->led_pin,my_led_dev->clock_offset); printk(KERN_INFO"reg:0x%x,0x%x,0x%x,0x%x,0x%x,\n",mem_ccm_ccgrx->start,\ mem_dr->start,\ mem_gdir->start,\ mem_iomuxc_mux->start,\ mem_iomux_pad->start); ret = alloc_chrdev_region(&devno, pdev->id, 1, "led"); if(ret < 0){ printk(KERN_ERR "chrdev alloc region failed\n"); return ret; } printk(KERN_INFO "devno is %u(major:%u,minor:%u)\n",devno,MAJOR(devno), MINOR(devno)); my_led_dev->my_devno = devno; cdev_init(&my_led_dev->dev, &led_fops); my_led_dev->dev.owner = THIS_MODULE; ret = cdev_add(&my_led_dev->dev, devno, 1); if(ret < 0){ printk(KERN_ERR "chrdev add failed\n"); goto add_err; } device_create(led_class,NULL,devno,NULL,"led_%s",(pdev->id == 0)?"red":((pdev->id == 1)? "green":"blue")); platform_set_drvdata(pdev, my_led_dev); return 0; add_err: unregister_chrdev_region(my_led_dev, 1); return ret; } int led_plat_remove(struct platform_device *pdev) { dev_t cur_dev; struct led_chrdev *my_led_dev = platform_get_drvdata(pdev); printk("led platform driver remove\n"); iounmap(my_led_dev->va_ccm_ccgrx); iounmap(my_led_dev->va_dr); iounmap(my_led_dev->va_gdir); iounmap(my_led_dev->va_iomuxc_mux); iounmap(my_led_dev->va_iomux_pad); cur_dev = my_led_dev->my_devno; cdev_del(&my_led_dev->dev); device_destroy(led_class, cur_dev); unregister_chrdev_region(cur_dev, 1); return 0; } static const struct of_device_id rgb_led[] = { {.compatible = "fire,rgb_led_red"}, {.compatible = "fire,rgb_led_green"}, {.compatible = "fire,rgb_led_blue"}, {/* sentinel */} }; static struct platform_driver led_pdrv = { .probe = led_plat_probe, .remove = led_plat_remove, .driver = { .name = "led_pdev", .owner = THIS_MODULE, .of_match_table = rgb_led, }, .id_table = led_pdev_ids, }; static int __init led_plat_drv_init(void) { printk("led platform driver init\n"); led_class = class_create(THIS_MODULE, "led_class"); if(IS_ERR(led_class)) { printk(KERN_ERR" create class faild!/n"); return -EBUSY; } platform_driver_register(&led_pdrv); return 0; } static void __exit led_plat_drv_exit(void) { printk("led platform driver exit\n"); platform_driver_unregister(&led_pdrv); class_destroy(led_class); } module_init(led_plat_drv_init); module_exit(led_plat_drv_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("liuchao");