| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677 | /* * linux/arch/arm/mach-omap2/board-n8x0.c * * Copyright (C) 2005-2009 Nokia Corporation * Author: Juha Yrjola <juha.yrjola@nokia.com> * * Modified from mach-omap2/board-generic.c * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include <linux/clk.h>#include <linux/delay.h>#include <linux/gpio.h>#include <linux/init.h>#include <linux/io.h>#include <linux/irq.h>#include <linux/stddef.h>#include <linux/i2c.h>#include <linux/spi/spi.h>#include <linux/usb/musb.h>#include <linux/platform_data/i2c-cbus-gpio.h>#include <linux/platform_data/spi-omap2-mcspi.h>#include <linux/platform_data/mtd-onenand-omap2.h>#include <linux/mfd/menelaus.h>#include <sound/tlv320aic3x.h>#include <asm/mach/arch.h>#include <asm/mach-types.h>#include "common.h"#include "mmc.h"#include "mux.h"#include "gpmc-onenand.h"#define TUSB6010_ASYNC_CS	1#define TUSB6010_SYNC_CS	4#define TUSB6010_GPIO_INT	58#define TUSB6010_GPIO_ENABLE	0#define TUSB6010_DMACHAN	0x3f#if defined(CONFIG_I2C_CBUS_GPIO) || defined(CONFIG_I2C_CBUS_GPIO_MODULE)static struct i2c_cbus_platform_data n8x0_cbus_data = {	.clk_gpio = 66,	.dat_gpio = 65,	.sel_gpio = 64,};static struct platform_device n8x0_cbus_device = {	.name	= "i2c-cbus-gpio",	.id	= 3,	.dev	= {		.platform_data = &n8x0_cbus_data,	},};static struct i2c_board_info n8x0_i2c_board_info_3[] __initdata = {	{		I2C_BOARD_INFO("retu-mfd", 0x01),	},};static void __init n8x0_cbus_init(void){	const int retu_irq_gpio = 108;	if (gpio_request_one(retu_irq_gpio, GPIOF_IN, "Retu IRQ"))		return;	irq_set_irq_type(gpio_to_irq(retu_irq_gpio), IRQ_TYPE_EDGE_RISING);	n8x0_i2c_board_info_3[0].irq = gpio_to_irq(retu_irq_gpio);	i2c_register_board_info(3, n8x0_i2c_board_info_3,				ARRAY_SIZE(n8x0_i2c_board_info_3));	platform_device_register(&n8x0_cbus_device);}#else /* CONFIG_I2C_CBUS_GPIO */static void __init n8x0_cbus_init(void){}#endif /* CONFIG_I2C_CBUS_GPIO */#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)/* * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and * 1.5 V voltage regulators of PM companion chip. Companion chip will then * provide then PGOOD signal to TUSB6010 which will release it from reset. */static int tusb_set_power(int state){	int i, retval = 0;	if (state) {		gpio_set_value(TUSB6010_GPIO_ENABLE, 1);		msleep(1);		/* Wait until TUSB6010 pulls INT pin down */		i = 100;		while (i && gpio_get_value(TUSB6010_GPIO_INT)) {			msleep(1);			i--;		}		if (!i) {			printk(KERN_ERR "tusb: powerup failed\n");			retval = -ENODEV;		}	} else {		gpio_set_value(TUSB6010_GPIO_ENABLE, 0);		msleep(10);	}	return retval;}static struct musb_hdrc_config musb_config = {	.multipoint	= 1,	.dyn_fifo	= 1,	.num_eps	= 16,	.ram_bits	= 12,};static struct musb_hdrc_platform_data tusb_data = {#ifdef CONFIG_USB_GADGET_MUSB_HDRC	.mode		= MUSB_OTG,#else	.mode		= MUSB_HOST,#endif	.set_power	= tusb_set_power,	.min_power	= 25,	/* x2 = 50 mA drawn from VBUS as peripheral */	.power		= 100,	/* Max 100 mA VBUS for host mode */	.config		= &musb_config,};static void __init n8x0_usb_init(void){	int ret = 0;	static char	announce[] __initdata = KERN_INFO "TUSB 6010\n";	/* PM companion chip power control pin */	ret = gpio_request_one(TUSB6010_GPIO_ENABLE, GPIOF_OUT_INIT_LOW,			       "TUSB6010 enable");	if (ret != 0) {		printk(KERN_ERR "Could not get TUSB power GPIO%i\n",		       TUSB6010_GPIO_ENABLE);		return;	}	tusb_set_power(0);	ret = tusb6010_setup_interface(&tusb_data, TUSB6010_REFCLK_19, 2,					TUSB6010_ASYNC_CS, TUSB6010_SYNC_CS,					TUSB6010_GPIO_INT, TUSB6010_DMACHAN);	if (ret != 0)		goto err;	printk(announce);	return;err:	gpio_free(TUSB6010_GPIO_ENABLE);}#elsestatic void __init n8x0_usb_init(void) {}#endif /*CONFIG_USB_MUSB_TUSB6010 */static struct omap2_mcspi_device_config p54spi_mcspi_config = {	.turbo_mode	= 0,};static struct spi_board_info n800_spi_board_info[] __initdata = {	{		.modalias	= "p54spi",		.bus_num	= 2,		.chip_select	= 0,		.max_speed_hz   = 48000000,		.controller_data = &p54spi_mcspi_config,	},};#if defined(CONFIG_MTD_ONENAND_OMAP2) || \	defined(CONFIG_MTD_ONENAND_OMAP2_MODULE)static struct mtd_partition onenand_partitions[] = {	{		.name           = "bootloader",		.offset         = 0,		.size           = 0x20000,		.mask_flags     = MTD_WRITEABLE,	/* Force read-only */	},	{		.name           = "config",		.offset         = MTDPART_OFS_APPEND,		.size           = 0x60000,	},	{		.name           = "kernel",		.offset         = MTDPART_OFS_APPEND,		.size           = 0x200000,	},	{		.name           = "initfs",		.offset         = MTDPART_OFS_APPEND,		.size           = 0x400000,	},	{		.name           = "rootfs",		.offset         = MTDPART_OFS_APPEND,		.size           = MTDPART_SIZ_FULL,	},};static struct omap_onenand_platform_data board_onenand_data[] = {	{		.cs		= 0,		.gpio_irq	= 26,		.parts		= onenand_partitions,		.nr_parts	= ARRAY_SIZE(onenand_partitions),		.flags		= ONENAND_SYNC_READ,	}};#endif#if defined(CONFIG_MENELAUS) &&						\	(defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE))/* * On both N800 and N810, only the first of the two MMC controllers is in use. * The two MMC slots are multiplexed via Menelaus companion chip over I2C. * On N800, both slots are powered via Menelaus. On N810, only one of the * slots is powered via Menelaus. The N810 EMMC is powered via GPIO. * * VMMC				slot 1 on both N800 and N810 * VDCDC3_APE and VMCS2_APE	slot 2 on N800 * GPIO23 and GPIO9		slot 2 EMMC on N810 * */#define N8X0_SLOT_SWITCH_GPIO	96#define N810_EMMC_VSD_GPIO	23#define N810_EMMC_VIO_GPIO	9static int slot1_cover_open;static int slot2_cover_open;static struct device *mmc_device;static int n8x0_mmc_switch_slot(struct device *dev, int slot){#ifdef CONFIG_MMC_DEBUG	dev_dbg(dev, "Choose slot %d\n", slot + 1);#endif	gpio_set_value(N8X0_SLOT_SWITCH_GPIO, slot);	return 0;}static int n8x0_mmc_set_power_menelaus(struct device *dev, int slot,					int power_on, int vdd){	int mV;#ifdef CONFIG_MMC_DEBUG	dev_dbg(dev, "Set slot %d power: %s (vdd %d)\n", slot + 1,		power_on ? "on" : "off", vdd);#endif	if (slot == 0) {		if (!power_on)			return menelaus_set_vmmc(0);		switch (1 << vdd) {		case MMC_VDD_33_34:		case MMC_VDD_32_33:		case MMC_VDD_31_32:			mV = 3100;			break;		case MMC_VDD_30_31:			mV = 3000;			break;		case MMC_VDD_28_29:			mV = 2800;			break;		case MMC_VDD_165_195:			mV = 1850;			break;		default:			BUG();		}		return menelaus_set_vmmc(mV);	} else {		if (!power_on)			return menelaus_set_vdcdc(3, 0);		switch (1 << vdd) {		case MMC_VDD_33_34:		case MMC_VDD_32_33:			mV = 3300;			break;		case MMC_VDD_30_31:		case MMC_VDD_29_30:			mV = 3000;			break;		case MMC_VDD_28_29:		case MMC_VDD_27_28:			mV = 2800;			break;		case MMC_VDD_24_25:		case MMC_VDD_23_24:			mV = 2400;			break;		case MMC_VDD_22_23:		case MMC_VDD_21_22:			mV = 2200;			break;		case MMC_VDD_20_21:			mV = 2000;			break;		case MMC_VDD_165_195:			mV = 1800;			break;		default:			BUG();		}		return menelaus_set_vdcdc(3, mV);	}	return 0;}static void n810_set_power_emmc(struct device *dev,					 int power_on){	dev_dbg(dev, "Set EMMC power %s\n", power_on ? "on" : "off");	if (power_on) {		gpio_set_value(N810_EMMC_VSD_GPIO, 1);		msleep(1);		gpio_set_value(N810_EMMC_VIO_GPIO, 1);		msleep(1);	} else {		gpio_set_value(N810_EMMC_VIO_GPIO, 0);		msleep(50);		gpio_set_value(N810_EMMC_VSD_GPIO, 0);		msleep(50);	}}static int n8x0_mmc_set_power(struct device *dev, int slot, int power_on,			      int vdd){	if (machine_is_nokia_n800() || slot == 0)		return n8x0_mmc_set_power_menelaus(dev, slot, power_on, vdd);	n810_set_power_emmc(dev, power_on);	return 0;}static int n8x0_mmc_set_bus_mode(struct device *dev, int slot, int bus_mode){	int r;	dev_dbg(dev, "Set slot %d bus mode %s\n", slot + 1,		bus_mode == MMC_BUSMODE_OPENDRAIN ? "open-drain" : "push-pull");	BUG_ON(slot != 0 && slot != 1);	slot++;	switch (bus_mode) {	case MMC_BUSMODE_OPENDRAIN:		r = menelaus_set_mmc_opendrain(slot, 1);		break;	case MMC_BUSMODE_PUSHPULL:		r = menelaus_set_mmc_opendrain(slot, 0);		break;	default:		BUG();	}	if (r != 0 && printk_ratelimit())		dev_err(dev, "MMC: unable to set bus mode for slot %d\n",			slot);	return r;}static int n8x0_mmc_get_cover_state(struct device *dev, int slot){	slot++;	BUG_ON(slot != 1 && slot != 2);	if (slot == 1)		return slot1_cover_open;	else		return slot2_cover_open;}static void n8x0_mmc_callback(void *data, u8 card_mask){	int bit, *openp, index;	if (machine_is_nokia_n800()) {		bit = 1 << 1;		openp = &slot2_cover_open;		index = 1;	} else {		bit = 1;		openp = &slot1_cover_open;		index = 0;	}	if (card_mask & bit)		*openp = 1;	else		*openp = 0;#ifdef CONFIG_MMC_OMAP	omap_mmc_notify_cover_event(mmc_device, index, *openp);#else	pr_warn("MMC: notify cover event not available\n");#endif}static int n8x0_mmc_late_init(struct device *dev){	int r, bit, *openp;	int vs2sel;	mmc_device = dev;	r = menelaus_set_slot_sel(1);	if (r < 0)		return r;	if (machine_is_nokia_n800())		vs2sel = 0;	else		vs2sel = 2;	r = menelaus_set_mmc_slot(2, 0, vs2sel, 1);	if (r < 0)		return r;	n8x0_mmc_set_power(dev, 0, MMC_POWER_ON, 16); /* MMC_VDD_28_29 */	n8x0_mmc_set_power(dev, 1, MMC_POWER_ON, 16);	r = menelaus_set_mmc_slot(1, 1, 0, 1);	if (r < 0)		return r;	r = menelaus_set_mmc_slot(2, 1, vs2sel, 1);	if (r < 0)		return r;	r = menelaus_get_slot_pin_states();	if (r < 0)		return r;	if (machine_is_nokia_n800()) {		bit = 1 << 1;		openp = &slot2_cover_open;	} else {		bit = 1;		openp = &slot1_cover_open;		slot2_cover_open = 0;	}	/* All slot pin bits seem to be inversed until first switch change */	if (r == 0xf || r == (0xf & ~bit))		r = ~r;	if (r & bit)		*openp = 1;	else		*openp = 0;	r = menelaus_register_mmc_callback(n8x0_mmc_callback, NULL);	return r;}static void n8x0_mmc_shutdown(struct device *dev){	int vs2sel;	if (machine_is_nokia_n800())		vs2sel = 0;	else		vs2sel = 2;	menelaus_set_mmc_slot(1, 0, 0, 0);	menelaus_set_mmc_slot(2, 0, vs2sel, 0);}static void n8x0_mmc_cleanup(struct device *dev){	menelaus_unregister_mmc_callback();	gpio_free(N8X0_SLOT_SWITCH_GPIO);	if (machine_is_nokia_n810()) {		gpio_free(N810_EMMC_VSD_GPIO);		gpio_free(N810_EMMC_VIO_GPIO);	}}/* * MMC controller1 has two slots that are multiplexed via I2C. * MMC controller2 is not in use. */static struct omap_mmc_platform_data mmc1_data = {	.nr_slots			= 2,	.switch_slot			= n8x0_mmc_switch_slot,	.init				= n8x0_mmc_late_init,	.cleanup			= n8x0_mmc_cleanup,	.shutdown			= n8x0_mmc_shutdown,	.max_freq			= 24000000,	.slots[0] = {		.wires			= 4,		.set_power		= n8x0_mmc_set_power,		.set_bus_mode		= n8x0_mmc_set_bus_mode,		.get_cover_state	= n8x0_mmc_get_cover_state,		.ocr_mask		= MMC_VDD_165_195 | MMC_VDD_30_31 |						MMC_VDD_32_33   | MMC_VDD_33_34,		.name			= "internal",	},	.slots[1] = {		.set_power		= n8x0_mmc_set_power,		.set_bus_mode		= n8x0_mmc_set_bus_mode,		.get_cover_state	= n8x0_mmc_get_cover_state,		.ocr_mask		= MMC_VDD_165_195 | MMC_VDD_20_21 |						MMC_VDD_21_22 | MMC_VDD_22_23 |						MMC_VDD_23_24 | MMC_VDD_24_25 |						MMC_VDD_27_28 | MMC_VDD_28_29 |						MMC_VDD_29_30 | MMC_VDD_30_31 |						MMC_VDD_32_33 | MMC_VDD_33_34,		.name			= "external",	},};static struct omap_mmc_platform_data *mmc_data[OMAP24XX_NR_MMC];static struct gpio n810_emmc_gpios[] __initdata = {	{ N810_EMMC_VSD_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vddf" },	{ N810_EMMC_VIO_GPIO, GPIOF_OUT_INIT_LOW,  "MMC slot 2 Vdd"  },};static void __init n8x0_mmc_init(void){	int err;	if (machine_is_nokia_n810()) {		mmc1_data.slots[0].name = "external";		/*		 * Some Samsung Movinand chips do not like open-ended		 * multi-block reads and fall to braind-dead state		 * while doing so. Reducing the number of blocks in		 * the transfer or delays in clock disable do not help		 */		mmc1_data.slots[1].name = "internal";		mmc1_data.slots[1].ban_openended = 1;	}	err = gpio_request_one(N8X0_SLOT_SWITCH_GPIO, GPIOF_OUT_INIT_LOW,			       "MMC slot switch");	if (err)		return;	if (machine_is_nokia_n810()) {		err = gpio_request_array(n810_emmc_gpios,					 ARRAY_SIZE(n810_emmc_gpios));		if (err) {			gpio_free(N8X0_SLOT_SWITCH_GPIO);			return;		}	}	mmc_data[0] = &mmc1_data;	omap242x_init_mmc(mmc_data);}#elsevoid __init n8x0_mmc_init(void){}#endif	/* CONFIG_MMC_OMAP */#ifdef CONFIG_MENELAUSstatic int n8x0_auto_sleep_regulators(void){	u32 val;	int ret;	val = EN_VPLL_SLEEP | EN_VMMC_SLEEP    \		| EN_VAUX_SLEEP | EN_VIO_SLEEP \		| EN_VMEM_SLEEP | EN_DC3_SLEEP \		| EN_VC_SLEEP | EN_DC2_SLEEP;	ret = menelaus_set_regulator_sleep(1, val);	if (ret < 0) {		pr_err("Could not set regulators to sleep on menelaus: %u\n",		       ret);		return ret;	}	return 0;}static int n8x0_auto_voltage_scale(void){	int ret;	ret = menelaus_set_vcore_hw(1400, 1050);	if (ret < 0) {		pr_err("Could not set VCORE voltage on menelaus: %u\n", ret);		return ret;	}	return 0;}static int n8x0_menelaus_late_init(struct device *dev){	int ret;	ret = n8x0_auto_voltage_scale();	if (ret < 0)		return ret;	ret = n8x0_auto_sleep_regulators();	if (ret < 0)		return ret;	return 0;}#elsestatic int n8x0_menelaus_late_init(struct device *dev){	return 0;}#endifstatic struct menelaus_platform_data n8x0_menelaus_platform_data __initdata = {	.late_init = n8x0_menelaus_late_init,};static struct i2c_board_info __initdata n8x0_i2c_board_info_1[] __initdata = {	{		I2C_BOARD_INFO("menelaus", 0x72),		.irq = 7 + OMAP_INTC_START,		.platform_data = &n8x0_menelaus_platform_data,	},};static struct aic3x_pdata n810_aic33_data __initdata = {	.gpio_reset = 118,};static struct i2c_board_info n810_i2c_board_info_2[] __initdata = {	{		I2C_BOARD_INFO("tlv320aic3x", 0x18),		.platform_data = &n810_aic33_data,	},};#ifdef CONFIG_OMAP_MUXstatic struct omap_board_mux board_mux[] __initdata = {	/* I2S codec port pins for McBSP block */	OMAP2420_MUX(EAC_AC_SCLK, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),	OMAP2420_MUX(EAC_AC_FS, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),	OMAP2420_MUX(EAC_AC_DIN, OMAP_MUX_MODE1 | OMAP_PIN_INPUT),	OMAP2420_MUX(EAC_AC_DOUT, OMAP_MUX_MODE1 | OMAP_PIN_OUTPUT),	{ .reg_offset = OMAP_MUX_TERMINATOR },};static struct omap_device_pad serial2_pads[] __initdata = {	{		.name	= "uart3_rx_irrx.uart3_rx_irrx",		.flags	= OMAP_DEVICE_PAD_REMUX | OMAP_DEVICE_PAD_WAKEUP,		.enable	= OMAP_MUX_MODE0,		.idle	= OMAP_MUX_MODE3	/* Mux as GPIO for idle */	},};static inline void board_serial_init(void){
 |