diff options
author | Rusty Russell <rusty@rustcorp.com.au> | 2008-12-31 23:05:57 +1030 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-12-31 23:05:57 +1030 |
commit | 2ca1a615835d9f4990f42102ab1f2ef434e7e89c (patch) | |
tree | 726cf3d5f29a6c66c44e4bd68e7ebed2fd83d059 /arch/arm/mach-omap2 | |
parent | e12f0102ac81d660c9f801d0a0e10ccf4537a9de (diff) | |
parent | 6a94cb73064c952255336cc57731904174b2c58f (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
Conflicts:
arch/x86/kernel/io_apic.c
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r-- | arch/arm/mach-omap2/Kconfig | 4 | ||||
-rw-r--r-- | arch/arm/mach-omap2/Makefile | 14 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-2430sdp.c | 52 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-apollon.c | 26 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-generic.c | 11 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-h4.c | 25 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-ldp.c | 97 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-omap3beagle.c | 90 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-omap3pandora.c | 212 | ||||
-rw-r--r-- | arch/arm/mach-omap2/board-overo.c | 43 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock24xx.h | 9 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.c | 2 | ||||
-rw-r--r-- | arch/arm/mach-omap2/clock34xx.h | 46 | ||||
-rw-r--r-- | arch/arm/mach-omap2/devices.c | 169 | ||||
-rw-r--r-- | arch/arm/mach-omap2/id.c | 305 | ||||
-rw-r--r-- | arch/arm/mach-omap2/irq.c | 39 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mmc-twl4030.c | 408 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mmc-twl4030.h | 29 | ||||
-rw-r--r-- | arch/arm/mach-omap2/mux.c | 44 | ||||
-rw-r--r-- | arch/arm/mach-omap2/usb-tusb6010.c | 6 |
20 files changed, 1376 insertions, 255 deletions
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig index 4832fcc7d04..3754b79092a 100644 --- a/arch/arm/mach-omap2/Kconfig +++ b/arch/arm/mach-omap2/Kconfig @@ -55,3 +55,7 @@ config MACH_OMAP_LDP config MACH_OVERO bool "Gumstix Overo board" depends on ARCH_OMAP3 && ARCH_OMAP34XX + +config MACH_OMAP3_PANDORA + bool "OMAP3 Pandora" + depends on ARCH_OMAP3 && ARCH_OMAP34XX
\ No newline at end of file diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile index c69392372c9..bbd12bc10fd 100644 --- a/arch/arm/mach-omap2/Makefile +++ b/arch/arm/mach-omap2/Makefile @@ -27,9 +27,15 @@ obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o # Specific board support obj-$(CONFIG_MACH_OMAP_GENERIC) += board-generic.o obj-$(CONFIG_MACH_OMAP_H4) += board-h4.o -obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o +obj-$(CONFIG_MACH_OMAP_2430SDP) += board-2430sdp.o \ + mmc-twl4030.o obj-$(CONFIG_MACH_OMAP_APOLLON) += board-apollon.o -obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o -obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o -obj-$(CONFIG_MACH_OVERO) += board-overo.o +obj-$(CONFIG_MACH_OMAP3_BEAGLE) += board-omap3beagle.o \ + mmc-twl4030.o +obj-$(CONFIG_MACH_OMAP_LDP) += board-ldp.o \ + mmc-twl4030.o +obj-$(CONFIG_MACH_OVERO) += board-overo.o \ + mmc-twl4030.o +obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o \ + mmc-twl4030.o diff --git a/arch/arm/mach-omap2/board-2430sdp.c b/arch/arm/mach-omap2/board-2430sdp.c index 24688efaa44..83fa37211d7 100644 --- a/arch/arm/mach-omap2/board-2430sdp.c +++ b/arch/arm/mach-omap2/board-2430sdp.c @@ -19,6 +19,7 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #include <linux/delay.h> +#include <linux/i2c/twl4030.h> #include <linux/err.h> #include <linux/clk.h> #include <linux/io.h> @@ -35,6 +36,7 @@ #include <mach/common.h> #include <mach/gpmc.h> +#include "mmc-twl4030.h" #define SDP2430_FLASH_CS 0 #define SDP2430_SMC91X_CS 5 @@ -168,13 +170,13 @@ static inline void __init sdp2430_init_smc91x(void) sdp2430_smc91x_resources[0].end = cs_mem_base + 0x30f; udelay(100); - if (omap_request_gpio(OMAP24XX_ETHR_GPIO_IRQ) < 0) { + if (gpio_request(OMAP24XX_ETHR_GPIO_IRQ, "SMC91x irq") < 0) { printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", OMAP24XX_ETHR_GPIO_IRQ); gpmc_cs_free(eth_cs); goto out; } - omap_set_gpio_direction(OMAP24XX_ETHR_GPIO_IRQ, 1); + gpio_direction_input(OMAP24XX_ETHR_GPIO_IRQ); out: clk_disable(gpmc_fck); @@ -197,12 +199,58 @@ static struct omap_board_config_kernel sdp2430_config[] = { {OMAP_TAG_UART, &sdp2430_uart_config}, }; + +static struct twl4030_gpio_platform_data sdp2430_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, +}; + +static struct twl4030_platform_data sdp2430_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &sdp2430_gpio_data, +}; + +static struct i2c_board_info __initdata sdp2430_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_24XX_SYS_NIRQ, + .platform_data = &sdp2430_twldata, + }, +}; + +static int __init omap2430_i2c_init(void) +{ + omap_register_i2c_bus(1, 400, NULL, 0); + omap_register_i2c_bus(2, 2600, sdp2430_i2c_boardinfo, + ARRAY_SIZE(sdp2430_i2c_boardinfo)); + return 0; +} + +static struct twl4030_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + .ext_clock = 1, + }, + {} /* Terminator */ +}; + static void __init omap_2430sdp_init(void) { + omap2430_i2c_init(); + platform_add_devices(sdp2430_devices, ARRAY_SIZE(sdp2430_devices)); omap_board_config = sdp2430_config; omap_board_config_size = ARRAY_SIZE(sdp2430_config); omap_serial_init(); + twl4030_mmc_init(mmc); } static void __init omap_2430sdp_map_io(void) diff --git a/arch/arm/mach-omap2/board-apollon.c b/arch/arm/mach-omap2/board-apollon.c index 989ad152d7f..bf1e5d32c2a 100644 --- a/arch/arm/mach-omap2/board-apollon.c +++ b/arch/arm/mach-omap2/board-apollon.c @@ -236,13 +236,13 @@ static inline void __init apollon_init_smc91x(void) udelay(100); omap_cfg_reg(W4__24XX_GPIO74); - if (omap_request_gpio(APOLLON_ETHR_GPIO_IRQ) < 0) { + if (gpio_request(APOLLON_ETHR_GPIO_IRQ, "SMC91x irq") < 0) { printk(KERN_ERR "Failed to request GPIO%d for smc91x IRQ\n", APOLLON_ETHR_GPIO_IRQ); gpmc_cs_free(APOLLON_ETH_CS); goto out; } - omap_set_gpio_direction(APOLLON_ETHR_GPIO_IRQ, 1); + gpio_direction_input(APOLLON_ETHR_GPIO_IRQ); out: clk_disable(gpmc_fck); @@ -261,16 +261,6 @@ static struct omap_uart_config apollon_uart_config __initdata = { .enabled_uarts = (1 << 0) | (0 << 1) | (0 << 2), }; -static struct omap_mmc_config apollon_mmc_config __initdata = { - .mmc [0] = { - .enabled = 1, - .wire4 = 1, - .wp_pin = -1, - .power_pin = -1, - .switch_pin = -1, - }, -}; - static struct omap_usb_config apollon_usb_config __initdata = { .register_dev = 1, .hmc_mode = 0x14, /* 0:dev 1:host1 2:disable */ @@ -284,7 +274,6 @@ static struct omap_lcd_config apollon_lcd_config __initdata = { static struct omap_board_config_kernel apollon_config[] = { { OMAP_TAG_UART, &apollon_uart_config }, - { OMAP_TAG_MMC, &apollon_mmc_config }, { OMAP_TAG_USB, &apollon_usb_config }, { OMAP_TAG_LCD, &apollon_lcd_config }, }; @@ -327,15 +316,15 @@ static void __init apollon_sw_init(void) /* Enter SW - Y11 */ omap_cfg_reg(Y11_242X_GPIO16); omap_request_gpio(SW_ENTER_GPIO16); - omap_set_gpio_direction(SW_ENTER_GPIO16, 1); + gpio_direction_input(SW_ENTER_GPIO16); /* Up SW - AA12 */ omap_cfg_reg(AA12_242X_GPIO17); omap_request_gpio(SW_UP_GPIO17); - omap_set_gpio_direction(SW_UP_GPIO17, 1); + gpio_direction_input(SW_UP_GPIO17); /* Down SW - AA8 */ omap_cfg_reg(AA8_242X_GPIO58); omap_request_gpio(SW_DOWN_GPIO58); - omap_set_gpio_direction(SW_DOWN_GPIO58, 1); + gpio_direction_input(SW_DOWN_GPIO58); set_irq_type(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), IRQ_TYPE_EDGE_RISING); if (request_irq(OMAP_GPIO_IRQ(SW_ENTER_GPIO16), &apollon_sw_interrupt, @@ -359,9 +348,8 @@ static void __init apollon_usb_init(void) /* USB device */ /* DEVICE_SUSPEND */ omap_cfg_reg(P21_242X_GPIO12); - omap_request_gpio(12); - omap_set_gpio_direction(12, 0); /* OUT */ - omap_set_gpio_dataout(12, 0); + gpio_request(12, "USB suspend"); + gpio_direction_output(12, 0); } static void __init omap_apollon_init(void) diff --git a/arch/arm/mach-omap2/board-generic.c b/arch/arm/mach-omap2/board-generic.c index 9ba097868e7..3b34c20d1df 100644 --- a/arch/arm/mach-omap2/board-generic.c +++ b/arch/arm/mach-omap2/board-generic.c @@ -41,19 +41,8 @@ static struct omap_uart_config generic_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; -static struct omap_mmc_config generic_mmc_config __initdata = { - .mmc [0] = { - .enabled = 0, - .wire4 = 0, - .wp_pin = -1, - .power_pin = -1, - .switch_pin = -1, - }, -}; - static struct omap_board_config_kernel generic_config[] = { { OMAP_TAG_UART, &generic_uart_config }, - { OMAP_TAG_MMC, &generic_mmc_config }, }; static void __init omap_generic_init(void) diff --git a/arch/arm/mach-omap2/board-h4.c b/arch/arm/mach-omap2/board-h4.c index 2fef2c84508..5e9b14675b1 100644 --- a/arch/arm/mach-omap2/board-h4.c +++ b/arch/arm/mach-omap2/board-h4.c @@ -19,6 +19,7 @@ #include <linux/delay.h> #include <linux/workqueue.h> #include <linux/i2c.h> +#include <linux/i2c/at24.h> #include <linux/input.h> #include <linux/err.h> #include <linux/clk.h> @@ -372,31 +373,33 @@ static struct omap_uart_config h4_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; -static struct omap_mmc_config h4_mmc_config __initdata = { - .mmc [0] = { - .enabled = 1, - .wire4 = 1, - .wp_pin = -1, - .power_pin = -1, - .switch_pin = -1, - }, -}; - static struct omap_lcd_config h4_lcd_config __initdata = { .ctrl_name = "internal", }; static struct omap_board_config_kernel h4_config[] = { { OMAP_TAG_UART, &h4_uart_config }, - { OMAP_TAG_MMC, &h4_mmc_config }, { OMAP_TAG_LCD, &h4_lcd_config }, }; +static struct at24_platform_data m24c01 = { + .byte_len = SZ_1K / 8, + .page_size = 16, +}; + static struct i2c_board_info __initdata h4_i2c_board_info[] = { { I2C_BOARD_INFO("isp1301_omap", 0x2d), .irq = OMAP_GPIO_IRQ(125), }, + { /* EEPROM on mainboard */ + I2C_BOARD_INFO("24c01", 0x52), + .platform_data = &m24c01, + }, + { /* EEPROM on cpu card */ + I2C_BOARD_INFO("24c01", 0x57), + .platform_data = &m24c01, + }, }; static void __init omap_h4_init(void) diff --git a/arch/arm/mach-omap2/board-ldp.c b/arch/arm/mach-omap2/board-ldp.c index 1ea59986aa7..aa6972781e4 100644 --- a/arch/arm/mach-omap2/board-ldp.c +++ b/arch/arm/mach-omap2/board-ldp.c @@ -21,6 +21,7 @@ #include <linux/clk.h> #include <linux/spi/spi.h> #include <linux/spi/ads7846.h> +#include <linux/i2c/twl4030.h> #include <mach/hardware.h> #include <asm/mach-types.h> @@ -38,11 +39,69 @@ #include <asm/delay.h> #include <mach/control.h> +#include "mmc-twl4030.h" + +#define SDP3430_SMC91X_CS 3 + +static struct resource ldp_smc911x_resources[] = { + [0] = { + .start = OMAP34XX_ETHR_START, + .end = OMAP34XX_ETHR_START + SZ_4K, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = 0, + .end = 0, + .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL, + }, +}; + +static struct platform_device ldp_smc911x_device = { + .name = "smc911x", + .id = -1, + .num_resources = ARRAY_SIZE(ldp_smc911x_resources), + .resource = ldp_smc911x_resources, +}; + +static struct platform_device *ldp_devices[] __initdata = { + &ldp_smc911x_device, +}; + +static inline void __init ldp_init_smc911x(void) +{ + int eth_cs; + unsigned long cs_mem_base; + int eth_gpio = 0; + + eth_cs = LDP_SMC911X_CS; + + if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) { + printk(KERN_ERR "Failed to request GPMC mem for smc911x\n"); + return; + } + + ldp_smc911x_resources[0].start = cs_mem_base + 0x0; + ldp_smc911x_resources[0].end = cs_mem_base + 0xf; + udelay(100); + + eth_gpio = LDP_SMC911X_GPIO; + + ldp_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio); + + if (omap_request_gpio(eth_gpio) < 0) { + printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n", + eth_gpio); + return; + } + gpio_direction_input(eth_gpio); +} + static void __init omap_ldp_init_irq(void) { omap2_init_common_hw(); omap_init_irq(); omap_gpio_init(); + ldp_init_smc911x(); } static struct omap_uart_config ldp_uart_config __initdata = { @@ -53,20 +112,56 @@ static struct omap_board_config_kernel ldp_config[] __initdata = { { OMAP_TAG_UART, &ldp_uart_config }, }; +static struct twl4030_gpio_platform_data ldp_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, +}; + +static struct twl4030_platform_data ldp_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &ldp_gpio_data, +}; + +static struct i2c_board_info __initdata ldp_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &ldp_twldata, + }, +}; + static int __init omap_i2c_init(void) { - omap_register_i2c_bus(1, 2600, NULL, 0); + omap_register_i2c_bus(1, 2600, ldp_i2c_boardinfo, + ARRAY_SIZE(ldp_i2c_boardinfo)); omap_register_i2c_bus(2, 400, NULL, 0); omap_register_i2c_bus(3, 400, NULL, 0); return 0; } +static struct twl4030_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + static void __init omap_ldp_init(void) { omap_i2c_init(); + platform_add_devices(ldp_devices, ARRAY_SIZE(ldp_devices)); omap_board_config = ldp_config; omap_board_config_size = ARRAY_SIZE(ldp_config); omap_serial_init(); + twl4030_mmc_init(mmc); } static void __init omap_ldp_map_io(void) diff --git a/arch/arm/mach-omap2/board-omap3beagle.c b/arch/arm/mach-omap2/board-omap3beagle.c index baa79674e9d..9e5ada01b5f 100644 --- a/arch/arm/mach-omap2/board-omap3beagle.c +++ b/arch/arm/mach-omap2/board-omap3beagle.c @@ -38,7 +38,9 @@ #include <mach/common.h> #include <mach/gpmc.h> #include <mach/nand.h> +#include <mach/mux.h> +#include "mmc-twl4030.h" #define GPMC_CS0_BASE 0x60 #define GPMC_CS_SIZE 0x30 @@ -103,6 +105,78 @@ static struct omap_uart_config omap3_beagle_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; +static struct twl4030_hsmmc_info mmc[] = { + { + .mmc = 1, + .wires = 8, + .gpio_wp = 29, + }, + {} /* Terminator */ +}; + +static struct gpio_led gpio_leds[]; + +static int beagle_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + /* gpio + 0 is "mmc0_cd" (input/IRQ) */ + + /* REVISIT: need ehci-omap hooks for external VBUS + * power switch and overcurrent detect + */ + + gpio_request(gpio + 1, "EHCI_nOC"); + gpio_direction_input(gpio + 1); + + /* TWL4030_GPIO_MAX + 0 == ledA, EHCI nEN_USB_PWR (out, active low) */ + gpio_request(gpio + TWL4030_GPIO_MAX, "nEN_USB_PWR"); + gpio_direction_output(gpio + TWL4030_GPIO_MAX, 1); + + /* TWL4030_GPIO_MAX + 1 == ledB, PMU_STAT (out, active low LED) */ + gpio_leds[2].gpio = gpio + TWL4030_GPIO_MAX + 1; + + return 0; +} + +static struct twl4030_gpio_platform_data beagle_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .use_leds = true, + .pullups = BIT(1), + .pulldowns = BIT(2) | BIT(6) | BIT(7) | BIT(8) | BIT(13) + | BIT(15) | BIT(16) | BIT(17), + .setup = beagle_twl_gpio_setup, +}; + +static struct twl4030_platform_data beagle_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + + /* platform_data for children goes here */ + .gpio = &beagle_gpio_data, +}; + +static struct i2c_board_info __initdata beagle_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &beagle_twldata, + }, +}; + +static int __init omap3_beagle_i2c_init(void) +{ + omap_register_i2c_bus(1, 2600, beagle_i2c_boardinfo, + ARRAY_SIZE(beagle_i2c_boardinfo)); +#ifdef CONFIG_I2C2_OMAP_BEAGLE + omap_register_i2c_bus(2, 400, NULL, 0); +#endif + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + static void __init omap3_beagle_init_irq(void) { omap2_init_common_hw(); @@ -130,6 +204,11 @@ static struct gpio_led gpio_leds[] = { .default_trigger = "mmc0", .gpio = 149, }, + { + .name = "beagleboard::pmu_stat", + .gpio = -EINVAL, /* gets replaced */ + .active_low = true, + }, }; static struct gpio_led_platform_data gpio_led_info = { @@ -218,11 +297,22 @@ static void __init omap3beagle_flash_init(void) static void __init omap3_beagle_init(void) { + omap3_beagle_i2c_init(); platform_add_devices(omap3_beagle_devices, ARRAY_SIZE(omap3_beagle_devices)); omap_board_config = omap3_beagle_config; omap_board_config_size = ARRAY_SIZE(omap3_beagle_config); omap_serial_init(); + + omap_cfg_reg(AH8_34XX_GPIO29); + mmc[0].gpio_cd = gpio + 0; + twl4030_mmc_init(mmc); + + omap_cfg_reg(J25_34XX_GPIO170); + gpio_request(170, "DVI_nPD"); + /* REVISIT leave DVI powered down until it's needed ... */ + gpio_direction_output(170, true); + omap3beagle_flash_init(); } diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c new file mode 100644 index 00000000000..b3196107afd --- /dev/null +++ b/arch/arm/mach-omap2/board-omap3pandora.c @@ -0,0 +1,212 @@ +/* + * board-omap3pandora.c (Pandora Handheld Console) + * + * 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. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/platform_device.h> + +#include <linux/spi/spi.h> +#include <linux/spi/ads7846.h> +#include <linux/i2c/twl4030.h> + +#include <asm/mach-types.h> +#include <asm/mach/arch.h> +#include <asm/mach/map.h> + +#include <mach/board.h> +#include <mach/common.h> +#include <mach/gpio.h> +#include <mach/hardware.h> +#include <mach/mcspi.h> + +#include "mmc-twl4030.h" + +#define OMAP3_PANDORA_TS_GPIO 94 + +static struct twl4030_hsmmc_info omap3pandora_mmc[] = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = 126, + .ext_clock = 0, + }, + { + .mmc = 2, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = 127, + .ext_clock = 1, + }, + {} /* Terminator */ +}; + +static struct omap_uart_config omap3pandora_uart_config __initdata = { + .enabled_uarts = (1 << 2), /* UART3 */ +}; + +static int omap3pandora_twl_gpio_setup(struct device *dev, + unsigned gpio, unsigned ngpio) +{ + /* gpio + {0,1} is "mmc{0,1}_cd" (input/IRQ) */ + omap3pandora_mmc[0].gpio_cd = gpio + 0; + omap3pandora_mmc[1].gpio_cd = gpio + 1; + twl4030_mmc_init(omap3pandora_mmc); + + return 0; +} + +static struct twl4030_gpio_platform_data omap3pandora_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, + .setup = omap3pandora_twl_gpio_setup, +}; + +static struct twl4030_usb_data omap3pandora_usb_data = { + .usb_mode = T2_USB_MODE_ULPI, +}; + +static struct twl4030_platform_data omap3pandora_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + .gpio = &omap3pandora_gpio_data, + .usb = &omap3pandora_usb_data, +}; + +static struct i2c_board_info __initdata omap3pandora_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("tps65950", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &omap3pandora_twldata, + }, +}; + +static int __init omap3pandora_i2c_init(void) +{ + omap_register_i2c_bus(1, 2600, omap3pandora_i2c_boardinfo, + ARRAY_SIZE(omap3pandora_i2c_boardinfo)); + /* i2c2 pins are not connected */ + omap_register_i2c_bus(3, 400, NULL, 0); + return 0; +} + +static void __init omap3pandora_init_irq(void) +{ + omap2_init_common_hw(); + omap_init_irq(); + omap_gpio_init(); +} + +static void __init omap3pandora_ads7846_init(void) +{ + int gpio = OMAP3_PANDORA_TS_GPIO; + int ret; + + ret = gpio_request(gpio, "ads7846_pen_down"); + if (ret < 0) { + printk(KERN_ERR "Failed to request GPIO %d for " + "ads7846 pen down IRQ\n", gpio); + return; + } + + gpio_direction_input(gpio); +} + +static int ads7846_get_pendown_state(void) +{ + return !gpio_get_value(OMAP3_PANDORA_TS_GPIO); +} + +static struct ads7846_platform_data ads7846_config = { + .x_max = 0x0fff, + .y_max = 0x0fff, + .x_plate_ohms = 180, + .pressure_max = 255, + .debounce_max = 10, + .debounce_tol = 3, + .debounce_rep = 1, + .get_pendown_state = ads7846_get_pendown_state, + .keep_vref_on = 1, +}; + +static struct omap2_mcspi_device_config ads7846_mcspi_config = { + .turbo_mode = 0, + .single_channel = 1, /* 0: slave, 1: master */ +}; + +static struct spi_board_info omap3pandora_spi_board_info[] __initdata = { + { + .modalias = "ads7846", + .bus_num = 1, + .chip_select = 0, + .max_speed_hz = 1500000, + .controller_data = &ads7846_mcspi_config, + .irq = OMAP_GPIO_IRQ(OMAP3_PANDORA_TS_GPIO), + .platform_data = &ads7846_config, + } +}; + +static struct platform_device omap3pandora_lcd_device = { + .name = "pandora_lcd", + .id = -1, +}; + +static struct omap_lcd_config omap3pandora_lcd_config __initdata = { + .ctrl_name = "internal", +}; + +static struct omap_board_config_kernel omap3pandora_config[] __initdata = { + { OMAP_TAG_UART, &omap3pandora_uart_config }, + { OMAP_TAG_LCD, &omap3pandora_lcd_config }, +}; + +static struct platform_device *omap3pandora_devices[] __initdata = { + &omap3pandora_lcd_device, +}; + +static void __init omap3pandora_init(void) +{ + omap3pandora_i2c_init(); + platform_add_devices(omap3pandora_devices, + ARRAY_SIZE(omap3pandora_devices)); + omap_board_config = omap3pandora_config; + omap_board_config_size = ARRAY_SIZE(omap3pandora_config); + omap_serial_init(); + spi_register_board_info(omap3pandora_spi_board_info, + ARRAY_SIZE(omap3pandora_spi_board_info)); + omap3pandora_ads7846_init(); +} + +static void __init omap3pandora_map_io(void) +{ + omap2_set_globals_343x(); + omap2_map_common_io(); +} + +MACHINE_START(OMAP3_PANDORA, "Pandora Handheld Console") + .phys_io = 0x48000000, + .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc, + .boot_params = 0x80000100, + .map_io = omap3pandora_map_io, + .init_irq = omap3pandora_init_irq, + .init_machine = omap3pandora_init, + .timer = &omap_timer, +MACHINE_END diff --git a/arch/arm/mach-omap2/board-overo.c b/arch/arm/mach-omap2/board-overo.c index e09aa59a399..82b3dc557c9 100644 --- a/arch/arm/mach-omap2/board-overo.c +++ b/arch/arm/mach-omap2/board-overo.c @@ -26,6 +26,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/platform_device.h> +#include <linux/i2c/twl4030.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> @@ -44,6 +45,8 @@ #include <mach/hardware.h> #include <mach/nand.h> +#include "mmc-twl4030.h" + #define NAND_BLOCK_SIZE SZ_128K #define GPMC_CS0_BASE 0x60 #define GPMC_CS_SIZE 0x30 @@ -139,8 +142,31 @@ static struct omap_uart_config overo_uart_config __initdata = { .enabled_uarts = ((1 << 0) | (1 << 1) | (1 << 2)), }; +static struct twl4030_gpio_platform_data overo_gpio_data = { + .gpio_base = OMAP_MAX_GPIO_LINES, + .irq_base = TWL4030_GPIO_IRQ_BASE, + .irq_end = TWL4030_GPIO_IRQ_END, +}; + +static struct twl4030_platform_data overo_twldata = { + .irq_base = TWL4030_IRQ_BASE, + .irq_end = TWL4030_IRQ_END, + .gpio = &overo_gpio_data, +}; + +static struct i2c_board_info __initdata overo_i2c_boardinfo[] = { + { + I2C_BOARD_INFO("twl4030", 0x48), + .flags = I2C_CLIENT_WAKE, + .irq = INT_34XX_SYS_NIRQ, + .platform_data = &overo_twldata, + }, +}; + static int __init overo_i2c_init(void) { + omap_register_i2c_bus(1, 2600, overo_i2c_boardinfo, + ARRAY_SIZE(overo_i2c_boardinfo)); /* i2c2 pins are used for gpio */ omap_register_i2c_bus(3, 400, NULL, 0); return 0; @@ -171,6 +197,22 @@ static struct platform_device *overo_devices[] __initdata = { &overo_lcd_device, }; +static struct twl4030_hsmmc_info mmc[] __initdata = { + { + .mmc = 1, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + { + .mmc = 2, + .wires = 4, + .gpio_cd = -EINVAL, + .gpio_wp = -EINVAL, + }, + {} /* Terminator */ +}; + static void __init overo_init(void) { overo_i2c_init(); @@ -178,6 +220,7 @@ static void __init overo_init(void) omap_board_config = overo_config; omap_board_config_size = ARRAY_SIZE(overo_config); omap_serial_init(); + twl4030_mmc_init(mmc); overo_flash_init(); if ((gpio_request(OVERO_GPIO_W2W_NRESET, diff --git a/arch/arm/mach-omap2/clock24xx.h b/arch/arm/mach-omap2/clock24xx.h index 242a19d86cc..ff6cd14d254 100644 --- a/arch/arm/mach-omap2/clock24xx.h +++ b/arch/arm/mach-omap2/clock24xx.h @@ -2522,7 +2522,6 @@ static struct clk usbhs_ick = { static struct clk mmchs1_ick = { .name = "mmchs_ick", - .id = 1, .parent = &l4_ck, .flags = CLOCK_IN_OMAP243X, .clkdm_name = "core_l4_clkdm", @@ -2533,7 +2532,6 @@ static struct clk mmchs1_ick = { static struct clk mmchs1_fck = { .name = "mmchs_fck", - .id = 1, .parent = &func_96m_ck, .flags = CLOCK_IN_OMAP243X, .clkdm_name = "core_l3_clkdm", @@ -2544,7 +2542,7 @@ static struct clk mmchs1_fck = { static struct clk mmchs2_ick = { .name = "mmchs_ick", - .id = 2, + .id = 1, .parent = &l4_ck, .flags = CLOCK_IN_OMAP243X, .clkdm_name = "core_l4_clkdm", @@ -2555,7 +2553,7 @@ static struct clk mmchs2_ick = { static struct clk mmchs2_fck = { .name = "mmchs_fck", - .id = 2, + .id = 1, .parent = &func_96m_ck, .flags = CLOCK_IN_OMAP243X, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, OMAP24XX_CM_FCLKEN2), @@ -2595,7 +2593,6 @@ static struct clk mdm_intc_ick = { static struct clk mmchsdb1_fck = { .name = "mmchsdb_fck", - .id = 1, .parent = &func_32k_ck, .flags = CLOCK_IN_OMAP243X, .clkdm_name = "core_l4_clkdm", @@ -2606,7 +2603,7 @@ static struct clk mmchsdb1_fck = { static struct clk mmchsdb2_fck = { .name = "mmchsdb_fck", - .id = 2, + .id = 1, .parent = &func_32k_ck, .flags = CLOCK_IN_OMAP243X, .clkdm_name = "core_l4_clkdm", diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c index 084e11082f8..31bb7010bd4 100644 --- a/arch/arm/mach-omap2/clock34xx.c +++ b/arch/arm/mach-omap2/clock34xx.c @@ -475,7 +475,7 @@ int __init omap2_clk_init(void) * Update this if there are further clock changes between ES2 * and production parts */ - if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) { + if (omap_rev() == OMAP3430_REV_ES1_0) { /* No 3430ES1-only rates exist, so no RATE_IN_3430ES1 */ cpu_clkflg |= CLOCK_IN_OMAP3430ES1; } else { diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h index c38a8a09692..a826094d89b 100644 --- a/arch/arm/mach-omap2/clock34xx.h +++ b/arch/arm/mach-omap2/clock34xx.h @@ -1374,7 +1374,7 @@ static struct clk core_96m_fck = { static struct clk mmchs3_fck = { .name = "mmchs_fck", - .id = 3, + .id = 2, .parent = &core_96m_fck, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP3430ES2_EN_MMC3_SHIFT, @@ -1385,7 +1385,7 @@ static struct clk mmchs3_fck = { static struct clk mmchs2_fck = { .name = "mmchs_fck", - .id = 2, + .id = 1, .parent = &core_96m_fck, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP3430_EN_MMC2_SHIFT, @@ -1406,7 +1406,6 @@ static struct clk mspro_fck = { static struct clk mmchs1_fck = { .name = "mmchs_fck", - .id = 1, .parent = &core_96m_fck, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_FCLKEN1), .enable_bit = OMAP3430_EN_MMC1_SHIFT, @@ -1722,7 +1721,7 @@ static struct clk usbtll_ick = { static struct clk mmchs3_ick = { .name = "mmchs_ick", - .id = 3, + .id = 2, .parent = &core_l4_ick, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), .enable_bit = OMAP3430ES2_EN_MMC3_SHIFT, @@ -1774,7 +1773,7 @@ static struct clk des2_ick = { static struct clk mmchs2_ick = { .name = "mmchs_ick", - .id = 2, + .id = 1, .parent = &core_l4_ick, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), .enable_bit = OMAP3430_EN_MMC2_SHIFT, @@ -1785,7 +1784,6 @@ static struct clk mmchs2_ick = { static struct clk mmchs1_ick = { .name = "mmchs_ick", - .id = 1, .parent = &core_l4_ick, .enable_reg = OMAP_CM_REGADDR(CORE_MOD, CM_ICLKEN1), .enable_bit = OMAP3430_EN_MMC1_SHIFT, @@ -2280,8 +2278,8 @@ static struct clk wkup_32k_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio1_fck = { - .name = "gpio1_fck", +static struct clk gpio1_dbck = { + .name = "gpio1_dbck", .parent = &wkup_32k_fck, .enable_reg = OMAP_CM_REGADDR(WKUP_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO1_SHIFT, @@ -2527,8 +2525,8 @@ static struct clk per_32k_alwon_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio6_fck = { - .name = "gpio6_fck", +static struct clk gpio6_dbck = { + .name = "gpio6_dbck", .parent = &per_32k_alwon_fck, .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO6_SHIFT, @@ -2537,8 +2535,8 @@ static struct clk gpio6_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio5_fck = { - .name = "gpio5_fck", +static struct clk gpio5_dbck = { + .name = "gpio5_dbck", .parent = &per_32k_alwon_fck, .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO5_SHIFT, @@ -2547,8 +2545,8 @@ static struct clk gpio5_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio4_fck = { - .name = "gpio4_fck", +static struct clk gpio4_dbck = { + .name = "gpio4_dbck", .parent = &per_32k_alwon_fck, .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO4_SHIFT, @@ -2557,8 +2555,8 @@ static struct clk gpio4_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio3_fck = { - .name = "gpio3_fck", +static struct clk gpio3_dbck = { + .name = "gpio3_dbck", .parent = &per_32k_alwon_fck, .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO3_SHIFT, @@ -2567,8 +2565,8 @@ static struct clk gpio3_fck = { .recalc = &followparent_recalc, }; -static struct clk gpio2_fck = { - .name = "gpio2_fck", +static struct clk gpio2_dbck = { + .name = "gpio2_dbck", .parent = &per_32k_alwon_fck, .enable_reg = OMAP_CM_REGADDR(OMAP3430_PER_MOD, CM_FCLKEN), .enable_bit = OMAP3430_EN_GPIO2_SHIFT, @@ -3170,7 +3168,7 @@ static struct clk *onchip_34xx_clks[] __initdata = { &usim_fck, &gpt1_fck, &wkup_32k_fck, - &gpio1_fck, + &gpio1_dbck, &wdt2_fck, &wkup_l4_ick, &usim_ick, @@ -3192,11 +3190,11 @@ static struct clk *onchip_34xx_clks[] __initdata = { &gpt8_fck, &gpt9_fck, &per_32k_alwon_fck, - &gpio6_fck, - &gpio5_fck, - &gpio4_fck, - &gpio3_fck, - &gpio2_fck, + &gpio6_dbck, + &gpio5_dbck, + &gpio4_dbck, + &gpio3_dbck, + &gpio2_dbck, &wdt3_fck, &per_l4_ick, &gpio6_ick, diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 90af2ac469a..9d7216ff6c9 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -14,16 +14,19 @@ #include <linux/init.h> #include <linux/platform_device.h> #include <linux/io.h> +#include <linux/clk.h> #include <mach/hardware.h> #include <asm/mach-types.h> #include <asm/mach/map.h> +#include <mach/control.h> #include <mach/tc.h> #include <mach/board.h> #include <mach/mux.h> #include <mach/gpio.h> #include <mach/eac.h> +#include <mach/mmc.h> #if defined(CONFIG_OMAP_DSP) || defined(CONFIG_OMAP_DSP_MODULE) #define OMAP2_MBOX_BASE IO_ADDRESS(OMAP24XX_MAILBOX_BASE) @@ -295,6 +298,171 @@ static void omap_init_sha1_md5(void) static inline void omap_init_sha1_md5(void) { } #endif +/*-------------------------------------------------------------------------*/ + +#ifdef CONFIG_ARCH_OMAP3 + +#define MMCHS_SYSCONFIG 0x0010 +#define MMCHS_SYSCONFIG_SWRESET (1 << 1) +#define MMCHS_SYSSTATUS 0x0014 +#define MMCHS_SYSSTATUS_RESETDONE (1 << 0) + +static struct platform_device dummy_pdev = { + .dev = { + .bus = &platform_bus_type, + }, +}; + +/** + * omap_hsmmc_reset() - Full reset of each HS-MMC controller + * + * Ensure that each MMC controller is fully reset. Controllers + * left in an unknown state (by bootloader) may prevent retention + * or OFF-mode. This is especially important in cases where the + * MMC driver is not enabled, _or_ built as a module. + * + * In order for reset to work, interface, functional and debounce + * clocks must be enabled. The debounce clock comes from func_32k_clk + * and is not under SW control, so we only enable i- and f-clocks. + **/ +static void __init omap_hsmmc_reset(void) +{ + u32 i, nr_controllers = cpu_is_omap34xx() ? OMAP34XX_NR_MMC : + OMAP24XX_NR_MMC; + + for (i = 0; i < nr_controllers; i++) { + u32 v, base = 0; + struct clk *iclk, *fclk; + struct device *dev = &dummy_pdev.dev; + + switch (i) { + case 0: + base = OMAP2_MMC1_BASE; + break; + case 1: + base = OMAP2_MMC2_BASE; + break; + case 2: + base = OMAP3_MMC3_BASE; + break; + } + + dummy_pdev.id = i; + iclk = clk_get(dev, "mmchs_ick"); + if (iclk && clk_enable(iclk)) + iclk = NULL; + + fclk = clk_get(dev, "mmchs_fck"); + if (fclk && clk_enable(fclk)) + fclk = NULL; + + if (!iclk || !fclk) { + printk(KERN_WARNING + "%s: Unable to enable clocks for MMC%d, " + "cannot reset.\n", __func__, i); + break; + } + + omap_writel(MMCHS_SYSCONFIG_SWRESET, base + MMCHS_SYSCONFIG); + v = omap_readl(base + MMCHS_SYSSTATUS); + while (!(omap_readl(base + MMCHS_SYSSTATUS) & + MMCHS_SYSSTATUS_RESETDONE)) + cpu_relax(); + + if (fclk) { + clk_disable(fclk); + clk_put(fclk); + } + if (iclk) { + clk_disable(iclk); + clk_put(iclk); + } + } +} +#else +static inline void omap_hsmmc_reset(void) {} +#endif + +#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ + defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE) + +static inline void omap2_mmc_mux(struct omap_mmc_platform_data *mmc_controller, + int controller_nr) +{ + if (cpu_is_omap2420() && controller_nr == 0) { + omap_cfg_reg(H18_24XX_MMC_CMD); + omap_cfg_reg(H15_24XX_MMC_CLKI); + omap_cfg_reg(G19_24XX_MMC_CLKO); + omap_cfg_reg(F20_24XX_MMC_DAT0); + omap_cfg_reg(F19_24XX_MMC_DAT_DIR0); + omap_cfg_reg(G18_24XX_MMC_CMD_DIR); + if (mmc_controller->slots[0].wires == 4) { + omap_cfg_reg(H14_24XX_MMC_DAT1); + omap_cfg_reg(E19_24XX_MMC_DAT2); + omap_cfg_reg(D19_24XX_MMC_DAT3); + omap_cfg_reg(E20_24XX_MMC_DAT_DIR1); + omap_cfg_reg(F18_24XX_MMC_DAT_DIR2); + omap_cfg_reg(E18_24XX_MMC_DAT_DIR3); + } + + /* + * Use internal loop-back in MMC/SDIO Module Input Clock + * selection + */ + if (mmc_controller->slots[0].internal_clock) { + u32 v = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); + v |= (1 << 24); + omap_ctrl_writel(v, OMAP2_CONTROL_DEVCONF0); + } + } +} + +void __init omap2_init_mmc(struct omap_mmc_platform_data **mmc_data, + int nr_controllers) +{ + int i; + + for (i = 0; i < nr_controllers; i++) { + unsigned long base, size; + unsigned int irq = 0; + + if (!mmc_data[i]) + continue; + + omap2_mmc_mux(mmc_data[i], i); + + switch (i) { + case 0: + base = OMAP2_MMC1_BASE; + irq = INT_24XX_MMC_IRQ; + break; + case 1: + base = OMAP2_MMC2_BASE; + irq = INT_24XX_MMC2_IRQ; + break; + case 2: + if (!cpu_is_omap34xx()) + return; + base = OMAP3_MMC3_BASE; + irq = INT_34XX_MMC3_IRQ; + break; + default: + continue; + } + + if (cpu_is_omap2420()) + size = OMAP2420_MMC_SIZE; + else + size = HSMMC_SIZE; + + omap_mmc_add(i, base, size, irq, mmc_data[i]); + }; +} + +#endif + +/*-------------------------------------------------------------------------*/ + #if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE) #if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430) #define OMAP_HDQ_BASE 0x480B2000 @@ -334,6 +502,7 @@ static int __init omap2_init_devices(void) /* please keep these calls, and their implementations above, * in alphabetical order so they're easier to sort through. */ + omap_hsmmc_reset(); omap_init_mbox(); omap_init_mcspi(); omap_hdq_init(); diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c index bf45ff39a7b..b0f8e7d6279 100644 --- a/arch/arm/mach-omap2/id.c +++ b/arch/arm/mach-omap2/id.c @@ -22,40 +22,15 @@ #include <mach/control.h> #include <mach/cpu.h> -static u32 class; -static void __iomem *tap_base; -static u16 tap_prod_id; - -#define OMAP_TAP_IDCODE 0x0204 -#define OMAP_TAP_DIE_ID_0 0x0218 -#define OMAP_TAP_DIE_ID_1 0x021C -#define OMAP_TAP_DIE_ID_2 0x0220 -#define OMAP_TAP_DIE_ID_3 0x0224 - -/* system_rev fields for OMAP2 processors: - * CPU id bits [31:16], - * CPU device type [15:12], (unprg,normal,POP) - * CPU revision [11:08] - * CPU class bits [07:00] - */ - -struct omap_id { - u16 hawkeye; /* Silicon type (Hawkeye id) */ - u8 dev; /* Device type from production_id reg */ - u32 type; /* combined type id copied to system_rev */ -}; +static struct omap_chip_id omap_chip; +static unsigned int omap_revision; -/* Register values to detect the OMAP version */ -static struct omap_id omap_ids[] __initdata = { - { .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200000 }, - { .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201000 }, - { .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202000 }, - { .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220000 }, - { .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230000 }, - { .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300000 }, -}; -static struct omap_chip_id omap_chip; +unsigned int omap_rev(void) +{ + return omap_revision; +} +EXPORT_SYMBOL(omap_rev); /** * omap_chip_is - test whether currently running OMAP matches a chip type @@ -70,135 +45,41 @@ int omap_chip_is(struct omap_chip_id oci) } EXPORT_SYMBOL(omap_chip_is); -static u32 __init read_tap_reg(int reg) -{ - unsigned int regval = 0; - u32 cpuid; - - /* Reading the IDCODE register on 3430 ES1 results in a - * data abort as the register is not exposed on the OCP - * Hence reading the Cortex Rev - */ - cpuid = read_cpuid(CPUID_ID); - - /* If the processor type is Cortex-A8 and the revision is 0x0 - * it means its Cortex r0p0 which is 3430 ES1 - */ - if ((((cpuid >> 4) & 0xFFF) == 0xC08) && ((cpuid & 0xF) == 0x0)) { - - if (reg == tap_prod_id) { - regval = 0x000F00F0; - goto out; - } - - switch (reg) { - case OMAP_TAP_IDCODE : regval = 0x0B7AE02F; break; - /* Making DevType as 0xF in ES1 to differ from ES2 */ - case OMAP_TAP_DIE_ID_0: regval = 0x01000000; break; - case OMAP_TAP_DIE_ID_1: regval = 0x1012d687; break; - case OMAP_TAP_DIE_ID_2: regval = 0x00000000; break; - case OMAP_TAP_DIE_ID_3: regval = 0x2d2c0000; break; - } - } else - regval = __raw_readl(tap_base + reg); - -out: - return regval; - -} +/*----------------------------------------------------------------------------*/ -/* - * _set_system_rev - set the system_rev global based on current OMAP chip type - * - * Set the system_rev global. This is primarily used by the cpu_is_omapxxxx() - * macros. - */ -static void __init _set_system_rev(u32 type, u8 rev) -{ - u32 i, ctrl_status; - - /* - * system_rev encoding is as follows - * system_rev & 0xff000000 -> Omap Class (24xx/34xx) - * system_rev & 0xfff00000 -> Omap Sub Class (242x/343x) - * system_rev & 0xffff0000 -> Omap type (2420/2422/2423/2430/3430) - * system_rev & 0x0000f000 -> Silicon revision (ES1, ES2 ) - * system_rev & 0x00000700 -> Device Type ( EMU/HS/GP/BAD ) - * system_rev & 0x000000c0 -> IDCODE revision[6:7] - * system_rev & 0x0000003f -> sys_boot[0:5] - */ - /* Embedding the ES revision info in type field */ - system_rev = type; - /* Also add IDCODE revision info only two lower bits */ - system_rev |= ((rev & 0x3) << 6); - - /* Add in the device type and sys_boot fields (see above) */ - if (cpu_is_omap24xx()) { - i = OMAP24XX_CONTROL_STATUS; - } else if (cpu_is_omap343x()) { - i = OMAP343X_CONTROL_STATUS; - } else { - printk(KERN_ERR "id: unknown CPU type\n"); - BUG(); - } - ctrl_status = omap_ctrl_readl(i); - system_rev |= (ctrl_status & (OMAP2_SYSBOOT_5_MASK | - OMAP2_SYSBOOT_4_MASK | - OMAP2_SYSBOOT_3_MASK | - OMAP2_SYSBOOT_2_MASK | - OMAP2_SYSBOOT_1_MASK | - OMAP2_SYSBOOT_0_MASK)); - system_rev |= (ctrl_status & OMAP2_DEVICETYPE_MASK); -} - - -/* - * _set_omap_chip - set the omap_chip global based on OMAP chip type - * - * Build the omap_chip bits. This variable is used by powerdomain and - * clockdomain code to indicate whether structures are applicable for - * the current OMAP chip type by ANDing it against a 'platform' bitfield - * in the structure. - */ -static void __init _set_omap_chip(void) -{ - if (cpu_is_omap343x()) { - - omap_chip.oc = CHIP_IS_OMAP3430; - if (is_sil_rev_equal_to(OMAP3430_REV_ES1_0)) - omap_chip.oc |= CHIP_IS_OMAP3430ES1; - else if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) - omap_chip.oc |= CHIP_IS_OMAP3430ES2; - - } else if (cpu_is_omap243x()) { - - /* Currently only supports 2430ES2.1 and 2430-all */ - omap_chip.oc |= CHIP_IS_OMAP2430; - - } else if (cpu_is_omap242x()) { - - /* Currently only supports 2420ES2.1.1 and 2420-all */ - omap_chip.oc |= CHIP_IS_OMAP2420; +#define OMAP_TAP_IDCODE 0x0204 +#define OMAP_TAP_DIE_ID_0 0x0218 +#define OMAP_TAP_DIE_ID_1 0x021C +#define OMAP_TAP_DIE_ID_2 0x0220 +#define OMAP_TAP_DIE_ID_3 0x0224 - } else { +#define read_tap_reg(reg) __raw_readl(tap_base + (reg)) - /* Current CPU not supported by this code. */ - printk(KERN_WARNING "OMAP chip type code does not yet support " - "this CPU type.\n"); - WARN_ON(1); +struct omap_id { + u16 hawkeye; /* Silicon type (Hawkeye id) */ + u8 dev; /* Device type from production_id reg */ + u32 type; /* Combined type id copied to omap_revision */ +}; - } +/* Register values to detect the OMAP version */ +static struct omap_id omap_ids[] __initdata = { + { .hawkeye = 0xb5d9, .dev = 0x0, .type = 0x24200024 }, + { .hawkeye = 0xb5d9, .dev = 0x1, .type = 0x24201024 }, + { .hawkeye = 0xb5d9, .dev = 0x2, .type = 0x24202024 }, + { .hawkeye = 0xb5d9, .dev = 0x4, .type = 0x24220024 }, + { .hawkeye = 0xb5d9, .dev = 0x8, .type = 0x24230024 }, + { .hawkeye = 0xb68a, .dev = 0x0, .type = 0x24300024 }, +}; -} +static void __iomem *tap_base; +static u16 tap_prod_id; -void __init omap2_check_revision(void) +void __init omap24xx_check_revision(void) { int i, j; - u32 idcode; - u32 prod_id; + u32 idcode, prod_id; u16 hawkeye; - u8 dev_type; - u8 rev; + u8 dev_type, rev; idcode = read_tap_reg(OMAP_TAP_IDCODE); prod_id = read_tap_reg(tap_prod_id); @@ -220,18 +101,6 @@ void __init omap2_check_revision(void) pr_debug("OMAP_TAP_PROD_ID_0: 0x%08x DEV_TYPE: %i\n", prod_id, dev_type); - /* - * Detection for 34xx ES2.0 and above can be done with just - * hawkeye and rev. See TRM 1.5.2 Device Identification. - * Note that rev cannot be used directly as ES1.0 uses value 0. - */ - if (hawkeye == 0xb7ae) { - system_rev = 0x34300000 | ((1 + rev) << 12); - pr_info("OMAP%04x ES2.%i\n", system_rev >> 16, rev); - _set_omap_chip(); - return; - } - /* Check hawkeye ids */ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { if (hawkeye == omap_ids[i].hawkeye) @@ -255,23 +124,115 @@ void __init omap2_check_revision(void) j = i; } - _set_system_rev(omap_ids[j].type, rev); + pr_info("OMAP%04x", omap_rev() >> 16); + if ((omap_rev() >> 8) & 0x0f) + pr_info("ES%x", (omap_rev() >> 12) & 0xf); + pr_info("\n"); +} - _set_omap_chip(); +void __init omap34xx_check_revision(void) +{ + u32 cpuid, idcode; + u16 hawkeye; + u8 rev; + char *rev_name = "ES1.0"; - pr_info("OMAP%04x", system_rev >> 16); - if ((system_rev >> 8) & 0x0f) - pr_info("ES%x", (system_rev >> 12) & 0xf); - pr_info("\n"); + /* + * We cannot access revision registers on ES1.0. + * If the processor type is Cortex-A8 and the revision is 0x0 + * it means its Cortex r0p0 which is 3430 ES1.0. + */ + cpuid = read_cpuid(CPUID_ID); + if ((((cpuid >> 4) & 0xfff) == 0xc08) && ((cpuid & 0xf) == 0x0)) { + omap_revision = OMAP3430_REV_ES1_0; + goto out; + } + /* + * Detection for 34xx ES2.0 and above can be done with just + * hawkeye and rev. See TRM 1.5.2 Device Identification. + * Note that rev does not map directly to our defined processor + * revision numbers as ES1.0 uses value 0. + */ + idcode = read_tap_reg(OMAP_TAP_IDCODE); + hawkeye = (idcode >> 12) & 0xffff; + rev = (idcode >> 28) & 0xff; + + if (hawkeye == 0xb7ae) { + switch (rev) { + case 0: + omap_revision = OMAP3430_REV_ES2_0; + rev_name = "ES2.0"; + break; + case 2: + omap_revision = OMAP3430_REV_ES2_1; + rev_name = "ES2.1"; + break; + case 3: + omap_revision = OMAP3430_REV_ES3_0; + rev_name = "ES3.0"; + break; + default: + /* Use the latest known revision as default */ + omap_revision = OMAP3430_REV_ES3_0; + rev_name = "Unknown revision\n"; + } + } + +out: + pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name); } +/* + * Try to detect the exact revision of the omap we're running on + */ +void __init omap2_check_revision(void) +{ + /* + * At this point we have an idea about the processor revision set + * earlier with omap2_set_globals_tap(). + */ + if (cpu_is_omap24xx()) + omap24xx_check_revision(); + else if (cpu_is_omap34xx()) + omap34xx_check_revision(); + else + pr_err("OMAP revision unknown, please fix!\n"); + + /* + * OK, now we know the exact revision. Initialize omap_chip bits + * for powerdowmain and clockdomain code. + */ + if (cpu_is_omap243x()) { + /* Currently only supports 2430ES2.1 and 2430-all */ + omap_chip.oc |= CHIP_IS_OMAP2430; + } else if (cpu_is_omap242x()) { + /* Currently only supports 2420ES2.1.1 and 2420-all */ + omap_chip.oc |= CHIP_IS_OMAP2420; + } else if (cpu_is_omap343x()) { + omap_chip.oc = CHIP_IS_OMAP3430; + if (omap_rev() == OMAP3430_REV_ES1_0) + omap_chip.oc |= CHIP_IS_OMAP3430ES1; + else if (omap_rev() > OMAP3430_REV_ES1_0) + omap_chip.oc |= CHIP_IS_OMAP3430ES2; + } else { + pr_err("Uninitialized omap_chip, please fix!\n"); + } +} + +/* + * Set up things for map_io and processor detection later on. Gets called + * pretty much first thing from board init. For multi-omap, this gets + * cpu_is_omapxxxx() working accurately enough for map_io. Then we'll try to + * detect the exact revision later on in omap2_detect_revision() once map_io + * is done. + */ void __init omap2_set_globals_tap(struct omap_globals *omap2_globals) { - class = omap2_globals->class; + omap_revision = omap2_globals->class; tap_base = omap2_globals->tap; - if (class == 0x3430) + if (cpu_is_omap34xx()) tap_prod_id = 0x0210; else tap_prod_id = 0x0208; diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c index c40fc378a25..636e2821af7 100644 --- a/arch/arm/mach-omap2/irq.c +++ b/arch/arm/mach-omap2/irq.c @@ -23,6 +23,7 @@ #define INTC_REVISION 0x0000 #define INTC_SYSCONFIG 0x0010 #define INTC_SYSSTATUS 0x0014 +#define INTC_SIR 0x0040 #define INTC_CONTROL 0x0048 #define INTC_MIR_CLEAR0 0x0088 #define INTC_MIR_SET0 0x008c @@ -60,6 +61,30 @@ static u32 intc_bank_read_reg(struct omap_irq_bank *bank, u16 reg) return __raw_readl(bank->base_reg + reg); } +static int previous_irq; + +/* + * On 34xx we can get occasional spurious interrupts if the ack from + * an interrupt handler does not get posted before we unmask. Warn about + * the interrupt handlers that need to flush posted writes. + */ +static int omap_check_spurious(unsigned int irq) +{ + u32 sir, spurious; + + sir = intc_bank_read_reg(&irq_banks[0], INTC_SIR); + spurious = sir >> 6; + + if (spurious > 1) { + printk(KERN_WARNING "Spurious irq %i: 0x%08x, please flush " + "posted write for irq %i\n", + irq, sir, previous_irq); + return spurious; + } + + return 0; +} + /* XXX: FIQ and additional INTC support (only MPU at the moment) */ static void omap_ack_irq(unsigned int irq) { @@ -70,6 +95,20 @@ static void omap_mask_irq(unsigned int irq) { int offset = irq & (~(IRQ_BITS_PER_REG - 1)); + if (cpu_is_omap34xx()) { + int spurious = 0; + + /* + * INT_34XX_GPT12_IRQ is also the spurious irq. Maybe because + * it is the highest irq number? + */ + if (irq == INT_34XX_GPT12_IRQ) + spurious = omap_check_spurious(irq); + + if (!spurious) + previous_irq = irq; + } + irq &= (IRQ_BITS_PER_REG - 1); intc_bank_write_reg(1 << irq, &irq_banks[0], INTC_MIR_SET0 + offset); diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c new file mode 100644 index 00000000000..437f52073f6 --- /dev/null +++ b/arch/arm/mach-omap2/mmc-twl4030.c @@ -0,0 +1,408 @@ +/* + * linux/arch/arm/mach-omap2/mmc-twl4030.c + * + * Copyright (C) 2007-2008 Texas Instruments + * Copyright (C) 2008 Nokia Corporation + * Author: Texas Instruments + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/gpio.h> +#include <linux/i2c/twl4030.h> + +#include <mach/hardware.h> +#include <mach/control.h> +#include <mach/mmc.h> +#include <mach/board.h> + +#include "mmc-twl4030.h" + +#if defined(CONFIG_TWL4030_CORE) && \ + (defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) + +#define LDO_CLR 0x00 +#define VSEL_S2_CLR 0x40 + +#define VMMC1_DEV_GRP 0x27 +#define VMMC1_CLR 0x00 +#define VMMC1_315V 0x03 +#define VMMC1_300V 0x02 +#define VMMC1_285V 0x01 +#define VMMC1_185V 0x00 +#define VMMC1_DEDICATED 0x2A + +#define VMMC2_DEV_GRP 0x2B +#define VMMC2_CLR 0x40 +#define VMMC2_315V 0x0c +#define VMMC2_300V 0x0b +#define VMMC2_285V 0x0a +#define VMMC2_260V 0x08 +#define VMMC2_185V 0x06 +#define VMMC2_DEDICATED 0x2E + +#define VMMC_DEV_GRP_P1 0x20 + +static u16 control_pbias_offset; +static u16 control_devconf1_offset; + +#define HSMMC_NAME_LEN 9 + +static struct twl_mmc_controller { + struct omap_mmc_platform_data *mmc; + u8 twl_vmmc_dev_grp; + u8 twl_mmc_dedicated; + char name[HSMMC_NAME_LEN]; +} hsmmc[] = { + { + .twl_vmmc_dev_grp = VMMC1_DEV_GRP, + .twl_mmc_dedicated = VMMC1_DEDICATED, + }, + { + .twl_vmmc_dev_grp = VMMC2_DEV_GRP, + .twl_mmc_dedicated = VMMC2_DEDICATED, + }, +}; + +static int twl_mmc_card_detect(int irq) +{ + unsigned i; + + for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { + struct omap_mmc_platform_data *mmc; + + mmc = hsmmc[i].mmc; + if (!mmc) + continue; + if (irq != mmc->slots[0].card_detect_irq) + continue; + + /* NOTE: assumes card detect signal is active-low */ + return !gpio_get_value_cansleep(mmc->slots[0].switch_pin); + } + return -ENOSYS; +} + +static int twl_mmc_get_ro(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + /* NOTE: assumes write protect signal is active-high */ + return gpio_get_value_cansleep(mmc->slots[0].gpio_wp); +} + +/* + * MMC Slot Initialization. + */ +static int twl_mmc_late_init(struct device *dev) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + int ret = 0; + int i; + + ret = gpio_request(mmc->slots[0].switch_pin, "mmc_cd"); + if (ret) + goto done; + ret = gpio_direction_input(mmc->slots[0].switch_pin); + if (ret) + goto err; + + for (i = 0; i < ARRAY_SIZE(hsmmc); i++) { + if (hsmmc[i].name == mmc->slots[0].name) { + hsmmc[i].mmc = mmc; + break; + } + } + + return 0; + +err: + gpio_free(mmc->slots[0].switch_pin); +done: + mmc->slots[0].card_detect_irq = 0; + mmc->slots[0].card_detect = NULL; + + dev_err(dev, "err %d configuring card detect\n", ret); + return ret; +} + +static void twl_mmc_cleanup(struct device *dev) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + gpio_free(mmc->slots[0].switch_pin); +} + +#ifdef CONFIG_PM + +static int twl_mmc_suspend(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + disable_irq(mmc->slots[0].card_detect_irq); + return 0; +} + +static int twl_mmc_resume(struct device *dev, int slot) +{ + struct omap_mmc_platform_data *mmc = dev->platform_data; + + enable_irq(mmc->slots[0].card_detect_irq); + return 0; +} + +#else +#define twl_mmc_suspend NULL +#define twl_mmc_resume NULL +#endif + +/* + * Sets the MMC voltage in twl4030 + */ +static int twl_mmc_set_voltage(struct twl_mmc_controller *c, int vdd) +{ + int ret; + u8 vmmc, dev_grp_val; + + switch (1 << vdd) { + case MMC_VDD_35_36: + case MMC_VDD_34_35: + case MMC_VDD_33_34: + case MMC_VDD_32_33: + case MMC_VDD_31_32: + case MMC_VDD_30_31: + if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) + vmmc = VMMC1_315V; + else + vmmc = VMMC2_315V; + break; + case MMC_VDD_29_30: + if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) + vmmc = VMMC1_315V; + else + vmmc = VMMC2_300V; + break; + case MMC_VDD_27_28: + case MMC_VDD_26_27: + if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) + vmmc = VMMC1_285V; + else + vmmc = VMMC2_285V; + break; + case MMC_VDD_25_26: + case MMC_VDD_24_25: + case MMC_VDD_23_24: + case MMC_VDD_22_23: + case MMC_VDD_21_22: + case MMC_VDD_20_21: + if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) + vmmc = VMMC1_285V; + else + vmmc = VMMC2_260V; + break; + case MMC_VDD_165_195: + if (c->twl_vmmc_dev_grp == VMMC1_DEV_GRP) + vmmc = VMMC1_185V; + else + vmmc = VMMC2_185V; + break; + default: + vmmc = 0; + break; + } + + if (vmmc) + dev_grp_val = VMMC_DEV_GRP_P1; /* Power up */ + else + dev_grp_val = LDO_CLR; /* Power down */ + + ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, + dev_grp_val, c->twl_vmmc_dev_grp); + if (ret) + return ret; + + ret = twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, + vmmc, c->twl_mmc_dedicated); + + return ret; +} + +static int twl_mmc1_set_power(struct device *dev, int slot, int power_on, + int vdd) +{ + u32 reg; + int ret = 0; + struct twl_mmc_controller *c = &hsmmc[0]; + struct omap_mmc_platform_data *mmc = dev->platform_data; + + if (power_on) { + if (cpu_is_omap2430()) { + reg = omap_ctrl_readl(OMAP243X_CONTROL_DEVCONF1); + if ((1 << vdd) >= MMC_VDD_30_31) + reg |= OMAP243X_MMC1_ACTIVE_OVERWRITE; + else + reg &= ~OMAP243X_MMC1_ACTIVE_OVERWRITE; + omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1); + } + + if (mmc->slots[0].internal_clock) { + reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0); + reg |= OMAP2_MMCSDIO1ADPCLKISEL; + omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0); + } + + reg = omap_ctrl_readl(control_pbias_offset); + reg |= OMAP2_PBIASSPEEDCTRL0; + reg &= ~OMAP2_PBIASLITEPWRDNZ0; + omap_ctrl_writel(reg, control_pbias_offset); + + ret = twl_mmc_set_voltage(c, vdd); + + /* 100ms delay required for PBIAS configuration */ + msleep(100); + reg = omap_ctrl_readl(control_pbias_offset); + reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0); + if ((1 << vdd) <= MMC_VDD_165_195) + reg &= ~OMAP2_PBIASLITEVMODE0; + else + reg |= OMAP2_PBIASLITEVMODE0; + omap_ctrl_writel(reg, control_pbias_offset); + } else { + reg = omap_ctrl_readl(control_pbias_offset); + reg &= ~OMAP2_PBIASLITEPWRDNZ0; + omap_ctrl_writel(reg, control_pbias_offset); + + ret = twl_mmc_set_voltage(c, 0); + + /* 100ms delay required for PBIAS configuration */ + msleep(100); + reg = omap_ctrl_readl(control_pbias_offset); + reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 | + OMAP2_PBIASLITEVMODE0); + omap_ctrl_writel(reg, control_pbias_offset); + } + + return ret; +} + +static int twl_mmc2_set_power(struct device *dev, int slot, int power_on, int vdd) +{ + int ret; + struct twl_mmc_controller *c = &hsmmc[1]; + struct omap_mmc_platform_data *mmc = dev->platform_data; + + if (power_on) { + if (mmc->slots[0].internal_clock) { + u32 reg; + + reg = omap_ctrl_readl(control_devconf1_offset); + reg |= OMAP2_MMCSDIO2ADPCLKISEL; + omap_ctrl_writel(reg, control_devconf1_offset); + } + ret = twl_mmc_set_voltage(c, vdd); + } else { + ret = twl_mmc_set_voltage(c, 0); + } + + return ret; +} + +static struct omap_mmc_platform_data *hsmmc_data[OMAP34XX_NR_MMC] __initdata; + +void __init twl4030_mmc_init(struct twl4030_hsmmc_info *controllers) +{ + struct twl4030_hsmmc_info *c; + int nr_hsmmc = ARRAY_SIZE(hsmmc_data); + + if (cpu_is_omap2430()) { + control_pbias_offset = OMAP243X_CONTROL_PBIAS_LITE; + control_devconf1_offset = OMAP243X_CONTROL_DEVCONF1; + nr_hsmmc = 2; + } else { + control_pbias_offset = OMAP343X_CONTROL_PBIAS_LITE; + control_devconf1_offset = OMAP343X_CONTROL_DEVCONF1; + } + + for (c = controllers; c->mmc; c++) { + struct twl_mmc_controller *twl = hsmmc + c->mmc - 1; + struct omap_mmc_platform_data *mmc = hsmmc_data[c->mmc - 1]; + + if (!c->mmc || c->mmc > nr_hsmmc) { + pr_debug("MMC%d: no such controller\n", c->mmc); + continue; + } + if (mmc) { + pr_debug("MMC%d: already configured\n", c->mmc); + continue; + } + + mmc = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL); + if (!mmc) { + pr_err("Cannot allocate memory for mmc device!\n"); + return; + } + + sprintf(twl->name, "mmc%islot%i", c->mmc, 1); + mmc->slots[0].name = twl->name; + mmc->nr_slots = 1; + mmc->slots[0].ocr_mask = MMC_VDD_165_195 | + MMC_VDD_26_27 | MMC_VDD_27_28 | + MMC_VDD_29_30 | + MMC_VDD_30_31 | MMC_VDD_31_32; + mmc->slots[0].wires = c->wires; + mmc->slots[0].internal_clock = !c->ext_clock; + mmc->dma_mask = 0xffffffff; + + /* note: twl4030 card detect GPIOs normally switch VMMCx ... */ + if (gpio_is_valid(c->gpio_cd)) { + mmc->init = twl_mmc_late_init; + mmc->cleanup = twl_mmc_cleanup; + mmc->suspend = twl_mmc_suspend; + mmc->resume = twl_mmc_resume; + + mmc->slots[0].switch_pin = c->gpio_cd; + mmc->slots[0].card_detect_irq = gpio_to_irq(c->gpio_cd); + mmc->slots[0].card_detect = twl_mmc_card_detect; + } else + mmc->slots[0].switch_pin = -EINVAL; + + /* write protect normally uses an OMAP gpio */ + if (gpio_is_valid(c->gpio_wp)) { + gpio_request(c->gpio_wp, "mmc_wp"); + gpio_direction_input(c->gpio_wp); + + mmc->slots[0].gpio_wp = c->gpio_wp; + mmc->slots[0].get_ro = twl_mmc_get_ro; + } else + mmc->slots[0].gpio_wp = -EINVAL; + + /* NOTE: we assume OMAP's MMC1 and MMC2 use + * the TWL4030's VMMC1 and VMMC2, respectively; + * and that OMAP's MMC3 isn't used. + */ + + switch (c->mmc) { + case 1: + mmc->slots[0].set_power = twl_mmc1_set_power; + break; + case 2: + mmc->slots[0].set_power = twl_mmc2_set_power; + break; + default: + pr_err("MMC%d configuration not supported!\n", c->mmc); + continue; + } + hsmmc_data[c->mmc - 1] = mmc; + } + + omap2_init_mmc(hsmmc_data, OMAP34XX_NR_MMC); +} + +#endif diff --git a/arch/arm/mach-omap2/mmc-twl4030.h b/arch/arm/mach-omap2/mmc-twl4030.h new file mode 100644 index 00000000000..e1c8076400c --- /dev/null +++ b/arch/arm/mach-omap2/mmc-twl4030.h @@ -0,0 +1,29 @@ +/* + * MMC definitions for OMAP2 + * + * 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. + */ + +struct twl4030_hsmmc_info { + u8 mmc; /* controller 1/2/3 */ + u8 wires; /* 1/4/8 wires */ + int gpio_cd; /* or -EINVAL */ + int gpio_wp; /* or -EINVAL */ + int ext_clock:1; /* use external pin for input clock */ +}; + +#if defined(CONFIG_TWL4030_CORE) && \ + (defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE) || \ + defined(CONFIG_MMC_OMAP_HS) || defined(CONFIG_MMC_OMAP_HS_MODULE)) + +void twl4030_mmc_init(struct twl4030_hsmmc_info *); + +#else + +static inline void twl4030_mmc_init(struct twl4030_hsmmc_info *info) +{ +} + +#endif diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c index b1393673d95..dacb41f130c 100644 --- a/arch/arm/mach-omap2/mux.c +++ b/arch/arm/mach-omap2/mux.c @@ -203,6 +203,15 @@ MUX_CFG_24XX("AE9_2430_USB0HS_NXT", 0x13D, 0, 0, 0, 1) MUX_CFG_24XX("AC7_2430_USB0HS_DATA7", 0x13E, 0, 0, 0, 1) /* 2430 McBSP */ +MUX_CFG_24XX("AD6_2430_MCBSP_CLKS", 0x011E, 0, 0, 0, 1) + +MUX_CFG_24XX("AB2_2430_MCBSP1_CLKR", 0x011A, 0, 0, 0, 1) +MUX_CFG_24XX("AD5_2430_MCBSP1_FSR", 0x011B, 0, 0, 0, 1) +MUX_CFG_24XX("AA1_2430_MCBSP1_DX", 0x011C, 0, 0, 0, 1) +MUX_CFG_24XX("AF3_2430_MCBSP1_DR", 0x011D, 0, 0, 0, 1) +MUX_CFG_24XX("AB3_2430_MCBSP1_FSX", 0x011F, 0, 0, 0, 1) +MUX_CFG_24XX("Y9_2430_MCBSP1_CLKX", 0x0120, 0, 0, 0, 1) + MUX_CFG_24XX("AC10_2430_MCBSP2_FSX", 0x012E, 1, 0, 0, 1) MUX_CFG_24XX("AD16_2430_MCBSP2_CLX", 0x012F, 1, 0, 0, 1) MUX_CFG_24XX("AE13_2430_MCBSP2_DX", 0x0130, 1, 0, 0, 1) @@ -211,6 +220,31 @@ MUX_CFG_24XX("AC10_2430_MCBSP2_FSX_OFF",0x012E, 0, 0, 0, 1) MUX_CFG_24XX("AD16_2430_MCBSP2_CLX_OFF",0x012F, 0, 0, 0, 1) MUX_CFG_24XX("AE13_2430_MCBSP2_DX_OFF", 0x0130, 0, 0, 0, 1) MUX_CFG_24XX("AD13_2430_MCBSP2_DR_OFF", 0x0131, 0, 0, 0, 1) + +MUX_CFG_24XX("AC9_2430_MCBSP3_CLKX", 0x0103, 0, 0, 0, 1) +MUX_CFG_24XX("AE4_2430_MCBSP3_FSX", 0x0104, 0, 0, 0, 1) +MUX_CFG_24XX("AE2_2430_MCBSP3_DR", 0x0105, 0, 0, 0, 1) +MUX_CFG_24XX("AF4_2430_MCBSP3_DX", 0x0106, 0, 0, 0, 1) + +MUX_CFG_24XX("N3_2430_MCBSP4_CLKX", 0x010B, 1, 0, 0, 1) +MUX_CFG_24XX("AD23_2430_MCBSP4_DR", 0x010C, 1, 0, 0, 1) +MUX_CFG_24XX("AB25_2430_MCBSP4_DX", 0x010D, 1, 0, 0, 1) +MUX_CFG_24XX("AC25_2430_MCBSP4_FSX", 0x010E, 1, 0, 0, 1) + +MUX_CFG_24XX("AE16_2430_MCBSP5_CLKX", 0x00ED, 1, 0, 0, 1) +MUX_CFG_24XX("AF12_2430_MCBSP5_FSX", 0x00ED, 1, 0, 0, 1) +MUX_CFG_24XX("K7_2430_MCBSP5_DX", 0x00EF, 1, 0, 0, 1) +MUX_CFG_24XX("M1_2430_MCBSP5_DR", 0x00F0, 1, 0, 0, 1) + +/* 2430 MCSPI1 */ +MUX_CFG_24XX("Y18_2430_MCSPI1_CLK", 0x010F, 0, 0, 0, 1) +MUX_CFG_24XX("AD15_2430_MCSPI1_SIMO", 0x0110, 0, 0, 0, 1) +MUX_CFG_24XX("AE17_2430_MCSPI1_SOMI", 0x0111, 0, 0, 0, 1) +MUX_CFG_24XX("U1_2430_MCSPI1_CS0", 0x0112, 0, 0, 0, 1) + +/* Touchscreen GPIO */ +MUX_CFG_24XX("AF19_2430_GPIO_85", 0x0113, 3, 0, 0, 1) + }; #define OMAP24XX_PINS_SZ ARRAY_SIZE(omap24xx_pins) @@ -417,6 +451,14 @@ MUX_CFG_34XX("AD2_3430_USB3FS_PHY_MM3_TXDAT", 0x188, MUX_CFG_34XX("AC1_3430_USB3FS_PHY_MM3_TXEN_N", 0x18a, OMAP34XX_MUX_MODE6 | OMAP34XX_PIN_OUTPUT) + +/* 34XX GPIO - bidirectional, unless the name has an "_OUT" suffix. + * No internal pullup/pulldown without "_UP" or "_DOWN" suffix. + */ +MUX_CFG_34XX("AH8_34XX_GPIO29", 0x5fa, + OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) +MUX_CFG_34XX("J25_34XX_GPIO170", 0x1c6, + OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT) }; #define OMAP34XX_PINS_SZ ARRAY_SIZE(omap34xx_pins) @@ -452,7 +494,7 @@ static void __init_or_module omap2_cfg_debug(const struct pin_config *cfg, u16 r #endif #ifdef CONFIG_ARCH_OMAP24XX -int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg) +static int __init_or_module omap24xx_cfg_reg(const struct pin_config *cfg) { static DEFINE_SPINLOCK(mux_spin_lock); unsigned long flags; diff --git a/arch/arm/mach-omap2/usb-tusb6010.c b/arch/arm/mach-omap2/usb-tusb6010.c index 10ef464d6be..15e509013de 100644 --- a/arch/arm/mach-omap2/usb-tusb6010.c +++ b/arch/arm/mach-omap2/usb-tusb6010.c @@ -12,11 +12,11 @@ #include <linux/errno.h> #include <linux/delay.h> #include <linux/platform_device.h> +#include <linux/gpio.h> #include <linux/usb/musb.h> #include <mach/gpmc.h> -#include <mach/gpio.h> #include <mach/mux.h> @@ -292,12 +292,12 @@ tusb6010_setup_interface(struct musb_hdrc_platform_data *data, ); /* IRQ */ - status = omap_request_gpio(irq); + status = gpio_request(irq, "TUSB6010 irq"); if (status < 0) { printk(error, 3, status); return status; } - omap_set_gpio_direction(irq, 1); + gpio_direction_input(irq); tusb_resources[2].start = irq + IH_GPIO_BASE; /* set up memory timings ... can speed them up later */ |