/*
 * arch/arm/mach-cxd4105/cxd4108.c
 *
 * CXD4108 devices
 *
 * Copyright 2007 Sony Corporation
 *
 * 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.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 */
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <asm/hardware.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
#include <asm/arch/uart.h>
#include <asm/arch/regs-uart.h>
#include <asm/arch/regs-emc.h>
#include <asm/arch/regs-gpio.h>
#include <asm/io.h>

static struct uart_platform_data uart0_data = {
	.chan		= 0,
	.fifosize	= 32,
	.clock		= "UARTCLK0",
};

static struct amba_device uart0_device = {
	.dev = {
		.bus_id = "apb:42",
		.platform_data	= &uart0_data,
	},
	.res = {
		 .start = CXD4105_UART0_BASE,
		 .end   = CXD4105_UART0_BASE+SZ_4K-1,
		 .flags = IORESOURCE_MEM,
	 },
	.irq = { IRQ_UART0, },
};

#if defined(CONFIG_CXD4105_UART3) || defined(CONFIG_CXD4105_HANDLE_UART3)
static struct uart_platform_data uart1_data = {
	.chan		= 1,
	.fifosize	= 32,
	.clock		= "UARTCLK1",
};

static struct amba_device uart1_device = {
	.dev = {
		.bus_id = "apb:43",
		.platform_data	= &uart1_data,
	},
	.res = {
		 .start = CXD4105_UART1_BASE,
		 .end   = CXD4105_UART1_BASE+SZ_4K-1,
		 .flags = IORESOURCE_MEM,
	 },
	.irq = { IRQ_UART1, },
};
#endif /* CONFIG_CXD4105_UART3 || CONFIG_CXD4105_HANDLE_UART3 */

static struct amba_device *amba_devs[] __initdata = {
#ifdef CONFIG_CXD4105_UART3
	&uart1_device,
#else
	&uart0_device,
# ifdef CONFIG_CXD4105_HANDLE_UART3
	&uart1_device,
# endif
#endif /* CONFIG_CXD4105_UART3 */
};

#if defined(CONFIG_SMC9118)
# define SMC911X_INT  2	/* IRQ = GPIOSYS2 */
static struct resource smc9118_resources[] = {
	[0] = {
		.start	= EMC_CS2_BASE,
		.end	= EMC_CS2_BASE + SZ_4K-1,
		.flags	= IORESOURCE_MEM,
	},
	[1] = {
		.start  = IRQ_GPIOx(SMC911X_INT),
		.end	= IRQ_GPIOx(SMC911X_INT),
		.flags	= IORESOURCE_IRQ,
	}
};

static struct platform_device smc9118_device = {
	.name		= "smc911x",
	.id		= -1,
	.num_resources	= ARRAY_SIZE(smc9118_resources),
	.resource	= smc9118_resources,
};
#endif /* CONFIG_SMC9118 */

static void emc_init(void)
{
#if defined(CONFIG_SMC9118) || defined(CONFIG_SERIAL_8250)
	u32 dat;

	/* bind EMC CS2 to AM2 */
	dat = readl(CXD4105_EMC_VIRT_BASE+EMC_CS_PHY_BIND);
	dat &= ~(EMC_CS_MASK << EMC_CS_SHIFT(2));
	dat |= EMC_PHY_AM2 << EMC_CS_SHIFT(2);
	writel(dat, CXD4105_EMC_VIRT_BASE+EMC_CS_PHY_BIND);
	/* config AM2 as PageMode:OFF,DW=16bit */
	writel(EMC_PHY_AM_DW16, CXD4105_EMC_VIRT_BASE+EMC_PHY_AM2_CFG);
	/* AM2 PRM1 (TWEA=0x02, TWEN=0x06, TWDH=0x02, TWWAIT=0x03) */
#define EMC_PARAM1 0x02060203
	writel(EMC_PARAM1, CXD4105_EMC_VIRT_BASE+EMC_PHY_AM2_PRM1);
	/* AM2 PRM2 (TOEA=0x02, TRDLAT=0x09, TRAH=0x02, TRWAIT=0x03) */
#define EMC_PARAM2 0x02090203
	writel(EMC_PARAM2, CXD4105_EMC_VIRT_BASE+EMC_PHY_AM2_PRM2);
#endif /* CONFIG_SMC9118 || CONFIG_SERIAL_8250 */
}

static void __init cxd4108_init(void)
{
	int i, ret;
	struct amba_device **dev;

	emc_init();
	ret = cxd4105_core_init();
	for (i = 0, dev = amba_devs; i < ARRAY_SIZE(amba_devs); i++, dev++) {
		ret = amba_device_register(*dev, &iomem_resource);
		if (ret) {
			printk(KERN_ERR "cxd4108_init: amba_device_register failed.\n");
		}
	}

#if defined(CONFIG_SMC9118)
	ret = platform_device_register(&smc9118_device);
	if (ret) {
		printk(KERN_ERR "cxd4108_init: platform_device_register failed.\n");
	}
#endif /* CONFIG_SMC9118 */
}

MACHINE_START(CXD4105, "ARM-CXD4108")
	/* Maintainer: Sony Corporation */
	.phys_io	= CXD4105_AHB_BASE,
	.io_pg_offst	= (IO_BASE >> 18) & 0xfffc,
	.map_io		= cxd4105_map_io,
	.init_irq	= cxd4105_init_irq,
	.timer		= &cxd4105_timer,
	.init_machine	= cxd4108_init,
MACHINE_END
