SPI 버스의 감지 순서를 보장하는 방법은 무엇입니까?

SPI 버스의 감지 순서를 보장하는 방법은 무엇입니까?

iMX8 CPU 기반의 임베디드 Linux 시스템이 있습니다. 나는 yocto 버전과 커널 버전을 업그레이드하고 있습니다.

두 개의 SPI 버스에 두 개의 SPI 장치가 있습니다. 두 번째 버스의 장치는 한 드라이버에 의해 생성되고 /dev/spidevX.X node다른 드라이버에 의해 생성되지 않습니다 /dev/* node.

커널 업그레이드 중에 SPI 장치의 주소가 일치하지 않는 것 같습니다. 이전 yocto 버전에서는 Kernel 5.4.24두 번째 하드웨어 SPI 버스에 있는 장치가 /dev/spidev1.0일치하는 것으로 나타났습니다.

커널 5.15.71로 업그레이드한 후 노드는 대부분 으로 표시되지만 /dev/spidev2.0, 저도 본 적이 있습니다 /dev/spidev1.0.

내 Google 결과에 따르면 / dev/spidevX.Yv는 X = bus, 을 의미합니다 Y = device/CS.

특정 하드웨어 버스가 항상 특정 버스 번호를 갖도록 하는 방법은 무엇입니까?

답변1

spidev(drivers/spi/spidev.c)는 /dev/spidevB.C를 생성합니다. 여기서 B는 버스 번호이고 C는 칩 선택입니다.

dev = device_create(spidev_class, &spi->dev, spidev->devt,
            spidev, "spidev%d.%d",
            spi->master->bus_num, spi->chip_select); 

SPI 코어를 고려하는 것은 어떻습니까?drivers/spi/spi.c

int spi_register_controller(struct spi_controller *ctlr)

컨트롤러 버스 번호(아래 표시된 코드)를 할당하면 코어 간의 불일치 문제가 발생할 수 있는 방법이 여러 가지 있습니다(가능성은 낮지만).

두 커널 버전 간의 SoC 장치 트리에서 SPI 컨트롤러를 비교하여 정의 불일치가 있는지 확인하고 해결합니다.

예를 들어 일부 컨트롤러는 버전 정의에서 누락되었습니다.

그러한 불일치가 없으면 장치 트리 별칭에 불일치가 있는지 확인하고 해결하십시오( 아래 코드에서 작동하는 위치) of_alias_get_id.of_alias_get_highest_id

단지 상상의 예일 뿐이고,

SoC 5.4.y에서

aliases {
    :
    spi0 = &ecspi1;
    spi1 = &ecspi2;
    spi2 = &ecspi3;
};

하지만 SoC 5.15.y에서는

aliases {
    :
    spi0 = &ecspi3;
    spi1 = &ecspi1;
    spi2 = &ecspi2;
};

장치 트리에 SPI 별칭이 없고 불일치가 발생하는 경우 컨트롤러의 두 트리에 동일한 번호를 가진 SPI 별칭을 추가해 보세요.

예를 들어,

aliases {
    :
    spi0 = &lpspi1;
};

그래서 여기서는 숫자를 사용합니다.0줄기 뒤에SPI그래서 of_alias_get_id아마도 of_alias_get_highest_id당신은 그것을 선택할 수 있습니다.

언급하신 커널 버전을 구체적으로 확인하지 않았고 iMX8 SoC에 대해서도 언급하지 않았습니다(그러나 lf-5.4.y 및 lf-5.15.y를 살펴보면 SPI가 표시되지 않으므로 iMX8QXP일 가능성이 가장 높습니다) 따라서 이를 정의해야 하므로 불일치가 발생할 수 있지만 확실하지 않습니다.)

SPI 컨트롤러 버스 번호 할당은 다음에서 비롯됩니다.drivers/spi/spi.c

int spi_register_controller(struct spi_controller *ctlr)
{

    if (ctlr->bus_num >= 0) {
        /* devices with a fixed bus num must check-in with the num */
        mutex_lock(&board_lock);
        id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
            ctlr->bus_num + 1, GFP_KERNEL);
        mutex_unlock(&board_lock);
        if (WARN(id < 0, "couldn't get idr"))
            return id == -ENOSPC ? -EBUSY : id;
        ctlr->bus_num = id;
    } else if (ctlr->dev.of_node) {
        /* allocate dynamic bus number using Linux idr */
        id = of_alias_get_id(ctlr->dev.of_node, "spi");
        if (id >= 0) {
            ctlr->bus_num = id;
            mutex_lock(&board_lock);
            id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
                       ctlr->bus_num + 1, GFP_KERNEL);
            mutex_unlock(&board_lock);
            if (WARN(id < 0, "couldn't get idr"))
                return id == -ENOSPC ? -EBUSY : id;
        }
    }
    if (ctlr->bus_num < 0) {
        first_dynamic = of_alias_get_highest_id("spi");
        if (first_dynamic < 0)
            first_dynamic = 0;
        else
            first_dynamic++;

        mutex_lock(&board_lock);
        id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
                   0, GFP_KERNEL);
        mutex_unlock(&board_lock);
        if (WARN(id < 0, "couldn't get idr"))
            return id;
        ctlr->bus_num = id;
    }

}

관련 정보