GPIO driver module for Jetway NF98 board

Joan Pau Beltran joanpau.beltran at uib.cat
Wed Jan 18 16:40:34 EST 2012


Sorry for the noise, but the last code was from a primitive version with
several typos and errors. Sorry for the noise.

Here it goes the fixed code:

#include <linux/module.h>
#include <linux/types.h>
#include <linux/ioport.h>
#include <linux/gpio.h>
#include <asm-generic/io.h>


/* TODO: Look how to get the GPIO base address from the LPC interface.*/
#define GPIO_BASE 0x500

/* pin 0 (GPIO 21) is controlled by an specific bit of a different set 
of ports: */
#define PIN0_FUNCTION  GPIO_BASE + 0x2
#define PIN0_DIRECTION GPIO_BASE + 0x6
#define PIN0_STATUS    GPIO_BASE + 0xE
#define PIN0_BIT       5

/* pins 1 to 7 (GPIO 33 to 39) correspond to the respective bit on these 
ports */
#define PINX_FUNCTION  GPIO_BASE + 0x30
#define PINX_DIRECTION GPIO_BASE + 0x34
#define PINX_STATUS    GPIO_BASE + 0x38


static int jwnf98_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
     unsigned long dir_add;
     unsigned bit_off;
     uint8_t byte;
     if (off)
     {
         dir_add = PINX_DIRECTION;
         bit_off = off;
     }
     else
     {
         dir_add = PIN0_DIRECTION;
         bit_off = PIN0_BIT;
     }
     byte = inb(dir_add);
     byte |= (1 << bit_off);
     outb(byte, dir_add);
     return 0;
}

static int jwnf98_gpio_direction_output(struct gpio_chip *gc, unsigned 
off, int val)
{
     unsigned long dir_add;
     unsigned long val_add;
     unsigned bit_off;
     uint8_t byte;
     if (off)
     {
         dir_add = PINX_DIRECTION;
         val_add = PINX_STATUS;
         bit_off = off;
     }
     else
     {
         dir_add = PIN0_DIRECTION;
         val_add = PIN0_STATUS;
         bit_off = PIN0_BIT;
     }
     byte = inb(dir_add);
     byte &= ~(1 << bit_off);
     outb(byte, dir_add);
     if (val)
     {
         byte = inb(val_add);
         byte |= (1 << bit_off);
         outb(byte, val_add);
     }
     else
     {
         byte = inb(val_add);
         byte &= ~(1 << bit_off);
         outb(byte, val_add);
     }
     return 0;
}

static int jwnf98_gpio_get(struct gpio_chip *gc, unsigned off)
{
     unsigned long add;
     unsigned bit;
     uint8_t byte;
     if (off)
     {
         add = PINX_STATUS;
         bit = off;
     }
     else
     {
         add = PIN0_STATUS;
         bit = PIN0_BIT;
     }
     byte = inb(add);
     byte &= (1 << bit);
     return !!byte; /* Is the double negation !! needed? */
}

static void jwnf98_gpio_set(struct gpio_chip *gc, unsigned off, int val)
{
     unsigned long add;
     unsigned bit;
     uint8_t byte;
     if (off)
     {
         add = PINX_STATUS;
         bit = off;
     }
     else
     {
         add = PIN0_STATUS;
         bit = PIN0_BIT;
     }
     byte = inb(add);
     if (val)
         byte |= (1 << bit);
     else
         byte &= ~(1 << bit);
     outb(byte, add);
}

static struct gpio_chip jwnf98_gpio_chip = {
     .label = "jwnf98_gpio",
     .owner = THIS_MODULE,
     .direction_input  = jwnf98_gpio_direction_input,
     .get = jwnf98_gpio_get,
     .direction_output = jwnf98_gpio_direction_output,
     .set = jwnf98_gpio_set,
     .dbg_show = NULL,
     .can_sleep = 0,
};

static int __init jwnf98_gpio_init(void)
{
     /*
     Do preliminar work here:
         - Request ports? DONE.
         - Create the chip here instead of let it be static? How? NOT 
NEEDED.
         - Enable gpio function for each pin? DONE.
         - Something else?
     */
     uint8_t byte;
     request_region(PIN0_FUNCTION,  1, "jwnf98_gpio");
     request_region(PIN0_DIRECTION, 1, "jwnf98_gpio");
     request_region(PIN0_STATUS,    1, "jwnf98_gpio");
     request_region(PIN0_BIT,       1, "jwnf98_gpio");
     request_region(PINX_FUNCTION,  1, "jwnf98_gpio");
     request_region(PINX_DIRECTION, 1, "jwnf98_gpio");
     request_region(PINX_STATUS,    1, "jwnf98_gpio");
     /*
     Should we check that the requested memory is available? How?
     */
     byte = inb(PIN0_FUNCTION);
     byte |= (1 << PIN0_BIT);
     outb(byte, PIN0_FUNCTION);
     byte = inb(PINX_FUNCTION);
     byte |= ~1;
     outb(byte, PINX_FUNCTION);
     /*
     Should we add the gpio_chip here with gpiochip_add?
     */
     return gpiochip_add(&jwnf98_gpio_chip);
}

static void __exit jwnf98_gpio_exit(void)
{
     /*
     Do cleanup work here:
         - Release ports? DONE.
         - Delete the chip if it was created on init function
           instead of being static? How? NOT NEEDED.
         - Disable gpio function for each pin? DONE.
         - Something else?
     */
     uint8_t byte;
     byte = inb(PIN0_FUNCTION);
     byte &= ~(1 << PIN0_BIT);
     outb(byte, PIN0_FUNCTION);
     byte = inb(PINX_FUNCTION);
     byte &= 1;
     outb(byte, PIN0_FUNCTION);
     release_region(PIN0_FUNCTION,  1);
     release_region(PIN0_DIRECTION, 1);
     release_region(PIN0_STATUS,    1);
     release_region(PIN0_BIT,       1);
     release_region(PINX_FUNCTION,  1);
     release_region(PINX_DIRECTION, 1);
     release_region(PINX_STATUS,    1);
     /*
     Should we remove the gpio_chip here? How to do that?
     */
}

module_init(jwnf98_gpio_init);
module_exit(jwnf98_gpio_exit);

MODULE_DESCRIPTION("Jetway NF98 GPIO driver");
MODULE_LICENSE("GPL");

-- 
Joan Pau Beltran




More information about the Kernelnewbies mailing list