/*
 * Copyright (c) 2017 BayLibre, SAS
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <clock_control/stm32_clock_control.h>
#include <drivers/clock_control.h>
#include <sys/util.h>
#include <kernel.h>
#include <errno.h>
#include <drivers/i2c.h>

#define LOG_LEVEL CONFIG_I2C_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_DECLARE(main);

#define DEV_DATA(dev) ((struct i2c_virtual_data * const)(dev)->driver_data)

struct i2c_virtual_data {
	sys_slist_t slaves;
};

int i2c_virtual_runtime_configure(struct device *dev, u32_t config)
{
	return 0;
}

static struct i2c_slave_config *find_address(struct i2c_virtual_data *data,
					     u16_t address, bool is_10bit)
{
	struct i2c_slave_config *cfg = NULL;
	sys_snode_t *node;
	bool search_10bit;

	SYS_SLIST_FOR_EACH_NODE(&data->slaves, node) {
		cfg = CONTAINER_OF(node, struct i2c_slave_config, node);

		search_10bit = (cfg->flags & I2C_ADDR_10_BITS);

		if (cfg->address == address && search_10bit == is_10bit) {
			return cfg;
		}
	}

	return NULL;
}

/* Attach I2C slaves */
int i2c_virtual_slave_register(struct device *dev,
			       struct i2c_slave_config *config)
{
	struct i2c_virtual_data *data = DEV_DATA(dev);

	if (!config) {
		return -EINVAL;
	}

	/* Check the address is unique */
	if (find_address(data, config->address,
			 (config->flags & I2C_ADDR_10_BITS))) {
		return -EINVAL;
	}

	sys_slist_append(&data->slaves, &config->node);

	return 0;
}


int i2c_virtual_slave_unregister(struct device *dev,
				 struct i2c_slave_config *config)
{
	struct i2c_virtual_data *data = DEV_DATA(dev);

	if (!config) {
		return -EINVAL;
	}

	if (!sys_slist_find_and_remove(&data->slaves, &config->node)) {
		return -EINVAL;
	}

	return 0;
}

static int i2c_virtual_msg_write(struct device *dev, struct i2c_msg *msg,
				 struct i2c_slave_config *config,
				 bool prev_write)
{
	unsigned int len = 0U;
	u8_t *buf = msg->buf;
	int ret;

	if (!prev_write) {
		config->callbacks->write_requested(config);
	}

	len = msg->len;
	while (len) {

		ret = config->callbacks->write_received(config, *buf);
		if (ret) {
			goto error;
		}
		buf++;
		len--;
	}

	if (!(msg->flags & I2C_MSG_RESTART) && msg->flags & I2C_MSG_STOP) {
		config->callbacks->stop(config);
	}

	return 0;
error:
	LOG_DBG("%s: NACK", __func__);

	return -EIO;
}

static int i2c_virtual_msg_read(struct device *dev, struct i2c_msg *msg,
				struct i2c_slave_config *config)
{
	unsigned int len = msg->len;
	u8_t *buf = msg->buf;

	if (!msg->len) {
		return 0;
	}

	config->callbacks->read_requested(config, buf);
	buf++;
	len--;

	while (len) {
		config->callbacks->read_processed(config, buf);
		buf++;
		len--;
	}

	if (!(msg->flags & I2C_MSG_RESTART) && msg->flags & I2C_MSG_STOP) {
		config->callbacks->stop(config);
	}

	return 0;
}

#define OPERATION(msg) (((struct i2c_msg *) msg)->flags & I2C_MSG_RW_MASK)

static int i2c_virtual_transfer(struct device *dev, struct i2c_msg *msg,
			      u8_t num_msgs, u16_t slave)
{
	struct i2c_virtual_data *data = DEV_DATA(dev);
	struct i2c_msg *current, *next;
	struct i2c_slave_config *cfg;
	bool is_write = false;
	int ret = 0;

	cfg = find_address(data, slave, (msg->flags & I2C_ADDR_10_BITS));
	if (!cfg) {
		return -EIO;
	}

	current = msg;
	current->flags |= I2C_MSG_RESTART;
	while (num_msgs > 0) {
		if (num_msgs > 1) {
			next = current + 1;

			/*
			 * Stop or restart condition between messages
			 * of different directions is required
			 */
			if (OPERATION(current) != OPERATION(next)) {
				if (!(next->flags & I2C_MSG_RESTART)) {
					ret = -EINVAL;
					break;
				}
			}
		}

		/* Stop condition is required for the last message */
		if ((num_msgs == 1U) && !(current->flags & I2C_MSG_STOP)) {
			ret = -EINVAL;
			break;
		}

		if ((current->flags & I2C_MSG_RW_MASK) == I2C_MSG_WRITE) {
			ret = i2c_virtual_msg_write(dev, current,
						    cfg, is_write);
			is_write = true;
		} else {
			ret = i2c_virtual_msg_read(dev, current, cfg);
			is_write = false;
		}

		if (ret < 0) {
			break;
		}

		current++;
		num_msgs--;
	};

	return ret;
}

static const struct i2c_driver_api api_funcs = {
	.configure = i2c_virtual_runtime_configure,
	.transfer = i2c_virtual_transfer,
	.slave_register = i2c_virtual_slave_register,
	.slave_unregister = i2c_virtual_slave_unregister,
};

static int i2c_virtual_init(struct device *dev)
{
	struct i2c_virtual_data *data = DEV_DATA(dev);

	sys_slist_init(&data->slaves);

	return 0;
}

static struct i2c_virtual_data i2c_virtual_dev_data_0;

DEVICE_AND_API_INIT(i2c_virtual_0, CONFIG_I2C_VIRTUAL_NAME, &i2c_virtual_init,
		    &i2c_virtual_dev_data_0, NULL,
		    POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
		    &api_funcs);
