Hi Bruce,
[EMAIL PROTECTED] wrote:
Hi,
I've got an MPC8347 running the 2.6.24-rc5 kernel and I'm trying to access
the GPIO registers. I already have a driver that's doing related work
(tho across PCI) and I just want to remap the internal CPU address to a
kernal address and be able to read/write the register using an IOCTL call
from user space. My problem is, every accessor I try does an endian
conversion before giving me my data. So here's some code snipits of what
I'm doing:
request_mem_region(0xe0000c00, 24, "my driver"); // 0xe0000c00 is the
memory mapped location of the GPIO regs
data_ptr2 = ioremap(0xe0000c00, 24);
Then in the IOCTL function I try to read from the register. First I
tried:
ioread32(data_ptr2);
I know that the mapping is working okay because I got the data from the
GPIO direction register, but it's been byte swapped. The contents of the
register are 0xFFFFFFE7, but what my user space app gets back is
0xE7FFFFFF. I've tried all the varients I can find, readl(), inl(),
in_be32(), in_le32(), even __raw_readl(). They all give me back byte
swapped data. I'm very confused. Especially since I've looked at
in_be32() and in_le32(), they're both inline assembly, and they use
different instructions. They can't be giving me the same results. I'm
sure I'm not the first person to want to access PowerPC internal registers
through a driver. Can anyone give me a hint what I'm doing wrong?
As an additional question related to PowerPC inline assembly, can anyone
tell me what "%U1%X1" means in the following:
__asm__ __volatile__("lwz%U1%X1 %0,%1; twi 0,%0,0; isync" : "=r" (ret) :
"m" (*addr));
Thanks.
See 'ya!
Bruce
_______________________________________________
I've attached a poorly-written-yet-functional GPIO driver that I wrote a
while ago for the MPC8349 (same as what you have for all intents and
purposes). It uses in_be32() and out_be32().
Let me know if you have any questions.
regards,
Ben
/******************************************************************************
*
* gpio_driver.c
* Copyright Qstreams Networks 2006
*
* This file contains a simple Linux device driver for accessing GPIO ports
* It is originally targeted for the MPC8349 PowerQUICC II Pro processor,
* although with simple modifications it should work with lots of CPUs. Note
* that all CPU accesses are big-endian.
*
* History:
* 04/11/2006 BAW Initial Creation
*
*****************************************************************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "gpio.h"
struct gpio_dev {
struct gpio_reg *regs;
struct cdev cdev;
};
MODULE_AUTHOR("Ben Warren");
MODULE_LICENSE("GPL");
static int gpio_major_num;
static struct gpio_dev *gpio_devices;
static spinlock_t gpioLock[GPIO_NUM_BANKS];
extern phys_addr_t get_immrbase(void);
static u32 readGpioReg(u8 bank, u32 * addr)
{
u32 value;
spin_lock(&gpioLock[bank]);
value = in_be32(addr);
spin_unlock(&gpioLock[bank]);
return value;
}
static void writeGpioReg(u8 bank, u32 * addr, u32 val, u32 mask)
{
spin_lock(&gpioLock[bank]);
out_be32(addr, (in_be32(addr) & ~mask) | val);
spin_unlock(&gpioLock[bank]);
}
/*****
* Kernel-mode GPIO access functions.
* DO NOT CALL FROM USERSPACE
*****/
int kgpio_set_dir(u8 bank, u8 bit, u8 isOutput)
{
u32 value = GPIO_BIT(bit);
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
writeGpioReg(bank, &gpio_devices[bank].regs->gpxdir,
isOutput ? value : 0, value);
return 0;
}
EXPORT_SYMBOL(kgpio_set_dir);
int kgpio_get_dir(u8 bank, u8 bit)
{
u32 value;
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdir);
return (value & GPIO_BIT(bit) ? 1 : 0);
}
EXPORT_SYMBOL(kgpio_get_dir);
int kgpio_set_data(u8 bank, u8 bit, u8 isHigh)
{
u32 value = GPIO_BIT(bit);
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
writeGpioReg(bank, &gpio_devices[bank].regs->gpxdat,
isHigh ? value : 0, value);
return 0;
}
EXPORT_SYMBOL(kgpio_set_data);
int kgpio_get_data(u8 bank, u8 bit)
{
u32 value;
if ((bank >= GPIO_NUM_BANKS) || !gpio_devices) {
return -ENODEV;
}
value = readGpioReg(bank, &gpio_devices[bank].regs->gpxdat);
return (value & GPIO_BIT(bit) ? 1 : 0);
}
EXPORT_SYMBOL(kgpio_get_data);
int gpio_open(struct inode *inode, struct file *filp)
{
struct gpio_dev *dev;
/* Set things up so other methods can access private data */
dev = container_of(inode->i_cdev, struct gpio_dev, cdev);
filp->private_data = dev;
return 0;
}
int gpio_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int rc = 0;
gpioDataAccess gpioData = { 0, 0 };
struct gpio_dev *dev;
u8 bank;
/* Check that the caller really wanted GPIO */
if (_IOC_TYPE(cmd) != GPIO_IOC_MAGIC)
return -ENOTTY;
if (_IOC_NR(cmd) > GPIO_IOC_MAXNR)
return -ENOTTY;
/* Check access controls */
if (_IOC_DIR(cmd) & _IOC_READ)
rc = !access_ok(VERIFY_WRITE, (void __user *)arg,
_IOC_SIZE(cmd));
else if (_IOC_DIR(cmd) & _IOC_WRITE)
rc = !access_ok(VERIFY_READ, (void __user *)arg,
_IOC_SIZE(cmd));
if (rc)
return -EFAULT;
bank = (u8) iminor(inode);
dev = filp->private_data;
switch (cmd) {
/* Direction Register access */
case GPIO_IOC_GET_DIR:
return readGpioReg(bank, &dev->regs->gpxdir);
case GPIO_IOC_SET_DIR:
if (copy_from_user(&gpioData,
(const void __user *)arg,
sizeof(gpioDataAccess))) {
printk(KERN_ERR "copy_from_user failed\n");
return -EFAULT;
}
writeGpioReg(bank, &dev->regs->gpxdir,
gpioData.value, gpioData.mask);
break;
/* Data Register access */
case GPIO_IOC_GET_DATA:
return readGpioReg(bank, &dev->regs->gpxdat);
case GPIO_IOC_SET_DATA:
if (copy_from_user(&gpioData,
(const void __user *)arg,
sizeof(gpioDataAccess))) {
printk(KERN_ERR "copy_from_user failed\n");
return -EFAULT;
}
writeGpioReg(bank, &dev->regs->gpxdat,
gpioData.value, gpioData.mask);
break;
default:
return -ENOTTY;
}
return rc;
}
/* File operations structure. Pretty limited on this device */
struct file_operations gpio_fops = {
.owner = THIS_MODULE,
.open = gpio_open,
.ioctl = gpio_ioctl,
};
static void gpio_cleanup(void)
{
int i;
u32 addr;
dev_t devno = MKDEV(gpio_major_num, 0);
if (gpio_devices) {
for (i = 0; i < GPIO_NUM_BANKS; i++) {
cdev_del(&gpio_devices[i].cdev);
}
iounmap(gpio_devices);
}
addr = get_immrbase() + GPIO1_IO_OFFSET;
release_mem_region(addr, sizeof(struct gpio_reg));
addr = get_immrbase() + GPIO2_IO_OFFSET;
release_mem_region(addr, sizeof(struct gpio_reg));
unregister_chrdev_region(devno, GPIO_NUM_BANKS);
}
static void gpio_setup_cdev(struct gpio_dev *dev, int index)
{
int rc, devno = MKDEV(gpio_major_num, index);
cdev_init(&dev->cdev, &gpio_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &gpio_fops;
if ((rc = cdev_add(&dev->cdev, devno, 1)))
printk(KERN_CRIT "Error %d adding gpio%d", rc, index);
}
static int gpio_init(void)
{
int i, rc;
dev_t dev = 0;
u32 addr;
/* Grab a dynamic major number and GPIO_NUM_BANKS minors */
rc = alloc_chrdev_region(&dev, 0, GPIO_NUM_BANKS, "gpio");
gpio_major_num = MAJOR(dev);
if (rc < 0) {
printk(KERN_CRIT "GPIO: couldn't get major number\n");
return rc;
}
if (!(gpio_devices = kmalloc(GPIO_NUM_BANKS * sizeof(struct gpio_dev),
GFP_KERNEL))) {
gpio_cleanup();
return -ENOMEM;
}
for (i = 0; i < GPIO_NUM_BANKS; i++) {
spin_lock_init(&gpioLock[i]);
gpio_setup_cdev(&gpio_devices[i], i);
addr =
get_immrbase() + (i ==
0 ? GPIO1_IO_OFFSET : GPIO2_IO_OFFSET);
if (!request_mem_region(addr,
sizeof(struct gpio_reg), "gpio")) {
printk(KERN_CRIT "gpio: I/O memory request failed\n");
return -ENODEV;
}
gpio_devices[i].regs = (struct gpio_reg *)ioremap_nocache(addr,
sizeof (struct gpio_reg));
if (!gpio_devices[i].regs) {
printk(KERN_CRIT "gpio: can't remap I/O memory\n");
return -ENODEV;
}
}
return 0;
}
module_init(gpio_init);
module_exit(gpio_cleanup);
#ifndef GPIO_INCLUDE_H
#define GPIO_INCLUDE_H
#include <asm/ioctl.h>
#define GPIO1_IO_OFFSET 0x00000c00
#define GPIO2_IO_OFFSET 0x00000d00
typedef struct _gpioDatAccess
{
unsigned int value;
unsigned int mask;
} gpioDataAccess;
#define GPIO_IOC_MAGIC 0xaa
#define GPIO_IOC_GET_DIR _IO(GPIO_IOC_MAGIC, 1)
#define GPIO_IOC_SET_DIR _IOW(GPIO_IOC_MAGIC, 2, gpioDataAccess)
#define GPIO_IOC_GET_DATA _IO(GPIO_IOC_MAGIC, 3)
#define GPIO_IOC_SET_DATA _IOW(GPIO_IOC_MAGIC, 4, gpioDataAccess)
#define GPIO_IOC_MAXNR 5
#define GPIO_NUM_BANKS 2
struct gpio_reg
{
unsigned int gpxdir;
unsigned int gpxdr;
unsigned int gpxdat;
unsigned int gpxier;
unsigned int gpximr;
unsigned int gpxicr;
};
/* On our CPU, bit 0 is the MS bit, so go from the left */
#define GPIO_BIT(x) (0x80000000 >> (x))
#endif /* GPIO_INCLUDE_H */
_______________________________________________
Linuxppc-embedded mailing list
Linuxppc-embedded@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-embedded