Android Driver (I) GPIO

Source: Internet
Author: User

The previous blog post made a series of analyses on Lichee, which is actually a basic quality of Android BSP-SHELL script, as described in seven years itch, therefore, the Lichee series focuses on the basic structure of SHELL scripts and Lichee. Of course, as a qualified Android BSP engineer, we master the Linux driver porting, it is also a basic skill. So from the beginning of this article, we will conduct in-depth analysis on some sun4i drivers. Of course, drivers involve a wide range of aspects, such as camera drivers involving data structures such as sensor transplantation and kernel queues. SD card drivers also involve the basic principles of DMA, the Touch Screen driver also involves the input subsystem, interrupt context, and other related knowledge. The WIFI driver will involve the wireless LAN protocol and wap_supplicant and other related knowledge, 2G/3G modules often involve RIL libraries and AT commands. In addition, for convenient management, most external devices are mounted on iic usb uart and other bus (or virtual Bus ), each Development Board has its own schematic diagram and cabling method. These hardware-related content cannot be bypassed by BSP engineers during driver debugging. Thinking about it, because it involves too much complexity and limited capabilities, I still feel that from the perspective of BSP, first of all, I would like to briefly introduce the basic background knowledge, understand the meaning of the driver, then we started to optimize the transplantation driver. In this practical way, we slowly started to look at the driver that the module seems to be more difficult.
Processor: SUN4I A10 system: Android platform architecture: ARM
From Simplicity to complexity, first we will discuss the driver drivers/misc/sun4i-gpio.c of sun4i gpio.
1. What is GPIO?
GPIO is generally called General-Purpose IO ports, which is also a General IO port. Embedded systems usually have a large number of external devices/circuits with simple structures. Some of these devices/circuits require CPU to provide control measures, some need to be used as the input signal by the CPU. In addition, many such devices/circuits only require one device, that is, as long as there are two States on/off, such as lighting and off. Traditional serial ports or parallel ports are not suitable for controlling these devices/circuits. Therefore, a general programmable I/O interface (GPIO) is generally provided on the microcontroller chip.

The interface has at least two registers, namely, "General IO control register" and "General IO data register ". All data registers are directed to the outside of the chip, and the function of each bit in this register is the signal direction of each bit, you can set it independently by the corresponding bit in the control register. In this way, the presence or absence of GPIO interfaces is a feature that distinguishes a microcontroller from a microprocessor.


Ii. A10 GPIO
A10 has eight sets of multi-function input/output GPIO, as shown in the following figure. Container Port A (PA): 18 input/output port container Port B (PB ): 24 input/output port serial Port C (PC): 25 input/output port serial Port D (PD): 28 input/output port serial Port E (PE ): 12 input/output port fill Port F (PF): 6 input/output port fill Port G (PG): 12 input/output port fill Port H (PH ): 28 input/output port serial Port I (PI): 22 input/output port serial Port S (PS): 84 input/output port for DRAM controller
To cope with changing system configurations, these groups of GPIO can be easily configured through software. In addition to PS, other groups of GPIO can be configured as multi-function modes, it also supports 32 external interrupt sources and interrupt mode Port S (PS) that can be configured by software is designed for DRAM controllers, so the GPIO ports we normally use are between PA-PI
Three, source code parsing in the linux-3.0 directory drivers/misc/sun4i-gpio.c we know that when loading a driver, will execute module_init, when the driver exits, it will execute module_exit. Then we will start the analysis from module_init (sun4i_gpio_init). When the driver is loaded, it will go to sun4i_gpio_init (void ).

// Generally, the functions in the driver are modified using static, because the namespace in C does not exist, that is, the namespace in C ++. After static modification, the function name is equivalent to being visible in the current source file. Even if there are functions with the same name in other source files, compilation will not be affected. Here we select the final function sun4i_gpio_init in this driver for full-text analysis.
Static int _ init sun4i_gpio_init (void) {int err; int I; int sun4i_gpio_used = 0; struct sun4i_gpio_data * gpio_ I;/* include/linux/sysfs. h explain struct attribute {const char * name; struct module * owner; mode_t mode;}; struct device_attribute {struct attribute attr; ssize_t (* show) (struct device * dev, struct device_attribute * attr, char * buf); ssize_t (* store) (struct d Evice * dev, struct device_attribute * attr, const char * buf, size_t count) ;}; these two are struct in the sys file system. The key points are show and store in device_attribute, read and Write the device */struct device_attribute * attr_ I; char pin [16]; pr_info ("sun4i gpio driver init \ n "); /* used to obtain the value of the sub-key gpio_used in sys_config1.fex primary key gpio_para. If the value of gpio_used is 0, it indicates that the driver has been disabled through configuration, in this way, the configuration is used to control the opening and closing of the driver. Here we know that if we want to add the separately controlled gpio, we only need to add the primary key of gpio_para and the name is gpio in the sys_config1.fex file. _ Used subkey */err = script_parser_fetch ("gpio_para", "gpio_used", & signature, sizeof (sun4i_gpio_used)/sizeof (int); if (err) {pr_err ("% s script_parser_fetch \" gpio_para \ "\" gpio_used \ "error \ n", _ FUNCTION _); goto exit;} if (! Sun4i_gpio_used) {pr_err ("% s sun4i_gpio is not used in config \ n", _ FUNCTION _); err =-1; goto exit ;} /* used to obtain the value of the sub-key gpio_num in sys_config1.fex primary key gpio_para. It is clear that the sub-key gpio_num is used to define how many gpio */err = script_parser_fetch ("gpio_para ", "gpio_num", & sun4i_gpio_num, sizeof (sun4i_gpio_num)/sizeof (int); if (err) {pr_err ("% s script_parser_fetch \" gpio_para \ "\" gpio_num \ "error \ n", _ FUNCTION _); goto exit;} su N4i_gpio_dbg ("sun4i_gpio_num: % d \ n", sun4i_gpio_num); if (! Sun4i_gpio_num) {pr_err ("% s sun4i_gpio_num is none \ n", _ FUNCTION _); err =-1; goto exit;}/* registers a miscellaneous device, the master device number is 10, which is defined by the system */err = misc_register (& sun4i_gpio_dev); if (err) {pr_err ("% s register sun4i_gpio as misc device error \ n", _ FUNCTION _); goto exit;}/* based on the number of gpio, apply for a memory block for each gpio struct to save the attributes of each gpio read from the sys_config1.fex file */psun4i_gpio = kzarloc (sizeof (struct sun4i_gpio_data) * sun4i_gpio_num _ KERNEL);/* according to the number of gpio, apply for a device attribute for each gpio, each device attribute is used to read and write gpio In the sys File System */pattr = kzarloc (sizeof (struct device_attribute) * sun4i_gpio_num, GFP_KERNEL); if (! Psun4i_gpio |! Pattr) {pr_err ("% s kzarloc failed \ n", _ FUNCTION _); err =-ENOMEM; goto exit;} gpio_ I = psun4i_gpio; attr_ I = pattr; /* cyclically read the value of each gpio in the sys_config1.fex file and save the parsed value to gpio_ I */for (I = 0; I <sun4i_gpio_num; I ++) {/* we can see that the sub-key is similar to gpio_pin_1 gpio_pin_2 gpio_pin_3 ...... in this way, the */sprintf (pin, "gpio_pin _ % d", I + 1); sun4i_gpio_dbg ("pin: % s \ n", pin ); err = script_parser_fetch ("gpio_para", pin, (int *) & gp Io_ I-> info, sizeof (script_gpio_set_t); if (err) {pr_err ("% s script_parser_fetch \" gpio_para \ "\" % s \ "error \ n ", _ FUNCTION __, pin); break ;} /*************************************** **************************************** * ***************************** this is a description of the CSP_GPIO_Request_EX function * CSP_GPIO_Request_EX ** function Name: ** parameter description: The name of the primary key that main_name transfers to. It matches the subkey name that the module (driver name) ** sub_name transfers. If it is null, it indicates all, otherwise, the matched independent GPIO is found. ** return value: 0: Err * other: success ** description: there is no conflict check *********************************** **************************************** * **********************************/gpio_ I-> gpio_handler = gpio_request_ex ("gpio_para ", pin); sun4i_gpio_dbg ("gpio handler: % d", gpio_ I-> gpio_handler); if (! Gpio_ I-> gpio_handler) {pr_err ("% s can not get \" gpio_para \ "\" % s \ "gpio handler, \ already used by others? ", _ FUNCTION __, pin); break;} sun4i_gpio_dbg (" % s: port: % d, portnum: % d \ n ", pin, gpio_ I-> info. port, gpio_ I-> info. port_num);/* Turn the name to pa1, k2etc... */sprintf (gpio_ I-> name, "p % c % d", 'A' + gpio_ I-> info. port-1, gpio_ I-> info. port_num); sun4i_gpio_dbg ("psun4i_gpio-> name % s \ n", gpio_ I-> name ); /* Add attributes to the group * // * initialize the attribute to the sys File System and assign values to the members of the device_attribute struct, in this case, the read/write IO function worker is the read IO data, while sun4i_gpio_enable_store is the write value to IO */sysfs_attr_init (& attr_ I-> attr); attr_ I-> attr. name = gpio_ I-> name; attr_ I-> attr. mode = S_IRUGO | S_IWUSR | S_IWGRP | S_IWOTH; attr_ I-> show = External; attr_ I-> store = External; region [I] = & attr_ I-> attr; gpio_ I ++; attr_ I ++;} sysfs_create_group (& region-> kobj, & Region); exit: return err;} static void _ exit sun4i_gpio_exit (void) {sun4i_gpio_dbg ("bye, sun4i_gpio exit \ n "); sysfs_remove_group (& region-> kobj, & Region); misc_deregister (& Region); kfree (psun4i_gpio); kfree (pattr);} struct restart, this struct is actually used to describe a gpiostruct sun4i_gpio_data {int status; // The current status is actually the gpio value, 0 or 1 unsigned gpio_handler; // used to identify this gpio, it is equivalent to a unique id script_gpio_set_t info; char name [8]; // an 8-byte string used to describe the structure name, for example, "PI09"} script_gpio_set_t, is actually used to describe a single gpiotypedef struct {char gpio_name [32]; int port; int port_num; int mul_sel; int pull; int drv_level; int data;} script_gpio_set_t;


Let's take a look at the gpio configuration file; --------------------------------------------------------------------------------; GPIO configuration PC19-PC22 4 IO ports are input; gpio_pin_1 buzzer; gpio_pin_2 camera light; gpio_pin_3 printer light; export [gpio_para] gpio_used = 1gpio_num = 11gpio_pin_1 = port: PI09 <1> <0> gpio_pin_2 = port: PB03 <1> <0> gpio_pin_3 = port: PH22 <1> <0> gpio_pin_4 = port: PH23 <1> <0> gpio_pin_5 = port: PH24 <1> <0> gpio_pin_6 = port: PH25 <1> <0> gpio_pin_7 = port: PH26 <1> <0> gpio_pin_8 = port: PC19 <1> <0> gpio_pin_9 = port: PC20 <1> <0> gpio_pin_10 = port: PC21 <1> <0> gpio_pin_11 = port: PC22 <1> <0>

Taking gpio_pin_1 as an example, err = script_parser_fetch ("gpio_para", pin, (int *) & gpio_ I-> info, sizeof (script_gpio_set_t )); the Code indicates that the content with the primary key "gpio_para" and sub-key "gpio_pin_1" is retrieved from the configuration file and saved in the structure script_gpio_set_t.
Gpio_name = "gpio_pin_1"
Port = 'I'
Port_num = 09mul_sel = 1 pull = defaultdrv_level = defaultdata = 0 in the article Lichee (5) sysconfig1.fex configuration system, we have briefly analyzed the form of sysconfig1.fex and the description of GPIO
Description gpio format: Port + serial number in the group <功能分配> <内部电阻状态> <驱动能力> <输出电平状态>
Correspondingly, mul_sel is the function allocation, short for Multifunction select. This determines what function it belongs to. Because we have the output function here, the default value is 1 to view the relevant GPIO manual, mul_sel is selected as follows:
Pull corresponds to the internal resistance state, and drv_level corresponds to the driving capacity. Generally, the default value defalut is used.
Data indicates the output level of the GPIO. Generally, 1 indicates the high level, and 0 indicates the low level.
The sysfssys file system is a Virtual File System in the memory. It provides us with a hierarchy of kobject objects, it helps users observe the topological structure of devices in a simple file system. With the help of attribute objects, kobject can provide users with kernel variables to read or write files by exporting files. The device model was originally proposed to facilitate power management. However, sysfs is an unexpected achievement. To facilitate debugging, the developer of the device model decides to export the device structure tree as a file system. This quickly proved to be wise. First, sysfs replaces device-related files in/proc. In addition, it provides a useful view for system objects. In fact, sysfs was initially called driverfs, which appeared earlier than kobject. Finally, sysfs made us realize that a new object model is very beneficial to the system, so kobject came into being. Since the introduction of sysfs by kernel in 2.6, sysfs is always an indispensable part of the kernel.
Iv. Results

After the driver is loaded, A gpio with the same name as the sys_config1.fex file appears. We can use echo 1>/sys/devices/virtual/misc prepare? Http://www.bkjia.com/kf/ware/vc/ "target =" _ blank "class =" keylink "> keys/2NbGR1BJT8HLo6y2 + lk70ojsqs2ouf2zzndycjxpbwcgc3jjjpq =" http://www.2cto.com/uploadfile/2014/0607/20140607112943969.jpg "alt =" \ "> here is another note, therefore, all files are-rw-, that is, any user can read and write the file, and this is attr_ I-> attr. mode = S_IRUGO "S_IWUSR | S_IWGRP | S_IWOTH;
5. analysis when I first saw this driver, I was surprised to find that there were no open, write, read, and other functions at all, the reason is that sun4i_gpio_write and sun4i_gpio_open are printed, and the read function does not even print, and they do not exist at all. At that time, I carefully read all the code before I found out, the gpio driver gave up the file_operations method, but used sysfs to read and write GPIO.
So far, let's summarize the benefits of using sysfs to handle gpio 1. the characteristics of GPIO make it very suitable to use sysfs. The main task of the GPIO driver is to pull the level up and down (sometimes there are waveform pulses, some devices can be provided with voltage to allow the device to work. Typical devices include buzzer, LED lamp, and vibration motor (motor. sysfs is also very suitable for Android operating systems. Some APPs usually need to control hardware, such as controlling LED lighting, Buzzer sound and no sound, if the system calls open write read, we must provide JNI interfaces to the JAVA program at the application layer. However, these interfaces are very simple, if you want to compile a so library for them again, It is very troublesome. If sysfs is used, our application only needs to read and write a file to operate GPIO.
static int sun4i_gpio_open(struct inode *inode, struct file *file) { pr_info("sun4i_gpio open\n"); return 0;}ssize_t sun4i_gpio_write(struct file *file, const char __user *buf, size_t size, loff_t *offset) { pr_info("sun4i_gpio write\n"); return 0;}static const struct file_operations sun4i_gpio_fops = { .open = sun4i_gpio_open, .write = sun4i_gpio_write, .release= sun4i_gpio_release};


This article is a very simple driver mentioned after introducing Lichee and having a basic understanding of Lichee, especially after understanding how sys_config1.fex configures drivers, this article also tries to explain the driver more thoroughly, so that beginners can be more clear at a glance. However, during the writing process, if you want to introduce background knowledge, often lead to another Background introduction, so want to understand the driver, indeed still need to have a certain degree of knowledge here, sun4i-gpio driver difficulties, mainly sys_config1.fex combination, for those who are familiar with sysfs, this driver is indeed very simple and a good driver, not as the author described in KCONFIG, "a uugly gpio driver" ^_^

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.