#include <linux/slab.h>
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 *msgs;
const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7A, 0x00, 0x00, 0x00}
size_t offset = 0;
int chunk_count = 0;
int total_msgs;
int i, ret;
if (len == 0)
return 0;
/* Вычисляем выравнивание */
size_t aligned_len = (len + 3) & ~3;
size_t total_padding = aligned_len - len;
/* Считаем точное количество сообщений. Каждый чанк строго по 4096 байт! */
/* Плюс 1 сообщение под стартовую команду 0x7A */
total_msgs = 1 + (aligned_len + 4095) / 4096;
msgs = kmalloc_array(total_msgs, sizeof(struct i2c_msg), GFP_KERNEL);
if (!msgs)
return -ENOMEM;
printk("%s(%d) Optimized 4КB Burst: Total msgs = %d, Padding = %zu\n",
__FUNCTION__, __LINE__, total_msgs, total_padding);
/* 1. Первое сообщение: строго 4 байта команды 0x7A (генерирует START) */
msgs[chunk_count].addr = client->addr;
msgs[chunk_count].flags = client->flags & I2C_M_TEN;
msgs[chunk_count].len = sizeof(lsc_bitstream_burst);
msgs[chunk_count].buf = (u8 *)lsc_bitstream_burst;
chunk_count++;
/* 2. Заполняем массив сообщений строго по 4096 байт с флагом NOSTART */
while (offset < len) {
size_t chunk_size = min((size_t)4096, len - offset);
msgs[chunk_count].addr = client->addr;
/* I2C_M_NOSTART заставляет контроллер i.MX95 удерживать шину непрерывно */
msgs[chunk_count].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
/* Если это самый последний чанк и нужен Padding */
if (offset + chunk_size == len && total_padding > 0) {
size_t padded_size = chunk_size + total_padding;
u8 *padded_buf = kmalloc(padded_size, GFP_KERNEL);
if (!padded_buf) {
/* Чистим за собой выделенную ранее память при ошибке */
for (i = 1; i < chunk_count; i++) {
if (msgs[i].len > 4096) kfree(msgs[i].buf);
}
kfree(msgs);
return -ENOMEM;
}
memcpy(padded_buf, buf + offset, chunk_size);
memset(padded_buf + chunk_size, 0xFF, total_padding);
msgs[chunk_count].len = padded_size;
msgs[chunk_count].buf = padded_buf;
} else {
/* Стандартный идеальный чанк ПЕЙЛОАДА (не более 4096 байт) */
msgs[chunk_count].len = chunk_size;
msgs[chunk_count].buf = (u8 *)(buf + offset);
}
offset += chunk_size;
chunk_count++;
}
printk("%s(%d) Submitting %d packets of 4KB to LPI2C engine atomically...\n",
__FUNCTION__, __LINE__, chunk_count);
/* 3. Отправляем ВСЮ пачку 4КБ дескрипторов за ОДИН атомарный вызов ядра */
ret = i2c_transfer(client->adapter, msgs, chunk_count);
/* 4. Освобождаем выделенную память */
if (total_padding > 0 && chunk_count > 1) {
kfree(msgs[chunk_count - 1].buf); // Удаляем временный padded_buf последнего чанка
}
kfree(msgs);
if (ret != chunk_count) {
dev_err(priv->dev, "Atomic 4KB transfer failed: %d\n", ret);
return (ret < 0) ? ret : -EIO;
}
printk("%s(%d) 4KB-aligned stream successfully flashed!\n", __FUNCTION__, __LINE__);
return 0;
}