Загрузка данных
#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;
}