我現在寫了一個 SPI 的 DRIVER, 但是用示波器一看,發現問題。用GPIO做CHIP SELECT 個信號是不受控制。
當SET CHIP SELECT 是 LOW 後,它用了幾十ms才到spi port出SPI(用了4us),再用幾十ms才SET CHIP SELECT HIGH。但是source code 中是什麼沒有(line 208)。
請問大家我少了什麼?
#include <mach/hardware.h> // s3c2410_gpio_****
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/cdev.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/poll.h>
#include <linux/miscdevice.h>
//#include <linux/semaphores.h>
#include <mach/regs-gpio.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME "spi_1"
#define SPI_MAJOR 153
//------------------------------
//------------------------------
#define r_clkcon *(volatile unsigned long*) ioremap(0x4C00000C, 4)
#define SPI_SPCON1 ioremap(0x59000020, 4)
#define SPI_SPSTA1 ioremap(0x59000024, 4)
#define SPI_SPPIN1 ioremap(0x59000028, 4)
#define SPI_SPPRE1 ioremap(0x5900002C, 4)
#define SPI_SPTDAT1 ioremap(0x59000030, 4)
#define SPI_SPRDAT1 ioremap(0x59000034, 4)
//DEFINE_MUTEX( spi_mutex);
//EXPORT_SYMBOL( spi_mutex);
//static struct semaphore lock;
static spinlock_t spi_lock;
char cs;
#define SPI1_EN0 0
#define SPI1_EN1 1
#define SPI1_EN2 2
static int s3c2440_spi_close( struct inode *inode, struct file *filp)
{
__raw_writel( 0x00000000, SPI_SPCON1);
printk( "s3c2440-spi close\n");
return 0;
}
static int s3c2440_spi_open( struct inode *inode, struct file *filp)
{
int value =0;
cs = -1;
printk( "s3c2440-spi open\n");
r_clkcon |= 0x40000; // setup peri clock
value = (int) r_clkcon;
printk( "r_CLKcon = 0x%X\n", value);
printk( "setup all EN signals\n");
//---------------------------------------
// setup EN for XXXX
//---------------------------------------
s3c2410_gpio_cfgpin( S3C2410_GPF5, S3C2410_GPF5_OUTP);
s3c2410_gpio_pullup( S3C2410_GPF5, 1); // 0 = enable
s3c2410_gpio_setpin( S3C2410_GPF5, 1);
//---------------------------------------
// setup EN for XXXX, XXXX
//---------------------------------------
s3c2410_gpio_cfgpin( S3C2410_GPG0, S3C2410_GPG0_OUTP);
s3c2410_gpio_pullup( S3C2410_GPG0, 0); // 0 = enable
s3c2410_gpio_setpin( S3C2410_GPG0, 1);
s3c2410_gpio_cfgpin( S3C2410_GPG3, S3C2410_GPG3_OUTP);
s3c2410_gpio_pullup( S3C2410_GPG3, 0); // 0 = enable
s3c2410_gpio_setpin( S3C2410_GPG3, 1);
//---------------------------------------
// setup SPI1
//---------------------------------------
printk( "setup SPI1 port\n");
s3c2410_gpio_cfgpin( S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
s3c2410_gpio_cfgpin( S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
s3c2410_gpio_cfgpin( S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
s3c2410_gpio_pullup( S3C2410_GPG5, 1); // 0 = enable
s3c2410_gpio_pullup( S3C2410_GPG6, 1); // 0 = enable
s3c2410_gpio_pullup( S3C2410_GPG7, 1); // 0 = enable
s3c2410_gpio_setpin( S3C2410_GPG5, 1);
s3c2410_gpio_setpin( S3C2410_GPG6, 1);
s3c2410_gpio_setpin( S3C2410_GPG7, 1);
__raw_writel( 0x00000000, SPI_SPPIN1);
__raw_writel( 0x00000007, SPI_SPPRE1); // SPI baudrate prescaler, Baudrate = PCLK/2/(Prescaler value +1)
__raw_writel( 0x00000018, SPI_SPCON1); // enable SPI0
printk( "Open SPI completed\n");
return 0;
}
static ssize_t s3c2440_spi_ioctl( struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
switch( cmd)
{
case SPI1_EN0:
cs = 0;
break;
case SPI1_EN1:
cs = 1;
break;
case SPI1_EN2:
cs = 2;
break;
default:
cs = -1;
break;
}
printk( "SPI1 IO_Ctl (%d)\n", cs);
return 0;
}
static ssize_t s3c2440_spi_read( struct file *filp, char __user *buf, size_t count,
loff_t *f_ops)
{
unsigned char *dataRx;
int x = 0;
if( cs == -1)
return -EFAULT;
if( count > 1024)
count = 1024;
dataRx = kmalloc( count, GFP_KERNEL);
if( dataRx == NULL)
return -ENOMEM;
if( copy_to_user( buf, dataRx, count))
{
kfree( dataRx);
return -EFAULT;
}
printk( "SPI1 read data\n");
kfree( dataRx);
return x;
}
static ssize_t s3c2440_spi_write( struct file *filp, const char __user *buf, size_t count, loff_t *f_ops)
{
unsigned char *dataTx;
int x = 0, y = 0;
// unsigned long flags;
if( cs == -1)
return -EFAULT;
if( count > 1024)
count = 1024;
dataTx = kmalloc( count, GFP_KERNEL);
if( dataTx == NULL)
return -ENOMEM;
if( copy_from_user( dataTx, buf, count))
{
kfree( dataTx);
return -EFAULT;
}
// local_irq_save( flags);
// mutex_lock( &spi_mutex);
//while(( spi_spsta1 & 0x01) != 0x01);
spin_lock_irq( &spi_lock);
for( x = 0; x < count; x++)
{
switch( cs)
{
case SPI1_EN0:
s3c2410_gpio_setpin( S3C2410_GPF5, 0);
break;
case SPI1_EN1:
s3c2410_gpio_setpin( S3C2410_GPG0, 0);
break;
case SPI1_EN2:
s3c2410_gpio_setpin( S3C2410_GPG3, 0);
break;
}
__raw_writel( dataTx[x], SPI_SPTDAT1); <﹣﹣﹣﹣﹣﹣ ???
switch( cs)
{
case SPI1_EN0:
s3c2410_gpio_setpin( S3C2410_GPF5, 1);
break;
case SPI1_EN1:
s3c2410_gpio_setpin( S3C2410_GPG0, 1);
break;
case SPI1_EN2:
s3c2410_gpio_setpin( S3C2410_GPG3, 1);
break;
}
}
// mutex_unlock( &spi_mutex);
// local_irq_restore( flags);
spin_unlock_irq( &spi_lock);
kfree( dataTx);
return x;
}
static struct file_operations s3c2410_spi_fops = {
.owner = THIS_MODULE,
.open = s3c2440_spi_open,
.write = s3c2440_spi_write,
.read = s3c2440_spi_read,
.ioctl = s3c2440_spi_ioctl,
.release = s3c2440_spi_close,
};
static struct miscdevice misc = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &s3c2410_spi_fops,
};
static int __init dev_init( void)
{
int ret;
// init_MUTEX( &lock);
spin_lock_init( &spi_lock);
ret = misc_register( &misc);
printk( DEVICE_NAME " initialized\n");
return 0;
}
static void __exit dev_exit( void)
{
misc_deregister( &misc);
printk( "Good-byte, SPI removed\n");
}
module_init( dev_init);
module_exit( dev_exit);
MODULE_LICENSE( "GPL");
MODULE_AUTHOR( "GPL");
App:
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#define SPI1_EN0 0
int main(void)
{
int fd;
int x;
int y;
unsigned char data[11];
// pthread_mutex_t lock;
// spinlock_t spi_lock;
// pthread_mutex_init( &lock, 0);
// spin_lock_init( &spi_lock);
fd = open( "/dev/spi_1", O_RDWR | O_NOCTTY);
if( fd < 0)
{
return -1;
}
else
{
ioctl( fd, SPI1_EN0, 0);
for( x = 0; x < 10; x++)
data[x] = x;
// spin_lock_irq( &spi_lock);
// pthread_mutex_lock( &lock);
write( fd, &data, 10);
// spin_unlock_irq( &spi_lock);
// pthread_mutex_unlock( &lock);
}
}