#include <linux/vmalloc.h>
#include <linux/string.h>
/*
* Старую функцию burst_init делаем пустой заглушкой,
* так как команда 0x7A теперь вшита в начало единого монолитного буфера.
*/
static int sysconfig_i2c_bitstream_burst_init(struct sysconfig_priv *priv)
{
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;
const u8 lsc_cmd[] = SYSCONFIG_LSC_BITSTREAM_BURST; // {0x7a, 0x00, 0x00, 0x00}
size_t cmd_len = sizeof(lsc_cmd);
size_t aligned_payload_len;
size_t padding_needed;
size_t total_buffer_size;
u8 *tx_buffer;
int ret;
if (len == 0)
return 0;
/* 1. Считаем выравнивание (Padding) тела прошивки до кратности 4 байтам */
aligned_payload_len = (len + 3) & ~3;
padding_needed = aligned_payload_len - len;
/* Полный размер буфера: 4 байта команды 0x7A + выровненная прошивка */
total_buffer_size = cmd_len + aligned_payload_len;
printk("%s(%d) [400kHz] Total payload: Raw len = %zu, Aligned len = %zu (Padding: %zu bytes)\n",
__FUNCTION__, __LINE__, len, aligned_payload_len, padding_needed);
printk("%s(%d) Allocating single monolithic vmalloc buffer: %zu bytes\n",
__FUNCTION__, __LINE__, total_buffer_size);
/* 2. Выделяем виртуально непрерывный буфер большой емкости */
tx_buffer = vmalloc(total_buffer_size);
if (!tx_buffer) {
dev_err(priv->dev, "Failed to allocate vmalloc buffer for monolithic transfer\n");
return -ENOMEM;
}
/* 3. Собираем монолитный пакет в памяти */
/* Копируем команду начала Burst (0x7A, 0x00, 0x00, 0x00) */
memcpy(tx_buffer, lsc_cmd, cmd_len);
/* Копируем бинарный поток прошивки (LED_impl_1_clean_reverse.bin) */
memcpy(tx_buffer + cmd_len, buf, len);
/* Если нужно выравнивание, заполняем оставшийся хвостик байтами NOP (0xFF) */
if (padding_needed > 0) {
memset(tx_buffer + cmd_len + len, 0xFF, padding_needed);
}
/* 4. Конфигурируем ОДНО единственное I2C сообщение без флага NOSTART */
msg.addr = client->addr;
msg.flags = client->flags & I2C_M_TEN; // Обычная запись: выдаст START, адрес и погонит массив
msg.len = total_buffer_size;
msg.buf = tx_buffer;
printk("%s(%d) Launching atomic monolithic i2c_transfer via DMA...\n", __FUNCTION__, __LINE__);
/* 5. Отправляем всё за ОДИН аппаратный вызов */
ret = i2c_transfer(client->adapter, &msg, 1);
/* 6. Освобождаем память */
vfree(tx_buffer);
if (ret < 0) {
dev_err(priv->dev, "Monolithic I2C burst write failed: %d\n", ret);
return ret;
}
if (ret != 1) {
dev_err(priv->dev, "Monolithic I2C transfer incomplete\n");
return -EIO;
}
printk("%s(%d) Monolithic burst successfully finished without gaps!\n", __FUNCTION__, __LINE__);
return 0;
}