#include <linux/vmalloc.h>
#include <linux/string.h>
static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
/* Делаем заглушкой, так как отправка команды перенесена в burst_write */
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);
/* Массив из 2-х сообщений для ОДНОГО вызова i2c_transfer */
struct i2c_msg msgs[2];
const u8 lsc_cmd[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7a, 0x00, 0x00, 0x00}
size_t aligned_payload_len;
size_t padding_needed;
u8 *payload_buffer;
int ret;
if (len == 0)
return 0;
/* 1. Рассчитываем выравнивание (Padding) только для тела прошивки */
aligned_payload_len = (len + 3) & ~3; // Округляем вверх до кратности 4 байтам
padding_needed = aligned_payload_len - len;
printk("%s(%d) [400kHz Two-Stage Monolithic] Raw len = %zu, Aligned len = %zu (Padding: %zu bytes)\n",
__FUNCTION__, __LINE__, len, aligned_payload_len, padding_needed);
/* 2. Выделяем виртуально непрерывный буфер ТОЛЬКО под стрим + padding */
payload_buffer = vmalloc(aligned_payload_len);
if (!payload_buffer) {
dev_err(priv->dev, "Failed to allocate vmalloc buffer for bitstream payload\n");
return -ENOMEM;
}
/* 3. Копируем тело прошивки и забиваем хвост байтами NOP (0xFF) */
memcpy(payload_buffer, buf, len);
if (padding_needed > 0) {
memset(payload_buffer + len, 0xFF, padding_needed);
}
/* 4. Настраиваем ПЕРВОЕ сообщение: строго 4 байта команды (генерирует START) */
msgs[0].addr = client->addr;
msgs[0].flags = client->flags & I2C_M_TEN; // Обычная запись
msgs[0].len = sizeof(lsc_cmd);
msgs[0].buf = (u8 *)lsc_cmd;
/* 5. Настраиваем ВТОРОЕ сообщение: монолитный стрим + padding (удерживает шину) */
msgs[1].addr = client->addr;
/* Флаг I2C_M_NOSTART запрещает i.MX95 выдавать STOP/RESTART между msgs[0] и msgs[1] */
msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
msgs[1].len = aligned_payload_len;
msgs[1].buf = payload_buffer;
printk("%s(%d) Launching atomic two-stage i2c_transfer (Cmd + Monolithic Stream)...\n", __FUNCTION__, __LINE__);
/* 6. Отправляем оба сообщения за ОДИН атомарный проход ядра */
ret = i2c_transfer(client->adapter, msgs, 2);
/* 7. Освобождаем выделенную память */
vfree(payload_buffer);
if (ret < 0) {
dev_err(priv->dev, "Two-stage I2C burst write failed: %d\n", ret);
return ret;
}
if (ret != 2) {
dev_err(priv->dev, "Two-stage I2C transfer incomplete (sent %d msgs instead of 2)\n", ret);
return -EIO;
}
printk("%s(%d) Two-stage burst successfully completed!\n", __FUNCTION__, __LINE__);
return 0;
}