Merge branch 'ux500-core' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-stericsson into devel-stable

This commit is contained in:
Russell King 2011-01-03 10:31:54 +00:00
commit cde9efef40
55 changed files with 3389 additions and 1631 deletions

View File

@ -798,6 +798,7 @@ config ARCH_U8500
select GENERIC_CLOCKEVENTS
select COMMON_CLKDEV
select ARCH_REQUIRE_GPIOLIB
select ARCH_HAS_CPUFREQ
help
Support for ST-Ericsson's Ux500 architecture

View File

@ -2,14 +2,16 @@
# Makefile for the linux kernel, U8500 machine.
#
obj-y := clock.o cpu.o devices.o
obj-$(CONFIG_UX500_SOC_DB5500) += cpu-db5500.o devices-db5500.o
obj-y := clock.o cpu.o devices.o devices-common.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_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.o
obj-$(CONFIG_MACH_U5500) += board-u5500.o
obj-$(CONFIG_MACH_U8500_MOP) += board-mop500.o board-mop500-sdi.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_HOTPLUG_CPU) += hotplug.o
obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
obj-$(CONFIG_REGULATOR_AB8500) += board-mop500-regulators.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem_irq.o
obj-$(CONFIG_U5500_MBOX) += mbox.o
obj-$(CONFIG_U5500_MODEM_IRQ) += modem-irq-db5500.o
obj-$(CONFIG_U5500_MBOX) += mbox-db5500.o
obj-$(CONFIG_CPU_FREQ) += cpufreq.o

View File

@ -0,0 +1,229 @@
/*
* 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));
}

View File

@ -16,10 +16,24 @@
#include <mach/devices.h>
#include <mach/hardware.h>
#include "devices-db8500.h"
#include "pins-db8500.h"
#include "board-mop500.h"
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) */
GPIO197_MC4_DAT3,
GPIO198_MC4_DAT2,
@ -49,6 +63,55 @@ static pin_cfg_t mop500_sdi2_pins[] = {
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)
*/
@ -74,18 +137,24 @@ static struct mmci_platform_data mop500_sdi4_data = {
.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));
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()) {
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 */
amba_device_register(&u8500_sdi4_device, &iomem_resource);
db8500_add_sdi4(&mop500_sdi4_data);
}

View File

@ -13,25 +13,26 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/amba/bus.h>
#include <linux/amba/pl022.h>
#include <linux/spi/spi.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/arch.h>
#include <plat/pincfg.h>
#include <plat/i2c.h>
#include <plat/ske.h>
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/irqs.h>
#include "devices-db8500.h"
#include "pins-db8500.h"
#include "board-mop500.h"
@ -69,22 +70,12 @@ static pin_cfg_t mop500_pins[] = {
GPIO166_KP_O2,
GPIO167_KP_O1,
GPIO168_KP_O0,
};
static void ab4500_spi_cs_control(u32 command)
{
/* set the FRM signal, which is CS - TODO */
}
/* GPIO_EXP_INT */
GPIO217_GPIO,
struct pl022_config_chip ab4500_chip_info = {
.com_mode = INTERRUPT_TRANSFER,
.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,
/* STMPE1601 IRQ */
GPIO218_GPIO | PIN_INPUT_PULLUP,
};
static struct ab8500_platform_data ab8500_platdata = {
@ -93,9 +84,9 @@ static struct ab8500_platform_data ab8500_platdata = {
static struct resource ab8500_resources[] = {
[0] = {
.start = IRQ_AB8500,
.end = IRQ_AB8500,
.flags = IORESOURCE_IRQ
.start = IRQ_DB8500_AB8500,
.end = IRQ_DB8500_AB8500,
.flags = IORESOURCE_IRQ
}
};
@ -109,19 +100,6 @@ struct platform_device ab8500_device = {
.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 = {
.bus_id = 0,
/* pl022 not yet supports dma */
@ -132,6 +110,34 @@ static struct pl022_ssp_controller ssp0_platform_data = {
.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) \
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);
U8500_I2C_CONTROLLER(2, 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 = {
&ux500_uart0_device,
&ux500_uart1_device,
&ux500_uart2_device,
&u8500_ssp0_device,
};
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),
};
/*
* 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)
static void __init mop500_i2c_init(void)
{
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;
db8500_add_i2c0(&u8500_i2c0_data);
db8500_add_i2c1(&u8500_i2c1_data);
db8500_add_i2c2(&u8500_i2c2_data);
db8500_add_i2c3(&u8500_i2c3_data);
}
/*
* 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 = &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 mop500_spi_init(void)
{
db8500_add_ssp0(&ssp0_platform_data);
}
static void __init mop500_uart_init(void)
{
db8500_add_uart0();
db8500_add_uart1();
db8500_add_uart2();
}
static void __init u8500_init_machine(void)
{
int i;
u8500_init_devices();
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));
mop500_i2c_init();
mop500_sdi_init();
mop500_spi_init();
mop500_uart_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);
mop500_keypad_init();
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")

View File

@ -7,6 +7,15 @@
#ifndef __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_tc35892_init(void);
extern void mop500_keypad_init(void);
#endif

View File

@ -0,0 +1,49 @@
/*
* 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);
}

View File

@ -9,6 +9,7 @@
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <asm/mach/arch.h>
#include <asm/mach-types.h>
@ -17,20 +18,24 @@
#include <mach/devices.h>
#include <mach/setup.h>
static struct amba_device *amba_board_devs[] __initdata = {
&ux500_uart0_device,
&ux500_uart1_device,
&ux500_uart2_device,
};
#include "devices-db5500.h"
static void __init u5500_uart_init(void)
{
db5500_add_uart0();
db5500_add_uart1();
db5500_add_uart2();
}
static void __init u5500_init_machine(void)
{
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,
.map_io = u5500_map_io,
.init_irq = ux500_init_irq,

View File

@ -20,6 +20,12 @@
#include <mach/hardware.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_PCKDIS 0x04
#define PRCC_KCKEN 0x08
@ -133,7 +139,7 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
{
void __iomem *addr = __io_address(UX500_PRCMU_BASE)
+ PRCM_TCR;
u32 tcr = readl(addr);
u32 tcr;
int mtu = (int) clk->data;
/*
* One of these is selected eventually
@ -144,6 +150,14 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
unsigned long mturate;
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 */
if (clk->parent_periph)
mturate = clk_get_rate(clk->parent_periph);
@ -153,45 +167,6 @@ static unsigned long clk_mtu_get_rate(struct clk *clk)
/* We need to be connected SOMEWHERE */
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 */
if (tcr & (1 << mtu))
retclk = clk32k;
@ -317,6 +292,7 @@ static struct clkops clk_prcc_ops = {
};
static struct clk clk_32khz = {
.name = "clk_32khz",
.rate = 32000,
};
@ -366,94 +342,96 @@ static DEFINE_PRCMU_CLK(uiccclk, 0x4, 1, UICCCLK); /* v1 */
*/
/* Peripheral Cluster #1 */
static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, i2c4, 10, 9, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, gpio0, 9, -1, NULL);
static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, slimbus0, 8, 8, &clk_slimclk);
static DEFINE_PRCC_CLK(1, spi3_ed, 7, 7, NULL);
static DEFINE_PRCC_CLK(1, spi3_v1, 7, -1, NULL);
static DEFINE_PRCC_CLK(1, i2c2, 6, 6, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, sdi0, 5, 5, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
static DEFINE_PRCC_CLK(1, msp1_ed, 4, 4, &clk_msp02clk);
static DEFINE_PRCC_CLK(1, msp1_v1, 4, 4, &clk_msp1clk);
static DEFINE_PRCC_CLK(1, msp0, 3, 3, &clk_msp02clk);
static DEFINE_PRCC_CLK(1, i2c1, 2, 2, &clk_i2cclk);
static DEFINE_PRCC_CLK(1, uart1, 1, 1, &clk_uartclk);
static DEFINE_PRCC_CLK(1, uart0, 0, 0, &clk_uartclk);
/* Peripheral Cluster #2 */
static DEFINE_PRCC_CLK(2, gpio1_ed, 12, -1, NULL);
static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, ssitx_ed, 11, -1, NULL);
static DEFINE_PRCC_CLK(2, ssirx_ed, 10, -1, NULL);
static DEFINE_PRCC_CLK(2, spi0_ed, 9, -1, NULL);
static DEFINE_PRCC_CLK(2, sdi3_ed, 8, 6, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, sdi1_ed, 7, 5, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, msp2_ed, 6, 4, &clk_msp02clk);
static DEFINE_PRCC_CLK(2, sdi4_ed, 4, 2, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, pwl_ed, 3, 1, NULL);
static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(2, spi1_ed, 2, -1, NULL);
static DEFINE_PRCC_CLK(2, spi2_ed, 1, -1, NULL);
static DEFINE_PRCC_CLK(2, i2c3_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(2, gpio1_v1, 11, -1, NULL);
static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, ssitx_v1, 10, 7, NULL);
static DEFINE_PRCC_CLK(2, ssirx_v1, 9, 6, NULL);
static DEFINE_PRCC_CLK(2, spi0_v1, 8, -1, NULL);
static DEFINE_PRCC_CLK(2, sdi3_v1, 7, 5, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, sdi1_v1, 6, 4, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, msp2_v1, 5, 3, &clk_msp02clk);
static DEFINE_PRCC_CLK(2, sdi4_v1, 4, 2, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(2, pwl_v1, 3, 1, NULL);
static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(2, spi1_v1, 2, -1, NULL);
static DEFINE_PRCC_CLK(2, spi2_v1, 1, -1, NULL);
static DEFINE_PRCC_CLK(2, i2c3_v1, 0, 0, &clk_i2cclk);
/* Peripheral Cluster #3 */
static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
static DEFINE_PRCC_CLK(3, gpio2, 8, -1, NULL);
static DEFINE_PRCC_CLK(3, sdi5, 7, 7, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(3, uart2, 6, 6, &clk_uartclk);
static DEFINE_PRCC_CLK(3, ske, 5, 5, &clk_32khz);
static DEFINE_PRCC_CLK(3, sdi2, 4, 4, &clk_sdmmcclk);
static DEFINE_PRCC_CLK(3, i2c0, 3, 3, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp1_ed, 2, 2, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp0_ed, 1, 1, &clk_i2cclk);
static DEFINE_PRCC_CLK(3, ssp1_v1, 2, 2, &clk_sspclk);
static DEFINE_PRCC_CLK(3, ssp0_v1, 1, 1, &clk_sspclk);
static DEFINE_PRCC_CLK(3, fsmc, 0, -1, NULL);
/* Peripheral Cluster #4 is in the always on domain */
/* Peripheral Cluster #5 */
static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
static DEFINE_PRCC_CLK(5, gpio3, 1, -1, NULL);
static DEFINE_PRCC_CLK(5, usb_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(5, usb_v1, 0, 0, NULL);
/* Peripheral Cluster #6 */
/* MTU ID in data */
static DEFINE_PRCC_CLK_CUSTOM(6, mtu1_v1, 8, -1, NULL, clk_mtu_get_rate, 1);
static DEFINE_PRCC_CLK_CUSTOM(6, mtu0_v1, 7, -1, NULL, clk_mtu_get_rate, 0);
static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
static DEFINE_PRCC_CLK(6, cfgreg_v1, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, dmc_ed, 6, 6, NULL);
static DEFINE_PRCC_CLK(6, hash1, 5, -1, NULL);
static DEFINE_PRCC_CLK(6, unipro_v1, 4, 1, &clk_uniproclk);
static DEFINE_PRCC_CLK(6, cryp1_ed, 4, -1, NULL);
static DEFINE_PRCC_CLK(6, pka, 3, -1, NULL);
static DEFINE_PRCC_CLK(6, hash0, 2, -1, NULL);
static DEFINE_PRCC_CLK(6, cryp0, 1, -1, NULL);
static DEFINE_PRCC_CLK(6, rng_ed, 0, 0, &clk_i2cclk);
static DEFINE_PRCC_CLK(6, rng_v1, 0, 0, &clk_rngclk);
/* Peripheral Cluster #7 */
static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
static DEFINE_PRCC_CLK(7, tzpc0_ed, 4, -1, NULL);
/* MTU ID in data */
static DEFINE_PRCC_CLK_CUSTOM(7, mtu1_ed, 3, -1, NULL, clk_mtu_get_rate, 1);
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, cfgreg_ed, 0, -1, NULL);
static DEFINE_PRCC_CLK(7, wdg_ed, 1, -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[] = {
CLK(dummy_apb_pclk, NULL, "apb_pclk"),
@ -554,7 +532,7 @@ static struct clk_lookup u8500_ed_clks[] = {
static struct clk_lookup u8500_v1_clks[] = {
/* Peripheral Cluster #1 */
CLK(i2c4, "nmk-i2c.4", NULL),
CLK(i2c4, "nmk-i2c.4", NULL),
CLK(spi3_v1, "spi3", NULL),
CLK(msp1_v1, "msp1", NULL),
@ -599,6 +577,183 @@ static struct clk_lookup u8500_v1_clks[] = {
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)
{
if (cpu_is_u8500ed()) {
@ -609,7 +764,8 @@ int __init clk_init(void)
/* Clock tree for U5500 not implemented yet */
clk_prcc_ops.enable = clk_prcc_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));
@ -618,5 +774,12 @@ int __init clk_init(void)
else
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;
}

View File

@ -90,6 +90,10 @@ struct clk {
struct clk *parent_cluster;
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) \

View File

@ -8,14 +8,19 @@
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <asm/mach/map.h>
#include <plat/gpio.h>
#include <mach/hardware.h>
#include <mach/devices.h>
#include <mach/setup.h>
#include <mach/irqs.h>
#include "devices-db5500.h"
static struct map_desc u5500_io_desc[] __initdata = {
__IO_DEV_DESC(U5500_GPIO0_BASE, SZ_4K),
__IO_DEV_DESC(U5500_GPIO1_BASE, SZ_4K),
@ -110,19 +115,32 @@ static struct platform_device mbox2_device = {
};
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,
&mbox1_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)
{
ux500_map_io();
@ -132,7 +150,9 @@ void __init u5500_map_io(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,
ARRAY_SIZE(u5500_platform_devs));

View File

@ -22,23 +22,15 @@
#include <mach/setup.h>
#include <mach/devices.h>
#include "devices-db8500.h"
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,
};
/* minimum static i/o mapping required to boot U8500 platforms */
static struct map_desc u8500_io_desc[] __initdata = {
__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_GPIO1_BASE, SZ_4K),
__IO_DEV_DESC(U8500_GPIO2_BASE, SZ_4K),
@ -46,13 +38,18 @@ static struct map_desc u8500_io_desc[] __initdata = {
__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_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_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)
iotable_init(u8500_io_desc, ARRAY_SIZE(u8500_io_desc));
if (cpu_is_u8500ed())
iotable_init(u8500ed_io_desc, ARRAY_SIZE(u8500ed_io_desc));
else
iotable_init(u8500v1_io_desc, ARRAY_SIZE(u8500v1_io_desc));
iotable_init(u8500_ed_io_desc, ARRAY_SIZE(u8500_ed_io_desc));
else if (cpu_is_u8500v1())
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 */
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
*/
@ -152,12 +173,13 @@ void __init u8500_init_devices(void)
else
pr_warning("ASIC: UNKNOWN SILICON VERSION!\n");
ux500_init_devices();
if (cpu_is_u8500ed())
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));
return ;

View File

@ -6,7 +6,6 @@
*/
#include <linux/platform_device.h>
#include <linux/amba/bus.h>
#include <linux/io.h>
#include <linux/clk.h>
@ -20,6 +19,7 @@
#include <mach/hardware.h>
#include <mach/setup.h>
#include <mach/devices.h>
#include <mach/prcmu.h>
#include "clock.h"
@ -45,20 +45,11 @@ static struct map_desc ux500_io_desc[] __initdata = {
__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)
{
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)
{
gic_dist_init(0, __io_address(UX500_GIC_DIST_BASE), 29);
@ -68,6 +59,8 @@ void __init ux500_init_irq(void)
* Init clocks here so that they are available for system timer
* initialization.
*/
if (cpu_is_u8500())
prcmu_early_init();
clk_init();
}

View File

@ -0,0 +1,211 @@
/*
* 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);

View File

@ -0,0 +1,145 @@
/*
* 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);
}
}

View File

@ -0,0 +1,82 @@
/*
* 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

View File

@ -1,46 +0,0 @@
/*
* 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),
};

View File

@ -0,0 +1,66 @@
/*
* 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

View File

@ -19,173 +19,6 @@
#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[] = {
[0] = {
.start = U8500_DMA_BASE,
@ -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",
.id = -1,
.num_resources = ARRAY_SIZE(keypad_resources),

View File

@ -0,0 +1,98 @@
/*
* 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

View File

@ -14,69 +14,6 @@
#include <mach/hardware.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)
{
int i;

View File

@ -0,0 +1,120 @@
/*
* 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);
}

View File

@ -114,4 +114,8 @@
#define U5500_MBOX2_LOCAL_START (U5500_MBOX_BASE + 0x20)
#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

View File

@ -92,7 +92,8 @@
#define U8500_SCR_BASE (U8500_PER4_BASE + 0x05000)
#define U8500_DMC_BASE (U8500_PER4_BASE + 0x06000)
#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 */
#define U8500_FSMC_BASE (U8500_PER3_BASE + 0x0000)

View File

@ -14,27 +14,10 @@ extern struct platform_device u5500_gpio_devs[];
extern struct platform_device u8500_gpio_devs[];
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 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);
#endif

View File

@ -9,42 +9,4 @@
#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 */

View File

@ -142,6 +142,8 @@ static inline bool cpu_is_u5500(void)
#endif
}
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
#endif
#endif /* __MACH_HARDWARE_H */

View File

@ -8,12 +8,36 @@
#ifndef __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_END (MOP500_AB8500_IRQ_BASE \
+ 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
#undef IRQ_BOARD_END

View File

@ -21,50 +21,6 @@
/* Interrupt numbers generic for shared peripheral */
#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
* INTID[160:32]. The first 32 interrupts are reserved.

View File

@ -0,0 +1,30 @@
/*
* 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 */

View File

@ -1,10 +1,15 @@
/*
* 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
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation.
* Author: Kumar Sanghvi <kumar.sanghvi@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
*
* License Terms: GNU General Public License v2
*
* PRCM Unit registers
*/
#ifndef __MACH_PRCMU_REGS_H
#define __MACH_PRCMU_REGS_H
@ -88,4 +93,4 @@
/* Miscellaneous unit registers */
#define PRCM_DSI_SW_RESET (_PRCMU_BASE + 0x324)
#endif /* __MACH_PRCMU__REGS_H */
#endif /* __MACH_PRCMU_REGS_H */

View File

@ -2,14 +2,27 @@
* Copyright (C) STMicroelectronics 2009
* 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
*
* PRCMU f/w APIs
* PRCM Unit f/w API
*/
#ifndef __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_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 */

View File

@ -18,14 +18,19 @@ extern void __init ux500_map_io(void);
extern void __init u5500_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 u8500_init_devices(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 */
extern void nmdk_timer_init(void);
struct amba_device;
extern void __init amba_add_devices(struct amba_device *devs[], int num);
struct sys_timer;

View File

@ -19,38 +19,43 @@
#define __ASM_ARCH_UNCOMPRESS_H
#include <asm/setup.h>
#include <asm/mach-types.h>
#include <linux/io.h>
#include <linux/amba/serial.h>
#include <mach/hardware.h>
#define U8500_UART_DR 0x80007000
#define U8500_UART_LCRH 0x8000702c
#define U8500_UART_CR 0x80007030
#define U8500_UART_FR 0x80007018
static u32 ux500_uart_base;
static void putc(const char c)
{
/* 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;
if (c == '\n')
putc('\r');
while (__raw_readb(U8500_UART_FR) & (1 << 5))
while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 5))
barrier();
__raw_writeb(c, U8500_UART_DR);
__raw_writeb(c, ux500_uart_base + UART01x_DR);
}
static void flush(void)
{
if (!(__raw_readb(U8500_UART_CR) & 0x1))
if (!(__raw_readb(ux500_uart_base + UART011_CR) & 0x1))
return;
while (__raw_readb(U8500_UART_FR) & (1 << 3))
while (__raw_readb(ux500_uart_base + UART01x_FR) & (1 << 3))
barrier();
}
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 */

View File

@ -38,7 +38,7 @@
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/completion.h>
#include <mach/mbox.h>
#include <mach/mbox-db5500.h>
#define MBOX_NAME "mbox"

View File

@ -26,7 +26,7 @@
* control for which core is the next to come out of the secondary
* boot "holding pen"
*/
volatile int __cpuinitdata pen_release = -1;
volatile int pen_release = -1;
static unsigned int __init get_core_count(void)
{

View File

@ -1,10 +1,14 @@
/*
* Copyright (C) ST Ericsson SA 2010
* Copyright (C) STMicroelectronics 2009
* Copyright (C) ST-Ericsson SA 2010
*
* 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>
*
* U8500 PRCMU driver.
* U8500 PRCM Unit interface driver
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
@ -19,11 +23,26 @@
#include <mach/hardware.h>
#include <mach/prcmu-regs.h>
#include <mach/prcmu-defs.h>
#define PRCMU_TCDM_BASE __io_address(U8500_PRCMU_TCDM_BASE)
/* Global var to runtime determine TCDM base for v2 or v1 */
static __iomem void *tcdm_base;
#define REQ_MB5 (PRCMU_TCDM_BASE + 0xE44)
#define ACK_MB5 (PRCMU_TCDM_BASE + 0xDF4)
#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 REQ_MB1_ARMOPP (REQ_MB1 + 0x0)
#define REQ_MB1_APEOPP (REQ_MB1 + 0x1)
#define REQ_MB1_BOOSTOPP (REQ_MB1 + 0x2)
#define ACK_MB1 (tcdm_base + 0xE04)
#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_HW_BITS (REQ_MB5 + 1)
@ -33,10 +52,33 @@
#define ACK_MB5_I2C_STATUS (ACK_MB5 + 1)
#define ACK_MB5_I2C_VAL (ACK_MB5 + 3)
#define I2C_WRITE(slave) ((slave) << 1)
#define I2C_READ(slave) (((slave) << 1) | BIT(0))
#define PRCM_AVS_VARM_MAX_OPP (tcdm_base + 0x2E4)
#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)
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 {
I2C_WR_OK = 0x01,
I2C_RD_OK = 0x02,
@ -145,6 +187,104 @@ unlock_and_return:
}
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)
{
writel(MBOX_BIT(0), PRCM_ARM_IT1_CLEAR);
@ -152,6 +292,9 @@ static void read_mailbox_0(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);
}
@ -217,15 +360,35 @@ static irqreturn_t prcmu_irq_handler(int irq, void *data)
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)
{
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);
init_completion(&mb5_transfer.work);
/* Clean up the mailbox interrupts after pre-kernel code. */
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);

View File

@ -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,
pin_cfg_t cfg)
pin_cfg_t cfg, bool sleep)
{
static const char *afnames[] = {
[NMK_GPIO_ALT_GPIO] = "GPIO",
@ -145,11 +145,34 @@ static void __nmk_config_pin(struct nmk_gpio_chip *nmk_chip, unsigned offset,
int output = PIN_DIR(cfg);
int val = PIN_VAL(cfg);
dev_dbg(nmk_chip->chip.dev, "pin %d: af %s, pull %s, slpm %s (%s%s)\n",
pin, afnames[af], pullnames[pull], slpmnames[slpm],
dev_dbg(nmk_chip->chip.dev, "pin %d [%#lx]: af %s, pull %s, slpm %s (%s%s)\n",
pin, cfg, afnames[af], pullnames[pull], slpmnames[slpm],
output ? "output " : "input",
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)
__nmk_gpio_make_output(nmk_chip, offset, val);
else {
@ -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
* 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;
int gpio = PIN_NUM(cfg);
@ -186,7 +209,7 @@ int nmk_config_pin(pin_cfg_t cfg)
return -EINVAL;
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);
return 0;
@ -207,7 +230,7 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num)
int i;
for (i = 0; i < num; i++) {
int ret = nmk_config_pin(cfgs[i]);
ret = nmk_config_pin(cfgs[i], false);
if (ret)
break;
}
@ -216,6 +239,21 @@ int nmk_config_pins(pin_cfg_t *cfgs, int num)
}
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
* @gpio: pin number
@ -634,7 +672,7 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
chip = &nmk_chip->chip;
chip->base = pdata->first_gpio;
chip->label = pdata->name;
chip->label = pdata->name ?: dev_name(&dev->dev);
chip->dev = &dev->dev;
chip->owner = THIS_MODULE;

View File

@ -19,16 +19,22 @@
* bit 9..10 - Alternate Function Selection
* bit 11..12 - Pull up/down state
* bit 13 - Sleep mode behaviour
* bit 14 - (sleep mode) Direction
* bit 15 - (sleep mode) Value (if output)
* bit 14 - Direction
* 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
*
* PIN_CFG_DEFAULT - default config (0):
* pull up/down = disabled
* sleep mode = input/wakeup
* (sleep mode) direction = input
* (sleep mode) value = low
* direction = input
* 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_PULL - default config with alternate function and pull up/down
@ -75,30 +81,64 @@ typedef unsigned long pin_cfg_t;
#define PIN_VAL_LOW (0 << PIN_VAL_SHIFT)
#define PIN_VAL_HIGH (1 << PIN_VAL_SHIFT)
/* Shortcuts. Use these instead of separate DIR and VAL. */
#define PIN_INPUT PIN_DIR_INPUT
#define PIN_SLPM_PULL_SHIFT 16
#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_HIGH (PIN_DIR_OUTPUT | PIN_VAL_HIGH)
/*
* These are the same as the ones above, but should make more sense to the
* reader when seen along with a setting a pin to AF mode.
*/
#define PIN_SLPM_INPUT PIN_INPUT
#define PIN_SLPM_OUTPUT_LOW PIN_OUTPUT_LOW
#define PIN_SLPM_OUTPUT_HIGH PIN_OUTPUT_HIGH
#define PIN_SLPM_INPUT_PULLDOWN (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_DOWN)
#define PIN_SLPM_INPUT_PULLUP (PIN_SLPM_DIR_INPUT | PIN_SLPM_PULL_UP)
#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_OUTPUT_HIGH (PIN_SLPM_DIR_OUTPUT | PIN_SLPM_VAL_HIGH)
#define PIN_CFG_DEFAULT (PIN_PULL_NONE | PIN_SLPM_INPUT)
#define PIN_CFG_DEFAULT (0)
#define PIN_CFG(num, alt) \
(PIN_CFG_DEFAULT |\
(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) \
((PIN_CFG_DEFAULT & ~PIN_PULL_MASK) |\
(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_sleep(pin_cfg_t *cfgs, int num);
#endif

View File

@ -230,11 +230,11 @@ config GPIO_STMPE
This enables support for the GPIOs found on the STMPE I/O
Expanders.
config GPIO_TC35892
bool "TC35892 GPIOs"
depends on MFD_TC35892
config GPIO_TC3589X
bool "TC3589X GPIOs"
depends on MFD_TC3589X
help
This enables support for the GPIOs found on the TC35892
This enables support for the GPIOs found on the TC3589X
I/O Expander.
config GPIO_TWL4030

View File

@ -24,7 +24,7 @@ obj-$(CONFIG_GPIO_PCF857X) += pcf857x.o
obj-$(CONFIG_GPIO_PCH) += pch_gpio.o
obj-$(CONFIG_GPIO_PL061) += pl061.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_TWL4030) += twl4030-gpio.o
obj-$(CONFIG_GPIO_UCB1400) += ucb1400_gpio.o

View File

@ -1,389 +0,0 @@
/*
* 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/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc35892.h>
/*
* These registers are modified under the irq bus lock and cached to avoid
* unnecessary writes in bus_sync_unlock.
*/
enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
#define CACHE_NR_REGS 4
#define CACHE_NR_BANKS 3
struct tc35892_gpio {
struct gpio_chip chip;
struct tc35892 *tc35892;
struct device *dev;
struct mutex irq_lock;
int irq_base;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
static inline struct tc35892_gpio *to_tc35892_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct tc35892_gpio, chip);
}
static int tc35892_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
u8 mask = 1 << (offset % 8);
int ret;
ret = tc35892_reg_read(tc35892, reg);
if (ret < 0)
return ret;
return ret & mask;
}
static void tc35892_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODATA0 + (offset / 8) * 2;
unsigned pos = offset % 8;
u8 data[] = {!!val << pos, 1 << pos};
tc35892_block_write(tc35892, reg, ARRAY_SIZE(data), data);
}
static int tc35892_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
tc35892_gpio_set(chip, offset, val);
return tc35892_set_bits(tc35892, reg, 1 << pos, 1 << pos);
}
static int tc35892_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 reg = TC35892_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
return tc35892_set_bits(tc35892, reg, 1 << pos, 0);
}
static int tc35892_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct tc35892_gpio *tc35892_gpio = to_tc35892_gpio(chip);
return tc35892_gpio->irq_base + offset;
}
static struct gpio_chip template_chip = {
.label = "tc35892",
.owner = THIS_MODULE,
.direction_input = tc35892_gpio_direction_input,
.get = tc35892_gpio_get,
.direction_output = tc35892_gpio_direction_output,
.set = tc35892_gpio_set,
.to_irq = tc35892_gpio_to_irq,
.can_sleep = 1,
};
static int tc35892_gpio_irq_set_type(unsigned int irq, unsigned int type)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
if (type == IRQ_TYPE_EDGE_BOTH) {
tc35892_gpio->regs[REG_IBE][regoffset] |= mask;
return 0;
}
tc35892_gpio->regs[REG_IBE][regoffset] &= ~mask;
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
tc35892_gpio->regs[REG_IS][regoffset] |= mask;
else
tc35892_gpio->regs[REG_IS][regoffset] &= ~mask;
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
tc35892_gpio->regs[REG_IEV][regoffset] |= mask;
else
tc35892_gpio->regs[REG_IEV][regoffset] &= ~mask;
return 0;
}
static void tc35892_gpio_irq_lock(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
mutex_lock(&tc35892_gpio->irq_lock);
}
static void tc35892_gpio_irq_sync_unlock(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
static const u8 regmap[] = {
[REG_IBE] = TC35892_GPIOIBE0,
[REG_IEV] = TC35892_GPIOIEV0,
[REG_IS] = TC35892_GPIOIS0,
[REG_IE] = TC35892_GPIOIE0,
};
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
for (j = 0; j < CACHE_NR_BANKS; j++) {
u8 old = tc35892_gpio->oldregs[i][j];
u8 new = tc35892_gpio->regs[i][j];
if (new == old)
continue;
tc35892_gpio->oldregs[i][j] = new;
tc35892_reg_write(tc35892, regmap[i] + j * 8, new);
}
}
mutex_unlock(&tc35892_gpio->irq_lock);
}
static void tc35892_gpio_irq_mask(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc35892_gpio->regs[REG_IE][regoffset] &= ~mask;
}
static void tc35892_gpio_irq_unmask(unsigned int irq)
{
struct tc35892_gpio *tc35892_gpio = get_irq_chip_data(irq);
int offset = irq - tc35892_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc35892_gpio->regs[REG_IE][regoffset] |= mask;
}
static struct irq_chip tc35892_gpio_irq_chip = {
.name = "tc35892-gpio",
.bus_lock = tc35892_gpio_irq_lock,
.bus_sync_unlock = tc35892_gpio_irq_sync_unlock,
.mask = tc35892_gpio_irq_mask,
.unmask = tc35892_gpio_irq_unmask,
.set_type = tc35892_gpio_irq_set_type,
};
static irqreturn_t tc35892_gpio_irq(int irq, void *dev)
{
struct tc35892_gpio *tc35892_gpio = dev;
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
u8 status[CACHE_NR_BANKS];
int ret;
int i;
ret = tc35892_block_read(tc35892, TC35892_GPIOMIS0,
ARRAY_SIZE(status), status);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(status); i++) {
unsigned int stat = status[i];
if (!stat)
continue;
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
handle_nested_irq(tc35892_gpio->irq_base + line);
stat &= ~(1 << bit);
}
tc35892_reg_write(tc35892, TC35892_GPIOIC0 + i, status[i]);
}
return IRQ_HANDLED;
}
static int tc35892_gpio_irq_init(struct tc35892_gpio *tc35892_gpio)
{
int base = tc35892_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc35892_gpio->chip.ngpio; irq++) {
set_irq_chip_data(irq, tc35892_gpio);
set_irq_chip_and_handler(irq, &tc35892_gpio_irq_chip,
handle_simple_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_gpio_irq_remove(struct tc35892_gpio *tc35892_gpio)
{
int base = tc35892_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc35892_gpio->chip.ngpio; 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 __devinit tc35892_gpio_probe(struct platform_device *pdev)
{
struct tc35892 *tc35892 = dev_get_drvdata(pdev->dev.parent);
struct tc35892_gpio_platform_data *pdata;
struct tc35892_gpio *tc35892_gpio;
int ret;
int irq;
pdata = tc35892->pdata->gpio;
if (!pdata)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
tc35892_gpio = kzalloc(sizeof(struct tc35892_gpio), GFP_KERNEL);
if (!tc35892_gpio)
return -ENOMEM;
mutex_init(&tc35892_gpio->irq_lock);
tc35892_gpio->dev = &pdev->dev;
tc35892_gpio->tc35892 = tc35892;
tc35892_gpio->chip = template_chip;
tc35892_gpio->chip.ngpio = tc35892->num_gpio;
tc35892_gpio->chip.dev = &pdev->dev;
tc35892_gpio->chip.base = pdata->gpio_base;
tc35892_gpio->irq_base = tc35892->irq_base + TC35892_INT_GPIO(0);
/* Bring the GPIO module out of reset */
ret = tc35892_set_bits(tc35892, TC35892_RSTCTRL,
TC35892_RSTCTRL_GPIRST, 0);
if (ret < 0)
goto out_free;
ret = tc35892_gpio_irq_init(tc35892_gpio);
if (ret)
goto out_free;
ret = request_threaded_irq(irq, NULL, tc35892_gpio_irq, IRQF_ONESHOT,
"tc35892-gpio", tc35892_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
}
ret = gpiochip_add(&tc35892_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
goto out_freeirq;
}
if (pdata->setup)
pdata->setup(tc35892, tc35892_gpio->chip.base);
platform_set_drvdata(pdev, tc35892_gpio);
return 0;
out_freeirq:
free_irq(irq, tc35892_gpio);
out_removeirq:
tc35892_gpio_irq_remove(tc35892_gpio);
out_free:
kfree(tc35892_gpio);
return ret;
}
static int __devexit tc35892_gpio_remove(struct platform_device *pdev)
{
struct tc35892_gpio *tc35892_gpio = platform_get_drvdata(pdev);
struct tc35892 *tc35892 = tc35892_gpio->tc35892;
struct tc35892_gpio_platform_data *pdata = tc35892->pdata->gpio;
int irq = platform_get_irq(pdev, 0);
int ret;
if (pdata->remove)
pdata->remove(tc35892, tc35892_gpio->chip.base);
ret = gpiochip_remove(&tc35892_gpio->chip);
if (ret < 0) {
dev_err(tc35892_gpio->dev,
"unable to remove gpiochip: %d\n", ret);
return ret;
}
free_irq(irq, tc35892_gpio);
tc35892_gpio_irq_remove(tc35892_gpio);
platform_set_drvdata(pdev, NULL);
kfree(tc35892_gpio);
return 0;
}
static struct platform_driver tc35892_gpio_driver = {
.driver.name = "tc35892-gpio",
.driver.owner = THIS_MODULE,
.probe = tc35892_gpio_probe,
.remove = __devexit_p(tc35892_gpio_remove),
};
static int __init tc35892_gpio_init(void)
{
return platform_driver_register(&tc35892_gpio_driver);
}
subsys_initcall(tc35892_gpio_init);
static void __exit tc35892_gpio_exit(void)
{
platform_driver_unregister(&tc35892_gpio_driver);
}
module_exit(tc35892_gpio_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC35892 GPIO driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");

389
drivers/gpio/tc3589x-gpio.c Normal file
View File

@ -0,0 +1,389 @@
/*
* 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/init.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/mfd/tc3589x.h>
/*
* These registers are modified under the irq bus lock and cached to avoid
* unnecessary writes in bus_sync_unlock.
*/
enum { REG_IBE, REG_IEV, REG_IS, REG_IE };
#define CACHE_NR_REGS 4
#define CACHE_NR_BANKS 3
struct tc3589x_gpio {
struct gpio_chip chip;
struct tc3589x *tc3589x;
struct device *dev;
struct mutex irq_lock;
int irq_base;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
};
static inline struct tc3589x_gpio *to_tc3589x_gpio(struct gpio_chip *chip)
{
return container_of(chip, struct tc3589x_gpio, chip);
}
static int tc3589x_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
u8 mask = 1 << (offset % 8);
int ret;
ret = tc3589x_reg_read(tc3589x, reg);
if (ret < 0)
return ret;
return ret & mask;
}
static void tc3589x_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODATA0 + (offset / 8) * 2;
unsigned pos = offset % 8;
u8 data[] = {!!val << pos, 1 << pos};
tc3589x_block_write(tc3589x, reg, ARRAY_SIZE(data), data);
}
static int tc3589x_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int val)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
tc3589x_gpio_set(chip, offset, val);
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 1 << pos);
}
static int tc3589x_gpio_direction_input(struct gpio_chip *chip,
unsigned offset)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 reg = TC3589x_GPIODIR0 + offset / 8;
unsigned pos = offset % 8;
return tc3589x_set_bits(tc3589x, reg, 1 << pos, 0);
}
static int tc3589x_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct tc3589x_gpio *tc3589x_gpio = to_tc3589x_gpio(chip);
return tc3589x_gpio->irq_base + offset;
}
static struct gpio_chip template_chip = {
.label = "tc3589x",
.owner = THIS_MODULE,
.direction_input = tc3589x_gpio_direction_input,
.get = tc3589x_gpio_get,
.direction_output = tc3589x_gpio_direction_output,
.set = tc3589x_gpio_set,
.to_irq = tc3589x_gpio_to_irq,
.can_sleep = 1,
};
static int tc3589x_gpio_irq_set_type(unsigned int irq, unsigned int type)
{
struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq);
int offset = irq - tc3589x_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
if (type == IRQ_TYPE_EDGE_BOTH) {
tc3589x_gpio->regs[REG_IBE][regoffset] |= mask;
return 0;
}
tc3589x_gpio->regs[REG_IBE][regoffset] &= ~mask;
if (type == IRQ_TYPE_LEVEL_LOW || type == IRQ_TYPE_LEVEL_HIGH)
tc3589x_gpio->regs[REG_IS][regoffset] |= mask;
else
tc3589x_gpio->regs[REG_IS][regoffset] &= ~mask;
if (type == IRQ_TYPE_EDGE_RISING || type == IRQ_TYPE_LEVEL_HIGH)
tc3589x_gpio->regs[REG_IEV][regoffset] |= mask;
else
tc3589x_gpio->regs[REG_IEV][regoffset] &= ~mask;
return 0;
}
static void tc3589x_gpio_irq_lock(unsigned int irq)
{
struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq);
mutex_lock(&tc3589x_gpio->irq_lock);
}
static void tc3589x_gpio_irq_sync_unlock(unsigned int irq)
{
struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
static const u8 regmap[] = {
[REG_IBE] = TC3589x_GPIOIBE0,
[REG_IEV] = TC3589x_GPIOIEV0,
[REG_IS] = TC3589x_GPIOIS0,
[REG_IE] = TC3589x_GPIOIE0,
};
int i, j;
for (i = 0; i < CACHE_NR_REGS; i++) {
for (j = 0; j < CACHE_NR_BANKS; j++) {
u8 old = tc3589x_gpio->oldregs[i][j];
u8 new = tc3589x_gpio->regs[i][j];
if (new == old)
continue;
tc3589x_gpio->oldregs[i][j] = new;
tc3589x_reg_write(tc3589x, regmap[i] + j * 8, new);
}
}
mutex_unlock(&tc3589x_gpio->irq_lock);
}
static void tc3589x_gpio_irq_mask(unsigned int irq)
{
struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq);
int offset = irq - tc3589x_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc3589x_gpio->regs[REG_IE][regoffset] &= ~mask;
}
static void tc3589x_gpio_irq_unmask(unsigned int irq)
{
struct tc3589x_gpio *tc3589x_gpio = get_irq_chip_data(irq);
int offset = irq - tc3589x_gpio->irq_base;
int regoffset = offset / 8;
int mask = 1 << (offset % 8);
tc3589x_gpio->regs[REG_IE][regoffset] |= mask;
}
static struct irq_chip tc3589x_gpio_irq_chip = {
.name = "tc3589x-gpio",
.bus_lock = tc3589x_gpio_irq_lock,
.bus_sync_unlock = tc3589x_gpio_irq_sync_unlock,
.mask = tc3589x_gpio_irq_mask,
.unmask = tc3589x_gpio_irq_unmask,
.set_type = tc3589x_gpio_irq_set_type,
};
static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
{
struct tc3589x_gpio *tc3589x_gpio = dev;
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
u8 status[CACHE_NR_BANKS];
int ret;
int i;
ret = tc3589x_block_read(tc3589x, TC3589x_GPIOMIS0,
ARRAY_SIZE(status), status);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < ARRAY_SIZE(status); i++) {
unsigned int stat = status[i];
if (!stat)
continue;
while (stat) {
int bit = __ffs(stat);
int line = i * 8 + bit;
handle_nested_irq(tc3589x_gpio->irq_base + line);
stat &= ~(1 << bit);
}
tc3589x_reg_write(tc3589x, TC3589x_GPIOIC0 + i, status[i]);
}
return IRQ_HANDLED;
}
static int tc3589x_gpio_irq_init(struct tc3589x_gpio *tc3589x_gpio)
{
int base = tc3589x_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; irq++) {
set_irq_chip_data(irq, tc3589x_gpio);
set_irq_chip_and_handler(irq, &tc3589x_gpio_irq_chip,
handle_simple_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_gpio_irq_remove(struct tc3589x_gpio *tc3589x_gpio)
{
int base = tc3589x_gpio->irq_base;
int irq;
for (irq = base; irq < base + tc3589x_gpio->chip.ngpio; 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 __devinit tc3589x_gpio_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
struct tc3589x_gpio_platform_data *pdata;
struct tc3589x_gpio *tc3589x_gpio;
int ret;
int irq;
pdata = tc3589x->pdata->gpio;
if (!pdata)
return -ENODEV;
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
tc3589x_gpio = kzalloc(sizeof(struct tc3589x_gpio), GFP_KERNEL);
if (!tc3589x_gpio)
return -ENOMEM;
mutex_init(&tc3589x_gpio->irq_lock);
tc3589x_gpio->dev = &pdev->dev;
tc3589x_gpio->tc3589x = tc3589x;
tc3589x_gpio->chip = template_chip;
tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
tc3589x_gpio->chip.dev = &pdev->dev;
tc3589x_gpio->chip.base = pdata->gpio_base;
tc3589x_gpio->irq_base = tc3589x->irq_base + TC3589x_INT_GPIO(0);
/* Bring the GPIO module out of reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL,
TC3589x_RSTCTRL_GPIRST, 0);
if (ret < 0)
goto out_free;
ret = tc3589x_gpio_irq_init(tc3589x_gpio);
if (ret)
goto out_free;
ret = request_threaded_irq(irq, NULL, tc3589x_gpio_irq, IRQF_ONESHOT,
"tc3589x-gpio", tc3589x_gpio);
if (ret) {
dev_err(&pdev->dev, "unable to get irq: %d\n", ret);
goto out_removeirq;
}
ret = gpiochip_add(&tc3589x_gpio->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
goto out_freeirq;
}
if (pdata->setup)
pdata->setup(tc3589x, tc3589x_gpio->chip.base);
platform_set_drvdata(pdev, tc3589x_gpio);
return 0;
out_freeirq:
free_irq(irq, tc3589x_gpio);
out_removeirq:
tc3589x_gpio_irq_remove(tc3589x_gpio);
out_free:
kfree(tc3589x_gpio);
return ret;
}
static int __devexit tc3589x_gpio_remove(struct platform_device *pdev)
{
struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
int irq = platform_get_irq(pdev, 0);
int ret;
if (pdata->remove)
pdata->remove(tc3589x, tc3589x_gpio->chip.base);
ret = gpiochip_remove(&tc3589x_gpio->chip);
if (ret < 0) {
dev_err(tc3589x_gpio->dev,
"unable to remove gpiochip: %d\n", ret);
return ret;
}
free_irq(irq, tc3589x_gpio);
tc3589x_gpio_irq_remove(tc3589x_gpio);
platform_set_drvdata(pdev, NULL);
kfree(tc3589x_gpio);
return 0;
}
static struct platform_driver tc3589x_gpio_driver = {
.driver.name = "tc3589x-gpio",
.driver.owner = THIS_MODULE,
.probe = tc3589x_gpio_probe,
.remove = __devexit_p(tc3589x_gpio_remove),
};
static int __init tc3589x_gpio_init(void)
{
return platform_driver_register(&tc3589x_gpio_driver);
}
subsys_initcall(tc3589x_gpio_init);
static void __exit tc3589x_gpio_exit(void)
{
platform_driver_unregister(&tc3589x_gpio_driver);
}
module_exit(tc3589x_gpio_exit);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("TC3589x GPIO driver");
MODULE_AUTHOR("Hanumath Prasad, Rabin Vincent");

View File

@ -459,6 +459,16 @@ config KEYBOARD_OMAP4
To compile this driver as a module, choose M here: the
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
tristate "TI TNETV107X keypad support"
depends on ARCH_DAVINCI_TNETV107X

View File

@ -41,6 +41,7 @@ obj-$(CONFIG_KEYBOARD_SH_KEYSC) += sh_keysc.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TNETV107X) += tnetv107x-keypad.o
obj-$(CONFIG_KEYBOARD_TWL4030) += twl4030_keypad.o
obj-$(CONFIG_KEYBOARD_XTKBD) += xtkbd.o

View File

@ -0,0 +1,472 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* Author: Jayeeta Banerjee <jayeeta.banerjee@stericsson.com>
* Author: Sundar Iyer <sundar.iyer@stericsson.com>
*
* License Terms: GNU General Public License, version 2
*
* TC35893 MFD Keypad Controller driver
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/platform_device.h>
#include <linux/input/matrix_keypad.h>
#include <linux/i2c.h>
#include <linux/slab.h>
#include <linux/mfd/tc3589x.h>
/* Maximum supported keypad matrix row/columns size */
#define TC3589x_MAX_KPROW 8
#define TC3589x_MAX_KPCOL 12
/* keypad related Constants */
#define TC3589x_MAX_DEBOUNCE_SETTLE 0xFF
#define DEDICATED_KEY_VAL 0xFF
/* Pull up/down masks */
#define TC3589x_NO_PULL_MASK 0x0
#define TC3589x_PULL_DOWN_MASK 0x1
#define TC3589x_PULL_UP_MASK 0x2
#define TC3589x_PULLUP_ALL_MASK 0xAA
#define TC3589x_IO_PULL_VAL(index, mask) ((mask)<<((index)%4)*2))
/* Bit masks for IOCFG register */
#define IOCFG_BALLCFG 0x01
#define IOCFG_IG 0x08
#define KP_EVCODE_COL_MASK 0x0F
#define KP_EVCODE_ROW_MASK 0x70
#define KP_RELEASE_EVT_MASK 0x80
#define KP_ROW_SHIFT 4
#define KP_NO_VALID_KEY_MASK 0x7F
/* bit masks for RESTCTRL register */
#define TC3589x_KBDRST 0x2
#define TC3589x_IRQRST 0x10
#define TC3589x_RESET_ALL 0x1B
/* KBDMFS register bit mask */
#define TC3589x_KBDMFS_EN 0x1
/* CLKEN register bitmask */
#define KPD_CLK_EN 0x1
/* RSTINTCLR register bit mask */
#define IRQ_CLEAR 0x1
/* bit masks for keyboard interrupts*/
#define TC3589x_EVT_LOSS_INT 0x8
#define TC3589x_EVT_INT 0x4
#define TC3589x_KBD_LOSS_INT 0x2
#define TC3589x_KBD_INT 0x1
/* bit masks for keyboard interrupt clear*/
#define TC3589x_EVT_INT_CLR 0x2
#define TC3589x_KBD_INT_CLR 0x1
#define TC3589x_KBD_KEYMAP_SIZE 64
/**
* struct tc_keypad - data structure used by keypad driver
* @input: pointer to input device object
* @board: keypad platform device
* @krow: number of rows
* @kcol: number of coloumns
* @keymap: matrix scan code table for keycodes
*/
struct tc_keypad {
struct tc3589x *tc3589x;
struct input_dev *input;
const struct tc3589x_keypad_platform_data *board;
unsigned int krow;
unsigned int kcol;
unsigned short keymap[TC3589x_KBD_KEYMAP_SIZE];
bool keypad_stopped;
};
static int __devinit tc3589x_keypad_init_key_hardware(struct tc_keypad *keypad)
{
int ret;
struct tc3589x *tc3589x = keypad->tc3589x;
u8 settle_time = keypad->board->settle_time;
u8 dbounce_period = keypad->board->debounce_period;
u8 rows = keypad->board->krow & 0xf; /* mask out the nibble */
u8 column = keypad->board->kcol & 0xf; /* mask out the nibble */
/* validate platform configurations */
if (keypad->board->kcol > TC3589x_MAX_KPCOL ||
keypad->board->krow > TC3589x_MAX_KPROW ||
keypad->board->debounce_period > TC3589x_MAX_DEBOUNCE_SETTLE ||
keypad->board->settle_time > TC3589x_MAX_DEBOUNCE_SETTLE)
return -EINVAL;
/* configure KBDSIZE 4 LSbits for cols and 4 MSbits for rows */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSIZE,
(rows << KP_ROW_SHIFT) | column);
if (ret < 0)
return ret;
/* configure dedicated key config, no dedicated key selected */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_LSB, DEDICATED_KEY_VAL);
if (ret < 0)
return ret;
ret = tc3589x_reg_write(tc3589x, TC3589x_KBCFG_MSB, DEDICATED_KEY_VAL);
if (ret < 0)
return ret;
/* Configure settle time */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDSETTLE_REG, settle_time);
if (ret < 0)
return ret;
/* Configure debounce time */
ret = tc3589x_reg_write(tc3589x, TC3589x_KBDBOUNCE, dbounce_period);
if (ret < 0)
return ret;
/* Start of initialise keypad GPIOs */
ret = tc3589x_set_bits(tc3589x, TC3589x_IOCFG, 0x0, IOCFG_IG);
if (ret < 0)
return ret;
/* Configure pull-up resistors for all row GPIOs */
ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_LSB,
TC3589x_PULLUP_ALL_MASK);
if (ret < 0)
return ret;
ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG0_MSB,
TC3589x_PULLUP_ALL_MASK);
if (ret < 0)
return ret;
/* Configure pull-up resistors for all column GPIOs */
ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_LSB,
TC3589x_PULLUP_ALL_MASK);
if (ret < 0)
return ret;
ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG1_MSB,
TC3589x_PULLUP_ALL_MASK);
if (ret < 0)
return ret;
ret = tc3589x_reg_write(tc3589x, TC3589x_IOPULLCFG2_LSB,
TC3589x_PULLUP_ALL_MASK);
return ret;
}
#define TC35893_DATA_REGS 4
#define TC35893_KEYCODE_FIFO_EMPTY 0x7f
#define TC35893_KEYCODE_FIFO_CLEAR 0xff
#define TC35893_KEYPAD_ROW_SHIFT 0x3
static irqreturn_t tc3589x_keypad_irq(int irq, void *dev)
{
struct tc_keypad *keypad = dev;
struct tc3589x *tc3589x = keypad->tc3589x;
u8 i, row_index, col_index, kbd_code, up;
u8 code;
for (i = 0; i < TC35893_DATA_REGS * 2; i++) {
kbd_code = tc3589x_reg_read(tc3589x, TC3589x_EVTCODE_FIFO);
/* loop till fifo is empty and no more keys are pressed */
if (kbd_code == TC35893_KEYCODE_FIFO_EMPTY ||
kbd_code == TC35893_KEYCODE_FIFO_CLEAR)
continue;
/* valid key is found */
col_index = kbd_code & KP_EVCODE_COL_MASK;
row_index = (kbd_code & KP_EVCODE_ROW_MASK) >> KP_ROW_SHIFT;
code = MATRIX_SCAN_CODE(row_index, col_index,
TC35893_KEYPAD_ROW_SHIFT);
up = kbd_code & KP_RELEASE_EVT_MASK;
input_event(keypad->input, EV_MSC, MSC_SCAN, code);
input_report_key(keypad->input, keypad->keymap[code], !up);
input_sync(keypad->input);
}
/* clear IRQ */
tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
/* enable IRQ */
tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
0x0, TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
return IRQ_HANDLED;
}
static int tc3589x_keypad_enable(struct tc_keypad *keypad)
{
struct tc3589x *tc3589x = keypad->tc3589x;
int ret;
/* pull the keypad module out of reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x0);
if (ret < 0)
return ret;
/* configure KBDMFS */
ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMFS, 0x0, TC3589x_KBDMFS_EN);
if (ret < 0)
return ret;
/* enable the keypad clock */
ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x0, KPD_CLK_EN);
if (ret < 0)
return ret;
/* clear pending IRQs */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTINTCLR, 0x0, 0x1);
if (ret < 0)
return ret;
/* enable the IRQs */
ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK, 0x0,
TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT);
if (ret < 0)
return ret;
keypad->keypad_stopped = false;
return ret;
}
static int tc3589x_keypad_disable(struct tc_keypad *keypad)
{
struct tc3589x *tc3589x = keypad->tc3589x;
int ret;
/* clear IRQ */
ret = tc3589x_set_bits(tc3589x, TC3589x_KBDIC,
0x0, TC3589x_EVT_INT_CLR | TC3589x_KBD_INT_CLR);
if (ret < 0)
return ret;
/* disable all interrupts */
ret = tc3589x_set_bits(tc3589x, TC3589x_KBDMSK,
~(TC3589x_EVT_LOSS_INT | TC3589x_EVT_INT), 0x0);
if (ret < 0)
return ret;
/* disable the keypad module */
ret = tc3589x_set_bits(tc3589x, TC3589x_CLKEN, 0x1, 0x0);
if (ret < 0)
return ret;
/* put the keypad module into reset */
ret = tc3589x_set_bits(tc3589x, TC3589x_RSTCTRL, TC3589x_KBDRST, 0x1);
keypad->keypad_stopped = true;
return ret;
}
static int tc3589x_keypad_open(struct input_dev *input)
{
int error;
struct tc_keypad *keypad = input_get_drvdata(input);
/* enable the keypad module */
error = tc3589x_keypad_enable(keypad);
if (error < 0) {
dev_err(&input->dev, "failed to enable keypad module\n");
return error;
}
error = tc3589x_keypad_init_key_hardware(keypad);
if (error < 0) {
dev_err(&input->dev, "failed to configure keypad module\n");
return error;
}
return 0;
}
static void tc3589x_keypad_close(struct input_dev *input)
{
struct tc_keypad *keypad = input_get_drvdata(input);
/* disable the keypad module */
tc3589x_keypad_disable(keypad);
}
static int __devinit tc3589x_keypad_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
struct tc_keypad *keypad;
struct input_dev *input;
const struct tc3589x_keypad_platform_data *plat;
int error, irq;
plat = tc3589x->pdata->keypad;
if (!plat) {
dev_err(&pdev->dev, "invalid keypad platform data\n");
return -EINVAL;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0)
return irq;
keypad = kzalloc(sizeof(struct tc_keypad), GFP_KERNEL);
input = input_allocate_device();
if (!keypad || !input) {
dev_err(&pdev->dev, "failed to allocate keypad memory\n");
error = -ENOMEM;
goto err_free_mem;
}
keypad->board = plat;
keypad->input = input;
keypad->tc3589x = tc3589x;
input->id.bustype = BUS_I2C;
input->name = pdev->name;
input->dev.parent = &pdev->dev;
input->keycode = keypad->keymap;
input->keycodesize = sizeof(keypad->keymap[0]);
input->keycodemax = ARRAY_SIZE(keypad->keymap);
input->open = tc3589x_keypad_open;
input->close = tc3589x_keypad_close;
input_set_drvdata(input, keypad);
input_set_capability(input, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input->evbit);
if (!plat->no_autorepeat)
__set_bit(EV_REP, input->evbit);
matrix_keypad_build_keymap(plat->keymap_data, 0x3,
input->keycode, input->keybit);
error = request_threaded_irq(irq, NULL,
tc3589x_keypad_irq, plat->irqtype,
"tc3589x-keypad", keypad);
if (error < 0) {
dev_err(&pdev->dev,
"Could not allocate irq %d,error %d\n",
irq, error);
goto err_free_mem;
}
error = input_register_device(input);
if (error) {
dev_err(&pdev->dev, "Could not register input device\n");
goto err_free_irq;
}
/* let platform decide if keypad is a wakeup source or not */
device_init_wakeup(&pdev->dev, plat->enable_wakeup);
device_set_wakeup_capable(&pdev->dev, plat->enable_wakeup);
platform_set_drvdata(pdev, keypad);
return 0;
err_free_irq:
free_irq(irq, keypad);
err_free_mem:
input_free_device(input);
kfree(keypad);
return error;
}
static int __devexit tc3589x_keypad_remove(struct platform_device *pdev)
{
struct tc_keypad *keypad = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (!keypad->keypad_stopped)
tc3589x_keypad_disable(keypad);
free_irq(irq, keypad);
input_unregister_device(keypad->input);
kfree(keypad);
return 0;
}
#ifdef CONFIG_PM
static int tc3589x_keypad_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tc_keypad *keypad = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
/* keypad is already off; we do nothing */
if (keypad->keypad_stopped)
return 0;
/* if device is not a wakeup source, disable it for powersave */
if (!device_may_wakeup(&pdev->dev))
tc3589x_keypad_disable(keypad);
else
enable_irq_wake(irq);
return 0;
}
static int tc3589x_keypad_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct tc_keypad *keypad = platform_get_drvdata(pdev);
int irq = platform_get_irq(pdev, 0);
if (!keypad->keypad_stopped)
return 0;
/* enable the device to resume normal operations */
if (!device_may_wakeup(&pdev->dev))
tc3589x_keypad_enable(keypad);
else
disable_irq_wake(irq);
return 0;
}
static const SIMPLE_DEV_PM_OPS(tc3589x_keypad_dev_pm_ops,
tc3589x_keypad_suspend, tc3589x_keypad_resume);
#endif
static struct platform_driver tc3589x_keypad_driver = {
.driver.name = "tc3589x-keypad",
.driver.owner = THIS_MODULE,
#ifdef CONFIG_PM
.driver.pm = &tc3589x_keypad_dev_pm_ops,
#endif
.probe = tc3589x_keypad_probe,
.remove = __devexit_p(tc3589x_keypad_remove),
};
static int __init tc3589x_keypad_init(void)
{
return platform_driver_register(&tc3589x_keypad_driver);
}
module_init(tc3589x_keypad_init);
static void __exit tc3589x_keypad_exit(void)
{
return platform_driver_unregister(&tc3589x_keypad_driver);
}
module_exit(tc3589x_keypad_exit);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jayeeta Banerjee/Sundar Iyer");
MODULE_DESCRIPTION("TC35893 Keypad Driver");
MODULE_ALIAS("platform:tc3589x-keypad")

View File

@ -218,12 +218,12 @@ config MFD_STMPE
Keypad: stmpe-keypad
Touchscreen: stmpe-ts
config MFD_TC35892
bool "Support Toshiba TC35892"
config MFD_TC3589X
bool "Support Toshiba TC35892 and variants"
depends on I2C=y && GENERIC_HARDIRQS
select MFD_CORE
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,
additional drivers must be enabled in order to use the

View File

@ -16,7 +16,7 @@ obj-$(CONFIG_MFD_DAVINCI_VOICECODEC) += davinci_voicecodec.o
obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.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_TC6387XB) += tc6387xb.o tmio_core.o
obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o

View File

@ -1,345 +0,0 @@
/*
* 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");

422
drivers/mfd/tc3589x.c Normal file
View File

@ -0,0 +1,422 @@
/*
* 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");

View File

@ -11,7 +11,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <mach/mbox.h>
#include <mach/mbox-db5500.h>
#include <net/caif/caif_shm.h>
MODULE_LICENSE("GPL");

View File

@ -1,136 +0,0 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
*/
#ifndef __LINUX_MFD_TC35892_H
#define __LINUX_MFD_TC35892_H
#include <linux/device.h>
#define TC35892_RSTCTRL_IRQRST (1 << 4)
#define TC35892_RSTCTRL_TIMRST (1 << 3)
#define TC35892_RSTCTRL_ROTRST (1 << 2)
#define TC35892_RSTCTRL_KBDRST (1 << 1)
#define TC35892_RSTCTRL_GPIRST (1 << 0)
#define TC35892_IRQST 0x91
#define TC35892_MANFCODE_MAGIC 0x03
#define TC35892_MANFCODE 0x80
#define TC35892_VERSION 0x81
#define TC35892_IOCFG 0xA7
#define TC35892_CLKMODE 0x88
#define TC35892_CLKCFG 0x89
#define TC35892_CLKEN 0x8A
#define TC35892_RSTCTRL 0x82
#define TC35892_EXTRSTN 0x83
#define TC35892_RSTINTCLR 0x84
#define TC35892_GPIOIS0 0xC9
#define TC35892_GPIOIS1 0xCA
#define TC35892_GPIOIS2 0xCB
#define TC35892_GPIOIBE0 0xCC
#define TC35892_GPIOIBE1 0xCD
#define TC35892_GPIOIBE2 0xCE
#define TC35892_GPIOIEV0 0xCF
#define TC35892_GPIOIEV1 0xD0
#define TC35892_GPIOIEV2 0xD1
#define TC35892_GPIOIE0 0xD2
#define TC35892_GPIOIE1 0xD3
#define TC35892_GPIOIE2 0xD4
#define TC35892_GPIORIS0 0xD6
#define TC35892_GPIORIS1 0xD7
#define TC35892_GPIORIS2 0xD8
#define TC35892_GPIOMIS0 0xD9
#define TC35892_GPIOMIS1 0xDA
#define TC35892_GPIOMIS2 0xDB
#define TC35892_GPIOIC0 0xDC
#define TC35892_GPIOIC1 0xDD
#define TC35892_GPIOIC2 0xDE
#define TC35892_GPIODATA0 0xC0
#define TC35892_GPIOMASK0 0xc1
#define TC35892_GPIODATA1 0xC2
#define TC35892_GPIOMASK1 0xc3
#define TC35892_GPIODATA2 0xC4
#define TC35892_GPIOMASK2 0xC5
#define TC35892_GPIODIR0 0xC6
#define TC35892_GPIODIR1 0xC7
#define TC35892_GPIODIR2 0xC8
#define TC35892_GPIOSYNC0 0xE6
#define TC35892_GPIOSYNC1 0xE7
#define TC35892_GPIOSYNC2 0xE8
#define TC35892_GPIOWAKE0 0xE9
#define TC35892_GPIOWAKE1 0xEA
#define TC35892_GPIOWAKE2 0xEB
#define TC35892_GPIOODM0 0xE0
#define TC35892_GPIOODE0 0xE1
#define TC35892_GPIOODM1 0xE2
#define TC35892_GPIOODE1 0xE3
#define TC35892_GPIOODM2 0xE4
#define TC35892_GPIOODE2 0xE5
#define TC35892_INT_GPIIRQ 0
#define TC35892_INT_TI0IRQ 1
#define TC35892_INT_TI1IRQ 2
#define TC35892_INT_TI2IRQ 3
#define TC35892_INT_ROTIRQ 5
#define TC35892_INT_KBDIRQ 6
#define TC35892_INT_PORIRQ 7
#define TC35892_NR_INTERNAL_IRQS 8
#define TC35892_INT_GPIO(x) (TC35892_NR_INTERNAL_IRQS + (x))
struct tc35892 {
struct mutex lock;
struct device *dev;
struct i2c_client *i2c;
int irq_base;
int num_gpio;
struct tc35892_platform_data *pdata;
};
extern int tc35892_reg_write(struct tc35892 *tc35892, u8 reg, u8 data);
extern int tc35892_reg_read(struct tc35892 *tc35892, u8 reg);
extern int tc35892_block_read(struct tc35892 *tc35892, u8 reg, u8 length,
u8 *values);
extern int tc35892_block_write(struct tc35892 *tc35892, u8 reg, u8 length,
const u8 *values);
extern int tc35892_set_bits(struct tc35892 *tc35892, u8 reg, u8 mask, u8 val);
/**
* struct tc35892_gpio_platform_data - TC35892 GPIO platform data
* @gpio_base: first gpio number assigned to TC35892. A maximum of
* %TC35892_NR_GPIOS GPIOs will be allocated.
* @setup: callback for board-specific initialization
* @remove: callback for board-specific teardown
*/
struct tc35892_gpio_platform_data {
int gpio_base;
void (*setup)(struct tc35892 *tc35892, unsigned gpio_base);
void (*remove)(struct tc35892 *tc35892, unsigned gpio_base);
};
/**
* struct tc35892_platform_data - TC35892 platform data
* @irq_base: base IRQ number. %TC35892_NR_IRQS irqs will be used.
* @gpio: GPIO-specific platform data
*/
struct tc35892_platform_data {
int irq_base;
struct tc35892_gpio_platform_data *gpio;
};
#define TC35892_NR_GPIOS 24
#define TC35892_NR_IRQS TC35892_INT_GPIO(TC35892_NR_GPIOS)
#endif

195
include/linux/mfd/tc3589x.h Normal file
View File

@ -0,0 +1,195 @@
/*
* Copyright (C) ST-Ericsson SA 2010
*
* License Terms: GNU General Public License, version 2
*/
#ifndef __LINUX_MFD_TC3589x_H
#define __LINUX_MFD_TC3589x_H
#include <linux/device.h>
enum tx3589x_block {
TC3589x_BLOCK_GPIO = 1 << 0,
TC3589x_BLOCK_KEYPAD = 1 << 1,
};
#define TC3589x_RSTCTRL_IRQRST (1 << 4)
#define TC3589x_RSTCTRL_TIMRST (1 << 3)
#define TC3589x_RSTCTRL_ROTRST (1 << 2)
#define TC3589x_RSTCTRL_KBDRST (1 << 1)
#define TC3589x_RSTCTRL_GPIRST (1 << 0)
/* Keyboard Configuration Registers */
#define TC3589x_KBDSETTLE_REG 0x01
#define TC3589x_KBDBOUNCE 0x02
#define TC3589x_KBDSIZE 0x03
#define TC3589x_KBCFG_LSB 0x04
#define TC3589x_KBCFG_MSB 0x05
#define TC3589x_KBDIC 0x08
#define TC3589x_KBDMSK 0x09
#define TC3589x_EVTCODE_FIFO 0x10
#define TC3589x_KBDMFS 0x8F
#define TC3589x_IRQST 0x91
#define TC3589x_MANFCODE_MAGIC 0x03
#define TC3589x_MANFCODE 0x80
#define TC3589x_VERSION 0x81
#define TC3589x_IOCFG 0xA7
#define TC3589x_CLKMODE 0x88
#define TC3589x_CLKCFG 0x89
#define TC3589x_CLKEN 0x8A
#define TC3589x_RSTCTRL 0x82
#define TC3589x_EXTRSTN 0x83
#define TC3589x_RSTINTCLR 0x84
/* Pull up/down configuration registers */
#define TC3589x_IOCFG 0xA7
#define TC3589x_IOPULLCFG0_LSB 0xAA
#define TC3589x_IOPULLCFG0_MSB 0xAB
#define TC3589x_IOPULLCFG1_LSB 0xAC
#define TC3589x_IOPULLCFG1_MSB 0xAD
#define TC3589x_IOPULLCFG2_LSB 0xAE
#define TC3589x_GPIOIS0 0xC9
#define TC3589x_GPIOIS1 0xCA
#define TC3589x_GPIOIS2 0xCB
#define TC3589x_GPIOIBE0 0xCC
#define TC3589x_GPIOIBE1 0xCD
#define TC3589x_GPIOIBE2 0xCE
#define TC3589x_GPIOIEV0 0xCF
#define TC3589x_GPIOIEV1 0xD0
#define TC3589x_GPIOIEV2 0xD1
#define TC3589x_GPIOIE0 0xD2
#define TC3589x_GPIOIE1 0xD3
#define TC3589x_GPIOIE2 0xD4
#define TC3589x_GPIORIS0 0xD6
#define TC3589x_GPIORIS1 0xD7
#define TC3589x_GPIORIS2 0xD8
#define TC3589x_GPIOMIS0 0xD9
#define TC3589x_GPIOMIS1 0xDA
#define TC3589x_GPIOMIS2 0xDB
#define TC3589x_GPIOIC0 0xDC
#define TC3589x_GPIOIC1 0xDD
#define TC3589x_GPIOIC2 0xDE
#define TC3589x_GPIODATA0 0xC0
#define TC3589x_GPIOMASK0 0xc1
#define TC3589x_GPIODATA1 0xC2
#define TC3589x_GPIOMASK1 0xc3
#define TC3589x_GPIODATA2 0xC4
#define TC3589x_GPIOMASK2 0xC5
#define TC3589x_GPIODIR0 0xC6
#define TC3589x_GPIODIR1 0xC7
#define TC3589x_GPIODIR2 0xC8
#define TC3589x_GPIOSYNC0 0xE6
#define TC3589x_GPIOSYNC1 0xE7
#define TC3589x_GPIOSYNC2 0xE8
#define TC3589x_GPIOWAKE0 0xE9
#define TC3589x_GPIOWAKE1 0xEA
#define TC3589x_GPIOWAKE2 0xEB
#define TC3589x_GPIOODM0 0xE0
#define TC3589x_GPIOODE0 0xE1
#define TC3589x_GPIOODM1 0xE2
#define TC3589x_GPIOODE1 0xE3
#define TC3589x_GPIOODM2 0xE4
#define TC3589x_GPIOODE2 0xE5
#define TC3589x_INT_GPIIRQ 0
#define TC3589x_INT_TI0IRQ 1
#define TC3589x_INT_TI1IRQ 2
#define TC3589x_INT_TI2IRQ 3
#define TC3589x_INT_ROTIRQ 5
#define TC3589x_INT_KBDIRQ 6
#define TC3589x_INT_PORIRQ 7
#define TC3589x_NR_INTERNAL_IRQS 8
#define TC3589x_INT_GPIO(x) (TC3589x_NR_INTERNAL_IRQS + (x))
struct tc3589x {
struct mutex lock;
struct device *dev;
struct i2c_client *i2c;
int irq_base;
int num_gpio;
struct tc3589x_platform_data *pdata;
};
extern int tc3589x_reg_write(struct tc3589x *tc3589x, u8 reg, u8 data);
extern int tc3589x_reg_read(struct tc3589x *tc3589x, u8 reg);
extern int tc3589x_block_read(struct tc3589x *tc3589x, u8 reg, u8 length,
u8 *values);
extern int tc3589x_block_write(struct tc3589x *tc3589x, u8 reg, u8 length,
const u8 *values);
extern int tc3589x_set_bits(struct tc3589x *tc3589x, u8 reg, u8 mask, u8 val);
/*
* Keypad related platform specific constants
* These values may be modified for fine tuning
*/
#define TC_KPD_ROWS 0x8
#define TC_KPD_COLUMNS 0x8
#define TC_KPD_DEBOUNCE_PERIOD 0xA3
#define TC_KPD_SETTLE_TIME 0xA3
/**
* struct tc35893_platform_data - data structure for platform specific data
* @keymap_data: matrix scan code table for keycodes
* @krow: mask for available rows, value is 0xFF
* @kcol: mask for available columns, value is 0xFF
* @debounce_period: platform specific debounce time
* @settle_time: platform specific settle down time
* @irqtype: type of interrupt, falling or rising edge
* @enable_wakeup: specifies if keypad event can wake up system from sleep
* @no_autorepeat: flag for auto repetition
*/
struct tc3589x_keypad_platform_data {
const struct matrix_keymap_data *keymap_data;
u8 krow;
u8 kcol;
u8 debounce_period;
u8 settle_time;
unsigned long irqtype;
bool enable_wakeup;
bool no_autorepeat;
};
/**
* struct tc3589x_gpio_platform_data - TC3589x GPIO platform data
* @gpio_base: first gpio number assigned to TC3589x. A maximum of
* %TC3589x_NR_GPIOS GPIOs will be allocated.
* @setup: callback for board-specific initialization
* @remove: callback for board-specific teardown
*/
struct tc3589x_gpio_platform_data {
int gpio_base;
void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base);
void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base);
};
/**
* struct tc3589x_platform_data - TC3589x platform data
* @block: bitmask of blocks to enable (use TC3589x_BLOCK_*)
* @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used.
* @gpio: GPIO-specific platform data
* @keypad: keypad-specific platform data
*/
struct tc3589x_platform_data {
unsigned int block;
int irq_base;
struct tc3589x_gpio_platform_data *gpio;
const struct tc3589x_keypad_platform_data *keypad;
};
#define TC3589x_NR_GPIOS 24
#define TC3589x_NR_IRQS TC3589x_INT_GPIO(TC3589x_NR_GPIOS)
#endif