/*
 * Copyright (C) 2009 Marc Kleine-Budde <mkl@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 - barebox 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);
static LIST_HEAD(adapter_list);

/**
 * i2c_transfer - execute a single or combined I2C message
 * @param	adap	Handle to I2C bus
 * @param	msgs	One or more messages to execute before STOP is
 *			issued to terminate the operation; each
 *			message begins with a START.
 *
 * @param	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).
	 */

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

	/* 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, SECOND >> 1))
			break;
	}

	return ret;
}
EXPORT_SYMBOL(i2c_transfer);

/**
 * i2c_master_send - issue a single I2C message in master transmit mode
 *
 * @param	client	Handle to slave device
 * @param	buf	Data that will be written to the slave
 * @param	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)
{
	struct i2c_adapter *adap = client->adapter;
	struct i2c_msg msg;
	int ret;

	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
 *
 * @param	client	Handle to slave device
 * @param	buf	Where to store data read from slave
 * @param	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;
}
EXPORT_SYMBOL(i2c_read_reg);

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;
}
EXPORT_SYMBOL(i2c_write_reg);

/**
 * i2c_new_device - instantiate one new I2C device
 *
 * @param	adapter	Controller to which device is connected
 * @param	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
 *
 * @param	info	array of chip descriptors
 * @param	n	how many descriptors are provided
 *
 * Board-specific early init code calls this (probably during
 * arch_initcall) with segments of the I2C device table.
 *
 * 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.
 *
 */
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_get_adapter - get an i2c adapter from its busnum
 *
 * @param	busnum	the desired bus number
 *
 */
struct i2c_adapter *i2c_get_adapter(int busnum)
{
	struct i2c_adapter *adap;

	list_for_each_entry(adap, &adapter_list, list)
		if (adap->nr == busnum)
			return adap;
	return NULL;
}

/**
 * i2c_add_numbered_adapter - declare i2c adapter, use static bus number
 * @adapter: the adapter to register (with adap->nr initialized)
 *
 * This routine is used to declare an I2C adapter when its bus number
 * matters.  For example, use it for I2C adapters from system-on-chip CPUs,
 * or otherwise built in to the system's mainboard, and where i2c_board_info
 * is used to properly configure I2C devices.
 *
 * When this returns zero, the specified adapter became available for
 * clients using the bus number provided in adap->nr.  Also, the table
 * of I2C devices pre-declared using i2c_register_board_info() is scanned,
 * and the appropriate driver model device nodes are created.  Otherwise, a
 * negative errno value is returned.
 */
int i2c_add_numbered_adapter(struct i2c_adapter *adapter)
{
	if (i2c_get_adapter(adapter->nr))
		return -EBUSY;

	list_add_tail(&adapter->list, &adapter_list);

	/* populate children from any i2c device tables */
	scan_boardinfo(adapter);

	return 0;
}
EXPORT_SYMBOL(i2c_add_numbered_adapter);
