SPI Subsystem -2- (Driver)

 

SPI Controller Core

SPI Master & Slave 컨트롤러 등록

spi_register_controller()

호환을 위해 spi_register_master() 매크로 함수는 spi_register_controller()를 호출한다.

drivers/spi/spi.c

/**
 * spi_register_controller - register SPI master or slave controller
 * @ctlr: initialized master, originally from spi_alloc_master() or
 *      spi_alloc_slave()
 * Context: can sleep
 *
 * SPI controllers connect to their drivers using some non-SPI bus,
 * such as the platform bus.  The final stage of probe() in that code
 * includes calling spi_register_controller() to hook up to this SPI bus glue.
 *
 * SPI controllers use board specific (often SOC specific) bus numbers,
 * and board-specific addressing for SPI devices combines those numbers
 * with chip select numbers.  Since SPI does not directly support dynamic
 * device identification, boards need configuration tables telling which
 * chip is at which address.
 *
 * This must be called from context that can sleep.  It returns zero on
 * success, else a negative error code (dropping the controller's refcount).
 * After a successful return, the caller is responsible for calling
 * spi_unregister_controller().
 *
 * Return: zero on success, else a negative error code.
 */
int spi_register_controller(struct spi_controller *ctlr)
{
        struct device           *dev = ctlr->dev.parent;
        struct boardinfo        *bi;
        int                     status = -ENODEV;
        int                     id, first_dynamic;

        if (!dev)
                return -ENODEV;

        if (!spi_controller_is_slave(ctlr)) {
                status = of_spi_register_master(ctlr);
                if (status)
                        return status;
        }

        /* even if it's just one always-selected device, there must
         * be at least one chipselect
         */
        if (ctlr->num_chipselect == 0)
                return -EINVAL;
        /* allocate dynamic bus number using Linux idr */
        if ((ctlr->bus_num < 0) && ctlr->dev.of_node) {
                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;
        }
        INIT_LIST_HEAD(&ctlr->queue);
        spin_lock_init(&ctlr->queue_lock);
        spin_lock_init(&ctlr->bus_lock_spinlock);
        mutex_init(&ctlr->bus_lock_mutex);
        mutex_init(&ctlr->io_mutex);
        ctlr->bus_lock_flag = 0;
        init_completion(&ctlr->xfer_completion);
        if (!ctlr->max_dma_len)
                ctlr->max_dma_len = INT_MAX;

SPI 마스터 또는 슬레이브 컨트롤러를 등록한다.

  • 코드 라인 11~15에서 등록할 컨트롤러가 슬레이브가 아닌 경우 디바이스 트리로부터 칩셀렉트를 위해 gpio 핀 정보들을 읽어온다.
    • 1개 이상의 “cs-gpios” 속성 값을 읽어 해당하는 gpio 핀 번호를 ctlr->cs_gpios[]에 대입한다.
  • 코드 라인 20~21에서 선택할 수 있는 슬레이브 칩 수가 0인 경우 에러를 반환한다.
  • 코드 라인 23~34에서 spi 버스 번호가 0을 초과한, 즉 다수인경우 “spi” alias 명을 찾아 id 값으로 버스 번호를 적용하여 idr 할당한다.
  • 코드 라인 35~49에서 spi 버스 번호가 0 미만인 경우 “spi” alias명으로 찾은 가장 높은 id 값 +1로 버스 번호를 적용하여 idr 할당한다.
  • 코드 라인 50~58에서 spi 컨트롤러의 멤버들을 초기화한다.

 

        /* register the device, then userspace will see it.
         * registration fails if the bus ID is in use.
         */
        dev_set_name(&ctlr->dev, "spi%u", ctlr->bus_num);
        status = device_add(&ctlr->dev);
        if (status < 0) {
                /* free bus id */
                mutex_lock(&board_lock);
                idr_remove(&spi_master_idr, ctlr->bus_num);
                mutex_unlock(&board_lock);
                goto done;
        }
        dev_dbg(dev, "registered %s %s\n",
                        spi_controller_is_slave(ctlr) ? "slave" : "master",
                        dev_name(&ctlr->dev));

        /* If we're using a queued driver, start the queue */
        if (ctlr->transfer)
                dev_info(dev, "controller is unqueued, this is deprecated\n");
        else {
                status = spi_controller_initialize_queue(ctlr);
                if (status) {
                        device_del(&ctlr->dev);
                        /* free bus id */
                        mutex_lock(&board_lock);
                        idr_remove(&spi_master_idr, ctlr->bus_num);
                        mutex_unlock(&board_lock);
                        goto done;
                }
        }
        /* add statistics */
        spin_lock_init(&ctlr->statistics.lock);

        mutex_lock(&board_lock);
        list_add_tail(&ctlr->list, &spi_controller_list);
        list_for_each_entry(bi, &board_list, list)
                spi_match_controller_to_boardinfo(ctlr, &bi->board_info);
        mutex_unlock(&board_lock);

        /* Register devices from the device tree and ACPI */
        of_register_spi_devices(ctlr);
        acpi_register_spi_devices(ctlr);
done:
        return status;
}
EXPORT_SYMBOL_GPL(spi_register_controller);
  • 코드 라인 4~15에서 “spi<bus#>”  명으로 디바이스를 추가한다.
    • 예) “registered  master spi0” 또는 “registered slave spi1” 형식으로 디버그 메시지를 출력한다.
  • 코드 라인 18~30에서 (*transfer) 후크 함수는 deprecated될 예정이다. 이 함수가 지정되지 않은 경우큐 방식을 사용하기 위해 spi 컨트롤러용 큐를 초기화한다.
  • 코드 라인 32에서 통계 관련 락을 초기화한다.
  • 코드 라인 34~38에서 전역 spi_controller_list에 컨트롤러를 추가한다. 그런 후 컨트롤러가 전역 board_list에 있는 디바이스와 매치되는 경우 spi_new_device() 함수를 호출하여 spi 디바이스로 추가 등록한다.
  • 코드 라인 41에서 컨트롤러 노드의 하위 노드의 SPI 디바이스들을 추가한다.
    • of_register_spi_device() -> 다음 각종 spi 디바이스 속성 값을 파싱한 후 -> spi_add_device()
      • “spi-cpha”
      • “spi-cpol”
      • “spi-cs-high”
      • “spi-3wire”
      • “spi-tx-bus-width”
      • “spi-rx-bus-width”
      • “slave”
      • “reg”
      • “spi-max-frequency”
  • 코드 라인 42에서 ACPI 펌웨어에서 spi 디바이스 정보를 읽어와서 추가한다.

 

of_register_spi_devices()

drivers/spi/spi.c

/**
 * of_register_spi_devices() - Register child devices onto the SPI bus
 * @ctlr:       Pointer to spi_controller device
 *
 * Registers an spi_device for each child node of controller node which
 * represents a valid SPI slave.
 */
static void of_register_spi_devices(struct spi_controller *ctlr)
{
        struct spi_device *spi;
        struct device_node *nc;

        if (!ctlr->dev.of_node)
                return;

        for_each_available_child_of_node(ctlr->dev.of_node, nc) {
                if (of_node_test_and_set_flag(nc, OF_POPULATED))
                        continue;
                spi = of_register_spi_device(ctlr, nc);
                if (IS_ERR(spi)) {
                        dev_warn(&ctlr->dev,
                                 "Failed to create SPI device for %pOF\n", nc);
                        of_node_clear_flag(nc, OF_POPULATED);
                }
        }
}

컨트롤러 디바이스 트리 노드의 하위 노드들을 대상으로 매치되는 spi 디바이스들을 모두 등록한다.

 

of_register_spi_device()

drivers/spi/spi.c

static struct spi_device *
of_register_spi_device(struct spi_controller *ctlr, struct device_node *nc)
{
        struct spi_device *spi;
        int rc;

        /* Alloc an spi_device */
        spi = spi_alloc_device(ctlr);
        if (!spi) {
                dev_err(&ctlr->dev, "spi_device alloc error for %pOF\n", nc);
                rc = -ENOMEM;
                goto err_out;
        }

        /* Select device driver */
        rc = of_modalias_node(nc, spi->modalias,
                                sizeof(spi->modalias));
        if (rc < 0) {
                dev_err(&ctlr->dev, "cannot find modalias for %pOF\n", nc);
                goto err_out;
        }

        rc = of_spi_parse_dt(ctlr, spi, nc);
        if (rc)
                goto err_out;

        /* Store a pointer to the node in the device structure */
        of_node_get(nc);
        spi->dev.of_node = nc;

        /* Register the new device */
        rc = spi_add_device(spi);
        if (rc) {
                dev_err(&ctlr->dev, "spi_device register error %pOF\n", nc);
                goto err_of_node_put;
        }

        return spi;

err_of_node_put:
        of_node_put(nc);
err_out:
        spi_dev_put(spi);
        return ERR_PTR(rc);
}

컨트롤러 디바이스 트리 노드의 지정한 하위 노드의 spi 디바이스 하나를 등록한다.

  • 코드 라인 8~13에서 spi 디바이스를 할당 받아 초기화한다.
  • 코드 라인 16~21에서 “compatible” 속성 값에서 회사명과 컴마(“,”)를 제외한 드라이버명을 spi->modalias에 대입한다.
  • 코드 라인 23~25에서 spi 디바이스 노드에서 다음 속성들을 파싱해온다.
    • “spi-cpha”
    • “spi-cpol”
    • “spi-cs-high”
    • “spi-3wire”
    • “spi-tx-bus-width”
    • “spi-rx-bus-width”
    • “slave”
    • “reg”
    • “spi-max-frequency”
  • 코드 라인 28~29에서 spi 디바이스의 참조 카운터를 1 증가시키고, 디바이스 트리의 spi 디바이스 노드를 가리키게 한다.
  • 코드 라인 32~36에서 spi 디바이스를 추가한다.

 

spi_add_device()

drivers/spi/spi.c

/**
 * spi_add_device - Add spi_device allocated with spi_alloc_device
 * @spi: spi_device to register
 *
 * Companion function to spi_alloc_device.  Devices allocated with
 * spi_alloc_device can be added onto the spi bus with this function.
 *
 * Return: 0 on success; negative errno on failure
 */
int spi_add_device(struct spi_device *spi)
{
        static DEFINE_MUTEX(spi_add_lock);
        struct spi_controller *ctlr = spi->controller;
        struct device *dev = ctlr->dev.parent;
        int status;

        /* Chipselects are numbered 0..max; validate. */
        if (spi->chip_select >= ctlr->num_chipselect) {
                dev_err(dev, "cs%d >= max %d\n", spi->chip_select,
                        ctlr->num_chipselect);
                return -EINVAL;
        }

        /* Set the bus ID string */
        spi_dev_set_name(spi);

        /* We need to make sure there's no other device with this
         * chipselect **BEFORE** we call setup(), else we'll trash
         * its configuration.  Lock against concurrent add() calls.
         */
        mutex_lock(&spi_add_lock);

        status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
        if (status) {
                dev_err(dev, "chipselect %d already in use\n",
                                spi->chip_select);
                goto done;
        }

        if (ctlr->cs_gpios)
                spi->cs_gpio = ctlr->cs_gpios[spi->chip_select];

        /* Drivers may modify this initial i/o setup, but will
         * normally rely on the device being setup.  Devices
         * using SPI_CS_HIGH can't coexist well otherwise...
         */
        status = spi_setup(spi);
        if (status < 0) {
                dev_err(dev, "can't setup %s, status %d\n",
                                dev_name(&spi->dev), status);
                goto done;
        }

        /* Device may be bound to an active driver when this returns */
        status = device_add(&spi->dev);
        if (status < 0)
                dev_err(dev, "can't add %s, status %d\n",
                                dev_name(&spi->dev), status);
        else
                dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));

done:
        mutex_unlock(&spi_add_lock);
        return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);

spi 디바이스를 칩셀렉션하고 hw 설정한 후 추가한다.

  • 코드 라인 9~13에서 최대 슬레이브 칩 수를 초과하는 칩이 선택된 경우 에러를 반환한다.
  • 코드 라인 16에서 버스 번호를 포함하여 spi 디바이스 명을 결정하는데 다음 둘 중 하나를 사용한다.
    • acpi를 사용하는 경우 “spi-<device name>” 포맷을 사용한다.
    • 그 외의 경우 “<컨트롤러명>.<칩 셀렉트 번호>” 포맷을 사용한다.
  • 코드 라인 24~29에서 spi 디바이스가 이미 셋업되어 사용중인지 확인한다. 사용중이면 경고 메시지를 출력하고 등록을 포기한다.
  • 코드 라인 31~32에서 gpio를 사용하여 칩셀렉트를 하는 경우 사용할 gpio 번호를 지정한다.
  • 코드 라인 38~43에서 spi 디바이스를 hw 설정한다.
  • 코드 라인 46~51에서 spi 디바이스를 추가한다.

 

spi_setup()

drivers/spi/spi.c

/**
 * spi_setup - setup SPI mode and clock rate
 * @spi: the device whose settings are being modified
 * Context: can sleep, and no requests are queued to the device
 *
 * SPI protocol drivers may need to update the transfer mode if the
 * device doesn't work with its default.  They may likewise need
 * to update clock rates or word sizes from initial values.  This function
 * changes those settings, and must be called from a context that can sleep.
 * Except for SPI_CS_HIGH, which takes effect immediately, the changes take
 * effect the next time the device is selected and data is transferred to
 * or from it.  When this function returns, the spi device is deselected.
 *
 * Note that this call will fail if the protocol driver specifies an option
 * that the underlying controller or its driver does not support.  For
 * example, not all hardware supports wire transfers using nine bit words,
 * LSB-first wire encoding, or active-high chipselects.
 *
 * Return: zero on success, else a negative error code.
 */
int spi_setup(struct spi_device *spi)
{
        unsigned        bad_bits, ugly_bits;
        int             status;

        /* check mode to prevent that DUAL and QUAD set at the same time
         */
        if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||
                ((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {
                dev_err(&spi->dev,
                "setup: can not select dual and quad at the same time\n");
                return -EINVAL;
        }
        /* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
         */
        if ((spi->mode & SPI_3WIRE) && (spi->mode &
                (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
                return -EINVAL;
        /* help drivers fail *cleanly* when they need options
         * that aren't supported with their current controller
         */
        bad_bits = spi->mode & ~spi->controller->mode_bits;
        ugly_bits = bad_bits &
                    (SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
        if (ugly_bits) {
                dev_warn(&spi->dev,
                         "setup: ignoring unsupported mode bits %x\n",
                         ugly_bits);
                spi->mode &= ~ugly_bits;
                bad_bits &= ~ugly_bits;
        }
        if (bad_bits) {
                dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
                        bad_bits);
                return -EINVAL;
        }

        if (!spi->bits_per_word)
                spi->bits_per_word = 8;

        status = __spi_validate_bits_per_word(spi->controller,
                                              spi->bits_per_word);
        if (status)
                return status;

        if (!spi->max_speed_hz)
                spi->max_speed_hz = spi->controller->max_speed_hz;

        if (spi->controller->setup)
                status = spi->controller->setup(spi);

        spi_set_cs(spi, false);

        dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
                        (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
                        (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
                        (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
                        (spi->mode & SPI_3WIRE) ? "3wire, " : "",
                        (spi->mode & SPI_LOOP) ? "loopback, " : "",
                        spi->bits_per_word, spi->max_speed_hz,
                        status);

        return status;
}

spi 디바이스의 클럭 모드 및 속도 등을 설정한다.

  • 코드 라인 8~13에서 spi 디바이스가 동시에 dual 및 quad 설정을 요청하는 경우 에러 미세지를 출력하고 에러를 반환한다.
  • 코드 라인 16~18에서 3wire 모드가 선택된 경우 dual 및 quad와 같이 설정할 수 없다.
  • 코드 라인 22~36에서 spi 컨트롤러가 지원하지 않는 모드를 요청한 경우 에러 메시지를 출력하고 에러를 반환한다.
    • 단 컨트롤러가 지원하지 않는 dual 또는 quad 요청을 한 경우 에러를 반환하지 않고 모드 플래그에서 제거한다.
  • 코드 라인 38~39에서 워드당 비트 수를 0으로 요청한 경우 디폴트로 8 비트를 사용한다.
  • 코드 라인 41~44에서 컨트롤러에 워드당 비트수 제한 마스크 이내에서 사용되어야 하고 워드당 비트 수가 32를 초과한 경우 에러를 반환한다.
  • 코드 라인 46~47에서 spi 디바이스의 속도 제한 값이 없는 경우 spi 컨트롤러의 값을 사용한다.
  • 코드 라인 49~50에서 spi 디바이스 설정 값으로 spi 컨트롤러를 설정한다.
  • 코드 라인 52에서 spi 디바이스의 칩 셀렉트를 하지 않도록 설정한다.
  • 코드 라인 54에서 설정 정보를 출력한다.
    • “setup mode %d, “%s%s%s%s%u bits/w, %d Hz max –> %d”
      • 1) cpol 또는 cpha 모드 비트만을 출력한다.
      • 2) cs_high 여부
      • 3) lsb 부터 출력하는지 여부
      • 4) 3wire 모드 여부
      • 5) loopback 모드 여부
      • 6) 워드당 비트 수
      • 7) 최대 제한 속도
      • 8) 설정 상태 값

 


Kernel API

SPI 전송

spi_async()

  • 비동기 메시지 전송 요청
  • 메시지 전송이 완료되면 지정한 콜백 함수가 호출된다.
  • irq context 또는 process context 모두에서 사용할 수 있다.

drivers/spi/spi.c

/**
 * spi_async - asynchronous SPI transfer
 * @spi: device with which data will be exchanged
 * @message: describes the data transfers, including completion callback
 * Context: any (irqs may be blocked, etc)
 *
 * This call may be used in_irq and other contexts which can't sleep,
 * as well as from task contexts which can sleep.
 *
 * The completion callback is invoked in a context which can't sleep.
 * Before that invocation, the value of message->status is undefined.
 * When the callback is issued, message->status holds either zero (to
 * indicate complete success) or a negative error code.  After that
 * callback returns, the driver which issued the transfer request may
 * deallocate the associated memory; it's no longer in use by any SPI
 * core or controller driver code.
 *
 * Note that although all messages to a spi_device are handled in
 * FIFO order, messages may go to different devices in other orders.
 * Some device might be higher priority, or have various "hard" access
 * time requirements, for example.
 *
 * On detection of any fault during the transfer, processing of
 * the entire message is aborted, and the device is deselected.
 * Until returning from the associated message completion callback,
 * no other spi_message queued to that device will be processed.
 * (This rule applies equally to all the synchronous transfer calls,
 * which are wrappers around this core asynchronous primitive.)
 *
 * Return: zero on success, else a negative error code.
 */
int spi_async(struct spi_device *spi, struct spi_message *message)
{
        struct spi_controller *ctlr = spi->controller;
        int ret;
        unsigned long flags;

        ret = __spi_validate(spi, message);
        if (ret != 0)
                return ret;

        spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);

        if (ctlr->bus_lock_flag)
                ret = -EBUSY;
        else
                ret = __spi_async(spi, message);

        spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);

        return ret;
}
EXPORT_SYMBOL_GPL(spi_async);

준비된 @message를 @spi 슬레이브 장치로 비동기 전송한다. 결과가 0이면 정상이다.

  • 코드 라인 7~9에서 @message가 적절한지 유효 검사를 수행한다.
  • 코드 라인 11~18에서 spinlock을 획득한 채로 SPI 비동기 전송을 수행한다.
  • 코드 라인 20에서 결과를 반환한다. (결과 0이면 정상)

 

__spi_async()

drivers/spi/spi.c

static int __spi_async(struct spi_device *spi, struct spi_message *message)
{
        struct spi_controller *ctlr = spi->controller;

        message->spi = spi;

        SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_async);
        SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_async);

        trace_spi_message_submit(message);

        return ctlr->transfer(spi, message);
}

준비된 @message를 @spi 슬레이브 장치로 비동기 전송한다. 결과가 0이면 정상이다.

  • 코드 라인 3에서 spi 슬레이브 장치가 소속한 spi 컨트롤러를 알아온다.
  • 코드 라인 7~8에서 spi 컨트롤러와 슬레이브측의 spi_async 카운터를 각각 1씩 증가시킨다.
  • 코드 라인 10에서 trace 메시지를 출력한다.
  • 코드 라인 12에서 컨트롤러에 구현된 (*transfer) 함수를 사용하여 @message를 @spi 슬레이브 디바이스에 비동기 전송한다.

 

spi_sync()

  • 동기 메시지 전송 요청
  • 슬립 가능한 프로세스 context에서만 사용할 수 있다.
    • irq context에서 사용하면 안된다.

drivers/spi/spi.c

/**
 * spi_sync - blocking/synchronous SPI data transfers
 * @spi: device with which data will be exchanged
 * @message: describes the data transfers
 * Context: can sleep
 *
 * This call may only be used from a context that may sleep.  The sleep
 * is non-interruptible, and has no timeout.  Low-overhead controller
 * drivers may DMA directly into and out of the message buffers.
 *
 * Note that the SPI device's chip select is active during the message,
 * and then is normally disabled between messages.  Drivers for some
 * frequently-used devices may want to minimize costs of selecting a chip,
 * by leaving it selected in anticipation that the next message will go
 * to the same chip.  (That may increase power usage.)
 *
 * Also, the caller is guaranteeing that the memory associated with the
 * message will not be freed before this call returns.
 *
 * Return: zero on success, else a negative error code.
 */
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
        int ret;

        mutex_lock(&spi->controller->bus_lock_mutex);
        ret = __spi_sync(spi, message);
        mutex_unlock(&spi->controller->bus_lock_mutex);

        return ret;
}
EXPORT_SYMBOL_GPL(spi_sync);

준비된 @message를 @spi 슬레이브 장치로 동기 전송한다. 결과가 0이면 정상이다.

  • 코드 라인 5~7에서 spi 컨트롤러의 버스 락을 획득한채로 @spi 슬레이브 디바이스에게 @message를 동기 전송한다.
  • 코드 라인 9에서 결과 값을 반환한다.

 

__spi_sync()

drivers/spi/spi.c

static int __spi_sync(struct spi_device *spi, struct spi_message *message)
{
        DECLARE_COMPLETION_ONSTACK(done);
        int status;
        struct spi_controller *ctlr = spi->controller;
        unsigned long flags;

        status = __spi_validate(spi, message);
        if (status != 0)
                return status;

        message->complete = spi_complete;
        message->context = &done;
        message->spi = spi;

        SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics, spi_sync);
        SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics, spi_sync);

        /* If we're not using the legacy transfer method then we will
         * try to transfer in the calling context so special case.
         * This code would be less tricky if we could remove the
         * support for driver implemented message queues.
         */
        if (ctlr->transfer == spi_queued_transfer) {
                spin_lock_irqsave(&ctlr->bus_lock_spinlock, flags);

                trace_spi_message_submit(message);

                status = __spi_queued_transfer(spi, message, false);

                spin_unlock_irqrestore(&ctlr->bus_lock_spinlock, flags);
        } else {
                status = spi_async_locked(spi, message);
        }

        if (status == 0) {
                /* Push out the messages in the calling context if we
                 * can.
                 */
                if (ctlr->transfer == spi_queued_transfer) {
                        SPI_STATISTICS_INCREMENT_FIELD(&ctlr->statistics,
                                                       spi_sync_immediate);
                        SPI_STATISTICS_INCREMENT_FIELD(&spi->statistics,
                                                       spi_sync_immediate);
                        __spi_pump_messages(ctlr, false);
                }

                wait_for_completion(&done);
                status = message->status;
        }
        message->context = NULL;
        return status;
}

준비된 @message를 @spi 슬레이브 장치로 동기 전송한다. 결과가 0이면 정상이다.

  • 코드 라인 3에서 동기 전송의 완료를 대기하기 위해 사용할 값을 준비한다.
  • 코드 라인 5에서 @spi 슬레이브 장치가 소속한 spi 컨트롤러를 알아온다.
  • 코드 라인 8~10에서 @message의 유효성 검사를 수행한다.
  • 코드 라인 12~14에서 메시지에 전송완료를 대기 준비와 spi 슬레이브 디바이스를 지정한다.
  • 코드 라인 16~17에서 spi 컨트롤러와 슬레이브측의 spi_sync 카운터를 각각 1씩 증가시킨다.
  • 코드 라인 24~31에서 queued 전송이 가능한 spi 컨트롤러인 경우 이 방식으로 @message를 @spi 슬레이브 디바이스에 전송을 하도록 큐에 추가한다.
  • 코드 라인 32~34에서 queued 전송이 가능하지 않은 spi 컨트롤러인 경우 @message를 @spi 슬레이브 디바이스에 비동기 전송을 요청한다.
  • 코드 라인 36~50에서 성공적으로 전송 요청을 하였으면 전송이 완료될 때까지 대기한다. queued 전송이 가능한 spi 컨트롤러의 경우 spi 컨트롤러와 슬레이브측의 spi_sync_immediate 카운터를 각각 1씩 증가시킨다.
  • 코드 라인 51~52에서 message의 context를 null로 하고, 결과 값을 반환한다.

 

spi_complete()

drivers/spi/spi.c

/* Utility methods for SPI protocol drivers, layered on
 * top of the core.  Some other utility methods are defined as
 * inline functions.
 */

static void spi_complete(void *arg)
{
        complete(arg);
}

spi 전송이 실제 완료된 경우 complete를 호출한다.

 

spi_queued_transfer()

drivers/spi/spi.c

/**
 * spi_queued_transfer - transfer function for queued transfers
 * @spi: spi device which is requesting transfer
 * @msg: spi message which is to handled is queued to driver queue
 *
 * Return: zero on success, else a negative error code.
 */
static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
{
        return __spi_queued_transfer(spi, msg, true);
}

@spi 디바이스로 전송할 @msg를 spi 컨트롤러의 큐에 추가한다. 또한 컨트롤러의 spi 메시지 전송용 워커 스레드가 동작하지 않고 있으면 깨워 동작시킨다. 메시지를 큐에 잘 추가한 경우 성공 값 0을 반환한다.

 

__spi_queued_transfer()

drivers/spi/spi.c

static int __spi_queued_transfer(struct spi_device *spi,
                                 struct spi_message *msg,
                                 bool need_pump)
{
        struct spi_controller *ctlr = spi->controller;
        unsigned long flags;

        spin_lock_irqsave(&ctlr->queue_lock, flags);

        if (!ctlr->running) {
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                return -ESHUTDOWN;
        }
        msg->actual_length = 0;
        msg->status = -EINPROGRESS;

        list_add_tail(&msg->queue, &ctlr->queue);
        if (!ctlr->busy && need_pump)
                kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);

        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
        return 0;
}

@spi 디바이스로 전송할 @msg를 spi 컨트롤러의 큐에 추가한다. @need_pump가 요청되면 컨트롤러의 spi 메시지 전송용 워커 스레드가 동작하지 않고 있으면 깨워 동작시킨다. 메시지를 큐에 잘 추가한 경우 성공 값 0을 반환한다.

  • 코드 라인 5에서 @spi 슬레이브 디바이스가 소속한 spi 컨트롤러를 알아온다.
  • 코드 라인 8에서 spi 컨트롤러의 큐에 대한 락을 획득한다.
  • 코드 라인 10~13에서 spi 컨트롤러가 동작 중이지 않고 꺼져 있는 상태면, -ESHUTDOWN 에러를 반환한다.
  • 코드 라인 14~15에서 메시지의 전송 직전 초기 상태로 actual_legnth를 0으로 그리고 상태를 -EINPROGRESS로 지정한다.
  • 코드 라인 17에서 spi 컨트롤러의 큐에 @msg를 추가한다.
  • 코드 라인 18~19에서 @need_pump가 요청되면 컨트롤러의 spi 메시지 전송용 워커 스레드가 동작하지 않고 있으면 깨워 동작시킨다.
  • 코드 라인 21~22에서 spi 컨트롤러의 큐에 대한 락을 풀고, 성공 결과 값 0을 반환한다.

 

__spi_pump_messages()

drivers/spi/spi.c – 1/2

/**
 * __spi_pump_messages - function which processes spi message queue
 * @ctlr: controller to process queue for
 * @in_kthread: true if we are in the context of the message pump thread
 *
 * This function checks if there is any spi message in the queue that
 * needs processing and if so call out to the driver to initialize hardware
 * and transfer each message.
 *
 * Note that it is called both from the kthread itself and also from
 * inside spi_sync(); the queue extraction handling at the top of the
 * function should deal with this safely.
 */
static void __spi_pump_messages(struct spi_controller *ctlr, bool in_kthread)
{
        unsigned long flags;
        bool was_busy = false;
        int ret;

        /* Lock queue */
        spin_lock_irqsave(&ctlr->queue_lock, flags);

        /* Make sure we are not already running a message */
        if (ctlr->cur_msg) {
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                return;
        }

        /* If another context is idling the device then defer */
        if (ctlr->idling) {
                kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                return;
        }

        /* Check if the queue is idle */
        if (list_empty(&ctlr->queue) || !ctlr->running) {
                if (!ctlr->busy) {
                        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                        return;
                }

                /* Only do teardown in the thread */
                if (!in_kthread) {
                        kthread_queue_work(&ctlr->kworker,
                                           &ctlr->pump_messages);
                        spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                        return;
                }

                ctlr->busy = false;
                ctlr->idling = true;
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);

                kfree(ctlr->dummy_rx);
                ctlr->dummy_rx = NULL;
                kfree(ctlr->dummy_tx);
                ctlr->dummy_tx = NULL;
                if (ctlr->unprepare_transfer_hardware &&
                    ctlr->unprepare_transfer_hardware(ctlr))
                        dev_err(&ctlr->dev,
                                "failed to unprepare transfer hardware\n");
                if (ctlr->auto_runtime_pm) {
                        pm_runtime_mark_last_busy(ctlr->dev.parent);
                        pm_runtime_put_autosuspend(ctlr->dev.parent);
                }
                trace_spi_controller_idle(ctlr);

                spin_lock_irqsave(&ctlr->queue_lock, flags);
                ctlr->idling = false;
                spin_unlock_irqrestore(&ctlr->queue_lock, flags);
                return;
        }

queued 전송을 지원하는 spi 컨트롤러의 전송을 시작한다. 이 함수가 스레드 내부에서 호출된 경우 @in_kthread가 설정되어 요청된다.

  • 코드 라인 8에서 @ctrl spi 컨트롤러에 큐잉된 메시지를 꺼내기 위해 @ctrl spi 컨트롤러의 큐 락을 건다.
  • 코드 라인 11~13에서 이미 전송 중인 경우 락을 풀고 함수를 빠져나간다.
  • 코드 라인 16~20에서 spi 컨트롤러가 다른 코드의 요청으로 인해 절전 진행 중(idling) 상태라면 메시지 전송을 이번 호출에서 유예(defer)시켜 다음 타임에 전송하도록 spi 전송 스레드를 다시 깨워 이 함수를 호출하도록 요청해놓고 함수를 빠져나간다.
  • 코드 라인 23에서 spi 컨트롤러의 큐가 비어 있거나, shutdown 상태인 경우이다.
  • 코드 라인 24~27에서 spi 컨트롤러가 busy 상태가 아니라면 메시지가 없는 상태로 이 함수가 호출된 상태이므로 그냥 함수를 빠져나간다.
  • 코드 라인 30~35에서 스레드 내부에서 호출되지 않은 경우 이번 호출에서 유예(defer)시켜 다음 타임에 전송하도록 spi 전송 스레드를 다시 깨워 이 함수를 호출하도록 요청해놓고 함수를 빠져나간다.
  • 코드 라인 37~39에서 spi 컨트롤러를 절전 상태로 변경하기 위해 busy 상태를 false로, idling 상태를 true로 변경하고 스핀락을 푼다.
  • 코드 라인 41~44에서 spi 컨트롤러의 dumy_rx 및 dump_txㄹ르 해제하고 null을 대입한다.
  • 코드 라인 45~48에서 spi 컨트롤러의 (*unprepare_transfer_hardware)가 지원되면 호출하여, spi 컨트롤러의 전원등을 끈다.
  • 코드 라인 49~52에서 spi 컨트롤러의 (*auto_runtime_pm)가 지원되면 @spi 컨트롤러 디바이스의 마지막 busy 타임을 갱신하고, 절전 상태로 전환시킨다.
  • 코드 라인 53에서 spi 컨트롤러가 절전(idle) 상태로 진입하였다는 메시지를 출력한다.
  • 코드 라인 55~59에서 절전(idle) 상태로 진입이 완료되었으므로, spin 락을 획득한 생태로 spi 컨트롤러의 idling 상태를 false로 변경하고, 함수를 빠져나간다.

 

drivers/spi/spi.c – 2/2

        /* Extract head of queue */
        ctlr->cur_msg =
                list_first_entry(&ctlr->queue, struct spi_message, queue);

        list_del_init(&ctlr->cur_msg->queue);
        if (ctlr->busy)
                was_busy = true;
        else
                ctlr->busy = true;
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);

        mutex_lock(&ctlr->io_mutex);

        if (!was_busy && ctlr->auto_runtime_pm) {
                ret = pm_runtime_get_sync(ctlr->dev.parent);
                if (ret < 0) {
                        pm_runtime_put_noidle(ctlr->dev.parent);
                        dev_err(&ctlr->dev, "Failed to power device: %d\n",
                                ret);
                        mutex_unlock(&ctlr->io_mutex);
                        return;
                }
        }

        if (!was_busy)
                trace_spi_controller_busy(ctlr);

        if (!was_busy && ctlr->prepare_transfer_hardware) {
                ret = ctlr->prepare_transfer_hardware(ctlr);
                if (ret) {
                        dev_err(&ctlr->dev,
                                "failed to prepare transfer hardware\n");

                        if (ctlr->auto_runtime_pm)
                                pm_runtime_put(ctlr->dev.parent);
                        mutex_unlock(&ctlr->io_mutex);
                        return;
                }
        }

        trace_spi_message_start(ctlr->cur_msg);

        if (ctlr->prepare_message) {
                ret = ctlr->prepare_message(ctlr, ctlr->cur_msg);
                if (ret) {
                        dev_err(&ctlr->dev, "failed to prepare message: %d\n",
                                ret);
                        ctlr->cur_msg->status = ret;
                        spi_finalize_current_message(ctlr);
                        goto out;
                }
                ctlr->cur_msg_prepared = true;
        }

        ret = spi_map_msg(ctlr, ctlr->cur_msg);
        if (ret) {
                ctlr->cur_msg->status = ret;
                spi_finalize_current_message(ctlr);
                goto out;
        }

        ret = ctlr->transfer_one_message(ctlr, ctlr->cur_msg);
        if (ret) {
                dev_err(&ctlr->dev,
                        "failed to transfer one message from queue\n");
                goto out;
        }

out:
        mutex_unlock(&ctlr->io_mutex);

        /* Prod the scheduler in case transfer_one() was busy waiting */
        if (!ret)
                cond_resched();
}
  • 코드 라인 2~5에서 큐에서 처음 메시지를 하나 꺼내서 컨트롤러가 처리 중인 메시지로 둔다.
  • 코드 라인 6~10에서 spi 컨트롤러를 busy 상태로 변경한다. 이미 busy 상태인 경우 was_busy에 true를 대입하고, 스핀락을 푼다.
  • 코드 라인 12에서 spi 컨트롤러의 io 락을 획득한다.
  • 코드 라인 14~23에서 io 락을 획득하였으므로 다시 한 번 확인하여 여전히 절전 중이면 함수를 빠져나간다.
  • 코드 라인 25~26에서 spi 컨트롤러가 busy 상태가 아니었었으면(!was_busy) busy 상태로 진입했다는 트레이스 메시지를 출력한다.
  • 코드 라인 28~45에서 spi 컨트롤러가 busy 상태가 아니었었고(!was_busy) spi 컨트롤러가  (*prepare_transfer_hardware)를 지원하는 경우 호출하여 spi 컨트롤러의 파워를 다시 켠다.
  • 코드 라인 47에서 이제 막 전송을 시작하기 위해 트레이스 메시지를 출력한다.
  • 코드 라인 49~59에서 spi 컨트롤러가 메시지 전송 전에 처리할 일을 수행하기 위해 spi 컨트롤러의 (*prepare_message)를 호출한다.
  • 코드 라인 61~66에서 DMA 전송을 사용하는 spi 컨트롤러인 경우 DMA용 버퍼를 준비하고 매핑한다.
  • 코드 라인 68~73에서 PTP 시스템 타임스탬프를 추가한다.
    • spi: Add a PTP system timestamp to the transfer structure (2019, k)
  • 코드 라인 75~80에서 spi 컨트롤러의 (*transfer_one_message)를 호출하여 메시지를 전송한다.
  • 코드 라인 82~87에서 out: 레이블이다. io 락을 해제하고 함수를 나가는데, 전송이 실패(busy waiting)한 경우 preemption 포인트를 수행한다.

 

spi_finalize_current_message()

drivers/spi/spi.c

/**
 * spi_finalize_current_message() - the current message is complete
 * @ctlr: the controller to return the message to
 *
 * Called by the driver to notify the core that the message in the front of the
 * queue is complete and can be removed from the queue.
 */
void spi_finalize_current_message(struct spi_controller *ctlr)
{
        struct spi_message *mesg;
        unsigned long flags;
        int ret;

        spin_lock_irqsave(&ctlr->queue_lock, flags);
        mesg = ctlr->cur_msg;
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);

        spi_unmap_msg(ctlr, mesg);

        if (ctlr->cur_msg_prepared && ctlr->unprepare_message) {
                ret = ctlr->unprepare_message(ctlr, mesg);
                if (ret) {
                        dev_err(&ctlr->dev, "failed to unprepare message: %d\n",
                                ret);
                }
        }

        spin_lock_irqsave(&ctlr->queue_lock, flags);
        ctlr->cur_msg = NULL;
        ctlr->cur_msg_prepared = false;
        kthread_queue_work(&ctlr->kworker, &ctlr->pump_messages);
        spin_unlock_irqrestore(&ctlr->queue_lock, flags);

        trace_spi_message_done(mesg);

        mesg->state = NULL;
        if (mesg->complete)
                mesg->complete(mesg->context);
}
EXPORT_SYMBOL_GPL(spi_finalize_current_message);

@ctrl spi 컨트롤러가 처리한 메시지의 완료 처리를 수행한다.

  • 코드 라인 7~9에서 spi 컨트롤러가 처리한 메시지를 알아온다.
  • 코드 라인 11에서 DMA 방식의 컨트롤러인 경우 DMA 버퍼의 매핑을 해제한다.
  • 코드 라인 13~19에서 메시지의 처리가 완료된 후 처리할 일을 수행하기 위해, spi 컨트롤러가 (*unprepare_message)를 호출한다.
  • 코드 라인 21~25에서 스핀락을 획득한 채로 spi 컨트롤러의 cur_msg에 null 을 대입하고, cur_msg_prepared에 false를 대입한 후 다시 다음 메시지 처리를 수행하도록 워커 스레드를 큐잉한다.
  • 코드 라인 27에서 메시지 처리 완료 트레이스 메시지를 출력한다.
  • 코드 라인 29~31에서 메시지의 상태를 null로 바꾸고, 메시지의 처리가 완료된 경우 complete를 호출하여, sinc 상태에서 대기 중인 태스크를 깨운다.

 

spi_write() & spi_read()

  • spi_sync()를 호출하여 사용한다.

 

spi_read_flash()

  • SPI 플래시를 읽을 수 있도록 최적화된 함수를 제공한다.

spi_message_init()

  • SPI 메시지 초기화

 

spi_message_add_tail()

  • 전송 요청을 메시지의 전송 리스트에 추가한다.
    • spi_message->transfers 리스트에 spi_transfer->transfer_list를 추가한다.

 

구조체

spi_device 구조체

/**
 * struct spi_device - Controller side proxy for an SPI slave device
 * @dev: Driver model representation of the device.
 * @controller: SPI controller used with the device.
 * @master: Copy of controller, for backwards compatibility.
 * @max_speed_hz: Maximum clock rate to be used with this chip
 *      (on this board); may be changed by the device's driver.
 *      The spi_transfer.speed_hz can override this for each transfer.
 * @chip_select: Chipselect, distinguishing chips handled by @controller.
 * @mode: The spi mode defines how data is clocked out and in.
 *      This may be changed by the device's driver.
 *      The "active low" default for chipselect mode can be overridden
 *      (by specifying SPI_CS_HIGH) as can the "MSB first" default for
 *      each word in a transfer (by specifying SPI_LSB_FIRST).
 * @bits_per_word: Data transfers involve one or more words; word sizes
 *      like eight or 12 bits are common.  In-memory wordsizes are
 *      powers of two bytes (e.g. 20 bit samples use 32 bits).
 *      This may be changed by the device's driver, or left at the
 *      default (0) indicating protocol words are eight bit bytes.
 *      The spi_transfer.bits_per_word can override this for each transfer.
 * @irq: Negative, or the number passed to request_irq() to receive
 *      interrupts from this device.
 * @controller_state: Controller's runtime state
 * @controller_data: Board-specific definitions for controller, such as
 *      FIFO initialization parameters; from board_info.controller_data
 * @modalias: Name of the driver to use with this device, or an alias
 *      for that name.  This appears in the sysfs "modalias" attribute
 *      for driver coldplugging, and in uevents used for hotplugging
 * @cs_gpio: gpio number of the chipselect line (optional, -ENOENT when
 *      when not using a GPIO line)
 *
 * @statistics: statistics for the spi_device
 *
 * A @spi_device is used to interchange data between an SPI slave
 * (usually a discrete chip) and CPU memory.
 *
 * In @dev, the platform_data is used to hold information about this
 * device that's meaningful to the device's protocol driver, but not
 * to its controller.  One example might be an identifier for a chip
 * variant with slightly different functionality; another might be
 * information about how this particular board wires the chip's pins.
 */
struct spi_device {
        struct device           dev;
        struct spi_controller   *controller;
        struct spi_controller   *master;        /* compatibility layer */
        u32                     max_speed_hz;
        u8                      chip_select;
        u8                      bits_per_word;
        u16                     mode;
#define SPI_CPHA        0x01                    /* clock phase */
#define SPI_CPOL        0x02                    /* clock polarity */
#define SPI_MODE_0      (0|0)                   /* (original MicroWire) */
#define SPI_MODE_1      (0|SPI_CPHA)
#define SPI_MODE_2      (SPI_CPOL|0)
#define SPI_MODE_3      (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH     0x04                    /* chipselect active high? */
#define SPI_LSB_FIRST   0x08                    /* per-word bits-on-wire */
#define SPI_3WIRE       0x10                    /* SI/SO signals shared */
#define SPI_LOOP        0x20                    /* loopback mode */
#define SPI_NO_CS       0x40                    /* 1 dev/bus, no chipselect */
#define SPI_READY       0x80                    /* slave pulls low to pause */
#define SPI_TX_DUAL     0x100                   /* transmit with 2 wires */
#define SPI_TX_QUAD     0x200                   /* transmit with 4 wires */
#define SPI_RX_DUAL     0x400                   /* receive with 2 wires */
#define SPI_RX_QUAD     0x800                   /* receive with 4 wires */
        int                     irq;
        void                    *controller_state;
        void                    *controller_data;
        char                    modalias[SPI_NAME_SIZE];
        int                     cs_gpio;        /* chip select gpio */

        /* the statistics */
        struct spi_statistics   statistics;

        /*
         * likely need more hooks for more protocol options affecting how
         * the controller talks to each chip, like:
         *  - memory packing (12 bit samples into low bits, others zeroed)
         *  - priority
         *  - drop chipselect after each word
         *  - chipselect delays
         *  - ...
         */
};

spi 슬레이브 디바이스를 표현하는 구조체

  •  dev
    • 디바이스 구조체
  • *controller
    • spi 컨트롤러를 가리킨다.
  • *master
    • spi 컨트롤러를 가리킨다. (호환을 위해 사용한다)
  • max_speed_hz
    • 디바이스가 처리할 수 있는 최대 처리 가능한 클럭
  • chip_select
    • 이 슬레이브 디바이스를 선택하기 위해 사용해야 할 chip 셀렉트 번호
  • bits_per_word
    • 한 번에 전송할 수 있는 워드 처리 대역 비트
    • 보통 8 bits 또는 16bits를 사용하고, 32 bits를 지원하는 디바이스도 있다.
  • mode
    • spi 디바이스가 지원하는 기능들을 표현한다.
  • irq
    • spi 디바이스가 인터럽트를 사용하는 경우 지정된다.
  • controller_state
    • 컨트롤러의 런타임 상태
  • controller_data
    • 컨트롤러를 위한 보드별 설정이 담긴다.
  • modalias[]
    • 이 슬레이브 디바이스를 사용하기 위한 이름이 담긴다.
  • cs_gpio
    • chip 셀렉션을 위한 gpio 번호로 legacy 코드를 지원하기 위해 사용된다.
  • statistics
    • spi 디바이스 통계

 

spi_message 구조체

include/linux/spi/spi.h

/**
 * struct spi_message - one multi-segment SPI transaction
 * @transfers: list of transfer segments in this transaction
 * @spi: SPI device to which the transaction is queued
 * @is_dma_mapped: if true, the caller provided both dma and cpu virtual
 *      addresses for each transfer buffer
 * @complete: called to report transaction completions
 * @context: the argument to complete() when it's called
 * @frame_length: the total number of bytes in the message
 * @actual_length: the total number of bytes that were transferred in all
 *      successful segments
 * @status: zero for success, else negative errno
 * @queue: for use by whichever driver currently owns the message
 * @state: for use by whichever driver currently owns the message
 * @resources: for resource management when the spi message is processed
 *
 * A @spi_message is used to execute an atomic sequence of data transfers,
 * each represented by a struct spi_transfer.  The sequence is "atomic"
 * in the sense that no other spi_message may use that SPI bus until that
 * sequence completes.  On some systems, many such sequences can execute as
 * as single programmed DMA transfer.  On all systems, these messages are
 * queued, and might complete after transactions to other devices.  Messages
 * sent to a given spi_device are always executed in FIFO order.
 *
 * The code that submits an spi_message (and its spi_transfers)
 * to the lower layers is responsible for managing its memory.
 * Zero-initialize every field you don't set up explicitly, to
 * insulate against future API updates.  After you submit a message
 * and its transfers, ignore them until its completion callback.
 */
struct spi_message {
        struct list_head        transfers;

        struct spi_device       *spi;

        unsigned                is_dma_mapped:1;

        /* REVISIT:  we might want a flag affecting the behavior of the
         * last transfer ... allowing things like "read 16 bit length L"
         * immediately followed by "read L bytes".  Basically imposing
         * a specific message scheduling algorithm.
         *
         * Some controller drivers (message-at-a-time queue processing)
         * could provide that as their default scheduling algorithm.  But
         * others (with multi-message pipelines) could need a flag to
         * tell them about such special cases.
         */

        /* completion is reported through a callback */
        void                    (*complete)(void *context);
        void                    *context;
        unsigned                frame_length;
        unsigned                actual_length;
        int                     status;

        /* for optional use by whatever driver currently owns the
         * spi_message ...  between calls to spi_async and then later
         * complete(), that's the spi_controller controller driver.
         */
        struct list_head        queue;
        void                    *state;

        /* list of spi_res reources when the spi message is processed */
        struct list_head        resources;
};

spi 메시지를 표현한다.

  •  transfers
    • 트랜잭션을 구성하는 전송 리스트
  • *spi
    • 트랜잭션이 향할 spi 디바이스
  • is_dma_mapped
    • dma를 지원한다.
  • (*complete)
    • 트랜잭션이 완료되면 호출되는 후크 함수이다.
  • *context
    • (*complete) 호출될 때 사용되는 argument를 가리킨다.
  • frame_length
    • 메시지 전체 바이트 수
  • actual_length
    • 성공리에 SPI 전송된 전체 바이트 수
  • status
    • 0=성공, 음수=에러
  • queue
    • spi 컨트롤러의 큐에 등록될 때 사용하는 노드이다.
  • *state
    • 메시지 상태
  • resources
    • spi 메시지가 처리되었을 때 리소스 관리를 위해 사용한다.

 

/**
 * struct spi_transfer - a read/write buffer pair
 * @tx_buf: data to be written (dma-safe memory), or NULL
 * @rx_buf: data to be read (dma-safe memory), or NULL
 * @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
 * @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
 * @tx_nbits: number of bits used for writing. If 0 the default
 *      (SPI_NBITS_SINGLE) is used.
 * @rx_nbits: number of bits used for reading. If 0 the default
 *      (SPI_NBITS_SINGLE) is used.
 * @len: size of rx and tx buffers (in bytes)
 * @speed_hz: Select a speed other than the device default for this
 *      transfer. If 0 the default (from @spi_device) is used.
 * @bits_per_word: select a bits_per_word other than the device default
 *      for this transfer. If 0 the default (from @spi_device) is used.
 * @cs_change: affects chipselect after this transfer completes
 * @delay_usecs: microseconds to delay after this transfer before
 *      (optionally) changing the chipselect status, then starting
 *      the next transfer or completing this @spi_message.
 * @transfer_list: transfers are sequenced through @spi_message.transfers
 * @tx_sg: Scatterlist for transmit, currently not for client use
 * @rx_sg: Scatterlist for receive, currently not for client use
 *
 * SPI transfers always write the same number of bytes as they read.
 * Protocol drivers should always provide @rx_buf and/or @tx_buf.
 * In some cases, they may also want to provide DMA addresses for
 * the data being transferred; that may reduce overhead, when the
 * underlying driver uses dma.
 *
 * If the transmit buffer is null, zeroes will be shifted out
 * while filling @rx_buf.  If the receive buffer is null, the data
 * shifted in will be discarded.  Only "len" bytes shift out (or in).
 * It's an error to try to shift out a partial word.  (For example, by
 * shifting out three bytes with word size of sixteen or twenty bits;
 * the former uses two bytes per word, the latter uses four bytes.)
 *
 * In-memory data values are always in native CPU byte order, translated
 * from the wire byte order (big-endian except with SPI_LSB_FIRST).  So
 * for example when bits_per_word is sixteen, buffers are 2N bytes long
 * (@len = 2N) and hold N sixteen bit words in CPU byte order.
 *
 * When the word size of the SPI transfer is not a power-of-two multiple
 * of eight bits, those in-memory words include extra bits.  In-memory
 * words are always seen by protocol drivers as right-justified, so the
 * undefined (rx) or unused (tx) bits are always the most significant bits.
 *
 * All SPI transfers start with the relevant chipselect active.  Normally
 * it stays selected until after the last transfer in a message.  Drivers
 * can affect the chipselect signal using cs_change.
 *
 * (i) If the transfer isn't the last one in the message, this flag is
 * used to make the chipselect briefly go inactive in the middle of the
 * message.  Toggling chipselect in this way may be needed to terminate
 * a chip command, letting a single spi_message perform all of group of
 * chip transactions together.
 *
 * (ii) When the transfer is the last one in the message, the chip may
 * stay selected until the next transfer.  On multi-device SPI busses
 * with nothing blocking messages going to other devices, this is just
 * a performance hint; starting a message to another device deselects
 * this one.  But in other cases, this can be used to ensure correctness.
 * Some devices need protocol transactions to be built from a series of
 * spi_message submissions, where the content of one message is determined
 * by the results of previous messages and where the whole transaction
 * ends when the chipselect goes intactive.
 *
 * When SPI can transfer in 1x,2x or 4x. It can get this transfer information
 * from device through @tx_nbits and @rx_nbits. In Bi-direction, these
 * two should both be set. User can set transfer mode with SPI_NBITS_SINGLE(1x)
 * SPI_NBITS_DUAL(2x) and SPI_NBITS_QUAD(4x) to support these three transfer.
 *
 * The code that submits an spi_message (and its spi_transfers)
 * to the lower layers is responsible for managing its memory.
 * Zero-initialize every field you don't set up explicitly, to
 * insulate against future API updates.  After you submit a message
 * and its transfers, ignore them until its completion callback.
 */
struct spi_transfer {
        /* it's ok if tx_buf == rx_buf (right?)
         * for MicroWire, one buffer must be null
         * buffers must work with dma_*map_single() calls, unless
         *   spi_message.is_dma_mapped reports a pre-existing mapping
         */
        const void      *tx_buf;
        void            *rx_buf;
        unsigned        len;

        dma_addr_t      tx_dma;
        dma_addr_t      rx_dma;
        struct sg_table tx_sg;
        struct sg_table rx_sg;

        unsigned        cs_change:1;
        unsigned        tx_nbits:3;
        unsigned        rx_nbits:3;
#define SPI_NBITS_SINGLE        0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL          0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD          0x04 /* 4bits transfer */
        u8              bits_per_word;
        u16             delay_usecs;
        u32             speed_hz;

        struct list_head transfer_list;
};
  • tx_buf
    • 전송할 데이터를 가리키는 버퍼로 dma-safe되어야 한다.
    • 이 값이 null인 경우 rx 비트를 수신시 마다 0이 shift 출력된다.
  • rx_buf
    • 수신한 데이터를 저장할 버퍼로 dma-safe되어야 한다.
    • null 가능
  • len
    • tx 및 rx 버퍼 크기
  • tx_dma
    • tx dma 사용 시 tx_buf의 dma 주소
  • rx_dma
    • rx dma 사용 시 rx_buf의 dma 주소
  • tx_sg
    • tx용 Scatterlist
  • rx_sg
    • rx용 Scatterlist
  • cs_change
    • 전송 완료 후 chip select 필요 시
  • tx_nbits
    • 0인 경우 SPI_NBITS_SINGLE과 동일
    •  SPI_NBITS_SINGLE(1)
      • tx 시 한 클럭에 1비트 전송
    • SPI_NBITS_DUAL(2)
      • tx 시 한 클럭에 2비트 전송
    • SPI_NBITS_QUAd(4)
      • tx 시 한 클럭에 4비트 전송
  • rx_nbits
    • tx_nbits와 동일
  • bits_per_word
    • 워드 전송 시 사용할 비트 수
    • 0=디폴트 사용
    • 대부분의 경우 8비트를 사용하지만,
    • 터치 스크린 컨트롤러는 16비트를 사용하는 경우도 있고,
    • TI사의 A/D 또는 D/A 컨버터는 12비트를 사용하는 경우도 있다.
  • delay_usecs
    • 전송 후 필요한 딜레이
  • speed_hz
    • 사용할 스피드
    • 0=디폴트 사용
  • transfer_list
    • spi_message.transfers를 통해 순차 처리할 전송들이다.

 

참고

 

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다