1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
| #include <linux/init.h> #include <linux/module.h> #include <linux/gpio.h> #include <linux/of.h> #include <linux/of_gpio.h> #include <linux/delay.h> #include <linux/fs.h> #include <linux/cdev.h> #include <linux/uaccess.h>
#define LED_GPIO 20 #define DEVICE_NAME "rk3588_led" #define DEVICE_CLASS "led_class"
static int led_gpio = -1; static int major_number; static struct class *led_class = NULL; static struct device *led_device = NULL;
static int led_open(struct inode *, struct file *); static int led_release(struct inode *, struct file *); static ssize_t led_write(struct file *, const char __user *, size_t, loff_t *);
static struct file_operations fops = { .owner = THIS_MODULE, .open = led_open, .release = led_release, .write = led_write, };
static int led_open(struct inode *inodep, struct file *filep) { printk(KERN_INFO "LED device opened\n"); return 0; }
static int led_release(struct inode *inodep, struct file *filep) { printk(KERN_INFO "LED device closed\n"); return 0; }
static ssize_t led_write(struct file *filep, const char __user *buf, size_t len, loff_t *off) { char kbuf[2]; if (copy_from_user(kbuf, buf, len > 1 ? 1 : len) != 0) { printk(KERN_ERR "Failed to copy data from user\n"); return -EFAULT; } if (kbuf[0] == '1') { gpio_set_value(led_gpio, 1); printk(KERN_INFO "LED turned ON\n"); } else if (kbuf[0] == '0') { gpio_set_value(led_gpio, 0); printk(KERN_INFO "LED turned OFF\n"); } else { printk(KERN_WARNING "Invalid input. Use '1' to turn ON, '0' to turn OFF\n"); return -EINVAL; } return len; }
static int __init led_init(void) { int ret; ret = gpio_request(LED_GPIO, "led_gpio"); if (ret < 0) { printk(KERN_ERR "Failed to request GPIO %d\n", LED_GPIO); return ret; } ret = gpio_direction_output(LED_GPIO, 0); if (ret < 0) { printk(KERN_ERR "Failed to set GPIO direction\n"); gpio_free(LED_GPIO); return ret; } led_gpio = LED_GPIO; major_number = register_chrdev(0, DEVICE_NAME, &fops); if (major_number < 0) { printk(KERN_ERR "Failed to register character device\n"); gpio_free(led_gpio); return major_number; } led_class = class_create(DEVICE_CLASS); if (IS_ERR(led_class)) { printk(KERN_ERR "Failed to create device class\n"); unregister_chrdev(major_number, DEVICE_NAME); gpio_free(led_gpio); return PTR_ERR(led_class); } led_device = device_create(led_class, NULL, MKDEV(major_number, 0), NULL, DEVICE_NAME); if (IS_ERR(led_device)) { printk(KERN_ERR "Failed to create device\n"); class_destroy(led_class); unregister_chrdev(major_number, DEVICE_NAME); gpio_free(led_gpio); return PTR_ERR(led_device); } printk(KERN_INFO "LED driver initialized\n"); printk(KERN_INFO "Device created at /dev/%s\n", DEVICE_NAME); return 0; }
static void __exit led_exit(void) { if (led_gpio >= 0) { gpio_set_value(led_gpio, 0); gpio_free(led_gpio); } device_destroy(led_class, MKDEV(major_number, 0)); class_destroy(led_class); unregister_chrdev(major_number, DEVICE_NAME); printk(KERN_INFO "LED driver unloaded\n"); }
module_init(led_init); module_exit(led_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("RK3588 LED driver with character device interface");
|