Загрузка данных


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-х сообщений: 1-е с командой (со START), 2-е с флагом NOSTART */
    struct i2c_msg msgs[2];
    const u8 lsc_bitstream_burst[] = SYSCONFIG_LSC_BITSTREAM_BURST; // 0x7A, 0x00, 0x00, 0x00
    size_t offset = 0;
    int ret;

    if (len == 0)
        return 0;

    printk("%s(%d) Total length to send via continuous I2C = %ld\n", __FUNCTION__, __LINE__, len);

    /* 
     * ШАГ 1: Отправляем команду начала BURST и ПЕРВЫЙ кусок данных в одной сессии i2c_transfer.
     * Это гарантирует, что между командой 0x7A и данными не будет STOP-условия.
     */
    size_t first_chunk = min((size_t)4096, len);

    // Сообщение 0: Команда инициализации BURST (со START)
    msgs[0].addr = client->addr;
    msgs[0].flags = client->flags & I2C_M_TEN;
    msgs[0].len = sizeof(lsc_bitstream_burst);
    msgs[0].buf = (u8 *)lsc_bitstream_burst;

    // Сообщение 1: Первый кусок прошивки (удерживаем шину через NOSTART)
    msgs[1].addr = client->addr;
    msgs[1].flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
    msgs[1].len = first_chunk;
    msgs[1].buf = (u8 *)buf;

    // Передаем оба сообщения за один проход ядра. Контроллер i.MX95 выдаст START, 
    // передаст команду, НЕ выдавая STOP передаст первый блок данных, и только потом отпустит шину (или продолжит).
    ret = i2c_transfer(client->adapter, msgs, 2);
    if (ret != 2) {
        dev_err(priv->dev, "I2C initial burst command + data failed: %d\n", ret);
        return (ret < 0) ? ret : -EIO;
    }

    offset += first_chunk;

    /* 
     * ШАГ 2: Досылаем оставшуюся часть прошивки блоками по 4КБ.
     * Поведение I2C_M_NOSTART между разными вызовами i2c_transfer зависит от архитектуры LPI2C.
     * Чтобы перестраховаться от генерации STOP контроллером LPI2C, 
     * лучше всего передавать данные максимально большими пачками, если это позволяет DMA ядра.
     */
    while (offset < len) {
        size_t chunk_size = min((size_t)4096, len - offset);
        struct i2c_msg msg;

        msg.addr = client->addr;
        msg.flags = (client->flags & I2C_M_TEN) | I2C_M_NOSTART;
        msg.len = chunk_size;
        msg.buf = (u8 *)(buf + offset);

        ret = i2c_transfer(client->adapter, &msg, 1);
        if (ret != 1) {
            dev_err(priv->dev, "I2C continuous burst write failed at offset %zu: %d\n", offset, ret);
            return (ret < 0) ? ret : -EIO;
        }

        offset += chunk_size;
    }

    printk("%s(%d) Burst stream successfully transmitted\n", __FUNCTION__, __LINE__);
    return 0;
}