All of lore.kernel.org
 help / color / mirror / Atom feed
From: joanpau.beltran@uib.cat (Joan Pau Beltran)
To: kernelnewbies@lists.kernelnewbies.org
Subject: GPIO driver module for Jetway NF98 board
Date: Wed, 18 Jan 2012 21:48:43 +0100	[thread overview]
Message-ID: <4F17302B.3050402@uib.cat> (raw)
In-Reply-To: <20111229175339.GE14353@joshcartwright.net>



Al 29/12/11 18:53, En/na Josh Cartwright ha escrit:
>  I'd recommend getting the base address of the GPIO region as documented
>  in the Intel manuals, instead of what looks like throw-away testing code
>  from your vendor.
>
>  Take a peak at drivers/watchdog/iTCO_wdt.c, as this watchdog timer is
>  also accessed through the LPC device. It might give you a few ideas.

I inspected the file, but did not understand how to relate that code to 
my case.


>  Yes, precisely. I'd recommend just using standard shift/masking (which
>  looks like what you are already doing). Keep in mind, however,
>  you'll need some locking strategy to ensure that a read-modify-write
>  cycle happens atomically.

Is the blocking really needed, given the fact that the region is already 
requested?
I expected that requesting the region prevents interferences like that.
If not, how should I do that?


>  While I appreciate it being inlined this time, your mailer seemed to
>  have munged whitespace, such that the code is very difficult to read :(.
>  You may want to see Documentation/email-clients.txt

Really sorry, here it goes again, hoping it is ok this time.

#include <linux/module.h>
#include <linux/types.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);
}

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);
     }
}

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 gpio_pins = {
     .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 = jwnf98_gpio_dbg_show,
     .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, add);
     byte = inb(PINX_FUNCTION);
     byte |= ~1;
     outb(byte, add);
}

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, add);
     byte = inb(PINX_FUNCTION);
     byte &= 1;
     outb(byte, add);
     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);
}

module_init(jwnf98_gpio_init);
module_exit(jwnf98_gpio_exit);

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


As suggested, an alternative of the #define GPIO_BASE will be to try 
this code
in the init function:

     /* Needed macros. */
     /* Vendor and device IDs of LPC device. */
     #define LPC_VENDOR_ID 0x8086
     #define LPC_DEVICE_ID 0x5031
     /* Offset into low pin count (LPC) config space of the GPIO base 
address. */
     #define GPIO_BAR_OFFSET 0x48
     #define GPIO_BAR_BITMASK 0x0000ff80

     /* Code in the init function */
     struct pci_dev *pdev = NULL;
     /* Get dev struct for the LPC device. */
     /* The GPIO BAR is located in the LPC device config space. */
     pdev = pci_get_device(LPC_VENDOR_ID, LPC_DEVICE_ID, NULL);
     /* Get base address from the LPC configuration space. */
     /* Where shoud we store this address? In a static global variable?
     unsigned int gpio_base;
     pci_read_config_dword(pdev, GPIO_BAR_OFFSET, gpio_base);
     /* Clear all but address bits. */
     gpio_base &= GPIO_BAR_BITMASK;
     /* release reference to device */
     pci_dev_put(pdev);

-- 
Joan Pau Beltran


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.kernelnewbies.org/pipermail/kernelnewbies/attachments/20120118/0b52deb3/attachment.html 

  reply	other threads:[~2012-01-18 20:48 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2011-12-21 17:34 GPIO driver module for Jetway NF98 board Joan Pau Beltran
2011-12-22  1:21 ` Josh Cartwright
     [not found] ` <20111222001549.GA14353@joshcartwright.net>
2011-12-28 17:03   ` Joan Pau Beltran
2011-12-29 17:53     ` Josh Cartwright
2012-01-18 20:48       ` Joan Pau Beltran [this message]
2012-01-18 21:40         ` Joan Pau Beltran
2012-01-23 21:00           ` Joan Pau Beltran

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4F17302B.3050402@uib.cat \
    --to=joanpau.beltran@uib.cat \
    --cc=kernelnewbies@lists.kernelnewbies.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.