drivers: spi: add helpers for initializing from DT

Add helper macros for initializing a struct spi_sconfig for a SPI
device which is defined in the devicetree. They are available from C
only due to C++ compatibility issues.

For some fields, like 'frequency', we just get the value from the
standard devicetree property. For others, like the spi_cs_control
structure's 'gpio_dev', we rely on the new DEVICE_DT_GET() macro.

This patch does not change anything for controlling SPI devices that
aren't set up in devicetree. It is entirely a convenience for driver
and application code that relies on DT.

Signed-off-by: Martí Bolívar <marti.bolivar@nordicsemi.no>
This commit is contained in:
Martí Bolívar 2020-11-05 12:01:25 -08:00 committed by Anas Nashif
parent 6008e7ee24
commit d6cfa10b8f

View File

@ -142,6 +142,79 @@ struct spi_cs_control {
gpio_dt_flags_t gpio_dt_flags;
};
#ifndef __cplusplus
/**
* @brief Initialize and get a pointer to a @p spi_cs_control from a
* devicetree node identifier
*
* This helper is useful for initializing a device on a SPI bus. It
* initializes a struct spi_cs_control and returns a pointer to it.
* Here, @p node_id is a node identifier for a SPI device, not a SPI
* controller.
*
* Example devicetree fragment:
*
* spi@... {
* cs-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
* spidev: spi-device@0 { ... };
* };
*
* Assume that @p gpio0 follows the standard convention for specifying
* GPIOs, i.e. it has the following in its binding:
*
* gpio-cells:
* - pin
* - flags
*
* Example usage:
*
* struct spi_cs_control *ctrl =
* SPI_CS_CONTROL_PTR_DT(DT_NODELABEL(spidev), 2);
*
* This example is equivalent to:
*
* struct spi_cs_control *ctrl =
* &(struct spi_cs_control) {
* .gpio_dev = DEVICE_DT_GET(DT_NODELABEL(gpio0)),
* .delay = 2,
* .gpio_pin = 1,
* .gpio_dt_flags = GPIO_ACTIVE_LOW
* };
*
* This macro is not available in C++.
*
* @param node_id Devicetree node identifier for a device on a SPI bus
* @param delay_ The @p delay field to set in the @p spi_cs_control
* @return a pointer to the @p spi_cs_control structure
*/
#define SPI_CS_CONTROL_PTR_DT(node_id, delay_) \
(&(struct spi_cs_control) { \
.gpio_dev = DEVICE_DT_GET( \
DT_SPI_DEV_CS_GPIOS_CTLR(node_id)), \
.delay = (delay_), \
.gpio_pin = DT_SPI_DEV_CS_GPIOS_PIN(node_id), \
.gpio_dt_flags = DT_SPI_DEV_CS_GPIOS_FLAGS(node_id), \
})
/**
* @brief Get a pointer to a @p spi_cs_control from a devicetree node
*
* This is equivalent to
* <tt>SPI_CS_CONTROL_PTR_DT(DT_DRV_INST(inst), delay)</tt>.
*
* Therefore, @p DT_DRV_COMPAT must already be defined before using
* this macro.
*
* This macro is not available in C++.
*
* @param inst Devicetree node instance number
* @param delay_ The @p delay field to set in the @p spi_cs_control
* @return a pointer to the @p spi_cs_control structure
*/
#define SPI_CS_CONTROL_PTR_DT_INST(inst, delay_) \
SPI_CS_CONTROL_PTR_DT(DT_DRV_INST(inst), delay_)
#endif
/**
* @brief SPI controller configuration structure
*
@ -176,6 +249,54 @@ struct spi_config {
const struct spi_cs_control *cs;
};
#ifndef __cplusplus
/**
* @brief Structure initializer for spi_config from devicetree
*
* This helper macro expands to a static initializer for a <tt>struct
* spi_config</tt> by reading the relevant @p frequency, @p slave, and
* @p cs data from the devicetree.
*
* Important: the @p cs field is initialized using
* SPI_CS_CONTROL_PTR_DT(). The @p gpio_dev value pointed to by this
* structure must be checked using device_is_ready() before use.
*
* This macro is not available in C++.
*
* @param node_id Devicetree node identifier for the SPI device whose
* struct spi_config to create an initializer for
* @param operation_ the desired @p operation field in the struct spi_config
* @param delay_ the desired @p delay field in the struct spi_config's
* spi_cs_control, if there is one
*/
#define SPI_CONFIG_DT(node_id, operation_, delay_) \
{ \
.frequency = DT_PROP(node_id, spi_max_frequency), \
.operation = (operation_), \
.slave = DT_REG_ADDR(node_id), \
.cs = COND_CODE_1( \
DT_SPI_DEV_HAS_CS_GPIOS(node_id), \
(SPI_CS_CONTROL_PTR_DT(node_id, delay_)), \
(NULL)), \
}
/**
* @brief Structure initializer for spi_config from devicetree instance
*
* This is equivalent to
* <tt>SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_)</tt>.
*
* This macro is not available in C++.
*
* @param inst Devicetree instance number
* @param operation_ the desired @p operation field in the struct spi_config
* @param delay_ the desired @p delay field in the struct spi_config's
* spi_cs_control, if there is one
*/
#define SPI_CONFIG_DT_INST(inst, operation_, delay_) \
SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_)
#endif
/**
* @brief SPI buffer structure
*