Registration and application of Linux GPIO
Linux Kernel, GPIO, ARM
In Linux kernel code, a GPIO is often used as a special signal, such as a chip-selection signal for chips.
Gpio application function, we often use, such as Gpio_request, then the Gpio is when, and how to register, this article to explore.
Based on the i.mx6 of Freesccale on the platform
Start with the implementation of the function Gpio_request first.
/* These "optional" allocation calls help prevent drivers from stomping * on all other, and help provide better diagnosti CS in Debugfs. * they ' re called even less than the "set direction" calls. */int gpio_request (unsigned gpio, const char *label) {struct gpio_desc*desc;struct gpio_chip*chip;intstatus =-einval; Unsigned longflags;spin_lock_irqsave (&gpio_lock, flags); if (!gpio_is_valid (GPIO)) goto done;//here from Gpio_desc The code that takes a gpio_desc struct//In the array is basically based on the structure of the struct//we take a description of the Gpio from the array, which should be added to the array at the time the Gpio is registered, and/or with this array as a clue to see how the Gpio notes Book desc = &gpio_desc[gpio];chip = desc->chip;if (chip = = NULL) goto done;if (!try_module_get (chip->owner)) goto done;/* note:gpio_request () can be called in early boot, * before IRQs is enabled, for non-sleeping (SOC) GPIOs. */if (Test_and_set_bit (flag_requested, &desc->flags) = = 0) {Desc_set_label (desc, label?: "?"); Status = 0;} else {status =-ebusy;module_put (Chip->owner); goto done;} if (chip->request) {/* chip->requestMay sleep */spin_unlock_irqrestore (&gpio_lock, flags); status = Chip->request (chip, gpio-chip->base); spin_ Lock_irqsave (&gpio_lock, Flags), if (status < 0) {Desc_set_label (desc, NULL); Module_put (Chip->owner); clear_ Bit (flag_requested, &desc->flags);}} Done:if (status) Pr_debug ("gpio_request:gpio-%d (%s) status%d\n", Gpio, label?: "?", status); Spin_unlock_irqrestore (& Amp;gpio_lock, flags); return status;}
Takes an array gpio_desc as a clue.
Since we are taking the data from this number when we apply for GPIO, we should add data to this number when we register the GPIO.
In turn, the place to add data to this array should also be where the GPIO is registered.
This array is defined in the GPIOLIB.C file:
static struct Gpio_desc Gpio_desc[arch_nr_gpios];
The search found that the Gpiochip_add function has assigned values to the array gpio_desc.
See who called the function Gpiochip_add.
The Mxc_gpio_init function in the gpio.c file in the platform-related directory calls the Gpiochip_add:
if (!initialed)/* Its a serious configuration bug when it fails */bug_on (Gpiochip_add (&port[i].chip) < 0);
Continue looking up, the DEVICES.C in the platform-related directory has the following functions:
int Mx6q_register_gpios (void) {/* 7 ports for Mx6 */return Mxc_gpio_init (mxc_gpio_ports, 7);}
Definition of
Mxc_gpio_ports:
static struct Mxc_gpio_port mxc_gpio_ports[] = {{. Chip.label = ' gpio-0 ',. Base = Io_address (GPIO1_BASE_ADDR),. IRQ = mxc_in T_gpio1_int15_0_num,.irq_high = Mxc_int_gpio1_int31_16_num,.virtual_irq_start = Mxc_gpio_irq_start},{.chip.label = " Gpio-1 ",. Base = Io_address (GPIO2_BASE_ADDR),. IRQ = Mxc_int_gpio2_int15_0_num,.irq_high = Mxc_int_gpio2_int31_16_num, . Virtual_irq_start = Mxc_gpio_irq_start + * 1},{.chip.label = "gpio-2",. Base = Io_address (GPIO3_BASE_ADDR),. IRQ = MXC_I Nt_gpio3_int15_0_num,.irq_high = Mxc_int_gpio3_int31_16_num,.virtual_irq_start = MXC_GPIO_IRQ_START + 32 * 2},{. Chip.label = "Gpio-3",. Base = Io_address (GPIO4_BASE_ADDR),. IRQ = Mxc_int_gpio4_int15_0_num,.irq_high = mxc_int_gpio4_ Int31_16_num,.virtual_irq_start = Mxc_gpio_irq_start + * 3},{.chip.label = "gpio-4",. Base = Io_address (Gpio5_base_ ADDR),. IRQ = Mxc_int_gpio5_int15_0_num,.irq_high = Mxc_int_gpio5_int31_16_num,.virtual_irq_start = MXC_GPIO_IRQ_ START + * 4},{.chip.label = "gpio-5",. Base = Io_address (Gpio6_baSE_ADDR),. IRQ = Mxc_int_gpio6_int15_0_num,.irq_high = Mxc_int_gpio6_int31_16_num,.virtual_irq_start = MXC_GPIO_IRQ_ START + * 5},{.chip.label = "gpio-6",. Base = Io_address (GPIO7_BASE_ADDR),. IRQ = Mxc_int_gpio7_int15_0_num,.irq_high = M Xc_int_gpio7_int31_16_num,.virtual_irq_start = Mxc_gpio_irq_start + 32 * 6},};
Continue up, find the MX6_INIT_IRQ function in the irq.c file under the same directory called the Mx6q_register_gpios.
The MX6_INIT_IRQ function is assigned to the INIT_IRQ function of the Machine_desc struct in the board.c file:
Machine_start (mx6xxxx, "Freescale i. mx 6 Board"). boot_params= Mx6_phys_offset + 0x100,.fixup= fixup_mxc_board,.map_io= mx6_map_io,.init_irq= mx6_init_irq,.init_machine= mx6_board_init,.timer= &mxc_timer,.reserve= Mx6q_reserve, Machine_end
The following functions are available in the Arch/arm/kernel/irq.c file:
void __init Init_irq (void) {MACHINE_DESC->INIT_IRQ ();}
The Start_kernel function in the init/main.c file called the INIT_IRQ.
As for when the Start_kernel function is called, there is time for further research.
Summarize the GPIO registration process:
The Start_kernel function calls the INIT_IRQ function.
The INIT_IRQ function calls the INIT_IRQ function of the machine_desc struct.
The MACHINE_DESC structure is defined in the Board.c file, where Init_irq is assigned the MX6_INIT_IRQ.
The Mx6q_register_gpios function is called in the MX6_INIT_IRQ function.
The definition of the Mx6q_register_gpios function is described in the preceding article, where the function mxc_gpio_init is called.
The implementation of the function Mxc_gpio_init:
int mxc_gpio_init (struct mxc_gpio_port *port, int cnt) {int I, j;static bool initialed;/* save for local usage *///port is the former Polygon defines the array mxc_gpio_ports, CNT is the number of elements in the array mxc_gpio_ports = Port;gpio_table_size = CNT;PRINTK (kern_info "MXC gpio hardware\n"); for (i = 0; i < cnt; i++) {/* Disable the interrupt and clear the status */__raw_writel (0, port[i].base + gpio_imr); __r Aw_writel (~0, port[i].base + GPIO_ISR); for (j = port[i].virtual_irq_start;j < Port[i].virtual_irq_start +; J + +) {IRQ _set_lockdep_class (J, &gpio_lock_class);/*static struct Irq_chip gpio_irq_chip = {. Name = "Gpio",. Irq_ack = Gpio_ack _irq,.irq_mask = Gpio_mask_irq,.irq_unmask = Gpio_unmask_irq,.irq_set_type = Gpio_set_irq_type,.irq_set_wake = Gpio_ set_wake_irq,};*//** *handle_level_irq-level Type IRQ Handler * @irq: The interrupt number * @desc: the interrupt Descriptio n structure for this IRQ * *level type interrupts is active as long as the hardware line has a *the active level. This could require to mask the interrupt and Unmask *it After the associated handler have acknowledged the device, so that the *interrupt line was back to inactive. */irq_set_chip_and_handler (J, &gpio_irq_chip, HANDLE_LEVEL_IRQ); Set_irq_flags (J, irqf_valid);} /* Register GPIO Chip *///mxc_gpio_direction_input sets the corresponding gpio to input, Mxc_gpio_direction_output sets the corresponding gpio to output and sets an initial value//this The input/output of the child is the cpu Port[i].chip.direction_input = Mxc_gpio_direction_input;port[i].chip.direction_output = Mxc_gpio_ direction_output;//Get/Set gpio status Port[i].chip.get = Mxc_gpio_get;port[i].chip.set = Mxc_gpio_set;port[i].chip.base = i * 32;port[i].chip.ngpio = 32;spin_lock_init (&port[i].lock), if (!initialed)/* Its a serious configuration bug when it FA Ils *///adds Gpio chip, which is called a cue function we used earlier, which has a value assigned to the GPIO_DESC array bug_on (Gpiochip_add (&port[i].chip) < 0); if (Cpu_is_ MX1 () | | CPU_IS_MX3 () | | cpu_is_mx25 () | | cpu_is_mx51 () | | Cpu_is_mx53 () | | Cpu_is_mx6q () | | CPU_IS_MX6DL () | | CPU_IS_MX6SL ()) {/* Setup one handler for each entry */irq_set_chained_handler (Port[i].irq,mx3_gpio_irq_handler); Irq_set_handler_data (PORT[I].IRQ, &port[i]); if (Port[i].irq_high) {/* Setup Handler for GPIO */irq_set_chained_handler (Port[i].irq_high,mx3_gpio_irq_handler); Irq_set_handler_data (port [I].irq_high, &port[i]);}} initialed = True;if (CPU_IS_MX2 ()) {/* Setup one handler for all GPIO interrupts */irq_set_chained_handler (PORT[0].IRQ, MX 2_gpio_irq_handler); Irq_set_handler_data (PORT[0].IRQ, port);} return 0;}
Implementation of the
Gpiochip_add function:
/** * GPIOCHIP_ADD ()-Register a gpio_chip * @chip: The chip to register, with chip->base initialized * Context:poten Tially before IRQs or kmalloc would work * * Returns a negative errno if the chip can ' t be registered, such as * because th e Chip->base is invalid or already associated with a * different chip. Otherwise it returns zero as a success code. * * when Gpiochip_add () are called very early during boot, so this GPIOs * can be freely used, the CHIP->DEV device must Be registered before * The GPIO framework ' s Arch_initcall (). Otherwise SYSFS initialization * For GPIOs would fail rudely. * * If chip->base is negative, this requests dynamic assignment of * a range of valid GPIOs. */int gpiochip_add (struct gpio_chip *chip) {unsigned longflags;intstatus = 0;unsignedid;intbase = Chip->base;if ((! Gpio_is_valid (base) | | !gpio_is_valid (base + chip->ngpio-1)) && Base >= 0) {status =-einval;goto fail;} Spin_lock_irqsave (&gpio_lock, flags); if (Base < 0){base = Gpiochip_find_base (Chip->ngpio), if (base < 0) {status = Base;goto unlock;} Chip->base = base;} /* These GPIO numbers must not being managed by another gpio_chip */for (id = base; ID < base + chip->ngpio; id++) {if (gpio_desc[id].chip! = NULL) {status =-ebusy;break;}} if (status = = 0) {for (id = base; ID < base + chip->ngpio; id++) {//Find here only the chip member that assigned the GPIO_DESC member gpio_desc[id].ch IP = chip;/* revisit:most hardware initializes GPIOs as * inputs (often with pullups enabled) so power * usage is Minimi Zed. Linux code should set the * Gpio direction first thing; But until it does, * we could expose the wrong direction in Sysfs. */gpio_desc[id].flags =!chip->direction_input? (1 << flag_is_out): 0;}} Of_gpiochip_add (Chip), Unlock:spin_unlock_irqrestore (&gpio_lock, Flags), if (status) Goto fail;//Create the device, and add the corresponding Sysfsstatus = Gpiochip_export (Chip), if (status) Goto Fail;return 0;fail:/* Failures Here can mean systems won ' t boot ... */p R_err ("Gpiochip_add:gpios%D.. %d (%s) failed to register\n ", Chip->base, Chip->base + Chip->ngpio-1,chip->label? : "GENERIC"); return status;}
Definition of GPIO_DESC structure:
struct Gpio_desc {struct gpio_chip*chip;unsigned longflags;/* flag symbols is bit numbers */#define Flag_requested0#defi NE flag_is_out1#define flag_reserved2#define flag_export3/* protected by Sysfs_lock */#define FLAG_SYSFS4/* exported via /sys/class/gpio/control */#define flag_trig_fall5/* trigger on falling edge * #define FLAG_TRIG_RISE6/* trigger on rising Edge */#define flag_active_low7/* SYSFS value have ACTIVE low */#define ID_SHIFT16/* Add new flags before this one */#defi Ne gpio_flags_mask ((1 << id_shift)-1) #define GPIO_TRIGGER_MASK (BIT (Flag_trig_fall) | BIT (flag_trig_rise)) #ifdef config_debug_fsconst Char*label; #endif};
Registration and application of Linux GPIO