This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hi, guys!
I was wondering where in the kernel code (ubuntu 14) is the implementation of the PSP function gpio_request( ) for Sitara? I find only this declaration:
In KERNEL/include/linunx/gpio.h :
static inline int gpio_request(unsigned gpio, const char *label) { return -ENOSYS; }
Nope.
The "gpio_request" function is called from "drivers/gpio/gpiolib.c"
int gpio_request(unsigned gpio, const char *label) { return gpiod_request(gpio_to_desc(gpio), label); }
I've checked this file as well. My gpiolib.c has the implementation shown below. But in it I SEE NO device dependent register accesses like "base + GPIO_CTRL = .... "
int gpio_request(unsigned gpio, const char *label) { struct gpio_desc *desc; struct gpio_chip *chip; int status = -EPROBE_DEFER; unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); if (!gpio_is_valid(gpio)) { status = -EINVAL; goto done; } 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 are 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->request may 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); goto done; } } if (chip->get_direction) { /* chip->get_direction may sleep */ spin_unlock_irqrestore(&gpio_lock, flags); gpio_get_direction(gpio); spin_lock_irqsave(&gpio_lock, flags); } done: if (status) pr_debug("gpio_request: gpio-%d (%s) status %d\n", gpio, label ? : "?", status); spin_unlock_irqrestore(&gpio_lock, flags); return status; } EXPORT_SYMBOL_GPL(gpio_request);
Hello again!
Yes, your methods are correct! I know about the __raw_readl( ) and __raw_writel( ) APIs as well. But it's the initialization of the GPIO that fails in my driver. Here is a snippet of code from my driver...
I use the header files from STARTERWARE and I do exactly as in the AM335X_StarterWare_02_00_01_01/examples/beaglebone/gpio/gpioLEDBlink.c example but my code does not work if I comment out gpio_request( ). I suspect that it has something to do with the pinmuxing. Here's my code:
#include <linux/module.h> #include <linux/io.h> //ioremap, iounmap #include <linux/gpio.h> #include "soc_AM335x.h" #include "hw_cm_per.h" #include "hw_gpio_v2.h" #define GPIO_REG_SPACE 0x1000 #define CMPER_REG_SPACE 0x1000 void __iomem * gpio_start_address; void __iomem * cmper_start_address; unsigned long *p; static int __init hello_init(void) { printk("*******seconddrv init *******\n"); gpio_request(65, "mygpio"); //--------DOES NOT WORK WITHOUT THIS LINE----------- printk("cmper ioremap( )\n"); cmper_start_address = ioremap_nocache(SOC_CM_PER_REGS, CMPER_REG_SPACE); if(cmper_start_address == 0){ printk("\n\n\nioremap( ) failed!\n"); return -1; }else{ printk("start_addr: %p\n", cmper_start_address); } //Set CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE p = (cmper_start_address+CM_PER_GPIO2_CLKCTRL); *p |= CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE; while((*p & CM_PER_GPIO2_CLKCTRL_MODULEMODE) != CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE){ } //Set CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK *p |= CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK; while((*p & CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK) != CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK){ } //Wait for IDLEST while((*p & CM_PER_GPIO2_CLKCTRL_IDLEST) != (CM_PER_GPIO2_CLKCTRL_IDLEST_FUNC<<CM_PER_GPIO2_CLKCTRL_IDLEST_SHIFT)){ } //Wait for CLKACTIVITY_GPIO_2_GDBCLK p = (cmper_start_address+CM_PER_L4LS_CLKSTCTRL); while((*p & CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_2_GDBCLK) != CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_2_GDBCLK){ } printk("gpio ioremap( )\n"); gpio_start_address = ioremap_nocache(SOC_GPIO_2_REGS, GPIO_REG_SPACE); if(gpio_start_address == 0){ printk("\n\n\nioremap( ) failed!\n"); return -1; }else{ printk("start_addr: %p\n", gpio_start_address); } p = (gpio_start_address+GPIO_CTRL); *p &= ~GPIO_CTRL_DISABLEMODULE; p = (gpio_start_address+GPIO_SYSCONFIG); *p |= GPIO_SYSCONFIG_SOFTRESET; p = (gpio_start_address+GPIO_SYSSTATUS); while(!(*p & GPIO_SYSSTATUS_RESETDONE)){ } p = (gpio_start_address+GPIO_OE); *p &= ~0x2; p = (gpio_start_address+GPIO_SETDATAOUT); *p = 0x02; return 0; } static void __exit hello_exit(void) { printk("*******seconddrv exit*******\n"); p = (gpio_start_address+GPIO_CLEARDATAOUT); *p = 0x02; iounmap(gpio_start_address); iounmap(cmper_start_address); gpio_free(65); }
Hi!
I was unable to access the pin from the SYSFS because when I pinmux with direct register access I do not get an entry in /sys/class/gpio.
However I've discovered the problem with my code - for some reason I cannot pass the line:
while((*p & CM_PER_GPIO2_CLKCTRL_IDLEST) != (CM_PER_GPIO2_CLKCTRL_IDLEST_FUNC<<CM_PER_GPIO2_CLKCTRL_IDLEST_SHIFT)){ }
When I commented it out my simple device driver worked as expected. Thank you for your time, Titusrathinaraj!
Here's the code to turn on a LED at pin GPIO2_1 on driver __init and turn it off on driver __exit using adapted code from Starterware for Sitara:
#include <linux/module.h> #include <linux/io.h> //ioremap, iounmap #include <linux/gpio.h> #include "soc_AM335x.h" #include "hw_control_AM335x.h" #include "hw_cm_per.h" #include "hw_gpio_v2.h" #define GPIO_REG_SPACE 0x1000 #define CMPER_REG_SPACE 0x1000 #define CONTR_REG_SPACE 0x20000 void __iomem * control_start_address; void __iomem * gpio_start_address; void __iomem * cmper_start_address; unsigned long *p; static int __init hello_init(void) { printk("*******seconddrv init *******\n"); printk("control ioremap( )\n"); control_start_address = ioremap(SOC_CONTROL_REGS, CONTR_REG_SPACE); if(control_start_address == 0){ printk("\n\n\nioremap( ) failed!\n"); return -1; }else{ printk("start_addr: %p\n", control_start_address); } //Select pin mux p = control_start_address + 0x904; *p = 0x0f; printk("cmper ioremap( )\n"); cmper_start_address = ioremap_nocache(SOC_CM_PER_REGS, CMPER_REG_SPACE); if(cmper_start_address == 0){ printk("\n\n\nioremap( ) failed!\n"); return -1; }else{ printk("start_addr: %p\n", cmper_start_address); } //Set CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE p = (cmper_start_address+CM_PER_GPIO2_CLKCTRL); *p |= CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE; while((*p & CM_PER_GPIO2_CLKCTRL_MODULEMODE) != CM_PER_GPIO2_CLKCTRL_MODULEMODE_ENABLE){ } //Set CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK *p |= CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK; while((*p & CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK) != CM_PER_GPIO2_CLKCTRL_OPTFCLKEN_GPIO_2_GDBCLK){ } //Wait for IDLEST --- DOES NOT WORK //while((*p & CM_PER_GPIO2_CLKCTRL_IDLEST) != (CM_PER_GPIO2_CLKCTRL_IDLEST_FUNC<<CM_PER_GPIO2_CLKCTRL_IDLEST_SHIFT)){ } //Wait for CLKACTIVITY_GPIO_2_GDBCLK p = (cmper_start_address+CM_PER_L4LS_CLKSTCTRL); while((*p & CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_2_GDBCLK) != CM_PER_L4LS_CLKSTCTRL_CLKACTIVITY_GPIO_2_GDBCLK){ } printk("gpio ioremap( )\n"); gpio_start_address = ioremap_nocache(SOC_GPIO_2_REGS, GPIO_REG_SPACE); if(gpio_start_address == 0){ printk("\n\n\nioremap( ) failed!\n"); return -1; }else{ printk("start_addr: %p\n", gpio_start_address); } p = (gpio_start_address+GPIO_CTRL); *p &= ~GPIO_CTRL_DISABLEMODULE; p = (gpio_start_address+GPIO_SYSCONFIG); *p |= GPIO_SYSCONFIG_SOFTRESET; p = (gpio_start_address+GPIO_SYSSTATUS); while(!(*p & GPIO_SYSSTATUS_RESETDONE)){ } p = (gpio_start_address+GPIO_OE); *p &= ~0x2; p = (gpio_start_address+GPIO_SETDATAOUT); *p = 0x02; return 0; } static void __exit hello_exit(void) { printk("*******seconddrv exit*******\n"); p = (gpio_start_address+GPIO_CLEARDATAOUT); *p = 0x02; iounmap(gpio_start_address); iounmap(cmper_start_address); iounmap(control_start_address); } module_init(hello_init); module_exit(hello_exit); MODULE_AUTHOR("L.B."); MODULE_DESCRIPTION("BeagleBone Black blink a 0.5 mA LED on GPIO2_1. Device driver."); MODULE_LICENSE("GPL");