From: Pavel Machek <pavel@ucw.cz> To: Arve Hj?nnev?g <arve@android.com>, kernel list <linux-kernel@vger.kernel.org>, linux-arm-kernel <linux-arm-kernel@lists.infradead.org>, Brian Swetland <swetland@google.com> Subject: dream: glue for mmc controller Date: Tue, 3 Nov 2009 11:53:20 +0100 [thread overview] Message-ID: <20091103105319.GA2492@elf.ucw.cz> (raw) This is what I came up with (relative to the previous patches). Unfortunately, it does not quite work: mmc controller is detected, but it hangs trying to access the card. Good news is that GPIO support seems to work, and I am able to flash the keyboard backlight. Does anyone have an idea what is wrong? Do I need some more infrastructure to set up (DMA transfers or something?)? I'm only setting up one mmc channel; I believe the other one is for wifi, and it should work like this...? Pavel diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 91e6f5c..16c0faa 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -6,4 +6,4 @@ obj-y += clock.o clock-7x01a.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o -obj-$(CONFIG_MACH_TROUT) += board-dream.o +obj-$(CONFIG_MACH_TROUT) += board-dream.o board-dream-mmc.o board-dream-gpio.o generic_gpio.o diff --git a/arch/arm/mach-msm/board-dream-gpio.c b/arch/arm/mach-msm/board-dream-gpio.c new file mode 100644 index 0000000..7e86a99 --- /dev/null +++ b/arch/arm/mach-msm/board-dream-gpio.c @@ -0,0 +1,301 @@ +/* arch/arm/mach-msm/board-dream-gpio.c + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/irq.h> +#include <linux/pm.h> +#include <linux/sysdev.h> + +#include <asm/io.h> +#include <asm/gpio.h> +#include <asm/mach-types.h> + +#include "board-dream.h" +#include "gpio_chip.h" + +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_dream." + +static uint cpld_usb_h2w_sw; +module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); + +static uint8_t dream_cpld_shadow[4] = { +#if defined(CONFIG_MSM_DEBUG_UART1) + /* H2W pins <-> UART1 */ + [0] = 0x40, // for serial debug, low current +#else + /* H2W pins <-> UART3, Bluetooth <-> UART1 */ + [0] = 0x80, // for serial debug, low current +#endif + [1] = 0x04, // I2C_PULL + [3] = 0x04, // mmdi 32k en +}; +static uint8_t dream_int_mask[2] = { + [0] = 0xff, /* mask all interrupts */ + [1] = 0xff, +}; +static uint8_t dream_sleep_int_mask[] = { + [0] = 0xff, + [1] = 0xff, +}; +static int dream_suspended; + +static int dream_gpio_read(struct gpio_chip *chip, unsigned n) +{ + uint8_t b; + int reg; + if (n >= TROUT_GPIO_VIRTUAL_BASE) + n += TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET; + b = 1U << (n & 7); + reg = (n & 0x78) >> 2; // assumes base is 128 + return !!(readb(TROUT_CPLD_BASE + reg) & b); +} + +static void update_pwrsink(unsigned gpio, unsigned on) +{ + switch(gpio) { + case TROUT_GPIO_UI_LED_EN: + break; + case TROUT_GPIO_QTKEY_LED_EN: + break; + } +} + +static uint8_t dream_gpio_write_shadow(unsigned n, unsigned on) +{ + uint8_t b = 1U << (n & 7); + int reg = (n & 0x78) >> 2; // assumes base is 128 + + if(on) + return dream_cpld_shadow[reg >> 1] |= b; + else + return dream_cpld_shadow[reg >> 1] &= ~b; +} + +static int dream_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + int reg = (n & 0x78) >> 2; // assumes base is 128 + unsigned long flags; + uint8_t reg_val; + + if ((reg >> 1) >= ARRAY_SIZE(dream_cpld_shadow)) { + printk(KERN_ERR "dream_gpio_write called on input %d\n", n); + return -ENOTSUPP; + } + + local_irq_save(flags); + update_pwrsink(n, on); + reg_val = dream_gpio_write_shadow(n, on); + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); + return 0; +} + +static int dream_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags) +{ + if(flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) + dream_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH); + return 0; +} + +static int dream_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + if ((gpio < TROUT_GPIO_BANK0_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK0_LAST_INT_SOURCE) && + (gpio < TROUT_GPIO_BANK1_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK1_LAST_INT_SOURCE)) + return -ENOENT; + *irqp = TROUT_GPIO_TO_INT(gpio); + if(irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +static void dream_gpio_irq_ack(unsigned int irq) +{ + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_STAT_REG(bank); + /*printk(KERN_INFO "dream_gpio_irq_ack irq %d\n", irq);*/ + writeb(mask, TROUT_CPLD_BASE + reg); +} + +static void dream_gpio_irq_mask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = dream_int_mask[bank] |= mask; + /*printk(KERN_INFO "dream_gpio_irq_mask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!dream_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +static void dream_gpio_irq_unmask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = dream_int_mask[bank] &= ~mask; + /*printk(KERN_INFO "dream_gpio_irq_unmask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!dream_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +int dream_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned long flags; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + + local_irq_save(flags); + if(on) + dream_sleep_int_mask[bank] &= ~mask; + else + dream_sleep_int_mask[bank] |= mask; + local_irq_restore(flags); + return 0; +} + +static void dream_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int j, m; + unsigned v; + int bank; + int stat_reg; + int int_base = TROUT_INT_START; + uint8_t int_mask; + + for (bank = 0; bank < 2; bank++) { + stat_reg = TROUT_BANK_TO_STAT_REG(bank); + v = readb(TROUT_CPLD_BASE + stat_reg); + int_mask = dream_int_mask[bank]; + if (v & int_mask) { + writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg); + printk(KERN_ERR "dream_gpio_irq_handler: got masked " + "interrupt: %d:%02x\n", bank, v & int_mask); + } + v &= ~int_mask; + while (v) { + m = v & -v; + j = fls(m) - 1; + /*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b" + "it %d irq %d\n", bank, v, m, j, int_base + j);*/ + v &= ~m; + generic_handle_irq(int_base + j); + } + int_base += TROUT_INT_BANK0_COUNT; + } + desc->chip->ack(irq); +} + +static int dream_sysdev_suspend(struct sys_device *dev, pm_message_t state) +{ + dream_suspended = 1; + writeb(dream_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(dream_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + writeb(dream_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT0_REG); + writeb(dream_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT1_REG); + return 0; +} + +int dream_sysdev_resume(struct sys_device *dev) +{ + writeb(dream_int_mask[0], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(dream_int_mask[1], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + dream_suspended = 0; + return 0; +} + +static struct irq_chip dream_gpio_irq_chip = { + .name = "dreamgpio", + .ack = dream_gpio_irq_ack, + .mask = dream_gpio_irq_mask, + .unmask = dream_gpio_irq_unmask, + .set_wake = dream_gpio_irq_set_wake, + //.set_type = dream_gpio_irq_set_type, +}; + +static struct gpio_chip dream_gpio_chip = { + .start = TROUT_GPIO_START, + .end = TROUT_GPIO_END, + .configure = dream_gpio_configure, + .get_irq_num = dream_gpio_get_irq_num, + .read = dream_gpio_read, + .write = dream_gpio_write, +// .read_detect_status = dream_gpio_read_detect_status, +// .clear_detect_status = dream_gpio_clear_detect_status +}; + +struct sysdev_class dream_sysdev_class = { + .name = "dreamgpio_irq", + .suspend = dream_sysdev_suspend, + .resume = dream_sysdev_resume, +}; + +static struct sys_device dream_irq_device = { + .cls = &dream_sysdev_class, +}; + +static int __init dream_init_gpio(void) +{ + int i; + + if (!machine_is_trout()) + return 0; + + /* adjust GPIOs based on bootloader request */ + pr_info("dream_init_gpio: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); + dream_gpio_write_shadow(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); + + for(i = 0; i < ARRAY_SIZE(dream_cpld_shadow); i++) + writeb(dream_cpld_shadow[i], TROUT_CPLD_BASE + i * 2); + + for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) { + set_irq_chip(i, &dream_gpio_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + register_gpio_chip(&dream_gpio_chip); + + set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH); + set_irq_chained_handler(MSM_GPIO_TO_INT(17), dream_gpio_irq_handler); + set_irq_wake(MSM_GPIO_TO_INT(17), 1); + + if(sysdev_class_register(&dream_sysdev_class) == 0) + sysdev_register(&dream_irq_device); + + return 0; +} + +postcore_initcall(dream_init_gpio); diff --git a/arch/arm/mach-msm/board-dream-mmc.c b/arch/arm/mach-msm/board-dream-mmc.c new file mode 100644 index 0000000..1b65ece --- /dev/null +++ b/arch/arm/mach-msm/board-dream-mmc.c @@ -0,0 +1,240 @@ +/* linux/arch/arm/mach-msm/board-dream-mmc.c + * Author: Brian Swetland <swetland@google.com> + * + * GPLv2. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/err.h> +#include <linux/debugfs.h> + +#include <asm/gpio.h> +#include <asm/io.h> + +#include <mach/vreg.h> + +#include <mach/mmc.h> + +#include "devices.h" +#include "board-dream.h" +#include "proc_comm.h" + +#define DEBUG_SDSLOT_VDD 1 + +extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags); + +/* ---- COMMON ---- */ +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for(n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +/* ---- SDCARD ---- */ + +static uint32_t sdcard_on_gpio_table[] = { + PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ +}; + +static uint32_t sdcard_off_gpio_table[] = { + PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ +}; + +static uint opt_disable_sdcard; + +static int __init dream_disablesdcard_setup(char *str) +{ + int cal = simple_strtol(str, NULL, 0); + + opt_disable_sdcard = cal; + return 1; +} + +__setup("board_dream.disable_sdcard=", dream_disablesdcard_setup); + +static struct vreg *vreg_sdslot; /* SD slot power */ + +struct mmc_vdd_xlat { + int mask; + int level; +}; + +static struct mmc_vdd_xlat mmc_vdd_table[] = { + { MMC_VDD_165_195, 1800 }, + { MMC_VDD_20_21, 2050 }, + { MMC_VDD_21_22, 2150 }, + { MMC_VDD_22_23, 2250 }, + { MMC_VDD_23_24, 2350 }, + { MMC_VDD_24_25, 2450 }, + { MMC_VDD_25_26, 2550 }, + { MMC_VDD_26_27, 2650 }, + { MMC_VDD_27_28, 2750 }, + { MMC_VDD_28_29, 2850 }, + { MMC_VDD_29_30, 2950 }, +}; + +static unsigned int sdslot_vdd = 0xffffffff; +static unsigned int sdslot_vreg_enabled; + +static uint32_t dream_sdslot_switchvdd(struct device *dev, unsigned int vdd) +{ + int i, rc; + + BUG_ON(!vreg_sdslot); + + if (vdd == sdslot_vdd) + return 0; + + sdslot_vdd = vdd; + + if (vdd == 0) { +#if DEBUG_SDSLOT_VDD + printk("%s: Disabling SD slot power\n", __func__); +#endif + config_gpio_table(sdcard_off_gpio_table, + ARRAY_SIZE(sdcard_off_gpio_table)); + vreg_disable(vreg_sdslot); + sdslot_vreg_enabled = 0; + return 0; + } + + if (!sdslot_vreg_enabled) { + rc = vreg_enable(vreg_sdslot); + if (rc) { + printk(KERN_ERR "%s: Error enabling vreg (%d)\n", + __func__, rc); + } + config_gpio_table(sdcard_on_gpio_table, + ARRAY_SIZE(sdcard_on_gpio_table)); + sdslot_vreg_enabled = 1; + } + + for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) { + if (mmc_vdd_table[i].mask == (1 << vdd)) { +#if DEBUG_SDSLOT_VDD + printk("%s: Setting level to %u\n", + __func__, mmc_vdd_table[i].level); +#endif + rc = vreg_set_level(vreg_sdslot, + mmc_vdd_table[i].level); + if (rc) { + printk(KERN_ERR + "%s: Error setting vreg level (%d)\n", + __func__, rc); + } + return 0; + } + } + + printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd); + return 0; +} + +static unsigned int dream_sdslot_status(struct device *dev) +{ + unsigned int status; + + status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N); + return (!status); +} + +#define TROUT_MMC_VDD MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \ + | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \ + | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \ + | MMC_VDD_28_29 | MMC_VDD_29_30 + +static struct mmc_platform_data dream_sdslot_data = { + .ocr_mask = TROUT_MMC_VDD, + .status = dream_sdslot_status, + .translate_vdd = dream_sdslot_switchvdd, +}; + +int __init dream_init_mmc(unsigned int sys_rev) +{ + sdslot_vreg_enabled = 0; + + vreg_sdslot = vreg_get(0, "gp6"); + if (IS_ERR(vreg_sdslot)) + return PTR_ERR(vreg_sdslot); + + set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1); + + if (!opt_disable_sdcard) + msm_add_sdcc(2, &dream_sdslot_data, + TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0); + else + printk(KERN_INFO "dream: SD-Card interface disabled\n"); + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +static int dreammmc_dbg_sd_pwr_set(void *data, u64 val) +{ + dream_sdslot_switchvdd(NULL, (unsigned int) val); + return 0; +} + +static int dreammmc_dbg_sd_pwr_get(void *data, u64 *val) +{ + *val = sdslot_vdd; + return 0; +} + +static int dreammmc_dbg_sd_cd_set(void *data, u64 val) +{ + return -ENOSYS; +} + +static int dreammmc_dbg_sd_cd_get(void *data, u64 *val) +{ + *val = dream_sdslot_status(NULL); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(dreammmc_dbg_sd_pwr_fops, + dreammmc_dbg_sd_pwr_get, + dreammmc_dbg_sd_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(dreammmc_dbg_sd_cd_fops, + dreammmc_dbg_sd_cd_get, + dreammmc_dbg_sd_cd_set, "%llu\n"); + +static int __init dreammmc_dbg_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("dreammmc_dbg", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("sd_pwr", 0644, dent, NULL, + &dreammmc_dbg_sd_pwr_fops); + debugfs_create_file("sd_cd", 0644, dent, NULL, + &dreammmc_dbg_sd_cd_fops); + + return 0; +} + +device_initcall(dreammmc_dbg_init); + +#endif diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-dream.c index a0877a3..49de63b 100644 --- a/arch/arm/mach-msm/board-dream.c +++ b/arch/arm/mach-msm/board-dream.c @@ -12,16 +12,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * + * This machine is also known by its codename, "trout". */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/setup.h> +#include <asm/gpio.h> #include <mach/board.h> #include <mach/hardware.h> @@ -30,6 +33,9 @@ #include "devices.h" #include "board-dream.h" +extern int dream_init_mmc(unsigned int); + + static struct platform_device *devices[] __initdata = { &msm_device_uart3, &msm_device_smd, @@ -40,12 +46,12 @@ static struct platform_device *devices[] __initdata = { extern struct sys_timer msm_timer; -static void __init trout_init_irq(void) +static void __init dream_init_irq(void) { msm_init_irq(); } -static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, +static void __init dream_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { mi->nr_banks=1; @@ -54,12 +60,34 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, mi->bank[0].size = (101*1024*1024); } -static void __init trout_init(void) +static void __init dream_init(void) { + int rc; platform_add_devices(devices, ARRAY_SIZE(devices)); + + rc = dream_init_mmc(system_rev); + if (rc) + printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); + + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); } -static struct map_desc trout_io_desc[] __initdata = { +static struct map_desc dream_io_desc[] __initdata = { { .virtual = TROUT_CPLD_BASE, .pfn = __phys_to_pfn(TROUT_CPLD_START), @@ -68,10 +96,10 @@ static struct map_desc trout_io_desc[] __initdata = { } }; -static void __init trout_map_io(void) +static void __init dream_map_io(void) { msm_map_common_io(); - iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc)); + iotable_init(dream_io_desc, ARRAY_SIZE(dream_io_desc)); #ifdef CONFIG_MSM_DEBUG_UART3 /* route UART3 to the "H2W" extended usb connector */ @@ -87,9 +115,9 @@ MACHINE_START(TROUT, "HTC Dream") .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif .boot_params = 0x10000100, - .fixup = trout_fixup, - .map_io = trout_map_io, - .init_irq = trout_init_irq, - .init_machine = trout_init, + .fixup = dream_fixup, + .map_io = dream_map_io, + .init_irq = dream_init_irq, + .init_machine = dream_init, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-dream.h b/arch/arm/mach-msm/board-dream.h index 4f345a5..cdfb0ae 100644 --- a/arch/arm/mach-msm/board-dream.h +++ b/arch/arm/mach-msm/board-dream.h @@ -1,5 +1,153 @@ +#define MSM_SMI_BASE 0x00000000 +#define MSM_SMI_SIZE 0x00800000 + +#define MSM_EBI_BASE 0x10000000 +#define MSM_EBI_SIZE 0x06e00000 + +#define MSM_PMEM_GPU0_BASE 0x00000000 +#define MSM_PMEM_GPU0_SIZE 0x00700000 + +#define MSM_PMEM_MDP_BASE 0x02000000 +#define MSM_PMEM_MDP_SIZE 0x00800000 + +#define MSM_PMEM_ADSP_BASE 0x02800000 +#define MSM_PMEM_ADSP_SIZE 0x00800000 + +#define MSM_PMEM_CAMERA_BASE 0x03000000 +#define MSM_PMEM_CAMERA_SIZE 0x00800000 + +#define MSM_FB_BASE 0x03800000 +#define MSM_FB_SIZE 0x00100000 + +#define MSM_LINUX_BASE MSM_EBI_BASE +#define MSM_LINUX_SIZE 0x06500000 + +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE + +#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000 +#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K + +#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE) +#error invalid memory map +#endif + +#define DECLARE_MSM_IOMAP +#include <mach/msm_iomap.h> + +#define TROUT_4_BALL_UP_0 1 +#define TROUT_4_BALL_LEFT_0 18 +#define TROUT_4_BALL_DOWN_0 57 +#define TROUT_4_BALL_RIGHT_0 91 + +#define TROUT_5_BALL_UP_0 94 +#define TROUT_5_BALL_LEFT_0 18 +#define TROUT_5_BALL_DOWN_0 90 +#define TROUT_5_BALL_RIGHT_0 19 + +#define TROUT_POWER_KEY 20 + +#define TROUT_4_TP_LS_EN 19 +#define TROUT_5_TP_LS_EN 1 + #define TROUT_CPLD_BASE 0xE8100000 #define TROUT_CPLD_START 0x98000000 #define TROUT_CPLD_SIZE SZ_4K +#define TROUT_GPIO_CABLE_IN1 (83) +#define TROUT_GPIO_CABLE_IN2 (49) + +#define TROUT_GPIO_START (128) + +#define TROUT_GPIO_INT_MASK0_REG (0x0c) +#define TROUT_GPIO_INT_STAT0_REG (0x0e) +#define TROUT_GPIO_INT_MASK1_REG (0x14) +#define TROUT_GPIO_INT_STAT1_REG (0x10) + +#define TROUT_GPIO_HAPTIC_PWM (28) +#define TROUT_GPIO_PS_HOLD (25) + +#define TROUT_GPIO_MISC2_BASE (TROUT_GPIO_START + 0x00) +#define TROUT_GPIO_MISC3_BASE (TROUT_GPIO_START + 0x08) +#define TROUT_GPIO_MISC4_BASE (TROUT_GPIO_START + 0x10) +#define TROUT_GPIO_MISC5_BASE (TROUT_GPIO_START + 0x18) +#define TROUT_GPIO_INT2_BASE (TROUT_GPIO_START + 0x20) +#define TROUT_GPIO_MISC1_BASE (TROUT_GPIO_START + 0x28) +#define TROUT_GPIO_VIRTUAL_BASE (TROUT_GPIO_START + 0x30) +#define TROUT_GPIO_INT5_BASE (TROUT_GPIO_START + 0x48) + +#define TROUT_GPIO_CHARGER_EN (TROUT_GPIO_MISC2_BASE + 0) +#define TROUT_GPIO_ISET (TROUT_GPIO_MISC2_BASE + 1) +#define TROUT_GPIO_H2W_DAT_DIR (TROUT_GPIO_MISC2_BASE + 2) +#define TROUT_GPIO_H2W_CLK_DIR (TROUT_GPIO_MISC2_BASE + 3) +#define TROUT_GPIO_H2W_DAT_GPO (TROUT_GPIO_MISC2_BASE + 4) +#define TROUT_GPIO_H2W_CLK_GPO (TROUT_GPIO_MISC2_BASE + 5) +#define TROUT_GPIO_H2W_SEL0 (TROUT_GPIO_MISC2_BASE + 6) +#define TROUT_GPIO_H2W_SEL1 (TROUT_GPIO_MISC2_BASE + 7) + +#define TROUT_GPIO_SPOTLIGHT_EN (TROUT_GPIO_MISC3_BASE + 0) +#define TROUT_GPIO_FLASH_EN (TROUT_GPIO_MISC3_BASE + 1) +#define TROUT_GPIO_I2C_PULL (TROUT_GPIO_MISC3_BASE + 2) +#define TROUT_GPIO_TP_I2C_PULL (TROUT_GPIO_MISC3_BASE + 3) +#define TROUT_GPIO_TP_EN (TROUT_GPIO_MISC3_BASE + 4) +#define TROUT_GPIO_JOG_EN (TROUT_GPIO_MISC3_BASE + 5) +#define TROUT_GPIO_UI_LED_EN (TROUT_GPIO_MISC3_BASE + 6) +#define TROUT_GPIO_QTKEY_LED_EN (TROUT_GPIO_MISC3_BASE + 7) + +#define TROUT_GPIO_VCM_PWDN (TROUT_GPIO_MISC4_BASE + 0) +#define TROUT_GPIO_USB_H2W_SW (TROUT_GPIO_MISC4_BASE + 1) +#define TROUT_GPIO_COMPASS_RST_N (TROUT_GPIO_MISC4_BASE + 2) +#define TROUT_GPIO_HAPTIC_EN_UP (TROUT_GPIO_MISC4_BASE + 3) +#define TROUT_GPIO_HAPTIC_EN_MAIN (TROUT_GPIO_MISC4_BASE + 4) +#define TROUT_GPIO_USB_PHY_RST_N (TROUT_GPIO_MISC4_BASE + 5) +#define TROUT_GPIO_WIFI_PA_RESETX (TROUT_GPIO_MISC4_BASE + 6) +#define TROUT_GPIO_WIFI_EN (TROUT_GPIO_MISC4_BASE + 7) + +#define TROUT_GPIO_BT_32K_EN (TROUT_GPIO_MISC5_BASE + 0) +#define TROUT_GPIO_MAC_32K_EN (TROUT_GPIO_MISC5_BASE + 1) +#define TROUT_GPIO_MDDI_32K_EN (TROUT_GPIO_MISC5_BASE + 2) +#define TROUT_GPIO_COMPASS_32K_EN (TROUT_GPIO_MISC5_BASE + 3) + +#define TROUT_GPIO_NAVI_ACT_N (TROUT_GPIO_INT2_BASE + 0) +#define TROUT_GPIO_COMPASS_IRQ (TROUT_GPIO_INT2_BASE + 1) +#define TROUT_GPIO_SLIDING_DET (TROUT_GPIO_INT2_BASE + 2) +#define TROUT_GPIO_AUD_HSMIC_DET_N (TROUT_GPIO_INT2_BASE + 3) +#define TROUT_GPIO_SD_DOOR_N (TROUT_GPIO_INT2_BASE + 4) +#define TROUT_GPIO_CAM_BTN_STEP1_N (TROUT_GPIO_INT2_BASE + 5) +#define TROUT_GPIO_CAM_BTN_STEP2_N (TROUT_GPIO_INT2_BASE + 6) +#define TROUT_GPIO_TP_ATT_N (TROUT_GPIO_INT2_BASE + 7) +#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE (TROUT_GPIO_NAVI_ACT_N) +#define TROUT_GPIO_BANK0_LAST_INT_SOURCE (TROUT_GPIO_TP_ATT_N) + +#define TROUT_GPIO_H2W_DAT_GPI (TROUT_GPIO_MISC1_BASE + 0) +#define TROUT_GPIO_H2W_CLK_GPI (TROUT_GPIO_MISC1_BASE + 1) +#define TROUT_GPIO_CPLD128_VER_0 (TROUT_GPIO_MISC1_BASE + 4) +#define TROUT_GPIO_CPLD128_VER_1 (TROUT_GPIO_MISC1_BASE + 5) +#define TROUT_GPIO_CPLD128_VER_2 (TROUT_GPIO_MISC1_BASE + 6) +#define TROUT_GPIO_CPLD128_VER_3 (TROUT_GPIO_MISC1_BASE + 7) + +#define TROUT_GPIO_SDMC_CD_N (TROUT_GPIO_VIRTUAL_BASE + 0) +#define TROUT_GPIO_END (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_LAST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) + +#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \ + (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE) + +#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS) +#define TROUT_INT_BANK0_COUNT (8) +#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT) +#define TROUT_INT_BANK1_COUNT (1) +#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \ + TROUT_INT_BANK1_COUNT - 1) +#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \ + (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \ + (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n))) + +#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT) +#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7)) +#define TROUT_BANK_TO_MASK_REG(bank) \ + (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG) +#define TROUT_BANK_TO_STAT_REG(bank) \ + (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG) diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 31b6b30..afec7c2 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -155,6 +155,7 @@ struct platform_device msm_device_smd = { .id = -1, }; + static struct resource resources_sdc1[] = { { .start = MSM_SDC1_PHYS, @@ -163,8 +164,19 @@ static struct resource resources_sdc1[] = { }, { .start = INT_SDC1_0, + .end = INT_SDC1_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC1_1, .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -181,8 +193,19 @@ static struct resource resources_sdc2[] = { }, { .start = INT_SDC2_0, + .end = INT_SDC2_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC2_1, .end = INT_SDC2_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -199,8 +222,19 @@ static struct resource resources_sdc3[] = { }, { .start = INT_SDC3_0, + .end = INT_SDC3_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC3_1, .end = INT_SDC3_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -217,8 +251,19 @@ static struct resource resources_sdc4[] = { }, { .start = INT_SDC4_0, + .end = INT_SDC4_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC4_1, .end = INT_SDC4_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -266,3 +311,35 @@ struct platform_device msm_device_sdc4 = { .coherent_dma_mask = 0xffffffff, }, }; + + +static struct platform_device *msm_sdcc_devices[] __initdata = { + &msm_device_sdc1, + &msm_device_sdc2, + &msm_device_sdc3, + &msm_device_sdc4, +}; + +int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags) +{ + struct platform_device *pdev; + struct resource *res; + + if (controller < 1 || controller > 4) + return -EINVAL; + + pdev = msm_sdcc_devices[controller-1]; + pdev->dev.platform_data = plat; + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); + if (!res) + return -EINVAL; + else if (stat_irq) { + res->start = res->end = stat_irq; + res->flags &= ~IORESOURCE_DISABLED; + res->flags |= stat_irq_flags; + } + + return platform_device_register(pdev); +} diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c new file mode 100644 index 0000000..fe24d38 --- /dev/null +++ b/arch/arm/mach-msm/generic_gpio.c @@ -0,0 +1,274 @@ +/* arch/arm/mach-msm/generic_gpio.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <asm/gpio.h> +#include "gpio_chip.h" + +#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5) + +struct gpio_state { + unsigned long flags; + int refcount; +}; + +static DEFINE_SPINLOCK(gpio_chips_lock); +static LIST_HEAD(gpio_chip_list); +static struct gpio_chip **gpio_chip_array; +static unsigned long gpio_chip_array_size; + +int register_gpio_chip(struct gpio_chip *new_gpio_chip) +{ + int err = 0; + struct gpio_chip *gpio_chip; + int i; + unsigned long irq_flags; + unsigned int chip_array_start_index, chip_array_end_index; + + new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL); + if (new_gpio_chip->state == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate state\n"); + return -ENOMEM; + } + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start); + chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end); + if (chip_array_end_index >= gpio_chip_array_size) { + struct gpio_chip **new_gpio_chip_array; + unsigned long new_gpio_chip_array_size = chip_array_end_index + 1; + + new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC); + if (new_gpio_chip_array == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate array\n"); + err = -ENOMEM; + goto failed; + } + for (i = 0; i < gpio_chip_array_size; i++) + new_gpio_chip_array[i] = gpio_chip_array[i]; + for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++) + new_gpio_chip_array[i] = NULL; + gpio_chip_array = new_gpio_chip_array; + gpio_chip_array_size = new_gpio_chip_array_size; + } + list_for_each_entry(gpio_chip, &gpio_chip_list, list) { + if (gpio_chip->start > new_gpio_chip->end) { + list_add_tail(&new_gpio_chip->list, &gpio_chip->list); + goto added; + } + if (gpio_chip->end >= new_gpio_chip->start) { + printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n", + new_gpio_chip->start, new_gpio_chip->end, + gpio_chip->start, gpio_chip->end); + err = -EBUSY; + goto failed; + } + } + list_add_tail(&new_gpio_chip->list, &gpio_chip_list); +added: + for (i = chip_array_start_index; i <= chip_array_end_index; i++) { + if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start) + gpio_chip_array[i] = new_gpio_chip; + } +failed: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + if (err) + kfree(new_gpio_chip->state); + return err; +} + +static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio) +{ + unsigned long i; + struct gpio_chip *chip; + + i = GPIO_NUM_TO_CHIP_INDEX(gpio); + if (i >= gpio_chip_array_size) + return NULL; + chip = gpio_chip_array[i]; + if (chip == NULL) + return NULL; + list_for_each_entry_from(chip, &gpio_chip_list, list) { + if (gpio < chip->start) + return NULL; + if (gpio <= chip->end) + return chip; + } + return NULL; +} + +static int request_gpio(unsigned int gpio, unsigned long flags) +{ + int err = 0; + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip == NULL) { + err = -EINVAL; + goto err; + } + chip_index = gpio - chip->start; + if (chip->state[chip_index].refcount == 0) { + chip->configure(chip, gpio, flags); + chip->state[chip_index].flags = flags; + chip->state[chip_index].refcount++; + } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED)) + chip->state[chip_index].refcount++; + else + err = -EBUSY; +err: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return err; +} + +int gpio_request(unsigned gpio, const char *label) +{ + return request_gpio(gpio, 0); +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) { + chip_index = gpio - chip->start; + chip->state[chip_index].refcount--; + } + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_free); + +static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->get_irq_num) + ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} + +int gpio_to_irq(unsigned gpio) +{ + int ret, irq; + ret = gpio_get_irq_num(gpio, &irq, NULL); + if (ret) + return ret; + return irq; +} +EXPORT_SYMBOL(gpio_to_irq); + +int gpio_configure(unsigned int gpio, unsigned long flags) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) + ret = chip->configure(chip, gpio, flags); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_configure); + +int gpio_direction_input(unsigned gpio) +{ + return gpio_configure(gpio, GPIOF_INPUT); +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); + return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT); +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read) + ret = chip->read(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int on) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->write) + ret = chip->write(chip, gpio, on); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_read_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read_detect_status) + ret = chip->read_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_read_detect_status); + +int gpio_clear_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->clear_detect_status) + ret = chip->clear_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_clear_detect_status); diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h new file mode 100644 index 0000000..eab9f09 --- /dev/null +++ b/arch/arm/mach-msm/gpio_chip.h @@ -0,0 +1,38 @@ +/* arch/arm/mach-msm/gpio_chip.h + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_GPIO_CHIP_H +#define _LINUX_GPIO_CHIP_H + +#include <linux/list.h> + +struct gpio_chip { + struct list_head list; + struct gpio_state *state; + + unsigned int start; + unsigned int end; + + int (*configure)(struct gpio_chip *chip, unsigned int gpio, unsigned long flags); + int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp); + int (*read)(struct gpio_chip *chip, unsigned int gpio); + int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on); + int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio); + int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio); +}; + +int register_gpio_chip(struct gpio_chip *gpio_chip); + +#endif diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h new file mode 100644 index 0000000..61f410c --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw.h @@ -0,0 +1,100 @@ +/* arch/arm/mach-msm/gpio_hw.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H + +#include <mach/msm_iomap.h> + +/* see 80-VA736-2 Rev C pp 695-751 +** +** These are actually the *shadow* gpio registers, since the +** real ones (which allow full access) are only available to the +** ARM9 side of the world. +** +** Since the _BASE need to be page-aligned when we're mapping them +** to virtual addresses, adjust for the additional offset in these +** macros. +*/ + +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x10) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x14) +#define GPIO_OE_3 GPIO1_REG(0x18) +#define GPIO_OE_4 GPIO1_REG(0x1C) +#define GPIO_OE_5 GPIO1_REG(0x54) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x34) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x38) +#define GPIO_IN_3 GPIO1_REG(0x3C) +#define GPIO_IN_4 GPIO1_REG(0x40) +#define GPIO_IN_5 GPIO1_REG(0x44) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x70) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x74) +#define GPIO_INT_POS_3 GPIO1_REG(0x78) +#define GPIO_INT_POS_4 GPIO1_REG(0x7C) +#define GPIO_INT_POS_5 GPIO1_REG(0xBC) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0x80) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0x84) +#define GPIO_INT_EN_3 GPIO1_REG(0x88) +#define GPIO_INT_EN_4 GPIO1_REG(0x8C) +#define GPIO_INT_EN_5 GPIO1_REG(0xB8) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) + +#endif diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h new file mode 100644 index 0000000..590573f --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -0,0 +1,47 @@ +/* linux/include/asm-arm/arch-msm/gpio.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_GPIO_H +#define __ASM_ARCH_MSM_GPIO_H + +#include <linux/interrupt.h> + +int gpio_request(unsigned gpio, const char *label); +void gpio_free(unsigned gpio); +int gpio_direction_input(unsigned gpio); +int gpio_direction_output(unsigned gpio, int value); +int gpio_get_value(unsigned gpio); +void gpio_set_value(unsigned gpio, int value); +int gpio_to_irq(unsigned gpio); + +#include <asm-generic/gpio.h> + +/* extended gpio api */ + +#define GPIOF_IRQF_MASK 0x0000ffff /* use to specify edge detection without */ +#define GPIOF_IRQF_TRIGGER_NONE 0x00010000 /* IRQF_TRIGGER_NONE is 0 which also means "as already configured" */ +#define GPIOF_INPUT 0x00020000 +#define GPIOF_DRIVE_OUTPUT 0x00040000 +#define GPIOF_OUTPUT_LOW 0x00080000 +#define GPIOF_OUTPUT_HIGH 0x00100000 + +#define GPIOIRQF_SHARED 0x00000001 /* the irq line is shared with other inputs */ + +extern int gpio_configure(unsigned int gpio, unsigned long flags); +extern int gpio_read_detect_status(unsigned int gpio); +extern int gpio_clear_detect_status(unsigned int gpio); + +#endif diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index b31946e..7e0c1ac 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -69,6 +69,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) host->curr.mrq = NULL; host->curr.cmd = NULL; + printk("msm..._request_end\n"); if (mrq->data) mrq->data->bytes_xfered = host->curr.data_xfered; @@ -119,6 +120,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, unsigned long flags; struct mmc_request *mrq; + printk("data complete func\n"); spin_lock_irqsave(&host->lock, flags); mrq = host->curr.mrq; BUG_ON(!mrq); @@ -360,6 +362,8 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { void __iomem *base = host->base; + printk("start_command\n"); + if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { writel(0, base + MMCICOMMAND); udelay(2 + ((5 * 1000000) / host->clk_rate)); @@ -483,6 +487,7 @@ msmsdcc_pio_irq(int irq, void *dev_id) void __iomem *base = host->base; uint32_t status; + printk("msmsdcc_pio_irq\n"); status = readl(base + MMCISTATUS); do { @@ -589,6 +594,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, { struct mmc_data *data = host->curr.data; + printk("handle_irq_data\n"); if (!data) return; @@ -696,6 +702,7 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->curr.mrq != NULL); WARN_ON(host->pwr == 0); + printk("msm..._request\n"); spin_lock_irqsave(&host->lock, flags); host->stats.reqs++; diff --git a/kernel/printk.c b/kernel/printk.c index 2c98b0b..5f37e88 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -714,10 +714,12 @@ asmlinkage int vprintk(const char *fmt, va_list args) printed_len += vscnprintf(printk_buf + printed_len, sizeof(printk_buf) - printed_len, fmt, args); +#if 0 { extern void printascii(const char *); printascii(printk_buf); } +#endif p = printk_buf; -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
WARNING: multiple messages have this Message-ID (diff)
From: pavel@ucw.cz (Pavel Machek) To: linux-arm-kernel@lists.infradead.org Subject: dream: glue for mmc controller Date: Tue, 3 Nov 2009 11:53:20 +0100 [thread overview] Message-ID: <20091103105319.GA2492@elf.ucw.cz> (raw) This is what I came up with (relative to the previous patches). Unfortunately, it does not quite work: mmc controller is detected, but it hangs trying to access the card. Good news is that GPIO support seems to work, and I am able to flash the keyboard backlight. Does anyone have an idea what is wrong? Do I need some more infrastructure to set up (DMA transfers or something?)? I'm only setting up one mmc channel; I believe the other one is for wifi, and it should work like this...? Pavel diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile index 91e6f5c..16c0faa 100644 --- a/arch/arm/mach-msm/Makefile +++ b/arch/arm/mach-msm/Makefile @@ -6,4 +6,4 @@ obj-y += clock.o clock-7x01a.o obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o -obj-$(CONFIG_MACH_TROUT) += board-dream.o +obj-$(CONFIG_MACH_TROUT) += board-dream.o board-dream-mmc.o board-dream-gpio.o generic_gpio.o diff --git a/arch/arm/mach-msm/board-dream-gpio.c b/arch/arm/mach-msm/board-dream-gpio.c new file mode 100644 index 0000000..7e86a99 --- /dev/null +++ b/arch/arm/mach-msm/board-dream-gpio.c @@ -0,0 +1,301 @@ +/* arch/arm/mach-msm/board-dream-gpio.c + * + * Copyright (C) 2008 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/irq.h> +#include <linux/pm.h> +#include <linux/sysdev.h> + +#include <asm/io.h> +#include <asm/gpio.h> +#include <asm/mach-types.h> + +#include "board-dream.h" +#include "gpio_chip.h" + +#undef MODULE_PARAM_PREFIX +#define MODULE_PARAM_PREFIX "board_dream." + +static uint cpld_usb_h2w_sw; +module_param_named(usb_h2w_sw, cpld_usb_h2w_sw, uint, 0); + +static uint8_t dream_cpld_shadow[4] = { +#if defined(CONFIG_MSM_DEBUG_UART1) + /* H2W pins <-> UART1 */ + [0] = 0x40, // for serial debug, low current +#else + /* H2W pins <-> UART3, Bluetooth <-> UART1 */ + [0] = 0x80, // for serial debug, low current +#endif + [1] = 0x04, // I2C_PULL + [3] = 0x04, // mmdi 32k en +}; +static uint8_t dream_int_mask[2] = { + [0] = 0xff, /* mask all interrupts */ + [1] = 0xff, +}; +static uint8_t dream_sleep_int_mask[] = { + [0] = 0xff, + [1] = 0xff, +}; +static int dream_suspended; + +static int dream_gpio_read(struct gpio_chip *chip, unsigned n) +{ + uint8_t b; + int reg; + if (n >= TROUT_GPIO_VIRTUAL_BASE) + n += TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET; + b = 1U << (n & 7); + reg = (n & 0x78) >> 2; // assumes base is 128 + return !!(readb(TROUT_CPLD_BASE + reg) & b); +} + +static void update_pwrsink(unsigned gpio, unsigned on) +{ + switch(gpio) { + case TROUT_GPIO_UI_LED_EN: + break; + case TROUT_GPIO_QTKEY_LED_EN: + break; + } +} + +static uint8_t dream_gpio_write_shadow(unsigned n, unsigned on) +{ + uint8_t b = 1U << (n & 7); + int reg = (n & 0x78) >> 2; // assumes base is 128 + + if(on) + return dream_cpld_shadow[reg >> 1] |= b; + else + return dream_cpld_shadow[reg >> 1] &= ~b; +} + +static int dream_gpio_write(struct gpio_chip *chip, unsigned n, unsigned on) +{ + int reg = (n & 0x78) >> 2; // assumes base is 128 + unsigned long flags; + uint8_t reg_val; + + if ((reg >> 1) >= ARRAY_SIZE(dream_cpld_shadow)) { + printk(KERN_ERR "dream_gpio_write called on input %d\n", n); + return -ENOTSUPP; + } + + local_irq_save(flags); + update_pwrsink(n, on); + reg_val = dream_gpio_write_shadow(n, on); + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); + return 0; +} + +static int dream_gpio_configure(struct gpio_chip *chip, unsigned int gpio, unsigned long flags) +{ + if(flags & (GPIOF_OUTPUT_LOW | GPIOF_OUTPUT_HIGH)) + dream_gpio_write(chip, gpio, flags & GPIOF_OUTPUT_HIGH); + return 0; +} + +static int dream_gpio_get_irq_num(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + if ((gpio < TROUT_GPIO_BANK0_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK0_LAST_INT_SOURCE) && + (gpio < TROUT_GPIO_BANK1_FIRST_INT_SOURCE || + gpio > TROUT_GPIO_BANK1_LAST_INT_SOURCE)) + return -ENOENT; + *irqp = TROUT_GPIO_TO_INT(gpio); + if(irqnumflagsp) + *irqnumflagsp = 0; + return 0; +} + +static void dream_gpio_irq_ack(unsigned int irq) +{ + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_STAT_REG(bank); + /*printk(KERN_INFO "dream_gpio_irq_ack irq %d\n", irq);*/ + writeb(mask, TROUT_CPLD_BASE + reg); +} + +static void dream_gpio_irq_mask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = dream_int_mask[bank] |= mask; + /*printk(KERN_INFO "dream_gpio_irq_mask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!dream_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +static void dream_gpio_irq_unmask(unsigned int irq) +{ + unsigned long flags; + uint8_t reg_val; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + int reg = TROUT_BANK_TO_MASK_REG(bank); + + local_irq_save(flags); + reg_val = dream_int_mask[bank] &= ~mask; + /*printk(KERN_INFO "dream_gpio_irq_unmask irq %d => %d:%02x\n", + irq, bank, reg_val);*/ + if (!dream_suspended) + writeb(reg_val, TROUT_CPLD_BASE + reg); + local_irq_restore(flags); +} + +int dream_gpio_irq_set_wake(unsigned int irq, unsigned int on) +{ + unsigned long flags; + int bank = TROUT_INT_TO_BANK(irq); + uint8_t mask = TROUT_INT_TO_MASK(irq); + + local_irq_save(flags); + if(on) + dream_sleep_int_mask[bank] &= ~mask; + else + dream_sleep_int_mask[bank] |= mask; + local_irq_restore(flags); + return 0; +} + +static void dream_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + int j, m; + unsigned v; + int bank; + int stat_reg; + int int_base = TROUT_INT_START; + uint8_t int_mask; + + for (bank = 0; bank < 2; bank++) { + stat_reg = TROUT_BANK_TO_STAT_REG(bank); + v = readb(TROUT_CPLD_BASE + stat_reg); + int_mask = dream_int_mask[bank]; + if (v & int_mask) { + writeb(v & int_mask, TROUT_CPLD_BASE + stat_reg); + printk(KERN_ERR "dream_gpio_irq_handler: got masked " + "interrupt: %d:%02x\n", bank, v & int_mask); + } + v &= ~int_mask; + while (v) { + m = v & -v; + j = fls(m) - 1; + /*printk(KERN_INFO "msm_gpio_irq_handler %d:%02x %02x b" + "it %d irq %d\n", bank, v, m, j, int_base + j);*/ + v &= ~m; + generic_handle_irq(int_base + j); + } + int_base += TROUT_INT_BANK0_COUNT; + } + desc->chip->ack(irq); +} + +static int dream_sysdev_suspend(struct sys_device *dev, pm_message_t state) +{ + dream_suspended = 1; + writeb(dream_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(dream_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + writeb(dream_sleep_int_mask[0], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT0_REG); + writeb(dream_sleep_int_mask[1], + TROUT_CPLD_BASE + TROUT_GPIO_INT_STAT1_REG); + return 0; +} + +int dream_sysdev_resume(struct sys_device *dev) +{ + writeb(dream_int_mask[0], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK0_REG); + writeb(dream_int_mask[1], TROUT_CPLD_BASE + TROUT_GPIO_INT_MASK1_REG); + dream_suspended = 0; + return 0; +} + +static struct irq_chip dream_gpio_irq_chip = { + .name = "dreamgpio", + .ack = dream_gpio_irq_ack, + .mask = dream_gpio_irq_mask, + .unmask = dream_gpio_irq_unmask, + .set_wake = dream_gpio_irq_set_wake, + //.set_type = dream_gpio_irq_set_type, +}; + +static struct gpio_chip dream_gpio_chip = { + .start = TROUT_GPIO_START, + .end = TROUT_GPIO_END, + .configure = dream_gpio_configure, + .get_irq_num = dream_gpio_get_irq_num, + .read = dream_gpio_read, + .write = dream_gpio_write, +// .read_detect_status = dream_gpio_read_detect_status, +// .clear_detect_status = dream_gpio_clear_detect_status +}; + +struct sysdev_class dream_sysdev_class = { + .name = "dreamgpio_irq", + .suspend = dream_sysdev_suspend, + .resume = dream_sysdev_resume, +}; + +static struct sys_device dream_irq_device = { + .cls = &dream_sysdev_class, +}; + +static int __init dream_init_gpio(void) +{ + int i; + + if (!machine_is_trout()) + return 0; + + /* adjust GPIOs based on bootloader request */ + pr_info("dream_init_gpio: cpld_usb_hw2_sw = %d\n", cpld_usb_h2w_sw); + dream_gpio_write_shadow(TROUT_GPIO_USB_H2W_SW, cpld_usb_h2w_sw); + + for(i = 0; i < ARRAY_SIZE(dream_cpld_shadow); i++) + writeb(dream_cpld_shadow[i], TROUT_CPLD_BASE + i * 2); + + for(i = TROUT_INT_START; i <= TROUT_INT_END; i++) { + set_irq_chip(i, &dream_gpio_irq_chip); + set_irq_handler(i, handle_edge_irq); + set_irq_flags(i, IRQF_VALID); + } + + register_gpio_chip(&dream_gpio_chip); + + set_irq_type(MSM_GPIO_TO_INT(17), IRQF_TRIGGER_HIGH); + set_irq_chained_handler(MSM_GPIO_TO_INT(17), dream_gpio_irq_handler); + set_irq_wake(MSM_GPIO_TO_INT(17), 1); + + if(sysdev_class_register(&dream_sysdev_class) == 0) + sysdev_register(&dream_irq_device); + + return 0; +} + +postcore_initcall(dream_init_gpio); diff --git a/arch/arm/mach-msm/board-dream-mmc.c b/arch/arm/mach-msm/board-dream-mmc.c new file mode 100644 index 0000000..1b65ece --- /dev/null +++ b/arch/arm/mach-msm/board-dream-mmc.c @@ -0,0 +1,240 @@ +/* linux/arch/arm/mach-msm/board-dream-mmc.c + * Author: Brian Swetland <swetland@google.com> + * + * GPLv2. + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/delay.h> +#include <linux/mmc/host.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/err.h> +#include <linux/debugfs.h> + +#include <asm/gpio.h> +#include <asm/io.h> + +#include <mach/vreg.h> + +#include <mach/mmc.h> + +#include "devices.h" +#include "board-dream.h" +#include "proc_comm.h" + +#define DEBUG_SDSLOT_VDD 1 + +extern int msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags); + +/* ---- COMMON ---- */ +static void config_gpio_table(uint32_t *table, int len) +{ + int n; + unsigned id; + for(n = 0; n < len; n++) { + id = table[n]; + msm_proc_comm(PCOM_RPC_GPIO_TLMM_CONFIG_EX, &id, 0); + } +} + +/* ---- SDCARD ---- */ + +static uint32_t sdcard_on_gpio_table[] = { + PCOM_GPIO_CFG(62, 2, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_8MA), /* CLK */ + PCOM_GPIO_CFG(63, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* CMD */ + PCOM_GPIO_CFG(64, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_8MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 2, GPIO_OUTPUT, GPIO_PULL_UP, GPIO_4MA), /* DAT0 */ +}; + +static uint32_t sdcard_off_gpio_table[] = { + PCOM_GPIO_CFG(62, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CLK */ + PCOM_GPIO_CFG(63, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* CMD */ + PCOM_GPIO_CFG(64, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT3 */ + PCOM_GPIO_CFG(65, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT2 */ + PCOM_GPIO_CFG(66, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT1 */ + PCOM_GPIO_CFG(67, 0, GPIO_OUTPUT, GPIO_NO_PULL, GPIO_4MA), /* DAT0 */ +}; + +static uint opt_disable_sdcard; + +static int __init dream_disablesdcard_setup(char *str) +{ + int cal = simple_strtol(str, NULL, 0); + + opt_disable_sdcard = cal; + return 1; +} + +__setup("board_dream.disable_sdcard=", dream_disablesdcard_setup); + +static struct vreg *vreg_sdslot; /* SD slot power */ + +struct mmc_vdd_xlat { + int mask; + int level; +}; + +static struct mmc_vdd_xlat mmc_vdd_table[] = { + { MMC_VDD_165_195, 1800 }, + { MMC_VDD_20_21, 2050 }, + { MMC_VDD_21_22, 2150 }, + { MMC_VDD_22_23, 2250 }, + { MMC_VDD_23_24, 2350 }, + { MMC_VDD_24_25, 2450 }, + { MMC_VDD_25_26, 2550 }, + { MMC_VDD_26_27, 2650 }, + { MMC_VDD_27_28, 2750 }, + { MMC_VDD_28_29, 2850 }, + { MMC_VDD_29_30, 2950 }, +}; + +static unsigned int sdslot_vdd = 0xffffffff; +static unsigned int sdslot_vreg_enabled; + +static uint32_t dream_sdslot_switchvdd(struct device *dev, unsigned int vdd) +{ + int i, rc; + + BUG_ON(!vreg_sdslot); + + if (vdd == sdslot_vdd) + return 0; + + sdslot_vdd = vdd; + + if (vdd == 0) { +#if DEBUG_SDSLOT_VDD + printk("%s: Disabling SD slot power\n", __func__); +#endif + config_gpio_table(sdcard_off_gpio_table, + ARRAY_SIZE(sdcard_off_gpio_table)); + vreg_disable(vreg_sdslot); + sdslot_vreg_enabled = 0; + return 0; + } + + if (!sdslot_vreg_enabled) { + rc = vreg_enable(vreg_sdslot); + if (rc) { + printk(KERN_ERR "%s: Error enabling vreg (%d)\n", + __func__, rc); + } + config_gpio_table(sdcard_on_gpio_table, + ARRAY_SIZE(sdcard_on_gpio_table)); + sdslot_vreg_enabled = 1; + } + + for (i = 0; i < ARRAY_SIZE(mmc_vdd_table); i++) { + if (mmc_vdd_table[i].mask == (1 << vdd)) { +#if DEBUG_SDSLOT_VDD + printk("%s: Setting level to %u\n", + __func__, mmc_vdd_table[i].level); +#endif + rc = vreg_set_level(vreg_sdslot, + mmc_vdd_table[i].level); + if (rc) { + printk(KERN_ERR + "%s: Error setting vreg level (%d)\n", + __func__, rc); + } + return 0; + } + } + + printk(KERN_ERR "%s: Invalid VDD %d specified\n", __func__, vdd); + return 0; +} + +static unsigned int dream_sdslot_status(struct device *dev) +{ + unsigned int status; + + status = (unsigned int) gpio_get_value(TROUT_GPIO_SDMC_CD_N); + return (!status); +} + +#define TROUT_MMC_VDD MMC_VDD_165_195 | MMC_VDD_20_21 | MMC_VDD_21_22 \ + | MMC_VDD_22_23 | MMC_VDD_23_24 | MMC_VDD_24_25 \ + | MMC_VDD_25_26 | MMC_VDD_26_27 | MMC_VDD_27_28 \ + | MMC_VDD_28_29 | MMC_VDD_29_30 + +static struct mmc_platform_data dream_sdslot_data = { + .ocr_mask = TROUT_MMC_VDD, + .status = dream_sdslot_status, + .translate_vdd = dream_sdslot_switchvdd, +}; + +int __init dream_init_mmc(unsigned int sys_rev) +{ + sdslot_vreg_enabled = 0; + + vreg_sdslot = vreg_get(0, "gp6"); + if (IS_ERR(vreg_sdslot)) + return PTR_ERR(vreg_sdslot); + + set_irq_wake(TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 1); + + if (!opt_disable_sdcard) + msm_add_sdcc(2, &dream_sdslot_data, + TROUT_GPIO_TO_INT(TROUT_GPIO_SDMC_CD_N), 0); + else + printk(KERN_INFO "dream: SD-Card interface disabled\n"); + return 0; +} + +#if defined(CONFIG_DEBUG_FS) +static int dreammmc_dbg_sd_pwr_set(void *data, u64 val) +{ + dream_sdslot_switchvdd(NULL, (unsigned int) val); + return 0; +} + +static int dreammmc_dbg_sd_pwr_get(void *data, u64 *val) +{ + *val = sdslot_vdd; + return 0; +} + +static int dreammmc_dbg_sd_cd_set(void *data, u64 val) +{ + return -ENOSYS; +} + +static int dreammmc_dbg_sd_cd_get(void *data, u64 *val) +{ + *val = dream_sdslot_status(NULL); + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(dreammmc_dbg_sd_pwr_fops, + dreammmc_dbg_sd_pwr_get, + dreammmc_dbg_sd_pwr_set, "%llu\n"); + +DEFINE_SIMPLE_ATTRIBUTE(dreammmc_dbg_sd_cd_fops, + dreammmc_dbg_sd_cd_get, + dreammmc_dbg_sd_cd_set, "%llu\n"); + +static int __init dreammmc_dbg_init(void) +{ + struct dentry *dent; + + dent = debugfs_create_dir("dreammmc_dbg", 0); + if (IS_ERR(dent)) + return PTR_ERR(dent); + + debugfs_create_file("sd_pwr", 0644, dent, NULL, + &dreammmc_dbg_sd_pwr_fops); + debugfs_create_file("sd_cd", 0644, dent, NULL, + &dreammmc_dbg_sd_cd_fops); + + return 0; +} + +device_initcall(dreammmc_dbg_init); + +#endif diff --git a/arch/arm/mach-msm/board-dream.c b/arch/arm/mach-msm/board-dream.c index a0877a3..49de63b 100644 --- a/arch/arm/mach-msm/board-dream.c +++ b/arch/arm/mach-msm/board-dream.c @@ -12,16 +12,19 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * + * This machine is also known by its codename, "trout". */ #include <linux/kernel.h> #include <linux/init.h> #include <linux/platform_device.h> +#include <linux/delay.h> #include <asm/mach-types.h> #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/setup.h> +#include <asm/gpio.h> #include <mach/board.h> #include <mach/hardware.h> @@ -30,6 +33,9 @@ #include "devices.h" #include "board-dream.h" +extern int dream_init_mmc(unsigned int); + + static struct platform_device *devices[] __initdata = { &msm_device_uart3, &msm_device_smd, @@ -40,12 +46,12 @@ static struct platform_device *devices[] __initdata = { extern struct sys_timer msm_timer; -static void __init trout_init_irq(void) +static void __init dream_init_irq(void) { msm_init_irq(); } -static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, +static void __init dream_fixup(struct machine_desc *desc, struct tag *tags, char **cmdline, struct meminfo *mi) { mi->nr_banks=1; @@ -54,12 +60,34 @@ static void __init trout_fixup(struct machine_desc *desc, struct tag *tags, mi->bank[0].size = (101*1024*1024); } -static void __init trout_init(void) +static void __init dream_init(void) { + int rc; platform_add_devices(devices, ARRAY_SIZE(devices)); + + rc = dream_init_mmc(system_rev); + if (rc) + printk(KERN_CRIT "%s: MMC init failure (%d)\n", __func__, rc); + + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 1); + mdelay(300); + gpio_set_value(TROUT_GPIO_UI_LED_EN, 0); + mdelay(300); } -static struct map_desc trout_io_desc[] __initdata = { +static struct map_desc dream_io_desc[] __initdata = { { .virtual = TROUT_CPLD_BASE, .pfn = __phys_to_pfn(TROUT_CPLD_START), @@ -68,10 +96,10 @@ static struct map_desc trout_io_desc[] __initdata = { } }; -static void __init trout_map_io(void) +static void __init dream_map_io(void) { msm_map_common_io(); - iotable_init(trout_io_desc, ARRAY_SIZE(trout_io_desc)); + iotable_init(dream_io_desc, ARRAY_SIZE(dream_io_desc)); #ifdef CONFIG_MSM_DEBUG_UART3 /* route UART3 to the "H2W" extended usb connector */ @@ -87,9 +115,9 @@ MACHINE_START(TROUT, "HTC Dream") .io_pg_offst = ((MSM_DEBUG_UART_BASE) >> 18) & 0xfffc, #endif .boot_params = 0x10000100, - .fixup = trout_fixup, - .map_io = trout_map_io, - .init_irq = trout_init_irq, - .init_machine = trout_init, + .fixup = dream_fixup, + .map_io = dream_map_io, + .init_irq = dream_init_irq, + .init_machine = dream_init, .timer = &msm_timer, MACHINE_END diff --git a/arch/arm/mach-msm/board-dream.h b/arch/arm/mach-msm/board-dream.h index 4f345a5..cdfb0ae 100644 --- a/arch/arm/mach-msm/board-dream.h +++ b/arch/arm/mach-msm/board-dream.h @@ -1,5 +1,153 @@ +#define MSM_SMI_BASE 0x00000000 +#define MSM_SMI_SIZE 0x00800000 + +#define MSM_EBI_BASE 0x10000000 +#define MSM_EBI_SIZE 0x06e00000 + +#define MSM_PMEM_GPU0_BASE 0x00000000 +#define MSM_PMEM_GPU0_SIZE 0x00700000 + +#define MSM_PMEM_MDP_BASE 0x02000000 +#define MSM_PMEM_MDP_SIZE 0x00800000 + +#define MSM_PMEM_ADSP_BASE 0x02800000 +#define MSM_PMEM_ADSP_SIZE 0x00800000 + +#define MSM_PMEM_CAMERA_BASE 0x03000000 +#define MSM_PMEM_CAMERA_SIZE 0x00800000 + +#define MSM_FB_BASE 0x03800000 +#define MSM_FB_SIZE 0x00100000 + +#define MSM_LINUX_BASE MSM_EBI_BASE +#define MSM_LINUX_SIZE 0x06500000 + +#define MSM_PMEM_GPU1_SIZE 0x800000 +#define MSM_PMEM_GPU1_BASE MSM_RAM_CONSOLE_BASE - MSM_PMEM_GPU1_SIZE + +#define MSM_RAM_CONSOLE_BASE MSM_EBI_BASE + 0x6d00000 +#define MSM_RAM_CONSOLE_SIZE 128 * SZ_1K + +#if (MSM_FB_BASE + MSM_FB_SIZE) >= (MSM_PMEM_GPU1_BASE) +#error invalid memory map +#endif + +#define DECLARE_MSM_IOMAP +#include <mach/msm_iomap.h> + +#define TROUT_4_BALL_UP_0 1 +#define TROUT_4_BALL_LEFT_0 18 +#define TROUT_4_BALL_DOWN_0 57 +#define TROUT_4_BALL_RIGHT_0 91 + +#define TROUT_5_BALL_UP_0 94 +#define TROUT_5_BALL_LEFT_0 18 +#define TROUT_5_BALL_DOWN_0 90 +#define TROUT_5_BALL_RIGHT_0 19 + +#define TROUT_POWER_KEY 20 + +#define TROUT_4_TP_LS_EN 19 +#define TROUT_5_TP_LS_EN 1 + #define TROUT_CPLD_BASE 0xE8100000 #define TROUT_CPLD_START 0x98000000 #define TROUT_CPLD_SIZE SZ_4K +#define TROUT_GPIO_CABLE_IN1 (83) +#define TROUT_GPIO_CABLE_IN2 (49) + +#define TROUT_GPIO_START (128) + +#define TROUT_GPIO_INT_MASK0_REG (0x0c) +#define TROUT_GPIO_INT_STAT0_REG (0x0e) +#define TROUT_GPIO_INT_MASK1_REG (0x14) +#define TROUT_GPIO_INT_STAT1_REG (0x10) + +#define TROUT_GPIO_HAPTIC_PWM (28) +#define TROUT_GPIO_PS_HOLD (25) + +#define TROUT_GPIO_MISC2_BASE (TROUT_GPIO_START + 0x00) +#define TROUT_GPIO_MISC3_BASE (TROUT_GPIO_START + 0x08) +#define TROUT_GPIO_MISC4_BASE (TROUT_GPIO_START + 0x10) +#define TROUT_GPIO_MISC5_BASE (TROUT_GPIO_START + 0x18) +#define TROUT_GPIO_INT2_BASE (TROUT_GPIO_START + 0x20) +#define TROUT_GPIO_MISC1_BASE (TROUT_GPIO_START + 0x28) +#define TROUT_GPIO_VIRTUAL_BASE (TROUT_GPIO_START + 0x30) +#define TROUT_GPIO_INT5_BASE (TROUT_GPIO_START + 0x48) + +#define TROUT_GPIO_CHARGER_EN (TROUT_GPIO_MISC2_BASE + 0) +#define TROUT_GPIO_ISET (TROUT_GPIO_MISC2_BASE + 1) +#define TROUT_GPIO_H2W_DAT_DIR (TROUT_GPIO_MISC2_BASE + 2) +#define TROUT_GPIO_H2W_CLK_DIR (TROUT_GPIO_MISC2_BASE + 3) +#define TROUT_GPIO_H2W_DAT_GPO (TROUT_GPIO_MISC2_BASE + 4) +#define TROUT_GPIO_H2W_CLK_GPO (TROUT_GPIO_MISC2_BASE + 5) +#define TROUT_GPIO_H2W_SEL0 (TROUT_GPIO_MISC2_BASE + 6) +#define TROUT_GPIO_H2W_SEL1 (TROUT_GPIO_MISC2_BASE + 7) + +#define TROUT_GPIO_SPOTLIGHT_EN (TROUT_GPIO_MISC3_BASE + 0) +#define TROUT_GPIO_FLASH_EN (TROUT_GPIO_MISC3_BASE + 1) +#define TROUT_GPIO_I2C_PULL (TROUT_GPIO_MISC3_BASE + 2) +#define TROUT_GPIO_TP_I2C_PULL (TROUT_GPIO_MISC3_BASE + 3) +#define TROUT_GPIO_TP_EN (TROUT_GPIO_MISC3_BASE + 4) +#define TROUT_GPIO_JOG_EN (TROUT_GPIO_MISC3_BASE + 5) +#define TROUT_GPIO_UI_LED_EN (TROUT_GPIO_MISC3_BASE + 6) +#define TROUT_GPIO_QTKEY_LED_EN (TROUT_GPIO_MISC3_BASE + 7) + +#define TROUT_GPIO_VCM_PWDN (TROUT_GPIO_MISC4_BASE + 0) +#define TROUT_GPIO_USB_H2W_SW (TROUT_GPIO_MISC4_BASE + 1) +#define TROUT_GPIO_COMPASS_RST_N (TROUT_GPIO_MISC4_BASE + 2) +#define TROUT_GPIO_HAPTIC_EN_UP (TROUT_GPIO_MISC4_BASE + 3) +#define TROUT_GPIO_HAPTIC_EN_MAIN (TROUT_GPIO_MISC4_BASE + 4) +#define TROUT_GPIO_USB_PHY_RST_N (TROUT_GPIO_MISC4_BASE + 5) +#define TROUT_GPIO_WIFI_PA_RESETX (TROUT_GPIO_MISC4_BASE + 6) +#define TROUT_GPIO_WIFI_EN (TROUT_GPIO_MISC4_BASE + 7) + +#define TROUT_GPIO_BT_32K_EN (TROUT_GPIO_MISC5_BASE + 0) +#define TROUT_GPIO_MAC_32K_EN (TROUT_GPIO_MISC5_BASE + 1) +#define TROUT_GPIO_MDDI_32K_EN (TROUT_GPIO_MISC5_BASE + 2) +#define TROUT_GPIO_COMPASS_32K_EN (TROUT_GPIO_MISC5_BASE + 3) + +#define TROUT_GPIO_NAVI_ACT_N (TROUT_GPIO_INT2_BASE + 0) +#define TROUT_GPIO_COMPASS_IRQ (TROUT_GPIO_INT2_BASE + 1) +#define TROUT_GPIO_SLIDING_DET (TROUT_GPIO_INT2_BASE + 2) +#define TROUT_GPIO_AUD_HSMIC_DET_N (TROUT_GPIO_INT2_BASE + 3) +#define TROUT_GPIO_SD_DOOR_N (TROUT_GPIO_INT2_BASE + 4) +#define TROUT_GPIO_CAM_BTN_STEP1_N (TROUT_GPIO_INT2_BASE + 5) +#define TROUT_GPIO_CAM_BTN_STEP2_N (TROUT_GPIO_INT2_BASE + 6) +#define TROUT_GPIO_TP_ATT_N (TROUT_GPIO_INT2_BASE + 7) +#define TROUT_GPIO_BANK0_FIRST_INT_SOURCE (TROUT_GPIO_NAVI_ACT_N) +#define TROUT_GPIO_BANK0_LAST_INT_SOURCE (TROUT_GPIO_TP_ATT_N) + +#define TROUT_GPIO_H2W_DAT_GPI (TROUT_GPIO_MISC1_BASE + 0) +#define TROUT_GPIO_H2W_CLK_GPI (TROUT_GPIO_MISC1_BASE + 1) +#define TROUT_GPIO_CPLD128_VER_0 (TROUT_GPIO_MISC1_BASE + 4) +#define TROUT_GPIO_CPLD128_VER_1 (TROUT_GPIO_MISC1_BASE + 5) +#define TROUT_GPIO_CPLD128_VER_2 (TROUT_GPIO_MISC1_BASE + 6) +#define TROUT_GPIO_CPLD128_VER_3 (TROUT_GPIO_MISC1_BASE + 7) + +#define TROUT_GPIO_SDMC_CD_N (TROUT_GPIO_VIRTUAL_BASE + 0) +#define TROUT_GPIO_END (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_FIRST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) +#define TROUT_GPIO_BANK1_LAST_INT_SOURCE (TROUT_GPIO_SDMC_CD_N) + +#define TROUT_GPIO_VIRTUAL_TO_REAL_OFFSET \ + (TROUT_GPIO_INT5_BASE - TROUT_GPIO_VIRTUAL_BASE) + +#define TROUT_INT_START (NR_MSM_IRQS + NR_GPIO_IRQS) +#define TROUT_INT_BANK0_COUNT (8) +#define TROUT_INT_BANK1_START (TROUT_INT_START + TROUT_INT_BANK0_COUNT) +#define TROUT_INT_BANK1_COUNT (1) +#define TROUT_INT_END (TROUT_INT_START + TROUT_INT_BANK0_COUNT + \ + TROUT_INT_BANK1_COUNT - 1) +#define TROUT_GPIO_TO_INT(n) (((n) <= TROUT_GPIO_BANK0_LAST_INT_SOURCE) ? \ + (TROUT_INT_START - TROUT_GPIO_BANK0_FIRST_INT_SOURCE + (n)) : \ + (TROUT_INT_BANK1_START - TROUT_GPIO_BANK1_FIRST_INT_SOURCE + (n))) + +#define TROUT_INT_TO_BANK(n) ((n - TROUT_INT_START) / TROUT_INT_BANK0_COUNT) +#define TROUT_INT_TO_MASK(n) (1U << ((n - TROUT_INT_START) & 7)) +#define TROUT_BANK_TO_MASK_REG(bank) \ + (bank ? TROUT_GPIO_INT_MASK1_REG : TROUT_GPIO_INT_MASK0_REG) +#define TROUT_BANK_TO_STAT_REG(bank) \ + (bank ? TROUT_GPIO_INT_STAT1_REG : TROUT_GPIO_INT_STAT0_REG) diff --git a/arch/arm/mach-msm/devices.c b/arch/arm/mach-msm/devices.c index 31b6b30..afec7c2 100644 --- a/arch/arm/mach-msm/devices.c +++ b/arch/arm/mach-msm/devices.c @@ -155,6 +155,7 @@ struct platform_device msm_device_smd = { .id = -1, }; + static struct resource resources_sdc1[] = { { .start = MSM_SDC1_PHYS, @@ -163,8 +164,19 @@ static struct resource resources_sdc1[] = { }, { .start = INT_SDC1_0, + .end = INT_SDC1_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC1_1, .end = INT_SDC1_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -181,8 +193,19 @@ static struct resource resources_sdc2[] = { }, { .start = INT_SDC2_0, + .end = INT_SDC2_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC2_1, .end = INT_SDC2_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -199,8 +222,19 @@ static struct resource resources_sdc3[] = { }, { .start = INT_SDC3_0, + .end = INT_SDC3_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC3_1, .end = INT_SDC3_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -217,8 +251,19 @@ static struct resource resources_sdc4[] = { }, { .start = INT_SDC4_0, + .end = INT_SDC4_0, + .flags = IORESOURCE_IRQ, + .name = "cmd_irq", + }, + { + .start = INT_SDC4_1, .end = INT_SDC4_1, .flags = IORESOURCE_IRQ, + .name = "pio_irq", + }, + { + .flags = IORESOURCE_IRQ | IORESOURCE_DISABLED, + .name = "status_irq" }, { .start = 8, @@ -266,3 +311,35 @@ struct platform_device msm_device_sdc4 = { .coherent_dma_mask = 0xffffffff, }, }; + + +static struct platform_device *msm_sdcc_devices[] __initdata = { + &msm_device_sdc1, + &msm_device_sdc2, + &msm_device_sdc3, + &msm_device_sdc4, +}; + +int __init msm_add_sdcc(unsigned int controller, struct mmc_platform_data *plat, + unsigned int stat_irq, unsigned long stat_irq_flags) +{ + struct platform_device *pdev; + struct resource *res; + + if (controller < 1 || controller > 4) + return -EINVAL; + + pdev = msm_sdcc_devices[controller-1]; + pdev->dev.platform_data = plat; + + res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "status_irq"); + if (!res) + return -EINVAL; + else if (stat_irq) { + res->start = res->end = stat_irq; + res->flags &= ~IORESOURCE_DISABLED; + res->flags |= stat_irq_flags; + } + + return platform_device_register(pdev); +} diff --git a/arch/arm/mach-msm/generic_gpio.c b/arch/arm/mach-msm/generic_gpio.c new file mode 100644 index 0000000..fe24d38 --- /dev/null +++ b/arch/arm/mach-msm/generic_gpio.c @@ -0,0 +1,274 @@ +/* arch/arm/mach-msm/generic_gpio.c + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <asm/gpio.h> +#include "gpio_chip.h" + +#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5) + +struct gpio_state { + unsigned long flags; + int refcount; +}; + +static DEFINE_SPINLOCK(gpio_chips_lock); +static LIST_HEAD(gpio_chip_list); +static struct gpio_chip **gpio_chip_array; +static unsigned long gpio_chip_array_size; + +int register_gpio_chip(struct gpio_chip *new_gpio_chip) +{ + int err = 0; + struct gpio_chip *gpio_chip; + int i; + unsigned long irq_flags; + unsigned int chip_array_start_index, chip_array_end_index; + + new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL); + if (new_gpio_chip->state == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate state\n"); + return -ENOMEM; + } + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start); + chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end); + if (chip_array_end_index >= gpio_chip_array_size) { + struct gpio_chip **new_gpio_chip_array; + unsigned long new_gpio_chip_array_size = chip_array_end_index + 1; + + new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC); + if (new_gpio_chip_array == NULL) { + printk(KERN_ERR "register_gpio_chip: failed to allocate array\n"); + err = -ENOMEM; + goto failed; + } + for (i = 0; i < gpio_chip_array_size; i++) + new_gpio_chip_array[i] = gpio_chip_array[i]; + for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++) + new_gpio_chip_array[i] = NULL; + gpio_chip_array = new_gpio_chip_array; + gpio_chip_array_size = new_gpio_chip_array_size; + } + list_for_each_entry(gpio_chip, &gpio_chip_list, list) { + if (gpio_chip->start > new_gpio_chip->end) { + list_add_tail(&new_gpio_chip->list, &gpio_chip->list); + goto added; + } + if (gpio_chip->end >= new_gpio_chip->start) { + printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n", + new_gpio_chip->start, new_gpio_chip->end, + gpio_chip->start, gpio_chip->end); + err = -EBUSY; + goto failed; + } + } + list_add_tail(&new_gpio_chip->list, &gpio_chip_list); +added: + for (i = chip_array_start_index; i <= chip_array_end_index; i++) { + if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start) + gpio_chip_array[i] = new_gpio_chip; + } +failed: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + if (err) + kfree(new_gpio_chip->state); + return err; +} + +static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio) +{ + unsigned long i; + struct gpio_chip *chip; + + i = GPIO_NUM_TO_CHIP_INDEX(gpio); + if (i >= gpio_chip_array_size) + return NULL; + chip = gpio_chip_array[i]; + if (chip == NULL) + return NULL; + list_for_each_entry_from(chip, &gpio_chip_list, list) { + if (gpio < chip->start) + return NULL; + if (gpio <= chip->end) + return chip; + } + return NULL; +} + +static int request_gpio(unsigned int gpio, unsigned long flags) +{ + int err = 0; + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip == NULL) { + err = -EINVAL; + goto err; + } + chip_index = gpio - chip->start; + if (chip->state[chip_index].refcount == 0) { + chip->configure(chip, gpio, flags); + chip->state[chip_index].flags = flags; + chip->state[chip_index].refcount++; + } else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED)) + chip->state[chip_index].refcount++; + else + err = -EBUSY; +err: + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return err; +} + +int gpio_request(unsigned gpio, const char *label) +{ + return request_gpio(gpio, 0); +} +EXPORT_SYMBOL(gpio_request); + +void gpio_free(unsigned gpio) +{ + struct gpio_chip *chip; + unsigned long irq_flags; + unsigned long chip_index; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) { + chip_index = gpio - chip->start; + chip->state[chip_index].refcount--; + } + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_free); + +static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->get_irq_num) + ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} + +int gpio_to_irq(unsigned gpio) +{ + int ret, irq; + ret = gpio_get_irq_num(gpio, &irq, NULL); + if (ret) + return ret; + return irq; +} +EXPORT_SYMBOL(gpio_to_irq); + +int gpio_configure(unsigned int gpio, unsigned long flags) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip) + ret = chip->configure(chip, gpio, flags); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_configure); + +int gpio_direction_input(unsigned gpio) +{ + return gpio_configure(gpio, GPIOF_INPUT); +} +EXPORT_SYMBOL(gpio_direction_input); + +int gpio_direction_output(unsigned gpio, int value) +{ + gpio_set_value(gpio, value); + return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT); +} +EXPORT_SYMBOL(gpio_direction_output); + +int gpio_get_value(unsigned gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read) + ret = chip->read(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_get_value); + +void gpio_set_value(unsigned gpio, int on) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->write) + ret = chip->write(chip, gpio, on); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); +} +EXPORT_SYMBOL(gpio_set_value); + +int gpio_read_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->read_detect_status) + ret = chip->read_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_read_detect_status); + +int gpio_clear_detect_status(unsigned int gpio) +{ + int ret = -ENOTSUPP; + struct gpio_chip *chip; + unsigned long irq_flags; + + spin_lock_irqsave(&gpio_chips_lock, irq_flags); + chip = get_gpio_chip_locked(gpio); + if (chip && chip->clear_detect_status) + ret = chip->clear_detect_status(chip, gpio); + spin_unlock_irqrestore(&gpio_chips_lock, irq_flags); + return ret; +} +EXPORT_SYMBOL(gpio_clear_detect_status); diff --git a/arch/arm/mach-msm/gpio_chip.h b/arch/arm/mach-msm/gpio_chip.h new file mode 100644 index 0000000..eab9f09 --- /dev/null +++ b/arch/arm/mach-msm/gpio_chip.h @@ -0,0 +1,38 @@ +/* arch/arm/mach-msm/gpio_chip.h + * + * Copyright (C) 2007 Google, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef _LINUX_GPIO_CHIP_H +#define _LINUX_GPIO_CHIP_H + +#include <linux/list.h> + +struct gpio_chip { + struct list_head list; + struct gpio_state *state; + + unsigned int start; + unsigned int end; + + int (*configure)(struct gpio_chip *chip, unsigned int gpio, unsigned long flags); + int (*get_irq_num)(struct gpio_chip *chip, unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp); + int (*read)(struct gpio_chip *chip, unsigned int gpio); + int (*write)(struct gpio_chip *chip, unsigned int gpio, unsigned on); + int (*read_detect_status)(struct gpio_chip *chip, unsigned int gpio); + int (*clear_detect_status)(struct gpio_chip *chip, unsigned int gpio); +}; + +int register_gpio_chip(struct gpio_chip *gpio_chip); + +#endif diff --git a/arch/arm/mach-msm/gpio_hw.h b/arch/arm/mach-msm/gpio_hw.h new file mode 100644 index 0000000..61f410c --- /dev/null +++ b/arch/arm/mach-msm/gpio_hw.h @@ -0,0 +1,100 @@ +/* arch/arm/mach-msm/gpio_hw.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Brian Swetland <swetland@google.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ARCH_ARM_MACH_MSM_GPIO_HW_H +#define __ARCH_ARM_MACH_MSM_GPIO_HW_H + +#include <mach/msm_iomap.h> + +/* see 80-VA736-2 Rev C pp 695-751 +** +** These are actually the *shadow* gpio registers, since the +** real ones (which allow full access) are only available to the +** ARM9 side of the world. +** +** Since the _BASE need to be page-aligned when we're mapping them +** to virtual addresses, adjust for the additional offset in these +** macros. +*/ + +#define GPIO1_REG(off) (MSM_GPIO1_BASE + 0x800 + (off)) +#define GPIO2_REG(off) (MSM_GPIO2_BASE + 0xC00 + (off)) + +/* output value */ +#define GPIO_OUT_0 GPIO1_REG(0x00) /* gpio 15-0 */ +#define GPIO_OUT_1 GPIO2_REG(0x00) /* gpio 42-16 */ +#define GPIO_OUT_2 GPIO1_REG(0x04) /* gpio 67-43 */ +#define GPIO_OUT_3 GPIO1_REG(0x08) /* gpio 94-68 */ +#define GPIO_OUT_4 GPIO1_REG(0x0C) /* gpio 106-95 */ +#define GPIO_OUT_5 GPIO1_REG(0x50) /* gpio 107-121 */ + +/* same pin map as above, output enable */ +#define GPIO_OE_0 GPIO1_REG(0x10) +#define GPIO_OE_1 GPIO2_REG(0x08) +#define GPIO_OE_2 GPIO1_REG(0x14) +#define GPIO_OE_3 GPIO1_REG(0x18) +#define GPIO_OE_4 GPIO1_REG(0x1C) +#define GPIO_OE_5 GPIO1_REG(0x54) + +/* same pin map as above, input read */ +#define GPIO_IN_0 GPIO1_REG(0x34) +#define GPIO_IN_1 GPIO2_REG(0x20) +#define GPIO_IN_2 GPIO1_REG(0x38) +#define GPIO_IN_3 GPIO1_REG(0x3C) +#define GPIO_IN_4 GPIO1_REG(0x40) +#define GPIO_IN_5 GPIO1_REG(0x44) + +/* same pin map as above, 1=edge 0=level interrup */ +#define GPIO_INT_EDGE_0 GPIO1_REG(0x60) +#define GPIO_INT_EDGE_1 GPIO2_REG(0x50) +#define GPIO_INT_EDGE_2 GPIO1_REG(0x64) +#define GPIO_INT_EDGE_3 GPIO1_REG(0x68) +#define GPIO_INT_EDGE_4 GPIO1_REG(0x6C) +#define GPIO_INT_EDGE_5 GPIO1_REG(0xC0) + +/* same pin map as above, 1=positive 0=negative */ +#define GPIO_INT_POS_0 GPIO1_REG(0x70) +#define GPIO_INT_POS_1 GPIO2_REG(0x58) +#define GPIO_INT_POS_2 GPIO1_REG(0x74) +#define GPIO_INT_POS_3 GPIO1_REG(0x78) +#define GPIO_INT_POS_4 GPIO1_REG(0x7C) +#define GPIO_INT_POS_5 GPIO1_REG(0xBC) + +/* same pin map as above, interrupt enable */ +#define GPIO_INT_EN_0 GPIO1_REG(0x80) +#define GPIO_INT_EN_1 GPIO2_REG(0x60) +#define GPIO_INT_EN_2 GPIO1_REG(0x84) +#define GPIO_INT_EN_3 GPIO1_REG(0x88) +#define GPIO_INT_EN_4 GPIO1_REG(0x8C) +#define GPIO_INT_EN_5 GPIO1_REG(0xB8) + +/* same pin map as above, write 1 to clear interrupt */ +#define GPIO_INT_CLEAR_0 GPIO1_REG(0x90) +#define GPIO_INT_CLEAR_1 GPIO2_REG(0x68) +#define GPIO_INT_CLEAR_2 GPIO1_REG(0x94) +#define GPIO_INT_CLEAR_3 GPIO1_REG(0x98) +#define GPIO_INT_CLEAR_4 GPIO1_REG(0x9C) +#define GPIO_INT_CLEAR_5 GPIO1_REG(0xB4) + +/* same pin map as above, 1=interrupt pending */ +#define GPIO_INT_STATUS_0 GPIO1_REG(0xA0) +#define GPIO_INT_STATUS_1 GPIO2_REG(0x70) +#define GPIO_INT_STATUS_2 GPIO1_REG(0xA4) +#define GPIO_INT_STATUS_3 GPIO1_REG(0xA8) +#define GPIO_INT_STATUS_4 GPIO1_REG(0xAC) +#define GPIO_INT_STATUS_5 GPIO1_REG(0xB0) + +#endif diff --git a/arch/arm/mach-msm/include/mach/gpio.h b/arch/arm/mach-msm/include/mach/gpio.h new file mode 100644 index 0000000..590573f --- /dev/null +++ b/arch/arm/mach-msm/include/mach/gpio.h @@ -0,0 +1,47 @@ +/* linux/include/asm-arm/arch-msm/gpio.h + * + * Copyright (C) 2007 Google, Inc. + * Author: Mike Lockwood <lockwood@android.com> + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + * + */ + +#ifndef __ASM_ARCH_MSM_GPIO_H +#define __ASM_ARCH_MSM_GPIO_H + +#include <linux/interrupt.h> + +int gpio_request(unsigned gpio, const char *label); +void gpio_free(unsigned gpio); +int gpio_direction_input(unsigned gpio); +int gpio_direction_output(unsigned gpio, int value); +int gpio_get_value(unsigned gpio); +void gpio_set_value(unsigned gpio, int value); +int gpio_to_irq(unsigned gpio); + +#include <asm-generic/gpio.h> + +/* extended gpio api */ + +#define GPIOF_IRQF_MASK 0x0000ffff /* use to specify edge detection without */ +#define GPIOF_IRQF_TRIGGER_NONE 0x00010000 /* IRQF_TRIGGER_NONE is 0 which also means "as already configured" */ +#define GPIOF_INPUT 0x00020000 +#define GPIOF_DRIVE_OUTPUT 0x00040000 +#define GPIOF_OUTPUT_LOW 0x00080000 +#define GPIOF_OUTPUT_HIGH 0x00100000 + +#define GPIOIRQF_SHARED 0x00000001 /* the irq line is shared with other inputs */ + +extern int gpio_configure(unsigned int gpio, unsigned long flags); +extern int gpio_read_detect_status(unsigned int gpio); +extern int gpio_clear_detect_status(unsigned int gpio); + +#endif diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c index b31946e..7e0c1ac 100644 --- a/drivers/mmc/host/msm_sdcc.c +++ b/drivers/mmc/host/msm_sdcc.c @@ -69,6 +69,7 @@ msmsdcc_request_end(struct msmsdcc_host *host, struct mmc_request *mrq) host->curr.mrq = NULL; host->curr.cmd = NULL; + printk("msm..._request_end\n"); if (mrq->data) mrq->data->bytes_xfered = host->curr.data_xfered; @@ -119,6 +120,7 @@ msmsdcc_dma_complete_func(struct msm_dmov_cmd *cmd, unsigned long flags; struct mmc_request *mrq; + printk("data complete func\n"); spin_lock_irqsave(&host->lock, flags); mrq = host->curr.mrq; BUG_ON(!mrq); @@ -360,6 +362,8 @@ msmsdcc_start_command(struct msmsdcc_host *host, struct mmc_command *cmd, u32 c) { void __iomem *base = host->base; + printk("start_command\n"); + if (readl(base + MMCICOMMAND) & MCI_CPSM_ENABLE) { writel(0, base + MMCICOMMAND); udelay(2 + ((5 * 1000000) / host->clk_rate)); @@ -483,6 +487,7 @@ msmsdcc_pio_irq(int irq, void *dev_id) void __iomem *base = host->base; uint32_t status; + printk("msmsdcc_pio_irq\n"); status = readl(base + MMCISTATUS); do { @@ -589,6 +594,7 @@ msmsdcc_handle_irq_data(struct msmsdcc_host *host, u32 status, { struct mmc_data *data = host->curr.data; + printk("handle_irq_data\n"); if (!data) return; @@ -696,6 +702,7 @@ msmsdcc_request(struct mmc_host *mmc, struct mmc_request *mrq) WARN_ON(host->curr.mrq != NULL); WARN_ON(host->pwr == 0); + printk("msm..._request\n"); spin_lock_irqsave(&host->lock, flags); host->stats.reqs++; diff --git a/kernel/printk.c b/kernel/printk.c index 2c98b0b..5f37e88 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -714,10 +714,12 @@ asmlinkage int vprintk(const char *fmt, va_list args) printed_len += vscnprintf(printk_buf + printed_len, sizeof(printk_buf) - printed_len, fmt, args); +#if 0 { extern void printascii(const char *); printascii(printk_buf); } +#endif p = printk_buf; -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
next reply other threads:[~2009-11-03 10:53 UTC|newest] Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top 2009-11-03 10:53 Pavel Machek [this message] 2009-11-03 10:53 ` dream: glue for mmc controller Pavel Machek 2009-11-03 10:57 ` Ben Dooks 2009-11-03 10:57 ` Ben Dooks 2009-11-08 8:13 ` Pavel Machek 2009-11-08 8:13 ` Pavel Machek 2009-11-08 9:10 ` Russell King - ARM Linux 2009-11-08 9:10 ` Russell King - ARM Linux 2009-11-09 2:14 ` Arve Hjønnevåg 2009-11-09 2:14 ` Arve Hjønnevåg 2009-12-08 10:23 ` Pavel Machek 2009-12-08 10:23 ` Pavel Machek
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20091103105319.GA2492@elf.ucw.cz \ --to=pavel@ucw.cz \ --cc=arve@android.com \ --cc=linux-arm-kernel@lists.infradead.org \ --cc=linux-kernel@vger.kernel.org \ --cc=swetland@google.com \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.