Загрузка данных
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/slab.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)
{
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.
* Unlike SPI, explicit bus locking for the entire duration is
* handled sequentially via standard I2C multi-message handling.
*/
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.
* The data flows continuously as an ongoing payload sequence.
*/
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 blocks with the I2C_M_NOSTART flag. The final
* transaction automatically releases the bus with a STOP condition.
*/
return 0;
}
static int sysconfig_i2c_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct sysconfig_priv *priv;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->dev = dev;
priv->command_transfer = sysconfig_i2c_cmd_transfer;
priv->bitstream_burst_write_init = sysconfig_i2c_bitstream_burst_init;
priv->bitstream_burst_write = sysconfig_i2c_bitstream_burst_write;
priv->bitstream_burst_write_complete = sysconfig_i2c_bitstream_burst_complete;
/* Call the generic initialization sequence from lattice-sysconfig.c */
return sysconfig_probe(priv);
}
static const struct i2c_device_id sysconfig_i2c_ids[] = {
{ "sysconfig-crosslinknx", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, sysconfig_i2c_ids);
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id sysconfig_of_ids[] = {
{ .compatible = "lattice,sysconfig-crosslinknx" },
{ }
};
MODULE_DEVICE_TABLE(of, sysconfig_of_ids);
#endif
static struct i2c_driver lattice_sysconfig_driver = {
.probe = sysconfig_i2c_probe,
.id_table = sysconfig_i2c_ids,
.driver = {
.name = "lattice_sysconfig_i2c_fpga_mgr",
.of_match_table = of_match_ptr(sysconfig_of_ids),
},
};
module_i2c_driver(lattice_sysconfig_driver);
MODULE_DESCRIPTION("Lattice sysCONFIG Slave I2C FPGA Manager");
MODULE_LICENSE("GPL");