From mboxrd@z Thu Jan 1 00:00:00 1970 From: joanpau.beltran@uib.cat (Joan Pau Beltran) Date: Wed, 18 Jan 2012 22:40:34 +0100 Subject: GPIO driver module for Jetway NF98 board In-Reply-To: <4F17302B.3050402@uib.cat> References: <20111222012154.GB14353@joshcartwright.net> <4EFB4BE4.2090409@uib.cat> <20111229175339.GE14353@joshcartwright.net> <4F17302B.3050402@uib.cat> Message-ID: <4F173C52.5010805@uib.cat> To: kernelnewbies@lists.kernelnewbies.org List-Id: kernelnewbies.lists.kernelnewbies.org 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 #include #include #include #include /* 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