/********************************************************************************* * Copyright: (C) 2017 LingYun IoT Studio * All rights reserved. * * Filename: platdrv_led.c * Description: This is the common LED driver runs on S3C24XX. * * Version: 1.0.0(10/27/2011~) * Author: Guo Wenxue * ChangeLog: 1, Release initial version on "10/27/2011 11:39:10 AM" * ********************************************************************************/ #include #include #include #include #include #include #include #include "platdev_led.h" #define TIMER_TIMEOUT 40 #define PLATDRV_MAGIC 0x60 #define LED_OFF _IO (PLATDRV_MAGIC, 0x18) #define LED_ON _IO (PLATDRV_MAGIC, 0x19) #define LED_BLINK _IO (PLATDRV_MAGIC, 0x20) static int dev_major = 0; struct led_device { struct s3c_led_platform_data *data; struct cdev cdev; struct class *dev_class; struct timer_list blink_timer; } led_device; void led_timer_handler(unsigned long data) { int i; struct s3c_led_platform_data *pdata = (struct s3c_led_platform_data *)data; for(i=0; inleds; i++) { if(ON == pdata->leds[i].status) { s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); } else { s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); } if(ENABLE == pdata->leds[i].blink ) /* LED should blink */ { /* Switch status between 0 and 1 to turn LED ON or off */ pdata->leds[i].status = pdata->leds[i].status ^ 0x01; } mod_timer(&(led_device.blink_timer), jiffies + TIMER_TIMEOUT); } } static int led_open(struct inode *inode, struct file *file) { struct led_device *pdev ; struct s3c_led_platform_data *pdata; pdev = container_of(inode->i_cdev,struct led_device, cdev); pdata = pdev->data; file->private_data = pdata; return 0; } static int led_release(struct inode *inode, struct file *file) { return 0; } static void print_led_help(void) { printk("Follow is the ioctl() command for LED driver:\n"); printk("Turn LED on command : %u\n", LED_ON); printk("Turn LED off command : %u\n", LED_OFF); printk("Turn LED blink command : %u\n", LED_BLINK); } /* compatible with kernel version >=2.6.38*/ static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct s3c_led_platform_data *pdata = file->private_data; switch (cmd) { case LED_OFF: if(pdata->nleds <= arg) { printk("LED%ld doesn't exist\n", arg); return -ENOTTY; } pdata->leds[arg].status = OFF; pdata->leds[arg].blink = DISABLE; break; case LED_ON: if(pdata->nleds <= arg) { printk("LED%ld doesn't exist\n", arg); return -ENOTTY; } pdata->leds[arg].status = ON; pdata->leds[arg].blink = DISABLE; break; case LED_BLINK: if(pdata->nleds <= arg) { printk("LED%ld doesn't exist\n", arg); return -ENOTTY; } pdata->leds[arg].blink = ENABLE; pdata->leds[arg].status = ON; break; default: printk("LED driver don't support ioctl command=%d\n", cmd); print_led_help(); return -EINVAL; } return 0; } static struct file_operations led_fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .unlocked_ioctl = led_ioctl, /* compatible with kernel version >=2.6.38*/ }; static int s3c_led_probe(struct platform_device *dev) { struct s3c_led_platform_data *pdata = dev->dev.platform_data; int result = 0; int i; dev_t devno; /* Initialize the LED status */ for(i=0; inleds; i++) { s3c2410_gpio_cfgpin(pdata->leds[i].gpio, S3C2410_GPIO_OUTPUT); if(ON == pdata->leds[i].status) { s3c2410_gpio_setpin(pdata->leds[i].gpio, pdata->leds[i].active_level); } else { s3c2410_gpio_setpin(pdata->leds[i].gpio, ~pdata->leds[i].active_level); } } /* Alloc the device for driver */ if (0 != dev_major) { devno = MKDEV(dev_major, 0); result = register_chrdev_region(devno, 1, "led"); } else { result = alloc_chrdev_region(&devno, 0, 1, "led"); dev_major = MAJOR(devno); } /* Alloc for device major failure */ if (result < 0) { printk("LED driver can't get major %d\n", dev_major); return result; } /* Initialize button structure and register cdev*/ memset(&led_device, 0, sizeof(led_device)); led_device.data = dev->dev.platform_data; cdev_init (&(led_device.cdev), &led_fops); led_device.cdev.owner = THIS_MODULE; result = cdev_add (&(led_device.cdev), devno , 1); if (result) { printk (KERN_NOTICE "error %d add led device", result ); goto ERROR; } led_device.dev_class = class_create(THIS_MODULE, "led"); if(IS_ERR(led_device.dev_class)) { printk("LED driver create class failure\n"); result = -ENOMEM; goto ERROR; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) device_create(led_device.dev_class, NULL, devno, NULL, "led"); #else device_create (led_device.dev_class, NULL, devno, "led"); #endif /* Initial the LED blink timer */ init_timer(&(led_device.blink_timer)); led_device.blink_timer.function = led_timer_handler; led_device.blink_timer.data = (unsigned long)pdata; led_device.blink_timer.expires = jiffies + TIMER_TIMEOUT; add_timer(&(led_device.blink_timer)); printk("S3C led driver version 1.0.0 initiliazed.\n"); return 0; ERROR: printk("S3C led driver version 1.0.0 install failure.\n"); cdev_del(&(led_device.cdev)); unregister_chrdev_region(devno, 1); return result; } static int s3c_led_remove(struct platform_device *dev) { dev_t devno = MKDEV(dev_major, 0); del_timer(&(led_device.blink_timer)); cdev_del(&(led_device.cdev)); device_destroy(led_device.dev_class, devno); class_destroy(led_device.dev_class); unregister_chrdev_region(devno, 1); printk("S3C led driver removed\n" ); return 0; } static struct platform_driver s3c_led_driver = { .probe = s3c_led_probe, .remove = s3c_led_remove, .driver = { .name = "s3c_led", .owner = THIS_MODULE, }, }; static int __init platdrv_led_init(void) { int rv = 0; rv = platform_driver_register(&s3c_led_driver); if(rv) { printk(KERN_ERR "%s:%d: Can't register platform driver %d\n", __FUNCTION__,__LINE__, rv); return rv; } printk("Regist S3C LED Platform Driver successfully.\n"); return 0; } static void platdrv_led_exit(void) { printk("%s():%d remove LED platform drvier\n", __FUNCTION__,__LINE__); platform_driver_unregister(&s3c_led_driver); } module_init(platdrv_led_init); module_exit(platdrv_led_exit); module_param(dev_major, int, S_IRUGO); MODULE_AUTHOR("GuoWenxue"); MODULE_DESCRIPTION("FL2440 LED driver platform driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:s3c_platdrv_led");