blob: ce173ed335e3e901fb1f801a07e364356fc78201 [file] [log] [blame]
/*
* Copyright (C) 2009 ST-Ericsson SA
*
* 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/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <linux/i2c.h>
#include <linux/hsi.h>
#include <linux/i2s/i2s.h>
#include <linux/gpio.h>
#include <linux/input.h>
#include <linux/i2c/lp5521.h>
#include <linux/power_supply.h>
#include <linux/mfd/abx500.h>
#include <linux/lsm303dlh.h>
#include <linux/bu21013.h>
#include <asm/mach/arch.h>
#include <asm/mach/irq.h>
#include <asm/mach/map.h>
#include <asm/mach-types.h>
#include <plat/pincfg.h>
#include <mach/db8500-pins.h>
#include <mach/devices.h>
#include <mach/kpd.h>
#include <mach/stmpe2401.h>
#include <mach/stmpe1601.h>
#include <mach/tc35892.h>
#include <mach/sensors1p.h>
#include <mach/ab8500.h>
#include <mach/ab8500_bm.h>
#include <mach/mmc.h>
#include <mach/setup.h>
#include <mach/i2c.h>
#include <mach/tc35893-keypad.h>
#include <video/av8100.h>
#define IRQ_KP 1 /*To DO*/
int href_v1_board;
#define MOP500_PLATFORM_ID 0
#define HREF_PLATFORM_ID 1
int platform_id = MOP500_PLATFORM_ID;
/* we have equally similar boards with very minimal
* changes, so we detect the platform during boot
*/
static int __init board_id_setup(char *str)
{
if (!str)
return 1;
switch (*str) {
case '0':
printk(KERN_INFO "MOP500 platform\n");
platform_id = MOP500_PLATFORM_ID;
break;
case '1':
printk(KERN_INFO "HREF platform\n");
platform_id = HREF_PLATFORM_ID;
break;
default:
printk(KERN_INFO "Unknown board_id=%c\n", *str);
break;
};
return 1;
}
__setup("board_id=", board_id_setup);
static pin_cfg_t mop500_pins[] = {
/* I2C */
GPIO147_I2C0_SCL,
GPIO148_I2C0_SDA,
GPIO16_I2C1_SCL,
GPIO17_I2C1_SDA,
GPIO10_I2C2_SDA,
GPIO11_I2C2_SCL,
GPIO229_I2C3_SDA,
GPIO230_I2C3_SCL,
};
static struct gpio_altfun_data gpio_altfun_table[] = {
__GPIO_ALT(GPIO_ALT_UART_2, 29, 32, 0, NMK_GPIO_ALT_C, "uart2"),
__GPIO_ALT(GPIO_ALT_SSP_0, 143, 146, 0, NMK_GPIO_ALT_A, "ssp0"),
__GPIO_ALT(GPIO_ALT_SSP_1, 139, 142, 0, NMK_GPIO_ALT_A, "ssp1"),
__GPIO_ALT(GPIO_ALT_USB_OTG, 256, 267, 0, NMK_GPIO_ALT_A, "usb"),
__GPIO_ALT(GPIO_ALT_UART_1, 4, 7, 0, NMK_GPIO_ALT_A, "uart1"),
__GPIO_ALT(GPIO_ALT_UART_0_NO_MODEM, 0, 3, 0, NMK_GPIO_ALT_A, "uart0"),
__GPIO_ALT(GPIO_ALT_UART_0_MODEM, 0, 3, 1, NMK_GPIO_ALT_A, "uart0"),
__GPIO_ALT(GPIO_ALT_UART_0_MODEM, 33, 36, 0, NMK_GPIO_ALT_C, "uart0"),
__GPIO_ALT(GPIO_ALT_MSP_0, 12, 15, 0, NMK_GPIO_ALT_A, "msp0"),
__GPIO_ALT(GPIO_ALT_MSP_1, 33, 36, 0, NMK_GPIO_ALT_A, "msp1"),
__GPIO_ALT(GPIO_ALT_MSP_2, 192, 196, 0, NMK_GPIO_ALT_A, "msp2"),
__GPIO_ALT(GPIO_ALT_HSIR, 219, 221, 0, NMK_GPIO_ALT_A, "hsir"),
__GPIO_ALT(GPIO_ALT_HSIT, 222, 224, 0, NMK_GPIO_ALT_A, "hsit"),
__GPIO_ALT(GPIO_ALT_EMMC, 197, 207, 0, NMK_GPIO_ALT_A, "emmc"),
__GPIO_ALT(GPIO_ALT_SDMMC, 18, 28, 0, NMK_GPIO_ALT_A, "sdmmc"),
__GPIO_ALT(GPIO_ALT_SDIO, 208, 214, 0, NMK_GPIO_ALT_A, "sdio"),
__GPIO_ALT(GPIO_ALT_TRACE, 70, 74, 0, NMK_GPIO_ALT_C, "stm"),
__GPIO_ALT(GPIO_ALT_SDMMC2, 128, 138, 0, NMK_GPIO_ALT_A, "mmc2"),
__GPIO_ALT(GPIO_ALT_LCD_PANELB, 78, 81, 1, NMK_GPIO_ALT_A,
"mcde tvout"),
__GPIO_ALT(GPIO_ALT_LCD_PANELB, 150, 150, 0, NMK_GPIO_ALT_B,
"mcde tvout"),
#ifdef CONFIG_AV8100_HWTRIG_I2SDAT3
__GPIO_ALT(GPIO_ALT_LCD_PANELA, 69, 69, 0, NMK_GPIO_ALT_A,
"mcde tvout"),
#else
__GPIO_ALT(GPIO_ALT_LCD_PANELA, 68, 68, 0, NMK_GPIO_ALT_A,
"mcde tvout"),
#endif /* CONFIG_AV8100_HWTRIG_I2SDAT3 */
__GPIO_ALT(GPIO_ALT_MMIO_INIT_BOARD, 141, 142, 0, NMK_GPIO_ALT_B,
"mmio"),
__GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_I2C, 8, 9, 0, NMK_GPIO_ALT_A, "mmio"),
__GPIO_ALT(GPIO_ALT_MMIO_CAM_SET_EXT_CLK, 227, 228, 0, NMK_GPIO_ALT_A,
"mmio"),
__GPIO_ALT(GPIO_ALT_TP_SET_EXT_CLK, 228, 228, 0, NMK_GPIO_ALT_A,
"bu21013_tp"),
#ifdef CONFIG_KEYPAD_SKE
__GPIO_ALT(GPIO_ALT_KEYPAD, 153, 168, 0, NMK_GPIO_ALT_A, "ske-kp"),
#endif
};
/*
* Initializes the key scan table (lookup table) as per pre-defined scan
* codes to be passed to upper layer with respective key codes
*/
u8 const kpd_lookup_tbl1[MAX_KPROW][MAX_KPROW] = {
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_9,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_POWER,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_7,
KEY_VOLUMEUP,
KEY_RIGHT,
KEY_BACK,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_3,
KEY_RESERVED,
KEY_DOWN,
KEY_LEFT,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_UP,
KEY_RESERVED,
KEY_RESERVED,
KEY_SEND,
KEY_RESERVED
},
{
KEY_MENU,
KEY_RESERVED,
KEY_END,
KEY_VOLUMEDOWN,
KEY_0,
KEY_1,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_ENTER
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_2,
KEY_RESERVED
}
};
/*
* Alternative keymap for seperate applications, can be enabled from sysfs
*/
u8 const kpd_lookup_tbl2[MAX_KPROW][MAX_KPROW] = {
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_9,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_ENTER,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_7,
KEY_KPDOT,
KEY_6,
KEY_BACK,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_3,
KEY_RESERVED,
KEY_8,
KEY_4,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_5,
KEY_RESERVED,
KEY_RESERVED,
KEY_LEFT,
KEY_RESERVED
},
{
KEY_UP,
KEY_RESERVED,
KEY_RIGHT,
KEY_MENU,
KEY_0,
KEY_1,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_DOWN
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_2,
KEY_RESERVED
}
};
/*
* Initializes the key scan table (lookup table) as per schematic of
* the NUIB. Pre-defined scan codes to be passed to upper layer
* for each valid key in the matrix.
*/
u8 const kpd_lookup_tbl3[TC_KPD_ROWS][TC_KPD_COLUMNS] = {
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_BACK,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_1,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_9,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_END,
KEY_RESERVED,
KEY_RIGHT,
KEY_2,
KEY_DOWN,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_POWER,
KEY_3,
KEY_0,
KEY_RESERVED,
KEY_SEND,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_ENTER,
KEY_RESERVED,
KEY_UP,
KEY_RESERVED,
KEY_RESERVED,
KEY_7,
KEY_RESERVED,
KEY_RESERVED
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_VOLUMEUP,
KEY_RESERVED,
KEY_VOLUMEDOWN,
KEY_RESERVED,
KEY_RESERVED,
KEY_MENU
},
{
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_LEFT,
KEY_RESERVED
}
};
static struct stmpe2401_platform_data stmpe_data = {
.gpio_base = U8500_NR_GPIO,
.irq = GPIO_TO_IRQ(217),
};
static struct av8100_platform_data av8100_plat_data = {
.irq = GPIO_TO_IRQ(192),
};
static struct stmpe1601_platform_data stmpe1601_data = {
.gpio_base = (U8500_NR_GPIO + 24), /* U8500_NR_GPIO GPIOs + 24 extended
GPIOs of STMPE2401*/
.irq = GPIO_TO_IRQ(218),
};
static struct tc35892_platform_data tc35892_data = {
.gpio_base = U8500_NR_GPIO,
.irq = GPIO_TO_IRQ(217),
};
static struct tc35893_platform_data tc35893_data = {
.kcode_tbl = (u8 *)kpd_lookup_tbl3,
.krow = TC_KPD_ROWS,
.kcol = TC_KPD_COLUMNS,
.debounce_period = TC_KPD_DEBOUNCE_PERIOD,
.settle_time = TC_KPD_SETTLE_TIME,
.irqtype = (IRQF_TRIGGER_FALLING),
.irq = GPIO_TO_IRQ(218),
.enable_wakeup = true,
#ifdef CONFIG_TC_KEYPAD_POLL
.op_mode = 1,
#elif CONFIG_TC_KEYPAD_INTR
.op_mode = 0,
#endif
};
static struct lp5521_platform_data lp5521_data = {
.mode = LP5521_MODE_DIRECT_CONTROL,
.label = "uib-led",
.red_present = true,
.green_present = true,
.blue_present = true,
};
static struct i2c_board_info __initdata nmdk_i2c0_egpio_devices[] = {
{
/* stmpe2401 @ 0x84(w),0x85(r) */
I2C_BOARD_INFO("stmpe2401", 0x42),
.platform_data = &stmpe_data,
}
};
static struct i2c_board_info __initdata nmdk_i2c0_egpio1_devices[] = {
{
I2C_BOARD_INFO("tc35892", 0x42),
.platform_data = &tc35892_data,
}
};
#if defined(CONFIG_TOUCHSCREEN_BU21013) || \
defined(CONFIG_TOUCHSCREEN_BU21013_MODULE)
/**
* Touch panel related platform specific initialization
*/
/**
* bu21013_gpio_board_init : configures the touch panel.
* @ext_clk_en: external clcok enable
* @reset_pin: reset pin number
* This function can be used to configures
* the voltage and reset the touch panel controller.
*/
static int bu21013_gpio_board_init(int reset_pin)
{
#ifndef CONFIG_REGULATOR
int val;
#endif
int retval = 0;
void __iomem *clk_base;
unsigned int clk_value;
static bool config_set;
#ifndef CONFIG_REGULATOR
/* Set the voltage for Bu21013 controller */
val = ab8500_read(AB8500_REGU_CTRL2, AB8500_REGU_VAUX12_REGU_REG);
retval = ab8500_write(AB8500_REGU_CTRL2, AB8500_REGU_VAUX12_REGU_REG,
(val | TSC_AVDD_AUX1_REGULATOR));
if (retval < 0)
return retval;
val = ab8500_read(AB8500_REGU_CTRL2, AB8500_REGU_VAUX1_SEL_REG);
retval = ab8500_write(AB8500_REGU_CTRL2, AB8500_REGU_VAUX1_SEL_REG,
TSC_AVDD_VOLTAGE_2_5);
if (retval < 0)
return retval;
#endif
if (!config_set) {
retval = stm_gpio_altfuncenable(GPIO_ALT_TP_SET_EXT_CLK);
if (retval < 0) {
printk(KERN_ERR "%s: gpio alternate failed\n",
__func__);
return retval;
}
clk_base = (void __iomem *)IO_ADDRESS(U8500_PRCMU_BASE +
PRCMU_CLOCK_OCR);
clk_value = readl(clk_base);
writel(TSC_EXT_CLOCK_9_6MHZ, clk_base);
}
if (platform_id == MOP500_PLATFORM_ID) {
retval = gpio_request(EGPIO_PIN_2, "touchp_egpio2");
if (retval) {
printk(KERN_ERR "Unable to request gpio EGPIO_PIN_2");
return retval;
}
gpio_set_value(EGPIO_PIN_2, 1);
} else if (platform_id == HREF_PLATFORM_ID) {
if (!config_set) {
retval = gpio_request(reset_pin, "touchp_reset");
if (retval) {
printk(KERN_ERR "Unable to request gpio reset_pin");
return retval;
}
retval = gpio_direction_output(reset_pin, 1);
if (retval < 0) {
printk(KERN_ERR "%s: gpio direction failed\n",
__func__);
return retval;
}
gpio_set_value(reset_pin, 1);
config_set = true;
}
}
return retval;
}
/**
* bu21013_gpio_board_exit : deconfigures the touch panel controller
* @reset_pin: reset pin number
* This function can be used to deconfigures the chip selection
* for touch panel controller.
*/
static int bu21013_gpio_board_exit(int reset_pin)
{
int retval = 0;
static bool config_disable_set;
if (platform_id == MOP500_PLATFORM_ID) {
gpio_set_value(EGPIO_PIN_2, 0);
} else if (platform_id == HREF_PLATFORM_ID) {
if (!config_disable_set) {
retval = gpio_direction_output(reset_pin, 0);
if (retval < 0) {
printk(KERN_ERR "%s: gpio direction failed\n",
__func__);
return retval;
}
gpio_set_value(reset_pin, 0);
config_disable_set = true;
}
}
return retval;
}
/**
* bu21013_init_irq : sets the callback for touch panel controller
* @parameter: function pointer for touch screen callback handler.
* @data: data to be passed for touch panel callback handler.
* This function can be used to set the callback handler for
* touch panel controller.
*/
static int bu21013_init_irq(void (*callback)(void *parameter), void *data)
{
int retval = 0;
if (platform_id == MOP500_PLATFORM_ID) {
retval = stmpe2401_set_callback(EGPIO_PIN_3, callback,
(void *)data);
if (retval < 0)
printk(KERN_ERR "%s: set callback failed\n", __func__);
} else if (platform_id == HREF_PLATFORM_ID) {
if (!href_v1_board) {
retval = tc35892_set_callback(EGPIO_PIN_12, callback,
(void *)data);
if (retval < 0)
printk(KERN_ERR "%s: set callback failed\n",
__func__);
retval = tc35892_set_gpio_intr_conf(EGPIO_PIN_12,
EDGE_SENSITIVE,
TC35892_FALLING_EDGE_OR_LOWLEVEL);
if (retval < 0)
printk(KERN_ERR "%s: config failed\n",
__func__);
}
}
return retval;
}
/**
* bu21013_exit_irq : removes the callback for touch panel controller
* This function can be used to removes the callback handler for
* touch panel controller.
*/
static int bu21013_exit_irq(void)
{
int retval = 0;
if (platform_id == MOP500_PLATFORM_ID) {
retval = stmpe2401_remove_callback(EGPIO_PIN_3);
if (retval < 0)
pr_err("%s: remove callback failed\n",
__func__);
} else if (platform_id == HREF_PLATFORM_ID) {
if (!href_v1_board) {
retval = tc35892_remove_callback(EGPIO_PIN_12);
if (retval < 0)
pr_err("%s: remove calllback failed\n",
__func__);
}
}
return retval;
}
/**
* bu21013_pen_down_irq_enable : enable the interrupt for touch panel controller
* This function can be used to enable the interrupt for touch panel controller.
*/
static int bu21013_pen_down_irq_enable(void)
{
int retval = 0;
if (platform_id == HREF_PLATFORM_ID) {
if (!href_v1_board) {
retval = tc35892_set_intr_enable(EGPIO_PIN_12,
ENABLE_INTERRUPT);
if (retval < 0)
printk(KERN_ERR "%s: failed\n", __func__);
}
}
return retval;
}
/**
* bu21013_pen_down_irq_disable : disable the interrupt
* This function can be used to disable the interrupt for
* touch panel controller.
*/
static int bu21013_pen_down_irq_disable(void)
{
int retval = 0;
if (platform_id == HREF_PLATFORM_ID) {
if (!href_v1_board) {
retval = tc35892_set_intr_enable(EGPIO_PIN_12,
DISABLE_INTERRUPT);
if (retval < 0)
printk(KERN_ERR "%s: failed\n", __func__);
}
}
return retval;
}
/**
* bu21013_read_pin_val : get the interrupt pin value
* This function can be used to get the interrupt pin value for touch panel
* controller.
*/
static int bu21013_read_pin_val(void)
{
int data = 0;
if (platform_id == MOP500_PLATFORM_ID)
data = gpio_get_value(EGPIO_PIN_3);
else if (platform_id == HREF_PLATFORM_ID) {
if (!href_v1_board)
data = gpio_get_value(EGPIO_PIN_12);
else
data = gpio_get_value(TOUCH_GPIO_PIN);
}
return data;
}
/**
* bu21013_board_href_v1 : update the href v1 flag
* This function can be used to update the board.
*/
static bool bu21013_board_check(void)
{
href_v1_board = false;
if (platform_id == HREF_PLATFORM_ID) {
if (!u8500_is_earlydrop()) {
if (gpio_get_value(TOUCH_GPIO_PIN) == 1)
href_v1_board = true;
}
}
return href_v1_board;
}
static struct bu21013_platform_device tsc_plat_device = {
.cs_en = bu21013_gpio_board_init,
.cs_dis = bu21013_gpio_board_exit,
.irq_init = bu21013_init_irq,
.irq_exit = bu21013_exit_irq,
.pirq_en = bu21013_pen_down_irq_enable,
.pirq_dis = bu21013_pen_down_irq_disable,
.pirq_read_val = bu21013_read_pin_val,
.board_check = bu21013_board_check,
.irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN),
.cs_pin = EGPIO_PIN_13,
.x_max_res = 480,
.y_max_res = 864,
.touch_x_max = TOUCH_XMAX,
.touch_y_max = TOUCH_YMAX,
#ifdef CONFIG_BU21013_TSC_CNTL1
.tp_cntl = 1,
#endif
};
static struct bu21013_platform_device tsc_cntl2_plat_device = {
.cs_en = bu21013_gpio_board_init,
.cs_dis = bu21013_gpio_board_exit,
.board_check = bu21013_board_check,
.pirq_read_val = bu21013_read_pin_val,
.irq = GPIO_TO_IRQ(TOUCH_GPIO_PIN),
.cs_pin = EGPIO_PIN_13,
.x_max_res = 480,
.y_max_res = 864,
.touch_x_max = TOUCH_XMAX,
.touch_y_max = TOUCH_YMAX,
#ifdef CONFIG_BU21013_TSC_CNTL2
.tp_cntl = 2,
#endif
};
#endif
/* Portrait */
#ifdef CONFIG_DISPLAY_GENERIC_DSI_PRIMARY
/* Rotation always on */
static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata = {
.register_irq = NULL,
.free_irq = NULL,
.axis_map_x = 0, /* Axis map for HREF ED, HREF v1 and mop500 */
.axis_map_y = 1,
.axis_map_z = 2,
.negative_x = 0,
.negative_y = 0,
.negative_z = 0,
};
#else /* Landsacpe */
static struct lsm303dlh_platform_data __initdata lsm303dlh_pdata = {
.register_irq = NULL,
.free_irq = NULL,
.axis_map_x = 1, /* Axis map for HREF ED, HREF v1 and mop500 */
.axis_map_y = 0,
.axis_map_z = 2,
.negative_x = 1,
.negative_y = 0,
.negative_z = 0,
};
#endif
static struct ab3550_platform_data ab3550_plf_data = {
.irq = {
.base = 0,
.count = 0,
},
.dev_data = {
},
.dev_data_sz = {
},
.init_settings = NULL,
.init_settings_sz = 0,
};
static struct i2c_board_info __initdata u8500_i2c0_devices[] = {
{
I2C_BOARD_INFO("stmpe1601", 0x40),
.platform_data = &stmpe1601_data,
},
{
/* TC35893 keypad */
I2C_BOARD_INFO("tc35893-kp", 0x44),
.platform_data = &tc35893_data,
},
{
I2C_BOARD_INFO("av8100", 0x70),
.platform_data = &av8100_plat_data,
},
{
/* FIXME - address TBD, TODO */
I2C_BOARD_INFO("uib-kpd", 0x45),
},
{
/* Audio step-up */
I2C_BOARD_INFO("tps61052", 0x33),
}
};
static struct i2c_board_info __initdata u8500_i2c1_devices[] = {
{
/* GPS - Address TBD, FIXME */
I2C_BOARD_INFO("gps", 0x68),
},
{
/* AB3550 */
I2C_BOARD_INFO("ab3550", 0x4A),
.irq = -1,
.platform_data = &ab3550_plf_data,
}
};
static struct i2c_board_info __initdata u8500_i2c2_devices[] = {
{
/* ST 3D accelerometer @ 0x3A(w),0x3B(r) */
I2C_BOARD_INFO("lis302dl", 0x1D),
},
{
/* ASAHI KASEI AK8974 magnetometer, addr TBD FIXME */
I2C_BOARD_INFO("ak8974", 0x1),
},
#if defined(CONFIG_ALS_BH1780GLI)
{
/* Rohm BH1780GLI ambient light sensor */
I2C_BOARD_INFO("bh1780gli", 0x29),
},
#endif
{
/* RGB LED driver, there are 1st and 2nd, TODO */
I2C_BOARD_INFO("lp5521", 0x33),
.platform_data = &lp5521_data,
},
{
/* LSM303DLH Accelerometer */
I2C_BOARD_INFO("lsm303dlh_a", 0x18),
.platform_data = &lsm303dlh_pdata,
},
{
/* LSM303DLH Magnetometer */
I2C_BOARD_INFO("lsm303dlh_m", 0x1E),
.platform_data = &lsm303dlh_pdata,
},
};
static struct i2c_board_info __initdata u8500_i2c3_devices[] = {
{
/* NFC - Address TBD, FIXME */
I2C_BOARD_INFO("nfc", 0x68),
},
#if defined(CONFIG_TOUCHSCREEN_BU21013) || \
defined(CONFIG_TOUCHSCREEN_BU21013_MODULE)
{
/* Touschscreen */
I2C_BOARD_INFO("bu21013_tp", 0x5C),
.platform_data = &tsc_plat_device,
},
{
/* Touschscreen */
I2C_BOARD_INFO("bu21013_tp", 0x5D),
.platform_data = &tsc_cntl2_plat_device,
},
#endif
};
#ifdef CONFIG_KEYPAD_U8500
#define DEBUG_KP(x)
/* #define DEBUG_KP(x) printk x */
/* Keypad platform specific code */
#ifdef CONFIG_U8500_KEYPAD_DEBUG
#define KEYPAD_NAME "KEYPAD"
#undef NMDK_DEBUG
#undef NMDK_DEBUG_PFX
#undef NMDK_DBG
#define NMDK_DEBUG CONFIG_U8500_KEYPAD_DEBUG
#define NMDK_DEBUG_PFX KEYPAD_NAME
#define NMDK_DBG KERN_ERR
#endif
/**
* Keypad related platform specific constants
* These values may be modified for fine tuning
*/
#define KPD_NB_ROWS 0xFF
#define KPD_NB_COLUMNS 0xFF
#define KEYPAD_DEBOUNCE_PERIOD_STUIB 64 /* Debounce time 64ms */
#define NB_SCAN_CYCLES 8
/* spinlock_t cr_lock = SPIN_LOCK_UNLOCKED; */
static DEFINE_SPINLOCK(cr_lock);
extern irqreturn_t u8500_kp_intrhandler(/*int irq,*/ void *dev_id);
extern struct mutex u8500_keymap_mutex;
extern u8 u8500_keymap; /* Default keymap is keymap 0 */
/**
* u8500_kp_results_autoscan : This function gets scanned key data from stmpe
* @keys : o/p parameter, returns keys pressed.
* This function can be used in both polling or interrupt usage.
*/
int u8500_kp_results_autoscan(struct keypad_t *kp)
{
int err;
t_stmpe1601_key_status keys;
u8 kcode, i;
static int keyp_cnt;
mutex_lock(&u8500_keymap_mutex);
if (u8500_keymap == 0)
kp->board->kcode_tbl = (u8 *) kpd_lookup_tbl1;
else if (u8500_keymap == 1)
kp->board->kcode_tbl = (u8 *) kpd_lookup_tbl2;
mutex_unlock(&u8500_keymap_mutex);
/**
* read key data from stmpe1601
*/
err = stmpe1601_keypressed(&keys);
if (keys.button_pressed) {
for (i = 0; i < keys.button_pressed; i++) {
kcode = kp->board->kcode_tbl[(keys.button[i] & 0x7) *
8 + ((keys.button[i] >> 3) & 0x7)];
input_report_key(kp->inp_dev, kcode, 1);
if (kcode == KEY_RESERVED)
printk(KERN_ERR "Error in key detection."
" Key not present");
DEBUG_KP(("\nkey (%d, %d)-->DOWN, kcode = %d",
(keys.button[i] >> 3) & 0x7,
(keys.button[i] & 0x7), kcode));
keyp_cnt++;
}
}
if (keys.button_released) {
for (i = 0; i < keys.button_released; i++) {
kcode = kp->board->kcode_tbl[(keys.released[i] & 0x7) *
8 + ((keys.released[i] >> 3) & 0x7)];
input_report_key(kp->inp_dev, kcode, 0);
if (kcode == KEY_RESERVED)
printk(KERN_ERR "Error in key detection."
" Key not present");
DEBUG_KP(("\nkey (%d, %d)-->UP, kcode = %d",
(keys.released[i] >> 3) & 0x7,
(keys.released[i] & 0x7), kcode));
keyp_cnt--;
}
}
if (keys.button_pressed || keys.button_released)
DEBUG_KP(("\nkp_results_autoscan keyp_cnt = %d, pressed = %d "
"released = %d\n",
keyp_cnt, keys.button_pressed, keys.button_released));
return keyp_cnt;
}
/**
* u8500_kp_intrhandler - keypad interrupt handler
* @dev_id : platform data
* checks for valid interrupt, disables interrupt to avoid any nested interrupt
* starts work queue for further key processing with debouncing logic
*/
irqreturn_t u8500_kp_intrhandler(/*int irq, */void *dev_id)
{
struct keypad_t *kp = (struct keypad_t *)dev_id;
/* printk("\n Kp interrupt"); */
/* if (irq != kp->irq) return IRQ_NONE; */
if (!(test_bit(KPINTR_LKBIT, &kp->lockbits))) {
set_bit(KPINTR_LKBIT, &kp->lockbits);
if (kp->board->irqdis_int)
kp->board->irqdis_int(kp);
/* schedule_delayed_work(&kp->kscan_work,
kp->board->debounce_period); */
schedule_delayed_work(&kp->kscan_work, 0);
}
return IRQ_HANDLED;
}
/**
* u8500_kp_init_key_hardware - keypad hardware initialization
* @kp keypad configuration for this platform
* Initializes the keypad hardware specific parameters.
* This function will be called by u8500_keypad_init function during init
* Initialize keypad interrupt handler for interrupt mode operation if enabled
* Initialize Keyscan matrix
*
*/
int u8500_kp_init_key_hardware(struct keypad_t *kp)
{
int err;
t_stmpe1601_key_config kpconfig;
DEBUG_KP(("u8500_kp_init_key_hardware\n"));
/*
* Check if stmpe1601 is initialised properly, otherwise exit from here
*/
err = stmpe1601_read_info();
if (err) {
printk(KERN_ERR "\n Error in keypad init, keypad controller"
"not initialised.");
return -EIO;
}
/* setup Columns GPIOs (inputs) */
kpconfig.columns = kp->board->kcol; /* 0xFF 8 columns */
kpconfig.rows = kp->board->krow; /* 0xFF 8 rows */
/* 8, number of cycles for key data updating */
kpconfig.ncycles = NB_SCAN_CYCLES;
/* de-bounce time 64 ms */
kpconfig.debounce = kp->board->debounce_period;
kpconfig.scan = STMPE1601_SCAN_OFF;
err = stmpe1601_keypad_init(kpconfig);
if (err)
printk(KERN_ERR "Couldn't setup keypad configuration\n");
if (!kp->mode) {
/*
* true if interrupt mode operation
*/
DEBUG_KP(("\nsetting up keypad interrupt & "
"enable keypad intr\n"));
err = stmpe1601_set_callback(kp->board->irq,
u8500_kp_intrhandler, (void *)kp);
if (err) {
printk(KERN_ERR "\nCouldn't setup keypad callback\n");
return err;
}
err = kp->board->irqen(kp);
if (err) {
printk(KERN_ERR "Couldn't enable the keypad "
"source interrupt\n");
return err;
}
}
err = stmpe1601_keypad_scan(STMPE1601_SCAN_ON);
if (err)
printk(KERN_ERR "Couldn't enable keypad scan\n");
return 0;
}
/**
* u8500_kp_exit_key_hardware- keypad hardware exit function
*
* This function will be called by u8500_keypad_exit function during module
* exit, frees keypad interrupt if enabled
*/
int u8500_kp_exit_key_hardware(struct keypad_t *kp)
{
int err;
DEBUG_KP(("nomadik_kp_exit_key_hardware\n"));
err = stmpe1601_keypad_scan(STMPE1601_SCAN_OFF);
if (err)
printk(KERN_ERR "Couldn't disable keypad scan\n");
if (!kp->mode) { /* true if interrupt mode operation */
err = kp->board->irqdis(kp);
if (err) {
printk(KERN_ERR "Couldn't disable keypad callback\n");
return err;
}
err = stmpe1601_remove_callback(kp->board->irq);
if (err) {
printk(KERN_ERR "Couldn't remove keypad callback\n");
return err;
}
}
return 0;
}
/**
* u8500_kp_key_irqdis- disables keypad interrupt
*
* disables keypad interrupt
*/
int u8500_kp_key_irqdis(struct keypad_t *kp)
{
unsigned long flags;
/* Enable KEYPAD interrupt of STMPE 1601 */
int err;
/* DEBUG_KP(("u8500_kp_key_irqdis\n")); */
err = stmpe1601_irqdis(kp->board->irq);
/* err = stmpe1601_intsrc_set_state(STMPE1601_0,
STMPE1601_KEYPAD_IRQ, STMPE1601_DISABLE_INTERRUPT );*/
if (err) {
printk(KERN_ERR "Error in disabling Keypad Interrupt.");
return err;
}
spin_lock_irqsave(&cr_lock, flags);
kp->board->int_status = KP_INT_DISABLED;
spin_unlock_irqrestore(&cr_lock, flags);
return 0;
}
/**
* u8500_kp_key_irqen- enables keypad interrupt
*
* enables keypad interrupt
*/
int u8500_kp_key_irqen(struct keypad_t *kp)
{
unsigned long flags;
/* Enable KEYPAD interrupt of STMPE 1601*/
int err;
/* DEBUG_KP(("u8500_kp_key_irqen\n")); */
err = stmpe1601_irqen(kp->board->irq);
/* err = stmpe1601_intsrc_set_state(STMPE1601_0, STMPE1601_KEYPAD_IRQ,
STMPE1601_ENABLE_INTERRUPT ); */
if (err)
printk(KERN_ERR "Error in enabling Keypad Interrupt.= %d", err);
spin_lock_irqsave(&cr_lock, flags);
kp->board->int_status = KP_INT_ENABLED;
spin_unlock_irqrestore(&cr_lock, flags);
return 0;
}
static struct keypad_device keypad_board = {
.init = u8500_kp_init_key_hardware,
.exit = u8500_kp_exit_key_hardware,
.irqen = u8500_kp_key_irqen,
.irqdis_int = u8500_kp_key_irqdis,
/* .irqdis = u8500_kp_key_irqdis, */
/* .autoscan_disable = u8500_kp_disable_autoscan, */
.autoscan_results = u8500_kp_results_autoscan,
/* .autoscan_en=u8500_kp_autoscan_en, */
.kcode_tbl = (u8 *) kpd_lookup_tbl1,
.krow = KPD_NB_ROWS,
.kcol = KPD_NB_COLUMNS,
.debounce_period = KEYPAD_DEBOUNCE_PERIOD_STUIB,
.irqtype = 0,
.irq = KEYPAD_INT,
/* .irq=GPIO_TO_IRQ(KEYPAD_INT), */
.int_status = KP_INT_DISABLED,
.int_line_behaviour = INT_LINE_NOTSET,
.enable_wakeup = true,
};
static struct resource keypad_resources[] = {
[0] = {
.start = KEYPAD_INT,
.end = KEYPAD_INT,
.flags = IORESOURCE_IRQ,
},
};
static struct platform_device keypad_device = {
.name = "u8500-kp",
.id = 0,
.dev = {
.platform_data = &keypad_board,
},
.num_resources = ARRAY_SIZE(keypad_resources),
.resource = keypad_resources,
};
#endif /* CONFIG_KEYPAD_U8500 */
#ifdef CONFIG_SENSORS1P_MOP
static struct sensors1p_config sensors1p_config = {
/* SFH7741 */
.proximity = {
.pin = EGPIO_PIN_7,
.startup_time = 120, /* ms */
.regulator = "v-proximity",
},
/* HED54XXU11 */
.hal = {
.pin = EGPIO_PIN_8,
.startup_time = 100, /* Actually, I have no clue. */
.regulator = "v-hal",
},
};
struct platform_device sensors1p_device = {
.name = "sensors1p",
.dev = {
.platform_data = (void *)&sensors1p_config,
},
};
#endif
static struct i2s_board_info stm_i2s_board_info[] __initdata = {
{
.modalias = "i2s_device.0",
.platform_data = NULL,
.id = (MSP_0_CONTROLLER - 1),
.chip_select = 0,
},
{
.modalias = "i2s_device.1",
.platform_data = NULL,
.id = (MSP_1_CONTROLLER - 1),
.chip_select = 1,
},
{
/*
* XXX mop500_devices.c did not have this originally, and this
* was in device.c. Required?
*/
.modalias = "i2s_device.2",
.platform_data = NULL, /* can be fill some data */
.id = (MSP_2_CONTROLLER - 1),
.chip_select = 2,
}
};
#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
static struct nmk_i2c_controller u8500_i2c_##id = { \
/* \
* slave data setup time, which is \
* 250 ns,100ns,10ns which is 14,6,2 \
* respectively for a 48 Mhz \
* i2c clock \
*/ \
.slsu = _slsu, \
/* Tx FIFO threshold */ \
.tft = _tft, \
/* Rx FIFO threshold */ \
.rft = _rft, \
/* std. mode operation */ \
.clk_freq = clk, \
.sm = _sm, \
}
/*
* The board uses 4 i2c controllers, initialize all of
* them with slave data setup time of 250 ns,
* Tx & Rx FIFO threshold values as 1 and standard
* mode of operation
*/
U8500_I2C_CONTROLLER(0, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
U8500_I2C_CONTROLLER(4, 0xe, 1, 1, 400000, I2C_FREQ_MODE_FAST);
static struct hsi_board_info __initdata stm_hsi_devices[] = {
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
.chan_num = 0, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
.chan_num = 0, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
.chan_num = 1, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
.chan_num = 1, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
.chan_num = 2, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
.chan_num = 2, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 0,
.chan_num = 3, .mode = 1},
{.type = "HSI_LOOPBACK", .flags = 0, .controller_id = 1,
.chan_num = 3, .mode = 1},
};
static struct platform_device ab8500_gpadc_device = {
.name = "ab8500_gpadc"
};
static struct ab8500_bm_platform_data ab8500_bm_plat_data = {
.bat_type = {
{POWER_SUPPLY_TECHNOLOGY_LION, BATTERY_NOKIA_BL_5F},
{POWER_SUPPLY_TECHNOLOGY_LIPO, BATTERY_NOKIA_BP_5M},
},
.termination_vol = 4200,
.op_cur_lvl = CH_OP_CUR_LVL_0P9,
.ip_vol_lvl = CH_VOL_LVL_4P2,
};
static struct platform_device ab8500_bm_device = {
.name = "ab8500_bm",
.dev = {
.platform_data = &ab8500_bm_plat_data,
},
};
/* Force feedback vibrator device */
static struct platform_device ste_ff_vibra_device = {
.name = "ste_ff_vibra"
};
static struct platform_device *u8500_platform_devices[] __initdata = {
/*TODO - add platform devices here */
#ifdef CONFIG_KEYPAD_U8500
&keypad_device,
#endif
#ifdef CONFIG_SENSORS1P_MOP
&sensors1p_device,
#endif
};
static struct amba_device *amba_board_devs[] __initdata = {
&ux500_uart0_device,
&ux500_uart1_device,
&ux500_uart2_device,
&u8500_ssp0_device,
&u8500_ssp1_device,
&ux500_spi0_device,
&u8500_msp2_spi_device,
};
/* LED device for LCD backlight */
/* LCD backlight in LED device framework */
static struct platform_device u8500_leds_controller = {
.name = "ab8500-leds",
.id = 0,
};
static struct platform_device *platform_board_devs[] __initdata = {
&u8500_msp0_device,
&u8500_msp1_device,
&u8500_msp2_device,
&u8500_hsit_device,
&u8500_hsir_device,
&u8500_shrm_device,
&u8500_ab8500_device,
&ab8500_gpadc_device,
&ab8500_bm_device,
&ste_ff_vibra_device,
&ux500_musb_device,
&ux500_mcde_device,
&ux500_b2r2_device,
#ifdef CONFIG_ANDROID_PMEM
&u8500_pmem_device,
&u8500_pmem_mio_device,
&u8500_pmem_hwb_device,
#endif
#ifdef CONFIG_CRYPTO_DEV_UX500_HASH
&ux500_hash1_device,
#endif
&u8500_leds_controller,
#ifdef CONFIG_KEYPAD_SKE
&ske_keypad_device,
#endif
};
static void __init mop500_platdata_init(void)
{
}
static void __init mop500_i2c_init(void)
{
u8500_register_device(&u8500_i2c0_device, &u8500_i2c_0);
u8500_register_device(&ux500_i2c_controller1, &u8500_i2c_1);
u8500_register_device(&ux500_i2c_controller2, &u8500_i2c_2);
u8500_register_device(&ux500_i2c_controller3, &u8500_i2c_3);
if (!u8500_is_earlydrop())
u8500_register_device(&u8500_i2c4_device, &u8500_i2c_4);
}
static void __init mop500_init_machine(void)
{
stm_gpio_set_altfunctable(gpio_altfun_table,
ARRAY_SIZE(gpio_altfun_table));
#ifdef CONFIG_REGULATOR
u8500_init_regulators();
#endif
u8500_init_devices();
nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins));
mop500_platdata_init();
amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs));
platform_add_devices(platform_board_devs, ARRAY_SIZE(platform_board_devs));
mop500_i2c_init();
/* enable RTC as a wakeup capable */
device_init_wakeup(&ux500_rtc_device.dev, true);
stm_gpio_altfuncenable(GPIO_ALT_UART_0_NO_MODEM);
stm_gpio_altfuncenable(GPIO_ALT_UART_1);
stm_gpio_altfuncenable(GPIO_ALT_UART_2);
if (MOP500_PLATFORM_ID == platform_id)
i2c_register_board_info(0, nmdk_i2c0_egpio_devices,
ARRAY_SIZE(nmdk_i2c0_egpio_devices));
else if (HREF_PLATFORM_ID == platform_id)
i2c_register_board_info(0, nmdk_i2c0_egpio1_devices,
ARRAY_SIZE(nmdk_i2c0_egpio1_devices));
i2c_register_board_info(0, u8500_i2c0_devices,
ARRAY_SIZE(u8500_i2c0_devices));
i2c_register_board_info(1, u8500_i2c1_devices,
ARRAY_SIZE(u8500_i2c1_devices));
i2c_register_board_info(2, u8500_i2c2_devices,
ARRAY_SIZE(u8500_i2c2_devices));
i2c_register_board_info(3, u8500_i2c3_devices,
ARRAY_SIZE(u8500_i2c3_devices));
i2s_register_board_info(stm_i2s_board_info,
ARRAY_SIZE(stm_i2s_board_info));
hsi_register_board_info(stm_hsi_devices, ARRAY_SIZE(stm_hsi_devices));
platform_add_devices(u8500_platform_devices,
ARRAY_SIZE(u8500_platform_devices));
/* enable the STMPE as wakeup capable in deepsleep */
set_irq_type(stmpe1601_data.irq, IRQ_TYPE_EDGE_BOTH);
set_irq_wake(stmpe1601_data.irq, true);
}
static int __init u8500_i2call_init(void)
{
/* Enable pullups for UART Rx lines. */
nmk_gpio_set_pull(2, NMK_GPIO_PULL_UP);
nmk_gpio_set_pull(4, NMK_GPIO_PULL_UP);
nmk_gpio_set_pull(29, NMK_GPIO_PULL_UP);
return 0;
}
subsys_initcall(u8500_i2call_init);
MACHINE_START(U8500, "ST-Ericsson U8500 Platform")
/* Maintainer: ST-Ericsson */
.phys_io = UX500_UART2_BASE,
.io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
.boot_params = 0x00000100,
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
.timer = &u8500_timer,
.init_machine = mop500_init_machine,
MACHINE_END
MACHINE_START(NOMADIK, "ST-Ericsson U8500 Platform")
/* Maintainer: ST-Ericsson */
.phys_io = UX500_UART2_BASE,
.io_pg_offst = (IO_ADDRESS(UX500_UART2_BASE) >> 18) & 0xfffc,
.boot_params = 0x00000100,
.map_io = u8500_map_io,
.init_irq = ux500_init_irq,
.timer = &u8500_timer,
.init_machine = mop500_init_machine,
MACHINE_END