/*
 * Modified from board-htcherald.c
 *
 * HTC Pharos init stuff
 * Copyright (C) 2009 Jon Rhodes <life02@gmail.com>
 * Copyright (C) 2009 wing-linux.sourceforge.net
 *
 * 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/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/bootmem.h>
#include <linux/i2c-gpio.h>

#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/arch/omap850.h>
#include <asm/page.h>
#include <asm/memory.h>
#include <asm/arch/common.h>
#include <asm/arch/board.h>

#ifdef CONFIG_EFB_DEBUG
#include <asm/arch/efb.h>
#endif

#include <asm/arch/io.h>
#include <asm/arch/irqs.h>
#include <asm/arch/gpio.h>
#include <asm/arch/keypad.h>
#include <asm/arch/spi100k.h>

#include <linux/spi/spi.h>

#include <linux/delay.h>

#ifdef CONFIG_HTC_MMC
#include "htc-mmc.h"
#endif

#define HTCPHAROS_GPIO_DM 35
#define HTCPHAROS_GPIO_DP 36
#define HTCPHAROS_GPIO_POWER 135
#define HTCPHAROS_GPIO_DPAD_CENTER 75
//#define HTCPHAROS_GPIO_DPAD_JOGWEEL 77
#define HTCPHAROS_GPIO_DPAD_UP 80
#define HTCPHAROS_GPIO_DPAD_RIGHT 81
#define HTCPHAROS_GPIO_DPAD_DOWN 82
#define HTCPHAROS_GPIO_DPAD_LEFT 83

static struct omap_lcd_config htcpharos_lcd_config __initdata = {
	.ctrl_name	= "internal",
};

static struct omap_usb_config htcpharos_usb_config __initdata = {
	.otg		= 0,
	.register_host	= 0,
	.register_dev	= 1,
	.hmc_mode	= 4,
	.pins[0]	= 2,
};

static struct omap_mmc_config htcpharos_mmc_config __initdata =
{
	.mmc[0] = {
		.enabled = 1,
		.nomux = 1,
		.wire4 = 1,
		.power_pin = -1,
		.switch_pin = -1,
	}
};

/*
  UART1 Bluetooth
  UART2 IR?
*/
static struct omap_uart_config htcpharos_uart_config __initdata = {
        .enabled_uarts = (1 << 0) | (1 << 1),
};

static struct omap_board_config_kernel htcpharos_config[] = 
{
	{ OMAP_TAG_LCD, &htcpharos_lcd_config },
	{ OMAP_TAG_USB, &htcpharos_usb_config },
	{ OMAP_TAG_MMC, &htcpharos_mmc_config },
	{ OMAP_TAG_UART, &htcpharos_uart_config },
};

/* GSM device */
#define PHAROS_GSM_PHYS_START          0x13c00000 /* end of RAM */
#define PHAROS_GSM_PHYS_SIZE           0x00400000 /* 4.0 MB code/data/fifo */

static struct resource pharos_gsm_resources[] = {
	{       /* GSM DSP MMU */
                .start          = IO_ADDRESS(OMAP850_DSP_MMU_BASE),
                .end            = IO_ADDRESS(OMAP850_DSP_MMU_BASE) + 0x54,
                .flags          = IORESOURCE_MEM,
        },
        {       /* GSM software interrupt */
                .start          = INT_850_ICR,
                .flags          = IORESOURCE_IRQ,
        },
        {       /* GSM radio interrupt */
                .start          = INT_850_DBB_RF_EN,
                .flags          = IORESOURCE_IRQ,
        },
};

static struct platform_device gsm_device = {
        .name           = "wizard-gsm",
        .id             = 1,
        .num_resources  = ARRAY_SIZE(pharos_gsm_resources),
        .resource       = pharos_gsm_resources,
};
 
/* Keyboard definition */ 
static int htcpharos_keymap[] = {

	KEY(0,0,KEY_DIRECTORY), //Windows Key - ANDROID MENU
	KEY(0,1,KEY_CALENDAR), //Left Softkey - ANDROID BACK
	KEY(0,2,KEY_CAMERA), //Camera  
	KEY(1,0,KEY_SLASH), //OK Key - ANDROID OK
	KEY(1,1,KEY_LEFTCTRL), //Right Softkey - ANDROID HOME
	KEY(1,2,KEY_VOLUMEUP), //Volume Up - Android Volume Up
	KEY(2,0,KEY_PHONE), //Send Button - Android Call
	KEY(2,1,KEY_CANCEL), //End Button - Android End
	KEY(2,2,KEY_VOLUMEDOWN), //Volume Down - Android Volume Down
/*
	KEY(0,3,KEY_M), 
	KEY(0,4,KEY_F2),  
	KEY(0,5,KEY_MAIL), 
	KEY(0,6,KEY_DIRECTORY), 
	KEY(1,3,KEY_K),
	KEY(1,4,KEY_SLASH),
	KEY(1,5,KEY_I),
	KEY(1,6,KEY_U),
	KEY(2,3,KEY_J),
	KEY(2,4,KEY_ENTER),
	KEY(2,5,KEY_H),
	KEY(2,6,KEY_Y),
	KEY(3,0,KEY_SPACE),
	KEY(3,1,KEY_L),
	KEY(3,2,KEY_B),
	KEY(3,3,KEY_V),
	KEY(3,4,KEY_BACKSPACE),
	KEY(3,5,KEY_G),
	KEY(3,6,KEY_T),
	KEY(4,0,KEY_CAPSLOCK), 
	KEY(4,1,KEY_C),
	KEY(4,2,KEY_F),
	KEY(4,3,KEY_R),
	KEY(4,4,KEY_O),
	KEY(4,5,KEY_E),
	KEY(4,6,KEY_D),
	KEY(5,0,KEY_X),
	KEY(5,1,KEY_Z),
	KEY(5,2,KEY_S),
	KEY(5,3,KEY_W),
	KEY(5,4,KEY_P),
	KEY(5,5,KEY_Q),
	KEY(5,6,KEY_CAMERA),
	KEY(6,0,KEY_CONNECT), 
	KEY(6,2,KEY_C), 
	KEY(6,3,KEY_N), 
	KEY(6,4,KEY_F1), 
	KEY(6,5,KEY_WWW),
	KEY(6,6,KEY_CALENDAR), 
	*/
	0
};
 

struct omap_kp_platform_data htcpharos_kp_data = {
	.rows	= 7,
	.cols	= 7,
	.delay = 40,
	.rep = 1,
	.keymap = htcpharos_keymap,
};

static struct resource kp_resources={
		.start	= INT_850_MPUIO_KEYPAD,
		.end	= INT_850_MPUIO_KEYPAD,
		.flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHEDGE,
	};

static struct platform_device kp_device = {
	.name		= "omap-keypad",
	.id		= -1,
	.dev		= {
		.platform_data = &htcpharos_kp_data,
	},
	.num_resources	= 1, //ARRAY_SIZE(kp_resources),
	.resource	= &kp_resources,
};

/* GPIO buttons for keyboard slide and power button */
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
#include <linux/input.h>
#include <linux/gpio_keys.h>
 
static struct gpio_keys_button pharos_gpio_keys_table[] = { 
	{KEY_CANCEL, HTCPHAROS_GPIO_POWER, 1, "gpio-keys: POWER", EV_KEY, 1,1},
	{KEY_UP, HTCPHAROS_GPIO_DPAD_UP, 1, "gpio-keys: DPAD-UP", EV_KEY, 1,1},
	{KEY_DOWN, HTCPHAROS_GPIO_DPAD_DOWN, 1, "gpio-keys: DPAD-DOWN", EV_KEY, 1,1},
	{KEY_LEFT, HTCPHAROS_GPIO_DPAD_LEFT, 1, "gpio-keys: DPAD-LEFT", EV_KEY, 1,1},
	{KEY_RIGHT, HTCPHAROS_GPIO_DPAD_RIGHT, 1, "gpio-keys: DPAD-RIGHT", EV_KEY, 1,1},
	{KEY_SLASH, HTCPHAROS_GPIO_DPAD_CENTER, 1, "gpio-keys: DPAD-CENTER", EV_KEY, 1,1},

};

static struct gpio_keys_platform_data pharos_gpio_keys_data = {
   .buttons        = pharos_gpio_keys_table,
   .nbuttons       = ARRAY_SIZE(pharos_gpio_keys_table),
};

static struct platform_device pharos_gpiokeys_device = {
   .name      = "gpio-keys",
   .dev = {
      .platform_data = &pharos_gpio_keys_data,
   },
};
#endif

/* LCD Device resources */
static struct platform_device lcd_device = {
	.name           = "lcd_htcpharos",
	.id             = -1,
};

/*
#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)

static struct i2c_gpio_platform_data i2cgpio_device_data = {
	.sda_pin		= 69,
	.scl_pin		= 70,
	.udelay			= 2,		// ~100 kHz 
};

static struct platform_device i2cgpio_device = {
	.name			= "i2c-gpio",
	.id			= 0,
	.dev	 = {
		.platform_data	= &i2cgpio_device_data,
	},
};

#endif
*/

/* Bluetooth */
struct platform_device htcpharos_bt = {
        .name = "htc-bt",
        .id = 1
};

static struct platform_device *devices[] __initdata = {
 	&gsm_device,
	&kp_device,
	&lcd_device,
#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
	&pharos_gpiokeys_device,
#endif
#if defined(CONFIG_HTC_BT)
	&htcpharos_bt,
#endif
};

/*
 * Touchscreen
 */
/*static struct tsc2003_platform_data htcpharos_ts_platform_data __initdata = {
        .ts_x_plate_ohm    = 496, 
        .dav_gpio          = 76,
        .gpio_debounce     = 0,
		  .ts_max_pressure   = 100000,
        .ts_touch_pressure = 5000, 
};

static struct spi_board_info htcpharos_spi_board_info[] __initdata = { 
	{
 	       .modalias               = "tsc2003",
 	       .platform_data          = &htcpharos_ts_platform_data,
	       .max_speed_hz           = 2500000,
	       .bus_num                = 2,
	       .chip_select            = 1,
	       .irq		       = OMAP_GPIO_IRQ(76),
	} 
};
*/

/*
 * Init functions from here on
 */

static void __init htcpharos_map_io(void)
{
	omap1_map_common_io();
	printk("htcpharos_map_io done.\n");

#ifdef CONFIG_EFB_DEBUG
	efb_enable();
#endif

	/* Reserve GSM Memory */
	reserve_bootmem(PHAROS_GSM_PHYS_START, PHAROS_GSM_PHYS_SIZE, 0);
}

static void __init htcpharos_disable_watchdog(void)
{
  /* Disable watchdog if running */
  if (omap_readl(OMAP_WDT_TIMER_MODE) & 0x8000) {
    /*
     * disable a potentially running watchdog timer before
     * it kills us.
     */
    printk("OMAP850 Watchdog seems to be activated, disabling it for now.\n");
    omap_writel(0xF5, OMAP_WDT_TIMER_MODE);
    omap_writel(0xA0, OMAP_WDT_TIMER_MODE);
  }
}

/* TSC2046 init from board-nokia770.c */


static void __init htcpharos_usb_enable(void)
{
	unsigned int tries = 20;
	printk("trying to enable USB.\n");

	/* force USB_EN GPIO to 0 */
	do {
		omap_set_gpio_direction(33, 0); /* output */
		omap_set_gpio_dataout(33, 0); /* low */
		--tries;
	} while(omap_get_gpio_datain(33) && tries);
	if (tries) {
		printk("unable to reset USB_EN GPIO after 20 tries.\n");
		printk("I will try to continue anyway: USB may not be available.\n");
	}
	printk("USB_EN to 0 after %i tries.\n", tries);

	omap_set_gpio_dataout(73, 0);
	
	omap_set_gpio_direction(HTCPHAROS_GPIO_DM, 1); /* input */
	
	/* get uart control from GSM */
	
	/* select GPIO35 for D_MCLK_OUT */
	/* select GPIO36 for D_CRESET */
	omap_writel(omap_readl(OMAP730_IO_CONF_3) & 0xffffffcc, OMAP730_IO_CONF_3);
	omap_writel(omap_readl(OMAP730_IO_CONF_3) | 0x000000cc, OMAP730_IO_CONF_3);
	

	omap_set_gpio_direction(HTCPHAROS_GPIO_DP, 1); /* input */

	/* select D_DM, D_DP for D_DM and disable PE_DM control */
	omap_writel(omap_readl(OMAP730_IO_CONF_2) & 0xff1fffff, OMAP730_IO_CONF_2);
	omap_writel(omap_readl(OMAP730_IO_CONF_2) | 0x00100000, OMAP730_IO_CONF_2);
	mdelay(100);

	/* select USB_VBUSI for D_VBUSI, enable PE_VIBUSI pull enable control  */
	omap_writel(omap_readl(OMAP730_IO_CONF_2) & 0xf1ffffff, OMAP730_IO_CONF_2);
	omap_writel(omap_readl(OMAP730_IO_CONF_2) | 0x01000000, OMAP730_IO_CONF_2);

	/* set USB_VBUS_CTRL */
	omap_writel(omap_readl(OMAP730_MODE_1) | (1 << 25), OMAP730_MODE_1);
}

static void __init htcpharos_usb_otg(void)
{
	/* clock configuration */
	omap_writew(omap_readw(ULPD_SOFT_REQ) | (1 << 8) | SOFT_USB_CLK_REQ, ULPD_SOFT_REQ);

	//  clk_enable(&l3_ocpi_ck);
	omap_writew(omap_readw(ARM_IDLECT3) | (1 << 0), ARM_IDLECT3);

	/* pin muxing */
	omap_writel(omap_readl(OMAP730_MODE_1) & ~(1 <<  2), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) & ~(1 <<  3), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) |  (1 << 15), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) |  (1 << 23), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) |  (1 << 26), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) |  (1 << 25), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) & ~(1 << 24), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) & ~(1 << 10), OMAP730_MODE_1);
	omap_writel(omap_readl(OMAP730_MODE_1) & ~(1 << 11), OMAP730_MODE_1);
}

/*static void __init htcpharos_spi_mux(void)
{
	// Setup MUX config for SPI 
	omap_writel(omap_readl(OMAP850_IO_CONF_6) |  0x00088880, OMAP850_IO_CONF_6);
	omap_writel(omap_readl(OMAP850_IO_CONF_6) & ~0x00077770, OMAP850_IO_CONF_6);

	omap_writel(omap_readl(OMAP850_IO_CONF_8) |  0x01000000, OMAP850_IO_CONF_8);
	omap_writel(omap_readl(OMAP850_IO_CONF_8) & ~0x10110000, OMAP850_IO_CONF_8);

	omap_writel(omap_readl(OMAP850_IO_CONF_9) |  0x00000010, OMAP850_IO_CONF_9);
	omap_writel(omap_readl(OMAP850_IO_CONF_9) & ~0x00000001, OMAP850_IO_CONF_9);

	// configure spi setup registers 
	omap_writew(0xfffe, OMAP850_SPI2_BASE + 0x02);
	omap_writew(0x0000, OMAP850_SPI2_BASE + 0x08);
	omap_writew(0x7ff8, OMAP850_SPI2_BASE + 0x0e);
}*/

static void __init htcpharos_init(void)
{
  printk("HTC Pharos init.\n");
  efb_putstr("HTC init");
  omap_board_config = htcpharos_config;
  omap_board_config_size = ARRAY_SIZE(htcpharos_config);
  platform_add_devices(devices, ARRAY_SIZE(devices));

  htcpharos_disable_watchdog();
  htcpharos_i2c_init();
  htcpharos_usb_otg();
  htcpharos_usb_enable();
  //htcpharos_spi_mux(); //Turn off for DPAD to work

 // #ifdef CONFIG_HTC_MMC
  htc_mmc_init();
  //#endif

  // Add UART2 clock activation
  omap_writel(omap_readl(0xfffe0834) | 0x800, 0xfffe0834);
  // Add UART1 clock activation
  omap_writel(omap_readl(0xfffe0834) | 0x200, 0xfffe0834);
  omap_serial_init();

  /* For testing.. Disable for now */
  //spi_register_board_info(htcpharos_spi_board_info,
		//ARRAY_SIZE(htcpharos_spi_board_info));
  /* omap_free_gpio(76); */
}

static void __init htcpharos_init_irq(void)
{
	printk("htcpharos_init_irq.\n");
	omap1_init_common_hw();
	omap_init_irq();
	omap_gpio_init();
}

MACHINE_START(HTCPHAROS, "HTC Pharos")
        /* Maintainer: Jon Rhodes <life02@gmail.com> */
		  /* Maintainer: wing-linux.sourceforge.net */
        .phys_io        = 0xfff00000,
        .io_pg_offst    = ((0xfef00000) >> 18) & 0xfffc,
        .boot_params    = 0x10000100,
        .map_io         = htcpharos_map_io,
        .init_irq       = htcpharos_init_irq,
        .init_machine   = htcpharos_init,
        .timer          = &omap_timer,
MACHINE_END
