From 986435e3596cbae662b86812e4563fbb6013b994 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Thu, 1 Apr 2010 12:30:49 +0100 Subject: ARM: 6013/1: ST SPEAr: Added source files for SPEAr platform Reviewed-by: Linus Walleij Signed-off-by: Viresh Kumar Signed-off-by: Shiraz Hashim Signed-off-by: Russell King --- arch/arm/plat-spear/Makefile | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 arch/arm/plat-spear/Makefile (limited to 'arch/arm/plat-spear/Makefile') diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile new file mode 100644 index 000000000000..96f9ac3d4b81 --- /dev/null +++ b/arch/arm/plat-spear/Makefile @@ -0,0 +1,6 @@ +# +# SPEAr Platform specific Makefile +# + +# Common support +obj-y := clock.o time.o -- cgit v1.2.3 From 70f4c0bf9e4d067744ee453bc37c0c4adcea6e53 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Thu, 1 Apr 2010 12:31:29 +0100 Subject: ARM: 6020/1: ST SPEAr: Adding gpio pad multiplexing support GPIO Pads in spear platform are are multiplexed in various machines. This patch adds support for this pad multiplexing. Reviewed-by: Linus Walleij Signed-off-by: Viresh Kumar Signed-off-by: Russell King --- arch/arm/mach-spear3xx/include/mach/generic.h | 161 +++++++++- arch/arm/mach-spear3xx/spear300.c | 358 +++++++++++++++++++++ arch/arm/mach-spear3xx/spear300_evb.c | 22 ++ arch/arm/mach-spear3xx/spear310.c | 129 ++++++++ arch/arm/mach-spear3xx/spear310_evb.c | 30 ++ arch/arm/mach-spear3xx/spear320.c | 374 +++++++++++++++++++++ arch/arm/mach-spear3xx/spear320_evb.c | 27 ++ arch/arm/mach-spear3xx/spear3xx.c | 447 ++++++++++++++++++++++++++ arch/arm/plat-spear/Makefile | 2 +- arch/arm/plat-spear/include/plat/padmux.h | 92 ++++++ arch/arm/plat-spear/padmux.c | 164 ++++++++++ 11 files changed, 1798 insertions(+), 8 deletions(-) create mode 100644 arch/arm/plat-spear/include/plat/padmux.h create mode 100644 arch/arm/plat-spear/padmux.c (limited to 'arch/arm/plat-spear/Makefile') diff --git a/arch/arm/mach-spear3xx/include/mach/generic.h b/arch/arm/mach-spear3xx/include/mach/generic.h index aeea8453a9e2..af7e02c909a3 100644 --- a/arch/arm/mach-spear3xx/include/mach/generic.h +++ b/arch/arm/mach-spear3xx/include/mach/generic.h @@ -19,7 +19,9 @@ #include #include #include +#include +/* spear3xx declarations */ /* * Each GPT has 2 timer channels * Following GPT channels will be used as clock source and clockevent @@ -34,25 +36,170 @@ extern struct amba_device uart_device; extern struct sys_timer spear_sys_timer; /* Add spear3xx family function declarations here */ +void __init clk_init(void); void __init spear3xx_map_io(void); void __init spear3xx_init_irq(void); void __init spear3xx_init(void); -void __init spear300_init(void); -void __init spear310_init(void); -void __init spear320_init(void); -void __init clk_init(void); +void spear_pmx_init(struct pmx_driver *pmx_driver, uint base, uint size); -/* Add spear300 machine device structure declarations here */ +/* pad mux declarations */ +#define PMX_FIRDA_MASK (1 << 14) +#define PMX_I2C_MASK (1 << 13) +#define PMX_SSP_CS_MASK (1 << 12) +#define PMX_SSP_MASK (1 << 11) +#define PMX_MII_MASK (1 << 10) +#define PMX_GPIO_PIN0_MASK (1 << 9) +#define PMX_GPIO_PIN1_MASK (1 << 8) +#define PMX_GPIO_PIN2_MASK (1 << 7) +#define PMX_GPIO_PIN3_MASK (1 << 6) +#define PMX_GPIO_PIN4_MASK (1 << 5) +#define PMX_GPIO_PIN5_MASK (1 << 4) +#define PMX_UART0_MODEM_MASK (1 << 3) +#define PMX_UART0_MASK (1 << 2) +#define PMX_TIMER_3_4_MASK (1 << 1) +#define PMX_TIMER_1_2_MASK (1 << 0) + +/* pad mux devices */ +extern struct pmx_dev pmx_firda; +extern struct pmx_dev pmx_i2c; +extern struct pmx_dev pmx_ssp_cs; +extern struct pmx_dev pmx_ssp; +extern struct pmx_dev pmx_mii; +extern struct pmx_dev pmx_gpio_pin0; +extern struct pmx_dev pmx_gpio_pin1; +extern struct pmx_dev pmx_gpio_pin2; +extern struct pmx_dev pmx_gpio_pin3; +extern struct pmx_dev pmx_gpio_pin4; +extern struct pmx_dev pmx_gpio_pin5; +extern struct pmx_dev pmx_uart0_modem; +extern struct pmx_dev pmx_uart0; +extern struct pmx_dev pmx_timer_3_4; +extern struct pmx_dev pmx_timer_1_2; + +#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) +/* padmux plgpio devices */ +extern struct pmx_dev pmx_plgpio_0_1; +extern struct pmx_dev pmx_plgpio_2_3; +extern struct pmx_dev pmx_plgpio_4_5; +extern struct pmx_dev pmx_plgpio_6_9; +extern struct pmx_dev pmx_plgpio_10_27; +extern struct pmx_dev pmx_plgpio_28; +extern struct pmx_dev pmx_plgpio_29; +extern struct pmx_dev pmx_plgpio_30; +extern struct pmx_dev pmx_plgpio_31; +extern struct pmx_dev pmx_plgpio_32; +extern struct pmx_dev pmx_plgpio_33; +extern struct pmx_dev pmx_plgpio_34_36; +extern struct pmx_dev pmx_plgpio_37_42; +extern struct pmx_dev pmx_plgpio_43_44_47_48; +extern struct pmx_dev pmx_plgpio_45_46_49_50; +#endif + +extern struct pmx_driver pmx_driver; + +/* spear300 declarations */ #ifdef CONFIG_MACH_SPEAR300 +/* Add spear300 machine device structure declarations here */ extern struct amba_device gpio1_device; + +/* pad mux modes */ +extern struct pmx_mode nand_mode; +extern struct pmx_mode nor_mode; +extern struct pmx_mode photo_frame_mode; +extern struct pmx_mode lend_ip_phone_mode; +extern struct pmx_mode hend_ip_phone_mode; +extern struct pmx_mode lend_wifi_phone_mode; +extern struct pmx_mode hend_wifi_phone_mode; +extern struct pmx_mode ata_pabx_wi2s_mode; +extern struct pmx_mode ata_pabx_i2s_mode; +extern struct pmx_mode caml_lcdw_mode; +extern struct pmx_mode camu_lcd_mode; +extern struct pmx_mode camu_wlcd_mode; +extern struct pmx_mode caml_lcd_mode; + +/* pad mux devices */ +extern struct pmx_dev pmx_fsmc_2_chips; +extern struct pmx_dev pmx_fsmc_4_chips; +extern struct pmx_dev pmx_keyboard; +extern struct pmx_dev pmx_clcd; +extern struct pmx_dev pmx_telecom_gpio; +extern struct pmx_dev pmx_telecom_tdm; +extern struct pmx_dev pmx_telecom_spi_cs_i2c_clk; +extern struct pmx_dev pmx_telecom_camera; +extern struct pmx_dev pmx_telecom_dac; +extern struct pmx_dev pmx_telecom_i2s; +extern struct pmx_dev pmx_telecom_boot_pins; +extern struct pmx_dev pmx_telecom_sdio_4bit; +extern struct pmx_dev pmx_telecom_sdio_8bit; +extern struct pmx_dev pmx_gpio1; + +void spear300_pmx_init(void); + +/* Add spear300 machine function declarations here */ +void __init spear300_init(void); + #endif /* CONFIG_MACH_SPEAR300 */ -/* Add spear310 machine device structure declarations here */ +/* spear310 declarations */ #ifdef CONFIG_MACH_SPEAR310 +/* Add spear310 machine device structure declarations here */ + +/* pad mux devices */ +extern struct pmx_dev pmx_emi_cs_0_1_4_5; +extern struct pmx_dev pmx_emi_cs_2_3; +extern struct pmx_dev pmx_uart1; +extern struct pmx_dev pmx_uart2; +extern struct pmx_dev pmx_uart3_4_5; +extern struct pmx_dev pmx_fsmc; +extern struct pmx_dev pmx_rs485_0_1; +extern struct pmx_dev pmx_tdm0; + +void spear310_pmx_init(void); + +/* Add spear310 machine function declarations here */ +void __init spear310_init(void); + #endif /* CONFIG_MACH_SPEAR310 */ -/* Add spear320 machine device structure declarations here */ +/* spear320 declarations */ #ifdef CONFIG_MACH_SPEAR320 +/* Add spear320 machine device structure declarations here */ + +/* pad mux modes */ +extern struct pmx_mode auto_net_smii_mode; +extern struct pmx_mode auto_net_mii_mode; +extern struct pmx_mode auto_exp_mode; +extern struct pmx_mode small_printers_mode; + +/* pad mux devices */ +extern struct pmx_dev pmx_clcd; +extern struct pmx_dev pmx_emi; +extern struct pmx_dev pmx_fsmc; +extern struct pmx_dev pmx_spp; +extern struct pmx_dev pmx_sdio; +extern struct pmx_dev pmx_i2s; +extern struct pmx_dev pmx_uart1; +extern struct pmx_dev pmx_uart1_modem; +extern struct pmx_dev pmx_uart2; +extern struct pmx_dev pmx_touchscreen; +extern struct pmx_dev pmx_can; +extern struct pmx_dev pmx_sdio_led; +extern struct pmx_dev pmx_pwm0; +extern struct pmx_dev pmx_pwm1; +extern struct pmx_dev pmx_pwm2; +extern struct pmx_dev pmx_pwm3; +extern struct pmx_dev pmx_ssp1; +extern struct pmx_dev pmx_ssp2; +extern struct pmx_dev pmx_mii1; +extern struct pmx_dev pmx_smii0; +extern struct pmx_dev pmx_smii1; +extern struct pmx_dev pmx_i2c1; + +void spear320_pmx_init(void); + +/* Add spear320 machine function declarations here */ +void __init spear320_init(void); + #endif /* CONFIG_MACH_SPEAR320 */ #endif /* __MACH_GENERIC_H */ diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index 63aca8fc3ebb..66e7fcd8baf8 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -18,6 +18,357 @@ #include #include +/* pad multiplexing support */ +/* muxing registers */ +#define PAD_MUX_CONFIG_REG 0x00 +#define MODE_CONFIG_REG 0x04 + +/* modes */ +#define NAND_MODE (1 << 0) +#define NOR_MODE (1 << 1) +#define PHOTO_FRAME_MODE (1 << 2) +#define LEND_IP_PHONE_MODE (1 << 3) +#define HEND_IP_PHONE_MODE (1 << 4) +#define LEND_WIFI_PHONE_MODE (1 << 5) +#define HEND_WIFI_PHONE_MODE (1 << 6) +#define ATA_PABX_WI2S_MODE (1 << 7) +#define ATA_PABX_I2S_MODE (1 << 8) +#define CAML_LCDW_MODE (1 << 9) +#define CAMU_LCD_MODE (1 << 10) +#define CAMU_WLCD_MODE (1 << 11) +#define CAML_LCD_MODE (1 << 12) +#define ALL_MODES 0x1FFF + +struct pmx_mode nand_mode = { + .id = NAND_MODE, + .name = "nand mode", + .mask = 0x00, +}; + +struct pmx_mode nor_mode = { + .id = NOR_MODE, + .name = "nor mode", + .mask = 0x01, +}; + +struct pmx_mode photo_frame_mode = { + .id = PHOTO_FRAME_MODE, + .name = "photo frame mode", + .mask = 0x02, +}; + +struct pmx_mode lend_ip_phone_mode = { + .id = LEND_IP_PHONE_MODE, + .name = "lend ip phone mode", + .mask = 0x03, +}; + +struct pmx_mode hend_ip_phone_mode = { + .id = HEND_IP_PHONE_MODE, + .name = "hend ip phone mode", + .mask = 0x04, +}; + +struct pmx_mode lend_wifi_phone_mode = { + .id = LEND_WIFI_PHONE_MODE, + .name = "lend wifi phone mode", + .mask = 0x05, +}; + +struct pmx_mode hend_wifi_phone_mode = { + .id = HEND_WIFI_PHONE_MODE, + .name = "hend wifi phone mode", + .mask = 0x06, +}; + +struct pmx_mode ata_pabx_wi2s_mode = { + .id = ATA_PABX_WI2S_MODE, + .name = "ata pabx wi2s mode", + .mask = 0x07, +}; + +struct pmx_mode ata_pabx_i2s_mode = { + .id = ATA_PABX_I2S_MODE, + .name = "ata pabx i2s mode", + .mask = 0x08, +}; + +struct pmx_mode caml_lcdw_mode = { + .id = CAML_LCDW_MODE, + .name = "caml lcdw mode", + .mask = 0x0C, +}; + +struct pmx_mode camu_lcd_mode = { + .id = CAMU_LCD_MODE, + .name = "camu lcd mode", + .mask = 0x0D, +}; + +struct pmx_mode camu_wlcd_mode = { + .id = CAMU_WLCD_MODE, + .name = "camu wlcd mode", + .mask = 0x0E, +}; + +struct pmx_mode caml_lcd_mode = { + .id = CAML_LCD_MODE, + .name = "caml lcd mode", + .mask = 0x0F, +}; + +/* devices */ +struct pmx_dev_mode pmx_fsmc_2_chips_modes[] = { + { + .ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE | + ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE, + .mask = PMX_FIRDA_MASK, + }, +}; + +struct pmx_dev pmx_fsmc_2_chips = { + .name = "fsmc_2_chips", + .modes = pmx_fsmc_2_chips_modes, + .mode_count = ARRAY_SIZE(pmx_fsmc_2_chips_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_fsmc_4_chips_modes[] = { + { + .ids = NAND_MODE | NOR_MODE | PHOTO_FRAME_MODE | + ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE, + .mask = PMX_FIRDA_MASK | PMX_UART0_MASK, + }, +}; + +struct pmx_dev pmx_fsmc_4_chips = { + .name = "fsmc_4_chips", + .modes = pmx_fsmc_4_chips_modes, + .mode_count = ARRAY_SIZE(pmx_fsmc_4_chips_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_keyboard_modes[] = { + { + .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE | + LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE | + CAML_LCDW_MODE | CAMU_LCD_MODE | CAMU_WLCD_MODE | + CAML_LCD_MODE, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_keyboard = { + .name = "keyboard", + .modes = pmx_keyboard_modes, + .mode_count = ARRAY_SIZE(pmx_keyboard_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_clcd_modes[] = { + { + .ids = PHOTO_FRAME_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK , + }, { + .ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE | + CAMU_LCD_MODE | CAML_LCD_MODE, + .mask = PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_clcd = { + .name = "clcd", + .modes = pmx_clcd_modes, + .mode_count = ARRAY_SIZE(pmx_clcd_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_gpio_modes[] = { + { + .ids = PHOTO_FRAME_MODE | CAMU_LCD_MODE | CAML_LCD_MODE, + .mask = PMX_MII_MASK, + }, { + .ids = LEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE, + .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK, + }, { + .ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_WLCD_MODE, + .mask = PMX_MII_MASK | PMX_TIMER_3_4_MASK, + }, { + .ids = HEND_IP_PHONE_MODE | HEND_WIFI_PHONE_MODE, + .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK, + }, { + .ids = ATA_PABX_WI2S_MODE, + .mask = PMX_MII_MASK | PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK + | PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_telecom_gpio = { + .name = "telecom_gpio", + .modes = pmx_telecom_gpio_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_gpio_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_tdm_modes[] = { + { + .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE + | HEND_WIFI_PHONE_MODE | ATA_PABX_WI2S_MODE + | ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .mask = PMX_UART0_MODEM_MASK | PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_telecom_tdm = { + .name = "telecom_tdm", + .modes = pmx_telecom_tdm_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_tdm_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_spi_cs_i2c_clk_modes[] = { + { + .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE | + LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE + | ATA_PABX_WI2S_MODE | ATA_PABX_I2S_MODE | + CAML_LCDW_MODE | CAML_LCD_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_telecom_spi_cs_i2c_clk = { + .name = "telecom_spi_cs_i2c_clk", + .modes = pmx_telecom_spi_cs_i2c_clk_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_spi_cs_i2c_clk_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_camera_modes[] = { + { + .ids = CAML_LCDW_MODE | CAML_LCD_MODE, + .mask = PMX_MII_MASK, + }, { + .ids = CAMU_LCD_MODE | CAMU_WLCD_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK | PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_telecom_camera = { + .name = "telecom_camera", + .modes = pmx_telecom_camera_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_camera_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_dac_modes[] = { + { + .ids = ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .mask = PMX_TIMER_1_2_MASK, + }, +}; + +struct pmx_dev pmx_telecom_dac = { + .name = "telecom_dac", + .modes = pmx_telecom_dac_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_dac_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_i2s_modes[] = { + { + .ids = LEND_IP_PHONE_MODE | HEND_IP_PHONE_MODE + | LEND_WIFI_PHONE_MODE | HEND_WIFI_PHONE_MODE | + ATA_PABX_I2S_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE + | CAMU_WLCD_MODE | CAML_LCD_MODE, + .mask = PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_telecom_i2s = { + .name = "telecom_i2s", + .modes = pmx_telecom_i2s_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_i2s_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_boot_pins_modes[] = { + { + .ids = NAND_MODE | NOR_MODE, + .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK | + PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_telecom_boot_pins = { + .name = "telecom_boot_pins", + .modes = pmx_telecom_boot_pins_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_boot_pins_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_sdio_4bit_modes[] = { + { + .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE | + HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE | + CAMU_WLCD_MODE | CAML_LCD_MODE | ATA_PABX_WI2S_MODE | + ATA_PABX_I2S_MODE, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK | + PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK | + PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK, + }, +}; + +struct pmx_dev pmx_telecom_sdio_4bit = { + .name = "telecom_sdio_4bit", + .modes = pmx_telecom_sdio_4bit_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_sdio_4bit_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_telecom_sdio_8bit_modes[] = { + { + .ids = PHOTO_FRAME_MODE | LEND_IP_PHONE_MODE | + HEND_IP_PHONE_MODE | LEND_WIFI_PHONE_MODE | + HEND_WIFI_PHONE_MODE | CAML_LCDW_MODE | CAMU_LCD_MODE | + CAMU_WLCD_MODE | CAML_LCD_MODE, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK | + PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK | + PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK | PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_telecom_sdio_8bit = { + .name = "telecom_sdio_8bit", + .modes = pmx_telecom_sdio_8bit_modes, + .mode_count = ARRAY_SIZE(pmx_telecom_sdio_8bit_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_gpio1_modes[] = { + { + .ids = PHOTO_FRAME_MODE, + .mask = PMX_UART0_MODEM_MASK | PMX_TIMER_1_2_MASK | + PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_gpio1 = { + .name = "arm gpio1", + .modes = pmx_gpio1_modes, + .mode_count = ARRAY_SIZE(pmx_gpio1_modes), + .enb_on_reset = 1, +}; + +/* pmx driver structure */ +struct pmx_driver pmx_driver = { + .mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x0000000f}, + .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff}, +}; + /* Add spear300 specific devices here */ /* arm gpio1 device registeration */ static struct pl061_platform_data gpio1_plat_data = { @@ -38,8 +389,15 @@ struct amba_device gpio1_device = { .irq = {IRQ_GEN_RAS_1, NO_IRQ}, }; +/* spear300 routines */ void __init spear300_init(void) { /* call spear3xx family common init function */ spear3xx_init(); } + +void spear300_pmx_init(void) +{ + spear_pmx_init(&pmx_driver, SPEAR300_SOC_CONFIG_BASE, + SPEAR300_SOC_CONFIG_SIZE); +} diff --git a/arch/arm/mach-spear3xx/spear300_evb.c b/arch/arm/mach-spear3xx/spear300_evb.c index 1272a385c208..bb21db152a23 100644 --- a/arch/arm/mach-spear3xx/spear300_evb.c +++ b/arch/arm/mach-spear3xx/spear300_evb.c @@ -16,6 +16,22 @@ #include #include +/* padmux devices to enable */ +static struct pmx_dev *pmx_devs[] = { + /* spear3xx specific devices */ + &pmx_i2c, + &pmx_ssp_cs, + &pmx_ssp, + &pmx_mii, + &pmx_uart0, + + /* spear300 specific devices */ + &pmx_fsmc_2_chips, + &pmx_clcd, + &pmx_telecom_sdio_4bit, + &pmx_gpio1, +}; + static struct amba_device *amba_devs[] __initdata = { /* spear3xx specific devices */ &gpio_device, @@ -38,6 +54,12 @@ static void __init spear300_evb_init(void) /* call spear300 machine init function */ spear300_init(); + /* padmux initialization */ + pmx_driver.mode = &photo_frame_mode; + pmx_driver.devs = pmx_devs; + pmx_driver.devs_count = ARRAY_SIZE(pmx_devs); + spear300_pmx_init(); + /* Add Platform Devices */ platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs)); diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index 6eb62f9de7ee..dd5a57282711 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -16,10 +16,139 @@ #include #include +/* pad multiplexing support */ +/* muxing registers */ +#define PAD_MUX_CONFIG_REG 0x08 + +/* devices */ +struct pmx_dev_mode pmx_emi_cs_0_1_4_5_modes[] = { + { + .ids = 0x00, + .mask = PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_emi_cs_0_1_4_5 = { + .name = "emi_cs_0_1_4_5", + .modes = pmx_emi_cs_0_1_4_5_modes, + .mode_count = ARRAY_SIZE(pmx_emi_cs_0_1_4_5_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_emi_cs_2_3_modes[] = { + { + .ids = 0x00, + .mask = PMX_TIMER_1_2_MASK, + }, +}; + +struct pmx_dev pmx_emi_cs_2_3 = { + .name = "emi_cs_2_3", + .modes = pmx_emi_cs_2_3_modes, + .mode_count = ARRAY_SIZE(pmx_emi_cs_2_3_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart1_modes[] = { + { + .ids = 0x00, + .mask = PMX_FIRDA_MASK, + }, +}; + +struct pmx_dev pmx_uart1 = { + .name = "uart1", + .modes = pmx_uart1_modes, + .mode_count = ARRAY_SIZE(pmx_uart1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart2_modes[] = { + { + .ids = 0x00, + .mask = PMX_TIMER_1_2_MASK, + }, +}; + +struct pmx_dev pmx_uart2 = { + .name = "uart2", + .modes = pmx_uart2_modes, + .mode_count = ARRAY_SIZE(pmx_uart2_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart3_4_5_modes[] = { + { + .ids = 0x00, + .mask = PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_uart3_4_5 = { + .name = "uart3_4_5", + .modes = pmx_uart3_4_5_modes, + .mode_count = ARRAY_SIZE(pmx_uart3_4_5_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_fsmc_modes[] = { + { + .ids = 0x00, + .mask = PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_fsmc = { + .name = "fsmc", + .modes = pmx_fsmc_modes, + .mode_count = ARRAY_SIZE(pmx_fsmc_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_rs485_0_1_modes[] = { + { + .ids = 0x00, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_rs485_0_1 = { + .name = "rs485_0_1", + .modes = pmx_rs485_0_1_modes, + .mode_count = ARRAY_SIZE(pmx_rs485_0_1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_tdm0_modes[] = { + { + .ids = 0x00, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_tdm0 = { + .name = "tdm0", + .modes = pmx_tdm0_modes, + .mode_count = ARRAY_SIZE(pmx_tdm0_modes), + .enb_on_reset = 1, +}; + +/* pmx driver structure */ +struct pmx_driver pmx_driver = { + .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff}, +}; + /* Add spear310 specific devices here */ +/* spear310 routines */ void __init spear310_init(void) { /* call spear3xx family common init function */ spear3xx_init(); } + +void spear310_pmx_init(void) +{ + spear_pmx_init(&pmx_driver, SPEAR310_SOC_CONFIG_BASE, + SPEAR310_SOC_CONFIG_SIZE); +} diff --git a/arch/arm/mach-spear3xx/spear310_evb.c b/arch/arm/mach-spear3xx/spear310_evb.c index e781b2b7f137..7facf6643199 100644 --- a/arch/arm/mach-spear3xx/spear310_evb.c +++ b/arch/arm/mach-spear3xx/spear310_evb.c @@ -16,6 +16,30 @@ #include #include +/* padmux devices to enable */ +static struct pmx_dev *pmx_devs[] = { + /* spear3xx specific devices */ + &pmx_i2c, + &pmx_ssp, + &pmx_gpio_pin0, + &pmx_gpio_pin1, + &pmx_gpio_pin2, + &pmx_gpio_pin3, + &pmx_gpio_pin4, + &pmx_gpio_pin5, + &pmx_uart0, + + /* spear310 specific devices */ + &pmx_emi_cs_0_1_4_5, + &pmx_emi_cs_2_3, + &pmx_uart1, + &pmx_uart2, + &pmx_uart3_4_5, + &pmx_fsmc, + &pmx_rs485_0_1, + &pmx_tdm0, +}; + static struct amba_device *amba_devs[] __initdata = { /* spear3xx specific devices */ &gpio_device, @@ -37,6 +61,12 @@ static void __init spear310_evb_init(void) /* call spear310 machine init function */ spear310_init(); + /* padmux initialization */ + pmx_driver.mode = NULL; + pmx_driver.devs = pmx_devs; + pmx_driver.devs_count = ARRAY_SIZE(pmx_devs); + spear310_pmx_init(); + /* Add Platform Devices */ platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs)); diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index 72d45489dcb0..2cedf5eb9ec9 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -16,10 +16,384 @@ #include #include +/* pad multiplexing support */ +/* muxing registers */ +#define PAD_MUX_CONFIG_REG 0x0C +#define MODE_CONFIG_REG 0x10 + +/* modes */ +#define AUTO_NET_SMII_MODE (1 << 0) +#define AUTO_NET_MII_MODE (1 << 1) +#define AUTO_EXP_MODE (1 << 2) +#define SMALL_PRINTERS_MODE (1 << 3) +#define ALL_MODES 0xF + +struct pmx_mode auto_net_smii_mode = { + .id = AUTO_NET_SMII_MODE, + .name = "Automation Networking SMII Mode", + .mask = 0x00, +}; + +struct pmx_mode auto_net_mii_mode = { + .id = AUTO_NET_MII_MODE, + .name = "Automation Networking MII Mode", + .mask = 0x01, +}; + +struct pmx_mode auto_exp_mode = { + .id = AUTO_EXP_MODE, + .name = "Automation Expanded Mode", + .mask = 0x02, +}; + +struct pmx_mode small_printers_mode = { + .id = SMALL_PRINTERS_MODE, + .name = "Small Printers Mode", + .mask = 0x03, +}; + +/* devices */ +struct pmx_dev_mode pmx_clcd_modes[] = { + { + .ids = AUTO_NET_SMII_MODE, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_clcd = { + .name = "clcd", + .modes = pmx_clcd_modes, + .mode_count = ARRAY_SIZE(pmx_clcd_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_emi_modes[] = { + { + .ids = AUTO_EXP_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_emi = { + .name = "emi", + .modes = pmx_emi_modes, + .mode_count = ARRAY_SIZE(pmx_emi_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_fsmc_modes[] = { + { + .ids = ALL_MODES, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_fsmc = { + .name = "fsmc", + .modes = pmx_fsmc_modes, + .mode_count = ARRAY_SIZE(pmx_fsmc_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_spp_modes[] = { + { + .ids = SMALL_PRINTERS_MODE, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_spp = { + .name = "spp", + .modes = pmx_spp_modes, + .mode_count = ARRAY_SIZE(pmx_spp_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_sdio_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | + SMALL_PRINTERS_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_sdio = { + .name = "sdio", + .modes = pmx_sdio_modes, + .mode_count = ARRAY_SIZE(pmx_sdio_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_i2s_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE, + .mask = PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_i2s = { + .name = "i2s", + .modes = pmx_i2s_modes, + .mode_count = ARRAY_SIZE(pmx_i2s_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart1_modes[] = { + { + .ids = ALL_MODES, + .mask = PMX_GPIO_PIN0_MASK | PMX_GPIO_PIN1_MASK, + }, +}; + +struct pmx_dev pmx_uart1 = { + .name = "uart1", + .modes = pmx_uart1_modes, + .mode_count = ARRAY_SIZE(pmx_uart1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart1_modem_modes[] = { + { + .ids = AUTO_EXP_MODE, + .mask = PMX_TIMER_1_2_MASK | PMX_TIMER_3_4_MASK | + PMX_SSP_CS_MASK, + }, { + .ids = SMALL_PRINTERS_MODE, + .mask = PMX_GPIO_PIN3_MASK | PMX_GPIO_PIN4_MASK | + PMX_GPIO_PIN5_MASK | PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_uart1_modem = { + .name = "uart1_modem", + .modes = pmx_uart1_modem_modes, + .mode_count = ARRAY_SIZE(pmx_uart1_modem_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_uart2_modes[] = { + { + .ids = ALL_MODES, + .mask = PMX_FIRDA_MASK, + }, +}; + +struct pmx_dev pmx_uart2 = { + .name = "uart2", + .modes = pmx_uart2_modes, + .mode_count = ARRAY_SIZE(pmx_uart2_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_touchscreen_modes[] = { + { + .ids = AUTO_NET_SMII_MODE, + .mask = PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_touchscreen = { + .name = "touchscreen", + .modes = pmx_touchscreen_modes, + .mode_count = ARRAY_SIZE(pmx_touchscreen_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_can_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE | AUTO_EXP_MODE, + .mask = PMX_GPIO_PIN2_MASK | PMX_GPIO_PIN3_MASK | + PMX_GPIO_PIN4_MASK | PMX_GPIO_PIN5_MASK, + }, +}; + +struct pmx_dev pmx_can = { + .name = "can", + .modes = pmx_can_modes, + .mode_count = ARRAY_SIZE(pmx_can_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_sdio_led_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE, + .mask = PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_sdio_led = { + .name = "sdio_led", + .modes = pmx_sdio_led_modes, + .mode_count = ARRAY_SIZE(pmx_sdio_led_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_pwm0_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE, + .mask = PMX_UART0_MODEM_MASK, + }, { + .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_pwm0 = { + .name = "pwm0", + .modes = pmx_pwm0_modes, + .mode_count = ARRAY_SIZE(pmx_pwm0_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_pwm1_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE, + .mask = PMX_UART0_MODEM_MASK, + }, { + .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_pwm1 = { + .name = "pwm1", + .modes = pmx_pwm1_modes, + .mode_count = ARRAY_SIZE(pmx_pwm1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_pwm2_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_NET_MII_MODE, + .mask = PMX_SSP_CS_MASK, + }, { + .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_pwm2 = { + .name = "pwm2", + .modes = pmx_pwm2_modes, + .mode_count = ARRAY_SIZE(pmx_pwm2_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_pwm3_modes[] = { + { + .ids = AUTO_EXP_MODE | SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_pwm3 = { + .name = "pwm3", + .modes = pmx_pwm3_modes, + .mode_count = ARRAY_SIZE(pmx_pwm3_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_ssp1_modes[] = { + { + .ids = SMALL_PRINTERS_MODE | AUTO_NET_SMII_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_ssp1 = { + .name = "ssp1", + .modes = pmx_ssp1_modes, + .mode_count = ARRAY_SIZE(pmx_ssp1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_ssp2_modes[] = { + { + .ids = AUTO_NET_SMII_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_ssp2 = { + .name = "ssp2", + .modes = pmx_ssp2_modes, + .mode_count = ARRAY_SIZE(pmx_ssp2_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_mii1_modes[] = { + { + .ids = AUTO_NET_MII_MODE, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_mii1 = { + .name = "mii1", + .modes = pmx_mii1_modes, + .mode_count = ARRAY_SIZE(pmx_mii1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_smii0_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | AUTO_EXP_MODE | SMALL_PRINTERS_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_smii0 = { + .name = "smii0", + .modes = pmx_smii0_modes, + .mode_count = ARRAY_SIZE(pmx_smii0_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_smii1_modes[] = { + { + .ids = AUTO_NET_SMII_MODE | SMALL_PRINTERS_MODE, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_smii1 = { + .name = "smii1", + .modes = pmx_smii1_modes, + .mode_count = ARRAY_SIZE(pmx_smii1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_i2c1_modes[] = { + { + .ids = AUTO_EXP_MODE, + .mask = 0x0, + }, +}; + +struct pmx_dev pmx_i2c1 = { + .name = "i2c1", + .modes = pmx_i2c1_modes, + .mode_count = ARRAY_SIZE(pmx_i2c1_modes), + .enb_on_reset = 1, +}; + +/* pmx driver structure */ +struct pmx_driver pmx_driver = { + .mode_reg = {.offset = MODE_CONFIG_REG, .mask = 0x00000007}, + .mux_reg = {.offset = PAD_MUX_CONFIG_REG, .mask = 0x00007fff}, +}; + /* Add spear320 specific devices here */ +/* spear320 routines */ void __init spear320_init(void) { /* call spear3xx family common init function */ spear3xx_init(); } + +void spear320_pmx_init(void) +{ + spear_pmx_init(&pmx_driver, SPEAR320_SOC_CONFIG_BASE, + SPEAR320_SOC_CONFIG_SIZE); +} diff --git a/arch/arm/mach-spear3xx/spear320_evb.c b/arch/arm/mach-spear3xx/spear320_evb.c index 85bc4d226212..62ac685a4135 100644 --- a/arch/arm/mach-spear3xx/spear320_evb.c +++ b/arch/arm/mach-spear3xx/spear320_evb.c @@ -16,6 +16,27 @@ #include #include +/* padmux devices to enable */ +static struct pmx_dev *pmx_devs[] = { + /* spear3xx specific devices */ + &pmx_i2c, + &pmx_ssp, + &pmx_mii, + &pmx_uart0, + + /* spear320 specific devices */ + &pmx_fsmc, + &pmx_sdio, + &pmx_i2s, + &pmx_uart1, + &pmx_uart2, + &pmx_can, + &pmx_pwm0, + &pmx_pwm1, + &pmx_pwm2, + &pmx_mii1, +}; + static struct amba_device *amba_devs[] __initdata = { /* spear3xx specific devices */ &gpio_device, @@ -37,6 +58,12 @@ static void __init spear320_evb_init(void) /* call spear320 machine init function */ spear320_init(); + /* padmux initialization */ + pmx_driver.mode = &auto_net_mii_mode; + pmx_driver.devs = pmx_devs; + pmx_driver.devs_count = ARRAY_SIZE(pmx_devs); + spear320_pmx_init(); + /* Add Platform Devices */ platform_add_devices(plat_devs, ARRAY_SIZE(plat_devs)); diff --git a/arch/arm/mach-spear3xx/spear3xx.c b/arch/arm/mach-spear3xx/spear3xx.c index 82ebcd30465e..e87313aeae20 100644 --- a/arch/arm/mach-spear3xx/spear3xx.c +++ b/arch/arm/mach-spear3xx/spear3xx.c @@ -99,3 +99,450 @@ void __init spear3xx_map_io(void) /* This will initialize clock framework */ clk_init(); } + +/* pad multiplexing support */ +/* devices */ +struct pmx_dev_mode pmx_firda_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_FIRDA_MASK, + }, +}; + +struct pmx_dev pmx_firda = { + .name = "firda", + .modes = pmx_firda_modes, + .mode_count = ARRAY_SIZE(pmx_firda_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_i2c_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_I2C_MASK, + }, +}; + +struct pmx_dev pmx_i2c = { + .name = "i2c", + .modes = pmx_i2c_modes, + .mode_count = ARRAY_SIZE(pmx_i2c_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_ssp_cs_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_ssp_cs = { + .name = "ssp_chip_selects", + .modes = pmx_ssp_cs_modes, + .mode_count = ARRAY_SIZE(pmx_ssp_cs_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_ssp_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_SSP_MASK, + }, +}; + +struct pmx_dev pmx_ssp = { + .name = "ssp", + .modes = pmx_ssp_modes, + .mode_count = ARRAY_SIZE(pmx_ssp_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_mii_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_mii = { + .name = "mii", + .modes = pmx_mii_modes, + .mode_count = ARRAY_SIZE(pmx_mii_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin0_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN0_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin0 = { + .name = "gpio_pin0", + .modes = pmx_gpio_pin0_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin0_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin1_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN1_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin1 = { + .name = "gpio_pin1", + .modes = pmx_gpio_pin1_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin1_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin2_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN2_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin2 = { + .name = "gpio_pin2", + .modes = pmx_gpio_pin2_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin2_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin3_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN3_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin3 = { + .name = "gpio_pin3", + .modes = pmx_gpio_pin3_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin3_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin4_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN4_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin4 = { + .name = "gpio_pin4", + .modes = pmx_gpio_pin4_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin4_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_gpio_pin5_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_GPIO_PIN5_MASK, + }, +}; + +struct pmx_dev pmx_gpio_pin5 = { + .name = "gpio_pin5", + .modes = pmx_gpio_pin5_modes, + .mode_count = ARRAY_SIZE(pmx_gpio_pin5_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_uart0_modem_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_uart0_modem = { + .name = "uart0_modem", + .modes = pmx_uart0_modem_modes, + .mode_count = ARRAY_SIZE(pmx_uart0_modem_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_uart0_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_UART0_MASK, + }, +}; + +struct pmx_dev pmx_uart0 = { + .name = "uart0", + .modes = pmx_uart0_modes, + .mode_count = ARRAY_SIZE(pmx_uart0_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_timer_3_4_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_timer_3_4 = { + .name = "timer_3_4", + .modes = pmx_timer_3_4_modes, + .mode_count = ARRAY_SIZE(pmx_timer_3_4_modes), + .enb_on_reset = 0, +}; + +struct pmx_dev_mode pmx_timer_1_2_modes[] = { + { + .ids = 0xffffffff, + .mask = PMX_TIMER_1_2_MASK, + }, +}; + +struct pmx_dev pmx_timer_1_2 = { + .name = "timer_1_2", + .modes = pmx_timer_1_2_modes, + .mode_count = ARRAY_SIZE(pmx_timer_1_2_modes), + .enb_on_reset = 0, +}; + +#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) +/* plgpios devices */ +struct pmx_dev_mode pmx_plgpio_0_1_modes[] = { + { + .ids = 0x00, + .mask = PMX_FIRDA_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_0_1 = { + .name = "plgpio 0 and 1", + .modes = pmx_plgpio_0_1_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_0_1_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_2_3_modes[] = { + { + .ids = 0x00, + .mask = PMX_UART0_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_2_3 = { + .name = "plgpio 2 and 3", + .modes = pmx_plgpio_2_3_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_2_3_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_4_5_modes[] = { + { + .ids = 0x00, + .mask = PMX_I2C_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_4_5 = { + .name = "plgpio 4 and 5", + .modes = pmx_plgpio_4_5_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_4_5_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_6_9_modes[] = { + { + .ids = 0x00, + .mask = PMX_SSP_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_6_9 = { + .name = "plgpio 6 to 9", + .modes = pmx_plgpio_6_9_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_6_9_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_10_27_modes[] = { + { + .ids = 0x00, + .mask = PMX_MII_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_10_27 = { + .name = "plgpio 10 to 27", + .modes = pmx_plgpio_10_27_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_10_27_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_28_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN0_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_28 = { + .name = "plgpio 28", + .modes = pmx_plgpio_28_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_28_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_29_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN1_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_29 = { + .name = "plgpio 29", + .modes = pmx_plgpio_29_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_29_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_30_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN2_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_30 = { + .name = "plgpio 30", + .modes = pmx_plgpio_30_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_30_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_31_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN3_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_31 = { + .name = "plgpio 31", + .modes = pmx_plgpio_31_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_31_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_32_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN4_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_32 = { + .name = "plgpio 32", + .modes = pmx_plgpio_32_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_32_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_33_modes[] = { + { + .ids = 0x00, + .mask = PMX_GPIO_PIN5_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_33 = { + .name = "plgpio 33", + .modes = pmx_plgpio_33_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_33_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_34_36_modes[] = { + { + .ids = 0x00, + .mask = PMX_SSP_CS_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_34_36 = { + .name = "plgpio 34 to 36", + .modes = pmx_plgpio_34_36_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_34_36_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_37_42_modes[] = { + { + .ids = 0x00, + .mask = PMX_UART0_MODEM_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_37_42 = { + .name = "plgpio 37 to 42", + .modes = pmx_plgpio_37_42_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_37_42_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_43_44_47_48_modes[] = { + { + .ids = 0x00, + .mask = PMX_TIMER_1_2_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_43_44_47_48 = { + .name = "plgpio 43, 44, 47 and 48", + .modes = pmx_plgpio_43_44_47_48_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_43_44_47_48_modes), + .enb_on_reset = 1, +}; + +struct pmx_dev_mode pmx_plgpio_45_46_49_50_modes[] = { + { + .ids = 0x00, + .mask = PMX_TIMER_3_4_MASK, + }, +}; + +struct pmx_dev pmx_plgpio_45_46_49_50 = { + .name = "plgpio 45, 46, 49 and 50", + .modes = pmx_plgpio_45_46_49_50_modes, + .mode_count = ARRAY_SIZE(pmx_plgpio_45_46_49_50_modes), + .enb_on_reset = 1, +}; + +#endif + +/* spear padmux initialization function */ +void spear_pmx_init(struct pmx_driver *pmx_driver, uint base, uint size) +{ + int ret = 0; + + /* pad mux initialization */ + pmx_driver->base = ioremap(base, size); + if (!pmx_driver->base) { + ret = -ENOMEM; + goto pmx_fail; + } + + ret = pmx_register(pmx_driver); + iounmap(pmx_driver->base); + +pmx_fail: + if (ret) + printk(KERN_ERR "padmux: registeration failed. err no: %d\n", + ret); +} diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index 96f9ac3d4b81..6f4ad5e9462e 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile @@ -3,4 +3,4 @@ # # Common support -obj-y := clock.o time.o +obj-y := clock.o padmux.o time.o diff --git a/arch/arm/plat-spear/include/plat/padmux.h b/arch/arm/plat-spear/include/plat/padmux.h new file mode 100644 index 000000000000..877f3adcf610 --- /dev/null +++ b/arch/arm/plat-spear/include/plat/padmux.h @@ -0,0 +1,92 @@ +/* + * arch/arm/plat-spear/include/plat/padmux.h + * + * SPEAr platform specific gpio pads muxing file + * + * Copyright (C) 2009 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __PLAT_PADMUX_H +#define __PLAT_PADMUX_H + +#include + +/* + * struct pmx_reg: configuration structure for mode reg and mux reg + * + * offset: offset of mode reg + * mask: mask of mode reg + */ +struct pmx_reg { + u32 offset; + u32 mask; +}; + +/* + * struct pmx_dev_mode: configuration structure every group of modes of a device + * + * ids: all modes for this configuration + * mask: mask for supported mode + */ +struct pmx_dev_mode { + u32 ids; + u32 mask; +}; + +/* + * struct pmx_mode: mode definition structure + * + * name: mode name + * mask: mode mask + */ +struct pmx_mode { + char *name; + u32 id; + u32 mask; +}; + +/* + * struct pmx_dev: device definition structure + * + * name: device name + * modes: device configuration array for different modes supported + * mode_count: size of modes array + * is_active: is peripheral active/enabled + * enb_on_reset: if 1, mask bits to be cleared in reg otherwise to be set in reg + */ +struct pmx_dev { + char *name; + struct pmx_dev_mode *modes; + u8 mode_count; + bool is_active; + bool enb_on_reset; +}; + +/* + * struct pmx_driver: driver definition structure + * + * mode: mode to be set + * devs: array of pointer to pmx devices + * devs_count: ARRAY_SIZE of devs + * base: base address of soc config registers + * mode_reg: structure of mode config register + * mux_reg: structure of device mux config register + */ +struct pmx_driver { + struct pmx_mode *mode; + struct pmx_dev **devs; + u8 devs_count; + u32 *base; + struct pmx_reg mode_reg; + struct pmx_reg mux_reg; +}; + +/* pmx functions */ +int pmx_register(struct pmx_driver *driver); + +#endif /* __PLAT_PADMUX_H */ diff --git a/arch/arm/plat-spear/padmux.c b/arch/arm/plat-spear/padmux.c new file mode 100644 index 000000000000..d2aab3adcdeb --- /dev/null +++ b/arch/arm/plat-spear/padmux.c @@ -0,0 +1,164 @@ +/* + * arch/arm/plat-spear/include/plat/padmux.c + * + * SPEAr platform specific gpio pads muxing source file + * + * Copyright (C) 2009 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include + +/* + * struct pmx: pmx definition structure + * + * base: base address of configuration registers + * mode_reg: mode configurations + * mux_reg: muxing configurations + * active_mode: pointer to current active mode + */ +struct pmx { + u32 base; + struct pmx_reg mode_reg; + struct pmx_reg mux_reg; + struct pmx_mode *active_mode; +}; + +static struct pmx *pmx; + +/** + * pmx_mode_set - Enables an multiplexing mode + * @mode - pointer to pmx mode + * + * It will set mode of operation in hardware. + * Returns -ve on Err otherwise 0 + */ +static int pmx_mode_set(struct pmx_mode *mode) +{ + u32 val; + + if (!mode->name) + return -EFAULT; + + pmx->active_mode = mode; + + val = readl(pmx->base + pmx->mode_reg.offset); + val &= ~pmx->mode_reg.mask; + val |= mode->mask & pmx->mode_reg.mask; + writel(val, pmx->base + pmx->mode_reg.offset); + + return 0; +} + +/** + * pmx_devs_enable - Enables list of devices + * @devs - pointer to pmx device array + * @count - number of devices to enable + * + * It will enable pads for all required peripherals once and only once. + * If peripheral is not supported by current mode then request is rejected. + * Conflicts between peripherals are not handled and peripherals will be + * enabled in the order they are present in pmx_dev array. + * In case of conflicts last peripheral enalbed will be present. + * Returns -ve on Err otherwise 0 + */ +static int pmx_devs_enable(struct pmx_dev **devs, u8 count) +{ + u32 val, i, mask; + + if (!count) + return -EINVAL; + + val = readl(pmx->base + pmx->mux_reg.offset); + for (i = 0; i < count; i++) { + u8 j = 0; + + if (!devs[i]->name || !devs[i]->modes) { + printk(KERN_ERR "padmux: dev name or modes is null\n"); + continue; + } + /* check if peripheral exists in active mode */ + if (pmx->active_mode) { + bool found = false; + for (j = 0; j < devs[i]->mode_count; j++) { + if (devs[i]->modes[j].ids & + pmx->active_mode->id) { + found = true; + break; + } + } + if (found == false) { + printk(KERN_ERR "%s device not available in %s"\ + "mode\n", devs[i]->name, + pmx->active_mode->name); + continue; + } + } + + /* enable peripheral */ + mask = devs[i]->modes[j].mask & pmx->mux_reg.mask; + if (devs[i]->enb_on_reset) + val &= ~mask; + else + val |= mask; + + devs[i]->is_active = true; + } + writel(val, pmx->base + pmx->mux_reg.offset); + kfree(pmx); + + /* this will ensure that multiplexing can't be changed now */ + pmx = (struct pmx *)-1; + + return 0; +} + +/** + * pmx_register - registers a platform requesting pad mux feature + * @driver - pointer to driver structure containing driver specific parameters + * + * Also this must be called only once. This will allocate memory for pmx + * structure, will call pmx_mode_set, will call pmx_devs_enable. + * Returns -ve on Err otherwise 0 + */ +int pmx_register(struct pmx_driver *driver) +{ + int ret = 0; + + if (pmx) + return -EPERM; + if (!driver->base || !driver->devs) + return -EFAULT; + + pmx = kzalloc(sizeof(*pmx), GFP_KERNEL); + if (!pmx) + return -ENOMEM; + + pmx->base = (u32)driver->base; + pmx->mode_reg.offset = driver->mode_reg.offset; + pmx->mode_reg.mask = driver->mode_reg.mask; + pmx->mux_reg.offset = driver->mux_reg.offset; + pmx->mux_reg.mask = driver->mux_reg.mask; + + /* choose mode to enable */ + if (driver->mode) { + ret = pmx_mode_set(driver->mode); + if (ret) + goto pmx_fail; + } + ret = pmx_devs_enable(driver->devs, driver->devs_count); + if (ret) + goto pmx_fail; + + return 0; + +pmx_fail: + return ret; +} -- cgit v1.2.3 From 4c18e77f718cdda33363132127db4df795eadbd9 Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Mon, 3 May 2010 09:24:30 +0100 Subject: ARM: 6091/1: ST SPEAr: Adding support for shared irq layer Multiple peripherals in SPEAr share common hardware interrupt lines. This patch adds support for a shared irq layer, which registers hardware irqs by itself and exposes virtual irq numbers to peripherals. Signed-off-by: Viresh Kumar Signed-off-by: Russell King --- arch/arm/mach-spear3xx/include/mach/irqs.h | 101 +++++++++++++++-- arch/arm/mach-spear3xx/include/mach/spear300.h | 16 +++ arch/arm/mach-spear3xx/include/mach/spear310.h | 24 ++++ arch/arm/mach-spear3xx/include/mach/spear320.h | 26 +++++ arch/arm/mach-spear3xx/spear300.c | 67 ++++++++++- arch/arm/mach-spear3xx/spear310.c | 148 ++++++++++++++++++++++++ arch/arm/mach-spear3xx/spear320.c | 150 +++++++++++++++++++++++++ arch/arm/mach-spear6xx/include/mach/irqs.h | 1 + arch/arm/plat-spear/Makefile | 2 + arch/arm/plat-spear/include/plat/shirq.h | 73 ++++++++++++ arch/arm/plat-spear/shirq.c | 118 +++++++++++++++++++ 11 files changed, 718 insertions(+), 8 deletions(-) create mode 100644 arch/arm/plat-spear/include/plat/shirq.h create mode 100644 arch/arm/plat-spear/shirq.c (limited to 'arch/arm/plat-spear/Makefile') diff --git a/arch/arm/mach-spear3xx/include/mach/irqs.h b/arch/arm/mach-spear3xx/include/mach/irqs.h index fe980e07b6ab..7f940b818473 100644 --- a/arch/arm/mach-spear3xx/include/mach/irqs.h +++ b/arch/arm/mach-spear3xx/include/mach/irqs.h @@ -14,7 +14,7 @@ #ifndef __MACH_IRQS_H #define __MACH_IRQS_H -/* IRQ definitions */ +/* SPEAr3xx IRQ definitions */ #define IRQ_HW_ACCEL_MOD_0 0 #define IRQ_INTRCOMM_RAS_ARM 1 #define IRQ_CPU_GPT1_1 2 @@ -50,16 +50,103 @@ #define IRQ_HW_ACCEL_MOD_1 31 #define IRQ_VIC_END 32 -#define SPEAR_GPIO_INT_BASE IRQ_VIC_END +#define VIRQ_START IRQ_VIC_END +/* SPEAr300 Virtual irq definitions */ #ifdef CONFIG_MACH_SPEAR300 -#define SPEAR_GPIO1_INT_BASE (SPEAR_GPIO_INT_BASE + 8) -#define SPEAR_GPIO_INT_END (SPEAR_GPIO1_INT_BASE + 8) +/* IRQs sharing IRQ_GEN_RAS_1 */ +#define VIRQ_IT_PERS_S (VIRQ_START + 0) +#define VIRQ_IT_CHANGE_S (VIRQ_START + 1) +#define VIRQ_I2S (VIRQ_START + 2) +#define VIRQ_TDM (VIRQ_START + 3) +#define VIRQ_CAMERA_L (VIRQ_START + 4) +#define VIRQ_CAMERA_F (VIRQ_START + 5) +#define VIRQ_CAMERA_V (VIRQ_START + 6) +#define VIRQ_KEYBOARD (VIRQ_START + 7) +#define VIRQ_GPIO1 (VIRQ_START + 8) + +/* IRQs sharing IRQ_GEN_RAS_3 */ +#define IRQ_CLCD IRQ_GEN_RAS_3 + +/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ +#define IRQ_SDIO IRQ_INTRCOMM_RAS_ARM + +/* GPIO pins virtual irqs */ +#define SPEAR_GPIO_INT_BASE (VIRQ_START + 9) +#define SPEAR_GPIO1_INT_BASE (SPEAR_GPIO_INT_BASE + 8) +#define SPEAR_GPIO_INT_END (SPEAR_GPIO1_INT_BASE + 8) + +/* SPEAr310 Virtual irq definitions */ +#elif defined(CONFIG_MACH_SPEAR310) +/* IRQs sharing IRQ_GEN_RAS_1 */ +#define VIRQ_SMII0 (VIRQ_START + 0) +#define VIRQ_SMII1 (VIRQ_START + 1) +#define VIRQ_SMII2 (VIRQ_START + 2) +#define VIRQ_SMII3 (VIRQ_START + 3) +#define VIRQ_WAKEUP_SMII0 (VIRQ_START + 4) +#define VIRQ_WAKEUP_SMII1 (VIRQ_START + 5) +#define VIRQ_WAKEUP_SMII2 (VIRQ_START + 6) +#define VIRQ_WAKEUP_SMII3 (VIRQ_START + 7) + +/* IRQs sharing IRQ_GEN_RAS_2 */ +#define VIRQ_UART1 (VIRQ_START + 8) +#define VIRQ_UART2 (VIRQ_START + 9) +#define VIRQ_UART3 (VIRQ_START + 10) +#define VIRQ_UART4 (VIRQ_START + 11) +#define VIRQ_UART5 (VIRQ_START + 12) + +/* IRQs sharing IRQ_GEN_RAS_3 */ +#define VIRQ_EMI (VIRQ_START + 13) +#define VIRQ_PLGPIO (VIRQ_START + 14) + +/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ +#define VIRQ_TDM_HDLC (VIRQ_START + 15) +#define VIRQ_RS485_0 (VIRQ_START + 16) +#define VIRQ_RS485_1 (VIRQ_START + 17) + +/* GPIO pins virtual irqs */ +#define SPEAR_GPIO_INT_BASE (VIRQ_START + 18) + +/* SPEAr320 Virtual irq definitions */ #else -#define SPEAR_GPIO_INT_END (SPEAR_GPIO_INT_BASE + 8) +/* IRQs sharing IRQ_GEN_RAS_1 */ +#define VIRQ_EMI (VIRQ_START + 0) +#define VIRQ_CLCD (VIRQ_START + 1) +#define VIRQ_SPP (VIRQ_START + 2) + +/* IRQs sharing IRQ_GEN_RAS_2 */ +#define IRQ_SDIO IRQ_GEN_RAS_2 + +/* IRQs sharing IRQ_GEN_RAS_3 */ +#define VIRQ_PLGPIO (VIRQ_START + 3) +#define VIRQ_I2S_PLAY (VIRQ_START + 4) +#define VIRQ_I2S_REC (VIRQ_START + 5) + +/* IRQs sharing IRQ_INTRCOMM_RAS_ARM */ +#define VIRQ_CANU (VIRQ_START + 6) +#define VIRQ_CANL (VIRQ_START + 7) +#define VIRQ_UART1 (VIRQ_START + 8) +#define VIRQ_UART2 (VIRQ_START + 9) +#define VIRQ_SSP1 (VIRQ_START + 10) +#define VIRQ_SSP2 (VIRQ_START + 11) +#define VIRQ_SMII0 (VIRQ_START + 12) +#define VIRQ_MII1_SMII1 (VIRQ_START + 13) +#define VIRQ_WAKEUP_SMII0 (VIRQ_START + 14) +#define VIRQ_WAKEUP_MII1_SMII1 (VIRQ_START + 15) +#define VIRQ_I2C (VIRQ_START + 16) + +/* GPIO pins virtual irqs */ +#define SPEAR_GPIO_INT_BASE (VIRQ_START + 17) + +#endif + +/* PLGPIO Virtual IRQs */ +#if defined(CONFIG_MACH_SPEAR310) || defined(CONFIG_MACH_SPEAR320) +#define SPEAR_PLGPIO_INT_BASE (SPEAR_GPIO_INT_BASE + 8) +#define SPEAR_GPIO_INT_END (SPEAR_PLGPIO_INT_BASE + 102) #endif -#define VIRTUAL_IRQS (SPEAR_GPIO_INT_END - IRQ_VIC_END) -#define NR_IRQS (IRQ_VIC_END + VIRTUAL_IRQS) +#define VIRQ_END SPEAR_GPIO_INT_END +#define NR_IRQS VIRQ_END #endif /* __MACH_IRQS_H */ diff --git a/arch/arm/mach-spear3xx/include/mach/spear300.h b/arch/arm/mach-spear3xx/include/mach/spear300.h index 40c16f385cfa..ccaa76522ee2 100644 --- a/arch/arm/mach-spear3xx/include/mach/spear300.h +++ b/arch/arm/mach-spear3xx/include/mach/spear300.h @@ -20,6 +20,22 @@ #define SPEAR300_TELECOM_BASE 0x50000000 #define SPEAR300_TELECOM_SIZE 0x10000000 +/* Interrupt registers offsets and masks */ +#define SPEAR300_TELECOM_REG_SIZE 0x00010000 +#define INT_ENB_MASK_REG 0x54 +#define INT_STS_MASK_REG 0x58 +#define IT_PERS_S_IRQ_MASK (1 << 0) +#define IT_CHANGE_S_IRQ_MASK (1 << 1) +#define I2S_IRQ_MASK (1 << 2) +#define TDM_IRQ_MASK (1 << 3) +#define CAMERA_L_IRQ_MASK (1 << 4) +#define CAMERA_F_IRQ_MASK (1 << 5) +#define CAMERA_V_IRQ_MASK (1 << 6) +#define KEYBOARD_IRQ_MASK (1 << 7) +#define GPIO1_IRQ_MASK (1 << 8) + +#define SHIRQ_RAS1_MASK 0x1FF + #define SPEAR300_CLCD_BASE 0x60000000 #define SPEAR300_CLCD_SIZE 0x10000000 diff --git a/arch/arm/mach-spear3xx/include/mach/spear310.h b/arch/arm/mach-spear3xx/include/mach/spear310.h index d4f58d6469d9..b27bb8af3309 100644 --- a/arch/arm/mach-spear3xx/include/mach/spear310.h +++ b/arch/arm/mach-spear3xx/include/mach/spear310.h @@ -40,6 +40,30 @@ #define SPEAR310_SOC_CONFIG_BASE 0xB4000000 #define SPEAR310_SOC_CONFIG_SIZE 0x00000070 +/* Interrupt registers offsets and masks */ +#define INT_STS_MASK_REG 0x04 +#define SMII0_IRQ_MASK (1 << 0) +#define SMII1_IRQ_MASK (1 << 1) +#define SMII2_IRQ_MASK (1 << 2) +#define SMII3_IRQ_MASK (1 << 3) +#define WAKEUP_SMII0_IRQ_MASK (1 << 4) +#define WAKEUP_SMII1_IRQ_MASK (1 << 5) +#define WAKEUP_SMII2_IRQ_MASK (1 << 6) +#define WAKEUP_SMII3_IRQ_MASK (1 << 7) +#define UART1_IRQ_MASK (1 << 8) +#define UART2_IRQ_MASK (1 << 9) +#define UART3_IRQ_MASK (1 << 10) +#define UART4_IRQ_MASK (1 << 11) +#define UART5_IRQ_MASK (1 << 12) +#define EMI_IRQ_MASK (1 << 13) +#define TDM_HDLC_IRQ_MASK (1 << 14) +#define RS485_0_IRQ_MASK (1 << 15) +#define RS485_1_IRQ_MASK (1 << 16) + +#define SHIRQ_RAS1_MASK 0x000FF +#define SHIRQ_RAS2_MASK 0x01F00 +#define SHIRQ_RAS3_MASK 0x02000 +#define SHIRQ_INTRCOMM_RAS_MASK 0x1C000 #endif /* __MACH_SPEAR310_H */ diff --git a/arch/arm/mach-spear3xx/include/mach/spear320.h b/arch/arm/mach-spear3xx/include/mach/spear320.h index e8ad2ed82e24..cacf17a958cd 100644 --- a/arch/arm/mach-spear3xx/include/mach/spear320.h +++ b/arch/arm/mach-spear3xx/include/mach/spear320.h @@ -64,6 +64,32 @@ #define SPEAR320_SOC_CONFIG_BASE 0xB4000000 #define SPEAR320_SOC_CONFIG_SIZE 0x00000070 +/* Interrupt registers offsets and masks */ +#define INT_STS_MASK_REG 0x04 +#define INT_CLR_MASK_REG 0x04 +#define INT_ENB_MASK_REG 0x08 +#define GPIO_IRQ_MASK (1 << 0) +#define I2S_PLAY_IRQ_MASK (1 << 1) +#define I2S_REC_IRQ_MASK (1 << 2) +#define EMI_IRQ_MASK (1 << 7) +#define CLCD_IRQ_MASK (1 << 8) +#define SPP_IRQ_MASK (1 << 9) +#define SDIO_IRQ_MASK (1 << 10) +#define CAN_U_IRQ_MASK (1 << 11) +#define CAN_L_IRQ_MASK (1 << 12) +#define UART1_IRQ_MASK (1 << 13) +#define UART2_IRQ_MASK (1 << 14) +#define SSP1_IRQ_MASK (1 << 15) +#define SSP2_IRQ_MASK (1 << 16) +#define SMII0_IRQ_MASK (1 << 17) +#define MII1_SMII1_IRQ_MASK (1 << 18) +#define WAKEUP_SMII0_IRQ_MASK (1 << 19) +#define WAKEUP_MII1_SMII1_IRQ_MASK (1 << 20) +#define I2C1_IRQ_MASK (1 << 21) + +#define SHIRQ_RAS1_MASK 0x000380 +#define SHIRQ_RAS3_MASK 0x000007 +#define SHIRQ_INTRCOMM_RAS_MASK 0x3FF800 #endif /* __MACH_SPEAR320_H */ diff --git a/arch/arm/mach-spear3xx/spear300.c b/arch/arm/mach-spear3xx/spear300.c index 66e7fcd8baf8..3560f8c1e723 100644 --- a/arch/arm/mach-spear3xx/spear300.c +++ b/arch/arm/mach-spear3xx/spear300.c @@ -17,6 +17,7 @@ #include #include #include +#include /* pad multiplexing support */ /* muxing registers */ @@ -386,14 +387,78 @@ struct amba_device gpio1_device = { .end = SPEAR300_GPIO_BASE + SPEAR300_GPIO_SIZE - 1, .flags = IORESOURCE_MEM, }, - .irq = {IRQ_GEN_RAS_1, NO_IRQ}, + .irq = {VIRQ_GPIO1, NO_IRQ}, +}; + +/* spear3xx shared irq */ +struct shirq_dev_config shirq_ras1_config[] = { + { + .virq = VIRQ_IT_PERS_S, + .enb_mask = IT_PERS_S_IRQ_MASK, + .status_mask = IT_PERS_S_IRQ_MASK, + }, { + .virq = VIRQ_IT_CHANGE_S, + .enb_mask = IT_CHANGE_S_IRQ_MASK, + .status_mask = IT_CHANGE_S_IRQ_MASK, + }, { + .virq = VIRQ_I2S, + .enb_mask = I2S_IRQ_MASK, + .status_mask = I2S_IRQ_MASK, + }, { + .virq = VIRQ_TDM, + .enb_mask = TDM_IRQ_MASK, + .status_mask = TDM_IRQ_MASK, + }, { + .virq = VIRQ_CAMERA_L, + .enb_mask = CAMERA_L_IRQ_MASK, + .status_mask = CAMERA_L_IRQ_MASK, + }, { + .virq = VIRQ_CAMERA_F, + .enb_mask = CAMERA_F_IRQ_MASK, + .status_mask = CAMERA_F_IRQ_MASK, + }, { + .virq = VIRQ_CAMERA_V, + .enb_mask = CAMERA_V_IRQ_MASK, + .status_mask = CAMERA_V_IRQ_MASK, + }, { + .virq = VIRQ_KEYBOARD, + .enb_mask = KEYBOARD_IRQ_MASK, + .status_mask = KEYBOARD_IRQ_MASK, + }, { + .virq = VIRQ_GPIO1, + .enb_mask = GPIO1_IRQ_MASK, + .status_mask = GPIO1_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras1 = { + .irq = IRQ_GEN_RAS_1, + .dev_config = shirq_ras1_config, + .dev_count = ARRAY_SIZE(shirq_ras1_config), + .regs = { + .enb_reg = INT_ENB_MASK_REG, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS1_MASK, + .clear_reg = -1, + }, }; /* spear300 routines */ void __init spear300_init(void) { + int ret = 0; + /* call spear3xx family common init function */ spear3xx_init(); + + /* shared irq registeration */ + shirq_ras1.regs.base = + ioremap(SPEAR300_TELECOM_BASE, SPEAR300_TELECOM_REG_SIZE); + if (shirq_ras1.regs.base) { + ret = spear_shirq_register(&shirq_ras1); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ\n"); + } } void spear300_pmx_init(void) diff --git a/arch/arm/mach-spear3xx/spear310.c b/arch/arm/mach-spear3xx/spear310.c index dd5a57282711..96a1ab824bac 100644 --- a/arch/arm/mach-spear3xx/spear310.c +++ b/arch/arm/mach-spear3xx/spear310.c @@ -15,6 +15,7 @@ #include #include #include +#include /* pad multiplexing support */ /* muxing registers */ @@ -140,11 +141,158 @@ struct pmx_driver pmx_driver = { /* Add spear310 specific devices here */ +/* spear3xx shared irq */ +struct shirq_dev_config shirq_ras1_config[] = { + { + .virq = VIRQ_SMII0, + .status_mask = SMII0_IRQ_MASK, + }, { + .virq = VIRQ_SMII1, + .status_mask = SMII1_IRQ_MASK, + }, { + .virq = VIRQ_SMII2, + .status_mask = SMII2_IRQ_MASK, + }, { + .virq = VIRQ_SMII3, + .status_mask = SMII3_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_SMII0, + .status_mask = WAKEUP_SMII0_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_SMII1, + .status_mask = WAKEUP_SMII1_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_SMII2, + .status_mask = WAKEUP_SMII2_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_SMII3, + .status_mask = WAKEUP_SMII3_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras1 = { + .irq = IRQ_GEN_RAS_1, + .dev_config = shirq_ras1_config, + .dev_count = ARRAY_SIZE(shirq_ras1_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS1_MASK, + .clear_reg = -1, + }, +}; + +struct shirq_dev_config shirq_ras2_config[] = { + { + .virq = VIRQ_UART1, + .status_mask = UART1_IRQ_MASK, + }, { + .virq = VIRQ_UART2, + .status_mask = UART2_IRQ_MASK, + }, { + .virq = VIRQ_UART3, + .status_mask = UART3_IRQ_MASK, + }, { + .virq = VIRQ_UART4, + .status_mask = UART4_IRQ_MASK, + }, { + .virq = VIRQ_UART5, + .status_mask = UART5_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras2 = { + .irq = IRQ_GEN_RAS_2, + .dev_config = shirq_ras2_config, + .dev_count = ARRAY_SIZE(shirq_ras2_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS2_MASK, + .clear_reg = -1, + }, +}; + +struct shirq_dev_config shirq_ras3_config[] = { + { + .virq = VIRQ_EMI, + .status_mask = EMI_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras3 = { + .irq = IRQ_GEN_RAS_3, + .dev_config = shirq_ras3_config, + .dev_count = ARRAY_SIZE(shirq_ras3_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS3_MASK, + .clear_reg = -1, + }, +}; + +struct shirq_dev_config shirq_intrcomm_ras_config[] = { + { + .virq = VIRQ_TDM_HDLC, + .status_mask = TDM_HDLC_IRQ_MASK, + }, { + .virq = VIRQ_RS485_0, + .status_mask = RS485_0_IRQ_MASK, + }, { + .virq = VIRQ_RS485_1, + .status_mask = RS485_1_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_intrcomm_ras = { + .irq = IRQ_INTRCOMM_RAS_ARM, + .dev_config = shirq_intrcomm_ras_config, + .dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK, + .clear_reg = -1, + }, +}; + /* spear310 routines */ void __init spear310_init(void) { + void __iomem *base; + int ret = 0; + /* call spear3xx family common init function */ spear3xx_init(); + + /* shared irq registeration */ + base = ioremap(SPEAR310_SOC_CONFIG_BASE, SPEAR310_SOC_CONFIG_SIZE); + if (base) { + /* shirq 1 */ + shirq_ras1.regs.base = base; + ret = spear_shirq_register(&shirq_ras1); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 1\n"); + + /* shirq 2 */ + shirq_ras2.regs.base = base; + ret = spear_shirq_register(&shirq_ras2); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 2\n"); + + /* shirq 3 */ + shirq_ras3.regs.base = base; + ret = spear_shirq_register(&shirq_ras3); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 3\n"); + + /* shirq 4 */ + shirq_intrcomm_ras.regs.base = base; + ret = spear_shirq_register(&shirq_intrcomm_ras); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 4\n"); + } } void spear310_pmx_init(void) diff --git a/arch/arm/mach-spear3xx/spear320.c b/arch/arm/mach-spear3xx/spear320.c index 2cedf5eb9ec9..6a1219549369 100644 --- a/arch/arm/mach-spear3xx/spear320.c +++ b/arch/arm/mach-spear3xx/spear320.c @@ -15,6 +15,7 @@ #include #include #include +#include /* pad multiplexing support */ /* muxing registers */ @@ -385,11 +386,160 @@ struct pmx_driver pmx_driver = { /* Add spear320 specific devices here */ +/* spear3xx shared irq */ +struct shirq_dev_config shirq_ras1_config[] = { + { + .virq = VIRQ_EMI, + .status_mask = EMI_IRQ_MASK, + .clear_mask = EMI_IRQ_MASK, + }, { + .virq = VIRQ_CLCD, + .status_mask = CLCD_IRQ_MASK, + .clear_mask = CLCD_IRQ_MASK, + }, { + .virq = VIRQ_SPP, + .status_mask = SPP_IRQ_MASK, + .clear_mask = SPP_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras1 = { + .irq = IRQ_GEN_RAS_1, + .dev_config = shirq_ras1_config, + .dev_count = ARRAY_SIZE(shirq_ras1_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS1_MASK, + .clear_reg = INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +struct shirq_dev_config shirq_ras3_config[] = { + { + .virq = VIRQ_PLGPIO, + .enb_mask = GPIO_IRQ_MASK, + .status_mask = GPIO_IRQ_MASK, + .clear_mask = GPIO_IRQ_MASK, + }, { + .virq = VIRQ_I2S_PLAY, + .enb_mask = I2S_PLAY_IRQ_MASK, + .status_mask = I2S_PLAY_IRQ_MASK, + .clear_mask = I2S_PLAY_IRQ_MASK, + }, { + .virq = VIRQ_I2S_REC, + .enb_mask = I2S_REC_IRQ_MASK, + .status_mask = I2S_REC_IRQ_MASK, + .clear_mask = I2S_REC_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_ras3 = { + .irq = IRQ_GEN_RAS_3, + .dev_config = shirq_ras3_config, + .dev_count = ARRAY_SIZE(shirq_ras3_config), + .regs = { + .enb_reg = INT_ENB_MASK_REG, + .reset_to_enb = 1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_RAS3_MASK, + .clear_reg = INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + +struct shirq_dev_config shirq_intrcomm_ras_config[] = { + { + .virq = VIRQ_CANU, + .status_mask = CAN_U_IRQ_MASK, + .clear_mask = CAN_U_IRQ_MASK, + }, { + .virq = VIRQ_CANL, + .status_mask = CAN_L_IRQ_MASK, + .clear_mask = CAN_L_IRQ_MASK, + }, { + .virq = VIRQ_UART1, + .status_mask = UART1_IRQ_MASK, + .clear_mask = UART1_IRQ_MASK, + }, { + .virq = VIRQ_UART2, + .status_mask = UART2_IRQ_MASK, + .clear_mask = UART2_IRQ_MASK, + }, { + .virq = VIRQ_SSP1, + .status_mask = SSP1_IRQ_MASK, + .clear_mask = SSP1_IRQ_MASK, + }, { + .virq = VIRQ_SSP2, + .status_mask = SSP2_IRQ_MASK, + .clear_mask = SSP2_IRQ_MASK, + }, { + .virq = VIRQ_SMII0, + .status_mask = SMII0_IRQ_MASK, + .clear_mask = SMII0_IRQ_MASK, + }, { + .virq = VIRQ_MII1_SMII1, + .status_mask = MII1_SMII1_IRQ_MASK, + .clear_mask = MII1_SMII1_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_SMII0, + .status_mask = WAKEUP_SMII0_IRQ_MASK, + .clear_mask = WAKEUP_SMII0_IRQ_MASK, + }, { + .virq = VIRQ_WAKEUP_MII1_SMII1, + .status_mask = WAKEUP_MII1_SMII1_IRQ_MASK, + .clear_mask = WAKEUP_MII1_SMII1_IRQ_MASK, + }, { + .virq = VIRQ_I2C, + .status_mask = I2C1_IRQ_MASK, + .clear_mask = I2C1_IRQ_MASK, + }, +}; + +struct spear_shirq shirq_intrcomm_ras = { + .irq = IRQ_INTRCOMM_RAS_ARM, + .dev_config = shirq_intrcomm_ras_config, + .dev_count = ARRAY_SIZE(shirq_intrcomm_ras_config), + .regs = { + .enb_reg = -1, + .status_reg = INT_STS_MASK_REG, + .status_reg_mask = SHIRQ_INTRCOMM_RAS_MASK, + .clear_reg = INT_CLR_MASK_REG, + .reset_to_clear = 1, + }, +}; + /* spear320 routines */ void __init spear320_init(void) { + void __iomem *base; + int ret = 0; + /* call spear3xx family common init function */ spear3xx_init(); + + /* shared irq registeration */ + base = ioremap(SPEAR320_SOC_CONFIG_BASE, SPEAR320_SOC_CONFIG_SIZE); + if (base) { + /* shirq 1 */ + shirq_ras1.regs.base = base; + ret = spear_shirq_register(&shirq_ras1); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 1\n"); + + /* shirq 3 */ + shirq_ras3.regs.base = base; + ret = spear_shirq_register(&shirq_ras3); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 3\n"); + + /* shirq 4 */ + shirq_intrcomm_ras.regs.base = base; + ret = spear_shirq_register(&shirq_intrcomm_ras); + if (ret) + printk(KERN_ERR "Error registering Shared IRQ 4\n"); + } } void spear320_pmx_init(void) diff --git a/arch/arm/mach-spear6xx/include/mach/irqs.h b/arch/arm/mach-spear6xx/include/mach/irqs.h index 08a3abced750..8f214b03d75d 100644 --- a/arch/arm/mach-spear6xx/include/mach/irqs.h +++ b/arch/arm/mach-spear6xx/include/mach/irqs.h @@ -85,6 +85,7 @@ #define IRQ_VIC_END 64 +/* GPIO pins virtual irqs */ #define SPEAR_GPIO_INT_BASE IRQ_VIC_END #define SPEAR_GPIO0_INT_BASE SPEAR_GPIO_INT_BASE #define SPEAR_GPIO1_INT_BASE (SPEAR_GPIO0_INT_BASE + 8) diff --git a/arch/arm/plat-spear/Makefile b/arch/arm/plat-spear/Makefile index 6f4ad5e9462e..eb89540aeda9 100644 --- a/arch/arm/plat-spear/Makefile +++ b/arch/arm/plat-spear/Makefile @@ -4,3 +4,5 @@ # Common support obj-y := clock.o padmux.o time.o + +obj-$(CONFIG_ARCH_SPEAR3XX) += shirq.o diff --git a/arch/arm/plat-spear/include/plat/shirq.h b/arch/arm/plat-spear/include/plat/shirq.h new file mode 100644 index 000000000000..03ed8b585dcf --- /dev/null +++ b/arch/arm/plat-spear/include/plat/shirq.h @@ -0,0 +1,73 @@ +/* + * arch/arm/plat-spear/include/plat/shirq.h + * + * SPEAr platform shared irq layer header file + * + * Copyright (C) 2009 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#ifndef __PLAT_SHIRQ_H +#define __PLAT_SHIRQ_H + +#include +#include + +/* + * struct shirq_dev_config: shared irq device configuration + * + * virq: virtual irq number of device + * enb_mask: enable mask of device + * status_mask: status mask of device + * clear_mask: clear mask of device + */ +struct shirq_dev_config { + u32 virq; + u32 enb_mask; + u32 status_mask; + u32 clear_mask; +}; + +/* + * struct shirq_regs: shared irq register configuration + * + * base: base address of shared irq register + * enb_reg: enable register offset + * reset_to_enb: val 1 indicates, we need to clear bit for enabling interrupt + * status_reg: status register offset + * status_reg_mask: status register valid mask + * clear_reg: clear register offset + * reset_to_clear: val 1 indicates, we need to clear bit for clearing interrupt + */ +struct shirq_regs { + void __iomem *base; + u32 enb_reg; + u32 reset_to_enb; + u32 status_reg; + u32 status_reg_mask; + u32 clear_reg; + u32 reset_to_clear; +}; + +/* + * struct spear_shirq: shared irq structure + * + * irq: hardware irq number + * dev_config: array of device config structures which are using "irq" line + * dev_count: size of dev_config array + * regs: register configuration for shared irq block + */ +struct spear_shirq { + u32 irq; + struct shirq_dev_config *dev_config; + u32 dev_count; + struct shirq_regs regs; +}; + +int spear_shirq_register(struct spear_shirq *shirq); + +#endif /* __PLAT_SHIRQ_H */ diff --git a/arch/arm/plat-spear/shirq.c b/arch/arm/plat-spear/shirq.c new file mode 100644 index 000000000000..2172d6946aea --- /dev/null +++ b/arch/arm/plat-spear/shirq.c @@ -0,0 +1,118 @@ +/* + * arch/arm/plat-spear/shirq.c + * + * SPEAr platform shared irq layer source file + * + * Copyright (C) 2009 ST Microelectronics + * Viresh Kumar + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include + +struct spear_shirq *shirq; +static DEFINE_SPINLOCK(lock); + +static void shirq_irq_mask(unsigned irq) +{ + struct spear_shirq *shirq = get_irq_chip_data(irq); + u32 val, id = irq - shirq->dev_config[0].virq; + unsigned long flags; + + if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1) + return; + + spin_lock_irqsave(&lock, flags); + val = readl(shirq->regs.base + shirq->regs.enb_reg); + if (shirq->regs.reset_to_enb) + val |= shirq->dev_config[id].enb_mask; + else + val &= ~(shirq->dev_config[id].enb_mask); + writel(val, shirq->regs.base + shirq->regs.enb_reg); + spin_unlock_irqrestore(&lock, flags); +} + +static void shirq_irq_unmask(unsigned irq) +{ + struct spear_shirq *shirq = get_irq_chip_data(irq); + u32 val, id = irq - shirq->dev_config[0].virq; + unsigned long flags; + + if ((shirq->regs.enb_reg == -1) || shirq->dev_config[id].enb_mask == -1) + return; + + spin_lock_irqsave(&lock, flags); + val = readl(shirq->regs.base + shirq->regs.enb_reg); + if (shirq->regs.reset_to_enb) + val &= ~(shirq->dev_config[id].enb_mask); + else + val |= shirq->dev_config[id].enb_mask; + writel(val, shirq->regs.base + shirq->regs.enb_reg); + spin_unlock_irqrestore(&lock, flags); +} + +static struct irq_chip shirq_chip = { + .name = "spear_shirq", + .ack = shirq_irq_mask, + .mask = shirq_irq_mask, + .unmask = shirq_irq_unmask, +}; + +static void shirq_handler(unsigned irq, struct irq_desc *desc) +{ + u32 i, val, mask; + struct spear_shirq *shirq = get_irq_data(irq); + + desc->chip->ack(irq); + while ((val = readl(shirq->regs.base + shirq->regs.status_reg) & + shirq->regs.status_reg_mask)) { + for (i = 0; (i < shirq->dev_count) && val; i++) { + if (!(shirq->dev_config[i].status_mask & val)) + continue; + + generic_handle_irq(shirq->dev_config[i].virq); + + /* clear interrupt */ + val &= ~shirq->dev_config[i].status_mask; + if ((shirq->regs.clear_reg == -1) || + shirq->dev_config[i].clear_mask == -1) + continue; + mask = readl(shirq->regs.base + shirq->regs.clear_reg); + if (shirq->regs.reset_to_clear) + mask &= ~shirq->dev_config[i].clear_mask; + else + mask |= shirq->dev_config[i].clear_mask; + writel(mask, shirq->regs.base + shirq->regs.clear_reg); + } + } + desc->chip->unmask(irq); +} + +int spear_shirq_register(struct spear_shirq *shirq) +{ + int i; + + if (!shirq || !shirq->dev_config || !shirq->regs.base) + return -EFAULT; + + if (!shirq->dev_count) + return -EINVAL; + + set_irq_chained_handler(shirq->irq, shirq_handler); + for (i = 0; i < shirq->dev_count; i++) { + set_irq_chip(shirq->dev_config[i].virq, &shirq_chip); + set_irq_handler(shirq->dev_config[i].virq, handle_simple_irq); + set_irq_flags(shirq->dev_config[i].virq, IRQF_VALID); + set_irq_chip_data(shirq->dev_config[i].virq, shirq); + } + + set_irq_data(shirq->irq, shirq); + return 0; +} -- cgit v1.2.3