📄 at91_fram_spi.c
字号:
/*
* User-space interface to the SPI bus on Atmel AT91SAM9261S
*
* Based on SPI driver by Rick Bronson
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/poll.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <asm/bitops.h>
#include <asm/hardware.h>
#include <linux/ioport.h>
#include <asm/arch/pio.h>
#include <asm/io.h>
#include <asm/arch/gpio.h>
#include <asm/arch/hardware.h>
#include <asm/arch/at91sam9261_spi.h>
#include <asm/arch/pmc.h>
/* ......................................................................... */
/* ......................by solo......................................... */
#define SPI0_REG(val) (AT91C_VA_BASE_SPI0 + val)
/* ......................................................................... */
#define FRAM_MINOR 254
#define MAX_INDEX 0x7FFF
#define WREN 0x06 // Set Write Enable Latch
#define WRDI 0x04 // Write Disable
#define RDSR 0x05 // Read Status Register
#define WRSR 0x01 // Write Status Register
#define RDMD 0x03 // Read Memory Data
#define WRMD 0x02 // Write Memory Data
#define AT91C_SPI0_PCS1 (0xD << 16) // (SPI0) Peripheral Chip Select 1
#define SPI_CSR1 (SPI0_REG(SPI_CSR) + 4)
#define FM25_TD 60ns
#define FM25_TCSU 0
//#define AT91_MASTER_CLOCK 99328000 //99.328MHZ
#define AT91_MASTER_CLOCK 100000000 //100MHZ
#define FM25_CLK 20000000 //20MHZ
void spi_enable(void)
{
writel(AT91C_SPI_SPIEN, SPI0_REG(SPI_CR)); //LASTXFER = 0;
}
void spi_enable_last(void)
{
writel(AT91C_SPI_SPIEN | AT91C_SPI_LASTXFER, SPI0_REG(SPI_CR)); //LASTXFER = 1;
}
void spi_disable(void)
{
writel(AT91C_SPI_SPIDIS, SPI0_REG(SPI_CR));
}
unsigned char spi_transfer(unsigned char value)
{
unsigned char i;
writel(value, SPI0_REG(SPI_TDR));
while(!(readl(SPI0_REG(SPI_SR)) & AT91C_SPI_RDRF));
i = (unsigned char)readl(SPI0_REG(SPI_RDR));
return i;
}
void send_WREN(void)
{
spi_transfer(WREN);
spi_enable_last();
}
void send_WRDI(void)
{
spi_enable();
spi_transfer(WRDI);
spi_enable_last();
spi_disable();
}
void spi_write_status(unsigned char value)
{
send_WREN();
spi_enable();
spi_transfer(WRSR);
spi_transfer(value);
spi_enable_last();
spi_disable();
}
unsigned char spi_read_status(void)
{
unsigned char value;
unsigned char random = 0;
send_WREN();
spi_enable();
spi_transfer(RDSR);
value = spi_transfer(random);
spi_enable_last();
spi_disable();
return value;
}
void spi_write_memory(int num, int addr, unsigned char *buff)
{
int i;
spi_enable();
send_WREN();
spi_enable();
spi_transfer(WRMD);
spi_transfer((0x0ff00 & addr)>>8);
spi_transfer(0x0ff & addr);
for(i = 0; i < num; i++){
spi_transfer(*(buff+i));
}
spi_enable_last();
spi_disable();
}
void spi_read_memory(int num, int addr, unsigned char *buff)
{
int i;
unsigned char random = 0;
spi_enable();
spi_transfer(RDMD);
spi_transfer((0x0ff00 & addr)>>8);
spi_transfer(0x0ff & addr);
for(i = 0; i < num; i++){
*(buff+i) = spi_transfer(random);
}
spi_enable_last();
spi_disable();
}
/***********************************************************/
/*
* fram device is opened.
*/
static int fram_open(struct inode *inode, struct file *file)
{
return 0;
}
/*
* Close fram device.
*/
static int fram_close(struct inode *inode, struct file *file)
{
return 0;
}
loff_t fram_llseek(struct file *file,loff_t off,int whence)
{
loff_t newpos;
switch(whence)
{
case 0://SEEK_SET:
newpos = off;
break;
case 1://SEEK_CUR:
newpos = file->f_pos + off;
break;
case 2://SEEK_END:
newpos = MAX_INDEX + off;
break;
default:
return -EINVAL;
}
if(newpos < 0)
return -EINVAL;
if(newpos > MAX_INDEX)
return -EINVAL;
file->f_pos = newpos;
return newpos;
}
/*
* read fram device
*/
static ssize_t fram_read(struct file *file, char __user *data, size_t len, loff_t *ppos)
{
int index;
char *ddata;
ddata = (char *)kmalloc(len, GFP_KERNEL);
memset(ddata, 0, len);
index = file->f_pos;
spi_read_memory(len, index, ddata);
if (copy_to_user(data, ddata, len))
return -EFAULT;
kfree(ddata);
return len;
}
/*
* write fram device
*/
static ssize_t fram_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
{
int index;
char *idata = (char *)kmalloc(len, GFP_KERNEL);
if (copy_from_user(idata, data, len))
return -EFAULT;
index = file->f_pos;
spi_write_memory(len, index, idata);
kfree(idata);
return len;
}
/*
* Handle commands from user-space
*/
static int fram_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
int ret = 0;
switch (cmd) {
default:
ret = -EINVAL;
break;
}
return ret;
}
static struct file_operations fram_fops =
{
.owner = THIS_MODULE,
.llseek = fram_llseek,
.read = fram_read,
.write = fram_write,
.ioctl = fram_ioctl,
.open = fram_open,
.release = fram_close,
};
static struct miscdevice fram_miscdev =
{
.minor = FRAM_MINOR,
.name = "fram_spi",
.fops = &fram_fops,
};
/*
* AT91F_Spi Init
*/
void AT91F_SpiInit(void)
{
// Clock SPI
writel(1 << AT91C_ID_SPI0, (AT91C_VA_BASE_PMC + PMC_PCER));
// Configure PIO
at91_gpio_periph_enable(AT91C_VA_BASE_PIOA, 0, PERIPH_A, NO_PULL_UP, NO_GLITCH_FLT);
at91_gpio_periph_enable(AT91C_VA_BASE_PIOA, 1, PERIPH_A, NO_PULL_UP, NO_GLITCH_FLT);
at91_gpio_periph_enable(AT91C_VA_BASE_PIOA, 2, PERIPH_A, NO_PULL_UP, NO_GLITCH_FLT);
at91_gpio_periph_enable(AT91C_VA_BASE_PIOA, 4, PERIPH_A, NO_PULL_UP, NO_GLITCH_FLT);
// Reset the SPI, all SPI interrupts are not enabled
writel(AT91C_SPI_SWRST, SPI0_REG(SPI_CR));
// Configure SPI in master and fixed mode with a diffrent CS each time
writel(AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PS_FIXED |AT91C_SPI0_PCS1, SPI0_REG(SPI_MR));
//Configure CSR1 for Fram, SPI_MODE 3;DLYBCT= 0,DLYBS = 0;CSAAT = 1;PS = 0;SPI_BITS=8
writel(AT91C_SPI_CPOL | AT91C_SPI_NCPHA | AT91C_SPI_CSAAT | ((AT91_MASTER_CLOCK/FM25_CLK) << 8), SPI_CSR1);
}
static int __init fram_device_init(void)
{
AT91F_SpiInit();
misc_register(&fram_miscdev);
printk(KERN_INFO "fram devices installed!\n");
return 0;
}
static void __exit fram_device_exit(void)
{
misc_deregister(&fram_miscdev);
}
module_init(fram_device_init);
module_exit(fram_device_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("SOLOO");
MODULE_DESCRIPTION("fram drivers");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -