⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 at91_fram_spi.c

📁 at91sam9261的linux下铁电驱动程序
💻 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 + -