Анализ подсистемы SPI драйвера Linux
Анализ подсистемы SPI драйвера Linux

Основные понятия об оборудовании SPI

Шина SPI состоит из четырех линий связи.,полный дуплекс、Последовательная синхронная связь «главный-подчиненный»,Передавать 8 бит за раз,Сначала высокая позиция,Низко сзади.

  • MOSI (Master Out Slave In): выход ведущего устройства, вход ведомого устройства.
  • MISO (Master In Slave out): вход ведомого устройства, выход ведущего устройства.
  • SCLK: линия синхронизации для сигнала синхронизации.
  • CS: Строка выбора чипа: выберите, с каким ведомым устройством обмениваться данными, с помощью выбора чипа. Примечание: По сравнению с I2C, поскольку SPI использует две однонаправленные линии данных вместо двунаправленных линий данных, используемых I2C, SPI является полным. дуплексная связь, тогда как I2C является полудуплексной. ​ Подчиненное устройство, подключенное к шине выбора I2C, отличается своим подчиненным адресом, тогда как SPI использует линию выбора чипа CS.

Структура подсистемы SPI

  • Базовый уровень SPI: drivers/spi/spi.c
  • Уровень драйвера шины SPI (уровень драйвера хост-контроллера): driver/spi/spi_s3c24xx. c
  • Уровень драйвера устройства SPI:drivers/spi/spidev.c (Универсальный драйвер устройства SPI, предоставляемый ядром)

Подсистема шины режима «главный-подчиненный» в Linux использует ту же идею разделения.,Конкретные стратегии разделения аналогичны.,Также разделен науровень драйвера устройстваосновной слойуровень водителя автобуса。Подробный анализ конкретных стратегий разделения см.Анализ подсистемы I2C драйвера LinuxПромежуточная проверкаI2CОбъяснение структуры подсистемы。Автор здесь иI2Cаналогия с подсистемой,Перечислите имена структур данных.

I2C

SPI

Хост-адаптер (контроллер)

struct i2c_adapter

struct spi_master

Как управлять контроллером машины

struct i2c_algorithm

struct spi_bitbang

Ведомое устройство

struct i2c_client

struct spi_device

Ведомое устройство Информация о плате

struct i2c_board_info

struct spi_board_info

Ведомое устройствоводить машину

struct i2c_driver

struct spi_driver

Полный пакет

struct i2c_msg

struct spi_transfer

Инкапсуляция нескольких полных пакетов данных

никто

struct spi_message

Анализ исходного кода

Поскольку архитектура подсистемы аналогична шинам типа I2C,Поэтому он не будет расширяться на некоторые повторяющиеся части.,Подробный анализ см.Анализ подсистемы I2C драйвера LinuxАналитические методы в。

Базовый уровень SPI

Базовый уровень SPIКод находится по адресуdrivers/spi/spi.c середина, Начните анализ с функции init

Язык кода:javascript
копировать
static int __init spi_init(void)
{
    int status;

    buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
    if (!buf) {
        status = -ENOMEM;
        goto err0;
    }

    status = bus_register(&spi_bus_type);     /* Регистрация шины SPI */
    if (status < 0)
        goto err1;

    status = class_register(&spi_master_class);     /* Зарегистрировать класс SPI */
    if (status < 0)
        goto err2;
    return 0;

err2:
    bus_unregister(&spi_bus_type);
err1:
    kfree(buf);
    buf = NULL;
err0:
    return status;
}

spi_initФункция похожа наI2Cосновной Функция init в слое делает те же две вещи,Регистрация шины SPI и создание классов SPI,Это основная процедура модели драйвера ядра.,Я не скажу больше этого. Далее давайте посмотрим на функцию сопоставления

Язык кода:javascript
копировать
static const struct spi_device_id *spi_match_id(const struct spi_device_id *id,
                        const struct spi_device *sdev)
{
    while (id->name[0]) {
        if (!strcmp(sdev->modalias, id->name))
            return id;
        id++;
    }
    return NULL;
}

/* Метод сопоставления шины SPI */
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
    const struct spi_device *spi = to_spi_device(dev);
    const struct spi_driver *sdrv = to_spi_driver(drv);

    if (sdrv->id_table)
        return !!spi_match_id(sdrv->id_table, spi);

    return strcmp(spi->modalias, drv->name) == 0;
}

Видно, что сопоставление устройства SPI и драйвера заключается в том, чтобы сначала сопоставить имя в таблице id_table и модали устройства, а затем сопоставить имя драйвера и модали устройства.

Уровень драйвера шины SPI

Драйвер контроллера SPI, а именно уровень водителя автобусародыdrivers/spi/spi_s3c24xx. cсередина,Начните анализ с функции init。

Язык кода:javascript
копировать
static int __init s3c24xx_spi_init(void)
{   
    return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
}

найдетSPIконтроллерводить машину Он не используетсяplatform_driver_registerИнтерфейс для регистрации,Вместо этого используется другой интерфейсplatform_driver_probe, По сути, это выделенная платформенная шина, предоставляемая ядром и не поддерживающая горячую замену.водить машинуинтерфейс регистрации,Этот интерфейс принимает два параметра,Первый хорошо известенstruct platform_driver,Вторая функция — зонд.,когдаводить машину Сопоставьте устройствоначальство Это будет вызвано позжеprobeфункция。войти в s3c24xx_spi_probeфункцияпровести анализ,Функция зонда имеет много кода,Анализируйте по разделам.

Язык кода:javascript
копировать
struct s3c2410_spi_info *pdata;
struct s3c24xx_spi *hw;
struct spi_master *master;
struct resource *res;
int err = 0;

/* Создать экземпляр spi-контроллера */
master = spi_alloc_master(&pdev->dev, squdongqudongizeof(struct s3c24xx_spi));
if (master == NULL) {
    dev_err(&pdev->dev, "No memory for spi_master\n");
    err = -ENOMEM;
    goto err_nomem;
}

/* Получите частную структуру данных spi и инициализируйте ее как пустую. */
hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));

/* Установить личные данные spi*/
hw->master = spi_master_get(master);
hw->pdata = pdata = pdev->dev.platform_data;
hw->dev = &pdev->dev;

if (pdata == NULL) {
    dev_err(&pdev->dev, "No platform data supplied\n");
    err = -ENOENT;
    goto err_no_pdata;
}

platform_set_drvdata(pdev, hw);
init_completion(&hw->done);     /* завершение инициализации,  Используется для синхронизации ввода-вывода*/

После создания экземпляра контроллера SPI установите частные данные SPI, а затем инициализируйте завершение.

Язык кода:javascript
копировать
/* initialise fiq handler */

s3c24xx_spi_initfiq(hw);       /* Инициализируйте обработчик в структуре s3c24xx_spi и привяжите к нему функцию обработки прерываний. */

/* setup the master state. */

/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;

master->num_chipselect = hw->pdata->num_cs;
master->bus_num = pdata->bus_num;

Этот раздел инициализируетs3c24xx_spiСтруктуравhandler,Привяжите к нему функцию обработчика прерываний,Затем установите режим SPI, поддерживаемый хост-контроллером.,Установите номер линии выбора чипа ведущего устройства и номер шины.

Язык кода:javascript
копировать
hw->bitbang.master         = hw->master;
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
hw->bitbang.chipselect     = s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs      = s3c24xx_spi_txrx;

hw->master->setup  = s3c24xx_spi_setup;
hw->master->cleanup = s3c24xx_spi_cleanup;

bitbang представляет метод работы SPI. Ключом к этому разделу является заполнение параметра setup_transfer, который является методом передачи.

Язык кода:javascript
копировать
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
    dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
    err = -ENOENT;
    goto err_no_iores;
}

hw->ioarea = request_mem_region(res->start, resource_size(res),
                pdev->name);

if (hw->ioarea == NULL) {
    dev_err(&pdev->dev, "Cannot reserve region\n");
    err = -ENXIO;
    goto err_no_iores;
}

hw->regs = ioremap(res->start, resource_size(res));
if (hw->regs == NULL) {
    dev_err(&pdev->dev, "Cannot map IO\n");
    err = -ENXIO;
    goto err_no_iomap;
}

hw->irq = platform_get_irq(pdev, 0);
if (hw->irq < 0) {
    dev_err(&pdev->dev, "No IRQ specified\n");
    err = -ENOENT;
    goto err_no_irq;
}

err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
if (err) {
    dev_err(&pdev->dev, "Cannot claim IRQ\n");
    goto err_no_irq;
}

hw->clk = clk_get(&pdev->dev, "spi");
if (IS_ERR(hw->clk)) {
    dev_err(&pdev->dev, "No clock for device\n");
    err = PTR_ERR(hw->clk);
    goto err_no_clk;
}

/* setup any gpio we can */

if (!pdata->set_cs) {
    if (pdata->pin_cs < 0) {
        dev_err(&pdev->dev, "No chipselect pin\n");
        goto err_register;
    }

    err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
    if (err) {
        dev_err(&pdev->dev, "Failed to get gpio for cs\n");
        goto err_register;
    }

    hw->set_cs = s3c24xx_spi_gpiocs;
    gpio_direction_output(pdata->pin_cs, 1);
} else
    hw->set_cs = pdata->set_cs;

s3c24xx_spi_initialsetup(hw);  
    s3c24xx_spi_initialsetup(hw);  /* spi Инициализация контроллера */

/* register our spi controller */

/* Внутренне последний spi_register_master используется для регистрации контроллера SPI. */
err = spi_bitbang_start(&hw->bitbang);
if (err) {
    dev_err(&pdev->dev, "Failed to register SPI master\n");
    goto err_register;weiyu
}

Этот раздел тесно связан с конкретным оборудованием.,Начните с получения ресурсов платформы,Затем мы сделали IO-маппинг и Привязку соответственно. приложения прерывания и функции обработки прерывания、Инициализация часов и выбор чипаGPIOприменил и потянул высоко。Последний ключ - позвонитьs3c24xx_spi_initialsetupфункция,Долженфункция Внутри был сделан последний звонокspi_register_masterСпособ регистрацииSPIконтроллер。добрый СравниватьI2Cсуществоватьprobeфункциясерединаназываетсяi2c_add_numbered_adapterфункция,Он будет сканировать информацию о плате SPI внутри.,Затем используйте информацию о плате для создания устройств SPI.,и будетконтроллерspi_masterподсел наspi_deviceначальство,впоследствиисуществовать Уровень драйвера устройства SPIсередина Зарегистрировать устройствоводить машинупозвони послеprobeфункция会获取到Долженspi_device,Тогда ты сможешь пройтиspi_device серединаустановленspi_masterпозвонитьконтроллер Как работатьspi_bitbang_transferдля передачи данных。Следует отметить, чтоSPIиI2CПредоставляется общее оборудованиеводить машинудругой,Генерация узлов устройства не завершена в зарегистрированном хост-контроллере.,Скорее это делается в устройстве общего назначения.,Этот абзац начинается с уровня драйвера Анализ устройства можно посмотреть. Эта логика аналогична I2C, поэтому мы не будем ссылаться на Анализ. исходного код. (Ладно, как всегда ленив, QAQ)

Уровень драйвера устройства SPI

SPIОбщее оборудованиеводить машинуродыdrivers/spi/spidev.cсередина,Начните с функции init.

Язык кода:javascript
копировать
static struct spi_driver spidev_spi_driver = {
    .driver = {
        .name =     "spidev",
        .owner =    THIS_MODULE,
    },
    .probe =    spidev_probe,
    .remove =   __devexit_p(spidev_remove),
};

static int __init spidev_init(void)
{
    int status;

    /* Claim our 256 reserved device numbers.  Then register a class
     * that will key udev/mdev to add/remove /dev nodes.  Last, register
     * the driver which manages those device numbers.
     */
    BUILD_BUG_ON(N_SPI_MINORS > 256);
    /* Зарегистрируйтесь в качестве драйвера символьного устройства и предоставьте интерфейс вызова для уровня приложения. */
    status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
    if (status < 0)
        return status;

    /* Создать класс spidev */
    spidev_class = class_create(THIS_MODULE, "spidev");
    if (IS_ERR(spidev_class)) {
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
        return PTR_ERR(spidev_class);
    }

    /* вызовосновной Интерфейс, предоставляемый слоем для регистрации драйверов устройств */
    status = spi_register_driver(&spidev_spi_driver);
    if (status < 0) {
        class_destroy(spidev_class);
        unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
    }
    return status;
}

Напишу еще раз, когда будет время. Давай сначала отдохнем.

Автор этой статьи: Ifan Tsai  (кай-кай)

Ссылка на эту статью: https://cloud.tencent.com/developer/article/2164594

Заявление об авторских правах: Эта статья принимает Creative Commons Attribution-NonCommercial-ShareAlike 4.0 Международное лицензионное соглашение Дайте разрешение. При перепечатке просьба указывать источник!

boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose