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