/* Флаг для отслеживания первой транзакции */
static bool is_first_burst_chunk = true;
static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
/*
* ВАЖНО: Больше не шлем команду отдельно, чтобы не генерировать STOP на шине.
* Просто взводим флаг готовности к первой передаче.
*/
is_first_burst_chunk = true;
return 0;
}
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;
if (is_first_burst_chunk) {
/*
* Для самой первой пачки данных мы обязаны склеить
* команду BURST_WRITE (4 байта) и начало файла прошивки.
*/
u8 burst_cmd[] = SYSCONFIG_LSC_BITSTREAM_BURST;
size_t tx_len = sizeof(burst_cmd) + len;
u8 *tx_buf;
tx_buf = kmalloc(tx_len, GFP_KERNEL);
if (!tx_buf)
return -ENOMEM;
/* Копируем команду 0x7A, 0x00, 0x00, 0x00 */
memcpy(tx_buf, burst_cmd, sizeof(burst_cmd));
/* Следом копируем первый кусок прошивки */
memcpy(tx_buf + sizeof(burst_cmd), buf, len);
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN; /* СТАНДАРТНЫЙ СТАРТ (открываем шину) */
msg.len = tx_len;
msg.buf = tx_buf;
dev_info(priv->dev, "Sending burst command merged with first chunk (%zu bytes)...\n", tx_len);
ret = i2c_transfer(client->adapter, &msg, 1);
kfree(tx_buf);
if (ret < 0)
return ret;
if (ret != 1)
return -EIO;
is_first_burst_chunk = false;
} else {
/*
* Все последующие куски файла шлем стандартно через NOSTART.
* Теперь это безопасно, так как шина уже была открыта первой транзакцией!
*/
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;
if (ret != 1)
return -EIO;
}
/* Небольшая пауза для стабильности автомата ПЛИС */
usleep_range(100, 200);
return 0;
}