Commit cde9efef authored by Russell King's avatar Russell King

Merge branch 'ux500-core' of...

Merge branch 'ux500-core' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson into devel-stable
parents 50401d77 60ebe156
...@@ -798,6 +798,7 @@ config ARCH_U8500 ...@@ -798,6 +798,7 @@ config ARCH_U8500
select GENERIC_CLOCKEVENTS select GENERIC_CLOCKEVENTS
select COMMON_CLKDEV select COMMON_CLKDEV
select ARCH_REQUIRE_GPIOLIB select ARCH_REQUIRE_GPIOLIB
select ARCH_HAS_CPUFREQ
help help
Support for ST-Ericsson's Ux500 architecture Support for ST-Ericsson's Ux500 architecture
......
...@@ -2,14 +2,16 @@ ...@@ -2,14 +2,16 @@
# Makefile for the linux kernel, U8500 machine. # Makefile for the linux kernel, U8500 machine.
# #
obj-y := clock.o cpu.o devices.o obj-y := clock.o cpu.o devices.o devices-common.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o dma-db5500.o
obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o obj-$(CONFIG_UX500_SOC_DB8500) += cpu-db8500.o devices-db8500.o prcmu.o
obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o \
obj-$(CONFIG_MACH_U5500) += board-u5500.o board-mop500-keypads.o
obj-$(CONFIG_MACH_U5500) += board-u5500.o board-u5500-sdi.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox.o obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Keypad layouts for various boards
*/
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/mfd/stmpe.h>
#include <linux/mfd/tc3589x.h>
#include <linux/input/matrix_keypad.h>
#include <plat/pincfg.h>
#include <plat/ske.h>
#include <mach/devices.h>
#include <mach/hardware.h>
#include "devices-db8500.h"
#include "board-mop500.h"
/* STMPE/SKE keypad use this key layout */
static const unsigned int mop500_keymap[] = {
KEY(2, 5, KEY_END),
KEY(4, 1, KEY_POWER),
KEY(3, 5, KEY_VOLUMEDOWN),
KEY(1, 3, KEY_3),
KEY(5, 2, KEY_RIGHT),
KEY(5, 0, KEY_9),
KEY(0, 5, KEY_MENU),
KEY(7, 6, KEY_ENTER),
KEY(4, 5, KEY_0),
KEY(6, 7, KEY_2),
KEY(3, 4, KEY_UP),
KEY(3, 3, KEY_DOWN),
KEY(6, 4, KEY_SEND),
KEY(6, 2, KEY_BACK),
KEY(4, 2, KEY_VOLUMEUP),
KEY(5, 5, KEY_1),
KEY(4, 3, KEY_LEFT),
KEY(3, 2, KEY_7),
};
static const struct matrix_keymap_data mop500_keymap_data = {
.keymap = mop500_keymap,
.keymap_size = ARRAY_SIZE(mop500_keymap),
};
/*
* Nomadik SKE keypad
*/
#define ROW_PIN_I0 164
#define ROW_PIN_I1 163
#define ROW_PIN_I2 162
#define ROW_PIN_I3 161
#define ROW_PIN_I4 156
#define ROW_PIN_I5 155
#define ROW_PIN_I6 154
#define ROW_PIN_I7 153
#define COL_PIN_O0 168
#define COL_PIN_O1 167
#define COL_PIN_O2 166
#define COL_PIN_O3 165
#define COL_PIN_O4 160
#define COL_PIN_O5 159
#define COL_PIN_O6 158
#define COL_PIN_O7 157
#define SKE_KPD_MAX_ROWS 8
#define SKE_KPD_MAX_COLS 8
static int ske_kp_rows[] = {
ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
};
/*
* ske_set_gpio_row: request and set gpio rows
*/
static int ske_set_gpio_row(int gpio)
{
int ret;
ret = gpio_request(gpio, "ske-kp");
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio request failed\n");
return ret;
}
ret = gpio_direction_output(gpio, 1);
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio direction failed\n");
gpio_free(gpio);
}
return ret;
}
/*
* ske_kp_init - enable the gpio configuration
*/
static int ske_kp_init(void)
{
int ret, i;
for (i = 0; i < SKE_KPD_MAX_ROWS; i++) {
ret = ske_set_gpio_row(ske_kp_rows[i]);
if (ret < 0) {
pr_err("ske_kp_init: failed init\n");
return ret;
}
}
return 0;
}
static struct ske_keypad_platform_data ske_keypad_board = {
.init = ske_kp_init,
.keymap_data = &mop500_keymap_data,
.no_autorepeat = true,
.krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
.kcol = SKE_KPD_MAX_COLS,
.debounce_ms = 40, /* in millisecs */
};
/*
* STMPE1601
*/
static struct stmpe_keypad_platform_data stmpe1601_keypad_data = {
.debounce_ms = 64,
.scan_count = 8,
.no_autorepeat = true,
.keymap_data = &mop500_keymap_data,
};
static struct stmpe_platform_data stmpe1601_data = {
.id = 1,
.blocks = STMPE_BLOCK_KEYPAD,
.irq_trigger = IRQF_TRIGGER_FALLING,
.irq_base = MOP500_STMPE1601_IRQ(0),
.keypad = &stmpe1601_keypad_data,
.autosleep = true,
.autosleep_timeout = 1024,
};
static struct i2c_board_info mop500_i2c0_devices_stuib[] = {
{
I2C_BOARD_INFO("stmpe1601", 0x40),
.irq = NOMADIK_GPIO_TO_IRQ(218),
.platform_data = &stmpe1601_data,
.flags = I2C_CLIENT_WAKE,
},
};
/*
* TC35893
*/
static const unsigned int uib_keymap[] = {
KEY(3, 1, KEY_END),
KEY(4, 1, KEY_POWER),
KEY(6, 4, KEY_VOLUMEDOWN),
KEY(4, 2, KEY_EMAIL),
KEY(3, 3, KEY_RIGHT),
KEY(2, 5, KEY_BACKSPACE),
KEY(6, 7, KEY_MENU),
KEY(5, 0, KEY_ENTER),
KEY(4, 3, KEY_0),
KEY(3, 4, KEY_DOT),
KEY(5, 2, KEY_UP),
KEY(3, 5, KEY_DOWN),
KEY(4, 5, KEY_SEND),
KEY(0, 5, KEY_BACK),
KEY(6, 2, KEY_VOLUMEUP),
KEY(1, 3, KEY_SPACE),
KEY(7, 6, KEY_LEFT),
KEY(5, 5, KEY_SEARCH),
};
static struct matrix_keymap_data uib_keymap_data = {
.keymap = uib_keymap,
.keymap_size = ARRAY_SIZE(uib_keymap),
};
static struct tc3589x_keypad_platform_data tc35893_data = {
.krow = TC_KPD_ROWS,
.kcol = TC_KPD_COLUMNS,
.debounce_period = TC_KPD_DEBOUNCE_PERIOD,
.settle_time = TC_KPD_SETTLE_TIME,
.irqtype = IRQF_TRIGGER_FALLING,
.enable_wakeup = true,
.keymap_data = &uib_keymap_data,
.no_autorepeat = true,
};
static struct tc3589x_platform_data tc3589x_keypad_data = {
.block = TC3589x_BLOCK_KEYPAD,
.keypad = &tc35893_data,
.irq_base = MOP500_EGPIO_IRQ_BASE,
};
static struct i2c_board_info mop500_i2c0_devices_uib[] = {
{
I2C_BOARD_INFO("tc3589x", 0x44),
.platform_data = &tc3589x_keypad_data,
.irq = NOMADIK_GPIO_TO_IRQ(218),
.flags = I2C_CLIENT_WAKE,
},
};
void mop500_keypad_init(void)
{
db8500_add_ske_keypad(&ske_keypad_board);
i2c_register_board_info(0, mop500_i2c0_devices_stuib,
ARRAY_SIZE(mop500_i2c0_devices_stuib));
i2c_register_board_info(0, mop500_i2c0_devices_uib,
ARRAY_SIZE(mop500_i2c0_devices_uib));
}
...@@ -16,10 +16,24 @@ ...@@ -16,10 +16,24 @@
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include "devices-db8500.h"
#include "pins-db8500.h" #include "pins-db8500.h"
#include "board-mop500.h" #include "board-mop500.h"
static pin_cfg_t mop500_sdi_pins[] = { static pin_cfg_t mop500_sdi_pins[] = {
/* SDI0 (MicroSD slot) */
GPIO18_MC0_CMDDIR,
GPIO19_MC0_DAT0DIR,
GPIO20_MC0_DAT2DIR,
GPIO21_MC0_DAT31DIR,
GPIO22_MC0_FBCLK,
GPIO23_MC0_CLK,
GPIO24_MC0_CMD,
GPIO25_MC0_DAT0,
GPIO26_MC0_DAT1,
GPIO27_MC0_DAT2,
GPIO28_MC0_DAT3,
/* SDI4 (on-board eMMC) */ /* SDI4 (on-board eMMC) */
GPIO197_MC4_DAT3, GPIO197_MC4_DAT3,
GPIO198_MC4_DAT2, GPIO198_MC4_DAT2,
...@@ -49,6 +63,55 @@ static pin_cfg_t mop500_sdi2_pins[] = { ...@@ -49,6 +63,55 @@ static pin_cfg_t mop500_sdi2_pins[] = {
GPIO138_MC2_DAT7, GPIO138_MC2_DAT7,
}; };
/*
* SDI 0 (MicroSD slot)
*/
/* MMCIPOWER bits */
#define MCI_DATA2DIREN (1 << 2)
#define MCI_CMDDIREN (1 << 3)
#define MCI_DATA0DIREN (1 << 4)
#define MCI_DATA31DIREN (1 << 5)
#define MCI_FBCLKEN (1 << 7)
static u32 mop500_sdi0_vdd_handler(struct device *dev, unsigned int vdd,
unsigned char power_mode)
{
if (power_mode == MMC_POWER_UP)
gpio_set_value_cansleep(GPIO_SDMMC_EN, 1);
else if (power_mode == MMC_POWER_OFF)
gpio_set_value_cansleep(GPIO_SDMMC_EN, 0);
return MCI_FBCLKEN | MCI_CMDDIREN | MCI_DATA0DIREN |
MCI_DATA2DIREN | MCI_DATA31DIREN;
}
static struct mmci_platform_data mop500_sdi0_data = {
.vdd_handler = mop500_sdi0_vdd_handler,
.ocr_mask = MMC_VDD_29_30,
.f_max = 100000000,
.capabilities = MMC_CAP_4_BIT_DATA,
.gpio_cd = GPIO_SDMMC_CD,
.gpio_wp = -1,
};
void mop500_sdi_tc35892_init(void)
{
int ret;
ret = gpio_request(GPIO_SDMMC_EN, "SDMMC_EN");
if (!ret)
ret = gpio_request(GPIO_SDMMC_1V8_3V_SEL,
"GPIO_SDMMC_1V8_3V_SEL");
if (ret)
return;
gpio_direction_output(GPIO_SDMMC_1V8_3V_SEL, 1);
gpio_direction_output(GPIO_SDMMC_EN, 0);
db8500_add_sdi0(&mop500_sdi0_data);
}
/* /*
* SDI 2 (POP eMMC, not on DB8500ed) * SDI 2 (POP eMMC, not on DB8500ed)
*/ */
...@@ -74,18 +137,24 @@ static struct mmci_platform_data mop500_sdi4_data = { ...@@ -74,18 +137,24 @@ static struct mmci_platform_data mop500_sdi4_data = {
.gpio_wp = -1, .gpio_wp = -1,
}; };
void mop500_sdi_init(void) void __init mop500_sdi_init(void)
{ {
nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins)); nmk_config_pins(mop500_sdi_pins, ARRAY_SIZE(mop500_sdi_pins));
u8500_sdi2_device.dev.platform_data = &mop500_sdi2_data; /*
u8500_sdi4_device.dev.platform_data = &mop500_sdi4_data; * sdi0 will finally be added when the TC35892 initializes and calls
* mop500_sdi_tc35892_init() above.
*/
/* PoP:ed eMMC */
if (!cpu_is_u8500ed()) { if (!cpu_is_u8500ed()) {
nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins)); nmk_config_pins(mop500_sdi2_pins, ARRAY_SIZE(mop500_sdi2_pins));
amba_device_register(&u8500_sdi2_device, &iomem_resource); /* POP eMMC on v1.0 has problems with high speed */
if (!cpu_is_u8500v10())
mop500_sdi2_data.capabilities |= MMC_CAP_MMC_HIGHSPEED;
db8500_add_sdi2(&mop500_sdi2_data);
} }
/* On-board eMMC */ /* On-board eMMC */
amba_device_register(&u8500_sdi4_device, &iomem_resource); db8500_add_sdi4(&mop500_sdi4_data);
} }
...@@ -13,25 +13,26 @@ ...@@ -13,25 +13,26 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/amba/pl022.h> #include <linux/amba/pl022.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/mfd/ab8500.h> #include <linux/mfd/ab8500.h>
#include <linux/input/matrix_keypad.h> #include <linux/mfd/tc3589x.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <plat/pincfg.h> #include <plat/pincfg.h>
#include <plat/i2c.h> #include <plat/i2c.h>
#include <plat/ske.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/setup.h> #include <mach/setup.h>
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include "devices-db8500.h"
#include "pins-db8500.h" #include "pins-db8500.h"
#include "board-mop500.h" #include "board-mop500.h"
...@@ -69,22 +70,12 @@ static pin_cfg_t mop500_pins[] = { ...@@ -69,22 +70,12 @@ static pin_cfg_t mop500_pins[] = {
GPIO166_KP_O2, GPIO166_KP_O2,
GPIO167_KP_O1, GPIO167_KP_O1,
GPIO168_KP_O0, GPIO168_KP_O0,
};
static void ab4500_spi_cs_control(u32 command) /* GPIO_EXP_INT */
{ GPIO217_GPIO,
/* set the FRM signal, which is CS - TODO */
}
struct pl022_config_chip ab4500_chip_info = { /* STMPE1601 IRQ */
.com_mode = INTERRUPT_TRANSFER, GPIO218_GPIO | PIN_INPUT_PULLUP,
.iface = SSP_INTERFACE_MOTOROLA_SPI,
/* we can act as master only */
.hierarchy = SSP_MASTER,
.slave_tx_disable = 0,
.rx_lev_trig = SSP_RX_1_OR_MORE_ELEM,
.tx_lev_trig = SSP_TX_1_OR_MORE_EMPTY_LOC,
.cs_control = ab4500_spi_cs_control,
}; };
static struct ab8500_platform_data ab8500_platdata = { static struct ab8500_platform_data ab8500_platdata = {
...@@ -93,8 +84,8 @@ static struct ab8500_platform_data ab8500_platdata = { ...@@ -93,8 +84,8 @@ static struct ab8500_platform_data ab8500_platdata = {
static struct resource ab8500_resources[] = { static struct resource ab8500_resources[] = {
[0] = { [0] = {
.start = IRQ_AB8500, .start = IRQ_DB8500_AB8500,
.end = IRQ_AB8500, .end = IRQ_DB8500_AB8500,
.flags = IORESOURCE_IRQ .flags = IORESOURCE_IRQ
} }
}; };
...@@ -109,19 +100,6 @@ struct platform_device ab8500_device = { ...@@ -109,19 +100,6 @@ struct platform_device ab8500_device = {
.resource = ab8500_resources, .resource = ab8500_resources,
}; };
static struct spi_board_info ab8500_spi_devices[] = {
{
.modalias = "ab8500-spi",
.controller_data = &ab4500_chip_info,
.platform_data = &ab8500_platdata,
.max_speed_hz = 12000000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_3,
.irq = IRQ_DB8500_AB8500,
},
};
static struct pl022_ssp_controller ssp0_platform_data = { static struct pl022_ssp_controller ssp0_platform_data = {
.bus_id = 0, .bus_id = 0,
/* pl022 not yet supports dma */ /* pl022 not yet supports dma */
...@@ -132,6 +110,34 @@ static struct pl022_ssp_controller ssp0_platform_data = { ...@@ -132,6 +110,34 @@ static struct pl022_ssp_controller ssp0_platform_data = {
.num_chipselect = 5, .num_chipselect = 5,
}; };
/*
* TC35892
*/
static void mop500_tc35892_init(struct tc3589x *tc3589x, unsigned int base)
{
mop500_sdi_tc35892_init();
}
static struct tc3589x_gpio_platform_data mop500_tc35892_gpio_data = {
.gpio_base = MOP500_EGPIO(0),
.setup = mop500_tc35892_init,
};
static struct tc3589x_platform_data mop500_tc35892_data = {
.block = TC3589x_BLOCK_GPIO,
.gpio = &mop500_tc35892_gpio_data,
.irq_base = MOP500_EGPIO_IRQ_BASE,
};
static struct i2c_board_info mop500_i2c0_devices[] = {
{
I2C_BOARD_INFO("tc3589x", 0x42),
.irq = NOMADIK_GPIO_TO_IRQ(217),
.platform_data = &mop500_tc35892_data,
},
};
#define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \ #define U8500_I2C_CONTROLLER(id, _slsu, _tft, _rft, clk, _sm) \
static struct nmk_i2c_controller u8500_i2c##id##_data = { \ static struct nmk_i2c_controller u8500_i2c##id##_data = { \
/* \ /* \
...@@ -161,159 +167,49 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); ...@@ -161,159 +167,49 @@ U8500_I2C_CONTROLLER(1, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(2, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD); U8500_I2C_CONTROLLER(3, 0xe, 1, 1, 100000, I2C_FREQ_MODE_STANDARD);
static struct amba_device *amba_devs[] __initdata = { static void __init mop500_i2c_init(void)
&ux500_uart0_device, {
&ux500_uart1_device, db8500_add_i2c0(&u8500_i2c0_data);
&ux500_uart2_device, db8500_add_i2c1(&u8500_i2c1_data);
&u8500_ssp0_device, db8500_add_i2c2(&u8500_i2c2_data);
}; db8500_add_i2c3(&u8500_i2c3_data);
}
static const unsigned int ux500_keymap[] = {
KEY(2, 5, KEY_END),
KEY(4, 1, KEY_POWER),
KEY(3, 5, KEY_VOLUMEDOWN),
KEY(1, 3, KEY_3),
KEY(5, 2, KEY_RIGHT),
KEY(5, 0, KEY_9),
KEY(0, 5, KEY_MENU),
KEY(7, 6, KEY_ENTER),
KEY(4, 5, KEY_0),
KEY(6, 7, KEY_2),
KEY(3, 4, KEY_UP),
KEY(3, 3, KEY_DOWN),
KEY(6, 4, KEY_SEND),
KEY(6, 2, KEY_BACK),
KEY(4, 2, KEY_VOLUMEUP),
KEY(5, 5, KEY_1),
KEY(4, 3, KEY_LEFT),
KEY(3, 2, KEY_7),
};
static const struct matrix_keymap_data ux500_keymap_data = {
.keymap = ux500_keymap,
.keymap_size = ARRAY_SIZE(ux500_keymap),
};
/* /* add any platform devices here - TODO */
* Nomadik SKE keypad static struct platform_device *platform_devs[] __initdata = {
*/
#define ROW_PIN_I0 164
#define ROW_PIN_I1 163
#define ROW_PIN_I2 162
#define ROW_PIN_I3 161
#define ROW_PIN_I4 156
#define ROW_PIN_I5 155
#define ROW_PIN_I6 154
#define ROW_PIN_I7 153
#define COL_PIN_O0 168
#define COL_PIN_O1 167
#define COL_PIN_O2 166
#define COL_PIN_O3 165
#define COL_PIN_O4 160
#define COL_PIN_O5 159
#define COL_PIN_O6 158
#define COL_PIN_O7 157
#define SKE_KPD_MAX_ROWS 8
#define SKE_KPD_MAX_COLS 8
static int ske_kp_rows[] = {
ROW_PIN_I0, ROW_PIN_I1, ROW_PIN_I2, ROW_PIN_I3,
ROW_PIN_I4, ROW_PIN_I5, ROW_PIN_I6, ROW_PIN_I7,
}; };
/* static void __init mop500_spi_init(void)
* ske_set_gpio_row: request and set gpio rows
*/
static int ske_set_gpio_row(int gpio)
{ {
int ret; db8500_add_ssp0(&ssp0_platform_data);
ret = gpio_request(gpio, "ske-kp");
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio request failed\n");
return ret;
}
ret = gpio_direction_output(gpio, 1);
if (ret < 0) {
pr_err("ske_set_gpio_row: gpio direction failed\n");
gpio_free(gpio);
}
return ret;
} }
/* static void __init mop500_uart_init(void)
* ske_kp_init - enable the gpio configuration
*/
static int ske_kp_init(void)
{ {
int ret, i; db8500_add_uart0();
db8500_add_uart1();
for (i = 0; i < SKE_KPD_MAX_ROWS; i++) { db8500_add_uart2();
ret = ske_set_gpio_row(ske_kp_rows[i]);
if (ret < 0) {
pr_err("ske_kp_init: failed init\n");
return ret;
}
}
return 0;
} }
static struct ske_keypad_platform_data ske_keypad_board = {
.init = ske_kp_init,
.keymap_data = &ux500_keymap_data,
.no_autorepeat = true,
.krow = SKE_KPD_MAX_ROWS, /* 8x8 matrix */
.kcol = SKE_KPD_MAX_COLS,
.debounce_ms = 40, /* in millsecs */
};
/* add any platform devices here - TODO */
static struct platform_device *platform_devs[] __initdata = {
&u8500_i2c0_device,
&ux500_i2c1_device,
&ux500_i2c2_device,
&ux500_i2c3_device,
&ux500_ske_keypad_device,
};
static void __init u8500_init_machine(void) static void __init u8500_init_machine(void)
{ {
int i;
u8500_init_devices(); u8500_init_devices();
nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins)); nmk_config_pins(mop500_pins, ARRAY_SIZE(mop500_pins));
u8500_i2c0_device.dev.platform_data = &u8500_i2c0_data;
ux500_i2c1_device.dev.platform_data = &u8500_i2c1_data;
ux500_i2c2_device.dev.platform_data = &u8500_i2c2_data;
ux500_i2c3_device.dev.platform_data = &u8500_i2c3_data;
ux500_ske_keypad_device.dev.platform_data = &ske_keypad_board;
u8500_ssp0_device.dev.platform_data = &ssp0_platform_data;
/* Register the active AMBA devices on this board */
for (i = 0; i < ARRAY_SIZE(amba_devs); i++)
amba_device_register(amba_devs[i], &iomem_resource);
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
mop500_i2c_init();
mop500_sdi_init(); mop500_sdi_init();
mop500_spi_init();
mop500_uart_init();
mop500_keypad_init();
/* If HW is early drop (ED) or V1.0 then use SPI to access AB8500 */
if (cpu_is_u8500ed() || cpu_is_u8500v10())
spi_register_board_info(ab8500_spi_devices,
ARRAY_SIZE(ab8500_spi_devices));
else /* If HW is v.1.1 or later use I2C to access AB8500 */
platform_device_register(&ab8500_device); platform_device_register(&ab8500_device);
i2c_register_board_info(0, mop500_i2c0_devices,
ARRAY_SIZE(mop500_i2c0_devices));
} }
MACHINE_START(U8500, "ST-Ericsson MOP500 platform") MACHINE_START(U8500, "ST-Ericsson MOP500 platform")
......
...@@ -7,6 +7,15 @@ ...@@ -7,6 +7,15 @@
#ifndef __BOARD_MOP500_H #ifndef __BOARD_MOP500_H
#define __BOARD_MOP500_H #define __BOARD_MOP500_H
#define MOP500_EGPIO(x) (NOMADIK_NR_GPIO + (x))
/* GPIOs on the TC35892 expander */
#define GPIO_SDMMC_CD MOP500_EGPIO(3)
#define GPIO_SDMMC_EN MOP500_EGPIO(17)
#define GPIO_SDMMC_1V8_3V_SEL MOP500_EGPIO(18)
extern void mop500_sdi_init(void); extern void mop500_sdi_init(void);
extern void mop500_sdi_tc35892_init(void);
extern void mop500_keypad_init(void);
#endif #endif
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Hanumath Prasad <ulf.hansson@stericsson.com>
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/amba/mmci.h>
#include <linux/mmc/host.h>
#include <linux/gpio.h>
#include <plat/pincfg.h>
#include <mach/db5500-regs.h>
#include <plat/ste_dma40.h>
#include "pins-db5500.h"
#include "devices-db5500.h"
#include "ste-dma40-db5500.h"
static pin_cfg_t u5500_sdi_pins[] = {
/* SDI0 (POP eMMC) */
GPIO5_MC0_DAT0 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO6_MC0_DAT1 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO7_MC0_DAT2 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO8_MC0_DAT3 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO9_MC0_DAT4 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO10_MC0_DAT5 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO11_MC0_DAT6 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO12_MC0_DAT7 | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO13_MC0_CMD | PIN_DIR_INPUT | PIN_PULL_UP,
GPIO14_MC0_CLK | PIN_DIR_OUTPUT | PIN_VAL_LOW,
};
static struct mmci_platform_data u5500_sdi0_data = {
.ocr_mask = MMC_VDD_165_195,
.f_max = 50000000,
.capabilities = MMC_CAP_4_BIT_DATA |
MMC_CAP_8_BIT_DATA |
MMC_CAP_MMC_HIGHSPEED,
.gpio_cd = -1,
.gpio_wp = -1,
};
void __init u5500_sdi_init(void)
{
nmk_config_pins(u5500_sdi_pins, ARRAY_SIZE(u5500_sdi_pins));
db5500_add_sdi0(&u5500_sdi0_data);
}
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/irq.h>
#include <asm/mach/arch.h> #include <asm/mach/arch.h>
#include <asm/mach-types.h> #include <asm/mach-types.h>
...@@ -17,20 +18,24 @@ ...@@ -17,20 +18,24 @@
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/setup.h> #include <mach/setup.h>
static struct amba_device *amba_board_devs[] __initdata = { #include "devices-db5500.h"
&ux500_uart0_device,
&ux500_uart1_device, static void __init u5500_uart_init(void)
&ux500_uart2_device, {
}; db5500_add_uart0();
db5500_add_uart1();
db5500_add_uart2();
}
static void __init u5500_init_machine(void) static void __init u5500_init_machine(void)
{ {
u5500_init_devices(); u5500_init_devices();
amba_add_devices(amba_board_devs, ARRAY_SIZE(amba_board_devs)); u5500_sdi_init();
u5500_uart_init();
} }
MACHINE_START(U8500, "ST-Ericsson U5500 Platform") MACHINE_START(U5500, "ST-Ericsson U5500 Platform")
.boot_params = 0x00000100, .boot_params = 0x00000100,
.map_io = u5500_map_io, .map_io = u5500_map_io,
.init_irq = ux500_init_irq, .init_irq = ux500_init_irq,
......
...@@ -20,6 +20,12 @@ ...@@ -20,6 +20,12 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include "clock.h" #include "clock.h"
#ifdef CONFIG_DEBUG_FS
#include <linux/debugfs.h>
#include <linux/uaccess.h> /* for copy_from_user */
static LIST_HEAD(clk_list);
#endif
#define PRCC_PCKEN 0x00 #define PRCC_PCKEN 0x00
#define PRCC_PCKDIS 0x04 #define PRCC_PCKDIS 0x04
#define PRCC_KCKEN 0x08 #define PRCC_KCKEN 0x08
...@@ -133,7 +139,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) ...@@ -133,7 +139,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
{ {
void __iomem *addr = __io_address(UX500_PRCMU_BASE) void __iomem *addr = __io_address(UX500_PRCMU_BASE)
+ PRCM_TCR; + PRCM_TCR;
u32 tcr = readl(addr); u32 tcr;
int mtu = (int) clk->data; int mtu = (int) clk->data;
/* /*
* One of these is selected eventually * One of these is selected eventually
...@@ -144,6 +150,14 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) ...@@ -144,6 +150,14 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
unsigned long mturate; unsigned long mturate;
unsigned long retclk; unsigned long retclk;
/*
* On a startup, always conifgure the TCR to the doze mode;
* bootloaders do it for us. Do this in the kernel too.
*/
writel(PRCM_TCR_DOZE_MODE, addr);
tcr = readl(addr);
/* Get the rate from the parent as a default */ /* Get the rate from the parent as a default */
if (clk->parent_periph) if (clk->parent_periph)
mturate = clk_get_rate(clk->parent_periph); mturate = clk_get_rate(clk->parent_periph);
...@@ -153,45 +167,6 @@ static unsigned long clk_mtu_get_rate(struct clk *clk) ...@@ -153,45 +167,6 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
/* We need to be connected SOMEWHERE */ /* We need to be connected SOMEWHERE */
BUG(); BUG();
/*
* Are we in doze mode?
* In this mode the parent peripheral or the fixed 32768 Hz
* clock is fed into the block.
*/
if (!(tcr & PRCM_TCR_DOZE_MODE)) {
/*
* Here we're using the clock input from the APE ULP
* clock domain. But first: are the timers stopped?
*/
if (tcr & PRCM_TCR_STOPPED) {
clk32k = 0;
mturate = 0;
} else {
/* Else default mode: 0 and 2.4 MHz */
clk32k = 0;
if (cpu_is_u5500())
/* DB5500 divides by 8 */
mturate /= 8;
else if (cpu_is_u8500ed()) {
/*
* This clocking setting must not be used
* in the ED chip, it is simply not
* connected anywhere!
*/
mturate = 0;
BUG();
} else
/*
* In this mode the ulp38m4 clock is divided
* by a factor 16, on the DB8500 typically
* 38400000 / 16 ~ 2.4 MHz.
* TODO: Replace the constant with a reference
* to the ULP source once this is modeled.
*/
mturate = 38400000 / 16;
}
}
/* Return the clock selected for this MTU */ /* Return the clock selected for this MTU */
if (tcr & (1 << mtu)) if (tcr & (1 << mtu))
retclk = clk32k; retclk = clk32k;
...@@ -317,6 +292,7 @@ static struct clkops clk_prcc_ops = { ...@@ -317,6 +292,7 @@ static struct clkops clk_prcc_ops = {
}; };
static struct clk clk_32khz = { static struct clk clk_32khz = {
.name = "clk_32khz",
.rate = 32000, .rate = 32000,
}; };
...@@ -453,7 +429,9 @@ static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0); ...@@ -453,7 +429,9 @@ static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
static struct clk clk_dummy_apb_pclk; static struct clk clk_dummy_apb_pclk = {
.name = "apb_pclk",
};
static struct clk_lookup u8500_common_clks[] = { static struct clk_lookup u8500_common_clks[] = {
CLK(dummy_apb_pclk, NULL, "apb_pclk"), CLK(dummy_apb_pclk, NULL, "apb_pclk"),
...@@ -599,6 +577,183 @@ static struct clk_lookup u8500_v1_clks[] = { ...@@ -599,6 +577,183 @@ static struct clk_lookup u8500_v1_clks[] = {
CLK(uiccclk, "uicc", NULL), CLK(uiccclk, "uicc", NULL),
}; };
#ifdef CONFIG_DEBUG_FS
/*
* debugfs support to trace clock tree hierarchy and attributes with
* powerdebug
*/
static struct dentry *clk_debugfs_root;
void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
{
while (num--) {
/* Check that the clock has not been already registered */
if (!(cl->clk->list.prev != cl->clk->list.next))
list_add_tail(&cl->clk->list, &clk_list);
cl++;
}
}
static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
size_t size, loff_t *off)
{
struct clk *clk = file->f_dentry->d_inode->i_private;
char cusecount[128];
unsigned int len;
len = sprintf(cusecount, "%u\n", clk->enabled);
return simple_read_from_buffer(buf, size, off, cusecount, len);
}
static ssize_t rate_dbg_read(struct file *file, char __user *buf,
size_t size, loff_t *off)
{
struct clk *clk = file->f_dentry->d_inode->i_private;
char crate[128];
unsigned int rate;
unsigned int len;
rate = clk_get_rate(clk);
len = sprintf(crate, "%u\n", rate);
return simple_read_from_buffer(buf, size, off, crate, len);
}
static const struct file_operations usecount_fops = {
.read = usecount_dbg_read,
};
static const struct file_operations set_rate_fops = {
.read = rate_dbg_read,
};
static struct dentry *clk_debugfs_register_dir(struct clk *c,
struct dentry *p_dentry)
{
struct dentry *d, *clk_d, *child, *child_tmp;
char s[255];
char *p = s;
if (c->name == NULL)
p += sprintf(p, "BUG");
else
p += sprintf(p, "%s", c->name);
clk_d = debugfs_create_dir(s, p_dentry);
if (!clk_d)
return NULL;
d = debugfs_create_file("usecount", S_IRUGO,
clk_d, c, &usecount_fops);
if (!d)
goto err_out;
d = debugfs_create_file("rate", S_IRUGO,
clk_d, c, &set_rate_fops);
if (!d)
goto err_out;
/*
* TODO : not currently available in ux500
* d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
* if (!d)
* goto err_out;
*/
return clk_d;
err_out:
d = clk_d;
list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
debugfs_remove(child);
debugfs_remove(clk_d);
return NULL;
}
static void clk_debugfs_remove_dir(struct dentry *cdentry)
{
struct dentry *d, *child, *child_tmp;
d = cdentry;
list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
debugfs_remove(child);
debugfs_remove(cdentry);
return ;
}
static int clk_debugfs_register_one(struct clk *c)
{
struct clk *pa = c->parent_periph;
struct clk *bpa = c->parent_cluster;
if (!(bpa && !pa)) {
c->dent = clk_debugfs_register_dir(c,
pa ? pa->dent : clk_debugfs_root);
if (!c->dent)
return -ENOMEM;
}
if (bpa) {
c->dent_bus = clk_debugfs_register_dir(c,
bpa->dent_bus ? bpa->dent_bus : bpa->dent);
if ((!c->dent_bus) && (c->dent)) {
clk_debugfs_remove_dir(c->dent);
c->dent = NULL;
return -ENOMEM;
}
}
return 0;
}
static int clk_debugfs_register(struct clk *c)
{
int err;
struct clk *pa = c->parent_periph;
struct clk *bpa = c->parent_cluster;
if (pa && (!pa->dent && !pa->dent_bus)) {
err = clk_debugfs_register(pa);
if (err)
return err;
}
if (bpa && (!bpa->dent && !bpa->dent_bus)) {
err = clk_debugfs_register(bpa);
if (err)
return err;
}
if ((!c->dent) && (!c->dent_bus)) {
err = clk_debugfs_register_one(c);
if (err)
return err;
}
return 0;
}
static int __init clk_debugfs_init(void)
{
struct clk *c;
struct dentry *d;
int err;
d = debugfs_create_dir("clock", NULL);
if (!d)
return -ENOMEM;
clk_debugfs_root = d;
list_for_each_entry(c, &clk_list, list) {
err = clk_debugfs_register(c);
if (err)
goto err_out;
}
return 0;
err_out:
debugfs_remove_recursive(clk_debugfs_root);
return err;
}
late_initcall(clk_debugfs_init);
#endif /* defined(CONFIG_DEBUG_FS) */
int __init clk_init(void) int __init clk_init(void)
{ {
if (cpu_is_u8500ed()) { if (cpu_is_u8500ed()) {
...@@ -609,7 +764,8 @@ int __init clk_init(void) ...@@ -609,7 +764,8 @@ int __init clk_init(void)
/* Clock tree for U5500 not implemented yet */ /* Clock tree for U5500 not implemented yet */
clk_prcc_ops.enable = clk_prcc_ops.disable = NULL; clk_prcc_ops.enable = clk_prcc_ops.disable = NULL;
clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL; clk_prcmu_ops.enable = clk_prcmu_ops.disable = NULL;
clk_per6clk.rate = 26000000; clk_uartclk.rate = 36360000;
clk_sdmmcclk.rate = 99900000;
} }
clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks)); clkdev_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
...@@ -618,5 +774,12 @@ int __init clk_init(void) ...@@ -618,5 +774,12 @@ int __init clk_init(void)
else else
clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
#ifdef CONFIG_DEBUG_FS
clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
if (cpu_is_u8500ed())
clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
else
clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
#endif
return 0; return 0;
} }
...@@ -90,6 +90,10 @@ struct clk { ...@@ -90,6 +90,10 @@ struct clk {
struct clk *parent_cluster; struct clk *parent_cluster;
struct clk *parent_periph; struct clk *parent_periph;
#if defined(CONFIG_DEBUG_FS)
struct dentry *dent; /* For visible tree hierarchy */
struct dentry *dent_bus; /* For visible tree hierarchy */
#endif
}; };
#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ #define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \
......
...@@ -8,14 +8,19 @@ ...@@ -8,14 +8,19 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/amba/bus.h> #include <linux/amba/bus.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/irq.h>
#include <asm/mach/map.h> #include <asm/mach/map.h>
#include <plat/gpio.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/setup.h> #include <mach/setup.h>
#include <mach/irqs.h> #include <mach/irqs.h>
#include "devices-db5500.h"
static struct map_desc u5500_io_desc[] __initdata = { static struct map_desc u5500_io_desc[] __initdata = {
__IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K),
...@@ -110,19 +115,32 @@ static struct platform_device mbox2_device = { ...@@ -110,19 +115,32 @@ static struct platform_device mbox2_device = {
}; };
static struct platform_device *u5500_platform_devs[] __initdata = { static struct platform_device *u5500_platform_devs[] __initdata = {
&u5500_gpio_devs[0],
&u5500_gpio_devs[1],
&u5500_gpio_devs[2],
&u5500_gpio_devs[3],
&u5500_gpio_devs[4],
&u5500_gpio_devs[5],
&u5500_gpio_devs[6],
&u5500_gpio_devs[7],
&mbox0_device, &mbox0_device,
&mbox1_device, &mbox1_device,
&mbox2_device, &mbox2_device,
}; };
static resource_size_t __initdata db5500_gpio_base[] = {
U5500_GPIOBANK0_BASE,
U5500_GPIOBANK1_BASE,
U5500_GPIOBANK2_BASE,
U5500_GPIOBANK3_BASE,
U5500_GPIOBANK4_BASE,
U5500_GPIOBANK5_BASE,
U5500_GPIOBANK6_BASE,
U5500_GPIOBANK7_BASE,
};
static void __init db5500_add_gpios(void)
{
struct nmk_gpio_platform_data pdata = {
/* No custom data yet */
};
dbx500_add_gpios(ARRAY_AND_SIZE(db5500_gpio_base),
IRQ_DB5500_GPIO0, &pdata);
}
void __init u5500_map_io(void) void __init u5500_map_io(void)
{ {
ux500_map_io(); ux500_map_io();
...@@ -132,7 +150,9 @@ void __init u5500_map_io(void) ...@@ -132,7 +150,9 @@ void __init u5500_map_io(void)
void __init u5500_init_devices(void) void __init u5500_init_devices(void)
{ {
ux500_init_devices(); db5500_add_gpios();
db5500_dma_init();
db5500_add_rtc();
platform_add_devices(u5500_platform_devs, platform_add_devices(u5500_platform_devs,
ARRAY_SIZE(u5500_platform_devs)); ARRAY_SIZE(u5500_platform_devs));
......
...@@ -22,23 +22,15 @@ ...@@ -22,23 +22,15 @@
#include <mach/setup.h> #include <mach/setup.h>
#include <mach/devices.h> #include <mach/devices.h>
#include "devices-db8500.h"
static struct platform_device *platform_devs[] __initdata = { static struct platform_device *platform_devs[] __initdata = {
&u8500_gpio_devs[0],
&u8500_gpio_devs[1],
&u8500_gpio_devs[2],
&u8500_gpio_devs[3],
&u8500_gpio_devs[4],
&u8500_gpio_devs[5],
&u8500_gpio_devs[6],
&u8500_gpio_devs[7],
&u8500_gpio_devs[8],
&u8500_dma40_device, &u8500_dma40_device,
}; };
/* minimum static i/o mapping required to boot U8500 platforms */ /* minimum static i/o mapping required to boot U8500 platforms */
static struct map_desc u8500_io_desc[] __initdata = { static struct map_desc u8500_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K), __IO_DEV_DESC(U8500_PRCMU_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K), __IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
...@@ -46,13 +38,18 @@ static struct map_desc u8500_io_desc[] __initdata = { ...@@ -46,13 +38,18 @@ static struct map_desc u8500_io_desc[] __initdata = {
__MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M), __MEM_DEV_DESC(U8500_BOOT_ROM_BASE, SZ_1M),
}; };
static struct map_desc u8500ed_io_desc[] __initdata = { static struct map_desc u8500_ed_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K), __IO_DEV_DESC(U8500_MTU0_BASE_ED, SZ_4K),
__IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K), __IO_DEV_DESC(U8500_CLKRST7_BASE_ED, SZ_8K),
}; };
static struct map_desc u8500v1_io_desc[] __initdata = { static struct map_desc u8500_v1_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K), __IO_DEV_DESC(U8500_MTU0_BASE, SZ_4K),
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE_V1, SZ_4K),
};
static struct map_desc u8500_v2_io_desc[] __initdata = {
__IO_DEV_DESC(U8500_PRCMU_TCDM_BASE, SZ_4K),
}; };
/* /*
...@@ -125,14 +122,38 @@ void __init u8500_map_io(void) ...@@ -125,14 +122,38 @@ void __init u8500_map_io(void)
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc)); iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
if (cpu_is_u8500ed()) if (cpu_is_u8500ed())
iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc)); iotable_init(u8500_ed_io_desc, ARRAY_SIZE(u8500_ed_io_desc));
else else if (cpu_is_u8500v1())
iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc)); iotable_init(u8500_v1_io_desc, ARRAY_SIZE(u8500_v1_io_desc));
else if (cpu_is_u8500v2())
iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
/* Read out the ASIC ID as early as we can */ /* Read out the ASIC ID as early as we can */
get_db8500_asic_id(); get_db8500_asic_id();
} }
static resource_size_t __initdata db8500_gpio_base[] = {
U8500_GPIOBANK0_BASE,
U8500_GPIOBANK1_BASE,
U8500_GPIOBANK2_BASE,
U8500_GPIOBANK3_BASE,
U8500_GPIOBANK4_BASE,
U8500_GPIOBANK5_BASE,
U8500_GPIOBANK6_BASE,
U8500_GPIOBANK7_BASE,
U8500_GPIOBANK8_BASE,
};
static void __init db8500_add_gpios(void)
{
struct nmk_gpio_platform_data pdata = {
/* No custom data yet */
};
dbx500_add_gpios(ARRAY_AND_SIZE(db8500_gpio_base),
IRQ_DB8500_GPIO0, &pdata);
}
/* /*
* This function is called from the board init * This function is called from the board init
*/ */
...@@ -152,12 +173,13 @@ void __init u8500_init_devices(void) ...@@ -152,12 +173,13 @@ void __init u8500_init_devices(void)
else else
pr_warning("ASIC: UNKNOWN SILICON VERSION!\n"); pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
ux500_init_devices();
if (cpu_is_u8500ed()) if (cpu_is_u8500ed())
dma40_u8500ed_fixup(); dma40_u8500ed_fixup();
/* Register the platform devices */ db8500_add_rtc();
db8500_add_gpios();
platform_device_register_simple("cpufreq-u8500", -1, NULL, 0);
platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs)); platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
return ; return ;
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
*/ */
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/clk.h> #include <linux/clk.h>
...@@ -20,6 +19,7 @@ ...@@ -20,6 +19,7 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/setup.h> #include <mach/setup.h>
#include <mach/devices.h> #include <mach/devices.h>
#include <mach/prcmu.h>
#include "clock.h" #include "clock.h"
...@@ -45,20 +45,11 @@ static struct map_desc ux500_io_desc[] __initdata = { ...@@ -45,20 +45,11 @@ static struct map_desc ux500_io_desc[] __initdata = {
__IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K), __IO_DEV_DESC(UX500_BACKUPRAM0_BASE, SZ_8K),
}; };
static struct amba_device *ux500_amba_devs[] __initdata = {
&ux500_pl031_device,
};
void __init ux500_map_io(void) void __init ux500_map_io(void)
{ {
iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc)); iotable_init(ux500_io_desc, ARRAY_SIZE(ux500_io_desc));
} }
void __init ux500_init_devices(void)
{
amba_add_devices(ux500_amba_devs, ARRAY_SIZE(ux500_amba_devs));
}
void __init ux500_init_irq(void) void __init ux500_init_irq(void)
{ {
gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29); gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29);
...@@ -68,6 +59,8 @@ void __init ux500_init_irq(void) ...@@ -68,6 +59,8 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer * Init clocks here so that they are available for system timer
* initialization. * initialization.
*/ */
if (cpu_is_u8500())
prcmu_early_init();
clk_init(); clk_init();
} }
......
/*
* CPU frequency scaling for u8500
* Inspired by linux/arch/arm/mach-davinci/cpufreq.c
*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License v2
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Martin Persson <martin.persson@stericsson.com>
* Author: Jonas Aaberg <jonas.aberg@stericsson.com>
*
*/
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/cpufreq.h>
#include <linux/delay.h>
#include <mach/hardware.h>
#include <mach/prcmu.h>
#include <mach/prcmu-defs.h>
#define DRIVER_NAME "cpufreq-u8500"
#define CPUFREQ_NAME "u8500"
static struct device *dev;
static struct cpufreq_frequency_table freq_table[] = {
[0] = {
.index = 0,
.frequency = 200000,
},
[1] = {
.index = 1,
.frequency = 300000,
},
[2] = {
.index = 2,
.frequency = 600000,
},
[3] = {
/* Used for CPU_OPP_MAX, if available */
.index = 3,
.frequency = CPUFREQ_TABLE_END,
},
[4] = {
.index = 4,
.frequency = CPUFREQ_TABLE_END,
},
};
static enum prcmu_cpu_opp index2opp[] = {
CPU_OPP_EXT_CLK,
CPU_OPP_50,
CPU_OPP_100,
CPU_OPP_MAX
};
static int u8500_cpufreq_verify_speed(struct cpufreq_policy *policy)
{
return cpufreq_frequency_table_verify(policy, freq_table);
}
static int u8500_cpufreq_target(struct cpufreq_policy *policy,
unsigned int target_freq,
unsigned int relation)
{
struct cpufreq_freqs freqs;
unsigned int index;
int ret = 0;
/*
* Ensure desired rate is within allowed range. Some govenors
* (ondemand) will just pass target_freq=0 to get the minimum.
*/
if (target_freq < policy->cpuinfo.min_freq)
target_freq = policy->cpuinfo.min_freq;
if (target_freq > policy->cpuinfo.max_freq)
target_freq = policy->cpuinfo.max_freq;
ret = cpufreq_frequency_table_target(policy, freq_table,
target_freq, relation, &index);
if (ret < 0) {
dev_err(dev, "Could not look up next frequency\n");
return ret;
}
freqs.old = policy->cur;
freqs.new = freq_table[index].frequency;
freqs.cpu = policy->cpu;
if (freqs.old == freqs.new) {
dev_dbg(dev, "Current and target frequencies are equal\n");
return 0;
}
dev_dbg(dev, "transition: %u --> %u\n", freqs.old, freqs.new);
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
ret = prcmu_set_cpu_opp(index2opp[index]);
if (ret < 0) {
dev_err(dev, "Failed to set OPP level\n");
return ret;
}
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
}
static unsigned int u8500_cpufreq_getspeed(unsigned int cpu)
{
int i;
for (i = 0; prcmu_get_cpu_opp() != index2opp[i]; i++)
;
return freq_table[i].frequency;
}
static int __cpuinit u8500_cpu_init(struct cpufreq_policy *policy)
{
int res;
BUILD_BUG_ON(ARRAY_SIZE(index2opp) + 1 != ARRAY_SIZE(freq_table));
if (cpu_is_u8500v2()) {
freq_table[1].frequency = 400000;
freq_table[2].frequency = 800000;
if (prcmu_has_arm_maxopp())
freq_table[3].frequency = 1000000;
}
/* get policy fields based on the table */
res = cpufreq_frequency_table_cpuinfo(policy, freq_table);
if (!res)
cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
else {
dev_err(dev, "u8500-cpufreq : Failed to read policy table\n");
return res;
}
policy->min = policy->cpuinfo.min_freq;
policy->max = policy->cpuinfo.max_freq;
policy->cur = u8500_cpufreq_getspeed(policy->cpu);
policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
/*
* FIXME : Need to take time measurement across the target()
* function with no/some/all drivers in the notification
* list.
*/
policy->cpuinfo.transition_latency = 200 * 1000; /* in ns */
/* policy sharing between dual CPUs */
cpumask_copy(policy->cpus, &cpu_present_map);
policy->shared_type = CPUFREQ_SHARED_TYPE_ALL;
return res;
}
static struct freq_attr *u8500_cpufreq_attr[] = {
&cpufreq_freq_attr_scaling_available_freqs,
NULL,
};
static int u8500_cpu_exit(struct cpufreq_policy *policy)
{
cpufreq_frequency_table_put_attr(policy->cpu);
return 0;
}
static struct cpufreq_driver u8500_driver = {
.owner = THIS_MODULE,
.flags = CPUFREQ_STICKY,
.verify = u8500_cpufreq_verify_speed,
.target = u8500_cpufreq_target,
.get = u8500_cpufreq_getspeed,
.init = u8500_cpu_init,
.exit = u8500_cpu_exit,
.name = CPUFREQ_NAME,
.attr = u8500_cpufreq_attr,
};
static int __init u8500_cpufreq_probe(struct platform_device *pdev)
{
dev = &pdev->dev;
return cpufreq_register_driver(&u8500_driver);
}
static int __exit u8500_cpufreq_remove(struct platform_device *pdev)
{
return cpufreq_unregister_driver(&u8500_driver);
}
static struct platform_driver u8500_cpufreq_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
.remove = __exit_p(u8500_cpufreq_remove),
};
static int __init u8500_cpufreq_init(void)
{
return platform_driver_probe(&u8500_cpufreq_driver,
&u8500_cpufreq_probe);
}
device_initcall(u8500_cpufreq_init);
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL), version 2.
*/
#include <linux/kernel.h>
#include <linux/dma-mapping.h>
#include <linux/err.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <plat/gpio.h>
#include <mach/hardware.h>
#include "devices-common.h"
struct amba_device *
dbx500_add_amba_device(const char *name, resource_size_t base,
int irq, void *pdata, unsigned int periphid)
{
struct amba_device *dev;
int ret;
dev = kzalloc(sizeof *dev, GFP_KERNEL);
if (!dev)
return ERR_PTR(-ENOMEM);
dev->dev.init_name = name;
dev->res.start = base;
dev->res.end = base + SZ_4K - 1;
dev->res.flags = IORESOURCE_MEM;
dev->dma_mask = DMA_BIT_MASK(32);
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->irq[0] = irq;
dev->irq[1] = NO_IRQ;
dev->periphid = periphid;
dev->dev.platform_data = pdata;
ret = amba_device_register(dev, &iomem_resource);
if (ret) {
kfree(dev);
return ERR_PTR(ret);
}
return dev;
}
static struct platform_device *
dbx500_add_platform_device(const char *name, int id, void *pdata,
struct resource *res, int resnum)
{
struct platform_device *dev;
int ret;
dev = platform_device_alloc(name, id);
if (!dev)
return ERR_PTR(-ENOMEM);
dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
ret = platform_device_add_resources(dev, res, resnum);
if (ret)
goto out_free;
dev->dev.platform_data = pdata;
ret = platform_device_add(dev);
if (ret)
goto out_free;
return dev;
out_free:
platform_device_put(dev);
return ERR_PTR(ret);
}
struct platform_device *
dbx500_add_platform_device_4k1irq(const char *name, int id,
resource_size_t base,
int irq, void *pdata)
{
struct resource resources[] = {
[0] = {
.start = base,
.end = base + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = irq,
.end = irq,
.flags = IORESOURCE_IRQ,
}
};
return dbx500_add_platform_device(name, id, pdata, resources,
ARRAY_SIZE(resources));
}
static struct platform_device *
dbx500_add_gpio(int id, resource_size_t addr, int irq,
struct nmk_gpio_platform_data *pdata)
{
struct resource resources[] = {
{
.start = addr,
.end = addr + 127,
.flags = IORESOURCE_MEM,
},
{
.start = irq,
.end = irq,
.flags = IORESOURCE_IRQ,
}
};
return platform_device_register_resndata(NULL, "gpio", id,
resources, ARRAY_SIZE(resources),
pdata, sizeof(*pdata));
}
void dbx500_add_gpios(resource_size_t *base, int num, int irq,
struct nmk_gpio_platform_data *pdata)
{
int first = 0;
int i;
for (i = 0; i < num; i++, first += 32, irq++) {
pdata->first_gpio = first;
pdata->first_irq = NOMADIK_GPIO_TO_IRQ(first);
dbx500_add_gpio(i, base[i], irq, pdata);
}
}
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL), version 2.
*/
#ifndef __DEVICES_COMMON_H
#define __DEVICES_COMMON_H
extern struct amba_device *
dbx500_add_amba_device(const char *name, resource_size_t base,
int irq, void *pdata, unsigned int periphid);
extern struct platform_device *
dbx500_add_platform_device_4k1irq(const char *name, int id,
resource_size_t base,
int irq, void *pdata);
struct spi_master_cntlr;
static inline struct amba_device *
dbx500_add_msp_spi(const char *name, resource_size_t base, int irq,
struct spi_master_cntlr *pdata)
{
return dbx500_add_amba_device(name, base, irq, pdata, 0);
}
static inline struct amba_device *
dbx500_add_spi(const char *name, resource_size_t base, int irq,
struct spi_master_cntlr *pdata)
{
return dbx500_add_amba_device(name, base, irq, pdata, 0);
}
struct mmci_platform_data;
static inline struct amba_device *
dbx500_add_sdi(const char *name, resource_size_t base, int irq,
struct mmci_platform_data *pdata)
{
return dbx500_add_amba_device(name, base, irq, pdata, 0);
}
static inline struct amba_device *
dbx500_add_uart(const char *name, resource_size_t base, int irq)
{
return dbx500_add_amba_device(name, base, irq, NULL, 0);
}
struct nmk_i2c_controller;
static inline struct platform_device *
dbx500_add_i2c(int id, resource_size_t base, int irq,
struct nmk_i2c_controller *pdata)
{
return dbx500_add_platform_device_4k1irq("nmk-i2c", id, base, irq,
pdata);
}
struct msp_i2s_platform_data;
static inline struct platform_device *
dbx500_add_msp_i2s(int id, resource_size_t base, int irq,
struct msp_i2s_platform_data *pdata)
{
return dbx500_add_platform_device_4k1irq("MSP_I2S", id, base, irq,
pdata);
}
static inline struct amba_device *
dbx500_add_rtc(resource_size_t base, int irq)
{
return dbx500_add_amba_device("rtc-pl031", base, irq, NULL, 0);
}
struct nmk_gpio_platform_data;
void dbx500_add_gpios(resource_size_t *base, int num, int irq,
struct nmk_gpio_platform_data *pdata);
#endif
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL) version 2
*/
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <mach/hardware.h>
#include <mach/devices.h>
static struct nmk_gpio_platform_data u5500_gpio_data[] = {
GPIO_DATA("GPIO-0-31", 0),
GPIO_DATA("GPIO-32-63", 32), /* 36..63 not routed to pin */
GPIO_DATA("GPIO-64-95", 64), /* 83..95 not routed to pin */
GPIO_DATA("GPIO-96-127", 96), /* 102..127 not routed to pin */
GPIO_DATA("GPIO-128-159", 128), /* 149..159 not routed to pin */
GPIO_DATA("GPIO-160-191", 160),
GPIO_DATA("GPIO-192-223", 192),
GPIO_DATA("GPIO-224-255", 224), /* 228..255 not routed to pin */
};
static struct resource u5500_gpio_resources[] = {
GPIO_RESOURCE(0),
GPIO_RESOURCE(1),
GPIO_RESOURCE(2),
GPIO_RESOURCE(3),
GPIO_RESOURCE(4),
GPIO_RESOURCE(5),
GPIO_RESOURCE(6),
GPIO_RESOURCE(7),
};
struct platform_device u5500_gpio_devs[] = {
GPIO_DEVICE(0),
GPIO_DEVICE(1),
GPIO_DEVICE(2),
GPIO_DEVICE(3),
GPIO_DEVICE(4),
GPIO_DEVICE(5),
GPIO_DEVICE(6),
GPIO_DEVICE(7),
};
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL), version 2.
*/
#ifndef __DEVICES_DB5500_H
#define __DEVICES_DB5500_H
#include "devices-common.h"
#define db5500_add_i2c1(pdata) \
dbx500_add_i2c(1, U5500_I2C1_BASE, IRQ_DB5500_I2C1, pdata)
#define db5500_add_i2c2(pdata) \
dbx500_add_i2c(2, U5500_I2C2_BASE, IRQ_DB5500_I2C2, pdata)
#define db5500_add_i2c3(pdata) \
dbx500_add_i2c(3, U5500_I2C3_BASE, IRQ_DB5500_I2C3, pdata)
#define db5500_add_msp0_i2s(pdata) \
dbx500_add_msp_i2s(0, U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
#define db5500_add_msp1_i2s(pdata) \
dbx500_add_msp_i2s(1, U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
#define db5500_add_msp2_i2s(pdata) \
dbx500_add_msp_i2s(2, U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
#define db5500_add_msp0_spi(pdata) \
dbx500_add_msp_spi("msp0", U5500_MSP0_BASE, IRQ_DB5500_MSP0, pdata)
#define db5500_add_msp1_spi(pdata) \
dbx500_add_msp_spi("msp1", U5500_MSP1_BASE, IRQ_DB5500_MSP1, pdata)
#define db5500_add_msp2_spi(pdata) \
dbx500_add_msp_spi("msp2", U5500_MSP2_BASE, IRQ_DB5500_MSP2, pdata)
#define db5500_add_rtc() \
dbx500_add_rtc(U5500_RTC_BASE, IRQ_DB5500_RTC);
#define db5500_add_sdi0(pdata) \
dbx500_add_sdi("sdi0", U5500_SDI0_BASE, IRQ_DB5500_SDMMC0, pdata)
#define db5500_add_sdi1(pdata) \
dbx500_add_sdi("sdi1", U5500_SDI1_BASE, IRQ_DB5500_SDMMC1, pdata)
#define db5500_add_sdi2(pdata) \
dbx500_add_sdi("sdi2", U5500_SDI2_BASE, IRQ_DB5500_SDMMC2, pdata)
#define db5500_add_sdi3(pdata) \
dbx500_add_sdi("sdi3", U5500_SDI3_BASE, IRQ_DB5500_SDMMC3, pdata)
#define db5500_add_sdi4(pdata) \
dbx500_add_sdi("sdi4", U5500_SDI4_BASE, IRQ_DB5500_SDMMC4, pdata)
#define db5500_add_spi0(pdata) \
dbx500_add_spi("spi0", U5500_SPI0_BASE, IRQ_DB5500_SPI0, pdata)
#define db5500_add_spi1(pdata) \
dbx500_add_spi("spi1", U5500_SPI1_BASE, IRQ_DB5500_SPI1, pdata)
#define db5500_add_spi2(pdata) \
dbx500_add_spi("spi2", U5500_SPI2_BASE, IRQ_DB5500_SPI2, pdata)
#define db5500_add_spi3(pdata) \
dbx500_add_spi("spi3", U5500_SPI3_BASE, IRQ_DB5500_SPI3, pdata)
#define db5500_add_uart0() \
dbx500_add_uart("uart0", U5500_UART0_BASE, IRQ_DB5500_UART0)
#define db5500_add_uart1() \
dbx500_add_uart("uart1", U5500_UART1_BASE, IRQ_DB5500_UART1)
#define db5500_add_uart2() \
dbx500_add_uart("uart2", U5500_UART2_BASE, IRQ_DB5500_UART2)
#define db5500_add_uart3() \
dbx500_add_uart("uart3", U5500_UART3_BASE, IRQ_DB5500_UART3)
#endif
...@@ -19,173 +19,6 @@ ...@@ -19,173 +19,6 @@
#include "ste-dma40-db8500.h" #include "ste-dma40-db8500.h"
static struct nmk_gpio_platform_data u8500_gpio_data[] = {
GPIO_DATA("GPIO-0-31", 0),
GPIO_DATA("GPIO-32-63", 32), /* 37..63 not routed to pin */
GPIO_DATA("GPIO-64-95", 64),
GPIO_DATA("GPIO-96-127", 96), /* 98..127 not routed to pin */
GPIO_DATA("GPIO-128-159", 128),
GPIO_DATA("GPIO-160-191", 160), /* 172..191 not routed to pin */
GPIO_DATA("GPIO-192-223", 192),
GPIO_DATA("GPIO-224-255", 224), /* 231..255 not routed to pin */
GPIO_DATA("GPIO-256-288", 256), /* 268..288 not routed to pin */
};
static struct resource u8500_gpio_resources[] = {
GPIO_RESOURCE(0),
GPIO_RESOURCE(1),
GPIO_RESOURCE(2),
GPIO_RESOURCE(3),
GPIO_RESOURCE(4),
GPIO_RESOURCE(5),
GPIO_RESOURCE(6),
GPIO_RESOURCE(7),
GPIO_RESOURCE(8),
};
struct platform_device u8500_gpio_devs[] = {
GPIO_DEVICE(0),
GPIO_DEVICE(1),
GPIO_DEVICE(2),
GPIO_DEVICE(3),
GPIO_DEVICE(4),
GPIO_DEVICE(5),
GPIO_DEVICE(6),
GPIO_DEVICE(7),
GPIO_DEVICE(8),
};
struct amba_device u8500_ssp0_device = {
.dev = {
.coherent_dma_mask = ~0,
.init_name = "ssp0",
},
.res = {
.start = U8500_SSP0_BASE,
.end = U8500_SSP0_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SSP0, NO_IRQ },
/* ST-Ericsson modified id */
.periphid = SSP_PER_ID,
};
static struct resource u8500_i2c0_resources[] = {
[0] = {
.start = U8500_I2C0_BASE,
.end = U8500_I2C0_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_DB8500_I2C0,
.end = IRQ_DB8500_I2C0,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device u8500_i2c0_device = {
.name = "nmk-i2c",
.id = 0,
.resource = u8500_i2c0_resources,
.num_resources = ARRAY_SIZE(u8500_i2c0_resources),
};
static struct resource u8500_i2c4_resources[] = {
[0] = {
.start = U8500_I2C4_BASE,
.end = U8500_I2C4_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_DB8500_I2C4,
.end = IRQ_DB8500_I2C4,
.flags = IORESOURCE_IRQ,
}
};
struct platform_device u8500_i2c4_device = {
.name = "nmk-i2c",
.id = 4,
.resource = u8500_i2c4_resources,
.num_resources = ARRAY_SIZE(u8500_i2c4_resources),
};
/*
* SD/MMC
*/
struct amba_device u8500_sdi0_device = {
.dev = {
.init_name = "sdi0",
},
.res = {
.start = U8500_SDI0_BASE,
.end = U8500_SDI0_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC0, NO_IRQ},
};
struct amba_device u8500_sdi1_device = {
.dev = {
.init_name = "sdi1",
},
.res = {
.start = U8500_SDI1_BASE,
.end = U8500_SDI1_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC1, NO_IRQ},
};
struct amba_device u8500_sdi2_device = {
.dev = {
.init_name = "sdi2",
},
.res = {
.start = U8500_SDI2_BASE,
.end = U8500_SDI2_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC2, NO_IRQ},
};
struct amba_device u8500_sdi3_device = {
.dev = {
.init_name = "sdi3",
},
.res = {
.start = U8500_SDI3_BASE,
.end = U8500_SDI3_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC3, NO_IRQ},
};
struct amba_device u8500_sdi4_device = {
.dev = {
.init_name = "sdi4",
},
.res = {
.start = U8500_SDI4_BASE,
.end = U8500_SDI4_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC4, NO_IRQ},
};
struct amba_device u8500_sdi5_device = {
.dev = {
.init_name = "sdi5",
},
.res = {
.start = U8500_SDI5_BASE,
.end = U8500_SDI5_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_DB8500_SDMMC5, NO_IRQ},
};
static struct resource dma40_resources[] = { static struct resource dma40_resources[] = {
[0] = { [0] = {
.start = U8500_DMA_BASE, .start = U8500_DMA_BASE,
...@@ -295,7 +128,7 @@ struct resource keypad_resources[] = { ...@@ -295,7 +128,7 @@ struct resource keypad_resources[] = {
}, },
}; };
struct platform_device ux500_ske_keypad_device = { struct platform_device u8500_ske_keypad_device = {
.name = "nmk-ske-keypad", .name = "nmk-ske-keypad",
.id = -1, .id = -1,
.num_resources = ARRAY_SIZE(keypad_resources), .num_resources = ARRAY_SIZE(keypad_resources),
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
* License terms: GNU General Public License (GPL), version 2.
*/
#ifndef __DEVICES_DB8500_H
#define __DEVICES_DB8500_H
#include "devices-common.h"
struct ske_keypad_platform_data;
struct pl022_ssp_controller;
static inline struct platform_device *
db8500_add_ske_keypad(struct ske_keypad_platform_data *pdata)
{
return dbx500_add_platform_device_4k1irq("nmk-ske-keypad", -1,
U8500_SKE_BASE,
IRQ_DB8500_KB, pdata);
}
static inline struct amba_device *
db8500_add_ssp(const char *name, resource_size_t base, int irq,
struct pl022_ssp_controller *pdata)
{
return dbx500_add_amba_device(name, base, irq, pdata, SSP_PER_ID);
}
#define db8500_add_i2c0(pdata) \
dbx500_add_i2c(0, U8500_I2C0_BASE, IRQ_DB8500_I2C0, pdata)
#define db8500_add_i2c1(pdata) \
dbx500_add_i2c(1, U8500_I2C1_BASE, IRQ_DB8500_I2C1, pdata)
#define db8500_add_i2c2(pdata) \
dbx500_add_i2c(2, U8500_I2C2_BASE, IRQ_DB8500_I2C2, pdata)
#define db8500_add_i2c3(pdata) \
dbx500_add_i2c(3, U8500_I2C3_BASE, IRQ_DB8500_I2C3, pdata)
#define db8500_add_i2c4(pdata) \
dbx500_add_i2c(4, U8500_I2C4_BASE, IRQ_DB8500_I2C4, pdata)
#define db8500_add_msp0_i2s(pdata) \
dbx500_add_msp_i2s(0, U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
#define db8500_add_msp1_i2s(pdata) \
dbx500_add_msp_i2s(1, U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
#define db8500_add_msp2_i2s(pdata) \
dbx500_add_msp_i2s(2, U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
#define db8500_add_msp3_i2s(pdata) \
dbx500_add_msp_i2s(3, U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
#define db8500_add_msp0_spi(pdata) \
dbx500_add_msp_spi("msp0", U8500_MSP0_BASE, IRQ_DB8500_MSP0, pdata)
#define db8500_add_msp1_spi(pdata) \
dbx500_add_msp_spi("msp1", U8500_MSP1_BASE, IRQ_DB8500_MSP1, pdata)
#define db8500_add_msp2_spi(pdata) \
dbx500_add_msp_spi("msp2", U8500_MSP2_BASE, IRQ_DB8500_MSP2, pdata)
#define db8500_add_msp3_spi(pdata) \
dbx500_add_msp_spi("msp3", U8500_MSP3_BASE, IRQ_DB8500_MSP1, pdata)
#define db8500_add_rtc() \
dbx500_add_rtc(U8500_RTC_BASE, IRQ_DB8500_RTC);
#define db8500_add_sdi0(pdata) \
dbx500_add_sdi("sdi0", U8500_SDI0_BASE, IRQ_DB8500_SDMMC0, pdata)
#define db8500_add_sdi1(pdata) \
dbx500_add_sdi("sdi1", U8500_SDI1_BASE, IRQ_DB8500_SDMMC1, pdata)
#define db8500_add_sdi2(pdata) \
dbx500_add_sdi("sdi2", U8500_SDI2_BASE, IRQ_DB8500_SDMMC2, pdata)
#define db8500_add_sdi3(pdata) \
dbx500_add_sdi("sdi3", U8500_SDI3_BASE, IRQ_DB8500_SDMMC3, pdata)
#define db8500_add_sdi4(pdata) \
dbx500_add_sdi("sdi4", U8500_SDI4_BASE, IRQ_DB8500_SDMMC4, pdata)
#define db8500_add_sdi5(pdata) \
dbx500_add_sdi("sdi5", U8500_SDI5_BASE, IRQ_DB8500_SDMMC5, pdata)
#define db8500_add_ssp0(pdata) \
db8500_add_ssp("ssp0", U8500_SSP0_BASE, IRQ_DB8500_SSP0, pdata)
#define db8500_add_ssp1(pdata) \
db8500_add_ssp("ssp1", U8500_SSP1_BASE, IRQ_DB8500_SSP1, pdata)
#define db8500_add_spi0(pdata) \
dbx500_add_spi("spi0", U8500_SPI0_BASE, IRQ_DB8500_SPI0, pdata)
#define db8500_add_spi1(pdata) \
dbx500_add_spi("spi1", U8500_SPI1_BASE, IRQ_DB8500_SPI1, pdata)
#define db8500_add_spi2(pdata) \
dbx500_add_spi("spi2", U8500_SPI2_BASE, IRQ_DB8500_SPI2, pdata)
#define db8500_add_spi3(pdata) \
dbx500_add_spi("spi3", U8500_SPI3_BASE, IRQ_DB8500_SPI3, pdata)
#define db8500_add_uart0() \
dbx500_add_uart("uart0", U8500_UART0_BASE, IRQ_DB8500_UART0)
#define db8500_add_uart1() \
dbx500_add_uart("uart1", U8500_UART1_BASE, IRQ_DB8500_UART1)
#define db8500_add_uart2() \
dbx500_add_uart("uart2", U8500_UART2_BASE, IRQ_DB8500_UART2)
#endif
...@@ -14,69 +14,6 @@ ...@@ -14,69 +14,6 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/setup.h> #include <mach/setup.h>
#define __MEM_4K_RESOURCE(x) \
.res = {.start = (x), .end = (x) + SZ_4K - 1, .flags = IORESOURCE_MEM}
struct amba_device ux500_pl031_device = {
.dev = {
.init_name = "pl031",
},
.res = {
.start = UX500_RTC_BASE,
.end = UX500_RTC_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
},
.irq = {IRQ_RTC_RTT, NO_IRQ},
};
struct amba_device ux500_uart0_device = {
.dev = { .init_name = "uart0" },
__MEM_4K_RESOURCE(UX500_UART0_BASE),
.irq = {IRQ_UART0, NO_IRQ},
};
struct amba_device ux500_uart1_device = {
.dev = { .init_name = "uart1" },
__MEM_4K_RESOURCE(UX500_UART1_BASE),
.irq = {IRQ_UART1, NO_IRQ},
};
struct amba_device ux500_uart2_device = {
.dev = { .init_name = "uart2" },
__MEM_4K_RESOURCE(UX500_UART2_BASE),
.irq = {IRQ_UART2, NO_IRQ},
};
#define UX500_I2C_RESOURCES(id, size) \
static struct resource ux500_i2c##id##_resources[] = { \
[0] = { \
.start = UX500_I2C##id##_BASE, \
.end = UX500_I2C##id##_BASE + size - 1, \
.flags = IORESOURCE_MEM, \
}, \
[1] = { \
.start = IRQ_I2C##id, \
.end = IRQ_I2C##id, \
.flags = IORESOURCE_IRQ \
} \
}
UX500_I2C_RESOURCES(1, SZ_4K);
UX500_I2C_RESOURCES(2, SZ_4K);
UX500_I2C_RESOURCES(3, SZ_4K);
#define UX500_I2C_PDEVICE(cid) \
struct platform_device ux500_i2c##cid##_device = { \
.name = "nmk-i2c", \
.id = cid, \
.num_resources = 2, \
.resource = ux500_i2c##cid##_resources, \
}
UX500_I2C_PDEVICE(1);
UX500_I2C_PDEVICE(2);
UX500_I2C_PDEVICE(3);
void __init amba_add_devices(struct amba_device *devs[], int num) void __init amba_add_devices(struct amba_device *devs[], int num)
{ {
int i; int i;
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Per Forlin <per.forlin@stericsson.com> for ST-Ericsson
* Author: Jonas Aaberg <jonas.aberg@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabinv.vincent@stericsson.com> for ST-Ericsson
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <plat/ste_dma40.h>
#include <mach/setup.h>
#include <mach/hardware.h>
#include "ste-dma40-db5500.h"
static struct resource dma40_resources[] = {
[0] = {
.start = U5500_DMA_BASE,
.end = U5500_DMA_BASE + SZ_4K - 1,
.flags = IORESOURCE_MEM,
.name = "base",
},
[1] = {
.start = U5500_DMA_LCPA_BASE,
.end = U5500_DMA_LCPA_BASE + 2 * SZ_1K - 1,
.flags = IORESOURCE_MEM,
.name = "lcpa",
},
[2] = {
.start = IRQ_DB5500_DMA,
.end = IRQ_DB5500_DMA,
.flags = IORESOURCE_IRQ
}
};
/* Default configuration for physical memcpy */
static struct stedma40_chan_cfg dma40_memcpy_conf_phy = {
.mode = STEDMA40_MODE_PHYSICAL,
.dir = STEDMA40_MEM_TO_MEM,
.src_info.data_width = STEDMA40_BYTE_WIDTH,
.src_info.psize = STEDMA40_PSIZE_PHY_1,
.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
.dst_info.data_width = STEDMA40_BYTE_WIDTH,
.dst_info.psize = STEDMA40_PSIZE_PHY_1,
.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
};
/* Default configuration for logical memcpy */
static struct stedma40_chan_cfg dma40_memcpy_conf_log = {
.dir = STEDMA40_MEM_TO_MEM,
.src_info.data_width = STEDMA40_BYTE_WIDTH,
.src_info.psize = STEDMA40_PSIZE_LOG_1,
.src_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
.dst_info.data_width = STEDMA40_BYTE_WIDTH,
.dst_info.psize = STEDMA40_PSIZE_LOG_1,
.dst_info.flow_ctrl = STEDMA40_NO_FLOW_CTRL,
};
/*
* Mapping between soruce event lines and physical device address This was
* created assuming that the event line is tied to a device and therefore the
* address is constant, however this is not true for at least USB, and the
* values are just placeholders for USB. This table is preserved and used for
* now.
*/
static const dma_addr_t dma40_rx_map[DB5500_DMA_NR_DEV] = {
[DB5500_DMA_DEV24_SDMMC0_RX] = -1,
};
/* Mapping between destination event lines and physical device address */
static const dma_addr_t dma40_tx_map[DB5500_DMA_NR_DEV] = {
[DB5500_DMA_DEV24_SDMMC0_TX] = -1,
};
static int dma40_memcpy_event[] = {
DB5500_DMA_MEMCPY_TX_1,
DB5500_DMA_MEMCPY_TX_2,
DB5500_DMA_MEMCPY_TX_3,
DB5500_DMA_MEMCPY_TX_4,
DB5500_DMA_MEMCPY_TX_5,
};
static struct stedma40_platform_data dma40_plat_data = {
.dev_len = ARRAY_SIZE(dma40_rx_map),
.dev_rx = dma40_rx_map,
.dev_tx = dma40_tx_map,
.memcpy = dma40_memcpy_event,
.memcpy_len = ARRAY_SIZE(dma40_memcpy_event),
.memcpy_conf_phy = &dma40_memcpy_conf_phy,
.memcpy_conf_log = &dma40_memcpy_conf_log,
.disabled_channels = {-1},
};
static struct platform_device dma40_device = {
.dev = {
.platform_data = &dma40_plat_data,
},
.name = "dma40",
.id = 0,
.num_resources = ARRAY_SIZE(dma40_resources),
.resource = dma40_resources
};
void __init db5500_dma_init(void)
{
int ret;
ret = platform_device_register(&dma40_device);
if (ret)
dev_err(&dma40_device.dev, "unable to register device: %d\n", ret);
}
...@@ -114,4 +114,8 @@ ...@@ -114,4 +114,8 @@
#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20) #define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
#define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F) #define U5500_MBOX2_LOCAL_END (U5500_MBOX_BASE + 0x3F)
#define U5500_ESRAM_BASE 0x40000000
#define U5500_ESRAM_DMA_LCPA_OFFSET 0x10000
#define U5500_DMA_LCPA_BASE (U5500_ESRAM_BASE + U5500_ESRAM_DMA_LCPA_OFFSET)
#endif #endif
...@@ -92,7 +92,8 @@ ...@@ -92,7 +92,8 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000) #define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000) #define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000) #define U8500_PRCMU_BASE (U8500_PER4_BASE + 0x07000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x0f000) #define U8500_PRCMU_TCDM_BASE_V1 (U8500_PER4_BASE + 0x0f000)
#define U8500_PRCMU_TCDM_BASE (U8500_PER4_BASE + 0x68000)
/* per3 base addresses */ /* per3 base addresses */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000) #define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)
......
...@@ -14,27 +14,10 @@ extern struct platform_device u5500_gpio_devs[]; ...@@ -14,27 +14,10 @@ extern struct platform_device u5500_gpio_devs[];
extern struct platform_device u8500_gpio_devs[]; extern struct platform_device u8500_gpio_devs[];
extern struct amba_device ux500_pl031_device; extern struct amba_device ux500_pl031_device;
extern struct amba_device u8500_ssp0_device;
extern struct amba_device ux500_uart0_device;
extern struct amba_device ux500_uart1_device;
extern struct amba_device ux500_uart2_device;
extern struct platform_device ux500_i2c1_device;
extern struct platform_device ux500_i2c2_device;
extern struct platform_device ux500_i2c3_device;
extern struct platform_device u8500_i2c0_device;
extern struct platform_device u8500_i2c4_device;
extern struct platform_device u8500_dma40_device; extern struct platform_device u8500_dma40_device;
extern struct platform_device ux500_ske_keypad_device; extern struct platform_device ux500_ske_keypad_device;
extern struct amba_device u8500_sdi0_device;
extern struct amba_device u8500_sdi1_device;
extern struct amba_device u8500_sdi2_device;
extern struct amba_device u8500_sdi3_device;
extern struct amba_device u8500_sdi4_device;
extern struct amba_device u8500_sdi5_device;
void dma40_u8500ed_fixup(void); void dma40_u8500ed_fixup(void);
#endif #endif
...@@ -9,42 +9,4 @@ ...@@ -9,42 +9,4 @@
#include <plat/gpio.h> #include <plat/gpio.h>
#define __GPIO_RESOURCE(soc, block) \
{ \
.start = soc##_GPIOBANK##block##_BASE, \
.end = soc##_GPIOBANK##block##_BASE + 127, \
.flags = IORESOURCE_MEM, \
}, \
{ \
.start = IRQ_GPIO##block, \
.end = IRQ_GPIO##block, \
.flags = IORESOURCE_IRQ, \
}
#define __GPIO_DEVICE(soc, block) \
{ \
.name = "gpio", \
.id = block, \
.num_resources = 2, \
.resource = &soc##_gpio_resources[block * 2], \
.dev = { \
.platform_data = &soc##_gpio_data[block], \
}, \
}
#define GPIO_DATA(_name, first) \
{ \
.name = _name, \
.first_gpio = first, \
.first_irq = NOMADIK_GPIO_TO_IRQ(first), \
}
#ifdef CONFIG_UX500_SOC_DB8500
#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U8500, block)
#define GPIO_DEVICE(block) __GPIO_DEVICE(u8500, block)
#elif defined(CONFIG_UX500_SOC_DB5500)
#define GPIO_RESOURCE(block) __GPIO_RESOURCE(U5500, block)
#define GPIO_DEVICE(block) __GPIO_DEVICE(u5500, block)
#endif
#endif /* __ASM_ARCH_GPIO_H */ #endif /* __ASM_ARCH_GPIO_H */
...@@ -142,6 +142,8 @@ static inline bool cpu_is_u5500(void) ...@@ -142,6 +142,8 @@ static inline bool cpu_is_u5500(void)
#endif #endif
} }
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
#endif #endif
#endif /* __MACH_HARDWARE_H */ #endif /* __MACH_HARDWARE_H */
...@@ -8,12 +8,36 @@ ...@@ -8,12 +8,36 @@
#ifndef __MACH_IRQS_BOARD_MOP500_H #ifndef __MACH_IRQS_BOARD_MOP500_H
#define __MACH_IRQS_BOARD_MOP500_H #define __MACH_IRQS_BOARD_MOP500_H
#define AB8500_NR_IRQS 104 /* Number of AB8500 irqs is taken from header file */
#include <linux/mfd/ab8500.h>
#define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START #define MOP500_AB8500_IRQ_BASE IRQ_BOARD_START
#define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \ #define MOP500_AB8500_IRQ_END (MOP500_AB8500_IRQ_BASE \
+ AB8500_NR_IRQS) + AB8500_NR_IRQS)
#define MOP500_IRQ_END MOP500_AB8500_IRQ_END
/* TC35892 */
#define TC35892_NR_INTERNAL_IRQS 8
#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x))
#define TC35892_NR_GPIOS 24
#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS)
#define MOP500_EGPIO_NR_IRQS TC35892_NR_IRQS
#define MOP500_EGPIO_IRQ_BASE MOP500_AB8500_IRQ_END
#define MOP500_EGPIO_IRQ_END (MOP500_EGPIO_IRQ_BASE \
+ MOP500_EGPIO_NR_IRQS)
/* STMPE1601 irqs */
#define STMPE_NR_INTERNAL_IRQS 9
#define STMPE_INT_GPIO(x) (STMPE_NR_INTERNAL_IRQS + (x))
#define STMPE_NR_GPIOS 24
#define STMPE_NR_IRQS STMPE_INT_GPIO(STMPE_NR_GPIOS)
#define MOP500_STMPE1601_IRQBASE MOP500_EGPIO_IRQ_END
#define MOP500_STMPE1601_IRQ(x) (MOP500_STMPE1601_IRQBASE + (x))
#define MOP500_NR_IRQS MOP500_STMPE1601_IRQ(STMPE_NR_INTERNAL_IRQS)
#define MOP500_IRQ_END MOP500_NR_IRQS
#if MOP500_IRQ_END > IRQ_BOARD_END #if MOP500_IRQ_END > IRQ_BOARD_END
#undef IRQ_BOARD_END #undef IRQ_BOARD_END
......
...@@ -21,50 +21,6 @@ ...@@ -21,50 +21,6 @@
/* Interrupt numbers generic for shared peripheral */ /* Interrupt numbers generic for shared peripheral */
#define IRQ_MTU0 (IRQ_SHPI_START + 4) #define IRQ_MTU0 (IRQ_SHPI_START + 4)
#define IRQ_SPI2 (IRQ_SHPI_START + 6)
#define IRQ_SPI0 (IRQ_SHPI_START + 8)
#define IRQ_UART0 (IRQ_SHPI_START + 11)
#define IRQ_I2C3 (IRQ_SHPI_START + 12)
#define IRQ_SSP0 (IRQ_SHPI_START + 14)
#define IRQ_MTU1 (IRQ_SHPI_START + 17)
#define IRQ_RTC_RTT (IRQ_SHPI_START + 18)
#define IRQ_UART1 (IRQ_SHPI_START + 19)
#define IRQ_I2C0 (IRQ_SHPI_START + 21)
#define IRQ_I2C1 (IRQ_SHPI_START + 22)
#define IRQ_USBOTG (IRQ_SHPI_START + 23)
#define IRQ_DMA (IRQ_SHPI_START + 25)
#define IRQ_UART2 (IRQ_SHPI_START + 26)
#define IRQ_HSIR_EXCEP (IRQ_SHPI_START + 29)
#define IRQ_MSP0 (IRQ_SHPI_START + 31)
#define IRQ_HSIR_CH0_OVRRUN (IRQ_SHPI_START + 32)
#define IRQ_HSIR_CH1_OVRRUN (IRQ_SHPI_START + 33)
#define IRQ_HSIR_CH2_OVRRUN (IRQ_SHPI_START + 34)
#define IRQ_HSIR_CH3_OVRRUN (IRQ_SHPI_START + 35)
#define IRQ_AB8500 (IRQ_SHPI_START + 40)
#define IRQ_PRCMU (IRQ_SHPI_START + 47)
#define IRQ_DISP (IRQ_SHPI_START + 48)
#define IRQ_SiPI3 (IRQ_SHPI_START + 49)
#define IRQ_I2C4 (IRQ_SHPI_START + 51)
#define IRQ_SSP1 (IRQ_SHPI_START + 52)
#define IRQ_I2C2 (IRQ_SHPI_START + 55)
#define IRQ_SDMMC0 (IRQ_SHPI_START + 60)
#define IRQ_MSP1 (IRQ_SHPI_START + 62)
#define IRQ_SPI1 (IRQ_SHPI_START + 96)
#define IRQ_MSP2 (IRQ_SHPI_START + 98)
#define IRQ_SDMMC4 (IRQ_SHPI_START + 99)
#define IRQ_HSIRD0 (IRQ_SHPI_START + 104)
#define IRQ_HSIRD1 (IRQ_SHPI_START + 105)
#define IRQ_HSITD0 (IRQ_SHPI_START + 106)
#define IRQ_HSITD1 (IRQ_SHPI_START + 107)
#define IRQ_GPIO0 (IRQ_SHPI_START + 119)
#define IRQ_GPIO1 (IRQ_SHPI_START + 120)
#define IRQ_GPIO2 (IRQ_SHPI_START + 121)
#define IRQ_GPIO3 (IRQ_SHPI_START + 122)
#define IRQ_GPIO4 (IRQ_SHPI_START + 123)
#define IRQ_GPIO5 (IRQ_SHPI_START + 124)
#define IRQ_GPIO6 (IRQ_SHPI_START + 125)
#define IRQ_GPIO7 (IRQ_SHPI_START + 126)
#define IRQ_GPIO8 (IRQ_SHPI_START + 127)
/* There are 128 shared peripheral interrupts assigned to /* There are 128 shared peripheral interrupts assigned to
* INTID[160:32]. The first 32 interrupts are reserved. * INTID[160:32]. The first 32 interrupts are reserved.
......
/*
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Martin Persson <martin.persson@stericsson.com>
*
* License Terms: GNU General Public License v2
*
* PRCM Unit definitions
*/
#ifndef __MACH_PRCMU_DEFS_H
#define __MACH_PRCMU_DEFS_H
enum prcmu_cpu_opp {
CPU_OPP_INIT = 0x00,
CPU_OPP_NO_CHANGE = 0x01,
CPU_OPP_100 = 0x02,
CPU_OPP_50 = 0x03,
CPU_OPP_MAX = 0x04,
CPU_OPP_EXT_CLK = 0x07
};
enum prcmu_ape_opp {
APE_OPP_NO_CHANGE = 0x00,
APE_OPP_100 = 0x02,
APE_OPP_50 = 0x03,
};
#endif /* __MACH_PRCMU_DEFS_H */
/* /*
* Copyright (c) 2009 ST-Ericsson SA * Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
* *
* This program is free software; you can redistribute it and/or modify * Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* it under the terms of the GNU General Public License version 2 * Author: Sundar Iyer <sundar.iyer@stericsson.com>
* as published by the Free Software Foundation. *
* License Terms: GNU General Public License v2
*
* PRCM Unit registers
*/ */
#ifndef __MACH_PRCMU_REGS_H #ifndef __MACH_PRCMU_REGS_H
#define __MACH_PRCMU_REGS_H #define __MACH_PRCMU_REGS_H
...@@ -88,4 +93,4 @@ ...@@ -88,4 +93,4 @@
/* Miscellaneous unit registers */ /* Miscellaneous unit registers */
#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324) #define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
#endif /* __MACH_PRCMU__REGS_H */ #endif /* __MACH_PRCMU_REGS_H */
...@@ -2,14 +2,27 @@ ...@@ -2,14 +2,27 @@
* Copyright (C) STMicroelectronics 2009 * Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010 * Copyright (C) ST-Ericsson SA 2010
* *
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
*
* License Terms: GNU General Public License v2 * License Terms: GNU General Public License v2
* *
* PRCMU f/w APIs * PRCM Unit f/w API
*/ */
#ifndef __MACH_PRCMU_H #ifndef __MACH_PRCMU_H
#define __MACH_PRCMU_H #define __MACH_PRCMU_H
#include <mach/prcmu-defs.h>
void __init prcmu_early_init(void);
int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size); int prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size); int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size);
int prcmu_set_ape_opp(enum prcmu_ape_opp opp);
int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp);
int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp);
int prcmu_get_ape_opp(void);
int prcmu_get_cpu_opp(void);
bool prcmu_has_arm_maxopp(void);
#endif /* __MACH_PRCMU_H */ #endif /* __MACH_PRCMU_H */
...@@ -18,14 +18,19 @@ extern void __init ux500_map_io(void); ...@@ -18,14 +18,19 @@ extern void __init ux500_map_io(void);
extern void __init u5500_map_io(void); extern void __init u5500_map_io(void);
extern void __init u8500_map_io(void); extern void __init u8500_map_io(void);
extern void __init ux500_init_devices(void);
extern void __init u5500_init_devices(void); extern void __init u5500_init_devices(void);
extern void __init u8500_init_devices(void); extern void __init u8500_init_devices(void);
extern void __init ux500_init_irq(void); extern void __init ux500_init_irq(void);
extern void __init u5500_sdi_init(void);
extern void __init db5500_dma_init(void);
/* We re-use nomadik_timer for this platform */ /* We re-use nomadik_timer for this platform */
extern void nmdk_timer_init(void); extern void nmdk_timer_init(void);
struct amba_device;
extern void __init amba_add_devices(struct amba_device *devs[], int num); extern void __init amba_add_devices(struct amba_device *devs[], int num);
struct sys_timer; struct sys_timer;
......
...@@ -19,38 +19,43 @@ ...@@ -19,38 +19,43 @@
#define __ASM_ARCH_UNCOMPRESS_H #define __ASM_ARCH_UNCOMPRESS_H
#include <asm/setup.h> #include <asm/setup.h>
#include <asm/mach-types.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/amba/serial.h>
#include <mach/hardware.h> #include <mach/hardware.h>
#define U8500_UART_DR 0x80007000 static u32 ux500_uart_base;
#define U8500_UART_LCRH 0x8000702c
#define U8500_UART_CR 0x80007030
#define U8500_UART_FR 0x80007018
static void putc(const char c) static void putc(const char c)
{ {
/* Do nothing if the UART is not enabled. */ /* Do nothing if the UART is not enabled. */
if (!(__raw_readb(U8500_UART_CR) & 0x1)) if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1))
return; return;
if (c == '\n') if (c == '\n')
putc('\r'); putc('\r');
while (__raw_readb(U8500_UART_FR) & (1 << 5)) while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 5))
barrier(); barrier();
__raw_writeb(c, U8500_UART_DR); __raw_writeb(c, ux500_uart_base + UART01x_DR);
} }
static void flush(void) static void flush(void)
{ {
if (!(__raw_readb(U8500_UART_CR) & 0x1)) if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1))
return; return;
while (__raw_readb(U8500_UART_FR) & (1 << 3)) while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 3))
barrier(); barrier();
} }
static inline void arch_decomp_setup(void) static inline void arch_decomp_setup(void)
{ {
if (machine_is_u8500())
ux500_uart_base = U8500_UART2_BASE;
else if (machine_is_u5500())
ux500_uart_base = U5500_UART0_BASE;
else /* not much can be done to help here */
ux500_uart_base = U8500_UART2_BASE;
} }
#define arch_decomp_wdog() /* nothing to do here */ #define arch_decomp_wdog() /* nothing to do here */
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <linux/completion.h> #include <linux/completion.h>
#include <mach/mbox.h> #include <mach/mbox-db5500.h>
#define MBOX_NAME "mbox" #define MBOX_NAME "mbox"
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* control for which core is the next to come out of the secondary * control for which core is the next to come out of the secondary
* boot "holding pen" * boot "holding pen"
*/ */
volatile int __cpuinitdata pen_release = -1; volatile int pen_release = -1;
static unsigned int __init get_core_count(void) static unsigned int __init get_core_count(void)
{ {
......
/* /*
* Copyright (C) ST Ericsson SA 2010 * Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
* *
* License Terms: GNU General Public License v2 * License Terms: GNU General Public License v2
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
* Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com>
* *
* U8500 PRCMU driver. * U8500 PRCM Unit interface driver
*
*/ */
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -19,11 +23,26 @@ ...@@ -19,11 +23,26 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/prcmu-regs.h> #include <mach/prcmu-regs.h>
#include <mach/prcmu-defs.h>
/* Global var to runtime determine TCDM base for v2 or v1 */
static __iomem void *tcdm_base;
#define _MBOX_HEADER (tcdm_base + 0xFE8)
#define MBOX_HEADER_REQ_MB0 (_MBOX_HEADER + 0x0)
#define REQ_MB1 (tcdm_base + 0xFD0)
#define REQ_MB5 (tcdm_base + 0xE44)
#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE) #define REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44) #define ACK_MB1 (tcdm_base + 0xE04)
#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4) #define ACK_MB5 (tcdm_base + 0xDF4)
#define ACK_MB1_CURR_ARMOPP (ACK_MB1 + 0x0)
#define ACK_MB1_CURR_APEOPP (ACK_MB1 + 0x1)
#define REQ_MB5_I2C_SLAVE_OP (REQ_MB5) #define REQ_MB5_I2C_SLAVE_OP (REQ_MB5)
#define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1) #define REQ_MB5_I2C_HW_BITS (REQ_MB5 + 1)
...@@ -33,10 +52,33 @@ ...@@ -33,10 +52,33 @@
#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1) #define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
#define ACK_MB5_I2C_VAL (ACK_MB5 + 3) #define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
#define I2C_WRITE(slave) ((slave) << 1) #define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
#define I2C_READ(slave) (((slave) << 1) | BIT(0)) #define PRCM_AVS_ISMODEENABLE 7
#define PRCM_AVS_ISMODEENABLE_MASK (1 << PRCM_AVS_ISMODEENABLE)
#define I2C_WRITE(slave) \
(((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0))
#define I2C_READ(slave) \
(((slave) << 1) | (cpu_is_u8500v2() ? BIT(6) : 0) | BIT(0))
#define I2C_STOP_EN BIT(3) #define I2C_STOP_EN BIT(3)
enum mb1_h {
MB1H_ARM_OPP = 1,
MB1H_APE_OPP,
MB1H_ARM_APE_OPP,
};
static struct {
struct mutex lock;
struct completion work;
struct {
u8 arm_opp;
u8 ape_opp;
u8 arm_status;
u8 ape_status;
} ack;
} mb1_transfer;
enum ack_mb5_status { enum ack_mb5_status {
I2C_WR_OK = 0x01, I2C_WR_OK = 0x01,
I2C_RD_OK = 0x02, I2C_RD_OK = 0x02,
...@@ -145,6 +187,104 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) ...@@ -145,6 +187,104 @@ int prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size)
} }
EXPORT_SYMBOL(prcmu_abb_write); EXPORT_SYMBOL(prcmu_abb_write);
static int set_ape_cpu_opps(u8 header, enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp)
{
bool do_ape;
bool do_arm;
int err = 0;
do_ape = ((header == MB1H_APE_OPP) || (header == MB1H_ARM_APE_OPP));
do_arm = ((header == MB1H_ARM_OPP) || (header == MB1H_ARM_APE_OPP));
mutex_lock(&mb1_transfer.lock);
while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(1))
cpu_relax();
writeb(0, MBOX_HEADER_REQ_MB0);
writeb(cpu_opp, REQ_MB1_ARMOPP);
writeb(ape_opp, REQ_MB1_APEOPP);
writeb(0, REQ_MB1_BOOSTOPP);
writel(MBOX_BIT(1), PRCM_MBOX_CPU_SET);
wait_for_completion(&mb1_transfer.work);
if ((do_ape) && (mb1_transfer.ack.ape_status != 0))
err = -EIO;
if ((do_arm) && (mb1_transfer.ack.arm_status != 0))
err = -EIO;
mutex_unlock(&mb1_transfer.lock);
return err;
}
/**
* prcmu_set_ape_opp() - Set the OPP of the APE.
* @opp: The OPP to set.
*
* This function sets the OPP of the APE.
*/
int prcmu_set_ape_opp(enum prcmu_ape_opp opp)
{
return set_ape_cpu_opps(MB1H_APE_OPP, opp, APE_OPP_NO_CHANGE);
}
EXPORT_SYMBOL(prcmu_set_ape_opp);
/**
* prcmu_set_cpu_opp() - Set the OPP of the CPU.
* @opp: The OPP to set.
*
* This function sets the OPP of the CPU.
*/
int prcmu_set_cpu_opp(enum prcmu_cpu_opp opp)
{
return set_ape_cpu_opps(MB1H_ARM_OPP, CPU_OPP_NO_CHANGE, opp);
}
EXPORT_SYMBOL(prcmu_set_cpu_opp);
/**
* prcmu_set_ape_cpu_opps() - Set the OPPs of the APE and the CPU.
* @ape_opp: The APE OPP to set.
* @cpu_opp: The CPU OPP to set.
*
* This function sets the OPPs of the APE and the CPU.
*/
int prcmu_set_ape_cpu_opps(enum prcmu_ape_opp ape_opp,
enum prcmu_cpu_opp cpu_opp)
{
return set_ape_cpu_opps(MB1H_ARM_APE_OPP, ape_opp, cpu_opp);
}
EXPORT_SYMBOL(prcmu_set_ape_cpu_opps);
/**
* prcmu_get_ape_opp() - Get the OPP of the APE.
*
* This function gets the OPP of the APE.
*/
enum prcmu_ape_opp prcmu_get_ape_opp(void)
{
return readb(ACK_MB1_CURR_APEOPP);
}
EXPORT_SYMBOL(prcmu_get_ape_opp);
/**
* prcmu_get_cpu_opp() - Get the OPP of the CPU.
*
* This function gets the OPP of the CPU. The OPP is specified in %%.
* PRCMU_OPP_EXT is a special OPP value, not specified in %%.
*/
int prcmu_get_cpu_opp(void)
{
return readb(ACK_MB1_CURR_ARMOPP);
}
EXPORT_SYMBOL(prcmu_get_cpu_opp);
bool prcmu_has_arm_maxopp(void)
{
return (readb(PRCM_AVS_VARM_MAX_OPP) & PRCM_AVS_ISMODEENABLE_MASK)
== PRCM_AVS_ISMODEENABLE_MASK;
}
static void read_mailbox_0(void) static void read_mailbox_0(void)
{ {
writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR); writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
...@@ -152,6 +292,9 @@ static void read_mailbox_0(void) ...@@ -152,6 +292,9 @@ static void read_mailbox_0(void)
static void read_mailbox_1(void) static void read_mailbox_1(void)
{ {
mb1_transfer.ack.arm_opp = readb(ACK_MB1_CURR_ARMOPP);
mb1_transfer.ack.ape_opp = readb(ACK_MB1_CURR_APEOPP);
complete(&mb1_transfer.work);
writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR); writel(MBOX_BIT(1), PRCM_ARM_IT1_CLEAR);
} }
...@@ -217,15 +360,35 @@ static irqreturn_t prcmu_irq_handler(int irq, void *data) ...@@ -217,15 +360,35 @@ static irqreturn_t prcmu_irq_handler(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
void __init prcmu_early_init(void)
{
if (cpu_is_u8500v11() || cpu_is_u8500ed()) {
tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE_V1);
} else if (cpu_is_u8500v2()) {
tcdm_base = __io_address(U8500_PRCMU_TCDM_BASE);
} else {
pr_err("prcmu: Unsupported chip version\n");
BUG();
}
}
static int __init prcmu_init(void) static int __init prcmu_init(void)
{ {
if (cpu_is_u8500ed()) {
pr_err("prcmu: Unsupported chip version\n");
return 0;
}
mutex_init(&mb1_transfer.lock);
init_completion(&mb1_transfer.work);
mutex_init(&mb5_transfer.lock); mutex_init(&mb5_transfer.lock);
init_completion(&mb5_transfer.work); init_completion(&mb5_transfer.work);
/* Clean up the mailbox interrupts after pre-kernel code. */ /* Clean up the mailbox interrupts after pre-kernel code. */
writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR); writel((MBOX_BIT(NUM_MBOX) - 1), PRCM_ARM_IT1_CLEAR);
return request_irq(IRQ_PRCMU, prcmu_irq_handler, 0, "prcmu", NULL); return request_irq(IRQ_DB8500_PRCMU1, prcmu_irq_handler, 0,
"prcmu", NULL);
} }
arch_initcall(prcmu_init); arch_initcall(prcmu_init);
...@@ -119,7 +119,7 @@ static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip, ...@@ -119,7 +119,7 @@ static void __nmk_gpio_make_output(struct nmk_gpio_chip *nmk_chip,
} }
static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
pin_cfg_t cfg) pin_cfg_t cfg, bool sleep)
{ {
static const char *afnames[] = { static const char *afnames[] = {
[NMK_GPIO_ALT_GPIO] = "GPIO", [NMK_GPIO_ALT_GPIO] = "GPIO",
...@@ -145,11 +145,34 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, ...@@ -145,11 +145,34 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
int output = PIN_DIR(cfg); int output = PIN_DIR(cfg);
int val = PIN_VAL(cfg); int val = PIN_VAL(cfg);
dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n", dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
pin, afnames[af], pullnames[pull], slpmnames[slpm], pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
output ? "output " : "input", output ? "output " : "input",
output ? (val ? "high" : "low") : ""); output ? (val ? "high" : "low") : "");
if (sleep) {
int slpm_pull = PIN_SLPM_PULL(cfg);
int slpm_output = PIN_SLPM_DIR(cfg);
int slpm_val = PIN_SLPM_VAL(cfg);
/*
* The SLPM_* values are normal values + 1 to allow zero to
* mean "same as normal".
*/
if (slpm_pull)
pull = slpm_pull - 1;
if (slpm_output)
output = slpm_output - 1;
if (slpm_val)
val = slpm_val - 1;
dev_dbg(nmk_chip->chip.dev, "pin %d: sleep pull %s, dir %s, val %s\n",
pin,
slpm_pull ? pullnames[pull] : "same",
slpm_output ? (output ? "output" : "input") : "same",
slpm_val ? (val ? "high" : "low") : "same");
}
if (output) if (output)
__nmk_gpio_make_output(nmk_chip, offset, val); __nmk_gpio_make_output(nmk_chip, offset, val);
else { else {
...@@ -175,7 +198,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset, ...@@ -175,7 +198,7 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
* side-effects. The gpio can be manipulated later using standard GPIO API * side-effects. The gpio can be manipulated later using standard GPIO API
* calls. * calls.
*/ */
int nmk_config_pin(pin_cfg_t cfg) int nmk_config_pin(pin_cfg_t cfg, bool sleep)
{ {
struct nmk_gpio_chip *nmk_chip; struct nmk_gpio_chip *nmk_chip;
int gpio = PIN_NUM(cfg); int gpio = PIN_NUM(cfg);
...@@ -186,7 +209,7 @@ int nmk_config_pin(pin_cfg_t cfg) ...@@ -186,7 +209,7 @@ int nmk_config_pin(pin_cfg_t cfg)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&nmk_chip->lock, flags); spin_lock_irqsave(&nmk_chip->lock, flags);
__nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg); __nmk_config_pin(nmk_chip, gpio - nmk_chip->chip.base, cfg, sleep);
spin_unlock_irqrestore(&nmk_chip->lock, flags); spin_unlock_irqrestore(&nmk_chip->lock, flags);
return 0; return 0;
...@@ -207,7 +230,7 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num) ...@@ -207,7 +230,7 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num)
int i; int i;
for (i = 0; i < num; i++) { for (i = 0; i < num; i++) {
int ret = nmk_config_pin(cfgs[i]); ret = nmk_config_pin(cfgs[i], false);
if (ret) if (ret)
break; break;
} }
...@@ -216,6 +239,21 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num) ...@@ -216,6 +239,21 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num)
} }
EXPORT_SYMBOL(nmk_config_pins); EXPORT_SYMBOL(nmk_config_pins);
int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num)
{
int ret = 0;
int i;
for (i = 0; i < num; i++) {
ret = nmk_config_pin(cfgs[i], true);
if (ret)
break;
}
return ret;
}
EXPORT_SYMBOL(nmk_config_pins_sleep);
/** /**
* nmk_gpio_set_slpm() - configure the sleep mode of a pin * nmk_gpio_set_slpm() - configure the sleep mode of a pin
* @gpio: pin number * @gpio: pin number
...@@ -634,7 +672,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev) ...@@ -634,7 +672,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
chip = &nmk_chip->chip; chip = &nmk_chip->chip;
chip->base = pdata->first_gpio; chip->base = pdata->first_gpio;
chip->label = pdata->name; chip->label = pdata->name ?: dev_name(&dev->dev);
chip->dev = &dev->dev; chip->dev = &dev->dev;
chip->owner = THIS_MODULE; chip->owner = THIS_MODULE;
......
...@@ -19,16 +19,22 @@ ...@@ -19,16 +19,22 @@
* bit 9..10 - Alternate Function Selection * bit 9..10 - Alternate Function Selection
* bit 11..12 - Pull up/down state * bit 11..12 - Pull up/down state
* bit 13 - Sleep mode behaviour * bit 13 - Sleep mode behaviour
* bit 14 - (sleep mode) Direction * bit 14 - Direction
* bit 15 - (sleep mode) Value (if output) * bit 15 - Value (if output)
* bit 16..18 - SLPM pull up/down state
* bit 19..20 - SLPM direction
* bit 21..22 - SLPM Value (if output)
* *
* to facilitate the definition, the following macros are provided * to facilitate the definition, the following macros are provided
* *
* PIN_CFG_DEFAULT - default config (0): * PIN_CFG_DEFAULT - default config (0):
* pull up/down = disabled * pull up/down = disabled
* sleep mode = input/wakeup * sleep mode = input/wakeup
* (sleep mode) direction = input * direction = input
* (sleep mode) value = low * value = low
* SLPM direction = same as normal
* SLPM pull = same as normal
* SLPM value = same as normal
* *
* PIN_CFG - default config with alternate function * PIN_CFG - default config with alternate function
* PIN_CFG_PULL - default config with alternate function and pull up/down * PIN_CFG_PULL - default config with alternate function and pull up/down
...@@ -75,30 +81,64 @@ typedef unsigned long pin_cfg_t; ...@@ -75,30 +81,64 @@ typedef unsigned long pin_cfg_t;
#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT) #define PIN_VAL_LOW (0 << PIN_VAL_SHIFT)
#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT) #define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT)
/* Shortcuts. Use these instead of separate DIR and VAL. */ #define PIN_SLPM_PULL_SHIFT 16
#define PIN_INPUT PIN_DIR_INPUT #define PIN_SLPM_PULL_MASK (0x7 << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL(x) \
(((x) & PIN_SLPM_PULL_MASK) >> PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_NONE \
((1 + NMK_GPIO_PULL_NONE) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_UP \
((1 + NMK_GPIO_PULL_UP) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_PULL_DOWN \
((1 + NMK_GPIO_PULL_DOWN) << PIN_SLPM_PULL_SHIFT)
#define PIN_SLPM_DIR_SHIFT 19
#define PIN_SLPM_DIR_MASK (0x3 << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR(x) \
(((x) & PIN_SLPM_DIR_MASK) >> PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR_INPUT ((1 + 0) << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_DIR_OUTPUT ((1 + 1) << PIN_SLPM_DIR_SHIFT)
#define PIN_SLPM_VAL_SHIFT 21
#define PIN_SLPM_VAL_MASK (0x3 << PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL(x) \
(((x) & PIN_SLPM_VAL_MASK) >> PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL_LOW ((1 + 0) << PIN_SLPM_VAL_SHIFT)
#define PIN_SLPM_VAL_HIGH ((1 + 1) << PIN_SLPM_VAL_SHIFT)
/* Shortcuts. Use these instead of separate DIR, PULL, and VAL. */
#define PIN_INPUT_PULLDOWN (PIN_DIR_INPUT | PIN_PULL_DOWN)
#define PIN_INPUT_PULLUP (PIN_DIR_INPUT | PIN_PULL_UP)
#define PIN_INPUT_NOPULL (PIN_DIR_INPUT | PIN_PULL_NONE)
#define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW) #define PIN_OUTPUT_LOW (PIN_DIR_OUTPUT | PIN_VAL_LOW)
#define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH) #define PIN_OUTPUT_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
/* #define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN)
* These are the same as the ones above, but should make more sense to the #define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP)
* reader when seen along with a setting a pin to AF mode. #define PIN_SLPM_INPUT_NOPULL (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_NONE)
*/ #define PIN_SLPM_OUTPUT_LOW (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_LOW)
#define PIN_SLPM_INPUT PIN_INPUT #define PIN_SLPM_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH)
#define PIN_SLPM_OUTPUT_LOW PIN_OUTPUT_LOW
#define PIN_SLPM_OUTPUT_HIGH PIN_OUTPUT_HIGH
#define PIN_CFG_DEFAULT (PIN_PULL_NONE | PIN_SLPM_INPUT) #define PIN_CFG_DEFAULT (0)
#define PIN_CFG(num, alt) \ #define PIN_CFG(num, alt) \
(PIN_CFG_DEFAULT |\ (PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt)) (PIN_NUM(num) | PIN_##alt))
#define PIN_CFG_INPUT(num, alt, pull) \
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_INPUT_##pull))
#define PIN_CFG_OUTPUT(num, alt, val) \
(PIN_CFG_DEFAULT |\
(PIN_NUM(num) | PIN_##alt | PIN_OUTPUT_##val))
#define PIN_CFG_PULL(num, alt, pull) \ #define PIN_CFG_PULL(num, alt, pull) \
((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\ ((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\
(PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull)) (PIN_NUM(num) | PIN_##alt | PIN_PULL_##pull))
extern int nmk_config_pin(pin_cfg_t cfg); extern int nmk_config_pin(pin_cfg_t cfg, bool sleep);
extern int nmk_config_pins(pin_cfg_t *cfgs, int num); extern int nmk_config_pins(pin_cfg_t *cfgs, int num);
extern int nmk_config_pins_sleep(pin_cfg_t *cfgs, int num);
#endif #endif
...@@ -230,11 +230,11 @@ config GPIO_STMPE ...@@ -230,11 +230,11 @@ config GPIO_STMPE
This enables support for the GPIOs found on the STMPE I/O This enables support for the GPIOs found on the STMPE I/O
Expanders. Expanders.
config GPIO_TC35892 config GPIO_TC3589X
bool "TC35892 GPIOs" bool "TC3589X GPIOs"
depends on MFD_TC35892 depends on MFD_TC3589X
help help
This enables support for the GPIOs found on the TC35892 This enables support for the GPIOs found on the TC3589X
I/O Expander. I/O Expander.
config GPIO_TWL4030 config GPIO_TWL4030
......
...@@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o ...@@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PCH) += pch_gpio.o obj-$(CONFIG_GPIO_PCH) += pch_gpio.o
obj-$(CONFIG_GPIO_PL061) += pl061.o obj-$(CONFIG_GPIO_PL061) += pl061.o
obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o obj-$(CONFIG_GPIO_STMPE) += stmpe-gpio.o
obj-$(CONFIG_GPIO_TC35892) += tc35892-gpio.o obj-$(CONFIG_GPIO_TC3589X) += tc3589x-gpio.o
obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o obj-$(CONFIG_GPIO_TIMBERDALE) += timbgpio.o
obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o obj-$(CONFIG_GPIO_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o
......
...@@ -459,6 +459,16 @@ config KEYBOARD_OMAP4 ...@@ -459,6 +459,16 @@ config KEYBOARD_OMAP4
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called omap4-keypad. module will be called omap4-keypad.
config KEYBOARD_TC3589X
tristate "TC3589X Keypad support"
depends on MFD_TC3589X
help
Say Y here if you want to use the keypad controller on
TC35892/3 I/O expander.
To compile this driver as a module, choose M here: the
module will be called tc3589x-keypad.
config KEYBOARD_TNETV107X config KEYBOARD_TNETV107X
tristate "TI TNETV107X keypad support" tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X depends on ARCH_DAVINCI_TNETV107X
......
...@@ -41,6 +41,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o ...@@ -41,6 +41,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o
......
This diff is collapsed.
...@@ -218,12 +218,12 @@ config MFD_STMPE ...@@ -218,12 +218,12 @@ config MFD_STMPE
Keypad: stmpe-keypad Keypad: stmpe-keypad
Touchscreen: stmpe-ts Touchscreen: stmpe-ts
config MFD_TC35892 config MFD_TC3589X
bool "Support Toshiba TC35892" bool "Support Toshiba TC35892 and variants"
depends on I2C=y && GENERIC_HARDIRQS depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE select MFD_CORE
help help
Support for the Toshiba TC35892 I/O Expander. Support for the Toshiba TC35892 and variants I/O Expander.
This driver provides common support for accessing the device, This driver provides common support for accessing the device,
additional drivers must be enabled in order to use the additional drivers must be enabled in order to use the
......
...@@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o ...@@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
obj-$(CONFIG_MFD_STMPE) += stmpe.o obj-$(CONFIG_MFD_STMPE) += stmpe.o
obj-$(CONFIG_MFD_TC35892) += tc35892.o obj-$(CONFIG_MFD_TC3589X) += tc3589x.o
obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
......
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tc35892.h>
/**
* tc35892_reg_read() - read a single TC35892 register
* @tc35892: Device to read from
* @reg: Register to read
*/
int tc35892_reg_read(struct tc35892 *tc35892, u8 reg)
{
int ret;
ret = i2c_smbus_read_byte_data(tc35892->i2c, reg);
if (ret < 0)
dev_err(tc35892->dev, "failed to read reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_reg_read);
/**
* tc35892_reg_read() - write a single TC35892 register
* @tc35892: Device to write to
* @reg: Register to read
* @data: Value to write
*/
int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data)
{
int ret;
ret = i2c_smbus_write_byte_data(tc35892->i2c, reg, data);
if (ret < 0)
dev_err(tc35892->dev, "failed to write reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_reg_write);
/**
* tc35892_block_read() - read multiple TC35892 registers
* @tc35892: Device to read from
* @reg: First register
* @length: Number of registers
* @values: Buffer to write to
*/
int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length, u8 *values)
{
int ret;
ret = i2c_smbus_read_i2c_block_data(tc35892->i2c, reg, length, values);
if (ret < 0)
dev_err(tc35892->dev, "failed to read regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_block_read);
/**
* tc35892_block_write() - write multiple TC35892 registers
* @tc35892: Device to write to
* @reg: First register
* @length: Number of registers
* @values: Values to write
*/
int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length,
const u8 *values)
{
int ret;
ret = i2c_smbus_write_i2c_block_data(tc35892->i2c, reg, length,
values);
if (ret < 0)
dev_err(tc35892->dev, "failed to write regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_block_write);
/**
* tc35892_set_bits() - set the value of a bitfield in a TC35892 register
* @tc35892: Device to write to
* @reg: Register to write
* @mask: Mask of bits to set
* @values: Value to set
*/
int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val)
{
int ret;
mutex_lock(&tc35892->lock);
ret = tc35892_reg_read(tc35892, reg);
if (ret < 0)
goto out;
ret &= ~mask;
ret |= val;
ret = tc35892_reg_write(tc35892, reg, ret);
out:
mutex_unlock(&tc35892->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tc35892_set_bits);
static struct resource gpio_resources[] = {
{
.start = TC35892_INT_GPIIRQ,
.end = TC35892_INT_GPIIRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell tc35892_devs[] = {
{
.name = "tc35892-gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = &gpio_resources[0],
},
};
static irqreturn_t tc35892_irq(int irq, void *data)
{
struct tc35892 *tc35892 = data;
int status;
status = tc35892_reg_read(tc35892, TC35892_IRQST);
if (status < 0)
return IRQ_NONE;
while (status) {
int bit = __ffs(status);
handle_nested_irq(tc35892->irq_base + bit);
status &= ~(1 << bit);
}
/*
* A dummy read or write (to any register) appears to be necessary to
* have the last interrupt clear (for example, GPIO IC write) take
* effect.
*/
tc35892_reg_read(tc35892, TC35892_IRQST);
return IRQ_HANDLED;
}
static void tc35892_irq_dummy(unsigned int irq)
{
/* No mask/unmask at this level */
}
static struct irq_chip tc35892_irq_chip = {
.name = "tc35892",
.mask = tc35892_irq_dummy,
.unmask = tc35892_irq_dummy,
};
static int tc35892_irq_init(struct tc35892 *tc35892)
{
int base = tc35892->irq_base;
int irq;
for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
set_irq_chip_data(irq, tc35892);
set_irq_chip_and_handler(irq, &tc35892_irq_chip,
handle_edge_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void tc35892_irq_remove(struct tc35892 *tc35892)
{
int base = tc35892->irq_base;
int irq;
for (irq = base; irq < base + TC35892_NR_INTERNAL_IRQS; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static int tc35892_chip_init(struct tc35892 *tc35892)
{
int manf, ver, ret;
manf = tc35892_reg_read(tc35892, TC35892_MANFCODE);
if (manf < 0)
return manf;
ver = tc35892_reg_read(tc35892, TC35892_VERSION);
if (ver < 0)
return ver;
if (manf != TC35892_MANFCODE_MAGIC) {
dev_err(tc35892->dev, "unknown manufacturer: %#x\n", manf);
return -EINVAL;
}
dev_info(tc35892->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
/* Put everything except the IRQ module into reset */
ret = tc35892_reg_write(tc35892, TC35892_RSTCTRL,
TC35892_RSTCTRL_TIMRST
| TC35892_RSTCTRL_ROTRST
| TC35892_RSTCTRL_KBDRST
| TC35892_RSTCTRL_GPIRST);
if (ret < 0)
return ret;
/* Clear the reset interrupt. */
return tc35892_reg_write(tc35892, TC35892_RSTINTCLR, 0x1);
}
static int __devinit tc35892_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tc35892_platform_data *pdata = i2c->dev.platform_data;
struct tc35892 *tc35892;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
tc35892 = kzalloc(sizeof(struct tc35892), GFP_KERNEL);
if (!tc35892)
return -ENOMEM;
mutex_init(&tc35892->lock);
tc35892->dev = &i2c->dev;
tc35892->i2c = i2c;
tc35892->pdata = pdata;
tc35892->irq_base = pdata->irq_base;
tc35892->num_gpio = id->driver_data;
i2c_set_clientdata(i2c, tc35892);
ret = tc35892_chip_init(tc35892);
if (ret)
goto out_free;
ret = tc35892_irq_init(tc35892);
if (ret)
goto out_free;
ret = request_threaded_irq(tc35892->i2c->irq, NULL, tc35892_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tc35892", tc35892);
if (ret) {
dev_err(tc35892->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
}
ret = mfd_add_devices(tc35892->dev, -1, tc35892_devs,
ARRAY_SIZE(tc35892_devs), NULL,
tc35892->irq_base);
if (ret) {
dev_err(tc35892->dev, "failed to add children\n");
goto out_freeirq;
}
return 0;
out_freeirq:
free_irq(tc35892->i2c->irq, tc35892);
out_removeirq:
tc35892_irq_remove(tc35892);
out_free:
kfree(tc35892);
return ret;
}
static int __devexit tc35892_remove(struct i2c_client *client)
{
struct tc35892 *tc35892 = i2c_get_clientdata(client);
mfd_remove_devices(tc35892->dev);
free_irq(tc35892->i2c->irq, tc35892);
tc35892_irq_remove(tc35892);
kfree(tc35892);
return 0;
}
static const struct i2c_device_id tc35892_id[] = {
{ "tc35892", 24 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc35892_id);
static struct i2c_driver tc35892_driver = {
.driver.name = "tc35892",
.driver.owner = THIS_MODULE,
.probe = tc35892_probe,
.remove = __devexit_p(tc35892_remove),
.id_table = tc35892_id,
};
static int __init tc35892_init(void)
{
return i2c_add_driver(&tc35892_driver);
}
subsys_initcall(tc35892_init);
static void __exit tc35892_exit(void)
{
i2c_del_driver(&tc35892_driver);
}
module_exit(tc35892_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC35892 MFD core driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
* Author: Hanumath Prasad <hanumath.prasad@stericsson.com> for ST-Ericsson
* Author: Rabin Vincent <rabin.vincent@stericsson.com> for ST-Ericsson
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tc3589x.h>
#define TC3589x_CLKMODE_MODCTL_SLEEP 0x0
#define TC3589x_CLKMODE_MODCTL_OPERATION (1 << 0)
/**
* tc3589x_reg_read() - read a single TC3589x register
* @tc3589x: Device to read from
* @reg: Register to read
*/
int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg)
{
int ret;
ret = i2c_smbus_read_byte_data(tc3589x->i2c, reg);
if (ret < 0)
dev_err(tc3589x->dev, "failed to read reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc3589x_reg_read);
/**
* tc3589x_reg_read() - write a single TC3589x register
* @tc3589x: Device to write to
* @reg: Register to read
* @data: Value to write
*/
int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data)
{
int ret;
ret = i2c_smbus_write_byte_data(tc3589x->i2c, reg, data);
if (ret < 0)
dev_err(tc3589x->dev, "failed to write reg %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc3589x_reg_write);
/**
* tc3589x_block_read() - read multiple TC3589x registers
* @tc3589x: Device to read from
* @reg: First register
* @length: Number of registers
* @values: Buffer to write to
*/
int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length, u8 *values)
{
int ret;
ret = i2c_smbus_read_i2c_block_data(tc3589x->i2c, reg, length, values);
if (ret < 0)
dev_err(tc3589x->dev, "failed to read regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc3589x_block_read);
/**
* tc3589x_block_write() - write multiple TC3589x registers
* @tc3589x: Device to write to
* @reg: First register
* @length: Number of registers
* @values: Values to write
*/
int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
const u8 *values)
{
int ret;
ret = i2c_smbus_write_i2c_block_data(tc3589x->i2c, reg, length,
values);
if (ret < 0)
dev_err(tc3589x->dev, "failed to write regs %#x: %d\n",
reg, ret);
return ret;
}
EXPORT_SYMBOL_GPL(tc3589x_block_write);
/**
* tc3589x_set_bits() - set the value of a bitfield in a TC3589x register
* @tc3589x: Device to write to
* @reg: Register to write
* @mask: Mask of bits to set
* @values: Value to set
*/
int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val)
{
int ret;
mutex_lock(&tc3589x->lock);
ret = tc3589x_reg_read(tc3589x, reg);
if (ret < 0)
goto out;
ret &= ~mask;
ret |= val;
ret = tc3589x_reg_write(tc3589x, reg, ret);
out:
mutex_unlock(&tc3589x->lock);
return ret;
}
EXPORT_SYMBOL_GPL(tc3589x_set_bits);
static struct resource gpio_resources[] = {
{
.start = TC3589x_INT_GPIIRQ,
.end = TC3589x_INT_GPIIRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct resource keypad_resources[] = {
{
.start = TC3589x_INT_KBDIRQ,
.end = TC3589x_INT_KBDIRQ,
.flags = IORESOURCE_IRQ,
},
};
static struct mfd_cell tc3589x_dev_gpio[] = {
{
.name = "tc3589x-gpio",
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = &gpio_resources[0],
},
};
static struct mfd_cell tc3589x_dev_keypad[] = {
{
.name = "tc3589x-keypad",
.num_resources = ARRAY_SIZE(keypad_resources),
.resources = &keypad_resources[0],
},
};
static irqreturn_t tc3589x_irq(int irq, void *data)
{
struct tc3589x *tc3589x = data;
int status;
again:
status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
if (status < 0)
return IRQ_NONE;
while (status) {
int bit = __ffs(status);
handle_nested_irq(tc3589x->irq_base + bit);
status &= ~(1 << bit);
}
/*
* A dummy read or write (to any register) appears to be necessary to
* have the last interrupt clear (for example, GPIO IC write) take
* effect. In such a case, recheck for any interrupt which is still
* pending.
*/
status = tc3589x_reg_read(tc3589x, TC3589x_IRQST);
if (status)
goto again;
return IRQ_HANDLED;
}
static int tc3589x_irq_init(struct tc3589x *tc3589x)
{
int base = tc3589x->irq_base;
int irq;
for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
set_irq_chip_data(irq, tc3589x);
set_irq_chip_and_handler(irq, &dummy_irq_chip,
handle_edge_irq);
set_irq_nested_thread(irq, 1);
#ifdef CONFIG_ARM
set_irq_flags(irq, IRQF_VALID);
#else
set_irq_noprobe(irq);
#endif
}
return 0;
}
static void tc3589x_irq_remove(struct tc3589x *tc3589x)
{
int base = tc3589x->irq_base;
int irq;
for (irq = base; irq < base + TC3589x_NR_INTERNAL_IRQS; irq++) {
#ifdef CONFIG_ARM
set_irq_flags(irq, 0);
#endif
set_irq_chip_and_handler(irq, NULL, NULL);
set_irq_chip_data(irq, NULL);
}
}
static int tc3589x_chip_init(struct tc3589x *tc3589x)
{
int manf, ver, ret;
manf = tc3589x_reg_read(tc3589x, TC3589x_MANFCODE);
if (manf < 0)
return manf;
ver = tc3589x_reg_read(tc3589x, TC3589x_VERSION);
if (ver < 0)
return ver;
if (manf != TC3589x_MANFCODE_MAGIC) {
dev_err(tc3589x->dev, "unknown manufacturer: %#x\n", manf);
return -EINVAL;
}
dev_info(tc3589x->dev, "manufacturer: %#x, version: %#x\n", manf, ver);
/*
* Put everything except the IRQ module into reset;
* also spare the GPIO module for any pin initialization
* done during pre-kernel boot
*/
ret = tc3589x_reg_write(tc3589x, TC3589x_RSTCTRL,
TC3589x_RSTCTRL_TIMRST
| TC3589x_RSTCTRL_ROTRST
| TC3589x_RSTCTRL_KBDRST);
if (ret < 0)
return ret;
/* Clear the reset interrupt. */
return tc3589x_reg_write(tc3589x, TC3589x_RSTINTCLR, 0x1);
}
static int __devinit tc3589x_device_init(struct tc3589x *tc3589x)
{
int ret = 0;
unsigned int blocks = tc3589x->pdata->block;
if (blocks & TC3589x_BLOCK_GPIO) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
ARRAY_SIZE(tc3589x_dev_gpio), NULL,
tc3589x->irq_base);
if (ret) {
dev_err(tc3589x->dev, "failed to add gpio child\n");
return ret;
}
dev_info(tc3589x->dev, "added gpio block\n");
}
if (blocks & TC3589x_BLOCK_KEYPAD) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
ARRAY_SIZE(tc3589x_dev_keypad), NULL,
tc3589x->irq_base);
if (ret) {
dev_err(tc3589x->dev, "failed to keypad child\n");
return ret;
}
dev_info(tc3589x->dev, "added keypad block\n");
}
return ret;
}
static int __devinit tc3589x_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct tc3589x_platform_data *pdata = i2c->dev.platform_data;
struct tc3589x *tc3589x;
int ret;
if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
| I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
tc3589x = kzalloc(sizeof(struct tc3589x), GFP_KERNEL);
if (!tc3589x)
return -ENOMEM;
mutex_init(&tc3589x->lock);
tc3589x->dev = &i2c->dev;
tc3589x->i2c = i2c;
tc3589x->pdata = pdata;
tc3589x->irq_base = pdata->irq_base;
tc3589x->num_gpio = id->driver_data;
i2c_set_clientdata(i2c, tc3589x);
ret = tc3589x_chip_init(tc3589x);
if (ret)
goto out_free;
ret = tc3589x_irq_init(tc3589x);
if (ret)
goto out_free;
ret = request_threaded_irq(tc3589x->i2c->irq, NULL, tc3589x_irq,
IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
"tc3589x", tc3589x);
if (ret) {
dev_err(tc3589x->dev, "failed to request IRQ: %d\n", ret);
goto out_removeirq;
}
ret = tc3589x_device_init(tc3589x);
if (ret) {
dev_err(tc3589x->dev, "failed to add child devices\n");
goto out_freeirq;
}
return 0;
out_freeirq:
free_irq(tc3589x->i2c->irq, tc3589x);
out_removeirq:
tc3589x_irq_remove(tc3589x);
out_free:
kfree(tc3589x);
return ret;
}
static int __devexit tc3589x_remove(struct i2c_client *client)
{
struct tc3589x *tc3589x = i2c_get_clientdata(client);
mfd_remove_devices(tc3589x->dev);
free_irq(tc3589x->i2c->irq, tc3589x);
tc3589x_irq_remove(tc3589x);
kfree(tc3589x);
return 0;
}
static int tc3589x_suspend(struct device *dev)
{
struct tc3589x *tc3589x = dev_get_drvdata(dev);
struct i2c_client *client = tc3589x->i2c;
int ret = 0;
/* put the system to sleep mode */
if (!device_may_wakeup(&client->dev))
ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
TC3589x_CLKMODE_MODCTL_SLEEP);
return ret;
}
static int tc3589x_resume(struct device *dev)
{
struct tc3589x *tc3589x = dev_get_drvdata(dev);
struct i2c_client *client = tc3589x->i2c;
int ret = 0;
/* enable the system into operation */
if (!device_may_wakeup(&client->dev))
ret = tc3589x_reg_write(tc3589x, TC3589x_CLKMODE,
TC3589x_CLKMODE_MODCTL_OPERATION);
return ret;
}
static const SIMPLE_DEV_PM_OPS(tc3589x_dev_pm_ops, tc3589x_suspend,
tc3589x_resume);
static const struct i2c_device_id tc3589x_id[] = {
{ "tc3589x", 24 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tc3589x_id);
static struct i2c_driver tc3589x_driver = {
.driver.name = "tc3589x",
.driver.owner = THIS_MODULE,
#ifdef CONFIG_PM
.driver.pm = &tc3589x_dev_pm_ops,
#endif
.probe = tc3589x_probe,
.remove = __devexit_p(tc3589x_remove),
.id_table = tc3589x_id,
};
static int __init tc3589x_init(void)
{
return i2c_add_driver(&tc3589x_driver);
}
subsys_initcall(tc3589x_init);
static void __exit tc3589x_exit(void)
{
i2c_del_driver(&tc3589x_driver);
}
module_exit(tc3589x_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC3589x MFD core driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <mach/mbox.h> #include <mach/mbox-db5500.h>
#include <net/caif/caif_shm.h> #include <net/caif/caif_shm.h>
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
......
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment