/*
 * arch/arm/mach-at91/at91x40_devices.c
 * Copyright (C) 2011 Phil Budne
 *
 * from arch/arm/mach-at91/at91sam9260_devices.c
 * Copyright (C) 2006 Atmel
 *
 * 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/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>

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

#include <mach/at91x40.h>
//#include <mach/at91_st.h>
#include <mach/timex.h>
#include <mach/board.h>
#include <mach/gpio.h>
#include <mach/cpu.h>

#include "generic.h"

#if defined(CONFIG_SERIAL_ATMEL)
static struct resource uart0_resources[] = {
	[0] = {
		.start	= AT91_USART0,
		.end	= AT91_USART0 + SZ_16K - 1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start	= AT91X40_ID_USART0,
		.end	= AT91X40_ID_USART0,
		.flags	= IORESOURCE_IRQ,
	},
};

static struct atmel_uart_data uart0_data = {
#if 0
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
#endif
};

static u64 uart0_dmamask = DMA_BIT_MASK(32);

static struct platform_device at91x40_uart0_device = {
	.name		= "atmel_usart",
	.id		= 1,
	.dev		= {
				.dma_mask		= &uart0_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
				.platform_data		= &uart0_data,
	},
	.resource	= uart0_resources,
	.num_resources	= ARRAY_SIZE(uart0_resources),
};

static inline void configure_usart0_pins(unsigned pins)
{
	at91_set_A_periph(AT91_PIN_PA14, 1);		/* TXD0 */
	at91_set_A_periph(AT91_PIN_PA15, 0);		/* RXD0 */
}

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

static struct atmel_uart_data uart1_data = {
#if 0
	.use_dma_tx	= 1,
	.use_dma_rx	= 1,
#endif
};

static u64 uart1_dmamask = DMA_BIT_MASK(32);

static struct platform_device at91x40_uart1_device = {
	.name		= "atmel_usart",
	.id		= 2,
	.dev		= {
				.dma_mask		= &uart1_dmamask,
				.coherent_dma_mask	= DMA_BIT_MASK(32),
				.platform_data		= &uart1_data,
	},
	.resource	= uart1_resources,
	.num_resources	= ARRAY_SIZE(uart1_resources),
};

static inline void configure_usart1_pins(unsigned pins)
{
	at91_set_A_periph(AT91_PIN_PA21, 1);		/* TXD1 */
	at91_set_A_periph(AT91_PIN_PA22, 0);		/* RXD1 */
}

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

void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
{
	struct platform_device *pdev;
	struct atmel_uart_data *pdata;

	switch (id) {
	case AT91X40_ID_USART0:
		pdev = &at91x40_uart0_device;
		configure_usart0_pins(pins);
		break;
	case AT91X40_ID_USART1:
		pdev = &at91x40_uart1_device;
		configure_usart1_pins(pins);
		break;
	default:
		return;
	}
	pdata = pdev->dev.platform_data;
	pdata->num = portnr;		/* update to mapped ID */

	if (portnr < ATMEL_MAX_UART)
		at91_uarts[portnr] = pdev;
}

void __init at91_set_serial_console(unsigned portnr)
{
	if (portnr < ATMEL_MAX_UART) {
		atmel_default_console_device = at91_uarts[portnr];
	}
}

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]);
	}

	if (!atmel_default_console_device)
		printk(KERN_INFO "AT91: No default serial console defined.\n");
}
#else
void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
void __init at91_set_serial_console(unsigned portnr) {}
void __init at91_add_device_serial(void) {}
#endif
