Core Lingsi Sinlinx A64 linux writes LED through device tree
Development platform Lingsi Sinlinx A64
Memory: 1GB storage: 4GB
Detailed parameter https://m.tb.cn/h.3wMaSKm
Development board communication group 641395230
Quanzhi A64 device tree structure
# include / / this structure is used to describe every device and every device child node in the device tree
Struct device_node {const char * name; const char * type; phandle phandle; const char * full_name; struct property * properties; / / attribute struct property * deadprops; / * removed properties * / struct device_node * parent; / / device child object, point to the device object struct device_node * child; / / device object to which it belongs, and point to the child node struct device_node * sibling / / point to the next object at the same level. Struct device_node * next; / * next device of same type * / / should point to device_type is the same object struct device_node * allnext; / * next in list of all nodes * /.}
/ / the following function is used to obtain the device nodes and device child nodes in the device tree.
Extern struct device_node * of_find_node_by_name (struct device_node * from, const char * name)
/ / find the corresponding device node by name
Static inline int of_get_child_count (const struct device_node * np)
/ / get the number of child nodes of the specified device
Extern struct device_node * of_find_node_by_path (const char * path)
/ / obtain the device node through the path, which can be used to obtain the device child node
Extern struct device_node * of_find_node_by_type (struct device_node * from, const char * type); / / obtain the device node through the specified device_type
/ / the following function is used to obtain the attributes of a device node or device child node.
Static inline int of_property_read_u32 (const struct device_node * np, const char * propname, U32 * out_value) extern int of_property_read_u32_index (const struct device_node * np, const char * propname, U32 index, U32 * out_value); extern int of_property_read_u8_array (const struct device_node * np, const char * propname, U8 * out_values, size_t sz) Extern int of_property_read_u16_array (const struct device_node * np, const char * propname, U16 * out_values, size_t sz); extern int of_property_read_u32_array (const struct device_node * np, const char * propname, U32 * out_values, size_t sz); extern int of_property_read_u64 (const struct device_node * np, const char * propname, U64 * out_value) Extern int of_property_read_string (struct device_node * np, const char * propname, const char * * out_string)
First, add nodes and modify the dtsi file.
Vim / lichee/linux-3.10/arch/arm64/boot/dts/sun50iw1p1-pinctrl.dtsi
Driver code:
# include # define MY_DEVICE_NAME "my_led_device" / / get to the node in the device tree static int gpio =-1; int get_irqno_from_node (void) {struct gpio_config config Struct device_node * np = of_find_node_by_path ("/ leds"); if (np) {printk ("find node ok\ n");} else {printk ("find node failed\ n") } gpio = of_get_named_gpio_flags (nd, "gpios", I, (enum of_gpio_flags *) & config); / / read the GPIO configuration number and flag if (! gpio_is_valid (gpio)) of gpios from the device tree {/ / determine whether the GPIO number is valid or not, and valid gpio_request applies to occupy the GPIO. If there is an error in the initialization process, you need to call gpio_free to release the previously applied and successful GPIO printk ("gpio isn't valid\ n"); return-1;} if (gpio_request (gpio, "leds")
< 0) printk("gpio request failed %d\n", gpio); gpio_direction_output(gpio, 1); //关灯 return 0; } static int my_open (struct inode *node, struct file *filp) { if(gpio) { printk("open ok\n"); } else { return -EINVAL; } return 0; } static ssize_t my_write (struct file *filp, const char __user *buf, size_t size, loff_t *off) { unsigned char val; copy_from_user(&val, buf, 1); printk(" gpl_dat address 0x%x\n",gpl_dat); if (val) { gpio_direction_output(gpio, 0); //关灯 printk("led on\n"); } else { gpio_direction_output(gpio, 1); //关灯 printk("led off\n"); } return 1; } static const struct file_operations my_led_fops = { //step 1 :定义file_operations结构体 .open = my_open, .write = my_write, }; //step 1 : static struct class *led_class; static struct cdev *pcdev; //定义一个cdev指针 static dev_t n_dev; //第一个设备号(包含了主和次) static int __init led_device_init(void) {//step 2 :注册 int ret = -1; pcdev = cdev_alloc();//分配cdev结构空间 if(pcdev == NULL) { printk(KERN_EMERG" cdev_alloc error\n"); ret = -ENOMEM; /* 分配失败 */ return ret; } //2. 动态申请设备号 ret = alloc_chrdev_region(&n_dev, 0 , 2, MY_DEVICE_NAME); if(ret < 0 ) { //释放前面成功的资源 kfree(pcdev); /*释放cdev结构空间 */ printk(KERN_EMERG"alloc_chrdev_region error\n"); return ret; } cdev_init(pcdev, &my_led_fops); //初始化cdev结构 /* 建立cdev和file_operations之间的连接 */ /* 或这样初始化cdev结构 pcdev->Owner = THIS_MODULE; pcdev- > ops = & my_led_fops; * / ret = cdev_add (pcdev, n_dev, 2); / / add a driver to the kernel and register the driver if (ret < 0) {/ / release the previous successful resource unregister_chrdev_region (n_dev, 2) / * release the previously applied reconciliation number * / kfree (pcdev); / * release the cdev structure space * / printk (KERN_EMERG "alloc_chrdev_region error\ n"); return ret } / * automatically create device nodes / dev/SinlinxA64_LED*/ led_class = class_create (THIS_MODULE, "myled"); device_create (led_class, NULL, n_dev, NULL, "SinlinxA64_LED"); get_irqno_from_node (); printk (KERN_EMERG "cdev ok\ n"); return 0 } static void _ exit led_device_exit (void) {/ / step 2: log out / / log out cdev structure cdev_del (pcdev); / / release device number unregister_chrdev_region (n_dev, 2) / * starting device number (primary and secondary) consecutive secondary number * / / release cdev structure space kfree (pcdev); device_destroy (led_class, n_dev); class_destroy (led_class); gpio_free (gpio); printk (KERN_EMERG "cdev_del ok\ n");} module_init (led_device_init) Module_exit (led_device_exit); MODULE_LICENSE ("GPL")
Reference article: https://blog.csdn.net/jklinux/article/details/82382066