diff options
-rw-r--r-- | arch/arm/plat-omap/Makefile | 1 | ||||
-rw-r--r-- | arch/arm/plat-omap/i2c.c | 148 | ||||
-rw-r--r-- | include/asm-arm/arch-omap/common.h | 11 | ||||
-rw-r--r-- | include/asm-arm/arch-omap/irqs.h | 2 |
4 files changed, 162 insertions, 0 deletions
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile index 2549129aabc6..ce17df31b845 100644 --- a/arch/arm/plat-omap/Makefile +++ b/arch/arm/plat-omap/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_CPU_FREQ) += cpu-omap.o obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o obj-$(CONFIG_OMAP_DEBUG_DEVICES) += debug-devices.o obj-$(CONFIG_OMAP_DEBUG_LEDS) += debug-leds.o +obj-$(CONFIG_I2C_OMAP) += i2c.o diff --git a/arch/arm/plat-omap/i2c.c b/arch/arm/plat-omap/i2c.c new file mode 100644 index 000000000000..7990ab185bb1 --- /dev/null +++ b/arch/arm/plat-omap/i2c.c @@ -0,0 +1,148 @@ +/* + * linux/arch/arm/plat-omap/i2c.c + * + * Helper module for board specific I2C bus registration + * + * Copyright (C) 2007 Nokia Corporation. + * + * Contact: Jarkko Nikula <jarkko.nikula@nokia.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <linux/kernel.h> +#include <linux/platform_device.h> +#include <linux/i2c.h> +#include <asm/mach-types.h> +#include <asm/arch/mux.h> + +#define OMAP_I2C_SIZE 0x3f +#define OMAP1_I2C_BASE 0xfffb3800 +#define OMAP2_I2C_BASE1 0x48070000 +#define OMAP2_I2C_BASE2 0x48072000 +#define OMAP2_I2C_BASE3 0x48060000 + +static const char name[] = "i2c_omap"; + +#define I2C_RESOURCE_BUILDER(base, irq) \ + { \ + .start = (base), \ + .end = (base) + OMAP_I2C_SIZE, \ + .flags = IORESOURCE_MEM, \ + }, \ + { \ + .start = (irq), \ + .flags = IORESOURCE_IRQ, \ + }, + +static struct resource i2c_resources[][2] = { + { I2C_RESOURCE_BUILDER(0, 0) }, +#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) + { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE2, INT_24XX_I2C2_IRQ) }, +#endif +#if defined(CONFIG_ARCH_OMAP34XX) + { I2C_RESOURCE_BUILDER(OMAP2_I2C_BASE3, INT_34XX_I2C3_IRQ) }, +#endif +}; + +#define I2C_DEV_BUILDER(bus_id, res, data) \ + { \ + .id = (bus_id), \ + .name = name, \ + .num_resources = ARRAY_SIZE(res), \ + .resource = (res), \ + .dev = { \ + .platform_data = (data), \ + }, \ + } + +static u32 i2c_rate[ARRAY_SIZE(i2c_resources)]; +static struct platform_device omap_i2c_devices[] = { + I2C_DEV_BUILDER(1, i2c_resources[0], &i2c_rate[0]), +#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) + I2C_DEV_BUILDER(2, i2c_resources[1], &i2c_rate[1]), +#endif +#if defined(CONFIG_ARCH_OMAP34XX) + I2C_DEV_BUILDER(3, i2c_resources[2], &i2c_rate[2]), +#endif +}; + +static void __init omap_i2c_mux_pins(int bus_id) +{ + /* TODO: Muxing for OMAP3 */ + switch (bus_id) { + case 1: + if (cpu_class_is_omap1()) { + omap_cfg_reg(I2C_SCL); + omap_cfg_reg(I2C_SDA); + } else if (cpu_is_omap24xx()) { + omap_cfg_reg(M19_24XX_I2C1_SCL); + omap_cfg_reg(L15_24XX_I2C1_SDA); + } + break; + case 2: + if (cpu_is_omap24xx()) { + omap_cfg_reg(J15_24XX_I2C2_SCL); + omap_cfg_reg(H19_24XX_I2C2_SDA); + } + break; + } +} + +int __init omap_register_i2c_bus(int bus_id, u32 clkrate, + struct i2c_board_info const *info, + unsigned len) +{ + int ports, err; + struct platform_device *pdev; + struct resource *res; + resource_size_t base, irq; + + if (cpu_class_is_omap1()) + ports = 1; + else if (cpu_is_omap24xx()) + ports = 2; + else if (cpu_is_omap34xx()) + ports = 3; + + BUG_ON(bus_id < 1 || bus_id > ports); + + if (info) { + err = i2c_register_board_info(bus_id, info, len); + if (err) + return err; + } + + pdev = &omap_i2c_devices[bus_id - 1]; + *(u32 *)pdev->dev.platform_data = clkrate; + + if (bus_id == 1) { + res = pdev->resource; + if (cpu_class_is_omap1()) { + base = OMAP1_I2C_BASE; + irq = INT_I2C; + } else { + base = OMAP2_I2C_BASE1; + irq = INT_24XX_I2C1_IRQ; + } + res[0].start = base; + res[0].end = base + OMAP_I2C_SIZE; + res[1].start = irq; + } + + omap_i2c_mux_pins(bus_id); + return platform_device_register(pdev); +} diff --git a/include/asm-arm/arch-omap/common.h b/include/asm-arm/arch-omap/common.h index 08d58abd8218..442aecbb8f44 100644 --- a/include/asm-arm/arch-omap/common.h +++ b/include/asm-arm/arch-omap/common.h @@ -27,10 +27,21 @@ #ifndef __ARCH_ARM_MACH_OMAP_COMMON_H #define __ARCH_ARM_MACH_OMAP_COMMON_H +#ifdef CONFIG_I2C_OMAP +#include <linux/i2c.h> +#endif + struct sys_timer; extern void omap_map_common_io(void); extern struct sys_timer omap_timer; extern void omap_serial_init(void); +#ifdef CONFIG_I2C_OMAP +extern int omap_register_i2c_bus(int bus_id, u32 clkrate, + struct i2c_board_info const *info, + unsigned len); +#else +#define omap_register_i2c_bus(a, b, c, d) 0 +#endif #endif /* __ARCH_ARM_MACH_OMAP_COMMON_H */ diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h index 3ede58b51db2..87973654e625 100644 --- a/include/asm-arm/arch-omap/irqs.h +++ b/include/asm-arm/arch-omap/irqs.h @@ -263,6 +263,8 @@ #define INT_24XX_GPTIMER10 46 #define INT_24XX_GPTIMER11 47 #define INT_24XX_GPTIMER12 48 +#define INT_24XX_I2C1_IRQ 56 +#define INT_24XX_I2C2_IRQ 57 #define INT_24XX_MCBSP1_IRQ_TX 59 #define INT_24XX_MCBSP1_IRQ_RX 60 #define INT_24XX_MCBSP2_IRQ_TX 62 |