[PATCH 1/4] i2c: new framework

Marc Kleine-Budde mkl at pengutronix.de
Mon Nov 23 07:20:07 EST 2009


Signed-off-by: Marc Kleine-Budde <mkl at pengutronix.de>
---
 drivers/Kconfig      |    1 +
 drivers/Makefile     |    1 +
 drivers/i2c/Kconfig  |    2 +
 drivers/i2c/Makefile |    1 +
 drivers/i2c/i2c.c    |  362 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/i2c/i2c.h    |  147 ++++++++++++++++++++
 6 files changed, 514 insertions(+), 0 deletions(-)
 create mode 100644 drivers/i2c/Kconfig
 create mode 100644 drivers/i2c/Makefile
 create mode 100644 drivers/i2c/i2c.c
 create mode 100644 include/i2c/i2c.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index eb3a587..8bab7ac 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -3,6 +3,7 @@ menu "Drivers                       "
 source "drivers/serial/Kconfig"
 source "drivers/net/Kconfig"
 source "drivers/spi/Kconfig"
+source "drivers/i2c/Kconfig"
 source "drivers/nor/Kconfig"
 source "drivers/nand/Kconfig"
 source "drivers/usb/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 518060a..5dc7756 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -4,4 +4,5 @@ obj-y	+= nand/
 obj-y	+= nor/
 obj-y	+= usb/
 obj-$(CONFIG_SPI) += spi/
+obj-$(CONFIG_I2C) += i2c/
 obj-$(CONFIG_VIDEO) += video/
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
new file mode 100644
index 0000000..4d0f8da
--- /dev/null
+++ b/drivers/i2c/Kconfig
@@ -0,0 +1,2 @@
+menuconfig I2C
+	bool "I2C drivers                   "
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
new file mode 100644
index 0000000..9a37393
--- /dev/null
+++ b/drivers/i2c/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_I2C) += i2c.o
diff --git a/drivers/i2c/i2c.c b/drivers/i2c/i2c.c
new file mode 100644
index 0000000..e09d8e8
--- /dev/null
+++ b/drivers/i2c/i2c.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2009 Marc Kleine-Budde <mkl at pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ *
+ * Derived from:
+ * - i2c-core.c - a device driver for the iic-bus interface
+ *   Copyright (C) 1995-99 Simon G. Vogl
+ * - at24.c - handle most I2C EEPROMs
+ *   Copyright (C) 2005-2007 David Brownell
+ *   Copyright (C) 2008 Wolfram Sang, Pengutronix
+ * - spi.c - u-boot-v2 SPI Framework
+ *   Copyright (C) 2008 Sascha Hauer, Pengutronix
+ * - Linux SPI Framework
+ *   Copyright (C) 2005 David Brownell
+ *
+ */
+
+#include <clock.h>
+#include <common.h>
+#include <errno.h>
+#include <malloc.h>
+#include <xfuncs.h>
+
+#include <i2c/i2c.h>
+
+/*
+ * I2C devices should normally not be created by I2C device drivers; that
+ * would make them board-specific.  Similarly with I2C master drivers.
+ * Device registration normally goes into like arch/.../mach.../board-YYY.c
+ * with other readonly (flashable) information about mainboard devices.
+ */
+struct boardinfo {
+	struct list_head	list;
+	unsigned int		bus_num;
+	unsigned int		n_board_info;
+	struct i2c_board_info	board_info[0];
+};
+
+static LIST_HEAD(board_list);
+
+
+/**
+ * i2c_transfer - execute a single or combined I2C message
+ * @adap: Handle to I2C bus
+ * @msgs: One or more messages to execute before STOP is issued to
+ *	terminate the operation; each message begins with a START.
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Note that there is no requirement that each message be sent to
+ * the same slave address, although that is the most common model.
+ */
+int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	uint64_t start;
+	int ret, try;
+
+	/*
+	 * REVISIT the fault reporting model here is weak:
+	 *
+	 *  - When we get an error after receiving N bytes from a slave,
+	 *    there is no way to report "N".
+	 *
+	 *  - When we get a NAK after transmitting N bytes to a slave,
+	 *    there is no way to report "N" ... or to let the master
+	 *    continue executing the rest of this combined message, if
+	 *    that's the appropriate response.
+	 *
+	 *  - When for example "num" is two and we successfully complete
+	 *    the first message but get an error part way through the
+	 *    second, it's unclear whether that should be reported as
+	 *    one (discarding status on the second message) or errno
+	 *    (discarding status on the first one).
+	 */
+
+#ifdef DEBUG
+	for (ret = 0; ret < num; ret++) {
+		dev_dbg(adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+			"len=%d\n", ret, (msgs[ret].flags & I2C_M_RD)
+			? 'R' : 'W', msgs[ret].addr, msgs[ret].len);
+	}
+#endif
+
+	/* Retry automatically on arbitration loss */
+	start = get_time_ns();
+	for (ret = 0, try = 0; try <= 2; try++) {
+		ret = adap->master_xfer(adap, msgs, num);
+		if (ret != -EAGAIN)
+			break;
+		if (is_timeout(start, 500 * 1000 * 1000))	/* 500 ms */
+			break;
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(i2c_transfer);
+
+
+/**
+ * i2c_master_send - issue a single I2C message in master transmit mode
+ * @client: Handle to slave device
+ * @buf: Data that will be written to the slave
+ * @count: How many bytes to write
+ *
+ * Returns negative errno, or else the number of bytes written.
+ */
+int i2c_master_send(struct i2c_client *client, const char *buf, int count)
+{
+	int ret;
+	struct i2c_adapter *adap=client->adapter;
+	struct i2c_msg msg;
+
+	msg.addr = client->addr;
+	msg.len = count;
+	msg.buf = (char *)buf;
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	/*
+	 * If everything went ok (i.e. 1 msg transmitted), return
+	 * #bytes transmitted, else error code.
+	 */
+	return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_send);
+
+
+/**
+ * i2c_master_recv - issue a single I2C message in master receive mode
+ * @client: Handle to slave device
+ * @buf: Where to store data read from slave
+ * @count: How many bytes to read
+ *
+ * Returns negative errno, or else the number of bytes read.
+ */
+int i2c_master_recv(struct i2c_client *client, char *buf, int count)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_msg msg;
+	int ret;
+
+	msg.addr = client->addr;
+	msg.flags = I2C_M_RD;
+	msg.len = count;
+	msg.buf = buf;
+
+	ret = i2c_transfer(adap, &msg, 1);
+
+	/*
+	 * If everything went ok (i.e. 1 msg transmitted), return
+	 * #bytes transmitted, else error code.
+	 */
+	return (ret == 1) ? count : ret;
+}
+EXPORT_SYMBOL(i2c_master_recv);
+
+
+int i2c_read_reg(struct i2c_client *client, u32 addr, u8 *buf, u16 count)
+{
+	u8 msgbuf[2];
+	struct i2c_msg msg[] = {
+		{
+			.addr	= client->addr,
+			.buf	= msgbuf,
+		},
+		{
+			.addr	= client->addr,
+			.flags	= I2C_M_RD,
+			.buf	= buf,
+			.len	= count,
+		},
+	};
+	int status, i;
+
+	i = 0;
+	if (addr & I2C_ADDR_16_BIT)
+		msgbuf[i++] = addr >> 8;
+	msgbuf[i++] = addr;
+	msg->len = i;
+
+	status = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+	dev_dbg(&client->dev, "%s: %zu@%d --> %d\n", __func__,
+		count, addr, status);
+
+	if (status == ARRAY_SIZE(msg))
+		return count;
+	else if (status >= 0)
+		return -EIO;
+	else
+		return status;
+}
+
+
+int i2c_write_reg(struct i2c_client *client, u32 addr, const u8 *buf, u16 count)
+{
+	u8 msgbuf[256];				/* FIXME */
+	struct i2c_msg msg[] = {
+		{
+			.addr	= client->addr,
+			.buf	= msgbuf,
+			.len	= count,
+		}
+	};
+	int status, i;
+
+	i = 0;
+	if (addr & I2C_ADDR_16_BIT)
+		msgbuf[i++] = addr >> 8;
+	msgbuf[i++] = addr;
+	msg->len += i;
+
+	memcpy(msg->buf + i, buf, count);
+
+	status = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+	dev_dbg(&client->dev, "%s: %u@%d --> %d\n", __func__,
+		count, addr, status);
+
+	if (status == ARRAY_SIZE(msg))
+		return count;
+	else if (status >= 0)
+		return -EIO;
+	else
+		return status;
+}
+
+
+/**
+ * i2c_new_device - instantiate one new I2C device
+ * @adapter: Controller to which device is connected
+ * @chip: Describes the I2C device
+ *
+ * On typical mainboards, this is purely internal; and it's not needed
+ * after board init creates the hard-wired devices.  Some development
+ * platforms may not be able to use i2c_register_board_info though, and
+ * this is exported so that for example a USB or parport based adapter
+ * driver could add devices (which it would learn about out-of-band).
+ *
+ * Returns the new device, or NULL.
+ */
+struct i2c_client *i2c_new_device(struct i2c_adapter *adapter,
+				  struct i2c_board_info *chip)
+{
+	struct i2c_client *client;
+	int status;
+
+	client = xzalloc(sizeof *client);
+	strcpy(client->dev.name, chip->type);
+	client->dev.type_data = client;
+	client->adapter = adapter;
+	client->addr = chip->addr;
+
+	status = register_device(&client->dev);
+
+#if 0
+	/* drivers may modify this initial i/o setup */
+	status = master->setup(client);
+	if (status < 0) {
+		printf("can't setup %s, status %d\n",
+		       client->dev.name, status);
+		goto fail;
+	}
+#endif
+
+	return client;
+
+#if 0
+ fail:
+	free(proxy);
+	return NULL;
+#endif
+}
+EXPORT_SYMBOL(i2c_new_device);
+
+/**
+ * i2c_register_board_info - register I2C devices for a given board
+ * @info: array of chip descriptors
+ * @n: how many descriptors are provided
+ * Context: can sleep
+ *
+ * Board-specific early init code calls this (probably during arch_initcall)
+ * with segments of the I2C device table.  Any device nodes are created later,
+ * after the relevant parent I2C controller (bus_num) is defined.  We keep
+ * this table of devices forever, so that reloading a controller driver will
+ * not make Linux forget about these hard-wired devices.
+ *
+ * Other code can also call this, e.g. a particular add-on board might provide
+ * I2C devices through its expansion connector, so code initializing that board
+ * would naturally declare its I2C devices.
+ *
+ * The board info passed can safely be __initdata ... but be careful of
+ * any embedded pointers (platform_data, etc), they're copied as-is.
+ */
+int
+i2c_register_board_info(int bus_num, struct i2c_board_info const *info, unsigned n)
+{
+	struct boardinfo *bi;
+
+	bi = xmalloc(sizeof(*bi) + n * sizeof(*info));
+
+	bi->n_board_info = n;
+	bi->bus_num = bus_num;
+	memcpy(bi->board_info, info, n * sizeof(*info));
+
+	list_add_tail(&bi->list, &board_list);
+
+	return 0;
+}
+
+static void scan_boardinfo(struct i2c_adapter *adapter)
+{
+	struct boardinfo	*bi;
+
+	list_for_each_entry(bi, &board_list, list) {
+		struct i2c_board_info *chip = bi->board_info;
+		unsigned n;
+
+		if (bi->bus_num != adapter->nr)
+			continue;
+
+		for (n = bi->n_board_info; n > 0; n--, chip++) {
+			debug("%s: bus_num: %d, chip->addr 0x%02x\n", __func__, bi->bus_num, chip->addr);
+			/*
+			 * NOTE: this relies on i2c_new_device to
+			 * issue diagnostics when given bogus inputs
+			 */
+			(void) i2c_new_device(adapter, chip);
+		}
+	}
+}
+
+/**
+ * i2c_register_master - register I2C master controller
+ * @master: initialized master, originally from i2c_alloc_master()
+ * Context: can sleep
+ *
+ * I2C master controllers connect to their drivers using some non-I2C bus,
+ * such as the platform bus.  The final stage of probe() in that code
+ * includes calling i2c_register_master() to hook up to this I2C bus glue.
+ *
+ * I2C controllers use board specific (often SOC specific) bus numbers,
+ * and board-specific addressing for I2C devices combines those numbers
+ * with chip select numbers.  Since I2C does not directly support dynamic
+ * device identification, boards need configuration tables telling which
+ * chip is at which address.
+ *
+ * This must be called from context that can sleep.  It returns zero on
+ * success, else a negative error code (dropping the master's refcount).
+ * After a successful return, the caller is responsible for calling
+ * i2c_unregister_master().
+ */
+int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
+{
+	debug("%s: %s:%d\n", __func__, adapter->dev->name, adapter->dev->id);
+
+	/* populate children from any i2c device tables */
+	scan_boardinfo(adapter);
+
+	return 0;
+}
+EXPORT_SYMBOL(i2c_register_master);
diff --git a/include/i2c/i2c.h b/include/i2c/i2c.h
new file mode 100644
index 0000000..d94dff4
--- /dev/null
+++ b/include/i2c/i2c.h
@@ -0,0 +1,147 @@
+/*
+ * i2c.h - definitions for the u-boot-v2 i2c framework
+ *
+ * Copyricht (C) 2009 by Marc Kleine-Budde <mkl at pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ *
+ * Derived from:
+ * - i2c.h - i.MX I2C driver header file
+ *   Copyright (c) 2008, Darius Augulis <augulis.darius at gmail.com>
+ * - i2c.h - definitions for the i2c-bus interface
+ *   Copyright (C) 1995-2000 Simon G. Vogl
+ *
+ */
+
+#ifndef I2C_I2C_H
+#define I2C_I2C_H
+
+/**
+ * struct i2c_platform_data - structure of platform data for MXC I2C driver
+ * @bitrate:    Bus speed measured in Hz
+ *
+ **/
+struct i2c_platform_data {
+	int bitrate;
+};
+
+#define I2C_NAME_SIZE	20
+
+/**
+ * struct i2c_msg - an I2C transaction segment beginning with START
+ * @addr: Slave address, either seven or ten bits.  When this is a ten
+ *	bit address, I2C_M_TEN must be set in @flags and the adapter
+ *	must support I2C_FUNC_10BIT_ADDR.
+ * @flags: I2C_M_RD is handled by all adapters.  No other flags may be
+ *	provided unless the adapter exported the relevant I2C_FUNC_*
+ *	flags through i2c_check_functionality().
+ * @len: Number of data bytes in @buf being read from or written to the
+ *	I2C slave address.  For read transactions where I2C_M_RECV_LEN
+ *	is set, the caller guarantees that this buffer can hold up to
+ *	32 bytes in addition to the initial length byte sent by the
+ *	slave (plus, if used, the SMBus PEC); and this value will be
+ *	incremented by the number of block data bytes received.
+ * @buf: The buffer into which data is read, or from which it's written.
+ *
+ * An i2c_msg is the low level representation of one segment of an I2C
+ * transaction.  It is visible to drivers in the @i2c_transfer() procedure,
+ * to userspace from i2c-dev, and to I2C adapter drivers through the
+ * @i2c_adapter. at master_xfer() method.
+ *
+ * Except when I2C "protocol mangling" is used, all I2C adapters implement
+ * the standard rules for I2C transactions.  Each transaction begins with a
+ * START.  That is followed by the slave address, and a bit encoding read
+ * versus write.  Then follow all the data bytes, possibly including a byte
+ * with SMBus PEC.  The transfer terminates with a NAK, or when all those
+ * bytes have been transferred and ACKed.  If this is the last message in a
+ * group, it is followed by a STOP.  Otherwise it is followed by the next
+ * @i2c_msg transaction segment, beginning with a (repeated) START.
+ *
+ * Alternatively, when the adapter supports I2C_FUNC_PROTOCOL_MANGLING then
+ * passing certain @flags may have changed those standard protocol behaviors.
+ * Those flags are only for use with broken/nonconforming slaves, and with
+ * adapters which are known to support the specific mangling options they
+ * need (one or more of IGNORE_NAK, NO_RD_ACK, NOSTART, and REV_DIR_ADDR).
+ */
+
+struct i2c_msg {
+	__u8 *buf;		/* pointer to msg data */
+	__u16 addr;		/* slave address */
+#define I2C_M_RD		0x0001	/* read data, from slave to master */
+	__u16 flags;
+	__u16 len;		/* msg length */
+};
+
+
+/*
+ * i2c_adapter is the structure used to identify a physical i2c bus along
+ * with the access algorithms necessary to access it.
+ */
+struct i2c_adapter {
+	struct device_d *dev;
+
+	int nr;
+
+	int (*master_xfer)(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+};
+
+
+struct i2c_client {
+	struct device_d		dev;
+	struct i2c_adapter	*adapter;
+	unsigned short		addr;
+};
+
+#define to_i2c_client(a)	container_of(a, struct i2c_client, dev)
+
+
+/**
+ * struct i2c_board_info - template for device creation
+ * @type: chip type, to initialize i2c_client.name
+ * @flags: to initialize i2c_client.flags
+ * @addr: stored in i2c_client.addr
+ * @platform_data: stored in i2c_client.dev.platform_data
+ *
+ * I2C doesn't actually support hardware probing, although controllers and
+ * devices may be able to use I2C_SMBUS_QUICK to tell whether or not there's
+ * a device at a given address.  Drivers commonly need more information than
+ * that, such as chip type, configuration, associated IRQ, and so on.
+ *
+ * i2c_board_info is used to build tables of information listing I2C devices
+ * that are present.  This information is used to grow the driver model tree.
+ * For mainboards this is done statically using i2c_register_board_info();
+ * bus numbers identify adapters that aren't yet available.  For add-on boards,
+ * i2c_new_device() does this dynamically with the adapter already known.
+ */
+struct i2c_board_info {
+	char		type[I2C_NAME_SIZE];
+	unsigned short	addr;
+};
+
+/**
+ * I2C_BOARD_INFO - macro used to list an i2c device and its address
+ * @dev_type: identifies the device type
+ * @dev_addr: the device's address on the bus.
+ *
+ * This macro initializes essential fields of a struct i2c_board_info,
+ * declaring what has been provided on a particular board.  Optional
+ * fields (such as associated irq, or device-specific platform_data)
+ * are provided using conventional syntax.
+ */
+#define I2C_BOARD_INFO(dev_type, dev_addr) \
+	.type = dev_type, .addr = (dev_addr)
+
+extern int i2c_register_board_info(int busnum, struct i2c_board_info const *info, unsigned n);
+extern int i2c_add_numbered_adapter(struct i2c_adapter *adapter);
+
+extern int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
+extern int i2c_master_send(struct i2c_client *client, const char *buf, int count);
+extern int i2c_master_recv(struct i2c_client *client, char *buf, int count);
+
+
+#define I2C_ADDR_16_BIT	(1 << 31)
+
+extern int i2c_read_reg(struct i2c_client *client, u32 addr, u8 *buf, u16 count);
+extern int i2c_write_reg(struct i2c_client *client, u32 addr, const u8 *buf, u16 count);
+
+#endif /* I2C_I2C_H */
-- 
1.6.5.2





More information about the barebox mailing list