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


#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;
}