Hi BJ,
Did you see the code that I wrote at while ago from the DM6446. It was a
complete module with instructions on how to insert it and connect up the
correct device nodes, etc. Now I know your using the DM3555 but I have been
talking to Steve and he said that it should work and I think he got it all
going except for the read function. Anyways I copied and pasted my old
message I sent out originally.
I was in your exact same place 3 months ago. Also this was my very FIRST
linux module I had ever written so it probably shows.
Josh
----------------------------------------
Hey guys,
I promised I would post this for people who are faced with the same problem
as I have, no spi driver support for the davinci.
After some help from people on the email list, I wrote my own character spi
driver. Please bear with me since this is the FIRST linux driver I have ever
written. Its also hard coded to certain SPI clock polarity, phase,
setup/hold times, etc.
There are many possible advances that could be made so that you can
configure it through IOCTL commands, but my work isn't paying me to do that.
At this point I am diverging from this SPI driver and will start adding GPIO
interrupts to this driver so I know when to pull the device connected to the
SPI port.
To use this driver you will have to:
Copy all the code in this email into a text file called dv_spi.c
Copy the simple Makefile into a text file
Define the LINUXKERNEL_INSTALL_DIR path in your environment
Run make with with the Makefile and dv_spi.c
Now that you have the dv_spi.ko module copy it to the davinci
Create a spi device node in the /dev folder using this command "mknod -m 666
/dev/spi c 60 0"
Note if don't want to type step 6 on every boot up of the davinci you need
to either a.) make a udev rule or easier b.) create a startup script in
/etc/rc.d/init.d/ and ln -s link it into the rc3.d folder
Now you need to load the dv_spi.ko kernel module. Use "insmod dv_spi.ko"
To use this you just open up the /dev/spi as a file in C code and read/write
or fread/fwrite to it. Remember that spi is full duplex so when you write
the driver will read data as well and store it internal to the driver and
buffer it until the next read.
You can also echo "blah" > /dev/spi and it works as well.
Ok here is the Make file
----------------- Makefile start ----------------------------------
obj-m += dv_spi.o
MVTOOL_PREFIX=arm_v5t_le-
MAKE_ENV = ARCH=arm CROSS_COMPILE=$(MVTOOL_PREFIX)
.PHONY: clean release default
default: release
release:
make -C $(LINUXKERNEL_INSTALL_DIR) M=`pwd` $(MAKE_ENV) modules
clean:
-rm -rf *.o *mod* *.ko .cmem* .tmp*
---------Makefile end-----------------------------
-------- dv_spi.c start --------------------------
//
--------------------------------------------------------------------------
/*
File: dv_spi.c
Author: Joshua Hintze
E-Mail: [EMAIL PROTECTED]
Description: A very simple implementation for using the SPI
port on the Davinci 6446 platform. This is my first linux driver ever
so comments are appreciated.
Thanks goes to Sean on Davinci Mailing List
Limitations: Currently this is written to only use a single Chip Select
/SPI_ENO
the reason being that the
/SPI_EN1 is multiplexed with the ATA HDDIR lines.
Platform Dependencies: Davinci
Change History:
Date Author Description
*/
//
--------------------------------------------------------------------------
///////////////////////////
// INCLUDES
//////////////////////////
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h> // udelay()
#include <linux/fs.h> // everything...
#include <asm/uaccess.h> // copy_from/to_user
// Definition for SPI Base Address and the local Power or Sleep Controller
LPSoC
#include <asm/arch/hardware.h>
#include <asm/hardware/clock.h>
///////////////////////////
// PROTOTYPES
//////////////////////////
/* Declaration of dv_spi.c functions */
int dv_spi_open(struct inode *inode, struct file *filp);
int dv_spi_release(struct inode *inode, struct file *filp);
ssize_t dv_spi_read(struct file *filp, char *buf, size_t count, loff_t
*f_pos);
ssize_t dv_spi_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos);
static void dv_spi_exit(void);
static int dv_spi_init(void);
///////////////////////////
// DEFINITIONS & GLOBALS
//////////////////////////
// Register definitions to control the SPI
#define SPIGCR0 0x01c66800
#define SPIGCR1 0x01c66804
#define SPIINT 0x01c66808
#define SPILVL 0x01c6680c
#define SPIFLG 0x01C66810
// SPI Flag Status Register
#define SPIPC0 0x01C66814
// SPI Pin Control Register 0
#define SPIPC2 0x01C6681C
// SPI Pin Control Register 2
#define SPIDAT1 0x01C6683C
// SPI Shift Register 1
#define SPIBUF 0x01C66840
// SPI Buffer Register
#define SPIEMU 0x01C66844
// SPI Emulation Register
#define SPIDELAY 0x01C66848
// SPI Delay Register
#define SPIDEF 0x01C6684C
// SPI Default Chip Select Register
#define SPIFMT0 0x01C66850
// SPI Data Format Register 0
#define SPIFMT1 0x01C66854
// SPI Data Format Register 1
#define SPIFMT2 0x01C66858
// SPI Data Format Register 2
#define SPIFMT3 0x01C6685C
// SPI Data Format Register 3
#define INTVEC0 0x01C66860
// SPI Interrupt Vector Register 0
#define INTVEC1 0x01C66864
// SPI Interrupt Vector Register 1
// Definition for GPIO Pin Multiplexing
#define PINMUX1 0x01c40004
// SPI format - Polarity and Phase
// ***NOTE*** It doesn't seem like the SPI Phase for the davinci follows the
standard
// phase as described by the motorola architecture. I.E. phase 0 = sample on
rising edge of clock
// In the davinci it seems this is opposite.
#define SPI_PHASE 1
// Set these values to whatever you need
#define SPI_POLARITY 0
// Macro for accessing a memory location such as a register
#define SPI_REG(reg) (*(int *__iomem) IO_ADDRESS(reg))
// Version numbers
#define MAJOR_VERSION 60
#define MINOR_VERSION 01
// Global pointer to the clock struct. We use this to start up the LPSoC
(local power system on chip)
// so our SPI peripheral has power going to it.
static struct clk *g_clkptr = 0;
// Structure that declares the usual file access functions
static struct file_operations dv_spi_fops = {
read: dv_spi_read,
write: dv_spi_write,
open: dv_spi_open,
release: dv_spi_release
};
// We will use a 1K read buffer to store data
static unsigned char *g_readbuf = 0;
static unsigned int g_readbufcount = 0;
static int dv_spi_init(void)
{
int result;
/* Registering device */
result = register_chrdev(MAJOR_VERSION, "spi",
&dv_spi_fops);
if (result < 0)
{
printk("<1>dv_spi: cannot obtain major
number %d\n", MAJOR_VERSION);
return result;
}
// Allocate space for the read buffer
g_readbuf = kmalloc(1024, GFP_KERNEL);
if (!g_readbuf)
{
result = -ENOMEM;
dv_spi_exit();
return result;
}
printk("<1>Inserting SPI module\n");
return 0;
}
static void dv_spi_exit(void)
{
/* Freeing the major number */
unregister_chrdev(MAJOR_VERSION, "spi");
/* Freeing buffer memory */
if(g_readbuf)
kfree(g_readbuf);
if (g_clkptr)
dv_spi_release(0,0);
printk("<1>Removing SPI module\n");
}
// Called when a userspace program opens the file
int dv_spi_open(struct inode *inode, struct file *filp)
{
unsigned int control;
// Power up the SPI hardware by requesting and enabling the
clock
g_clkptr = clk_get(NULL, "SPICLK");
if(g_clkptr <= 0) printk("<l>Error could not get the
clock\n");
else clk_enable(g_clkptr);
// --------------------------------
// Configure GPIO Pins for SPI
// --------------------------------
// Enable the SPI pins on the GPIO
SPI_REG(PINMUX1) |= 0x100;
// --------------------------------
// Reset SPI
// --------------------------------
control=0x00000000;
SPI_REG(SPIGCR0)=control;
// Place SPI peripheral in reset
mdelay(1);
// Delay for a bit
control=0x00000001;
SPI_REG(SPIGCR0)=control;
// Remove from reset
// --------------------------------
// Enable SPI CLK & Master
// --------------------------------
control=0x00000003;
SPI_REG(SPIGCR1)=control;
// --------------------------------
// Enable pins : DI,DO,CLK,EN0
// --------------------------------
control=0x00000E01;
SPI_REG(SPIPC0)=control;
/* --------------------------------
// Set data format in SPIFMT0 - THIS CAN BE CHANGED BY IOCTL
commands
// SHIFTDIR in bit 20 set to 1 : MSB first
// POLARITY and PHASE in bit 17, 16 set to 0, 0
// PRESCALE in bit 15-8 set to whatever you need, SPI_CLK =
SYSCLK5 / (Prescale + 1)
// CHARLEN in bit 4-0 set to 08 : 8 bit characters
-------------------------------- */
control=0x00000000 | (SPI_POLARITY << 17) | (SPI_PHASE <<
16) | (0x7 << 8) | 0x8;
SPI_REG(SPIFMT0)=control;
// --------------------------------
// Set data format for used -> SPIFMT0
// --------------------------------
control=0x00000000 | (0x00 << 24);
SPI_REG(SPIDAT1)=control;
// --------------------------------
// Set hold time and setup time
// --------------------------------
control=0x00000000 | (0x03 << 16) | (0x06 << 24);
SPI_REG(SPIDELAY)=control;
// --------------------------------
// Set Chip Select Default
// CSHOLD -> 0 -> release SPI_EN0 state after transmission
-> bit 28
// CSNR -> 2 -> Only use SPI_EN0
// --------------------------------
control=SPI_REG(SPIDAT1);
control|= (0x2 << 16);
SPI_REG(SPIDAT1)=control;
// --------------------------------
// Enable for transmitting
// --------------------------------
control=SPI_REG(SPIGCR1);
control=control | 1 << 24; // enable SPIENA
SPI_REG(SPIGCR1)=control;
// Zero out our read buffer
memset(g_readbuf, 0, 1024);
g_readbufcount = 0;
return 0;
}
// Called when a userspace program closes the file
int dv_spi_release(struct inode *inode, struct file *filp)
{
// Place SPI peripheral into reset
SPI_REG(SPIGCR0)=0;
// Remove the SPI output on the GPIO
SPI_REG(PINMUX1) &= ~0x100;
// Disable the clock thus removing power from the peripheral
if(g_clkptr)
clk_disable(g_clkptr);
g_clkptr = 0;
return 0;
}
// Reading from the SPI device
ssize_t dv_spi_read(struct file *filp, char *buf, size_t count, loff_t
*f_pos)
{
// printk("<1>Attempting to read %d bytes and we only have %d
bytes\n",count,g_readbufcount);
if(g_readbufcount == 0) return 0; // No data
// See if there is enough available
if(count > g_readbufcount) count = g_readbufcount;
// Transferring data to user space
copy_to_user(buf,g_readbuf,count);
// Now shift the memory down
memmove(&g_readbuf[0],&g_readbuf[count],g_readbufcount-count);
g_readbufcount -= count;
// Advance the file pointer
*f_pos += count;
return count;
}
// Writing to the SPI device
ssize_t dv_spi_write(struct file *filp, const char *buf, size_t count,
loff_t *f_pos)
{
unsigned char spiData;
size_t i;
unsigned int control;
unsigned int ReadByte;
// Wait until the TX buffer is clear
control = SPI_REG(SPIBUF);
while(control & (1 << 29)) //
Wait until the TX data has been transmitted
control = SPI_REG(SPIBUF);
// Write out data one byte at a time
for(i=0; i < count; i++)
{
ReadByte = 0;
// Send the data
copy_from_user(&spiData,buf+i,1);
control = 0x00000000 | (0x1 << 28) | (0x2 <<
16) | spiData; // Hold the chip select line between multibytes
SPI_REG(SPIDAT1) = control;
if(i == (count -1))
SPI_REG(SPIDAT1) =
0x00000000 | (0x2 << 16) | spiData; // Remove the chip select hold
control = SPI_REG(SPIBUF);
while(control & (1 << 29))
// Wait until the TX data has been transmitted
{
// Check for data received
if(!(control & (1 << 31)))
{
// We have
just read a byte of data, store it.
if(g_readbufcount < 1024)
{
//
printk("<1>Read in byte value = %d!\n",count);
g_readbuf[g_readbufcount] = control & 0xFF;
g_readbufcount++;
ReadByte = 1;
}
}
control = SPI_REG(SPIBUF);
}
// Make sure we have always read in a byte
while(!ReadByte)
{
// Check for data received
if(!(control & (1 << 31)))
{
//
printk("<1>we received a byte with value %d\n",control & 0xFF);
// We have
just read a byte of data, store it.
if(g_readbufcount < 1024)
{
//
printk("<1>Read in byte value = %d\n",control);
g_readbuf[g_readbufcount] = control & 0xFF;
g_readbufcount++;
ReadByte = 1;
}
}
control = SPI_REG(SPIBUF);
}
}
return count;
}
MODULE_LICENSE("Dual BSD/GPL");
module_init(dv_spi_init);
module_exit(dv_spi_exit);
-------- dv_spi.c end --------------------------
-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED]
om] On Behalf Of BJ Opp
Sent: Thursday, March 06, 2008 12:07 PM
Cc: [email protected]
Subject: RE: DM355 SPI
To take Stephen's question a bit further. I'm trying to write a library
that uses the spi driver on the dm355. I was under the assumption that I'd
be able to access it much like the i2c is used, namely that there was a
/dev/spi node that I could open. I'm pretty sure that I have to write my
own driver using the functions available in dm355_spi_master but I'm sort of
at a loss how I can begin to do so. I have a small kernel module written
that I can insert and remove into the kernel at runtime but the details of
how to actually get it to use the spi bus are escaping me.
Has anybody written their own driver/library that uses the dm355 spi bus?
If so, could you point me in the right direction toward gettign mine up and
running. I looked at the code for the at25xxfl_eeprom, but that's more of
an mtd and I would think that my device (a controller for an optrex lcd)
would fit more as a character device since the read/writes don't operate in
block sizes. As you can see I'm a bit confused here and would really
appreciate some help.
Thanks
BJ
Viet Hoang wrote:
> Hi Steve,
> Boot the board, login, then use this command: cat /dev/mtdblock5.
> Put the scope at SCK(pin 6) , SI (pin 5) or SO (pin 2) (That EEPROM is
> U65), you can see the signal.
> Does this help?
> Regards,
> Viet Hoang.
>
> */Stephen Berry <[EMAIL PROTECTED]>/* wrote:
>
>
> Does anyone have any experience in getting the SPI interface
> running on the 355?
>
> It looks to me that the SPI framework as shipped with the 355
> doesn't work. To prove this I put a scope on the SPI eeprom on the
> EVM board - and the part isn't used during boot. I have made an
> assumption that the onboard eeprom was there for things like MAC
> addresses and other important numbers...
>
> My driver does the same thing on my hardware - no hardware
> response when I issue spi transactions (the software returns zeros).
>
> I do have Joshua Hintze's SPI code - but I would rather have my
> driver fit into an existing, working framework (if it exists).
>
> Does anyone have any patches for the original MVL 2.6.10 SPI code
> (1.3beta) - or anything else that may help?
>
> Thanks,
>
> Steve Berry
> ID2
>
> _______________________________________________
> Davinci-linux-open-source mailing list
> [email protected]
> http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
>
>
> Send instant messages to your online friends
> http://uk.messenger.yahoo.com
>
--
Integral Design and Development
312 Great Rd, Littleton MA 01460
voice: 978 501 7658 fax: 603-679-3988
This e-mail and any files transmitted with it are confidential and intended
solely for the use of the individual or entity to which they are addressed.
If you have received this e-mail in error please notify the originator
immediately. The addressee is formally notified hereby that this e-mail and
any attachments are to be treated as confidential.
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source
_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source