summaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2008-10-09 21:33:05 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-10-09 21:33:05 +0100
commitc97f68145e8067b3ac4b126a6faebf90f9ffc302 (patch)
treeeb2060681552a00e9efa98224b95f69a3dc84390 /arch/arm/mach-davinci
parentb1add0480a95b6ceaece5caf6c50614771eae9b2 (diff)
parent7bff3c4ce44ea48f50dc47a5994454984bd08c59 (diff)
downloadop-kernel-dev-c97f68145e8067b3ac4b126a6faebf90f9ffc302.zip
op-kernel-dev-c97f68145e8067b3ac4b126a6faebf90f9ffc302.tar.gz
Merge branch 'for-rmk' of git://source.mvista.com/git/linux-davinci-2.6.git
Merge branch 'davinci' into devel
Diffstat (limited to 'arch/arm/mach-davinci')
-rw-r--r--arch/arm/mach-davinci/Makefile2
-rw-r--r--arch/arm/mach-davinci/board-evm.c339
-rw-r--r--arch/arm/mach-davinci/devices.c48
-rw-r--r--arch/arm/mach-davinci/gpio.c133
-rw-r--r--arch/arm/mach-davinci/include/mach/common.h3
-rw-r--r--arch/arm/mach-davinci/include/mach/gpio.h73
-rw-r--r--arch/arm/mach-davinci/include/mach/i2c.h7
-rw-r--r--arch/arm/mach-davinci/include/mach/io.h43
-rw-r--r--arch/arm/mach-davinci/usb.c116
9 files changed, 614 insertions, 150 deletions
diff --git a/arch/arm/mach-davinci/Makefile b/arch/arm/mach-davinci/Makefile
index 99ac2e5..4dc4585 100644
--- a/arch/arm/mach-davinci/Makefile
+++ b/arch/arm/mach-davinci/Makefile
@@ -5,7 +5,7 @@
# Common objects
obj-y := time.o irq.o clock.o serial.o io.o id.o psc.o \
- gpio.o mux.o
+ gpio.o mux.o devices.o usb.o
# Board specific
obj-$(CONFIG_MACH_DAVINCI_EVM) += board-evm.o
diff --git a/arch/arm/mach-davinci/board-evm.c b/arch/arm/mach-davinci/board-evm.c
index 41f3cc4..a957d23 100644
--- a/arch/arm/mach-davinci/board-evm.c
+++ b/arch/arm/mach-davinci/board-evm.c
@@ -13,6 +13,13 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/leds.h>
+
+#include <linux/i2c.h>
+#include <linux/i2c/pcf857x.h>
+#include <linux/i2c/at24.h>
+
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/physmap.h>
@@ -20,13 +27,14 @@
#include <asm/setup.h>
#include <asm/mach-types.h>
-#include <mach/hardware.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/flash.h>
+#include <mach/hardware.h>
#include <mach/common.h>
+#include <mach/i2c.h>
/* other misc. init functions */
void __init davinci_psc_init(void);
@@ -34,10 +42,10 @@ void __init davinci_irq_init(void);
void __init davinci_map_common_io(void);
void __init davinci_init_common_hw(void);
-/* NOR Flash base address set to CS0 by default */
-#define NOR_FLASH_PHYS 0x02000000
+#if defined(CONFIG_MTD_PHYSMAP) || \
+ defined(CONFIG_MTD_PHYSMAP_MODULE)
-static struct mtd_partition davinci_evm_partitions[] = {
+static struct mtd_partition davinci_evm_norflash_partitions[] = {
/* bootloader (U-Boot, etc) in first 4 sectors */
{
.name = "bootloader",
@@ -68,32 +76,323 @@ static struct mtd_partition davinci_evm_partitions[] = {
}
};
-static struct physmap_flash_data davinci_evm_flash_data = {
+static struct physmap_flash_data davinci_evm_norflash_data = {
.width = 2,
- .parts = davinci_evm_partitions,
- .nr_parts = ARRAY_SIZE(davinci_evm_partitions),
+ .parts = davinci_evm_norflash_partitions,
+ .nr_parts = ARRAY_SIZE(davinci_evm_norflash_partitions),
};
/* NOTE: CFI probe will correctly detect flash part as 32M, but EMIF
* limits addresses to 16M, so using addresses past 16M will wrap */
-static struct resource davinci_evm_flash_resource = {
- .start = NOR_FLASH_PHYS,
- .end = NOR_FLASH_PHYS + SZ_16M - 1,
+static struct resource davinci_evm_norflash_resource = {
+ .start = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE,
+ .end = DAVINCI_ASYNC_EMIF_DATA_CE0_BASE + SZ_16M - 1,
.flags = IORESOURCE_MEM,
};
-static struct platform_device davinci_evm_flash_device = {
+static struct platform_device davinci_evm_norflash_device = {
.name = "physmap-flash",
.id = 0,
.dev = {
- .platform_data = &davinci_evm_flash_data,
+ .platform_data = &davinci_evm_norflash_data,
},
.num_resources = 1,
- .resource = &davinci_evm_flash_resource,
+ .resource = &davinci_evm_norflash_resource,
+};
+
+#endif
+
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+
+static struct resource ide_resources[] = {
+ {
+ .start = DAVINCI_CFC_ATA_BASE,
+ .end = DAVINCI_CFC_ATA_BASE + 0x7ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_IDE,
+ .end = IRQ_IDE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 ide_dma_mask = DMA_32BIT_MASK;
+
+static struct platform_device ide_dev = {
+ .name = "palm_bk3710",
+ .id = -1,
+ .resource = ide_resources,
+ .num_resources = ARRAY_SIZE(ide_resources),
+ .dev = {
+ .dma_mask = &ide_dma_mask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+};
+
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * I2C GPIO expanders
+ */
+
+#define PCF_Uxx_BASE(x) (DAVINCI_N_GPIO + ((x) * 8))
+
+
+/* U2 -- LEDs */
+
+static struct gpio_led evm_leds[] = {
+ { .name = "DS8", .active_low = 1,
+ .default_trigger = "heartbeat", },
+ { .name = "DS7", .active_low = 1, },
+ { .name = "DS6", .active_low = 1, },
+ { .name = "DS5", .active_low = 1, },
+ { .name = "DS4", .active_low = 1, },
+ { .name = "DS3", .active_low = 1, },
+ { .name = "DS2", .active_low = 1,
+ .default_trigger = "mmc0", },
+ { .name = "DS1", .active_low = 1,
+ .default_trigger = "ide-disk", },
+};
+
+static const struct gpio_led_platform_data evm_led_data = {
+ .num_leds = ARRAY_SIZE(evm_leds),
+ .leds = evm_leds,
+};
+
+static struct platform_device *evm_led_dev;
+
+static int
+evm_led_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ struct gpio_led *leds = evm_leds;
+ int status;
+
+ while (ngpio--) {
+ leds->gpio = gpio++;
+ leds++;
+ }
+
+ /* what an extremely annoying way to be forced to handle
+ * device unregistration ...
+ */
+ evm_led_dev = platform_device_alloc("leds-gpio", 0);
+ platform_device_add_data(evm_led_dev,
+ &evm_led_data, sizeof evm_led_data);
+
+ evm_led_dev->dev.parent = &client->dev;
+ status = platform_device_add(evm_led_dev);
+ if (status < 0) {
+ platform_device_put(evm_led_dev);
+ evm_led_dev = NULL;
+ }
+ return status;
+}
+
+static int
+evm_led_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ if (evm_led_dev) {
+ platform_device_unregister(evm_led_dev);
+ evm_led_dev = NULL;
+ }
+ return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u2 = {
+ .gpio_base = PCF_Uxx_BASE(0),
+ .setup = evm_led_setup,
+ .teardown = evm_led_teardown,
+};
+
+
+/* U18 - A/V clock generator and user switch */
+
+static int sw_gpio;
+
+static ssize_t
+sw_show(struct device *d, struct device_attribute *a, char *buf)
+{
+ char *s = gpio_get_value_cansleep(sw_gpio) ? "on\n" : "off\n";
+
+ strcpy(buf, s);
+ return strlen(s);
+}
+
+static DEVICE_ATTR(user_sw, S_IRUGO, sw_show, NULL);
+
+static int
+evm_u18_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ int status;
+
+ /* export dip switch option */
+ sw_gpio = gpio + 7;
+ status = gpio_request(sw_gpio, "user_sw");
+ if (status == 0)
+ status = gpio_direction_input(sw_gpio);
+ if (status == 0)
+ status = device_create_file(&client->dev, &dev_attr_user_sw);
+ else
+ gpio_free(sw_gpio);
+ if (status != 0)
+ sw_gpio = -EINVAL;
+
+ /* audio PLL: 48 kHz (vs 44.1 or 32), single rate (vs double) */
+ gpio_request(gpio + 3, "pll_fs2");
+ gpio_direction_output(gpio + 3, 0);
+
+ gpio_request(gpio + 2, "pll_fs1");
+ gpio_direction_output(gpio + 2, 0);
+
+ gpio_request(gpio + 1, "pll_sr");
+ gpio_direction_output(gpio + 1, 0);
+
+ return 0;
+}
+
+static int
+evm_u18_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ gpio_free(gpio + 1);
+ gpio_free(gpio + 2);
+ gpio_free(gpio + 3);
+
+ if (sw_gpio > 0) {
+ device_remove_file(&client->dev, &dev_attr_user_sw);
+ gpio_free(sw_gpio);
+ }
+ return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u18 = {
+ .gpio_base = PCF_Uxx_BASE(1),
+ .n_latch = (1 << 3) | (1 << 2) | (1 << 1),
+ .setup = evm_u18_setup,
+ .teardown = evm_u18_teardown,
};
+
+/* U35 - various I/O signals used to manage USB, CF, ATA, etc */
+
+static int
+evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ /* p0 = nDRV_VBUS (initial: don't supply it) */
+ gpio_request(gpio + 0, "nDRV_VBUS");
+ gpio_direction_output(gpio + 0, 1);
+
+ /* p1 = VDDIMX_EN */
+ gpio_request(gpio + 1, "VDDIMX_EN");
+ gpio_direction_output(gpio + 1, 1);
+
+ /* p2 = VLYNQ_EN */
+ gpio_request(gpio + 2, "VLYNQ_EN");
+ gpio_direction_output(gpio + 2, 1);
+
+ /* p3 = n3V3_CF_RESET (initial: stay in reset) */
+ gpio_request(gpio + 3, "nCF_RESET");
+ gpio_direction_output(gpio + 3, 0);
+
+ /* (p4 unused) */
+
+ /* p5 = 1V8_WLAN_RESET (initial: stay in reset) */
+ gpio_request(gpio + 5, "WLAN_RESET");
+ gpio_direction_output(gpio + 5, 1);
+
+ /* p6 = nATA_SEL (initial: select) */
+ gpio_request(gpio + 6, "nATA_SEL");
+ gpio_direction_output(gpio + 6, 0);
+
+ /* p7 = nCF_SEL (initial: deselect) */
+ gpio_request(gpio + 7, "nCF_SEL");
+ gpio_direction_output(gpio + 7, 1);
+
+ return 0;
+}
+
+static int
+evm_u35_teardown(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
+{
+ gpio_free(gpio + 7);
+ gpio_free(gpio + 6);
+ gpio_free(gpio + 5);
+ gpio_free(gpio + 3);
+ gpio_free(gpio + 2);
+ gpio_free(gpio + 1);
+ gpio_free(gpio + 0);
+ return 0;
+}
+
+static struct pcf857x_platform_data pcf_data_u35 = {
+ .gpio_base = PCF_Uxx_BASE(2),
+ .setup = evm_u35_setup,
+ .teardown = evm_u35_teardown,
+};
+
+/*----------------------------------------------------------------------*/
+
+/* Most of this EEPROM is unused, but U-Boot uses some data:
+ * - 0x7f00, 6 bytes Ethernet Address
+ * - 0x0039, 1 byte NTSC vs PAL (bit 0x80 == PAL)
+ * - ... newer boards may have more
+ */
+static struct at24_platform_data eeprom_info = {
+ .byte_len = (256*1024) / 8,
+ .page_size = 64,
+ .flags = AT24_FLAG_ADDR16,
+};
+
+static struct i2c_board_info __initdata i2c_info[] = {
+ {
+ I2C_BOARD_INFO("pcf8574", 0x38),
+ .platform_data = &pcf_data_u2,
+ },
+ {
+ I2C_BOARD_INFO("pcf8574", 0x39),
+ .platform_data = &pcf_data_u18,
+ },
+ {
+ I2C_BOARD_INFO("pcf8574", 0x3a),
+ .platform_data = &pcf_data_u35,
+ },
+ {
+ I2C_BOARD_INFO("24c256", 0x50),
+ .platform_data = &eeprom_info,
+ },
+ /* ALSO:
+ * - tvl320aic33 audio codec (0x1b)
+ * - msp430 microcontroller (0x23)
+ * - tvp5146 video decoder (0x5d)
+ */
+};
+
+/* The msp430 uses a slow bitbanged I2C implementation (ergo 20 KHz),
+ * which requires 100 usec of idle bus after i2c writes sent to it.
+ */
+static struct davinci_i2c_platform_data i2c_pdata = {
+ .bus_freq = 20 /* kHz */,
+ .bus_delay = 100 /* usec */,
+};
+
+static void __init evm_init_i2c(void)
+{
+ davinci_init_i2c(&i2c_pdata);
+ i2c_register_board_info(1, i2c_info, ARRAY_SIZE(i2c_info));
+}
+
static struct platform_device *davinci_evm_devices[] __initdata = {
- &davinci_evm_flash_device,
+#if defined(CONFIG_MTD_PHYSMAP) || \
+ defined(CONFIG_MTD_PHYSMAP_MODULE)
+ &davinci_evm_norflash_device,
+#endif
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+ &ide_dev,
+#endif
};
static void __init
@@ -106,13 +405,21 @@ static __init void davinci_evm_init(void)
{
davinci_psc_init();
-#if defined(CONFIG_BLK_DEV_DAVINCI) || defined(CONFIG_BLK_DEV_DAVINCI_MODULE)
+#if defined(CONFIG_BLK_DEV_PALMCHIP_BK3710) || \
+ defined(CONFIG_BLK_DEV_PALMCHIP_BK3710_MODULE)
+#if defined(CONFIG_MTD_PHYSMAP) || \
+ defined(CONFIG_MTD_PHYSMAP_MODULE)
printk(KERN_WARNING "WARNING: both IDE and NOR flash are enabled, "
"but share pins.\n\t Disable IDE for NOR support.\n");
#endif
+#endif
platform_add_devices(davinci_evm_devices,
ARRAY_SIZE(davinci_evm_devices));
+ evm_init_i2c();
+
+ /* irlml6401 sustains over 3A, switches 5V in under 8 msec */
+ setup_usb(500, 8);
}
static __init void davinci_evm_irq_init(void)
@@ -124,7 +431,7 @@ static __init void davinci_evm_irq_init(void)
MACHINE_START(DAVINCI_EVM, "DaVinci EVM")
/* Maintainer: MontaVista Software <source@mvista.com> */
.phys_io = IO_PHYS,
- .io_pg_offst = (io_p2v(IO_PHYS) >> 18) & 0xfffc,
+ .io_pg_offst = (__IO_ADDRESS(IO_PHYS) >> 18) & 0xfffc,
.boot_params = (DAVINCI_DDR_BASE + 0x100),
.map_io = davinci_evm_map_io,
.init_irq = davinci_evm_irq_init,
diff --git a/arch/arm/mach-davinci/devices.c b/arch/arm/mach-davinci/devices.c
new file mode 100644
index 0000000..3d4b1de
--- /dev/null
+++ b/arch/arm/mach-davinci/devices.c
@@ -0,0 +1,48 @@
+/*
+ * mach-davinci/devices.c
+ *
+ * DaVinci platform device setup/initialization
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/hardware.h>
+#include <mach/i2c.h>
+
+static struct resource i2c_resources[] = {
+ {
+ .start = DAVINCI_I2C_BASE,
+ .end = DAVINCI_I2C_BASE + 0x40,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_I2C,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct platform_device davinci_i2c_device = {
+ .name = "i2c_davinci",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(i2c_resources),
+ .resource = i2c_resources,
+};
+
+void __init davinci_init_i2c(struct davinci_i2c_platform_data *pdata)
+{
+ davinci_i2c_device.dev.platform_data = pdata;
+ (void) platform_device_register(&davinci_i2c_device);
+}
+
diff --git a/arch/arm/mach-davinci/gpio.c b/arch/arm/mach-davinci/gpio.c
index 574cb81..b49e9d0 100644
--- a/arch/arm/mach-davinci/gpio.c
+++ b/arch/arm/mach-davinci/gpio.c
@@ -1,7 +1,7 @@
/*
* TI DaVinci GPIO Support
*
- * Copyright (c) 2006 David Brownell
+ * Copyright (c) 2006-2007 David Brownell
* Copyright (c) 2007, MontaVista Software, Inc. <source@mvista.com>
*
* This program is free software; you can redistribute it and/or modify
@@ -26,47 +26,45 @@
#include <asm/mach/irq.h>
-static DEFINE_SPINLOCK(gpio_lock);
-static DECLARE_BITMAP(gpio_in_use, DAVINCI_N_GPIO);
-int gpio_request(unsigned gpio, const char *tag)
-{
- if (gpio >= DAVINCI_N_GPIO)
- return -EINVAL;
+static DEFINE_SPINLOCK(gpio_lock);
- if (test_and_set_bit(gpio, gpio_in_use))
- return -EBUSY;
+struct davinci_gpio {
+ struct gpio_chip chip;
+ struct gpio_controller *__iomem regs;
+};
- return 0;
-}
-EXPORT_SYMBOL(gpio_request);
+static struct davinci_gpio chips[DIV_ROUND_UP(DAVINCI_N_GPIO, 32)];
-void gpio_free(unsigned gpio)
-{
- if (gpio >= DAVINCI_N_GPIO)
- return;
-
- clear_bit(gpio, gpio_in_use);
-}
-EXPORT_SYMBOL(gpio_free);
/* create a non-inlined version */
-static struct gpio_controller *__iomem gpio2controller(unsigned gpio)
+static struct gpio_controller *__iomem __init gpio2controller(unsigned gpio)
{
return __gpio_to_controller(gpio);
}
+
+/*--------------------------------------------------------------------------*/
+
/*
- * Assuming the pin is muxed as a gpio output, set its output value.
+ * board setup code *MUST* set PINMUX0 and PINMUX1 as
+ * needed, and enable the GPIO clock.
*/
-void __gpio_set(unsigned gpio, int value)
+
+static int davinci_direction_in(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+ struct gpio_controller *__iomem g = d->regs;
+ u32 temp;
- __raw_writel(__gpio_mask(gpio), value ? &g->set_data : &g->clr_data);
-}
-EXPORT_SYMBOL(__gpio_set);
+ spin_lock(&gpio_lock);
+ temp = __raw_readl(&g->dir);
+ temp |= (1 << offset);
+ __raw_writel(temp, &g->dir);
+ spin_unlock(&gpio_lock);
+ return 0;
+}
/*
* Read the pin's value (works even if it's set up as output);
@@ -75,61 +73,72 @@ EXPORT_SYMBOL(__gpio_set);
* Note that changes are synched to the GPIO clock, so reading values back
* right after you've set them may give old values.
*/
-int __gpio_get(unsigned gpio)
+static int davinci_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+ struct gpio_controller *__iomem g = d->regs;
- return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
+ return (1 << offset) & __raw_readl(&g->in_data);
}
-EXPORT_SYMBOL(__gpio_get);
-
-/*--------------------------------------------------------------------------*/
-
-/*
- * board setup code *MUST* set PINMUX0 and PINMUX1 as
- * needed, and enable the GPIO clock.
- */
-
-int gpio_direction_input(unsigned gpio)
+static int
+davinci_direction_out(struct gpio_chip *chip, unsigned offset, int value)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+ struct gpio_controller *__iomem g = d->regs;
u32 temp;
- u32 mask;
-
- if (!g)
- return -EINVAL;
+ u32 mask = 1 << offset;
spin_lock(&gpio_lock);
- mask = __gpio_mask(gpio);
temp = __raw_readl(&g->dir);
- temp |= mask;
+ temp &= ~mask;
+ __raw_writel(mask, value ? &g->set_data : &g->clr_data);
__raw_writel(temp, &g->dir);
spin_unlock(&gpio_lock);
return 0;
}
-EXPORT_SYMBOL(gpio_direction_input);
-int gpio_direction_output(unsigned gpio, int value)
+/*
+ * Assuming the pin is muxed as a gpio output, set its output value.
+ */
+static void
+davinci_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
- struct gpio_controller *__iomem g = gpio2controller(gpio);
- u32 temp;
- u32 mask;
+ struct davinci_gpio *d = container_of(chip, struct davinci_gpio, chip);
+ struct gpio_controller *__iomem g = d->regs;
- if (!g)
- return -EINVAL;
+ __raw_writel((1 << offset), value ? &g->set_data : &g->clr_data);
+}
+
+static int __init davinci_gpio_setup(void)
+{
+ int i, base;
+
+ for (i = 0, base = 0;
+ i < ARRAY_SIZE(chips);
+ i++, base += 32) {
+ chips[i].chip.label = "DaVinci";
+
+ chips[i].chip.direction_input = davinci_direction_in;
+ chips[i].chip.get = davinci_gpio_get;
+ chips[i].chip.direction_output = davinci_direction_out;
+ chips[i].chip.set = davinci_gpio_set;
+
+ chips[i].chip.base = base;
+ chips[i].chip.ngpio = DAVINCI_N_GPIO - base;
+ if (chips[i].chip.ngpio > 32)
+ chips[i].chip.ngpio = 32;
+
+ chips[i].regs = gpio2controller(base);
+
+ gpiochip_add(&chips[i].chip);
+ }
- spin_lock(&gpio_lock);
- mask = __gpio_mask(gpio);
- temp = __raw_readl(&g->dir);
- temp &= ~mask;
- __raw_writel(mask, value ? &g->set_data : &g->clr_data);
- __raw_writel(temp, &g->dir);
- spin_unlock(&gpio_lock);
return 0;
}
-EXPORT_SYMBOL(gpio_direction_output);
+pure_initcall(davinci_gpio_setup);
+/*--------------------------------------------------------------------------*/
/*
* We expect irqs will normally be set up as input pins, but they can also be
* used as output pins ... which is convenient for testing.
diff --git a/arch/arm/mach-davinci/include/mach/common.h b/arch/arm/mach-davinci/include/mach/common.h
index a97dfbb..4b522e5 100644
--- a/arch/arm/mach-davinci/include/mach/common.h
+++ b/arch/arm/mach-davinci/include/mach/common.h
@@ -16,4 +16,7 @@ struct sys_timer;
extern struct sys_timer davinci_timer;
+/* parameters describe VBUS sourcing for host mode */
+extern void setup_usb(unsigned mA, unsigned potpgt_msec);
+
#endif /* __ARCH_ARM_MACH_DAVINCI_COMMON_H */
diff --git a/arch/arm/mach-davinci/include/mach/gpio.h b/arch/arm/mach-davinci/include/mach/gpio.h
index ec151cc..b3a2961 100644
--- a/arch/arm/mach-davinci/include/mach/gpio.h
+++ b/arch/arm/mach-davinci/include/mach/gpio.h
@@ -14,6 +14,7 @@
#define __DAVINCI_GPIO_H
#include <linux/io.h>
+#include <asm-generic/gpio.h>
#include <mach/hardware.h>
/*
@@ -27,13 +28,16 @@
* need to pay attention to PINMUX0 and PINMUX1 to be sure those pins are
* used as gpios, not with other peripherals.
*
- * GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation, and maybe
- * for later updates, code should write GPIO(N) or:
+ * On-chip GPIOs are numbered 0..(DAVINCI_N_GPIO-1). For documentation,
+ * and maybe for later updates, code should write GPIO(N) or:
* - GPIOV18(N) for 1.8V pins, N in 0..53; same as GPIO(0)..GPIO(53)
* - GPIOV33(N) for 3.3V pins, N in 0..17; same as GPIO(54)..GPIO(70)
*
* For GPIO IRQs use gpio_to_irq(GPIO(N)) or gpio_to_irq(GPIOV33(N)) etc
* for now, that's != GPIO(N)
+ *
+ * GPIOs can also be on external chips, numbered after the ones built-in
+ * to the DaVinci chip. For now, they won't be usable as IRQ sources.
*/
#define GPIO(X) (X) /* 0 <= X <= 70 */
#define GPIOV18(X) (X) /* 1.8V i/o; 0 <= X <= 53 */
@@ -67,11 +71,11 @@ __gpio_to_controller(unsigned gpio)
void *__iomem ptr;
if (gpio < 32)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
+ ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x10);
else if (gpio < 64)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
+ ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x38);
else if (gpio < DAVINCI_N_GPIO)
- ptr = (void *__iomem)IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
+ ptr = IO_ADDRESS(DAVINCI_GPIO_BASE + 0x60);
else
ptr = NULL;
return ptr;
@@ -83,25 +87,17 @@ static inline u32 __gpio_mask(unsigned gpio)
}
/* The get/set/clear functions will inline when called with constant
- * parameters, for low-overhead bitbanging. Illegal constant parameters
- * cause link-time errors.
+ * parameters referencing built-in GPIOs, for low-overhead bitbanging.
*
- * Otherwise, calls with variable parameters use outlined functions.
+ * Otherwise, calls with variable parameters or referencing external
+ * GPIOs (e.g. on GPIO expander chips) use outlined functions.
*/
-extern int __error_inval_gpio(void);
-
-extern void __gpio_set(unsigned gpio, int value);
-extern int __gpio_get(unsigned gpio);
-
static inline void gpio_set_value(unsigned gpio, int value)
{
- if (__builtin_constant_p(value)) {
+ if (__builtin_constant_p(value) && gpio < DAVINCI_N_GPIO) {
struct gpio_controller *__iomem g;
u32 mask;
- if (gpio >= DAVINCI_N_GPIO)
- __error_inval_gpio();
-
g = __gpio_to_controller(gpio);
mask = __gpio_mask(gpio);
if (value)
@@ -111,48 +107,47 @@ static inline void gpio_set_value(unsigned gpio, int value)
return;
}
- __gpio_set(gpio, value);
+ __gpio_set_value(gpio, value);
}
/* Returns zero or nonzero; works for gpios configured as inputs OR
- * as outputs.
+ * as outputs, at least for built-in GPIOs.
*
- * NOTE: changes in reported values are synchronized to the GPIO clock.
- * This is most easily seen after calling gpio_set_value() and then immediatly
- * gpio_get_value(), where the gpio_get_value() would return the old value
- * until the GPIO clock ticks and the new value gets latched.
+ * NOTE: for built-in GPIOs, changes in reported values are synchronized
+ * to the GPIO clock. This is easily seen after calling gpio_set_value()
+ * and then immediately gpio_get_value(), where the gpio_get_value() will
+ * return the old value until the GPIO clock ticks and the new value gets
+ * latched.
*/
-
static inline int gpio_get_value(unsigned gpio)
{
- struct gpio_controller *__iomem g;
-
- if (!__builtin_constant_p(gpio))
- return __gpio_get(gpio);
+ struct gpio_controller *__iomem g;
- if (gpio >= DAVINCI_N_GPIO)
- return __error_inval_gpio();
+ if (!__builtin_constant_p(gpio) || gpio >= DAVINCI_N_GPIO)
+ return __gpio_get_value(gpio);
g = __gpio_to_controller(gpio);
- return !!(__gpio_mask(gpio) & __raw_readl(&g->in_data));
+ return __gpio_mask(gpio) & __raw_readl(&g->in_data);
}
-/* powerup default direction is IN */
-extern int gpio_direction_input(unsigned gpio);
-extern int gpio_direction_output(unsigned gpio, int value);
-
-#include <asm-generic/gpio.h> /* cansleep wrappers */
-
-extern int gpio_request(unsigned gpio, const char *tag);
-extern void gpio_free(unsigned gpio);
+static inline int gpio_cansleep(unsigned gpio)
+{
+ if (__builtin_constant_p(gpio) && gpio < DAVINCI_N_GPIO)
+ return 0;
+ else
+ return __gpio_cansleep(gpio);
+}
static inline int gpio_to_irq(unsigned gpio)
{
+ if (gpio >= DAVINCI_N_GPIO)
+ return -EINVAL;
return DAVINCI_N_AINTC_IRQ + gpio;
}
static inline int irq_to_gpio(unsigned irq)
{
+ /* caller guarantees gpio_to_irq() succeeded */
return irq - DAVINCI_N_AINTC_IRQ;
}
diff --git a/arch/arm/mach-davinci/include/mach/i2c.h b/arch/arm/mach-davinci/include/mach/i2c.h
index e2f5416..c248e9b 100644
--- a/arch/arm/mach-davinci/include/mach/i2c.h
+++ b/arch/arm/mach-davinci/include/mach/i2c.h
@@ -14,8 +14,11 @@
/* All frequencies are expressed in kHz */
struct davinci_i2c_platform_data {
- unsigned int bus_freq; /* standard bus frequency */
- unsigned int bus_delay; /* transaction delay */
+ unsigned int bus_freq; /* standard bus frequency (kHz) */
+ unsigned int bus_delay; /* post-transaction delay (usec) */
};
+/* for board setup code */
+void davinci_init_i2c(struct davinci_i2c_platform_data *);
+
#endif /* __ASM_ARCH_I2C_H */
diff --git a/arch/arm/mach-davinci/include/mach/io.h b/arch/arm/mach-davinci/include/mach/io.h
index e7accb9..b78ee91 100644
--- a/arch/arm/mach-davinci/include/mach/io.h
+++ b/arch/arm/mach-davinci/include/mach/io.h
@@ -22,9 +22,8 @@
#define IO_OFFSET 0xfd000000 /* Virtual IO = 0xfec00000 */
#define IO_SIZE 0x00400000
#define IO_VIRT (IO_PHYS + IO_OFFSET)
-#define io_p2v(pa) ((pa) + IO_OFFSET)
#define io_v2p(va) ((va) - IO_OFFSET)
-#define IO_ADDRESS(x) io_p2v(x)
+#define __IO_ADDRESS(x) ((x) + IO_OFFSET)
/*
* We don't actually have real ISA nor PCI buses, but there is so many
@@ -35,7 +34,12 @@
#define __mem_pci(a) (a)
#define __mem_isa(a) (a)
-#ifndef __ASSEMBLER__
+#define IO_ADDRESS(pa) IOMEM(__IO_ADDRESS(pa))
+
+#ifdef __ASSEMBLER__
+#define IOMEM(x) x
+#else
+#define IOMEM(x) ((void __force __iomem *)(x))
/*
* Functions to access the DaVinci IO region
@@ -46,34 +50,13 @@
* - DO NOT use hardcoded virtual addresses to allow changing the
* IO address space again if needed
*/
-#define davinci_readb(a) (*(volatile unsigned char *)IO_ADDRESS(a))
-#define davinci_readw(a) (*(volatile unsigned short *)IO_ADDRESS(a))
-#define davinci_readl(a) (*(volatile unsigned int *)IO_ADDRESS(a))
-
-#define davinci_writeb(v,a) (*(volatile unsigned char *)IO_ADDRESS(a) = (v))
-#define davinci_writew(v,a) (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
-#define davinci_writel(v,a) (*(volatile unsigned int *)IO_ADDRESS(a) = (v))
-
-/* 16 bit uses LDRH/STRH, base +/- offset_8 */
-typedef struct { volatile u16 offset[256]; } __regbase16;
-#define __REGV16(vaddr) ((__regbase16 *)((vaddr)&~0xff)) \
- ->offset[((vaddr)&0xff)>>1]
-#define __REG16(paddr) __REGV16(io_p2v(paddr))
-
-/* 8/32 bit uses LDR/STR, base +/- offset_12 */
-typedef struct { volatile u8 offset[4096]; } __regbase8;
-#define __REGV8(vaddr) ((__regbase8 *)((vaddr)&~4095)) \
- ->offset[((vaddr)&4095)>>0]
-#define __REG8(paddr) __REGV8(io_p2v(paddr))
-
-typedef struct { volatile u32 offset[4096]; } __regbase32;
-#define __REGV32(vaddr) ((__regbase32 *)((vaddr)&~4095)) \
- ->offset[((vaddr)&4095)>>2]
-
-#define __REG(paddr) __REGV32(io_p2v(paddr))
-#else
+#define davinci_readb(a) __raw_readb(IO_ADDRESS(a))
+#define davinci_readw(a) __raw_readw(IO_ADDRESS(a))
+#define davinci_readl(a) __raw_readl(IO_ADDRESS(a))
-#define __REG(x) (*((volatile unsigned long *)io_p2v(x)))
+#define davinci_writeb(v, a) __raw_writeb(v, IO_ADDRESS(a))
+#define davinci_writew(v, a) __raw_writew(v, IO_ADDRESS(a))
+#define davinci_writel(v, a) __raw_writel(v, IO_ADDRESS(a))
#endif /* __ASSEMBLER__ */
#endif /* __ASM_ARCH_IO_H */
diff --git a/arch/arm/mach-davinci/usb.c b/arch/arm/mach-davinci/usb.c
new file mode 100644
index 0000000..fe182a8
--- /dev/null
+++ b/arch/arm/mach-davinci/usb.c
@@ -0,0 +1,116 @@
+/*
+ * USB
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/musb.h>
+#include <linux/usb/otg.h>
+
+#include <mach/common.h>
+#include <mach/hardware.h>
+
+#if defined(CONFIG_USB_MUSB_HDRC) || defined(CONFIG_USB_MUSB_HDRC_MODULE)
+static struct musb_hdrc_eps_bits musb_eps[] = {
+ { "ep1_tx", 8, },
+ { "ep1_rx", 8, },
+ { "ep2_tx", 8, },
+ { "ep2_rx", 8, },
+ { "ep3_tx", 5, },
+ { "ep3_rx", 5, },
+ { "ep4_tx", 5, },
+ { "ep4_rx", 5, },
+};
+
+static struct musb_hdrc_config musb_config = {
+ .multipoint = true,
+ .dyn_fifo = true,
+ .soft_con = true,
+ .dma = true,
+
+ .num_eps = 5,
+ .dma_channels = 8,
+ .ram_bits = 10,
+ .eps_bits = musb_eps,
+};
+
+static struct musb_hdrc_platform_data usb_data = {
+#if defined(CONFIG_USB_MUSB_OTG)
+ /* OTG requires a Mini-AB connector */
+ .mode = MUSB_OTG,
+#elif defined(CONFIG_USB_MUSB_PERIPHERAL)
+ .mode = MUSB_PERIPHERAL,
+#elif defined(CONFIG_USB_MUSB_HOST)
+ .mode = MUSB_HOST,
+#endif
+ .config = &musb_config,
+};
+
+static struct resource usb_resources[] = {
+ {
+ /* physical address */
+ .start = DAVINCI_USB_OTG_BASE,
+ .end = DAVINCI_USB_OTG_BASE + 0x5ff,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .start = IRQ_USBINT,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 usb_dmamask = DMA_32BIT_MASK;
+
+static struct platform_device usb_dev = {
+ .name = "musb_hdrc",
+ .id = -1,
+ .dev = {
+ .platform_data = &usb_data,
+ .dma_mask = &usb_dmamask,
+ .coherent_dma_mask = DMA_32BIT_MASK,
+ },
+ .resource = usb_resources,
+ .num_resources = ARRAY_SIZE(usb_resources),
+};
+
+#ifdef CONFIG_USB_MUSB_OTG
+
+static struct otg_transceiver *xceiv;
+
+struct otg_transceiver *otg_get_transceiver(void)
+{
+ if (xceiv)
+ get_device(xceiv->dev);
+ return xceiv;
+}
+EXPORT_SYMBOL(otg_get_transceiver);
+
+int otg_set_transceiver(struct otg_transceiver *x)
+{
+ if (xceiv && x)
+ return -EBUSY;
+ xceiv = x;
+ return 0;
+}
+EXPORT_SYMBOL(otg_set_transceiver);
+
+#endif
+
+void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+{
+ usb_data.power = mA / 2;
+ usb_data.potpgt = potpgt_msec / 2;
+ platform_device_register(&usb_dev);
+}
+
+#else
+
+void __init setup_usb(unsigned mA, unsigned potpgt_msec)
+{
+}
+
+#endif /* CONFIG_USB_MUSB_HDRC */
+
OpenPOWER on IntegriCloud