/*
 * Copyright (c) 2024 Advanced Micro Devices, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include <zephyr/drivers/i2c.h>
#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(main, LOG_LEVEL_INF);

#define PSI2C_I2C_MUX_ADDR     0x74
#define PSI2C_I2C_MUX_CHANNEL  0x01U

static const struct device *const ps_i2c_dev = DEVICE_DT_GET(DT_NODELABEL(ps_i2c1));

static int32_t iicps_master_configure_test(void)
{
	int32_t ret;
	uint32_t i2c_cfg, i2c_rd_cfg;

	LOG_INF("IIC-PS: master: configure-test: Start");

	/* check if driver is properly initialized */
	if (device_is_ready(ps_i2c_dev) == false) {
		LOG_INF("PS-I2C: device is NOT_READY");
		ret = -ENODEV;
		goto out;
	}
	LOG_INF("PS-I2C: device READY");

	/* configure iic speed */
	LOG_INF("PS-I2C: master: i2c_configure: Progress");
	i2c_cfg = I2C_SPEED_SET(I2C_SPEED_STANDARD) | I2C_MODE_CONTROLLER;
	ret = i2c_configure(ps_i2c_dev, i2c_cfg);
	if (ret != 0) {
		LOG_INF("PS-I2C: master: i2c_configure: failed: %d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: master: i2c_configure: Success");

	/* read i2c configuration */
	LOG_INF("PS-I2C: master: i2c_get_config: Progress");
	i2c_rd_cfg = 0;
	ret = i2c_get_config(ps_i2c_dev, &i2c_rd_cfg);
	if (ret != 0) {
		LOG_INF("PS-I2C: master: i2c_get_config: failed: %d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: master: i2c_get_config: Success");

	/* verify if same */
	if (i2c_cfg != i2c_rd_cfg) {
		LOG_INF("PS-I2C: master: invalid get_config, rd_cfg: %08Xh, exp_cfg: %08Xh",
			i2c_rd_cfg, i2c_cfg);
		goto out;
	}

out:
	if (ret != 0) {
		LOG_INF("IIC-PS: master: configure-test: FAILED");
	} else {
		LOG_INF("IIC-PS: master: configure-test: PASSED");
	}

	return ret;
}

static int32_t iicps_master_transfer_test(void)
{
	int32_t ret;
	struct i2c_msg msg[2];
	uint8_t WriteBuffer = 1U;
	uint8_t ReadBuffer;

	LOG_INF("IIC-PS: master: transfer-test: Start");

	/* perform a 1 byte of i2c write and then i2c read */
	LOG_INF("PS-I2C: i2c_transfer: write: Progress");
	msg[0].buf = &WriteBuffer;
	msg[0].len = 1;
	msg[0].flags = (uint8_t)I2C_MSG_WRITE;
	ret = i2c_transfer(ps_i2c_dev, &msg[0], 1, PSI2C_I2C_MUX_ADDR);
	if (ret != 0) {
		LOG_INF("PS-I2C: i2c_transfer: write: failed: %d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: i2c_transfer: write: PASSED");

	msg[1].buf = &ReadBuffer;
	msg[1].len = 1;
	msg[1].flags = (uint8_t)(I2C_MSG_READ);
	ret = i2c_transfer(ps_i2c_dev, &msg[1], 1, PSI2C_I2C_MUX_ADDR);
	if (ret != 0) {
		LOG_INF("PS-I2C: i2c_transfer: read: failed: %d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: i2c_transfer: read: PASSED");

	LOG_INF("PS-I2C: i2c_transfer: multi-msg: Progress");
	ret = i2c_transfer(ps_i2c_dev, &msg[0], 2, PSI2C_I2C_MUX_ADDR);
	if (ret != 0) {
		LOG_INF("PS-I2C: i2c_transfer: multi-msg: failed: %d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: i2c_transfer: multi-msg: PASSED");

out:
	if (ret != 0) {
		LOG_INF("IIC-PS: master: transfer-test: FAILED");
	} else {
		LOG_INF("IIC-PS: master: transfer-test: PASSED");
	}

	return ret;
}

static int32_t iicps_master_repstart_test(void)
{
	int32_t ret;
	uint8_t wr_datas[6];
	uint8_t rd_datas[6];

	LOG_INF("IIC-PS: master: rep-start-test: Start");

	LOG_INF("PS-I2C: master: write-read-rep-start: SLAVE:IIC-MUX Progress");
	wr_datas[0] = PSI2C_I2C_MUX_CHANNEL;
	LOG_INF("PS-I2C: master: write-read-rep-start: write data: %02Xh ", wr_datas[0]);
	(void)memset(rd_datas, 0, sizeof(rd_datas));
	ret = i2c_write_read(ps_i2c_dev, PSI2C_I2C_MUX_ADDR, wr_datas, 1, rd_datas, 1);
	if (ret != 0) {
		LOG_INF("PS-I2C: master: write-read-rep-start: SLAVE:IIC-MUX FAILED, ret:%d", ret);
		goto out;
	}
	LOG_INF("PS-I2C: master: write-read-rep-start: SLAVE:IIC-MUX success");
	LOG_INF("PS-I2C: master: write-read-rep-start: read data: %02Xh", rd_datas[0]);

out:
	if (ret == 0) {
		LOG_INF("IIC-PS: master: rep-start-test: PASSED");
	} else {
		LOG_INF("IIC-PS: master: rep-start-test: FAILED");
	}

	return ret;
}

static void iicps_master_mode_test(void)
{
	int32_t ret;

	LOG_INF("IIC-PS: master mode test: Start");

	ret = iicps_master_configure_test();
	if (ret != 0) {
		goto out;
	}

	ret = iicps_master_transfer_test();
	if (ret != 0) {
		goto out;
	}

	ret = iicps_master_repstart_test();
	if (ret != 0) {
		goto out;
	}

out:
	if (ret != 0) {
		LOG_INF("IIC-PS: master mode test: FAILED");
	} else {
		LOG_INF("IIC-PS: master mode test: PASSED");
	}
}

int main(void)
{
	/* master usecase */
	iicps_master_mode_test();

	return 0;
}
