Actually I've made some progress with both Joshua's code and the
existing 355 spi codebase.

Joshua - I use your code to make quick changes to test out settings that
I need for my final driver, but I will most likely rewrite the eeprom
driver to do what I want. There are some places where you put while
loops that never terminate, and I've been caught with a hung driver a
few times. An example is if you supply an even write count - the driver
spins waiting for an incoming value, but a command was never
initiated.... But it does work, and thats what I need at the moment!

As for the existing distribution - the
linux/drivers/mtd/devices/at25xxA_eeprom.c is a good place to start to
write your own device driver.

    Steve

Joshua Hintze wrote:
> 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
>>
>>     
>
>
>   

_______________________________________________
Davinci-linux-open-source mailing list
[email protected]
http://linux.davincidsp.com/mailman/listinfo/davinci-linux-open-source

Reply via email to