linux-spi.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* At91sam9260 slave mode operation
@ 2008-10-31  2:30 Ajay Joshi
  0 siblings, 0 replies; only message in thread
From: Ajay Joshi @ 2008-10-31  2:30 UTC (permalink / raw)
  To: spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f
  Cc: Mohammad Arif, Raymond Picard


[-- Attachment #1.1: Type: text/plain, Size: 801 bytes --]

 

Hello,

   

      I am using the ATMEL AT91SAM9260 controller.

 

      I am able to use the SPI controller in this as a Master.

      But I have the need to make it work as a slave controller.

      

     I am using the generic SPI device drivers (not the SPI subsystem)
at91_spi.c and at91_spidev.c.

     In this I disabled the DMA mode of transfer(as a first step). I
tried to receive one byte at a time.

     I have enabled the interrupt for RDRF. The interrupt does not arise
unless the clock is enabled(which should not be since the data is
sampled when SPCK is driven). 

     Hence there is no data.

 

     Has anyone made Atmel SPI slave controller work? 

     

     I have also attached the code for reference.

 

Regards

Ajay

 


[-- Attachment #1.2: Type: text/html, Size: 4519 bytes --]

[-- Attachment #2: at91_spi_slave.c --]
[-- Type: application/octet-stream, Size: 9857 bytes --]

#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/interrupt.h>
#include <linux/clk.h>
#include <linux/delay.h>

#include <linux/platform_device.h>
#include <asm/io.h>
#include <asm/semaphore.h>

#include <asm/arch/at91_spi.h>
#include <asm/arch/at91_pdc.h>
#include <asm/arch/board.h>
#include <asm/arch/spi.h>

#define DEBUG_SPI

static struct spi_local spi_dev[NR_SPI_DEVICES];	/* state of the SPI devices */
static int spi_enabled = 0;
static struct semaphore spi_lock;			/* protect access to SPI bus */
static int current_device = -1;				/* currently selected SPI device */
static struct clk *spi_clk;				/* SPI clock */
static void __iomem *spi_base;				/* SPI peripheral base-address */

DECLARE_COMPLETION(transfer_complete);


#define at91_spi_read(reg)		__raw_readl(spi_base + (reg))
#define at91_spi_write(reg, val)	__raw_writel((val), spi_base + (reg))


/* ......................................................................... */

/*
 * Access and enable the SPI bus.
 * This MUST be called before any transfers are performed.
 */
void spi_access_bus(short device)
{
	/* Ensure that requested device is valid */
	if ((device < 0) || (device >= NR_SPI_DEVICES))
		panic("at91_spi: spi_access_bus called with invalid device");

	if (spi_enabled == 0) {
		#if 0
		clk_enable(spi_clk);				/* Enable Peripheral clock */
		#endif
		//at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN);	/* Enable SPI */
#ifdef DEBUG_SPI
		printk("SPI on\n");
#endif
	}
	spi_enabled++;

	/* Lock the SPI bus */
	down(&spi_lock);
	current_device = device;

	/* Configure SPI bus for device */
	//at91_spi_write(AT91_SPI_MR, AT91_SPI_MODFDIS | (spi_dev[device].pcs << 16));
}

/*
 * Relinquish control of the SPI bus.
 */
void spi_release_bus(short device)
{
	if (device != current_device)
		panic("at91_spi: spi_release called with invalid device");

	/* Release the SPI bus */
	current_device = -1;
	up(&spi_lock);

	spi_enabled--;
	if (spi_enabled == 0) {
		//at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS);	/* Disable SPI */
		#if 0
		clk_disable(spi_clk);				/* Disable Peripheral clock */
		#endif
#ifdef DEBUG_SPI
		printk("SPI off\n");
#endif
	}
}

/*
 * Perform a data transfer over the SPI bus
 */
int spi_transfer(struct spi_transfer_list* list)
{
	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
	int tx_size;
	#if 0
	if (!list)
		panic("at91_spi: spi_transfer called with NULL transfer list");
	if (current_device == -1)
		panic("at91_spi: spi_transfer called without acquiring bus");

#ifdef DEBUG_SPI
	printk("SPI transfer start [%i]\n", list->nr_transfers);
#endif

	/* If we are in 16-bit mode, we need to modify what we pass to the PDC */
	tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1;

	/* Store transfer list */
	device->xfers = list;
	list->curr = 0;

	/* Assume there must be at least one transfer */
	device->tx = dma_map_single(NULL, list->tx[0], list->txlen[0], DMA_TO_DEVICE);
	device->rx = dma_map_single(NULL, list->rx[0], list->rxlen[0], DMA_FROM_DEVICE);

	/* Program PDC registers */
	at91_spi_write(AT91_PDC_TPR, device->tx);
	at91_spi_write(AT91_PDC_RPR, device->rx);
	at91_spi_write(AT91_PDC_TCR, list->txlen[0] / tx_size);
	at91_spi_write(AT91_PDC_RCR, list->rxlen[0] / tx_size);

	/* Is there a second transfer? */
	if (list->nr_transfers > 1) {
		device->txnext = dma_map_single(NULL, list->tx[1], list->txlen[1], DMA_TO_DEVICE);
		device->rxnext = dma_map_single(NULL, list->rx[1], list->rxlen[1], DMA_FROM_DEVICE);

		/* Program Next PDC registers */
		at91_spi_write(AT91_PDC_TNPR, device->txnext);
		at91_spi_write(AT91_PDC_RNPR, device->rxnext);
		at91_spi_write(AT91_PDC_TNCR, list->txlen[1] / tx_size);
		at91_spi_write(AT91_PDC_RNCR, list->rxlen[1] / tx_size);
	}
	else {
		device->txnext = 0;
		device->rxnext = 0;
		at91_spi_write(AT91_PDC_TNCR, 0);
		at91_spi_write(AT91_PDC_RNCR, 0);
	}

	// TODO: If we are doing consecutive transfers (at high speed, or
	//   small buffers), then it might be worth modifying the 'Delay between
	//   Consecutive Transfers' in the CSR registers.
	//   This is an issue if we cannot chain the next buffer fast enough
	//   in the interrupt handler.

	/* Enable transmitter and receiver */
	at91_spi_write(AT91_PDC_PTCR, AT91_PDC_RXTEN | AT91_PDC_TXTEN);
	#endif 
	at91_spi_write(AT91_SPI_IER,  AT91_SPI_RDRF);		/* enable buffer complete interrupt */
	wait_for_completion(&transfer_complete);

#ifdef DEBUG_SPI
	printk("SPI transfer end\n");
#endif

	return 0;
}

/* ......................................................................... */

/*
 * Handle interrupts from the SPI controller.
 */
static irqreturn_t at91spi_interrupt(int irq, void *dev_id)
{
	unsigned int status;
	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
	struct spi_transfer_list *list = device->xfers;
	printk("SPI read data %x\n",at91_spi_read(AT91_SPI_RDR));

#ifdef DEBUG_SPI
	printk("SPI interrupt status %x\n", at91_spi_read(AT91_SPI_SR) & at91_spi_read(AT91_SPI_IMR));
#endif
	at91_spi_write(AT91_SPI_IDR, AT91_SPI_RDRF);		/* disable interrupt */
	/* Disable transmitter and receiver */
	//at91_spi_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
	//device->xfers = NULL;
	printk("Disabling transmitter and receiver \n");
	complete(&transfer_complete);
	return IRQ_HANDLED;

	#if 1
	//if (!list)
		//panic("at91_spi: spi_interrupt with a NULL transfer list");

	status = at91_spi_read(AT91_SPI_SR) & at91_spi_read(AT91_SPI_IMR);	/* read status */

	dma_unmap_single(NULL, device->tx, list->txlen[list->curr], DMA_TO_DEVICE);
	dma_unmap_single(NULL, device->rx, list->rxlen[list->curr], DMA_FROM_DEVICE);

	device->tx = device->txnext;	/* move next transfer to current transfer */
	device->rx = device->rxnext;

	list->curr = list->curr + 1;
	if (list->curr == list->nr_transfers) {		/* all transfers complete */
		at91_spi_write(AT91_SPI_IDR, AT91_SPI_RDRF | AT91_SPI_ENDRX);		/* disable interrupt */
		printk("Transfer Complete \n");

		/* Disable transmitter and receiver */
		at91_spi_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);

		device->xfers = NULL;
		complete(&transfer_complete);
	}
	else if (list->curr+1 == list->nr_transfers) {	/* no more next transfers */
		device->txnext = 0;
		device->rxnext = 0;
		at91_spi_write(AT91_PDC_TNCR, 0);
		at91_spi_write(AT91_PDC_RNCR, 0);
	}
	else {
		int i = (list->curr)+1;

		/* If we are in 16-bit mode, we need to modify what we pass to the PDC */
		int tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1;

		device->txnext = dma_map_single(NULL, list->tx[i], list->txlen[i], DMA_TO_DEVICE);
		device->rxnext = dma_map_single(NULL, list->rx[i], list->rxlen[i], DMA_FROM_DEVICE);
		at91_spi_write(AT91_PDC_TNPR, device->txnext);
		at91_spi_write(AT91_PDC_RNPR, device->rxnext);
		at91_spi_write(AT91_PDC_TNCR, list->txlen[i] / tx_size);
		at91_spi_write(AT91_PDC_RNCR, list->rxlen[i] / tx_size);
	}
	#endif
	return IRQ_HANDLED;
}

/* ......................................................................... */

/*
 * Initialize the SPI controller
 */
static int __init at91spi_probe(struct platform_device *pdev)
{
	int i;
	unsigned long scbr;
	struct resource *res;

	init_MUTEX(&spi_lock);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res)
		return -ENXIO;
		
	if (!request_mem_region(res->start, res->end - res->start + 1, "atmel_spi"))
		return -EBUSY;

	spi_base = ioremap(res->start, res->end - res->start + 1);
	if (!spi_base) {
		release_mem_region(res->start, res->end - res->start + 1);
		return -ENOMEM;
	}
	
	printk(KERN_INFO"\n\n\n\n****************************\n\n\n\n");
	#if 1
	spi_clk = clk_get(NULL, "spi0_clk");
	if (IS_ERR(spi_clk)) {
		printk(KERN_ERR "at91_spi: no clock defined\n");
		iounmap(spi_base);
		release_mem_region(res->start, res->end - res->start + 1);
		return -ENODEV;
	}
	#endif
	at91_spi_write(AT91_SPI_CR, AT91_SPI_SWRST);	/* software reset of SPI controller */
	#if 0
	/*
	 * Calculate the correct SPI baud-rate divisor.
	 */
	scbr = clk_get_rate(spi_clk) / (2 * DEFAULT_SPI_CLK);
	scbr = scbr + 1;		/* round up */

	printk(KERN_INFO "at91_spi: Baud rate set to %ld\n", clk_get_rate(spi_clk) / (2 * scbr));
	
	/* Set Chip Select registers to good defaults */
	for (i = 0; i < 4; i++) {
		at91_spi_write(AT91_SPI_CSR(i), AT91_SPI_BITS_8 | (scbr << 8));
	}
	#endif
	at91_spi_write(AT91_SPI_CSR(0), AT91_SPI_CPOL | AT91_SPI_BITS_8 | (16 << 16));

	at91_spi_write(AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);

	memset(&spi_dev, 0, sizeof(spi_dev));
	spi_dev[0].pcs = 0xE;
	spi_dev[1].pcs = 0xD;
	spi_dev[2].pcs = 0xB;
	spi_dev[3].pcs = 0x7;

	if (request_irq(AT91SAM9260_ID_SPI0, at91spi_interrupt, 0, "spi", NULL)) {
		#if 0
		clk_put(spi_clk);
		#endif
		iounmap(spi_base);
		release_mem_region(res->start, res->end - res->start + 1);
		return -EBUSY;
	}

	at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN);		/* Enable SPI */
	at91_spi_write(AT91_SPI_MR, AT91_SPI_MODFDIS | (spi_dev[0].pcs << 16));

	return 0;
}

static int __devexit at91spi_remove(struct platform_device *pdev)
{
	struct resource *res;

	at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS);		/* Disable SPI */
	#if 0
	clk_put(spi_clk);
	#endif
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	iounmap(spi_base);
	release_mem_region(res->start, res->end - res->start + 1);

	free_irq(AT91SAM9260_ID_SPI0, 0);
	return 0;
}

static struct platform_driver at91spi_driver = {
	.probe		= at91spi_probe,
	.remove		= __devexit_p(at91spi_remove),
	.driver		= {
		.name	= "atmel_spi",
		.owner	= THIS_MODULE,
	},
};

static int __init at91spi_init(void)
{
	return platform_driver_register(&at91spi_driver);
}

static void __exit at91spi_exit(void)
{
	platform_driver_unregister(&at91spi_driver);
}


[-- Attachment #3: at91_spi_slave_dev.c --]
[-- Type: application/octet-stream, Size: 6278 bytes --]

#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <asm/arch/spi.h>
#ifdef CONFIG_DEVFS_FS
#include <linux/devfs_fs_kernel.h>
#endif

#define DEBUG_SPIDEV

#define SPI_SLAVE_MAJOR		154	/* registered device number */


#define MOZART_SLAVE_IOC_MAGIC  		0xD0	// To Be Defined
#define MOZART_GET_FLOW_CONTROL			_IOW(MOZART_SLAVE_IOC_MAGIC, 0,long)
#define MOZART_SEND_READ_SLAVE_RDY		_IOW(MOZART_SLAVE_IOC_MAGIC, 5,long)
#define MOZART_SEND_WRITE_SLAVE_RDY		_IOW(MOZART_SLAVE_IOC_MAGIC, 6,long)

/* ......................................................................... */

/*
 * Read or Write to SPI bus.
 */
static ssize_t spislavedev_rd_wr(struct file *file, char *buf, size_t count, loff_t *offset)
{
	unsigned int spi_device = (unsigned int) file->private_data;

	struct mm_struct * mm;
	struct page ** maplist;
	struct spi_transfer_list* list;
	int    pgcount;

	unsigned int ofs, pagelen;
	int res, i, err;
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 

	if (!count) {
		return 0;
	}
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	
	list = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
	if (!list) {
		return -ENOMEM;
	}
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 

	mm = current->mm;

	pgcount = ((unsigned long)buf+count+PAGE_SIZE-1)/PAGE_SIZE - (unsigned long)buf/PAGE_SIZE;

	if (pgcount >= MAX_SPI_TRANSFERS) {
		kfree(list);
		return -EFBIG;
	}
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 

	maplist = kmalloc (pgcount * sizeof (struct page *), GFP_KERNEL);

	if (!maplist) {
		kfree(list);
		return -ENOMEM;
	}
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	flush_cache_all();
	down_read(&mm->mmap_sem);
	err= get_user_pages(current, mm, (unsigned long)buf, pgcount, 1, 0, maplist, NULL);
	up_read(&mm->mmap_sem);

	if (err < 0) {
		kfree(list);
		kfree(maplist);
		return err;
	}
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	pgcount = err;

#ifdef DEBUG_SPIDEV
	printk("spislavedev_rd_rw: %i %i\n", count, pgcount);
#endif
	/* Set default return value = transfer length */
	res = count;

	/*
	 * At this point, the virtual area buf[0] .. buf[count-1] will have
	 * corresponding pages mapped in the physical memory and locked until
	 * we unmap the kiobuf.  The pages cannot be swapped out or moved
	 * around.
	 */
	ofs = (unsigned long) buf & (PAGE_SIZE -1);
	pagelen = PAGE_SIZE - ofs;
	if (count < pagelen)
		pagelen = count;
	printk("Offset to read %d\n",ofs);
	for (i = 0; i < pgcount; i++) {
		flush_dcache_page(maplist[i]);
		printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 

		list->tx[i] = list->rx[i] = page_address(maplist[i]) + ofs;
		list->txlen[i] = list->rxlen[i] = pagelen;

#ifdef DEBUG_SPIDEV
		printk("  %i: %x  (%i)\n", i, list->tx[i], list->txlen[i]);
#endif

		ofs = 0;	/* all subsequent transfers start at beginning of a page */
		count = count - pagelen;
		pagelen = (count < PAGE_SIZE) ? count : PAGE_SIZE;
	}
	list->nr_transfers = pgcount;

	/* Perform transfer on SPI bus */
	//printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	//spi_access_bus(spi_device);
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	spi_transfer(list);
	//spi_release_bus(spi_device);
	//printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 

	while (pgcount--) {
		page_cache_release (maplist[pgcount]);
	}
	flush_cache_all();

	kfree(maplist);
	kfree(list);

	return res;
}

static int spislavedev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	int spi_device = MINOR(inode->i_rdev);

	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	if (spi_device >= NR_SPI_DEVICES)
		return -ENODEV;

	// TODO: This interface can be used to configure the SPI bus.
	
	switch(cmd) {
		case MOZART_GET_FLOW_CONTROL:
			// TODO
			break ;
		
		case MOZART_SEND_READ_SLAVE_RDY:
			// TODO
			break ;
		
		case MOZART_SEND_WRITE_SLAVE_RDY:
			// TODO
			break;
		
		default:
			return -ENOIOCTLCMD;
	}
	return 0;
}

/*
 * Open the SPI device
 */
static int spislavedev_open(struct inode *inode, struct file *file)
{
	unsigned int spi_device = MINOR(inode->i_rdev);

	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	printk("spi_device %d - NR_SPI_DEVICES %d\n",spi_device,NR_SPI_DEVICES); 
	if (spi_device >= NR_SPI_DEVICES)
	{
		return -ENODEV;
	}
	/*
	 * 'private_data' is actually a pointer, but we overload it with the
	 * value we want to store.
	 */
	file->private_data = (void *)spi_device;
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	return 0;
}

/*
 * Close the SPI device
 */
static int spislavedev_close(struct inode *inode, struct file *file)
{
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
	return 0;
}

/* ......................................................................... */

static struct file_operations spislavedev_fops = {
	.owner		= THIS_MODULE,
	.llseek		= no_llseek,
	.read		= spislavedev_rd_wr,
	.write		= (int (*) (struct file *file, const char *buf, size_t count, loff_t *offset))spislavedev_rd_wr,
	.ioctl		= spislavedev_ioctl,
	.open		= spislavedev_open,
	.release	= spislavedev_close,
};

/*
 * Install the SPI /dev interface driver
 */
static int __init at91_spislavedev_init(void)
{
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
#ifdef CONFIG_DEVFS_FS
	int i;
#endif

	if (register_chrdev(SPI_SLAVE_MAJOR, "spi_slave", &spislavedev_fops)) {
		printk(KERN_ERR "at91_spislavedev: Unable to get major %d for SPI bus\n", SPI_SLAVE_MAJOR);
		return -EIO;
	}
	else
	{
		printk("Registered at91_spislavedev Major: %d\n",SPI_SLAVE_MAJOR);
	}

	printk(KERN_INFO "AT91 SPI driver loaded\n");

	return 0;
}

/*
 * Remove the SPI /dev interface driver
 */
static void __exit at91_spislavedev_exit(void)
{
	printk("\nIn %s : %s : %d\n",__FILE__,__FUNCTION__,__LINE__); 
#ifdef CONFIG_DEVFS_FS
	int i;
	for (i = 0; i < NR_SPI_DEVICES; i++) {
		devfs_remove("spi/%d", i);
	}

	devfs_remove("spi");
#endif

	if (unregister_chrdev(SPI_SLAVE_MAJOR, "spi")) {
		printk(KERN_ERR "at91_spislavedev: Unable to release major %d for SPI bus\n", SPI_SLAVE_MAJOR);
		return;
	}
}

[-- Attachment #4: at91sam9260_devices.c --]
[-- Type: application/octet-stream, Size: 25424 bytes --]

#include <asm/mach/arch.h>
#include <asm/mach/map.h>

#include <linux/platform_device.h>
#include <linux/delay.h>
#include <asm/arch/board.h>
#include <asm/arch/gpio.h>
#include <asm/arch/at91sam9260.h>
#include <asm/arch/at91sam9260_matrix.h>
#include <asm/arch/at91sam926x_mc.h>
#include <asm/arch/at91_pmc.h>
#include "generic.h"

#define SZ_512	0x00000200
#define SZ_256	0x00000100
#define SZ_16	0x00000010

/* --------------------------------------------------------------------
 *  USB Host
 * -------------------------------------------------------------------- */

#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
static u64 ohci_dmamask = 0xffffffffUL;
static struct at91_usbh_data usbh_data;

static struct resource usbh_resources[] = {
	[0] = {
		.start	= AT91SAM9260_UHP_BASE,
		.end	= AT91SAM9260_UHP_BASE + SZ_1M - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_UHP,
		.end	= AT91SAM9260_ID_UHP,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91_usbh_device = {
	.name		= "at91_ohci",
	.id		= -1,
	.dev		= {
				.dma_mask		= &ohci_dmamask,
				.coherent_dma_mask	= 0xffffffff,
				.platform_data		= &usbh_data,
	},
	.resource	= usbh_resources,
	.num_resources	= ARRAY_SIZE(usbh_resources),
};

void __init at91_add_device_usbh(struct at91_usbh_data *data)
{
	if (!data)
		return;

	usbh_data = *data;
	platform_device_register(&at91_usbh_device);
}
#else
void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
#endif


/* --------------------------------------------------------------------
 *  USB Device (Gadget)
 * -------------------------------------------------------------------- */

#ifdef CONFIG_USB_GADGET_AT91
static struct at91_udc_data udc_data;

static struct resource udc_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_UDP,
		.end	= AT91SAM9260_BASE_UDP + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_UDP,
		.end	= AT91SAM9260_ID_UDP,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91_udc_device = {
	.name		= "at91_udc",
	.id		= -1,
	.dev		= {
				.platform_data		= &udc_data,
	},
	.resource	= udc_resources,
	.num_resources	= ARRAY_SIZE(udc_resources),
};

void __init at91_add_device_udc(struct at91_udc_data *data)
{
	if (!data)
		return;

	if (data->vbus_pin) {
		at91_set_gpio_input(data->vbus_pin, 0);
		at91_set_deglitch(data->vbus_pin, 1);
	}

	/* Pullup pin is handled internally by USB device peripheral */

	udc_data = *data;
	platform_device_register(&at91_udc_device);
}
#else
void __init at91_add_device_udc(struct at91_udc_data *data) {}
#endif


/* --------------------------------------------------------------------
 *  Ethernet
 * -------------------------------------------------------------------- */

#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
static u64 eth_dmamask = 0xffffffffUL;
static struct eth_platform_data eth_data;

static struct resource eth_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_EMAC,
		.end	= AT91SAM9260_BASE_EMAC + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_EMAC,
		.end	= AT91SAM9260_ID_EMAC,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_eth_device = {
	.name		= "macb",
	.id		= -1,
	.dev		= {
				.dma_mask		= &eth_dmamask,
				.coherent_dma_mask	= 0xffffffff,
				.platform_data		= &eth_data,
	},
	.resource	= eth_resources,
	.num_resources	= ARRAY_SIZE(eth_resources),
};

void __init at91_add_device_eth(struct eth_platform_data *data)
{
	if (!data)
		return;

	if (data->phy_irq_pin) {
		at91_set_gpio_input(data->phy_irq_pin, 0);
		at91_set_deglitch(data->phy_irq_pin, 1);
	}

	/* Pins used for MII and RMII */
	at91_set_A_periph(AT91_PIN_PA19, 0);	/* ETXCK_EREFCK */
	at91_set_A_periph(AT91_PIN_PA17, 0);	/* ERXDV */
	at91_set_A_periph(AT91_PIN_PA14, 0);	/* ERX0 */
	at91_set_A_periph(AT91_PIN_PA15, 0);	/* ERX1 */
	at91_set_A_periph(AT91_PIN_PA18, 0);	/* ERXER */
	at91_set_A_periph(AT91_PIN_PA16, 0);	/* ETXEN */
	at91_set_A_periph(AT91_PIN_PA12, 0);	/* ETX0 */
	at91_set_A_periph(AT91_PIN_PA13, 0);	/* ETX1 */
	at91_set_A_periph(AT91_PIN_PA21, 0);	/* EMDIO */
	at91_set_A_periph(AT91_PIN_PA20, 0);	/* EMDC */

	if (!data->is_rmii) {
		at91_set_B_periph(AT91_PIN_PA28, 0);	/* ECRS */
		at91_set_B_periph(AT91_PIN_PA29, 0);	/* ECOL */
		at91_set_B_periph(AT91_PIN_PA25, 0);	/* ERX2 */
		at91_set_B_periph(AT91_PIN_PA26, 0);	/* ERX3 */
		at91_set_B_periph(AT91_PIN_PA27, 0);	/* ERXCK */
		at91_set_B_periph(AT91_PIN_PA23, 0);	/* ETX2 */
		at91_set_B_periph(AT91_PIN_PA24, 0);	/* ETX3 */
		at91_set_B_periph(AT91_PIN_PA22, 0);	/* ETXER */
	}

	eth_data = *data;
	platform_device_register(&at91sam9260_eth_device);
}
#else
void __init at91_add_device_eth(struct eth_platform_data *data) {}
#endif


/* --------------------------------------------------------------------
 *  MMC / SD
 * -------------------------------------------------------------------- */

#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
static u64 mmc_dmamask = 0xffffffffUL;
static struct at91_mmc_data mmc_data;

static struct resource mmc_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_MCI,
		.end	= AT91SAM9260_BASE_MCI + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_MCI,
		.end	= AT91SAM9260_ID_MCI,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_mmc_device = {
	.name		= "at91_mci",
	.id		= -1,
	.dev		= {
				.dma_mask		= &mmc_dmamask,
				.coherent_dma_mask	= 0xffffffff,
				.platform_data		= &mmc_data,
	},
	.resource	= mmc_resources,
	.num_resources	= ARRAY_SIZE(mmc_resources),
};

#define AT91_SDMMC_USE_EXTERNAL_PULLUP

void __init at91_add_device_mmc(struct at91_mmc_data *data)
{
#ifdef AT91_SDMMC_USE_EXTERNAL_PULLUP
	int pullup = 0;
#else
	int pullup = 1;
#endif	
	if (!data)
		return;

	/* input/irq */
	if (data->det_pin) {
//		at91_set_gpio_input(data->det_pin, 1);
		at91_set_gpio_input(data->det_pin, pullup);	// SCR
		at91_set_deglitch(data->det_pin, 1);
	}
	if (data->wp_pin) {
//		at91_set_gpio_input(data->wp_pin, 1);
		at91_set_gpio_input(data->wp_pin, pullup);	// SCR
	}
	if (data->vcc_pin)
		at91_set_gpio_output(data->vcc_pin, 0);

	/* CLK */
	at91_set_A_periph(AT91_PIN_PA8, 0);
	
	if (data->slot_b) {
		/* CMD */
		at91_set_B_periph(AT91_PIN_PA1, pullup);	// SCR

		/* DAT0, maybe DAT1..DAT3 */
		at91_set_B_periph(AT91_PIN_PA0, pullup);	// SCR
		if (data->wire4) {
			at91_set_B_periph(AT91_PIN_PA5, pullup);	// SCR
			at91_set_B_periph(AT91_PIN_PA4, pullup);	// SCR
			at91_set_B_periph(AT91_PIN_PA3, pullup);	// SCR
		}
	} else {
		/* CMD */
		at91_set_A_periph(AT91_PIN_PA7, 1);

		/* DAT0, maybe DAT1..DAT3 */
		at91_set_A_periph(AT91_PIN_PA6, 1);
		if (data->wire4) {
			at91_set_A_periph(AT91_PIN_PA9, 1);
			at91_set_A_periph(AT91_PIN_PA10, 1);
			at91_set_A_periph(AT91_PIN_PA11, 1);
		}
	}
	
	mmc_data = *data;
	platform_device_register(&at91sam9260_mmc_device);
}
#else
void __init at91_add_device_mmc(struct at91_mmc_data *data) {}
#endif


/* --------------------------------------------------------------------
 *  NAND / SmartMedia
 * -------------------------------------------------------------------- */

#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
static struct at91_nand_data nand_data;

#define NAND_BASE	AT91_CHIPSELECT_3

static struct resource nand_resources[] = {

	[0] = {
			.start	= NAND_BASE,
	#ifndef MOZART_BOARD
			.end	= NAND_BASE + SZ_8M - 1,
	#else
			.end	= NAND_BASE + SZ_16M - 1,
	#endif
			.flags	= IORESOURCE_MEM,
		},
	[1] = {
			.start	= AT91_BASE_SYS + AT91_ECC,
			.end	= AT91_BASE_SYS + AT91_ECC + SZ_512 - 1,
			.flags	= IORESOURCE_MEM,
		 }
};

static struct platform_device at91sam9260_nand_device = {
	.name		= "at91_nand",
	.id		= -1,
	.dev		= {
				.platform_data	= &nand_data,
	},
	.resource	= nand_resources,
	.num_resources	= ARRAY_SIZE(nand_resources),
};

void __init at91_add_device_nand(struct at91_nand_data *data)
{
	unsigned long csa, mode;

	if (!data)
		return;

	csa = at91_sys_read(AT91_MATRIX_EBICSA);
	at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC);

	/* set the bus interface characteristics */
	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
			| AT91_SMC_NRDSETUP_(0) | AT91_SMC_NCS_RDSETUP_(0));

	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(2) | AT91_SMC_NCS_WRPULSE_(5)
			| AT91_SMC_NRDPULSE_(2) | AT91_SMC_NCS_RDPULSE_(5));

	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(7) | AT91_SMC_NRDCYCLE_(7));

	if (data->bus_width_16)
		mode = AT91_SMC_DBW_16;
	else
		mode = AT91_SMC_DBW_8;
	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(1));

	/* enable pin */
	if (data->enable_pin)
		at91_set_gpio_output(data->enable_pin, 1);

	/* ready/busy pin */
	if (data->rdy_pin)
		at91_set_gpio_input(data->rdy_pin, 1);

	/* card detect pin */
	if (data->det_pin)
		at91_set_gpio_input(data->det_pin, 1);

	nand_data = *data;
	platform_device_register(&at91sam9260_nand_device);
}
#else
void __init at91_add_device_nand(struct at91_nand_data *data) {}
#endif


/* --------------------------------------------------------------------
 *  TWI (i2c)
 * -------------------------------------------------------------------- */

#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)

static struct resource twi_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_TWI,
		.end	= AT91SAM9260_BASE_TWI + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_TWI,
		.end	= AT91SAM9260_ID_TWI,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_twi_device = {
	.name		= "at91_i2c",
	.id		= -1,
	.resource	= twi_resources,
	.num_resources	= ARRAY_SIZE(twi_resources),
};

void __init at91_add_device_i2c(void)
{
	/* pins used for TWI interface */
	at91_set_A_periph(AT91_PIN_PA23, 0);		/* TWD */
	at91_set_multi_drive(AT91_PIN_PA23, 1);

	at91_set_A_periph(AT91_PIN_PA24, 0);		/* TWCK */
	at91_set_multi_drive(AT91_PIN_PA24, 1);
	
#ifdef MOZART_BOARD
// JL
	//Enable PCK0 for Codec
	at91_set_A_periph(AT91_PIN_PB30, 0);
	at91_set_multi_drive(AT91_PIN_PB30, 0);
	
	//Enable PCK1 for FM
	at91_set_A_periph(AT91_PIN_PB31, 0);
	at91_set_multi_drive(AT91_PIN_PB31, 0);
	
	at91_sys_write(AT91_PMC_SCER, AT91_PMC_PCK0 | AT91_PMC_PCK1);
#endif

	platform_device_register(&at91sam9260_twi_device);
}
#else
void __init at91_add_device_i2c(void) {}
#endif


/* --------------------------------------------------------------------
 *  SPI
 * -------------------------------------------------------------------- */

//#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE) || defined(CONFIG_MOZART_SLAVE) //tmulgund 
#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_AT91_SPI_SLAVE) || defined(CONFIG_AT91_SPI) //ajoshi
static u64 spi_dmamask = 0xffffffffUL;

static struct resource spi0_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_SPI0,
		.end	= AT91SAM9260_BASE_SPI0 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_SPI0,
		.end	= AT91SAM9260_ID_SPI0,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_spi0_device = {
	.name		= "atmel_spi",
	.id		= 0,
	.dev		= {
				.dma_mask		= &spi_dmamask,
				.coherent_dma_mask	= 0xffffffff,
	},
	.resource	= spi0_resources,
	.num_resources	= ARRAY_SIZE(spi0_resources),
};

static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PC11, AT91_PIN_PC16, AT91_PIN_PC17 };

static struct resource spi1_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_SPI1,
		.end	= AT91SAM9260_BASE_SPI1 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_SPI1,
		.end	= AT91SAM9260_ID_SPI1,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_spi1_device = {
	.name		= "atmel_spi",
	.id		= 1,
	.dev		= {
				.dma_mask		= &spi_dmamask,
				.coherent_dma_mask	= 0xffffffff,
	},
	.resource	= spi1_resources,
	.num_resources	= ARRAY_SIZE(spi1_resources),
};

static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PC5, AT91_PIN_PC4, AT91_PIN_PC3 };

void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
{
	int i;
	unsigned long cs_pin;
	short enable_spi0 = 0;
	short enable_spi1 = 0;

	/* Choose SPI chip-selects */
	for (i = 0; i < nr_devices; i++) {
		if (devices[i].controller_data)
			cs_pin = (unsigned long) devices[i].controller_data;
		else if (devices[i].bus_num == 0)
			cs_pin = spi0_standard_cs[devices[i].chip_select];
		else
			cs_pin = spi1_standard_cs[devices[i].chip_select];

		if (devices[i].bus_num == 0)
			enable_spi0 = 1;
		else
			enable_spi1 = 1;

		/* enable chip-select pin */
		#ifndef CONFIG_AT91_SPI_SLAVE
		 at91_set_gpio_output(cs_pin, 1); //tmulgund
		#else 
		 at91_set_gpio_input(cs_pin, 0);
		#endif

		/* pass chip-select pin to driver */
		devices[i].controller_data = (void *) cs_pin;
	}

	
	spi_register_board_info(devices, nr_devices);
	#ifndef CONFIG_AT91_SPI_SLAVE
	/* Configure SPI bus(es) */
	if (enable_spi0) {
	  	 at91_set_A_periph(AT91_PIN_PA3, 1);	/* SPI1_CS */ 
		 at91_set_A_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
		 at91_set_A_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
		 at91_set_A_periph(AT91_PIN_PA2, 0);	/* SPI1_SPCK */
		 
		at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk"); //tmulgund
		platform_device_register(&at91sam9260_spi0_device);
	}
	if (enable_spi1) {
		at91_set_A_periph(AT91_PIN_PB0, 0);	/* SPI1_MISO */
		at91_set_A_periph(AT91_PIN_PB1, 0);	/* SPI1_MOSI */
		at91_set_A_periph(AT91_PIN_PB2, 0);	/* SPI1_SPCK */

		at91_clock_associate("spi1_clk", &at91sam9260_spi1_device.dev, "spi_clk");
		platform_device_register(&at91sam9260_spi1_device);
	}
	#else
	/* Configure SPI bus(es) */
	if (enable_spi0) {
	  	 at91_set_A_periph(AT91_PIN_PA3, 1);	/* SPI1_CS */ 
		 at91_set_A_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
		 at91_set_A_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
		 at91_set_A_periph(AT91_PIN_PA2, 0);	/* SPI1_SPCK */
		 
		at91_clock_associate("spi0_clk", &at91sam9260_spi0_device.dev, "spi_clk"); //tmulgund
		platform_device_register(&at91sam9260_spi0_device);
	}
	#endif
}
#else
void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) 
{
	printk("FUNCTION:%s LINE %d\n",__FUNCTION__,__LINE__);
}
#endif


/* --------------------------------------------------------------------
 *  SSC
 * -------------------------------------------------------------------- */

#ifdef MOZART_BOARD
/*
//static struct atmel_at73c213_data at73c213_data;
static u64 ssc_dmamask = 0xffffffffUL;

static struct resource ssc_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_SSC,
		.end	= AT91SAM9260_BASE_SSC + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_SSC,
		.end	= AT91SAM9260_ID_SSC,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct platform_device at91sam9260_ssc_device = {
	.name		= "at91_ssc",
	.id			= -1,
	.dev		= {
				.dma_mask			= &ssc_dmamask,
				.coherent_dma_mask	= 0xffffffff,
//				.platform_data		= &at73c213_data,
	},
	.resource	= ssc_resources,
	.num_resources	= ARRAY_SIZE(ssc_resources),
};
*/
void __init at91_add_device_ssc(void)
{
/*
	struct clk *at73_clk;
	struct clk *ssc_clk;
	struct clk *parent_clk;

	// Set SSC1 IO
	at91_set_B_periph(AT91_PIN_PA17, 0);		// TD1 
	at91_set_B_periph(AT91_PIN_PA18, 0);		// TF1 
	at91_set_B_periph(AT91_PIN_PA19, 0);		// TK1 

	// AT73C213 MCK Clock
	at91_set_B_periph(AT91_PIN_PB31, 0);		// PCK2 

	at73_clk = clk_get(NULL, "pck2");
	parent_clk = clk_get(NULL, "plla");
	clk_set_parent(at73_clk, parent_clk);
	clk_set_rate(at73_clk, 12416000);
	clk_enable(at73_clk);

	ssc_clk = clk_get(NULL, "ssc1_clk");
	clk_enable(ssc_clk);
	
	at73c213_data.ssc_div  = 32;  
	at73c213_data.at73_mck = at73_clk;  
*/
//	platform_device_register(&at91sam9260_ssc_device);
}
#else
void __init at91_add_device_ssc(void)	{}
#endif


/* --------------------------------------------------------------------
 *  LEDs
 * -------------------------------------------------------------------- */

#if defined(CONFIG_LEDS)
u8 at91_leds_cpu;
u8 at91_leds_timer;

void __init at91_init_leds(u8 cpu_led, u8 timer_led)
{
	at91_leds_cpu	= cpu_led;
	at91_leds_timer	= timer_led;
}
#else
void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
#endif


#if defined(CONFIG_NEW_LEDS)

static struct platform_device at91_leds = {
	.name		= "at91_leds",
	.id		= -1,
};

void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr)
{
	if (!nr)
		return;

	at91_leds.dev.platform_data = leds;

	for ( ; nr; nr--, leds++) {
		leds->index = nr;	/* first record stores number of leds */
		at91_set_gpio_output(leds->gpio, (leds->flags & 1) == 0);
	}

	platform_device_register(&at91_leds);
}
#else
void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr) {}
#endif


/* --------------------------------------------------------------------
 *  UART
 * -------------------------------------------------------------------- */
#if defined(CONFIG_SERIAL_ATMEL)
static struct resource dbgu_resources[] = {
	[0] = {
		.start	= AT91_VA_BASE_SYS + AT91_DBGU,
		.end	= AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91_ID_SYS,
		.end	= AT91_ID_SYS,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data dbgu_data = {
	.use_dma_tx	= 0,
	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
};

static struct platform_device at91sam9260_dbgu_device = {
	.name		= "atmel_usart",
	.id		= 0,
	.dev		= {
				.platform_data	= &dbgu_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= dbgu_resources,
	.num_resources	= ARRAY_SIZE(dbgu_resources),
};

static inline void configure_dbgu_pins(void)
{
	at91_set_A_periph(AT91_PIN_PB14, 0);		/* DRXD */
	at91_set_A_periph(AT91_PIN_PB15, 1);		/* DTXD */
}

static struct resource uart0_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US0,
		.end	= AT91SAM9260_BASE_US0 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US0,
		.end	= AT91SAM9260_ID_US0,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart0_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart0_device = {
	.name		= "atmel_usart",
	.id		= 1,
	.dev		= {
				.platform_data	= &uart0_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart0_resources,
	.num_resources	= ARRAY_SIZE(uart0_resources),
};

static inline void configure_usart0_pins(void)
{
	//at91_set_A_periph(AT91_PIN_PB4, 1);		/* TXD0 */
	//at91_set_A_periph(AT91_PIN_PB5, 0);		/* RXD0 */
	at91_set_A_periph(AT91_PIN_PB26, 0);		/* RTS0 */
	at91_set_A_periph(AT91_PIN_PB27, 0);		/* CTS0 */
	at91_set_A_periph(AT91_PIN_PB24, 0);		/* DTR0 */
	at91_set_A_periph(AT91_PIN_PB22, 0);		/* DSR0 */
	at91_set_A_periph(AT91_PIN_PB23, 0);		/* DCD0 */
	at91_set_A_periph(AT91_PIN_PB25, 0);		/* RI0 */
}

static struct resource uart1_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US1,
		.end	= AT91SAM9260_BASE_US1 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US1,
		.end	= AT91SAM9260_ID_US1,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart1_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart1_device = {
	.name		= "atmel_usart",
	.id		= 2,
	.dev		= {
				.platform_data	= &uart1_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart1_resources,
	.num_resources	= ARRAY_SIZE(uart1_resources),
};

static inline void configure_usart1_pins(void)
{
	at91_set_A_periph(AT91_PIN_PB6, 1);		/* TXD1 */
	at91_set_A_periph(AT91_PIN_PB7, 0);		/* RXD1 */
	at91_set_A_periph(AT91_PIN_PB28, 0);		/* RTS1 */
	at91_set_A_periph(AT91_PIN_PB29, 0);		/* CTS1 */
}

static struct resource uart2_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US2,
		.end	= AT91SAM9260_BASE_US2 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US2,
		.end	= AT91SAM9260_ID_US2,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart2_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart2_device = {
	.name		= "atmel_usart",
	.id		= 3,
	.dev		= {
				.platform_data	= &uart2_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart2_resources,
	.num_resources	= ARRAY_SIZE(uart2_resources),
};

static inline void configure_usart2_pins(void)
{
	at91_set_A_periph(AT91_PIN_PB8, 1);		/* TXD2 */
	at91_set_A_periph(AT91_PIN_PB9, 0);		/* RXD2 */
}

static struct resource uart3_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US3,
		.end	= AT91SAM9260_BASE_US3 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US3,
		.end	= AT91SAM9260_ID_US3,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart3_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart3_device = {
	.name		= "atmel_usart",
	.id		= 4,
	.dev		= {
				.platform_data	= &uart3_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart3_resources,
	.num_resources	= ARRAY_SIZE(uart3_resources),
};

static inline void configure_usart3_pins(void)
{
	at91_set_A_periph(AT91_PIN_PB10, 1);		/* TXD3 */
	at91_set_A_periph(AT91_PIN_PB11, 0);		/* RXD3 */
}

static struct resource uart4_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US4,
		.end	= AT91SAM9260_BASE_US4 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US4,
		.end	= AT91SAM9260_ID_US4,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart4_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart4_device = {
	.name		= "atmel_usart",
	.id		= 5,
	.dev		= {
				.platform_data	= &uart4_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart4_resources,
	.num_resources	= ARRAY_SIZE(uart4_resources),
};

static inline void configure_usart4_pins(void)
{
	at91_set_B_periph(AT91_PIN_PA31, 1);		/* TXD4 */
	at91_set_B_periph(AT91_PIN_PA30, 0);		/* RXD4 */
}

static struct resource uart5_resources[] = {
	[0] = {
		.start	= AT91SAM9260_BASE_US5,
		.end	= AT91SAM9260_BASE_US5 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91SAM9260_ID_US5,
		.end	= AT91SAM9260_ID_US5,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart5_data = {
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
};

static struct platform_device at91sam9260_uart5_device = {
	.name		= "atmel_usart",
	.id		= 6,
	.dev		= {
				.platform_data	= &uart5_data,
				.coherent_dma_mask = 0xffffffff,
	},
	.resource	= uart5_resources,
	.num_resources	= ARRAY_SIZE(uart5_resources),
};

static inline void configure_usart5_pins(void)
{
	at91_set_A_periph(AT91_PIN_PB12, 1);		/* TXD5 */
	at91_set_A_periph(AT91_PIN_PB13, 0);		/* RXD5 */
}

struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
struct platform_device *atmel_default_console_device;	/* the serial console device */

void __init at91_init_serial(struct at91_uart_config *config)
{
	int i;

	/* Fill in list of supported UARTs */
	for (i = 0; i < config->nr_tty; i++) {
		switch (config->tty_map[i]) {
			case 0:
				configure_usart0_pins();
				at91_uarts[i] = &at91sam9260_uart0_device;
				at91_clock_associate("usart0_clk", &at91sam9260_uart0_device.dev, "usart");
				break;
			case 1:
				configure_usart1_pins();
				at91_uarts[i] = &at91sam9260_uart1_device;
				at91_clock_associate("usart1_clk", &at91sam9260_uart1_device.dev, "usart");
				break;
			case 2:
				configure_usart2_pins();
				at91_uarts[i] = &at91sam9260_uart2_device;
				at91_clock_associate("usart2_clk", &at91sam9260_uart2_device.dev, "usart");
				break;
			case 3:
				configure_usart3_pins();
				at91_uarts[i] = &at91sam9260_uart3_device;
				at91_clock_associate("usart3_clk", &at91sam9260_uart3_device.dev, "usart");
				break;
			case 4:
				configure_usart4_pins();
				at91_uarts[i] = &at91sam9260_uart4_device;
				at91_clock_associate("usart4_clk", &at91sam9260_uart4_device.dev, "usart");
				break;
			case 5:
				configure_usart5_pins();
				at91_uarts[i] = &at91sam9260_uart5_device;
				at91_clock_associate("usart5_clk", &at91sam9260_uart5_device.dev, "usart");
				break;
			case 6:
				configure_dbgu_pins();
				at91_uarts[i] = &at91sam9260_dbgu_device;
				at91_clock_associate("mck", &at91sam9260_dbgu_device.dev, "usart");
				break;
			default:
				continue;
		}
		at91_uarts[i]->id = i;		/* update ID number to mapped ID */
	}

	/* Set serial console device */
	if (config->console_tty < ATMEL_MAX_UART)
		atmel_default_console_device = at91_uarts[config->console_tty];
	if (!atmel_default_console_device)
		printk(KERN_INFO "AT91: No default serial console defined.\n");
}

void __init at91_add_device_serial(void)
{
	int i;

	for (i = 0; i < ATMEL_MAX_UART; i++) {
		if (at91_uarts[i])
			platform_device_register(at91_uarts[i]);
	}
}
#else
void __init at91_init_serial(struct at91_uart_config *config) {}
void __init at91_add_device_serial(void) {}
#endif


/* -------------------------------------------------------------------- */
/*
 * These devices are always present and don't need any board-specific
 * setup.
 */
static int __init at91_add_standard_devices(void)
{
	return 0;
}

arch_initcall(at91_add_standard_devices);

[-- Attachment #5: Type: text/plain, Size: 363 bytes --]

-------------------------------------------------------------------------
This SF.Net email is sponsored by the Moblin Your Move Developer's challenge
Build the coolest Linux based applications with Moblin SDK & win great prizes
Grand prize is a trip for two to an Open Source event anywhere in the world
http://moblin-contest.org/redirect.php?banner_id=100&url=/

[-- Attachment #6: Type: text/plain, Size: 210 bytes --]

_______________________________________________
spi-devel-general mailing list
spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org
https://lists.sourceforge.net/lists/listinfo/spi-devel-general

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-10-31  2:30 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-10-31  2:30 At91sam9260 slave mode operation Ajay Joshi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).