i2c.c 5.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*
 * 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>
29
#include <mach/irqs.h>
30
#include <mach/mux.h>
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82

#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
};

83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
#if defined(CONFIG_ARCH_OMAP24XX)
static const int omap24xx_pins[][2] = {
	{ M19_24XX_I2C1_SCL, L15_24XX_I2C1_SDA },
	{ J15_24XX_I2C2_SCL, H19_24XX_I2C2_SDA },
};
#else
static const int omap24xx_pins[][2] = {};
#endif
#if defined(CONFIG_ARCH_OMAP34XX)
static const int omap34xx_pins[][2] = {
	{ K21_34XX_I2C1_SCL, J21_34XX_I2C1_SDA},
	{ AF15_34XX_I2C2_SCL, AE15_34XX_I2C2_SDA},
	{ AF14_34XX_I2C3_SCL, AG14_34XX_I2C3_SDA},
};
#else
static const int omap34xx_pins[][2] = {};
#endif

static void __init omap_i2c_mux_pins(int bus)
102
{
103 104 105 106 107 108 109 110 111 112 113 114 115
	int scl, sda;

	if (cpu_class_is_omap1()) {
		scl = I2C_SCL;
		sda = I2C_SDA;
	} else if (cpu_is_omap24xx()) {
		scl = omap24xx_pins[bus][0];
		sda = omap24xx_pins[bus][1];
	} else if (cpu_is_omap34xx()) {
		scl = omap34xx_pins[bus][0];
		sda = omap34xx_pins[bus][1];
	} else {
		return;
116
	}
117 118 119

	omap_cfg_reg(sda);
	omap_cfg_reg(scl);
120 121
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
static int __init omap_i2c_nr_ports(void)
{
	int ports = 0;

	if (cpu_class_is_omap1())
		ports = 1;
	else if (cpu_is_omap24xx())
		ports = 2;
	else if (cpu_is_omap34xx())
		ports = 3;

	return ports;
}

/**
 * omap_i2c_bus_setup - Process command line options for the I2C bus speed
 * @str: String of options
 *
 * This function allow to override the default I2C bus speed for given I2C
 * bus with a command line option.
 *
 * Format: i2c_bus=bus_id,clkrate (in kHz)
 *
 * Returns 1 on success, 0 otherwise.
 */
static int __init omap_i2c_bus_setup(char *str)
{
	int ports;
	int ints[3];

	ports = omap_i2c_nr_ports();
	get_options(str, 3, ints);
	if (ints[0] < 2 || ints[1] < 1 || ints[1] > ports)
		return 0;
	i2c_rate[ints[1] - 1] = ints[2];

	return 1;
}
__setup("i2c_bus=", omap_i2c_bus_setup);

162 163 164 165 166 167 168 169 170
/**
 * omap_register_i2c_bus - register I2C bus with device descriptors
 * @bus_id: bus id counting from number 1
 * @clkrate: clock rate of the bus in kHz
 * @info: pointer into I2C device descriptor table or NULL
 * @len: number of descriptors in the table
 *
 * Returns 0 on success or an error code.
 */
171 172 173 174
int __init omap_register_i2c_bus(int bus_id, u32 clkrate,
			  struct i2c_board_info const *info,
			  unsigned len)
{
175
	int err;
176 177 178 179
	struct platform_device *pdev;
	struct resource *res;
	resource_size_t base, irq;

180
	BUG_ON(bus_id < 1 || bus_id > omap_i2c_nr_ports());
181 182 183 184 185 186 187 188

	if (info) {
		err = i2c_register_board_info(bus_id, info, len);
		if (err)
			return err;
	}

	pdev = &omap_i2c_devices[bus_id - 1];
189 190
	if (i2c_rate[bus_id - 1] == 0)
		i2c_rate[bus_id - 1] = clkrate;
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205

	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;
	}

206
	omap_i2c_mux_pins(bus_id - 1);
207 208
	return platform_device_register(pdev);
}