Загрузка данных


#include <linux/fpga/fpga-mgr.h>
#include "lattice-sysconfig.h"

static int sysconfig_i2c_cmd_transfer(struct sysconfig_priv *priv,
				      const void *tx_buf, size_t tx_len,
				      void *rx_buf, size_t rx_len)
{
	/* Получаем i2c_client через родительский dev, который мы сохраним в probe */
	struct i2c_client *client = to_i2c_client(priv->dev);
	struct i2c_msg msgs[2];
	int num_msgs = 0;
	int ret;

	/* 1. Write message (command and/or data payload) */
	if (tx_len > 0) {
		msgs[num_msgs].addr = client->addr;
		msgs[num_msgs].flags = client->flags & I2C_M_TEN;
		msgs[num_msgs].len = tx_len;
		msgs[num_msgs].buf = (u8 *)tx_buf;
		num_msgs++;
	}

	/* 2. Read message (if a response like device status is expected) */
	if (rx_len > 0) {
		msgs[num_msgs].addr = client->addr;
		/* I2C_M_RD flag switches the bus direction to read */
		msgs[num_msgs].flags = (client->flags & I2C_M_TEN) | I2C_M_RD;
		msgs[num_msgs].len = rx_len;
		msgs[num_msgs].buf = rx_buf;
		num_msgs++;
	}

	if (num_msgs == 0)
		return 0;

	/* Perform an atomic combined transaction */
	ret = i2c_transfer(client->adapter, msgs, num_msgs);
	if (ret < 0)
		return ret;

	return (ret == num_msgs) ? 0 : -EIO;
}

static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
	const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST;
	struct i2c_client *client = to_i2c_client(priv->dev);
	int ret;

	/* Send the initial burst write command to the FPGA */
	ret = i2c_master_send(client, lsc_bitstream_burst, sizeof(lsc_bitstream_burst));
	if (ret < 0)
		return ret;

	return (ret == sizeof(lsc_bitstream_burst)) ? 0 : -EIO;
}

static int sysconfig_i2c_bitstream_burst_write(struct sysconfig_priv *priv,
					       const char *buf, size_t len)
{
	struct i2c_client *client = to_i2c_client(priv->dev);
	struct i2c_msg msg;
	int ret;

	if (len == 0)
		return 0;

	/*
	 * IMPORTANT: Stream the remaining bitstream chunks.
	 * The I2C_M_NOSTART flag instructs the i.MX95 I2C controller NOT to 
	 * generate a repeated START condition or re-send the slave address.
	 */
	msg.addr = client->addr;
	msg.flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
	msg.len = len;
	msg.buf = (u8 *)buf;

	ret = i2c_transfer(client->adapter, &msg, 1);
	if (ret < 0)
		return ret;

	return (ret == 1) ? 0 : -EIO;
}

static int sysconfig_i2c_bitstream_burst_complete(struct sysconfig_priv *priv)
{
	/* In I2C, the stream sequence naturally completes when we stop transferring */
	return 0;
}

static int fpga_csi_bridge_probe(struct i2c_client *client)
{
	struct fpga_csi_bridge_priv *priv;
	struct device *dev = &client->dev;
	int ret;

	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
	if (!priv)
		return -ENOMEM;

	priv->client = client;

	mutex_init(&priv->lock);
	i2c_set_clientdata(client, priv);

	priv->reset_gpio = of_get_named_gpio(dev->of_node, "rst-gpios", 0);
	if (gpio_is_valid(priv->reset_gpio)) {
		ret = devm_gpio_request_one(dev, priv->reset_gpio, GPIOF_OUT_INIT_HIGH,
					    "fpga_csi_bridge_mipi_reset");
		if (ret < 0) {
			dev_err(dev, "Failed to set reset pin\n");
			return ret;
		}
	}

	/* power-up completes in approx 2ms, according to specifications */
	usleep_range(2000, 2500);

	/* ----------------------------------------------------------------- */
	/* Инициализация и регистрация подсистемы FPGA Manager                */
	/* ----------------------------------------------------------------- */
	priv->fpga_priv.dev = dev; /* Указываем на device нашего i2c_client */
	priv->fpga_priv.command_transfer = sysconfig_i2c_cmd_transfer;
	priv->fpga_priv.bitstream_burst_write_init = sysconfig_i2c_bitstream_burst_init;
	priv->fpga_priv.bitstream_burst_write = sysconfig_i2c_bitstream_burst_write;
	priv->fpga_priv.bitstream_burst_write_complete = sysconfig_i2c_bitstream_burst_complete;

	/* 
	 * Функция sysconfig_probe() из ядра автоматически поищет опциональные
	 * пины program-gpios, init-gpios, done-gpios в DTS-узле вашего csi-bridge.
	 * Если их там нет, она плавно переключится на чистый I2C-режим контроля.
	 */
	ret = sysconfig_probe(&priv->fpga_priv);
	if (ret) {
		dev_err(dev, "Failed to register integrated Lattice FPGA Manager\n");
		return ret;
	}
	/* ----------------------------------------------------------------- */

	ret = fpga_csi_bridge_parse_dt(priv);
	if (ret)
		return ret;

	ret = fpga_csi_bridge_v4l2_init(priv);
	if (ret)
		return ret;

	return 0;
}