4

im working with a AT91SAM9G25 board which has 4 PIO controller managing up to 32 programmable I/O lines. Each pin is configurable as either a general-purpose I/O line only or as an I/O line multiplexed up to two peripheral I/Os. So, for example, according with the documentation (SAM9G25, page 14), signal PC0 can be multiplexed such a general purpose I/O line or as the ISI_D0 line of the VIDEO_ATMEL_ISI (ISI of Image Sensor Interface).

╔════════════╦════════════╦════════════╦════════════╦════════════╗
║  Primary   ║ Alternates ║   PeripA   ║   PeripB   ║  PeripC    ║
╠════════════╬════════════╬════════════╬════════════╬════════════╣
║ Signal/Dir ║ Signal/Dir ║ Signal/Dir ║ Signal/Dir ║ Signal/Dir ║
║ ---------  ║ ---------  ║ ---------  ║ ---------  ║ ---------  ║
║ PC0 / I/O  ║            ║            ║ ISI_D0 / I ║            ║
╚════════════╩════════════╩════════════╩════════════╩════════════╝

The reset state of all GPIO lines is with direction IN and Pullup enabled. when i use GPIOLIB via sysfs i read a "1" value as INPUT in several GPIOs due to pullup. Is this a normal safe state of GPIO (INPUT with Pullup resistor) at reset in several boards when they can be multiplexed with other Peripherals?. I dont see how i can disable the pullup via userspace with GPIOLIB. So for example, i see that when kernel is booting it checks if the Image Sensor Peripheral is enabled at kernel or as a module and if so it sets the PC0 to Peripheral B. This is in the kernel sources at /arch/arm/mach-at91/at91sam9x5_devices.c

#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
....
         at91_set_B_periph(AT91_PIN_PC0, 0);    /* ISI_D0 */
...
#endif

Then if i dont enable ISI support in kernel i can use the PC0 signal as GPIO line. This is the /sys/kernel/debug/gpio:

    # cat /sys/kernel/debug/gpio

    GPIOs 32-63, A:

    GPIOs 64-95, B:
    [atmel_usba_udc] GPIOB16: [gpio] set
    [d1] GPIOB18: [gpio] clear

    GPIOs 96-127, C:

    GPIOs 128-159, D:
    [ohci_vbus] GPIOD19: [gpio] clear
    [ohci_vbus] GPIOD20: [gpio] clear
    [d2] GPIOD21: [gpio] set

And this is /sys/kernel/debug/at91_gpio

    # cat /sys/kernel/debug/at91_gpio

    Pin     PIOA            PIOB            PIOC            PIOD

    0:      A               A               GPIO:1          A
    1:      A               A               GPIO:1          A
    2:      GPIO:1          A               GPIO:1          A
    3:      GPIO:1          A               GPIO:1          A
    4:      GPIO:1          A               GPIO:1          GPIO:1
    5:      GPIO:1          A               GPIO:1          GPIO:1
    6:      GPIO:1          A               GPIO:1          A
    7:      B               A               GPIO:1          A
    8:      GPIO:1          GPIO:1          GPIO:1          A
    9:      A               A               GPIO:1          A
    10:     A               A               GPIO:1          A
    11:     A               GPIO:1          GPIO:1          A
    12:     A               GPIO:1          GPIO:1          A
    13:     A               GPIO:1          GPIO:1          A
    14:     A               GPIO:1          GPIO:1          GPIO:1
    15:     GPIO:1          GPIO:1          GPIO:1          A
    16:     GPIO:1          GPIO:1          GPIO:0          A
    17:     GPIO:1          GPIO:1          GPIO:1          A
    18:     GPIO:1          GPIO:1          GPIO:1          A
    19:     GPIO:1          A               GPIO:1          GPIO:0
    20:     GPIO:1          A               GPIO:0          GPIO:0
    21:     GPIO:1          A               GPIO:0          GPIO:1
    22:     GPIO:1          A               GPIO:1          A
    23:     GPIO:1          A               GPIO:1          A
    24:     GPIO:1          A               GPIO:1          A
    25:     GPIO:1          A               GPIO:1          A
    26:     GPIO:1          A               GPIO:1          A
    27:     GPIO:0          A               GPIO:1          A
    28:     GPIO:1          A               GPIO:0          A
    29:     GPIO:1          A               GPIO:0          A
    30:     GPIO:1          A               GPIO:1          A
    31:     GPIO:1          A               GPIO:1          A

The above output show that PIOA0 is multiplexed to Peripheral A (TXD0 UART Line), and for example PIOC20 is cleared, but the documentation says that all GPIO lines at reset state are INPUTS with pullup and i dont find where kernel or u-boot disable the pullup of this GPIO (maybe GPIOs keep their state if none touch his registers?)

But he main question is, how can i clear the pullup register of the GPIO lines? I find in kernel sources that /arch/arm/mach-at91/at91sam9x5_devices.c uses this function implemented in linux-2.6.39/arch/arm/mach-at91/gpio.c .

    /*
    * enable/disable the pull-down.
    * If pull-up already enabled while calling the function, we disable it.
    */
    int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
    {
        void __iomem    *pio = pin_to_controller(pin);
        unsigned    mask = pin_to_mask(pin);

        if (!pio || !cpu_has_pio3())
            return -EINVAL;

        /* Disable pull-up anyway */
        __raw_writel(mask, pio + PIO_PUDR);
        __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
        return 0;
    }
    EXPORT_SYMBOL(at91_set_pulldown);

Header arch/arm/mach-at91/include/mach/gpio.h

    #ifndef __ASSEMBLY__
    /* setup setup routines, called from board init or driver probe() */
    .....
    extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
    .....
    #endif  /* __ASSEMBLY__ */

How can use this functions with my toolchain, or should i make a kernel module?

Thanks

PD: Sorry for any mistakes in my english, i know i need to improve it.

MABC
  • 576
  • 2
  • 11
  • 29

2 Answers2

2

Maybe you can just leave the pullup alone. I've used GPIO on OMAP SoCs, at lowest level there are similar pin mux options, but it wasn't necessary to worry about pullups. Usually whatever is driving it can sink enough current (this is EE/circuit viewpoint, don't worry if you are unfamiliar). Floating input could be random and troublesome; pulled up high should be OK.

I would not think you should need to make a kernel module. I'd suggest you experiment using existing user mode interfaces. Your kernel should already have low-level drivers hooked in to provide access through sysfs. Refer to sysfs, omap gpio. I don't think I've seen pullup options in sysfs. If you get something working and need to call it from C code, then you can look for APIs, or just use system().

Joe Kul
  • 2,454
  • 16
  • 16
  • Hi Joe Kul, thanks. I will check about relays being activated by inputs line with pullups, i think you are right. I have another question related, thats how can i look for the kernel API for GPIO? Im a begginer interfacing my apps with the kernel, i only know the call systems (POSIX) way trough the GNU C library. But if there is not a module builted when i built the kernel, what library should i use? Which the way to use a driver in the kernel out of libc and without a library? Sorry if its a silly question or i maybe need more background about linux drivers. – MABC Mar 16 '13 at 12:51
  • The easiest way to begin would be to use commands at the linux console. Check sysfs link above. Linux console is where you would log in, then enter other commands like ls to see directory contents. If you want to drive GPIO #82 as an output low to a relay, these kind of commands may do it: echo 82 > /sys/class/gpio/export; echo out > /sys/class/gpio/gpio82/direction; echo 0 > /sys/class/gpio/gpio82/value. If you want to do that from a Linux application you could put them in a shell script file (/home/me/my.sh) then in application add this line of code: system("/home/me/my.sh"); – Joe Kul Mar 17 '13 at 00:50
  • Hi again joe kul, thanks. I know the way trough sysfs to drive GPIO, but the function to enable or disable GPIO pullup are not exported to sysfs, then i think i have to export this function to userspace via sysfs, but now i think this question is solved because the pullups are very weak to activate a relay. The question was about using general drivers in linux, i think the only way is using librarys or kernel module, or trough the general system calls of libc, im right? – MABC Mar 17 '13 at 01:16
  • Hi. If you needed to call low-level functions touching HW like at91_set_pulldown(), you would need kernel driver or hack/rebuild yes. But that is hard for a beginner. In this case I think the GPIO will work for you without any of that trouble. Thanks for answering question, good luck :) – Joe Kul Mar 17 '13 at 11:07
0

On newer kernels using device tree you can control it by recompiling the devicetree "blob" and do not need to change the kernel or write a kernel driver.

http://lxr.free-electrons.com/source/Documentation/devicetree/bindings/pinctrl/atmel,at91-pinctrl.txt

But it would be really sweet if pinctrl had a user space interface like the gpio so the complete solution in controlling pin's was user space controlled.

zingo
  • 249
  • 1
  • 5