1818 * controllers.
1919 * @defgroup spi_interface SPI
2020 * @since 1.0
21- * @version 1.0 .0
21+ * @version 1.1 .0
2222 * @ingroup io_interfaces
2323 * @{
2424 */
@@ -242,19 +242,38 @@ extern "C" {
242242 *
243243 */
244244struct spi_cs_control {
245- /**
246- * GPIO devicetree specification of CS GPIO.
247- * The device pointer can be set to NULL to fully inhibit CS control if
248- * necessary. The GPIO flags GPIO_ACTIVE_LOW/GPIO_ACTIVE_HIGH should be
249- * equivalent to SPI_CS_ACTIVE_HIGH/SPI_CS_ACTIVE_LOW options in struct
250- * spi_config.
251- */
252- struct gpio_dt_spec gpio ;
253- /**
254- * Delay in microseconds to wait before starting the
255- * transmission and before releasing the CS line.
256- */
257- uint32_t delay ;
245+ union {
246+ struct {
247+ /**
248+ * GPIO devicetree specification of CS GPIO.
249+ * The device pointer can be set to NULL to fully inhibit CS control if
250+ * necessary. The GPIO flags GPIO_ACTIVE_LOW/GPIO_ACTIVE_HIGH should be
251+ * equivalent to SPI_CS_ACTIVE_HIGH/SPI_CS_ACTIVE_LOW options in struct
252+ * spi_config.
253+ */
254+ struct gpio_dt_spec gpio ;
255+ /**
256+ * Delay in microseconds to wait before starting the
257+ * transmission and before releasing the CS line.
258+ */
259+ uint32_t delay ;
260+ };
261+ struct {
262+ /**
263+ * CS enable lead time, i.e. how long should the CS be asserted
264+ * before the first clock. Specified in nanoseconds.
265+ */
266+ uint32_t setup_ns ;
267+ /**
268+ * CS enable lag time, i.e. how long should the CS be asserted
269+ * after the last clock, before the CS de-asserts.
270+ * Specified in nanoseconds.
271+ */
272+ uint32_t hold_ns ;
273+ };
274+ };
275+ /* To keep track of which form of this struct is valid */
276+ bool cs_is_gpio ;
258277};
259278
260279/**
@@ -310,6 +329,26 @@ struct spi_cs_control {
310329#define SPI_CS_GPIOS_DT_SPEC_INST_GET (inst ) \
311330 SPI_CS_GPIOS_DT_SPEC_GET(DT_DRV_INST(inst))
312331
332+ /** @cond INTERNAL_HIDDEN */
333+ #define SPI_CS_CONTROL_MAX_DELAY (node_id ) \
334+ MAX(DT_PROP_OR(node_id, spi_cs_setup_delay_ns, 0), \
335+ DT_PROP_OR(node_id, spi_cs_hold_delay_ns, 0))
336+
337+
338+ #define SPI_CS_CONTROL_INIT_GPIO (node_id , ...) \
339+ .gpio = SPI_CS_GPIOS_DT_SPEC_GET(node_id), \
340+ .delay = COND_CODE_1(IS_EMPTY(__VA_ARGS__), \
341+ (DIV_ROUND_UP(SPI_CS_CONTROL_MAX_DELAY(node_id), 1000)), \
342+ (__VA_ARGS__))
343+
344+ #define SPI_CS_CONTROL_INIT_NATIVE (node_id ) \
345+ .setup_ns = DT_PROP_OR(node_id, spi_cs_setup_delay_ns, 0), \
346+ .hold_ns = DT_PROP_OR(node_id, spi_cs_hold_delay_ns, 0),
347+
348+ #define SPI_DEPRECATE_DELAY_WARN \
349+ __WARN("Delay parameter in SPI DT macros is deprecated, use DT prop instead")
350+ /** @endcond */
351+
313352/**
314353 * @brief Initialize and get a pointer to a @p spi_cs_control from a
315354 * devicetree node identifier
@@ -332,27 +371,34 @@ struct spi_cs_control {
332371 *
333372 * @code{.c}
334373 * struct spi_cs_control ctrl =
335- * SPI_CS_CONTROL_INIT(DT_NODELABEL(spidev), 2 );
374+ * SPI_CS_CONTROL_INIT(DT_NODELABEL(spidev));
336375 * @endcode
337376 *
338- * This example is equivalent to:
377+ * This example is roughly equivalent to:
339378 *
340379 * @code{.c}
341380 * struct spi_cs_control ctrl = {
342381 * .gpio = SPI_CS_GPIOS_DT_SPEC_GET(DT_NODELABEL(spidev)),
343- * .delay = 2,
382+ * .delay = DT_PROP(node_id, cs_delay_ns) / 1000,
383+ * .cs_is_gpio = true,
344384 * };
345385 * @endcode
346386 *
387+ * For non-gpio CS, the idea is similar but the lead and lag fields of the cs struct
388+ * will be populated instead.
389+ *
347390 * @param node_id Devicetree node identifier for a device on a SPI bus
348- * @param delay_ The @p delay field to set in the @p spi_cs_control
391+ *
349392 * @return a pointer to the @p spi_cs_control structure
350393 */
351- #define SPI_CS_CONTROL_INIT (node_id , delay_ ) \
352- { \
353- .gpio = SPI_CS_GPIOS_DT_SPEC_GET(node_id), \
354- .delay = (delay_), \
355- }
394+ #define SPI_CS_CONTROL_INIT (node_id , ...) \
395+ { \
396+ COND_CODE_0(IS_EMPTY(__VA_ARGS__), (SPI_DEPRECATE_DELAY_WARN), ()) \
397+ .cs_is_gpio = DT_SPI_DEV_HAS_CS_GPIOS(node_id), \
398+ COND_CODE_1(DT_SPI_DEV_HAS_CS_GPIOS(node_id), \
399+ (SPI_CS_CONTROL_INIT_GPIO(node_id, __VA_ARGS__)), \
400+ (SPI_CS_CONTROL_INIT_NATIVE(node_id))) \
401+ }
356402
357403/**
358404 * @brief Get a pointer to a @p spi_cs_control from a devicetree node
@@ -364,11 +410,11 @@ struct spi_cs_control {
364410 * this macro.
365411 *
366412 * @param inst Devicetree node instance number
367- * @param delay_ The @p delay field to set in the @p spi_cs_control
413+ *
368414 * @return a pointer to the @p spi_cs_control structure
369415 */
370- #define SPI_CS_CONTROL_INIT_INST (inst , delay_ ) \
371- SPI_CS_CONTROL_INIT(DT_DRV_INST(inst), delay_ )
416+ #define SPI_CS_CONTROL_INIT_INST (inst ) \
417+ SPI_CS_CONTROL_INIT(DT_DRV_INST(inst))
372418
373419/** @} */
374420
@@ -432,10 +478,8 @@ struct spi_config {
432478 * @param node_id Devicetree node identifier for the SPI device whose
433479 * struct spi_config to create an initializer for
434480 * @param operation_ the desired @p operation field in the struct spi_config
435- * @param delay_ the desired @p delay field in the struct spi_config's
436- * spi_cs_control, if there is one
437481 */
438- #define SPI_CONFIG_DT (node_id , operation_ , delay_ ) \
482+ #define SPI_CONFIG_DT (node_id , operation_ , ...) \
439483 { \
440484 .frequency = DT_PROP(node_id, spi_max_frequency), \
441485 .operation = (operation_) | \
@@ -445,22 +489,20 @@ struct spi_config {
445489 COND_CODE_1(DT_PROP(node_id, spi_cpha), SPI_MODE_CPHA, (0)) | \
446490 COND_CODE_1(DT_PROP(node_id, spi_hold_cs), SPI_HOLD_ON_CS, (0)), \
447491 .slave = DT_REG_ADDR(node_id), \
448- .cs = SPI_CS_CONTROL_INIT(node_id, delay_), \
492+ .cs = SPI_CS_CONTROL_INIT(node_id, __VA_ARGS__), \
449493 }
450494
451495/**
452496 * @brief Structure initializer for spi_config from devicetree instance
453497 *
454498 * This is equivalent to
455- * <tt>SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_ )</tt>.
499+ * <tt>SPI_CONFIG_DT(DT_DRV_INST(inst), operation_)</tt>.
456500 *
457501 * @param inst Devicetree instance number
458502 * @param operation_ the desired @p operation field in the struct spi_config
459- * @param delay_ the desired @p delay field in the struct spi_config's
460- * spi_cs_control, if there is one
461503 */
462- #define SPI_CONFIG_DT_INST (inst , operation_ , delay_ ) \
463- SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, delay_ )
504+ #define SPI_CONFIG_DT_INST (inst , operation_ , ...) \
505+ SPI_CONFIG_DT(DT_DRV_INST(inst), operation_, __VA_ARGS__ )
464506
465507/**
466508 * @brief Complete SPI DT information
@@ -486,28 +528,24 @@ struct spi_dt_spec {
486528 * @param node_id Devicetree node identifier for the SPI device whose
487529 * struct spi_dt_spec to create an initializer for
488530 * @param operation_ the desired @p operation field in the struct spi_config
489- * @param delay_ the desired @p delay field in the struct spi_config's
490- * spi_cs_control, if there is one
491531 */
492- #define SPI_DT_SPEC_GET (node_id , operation_ , delay_ ) \
493- { \
494- .bus = DEVICE_DT_GET(DT_BUS(node_id)), \
495- .config = SPI_CONFIG_DT(node_id, operation_, delay_) \
532+ #define SPI_DT_SPEC_GET (node_id , operation_ , ... ) \
533+ { \
534+ .bus = DEVICE_DT_GET(DT_BUS(node_id)), \
535+ .config = SPI_CONFIG_DT(node_id, operation_, __VA_ARGS__), \
496536 }
497537
498538/**
499539 * @brief Structure initializer for spi_dt_spec from devicetree instance
500540 *
501541 * This is equivalent to
502- * <tt>SPI_DT_SPEC_GET(DT_DRV_INST(inst), operation_, delay_ )</tt>.
542+ * <tt>SPI_DT_SPEC_GET(DT_DRV_INST(inst), operation_)</tt>.
503543 *
504544 * @param inst Devicetree instance number
505545 * @param operation_ the desired @p operation field in the struct spi_config
506- * @param delay_ the desired @p delay field in the struct spi_config's
507- * spi_cs_control, if there is one
508546 */
509- #define SPI_DT_SPEC_INST_GET (inst , operation_ , delay_ ) \
510- SPI_DT_SPEC_GET(DT_DRV_INST(inst), operation_, delay_ )
547+ #define SPI_DT_SPEC_INST_GET (inst , operation_ , ... ) \
548+ SPI_DT_SPEC_GET(DT_DRV_INST(inst), operation_, __VA_ARGS__ )
511549
512550/**
513551 * @brief Value that will never compare true with any valid overrun character
@@ -863,7 +901,7 @@ __subsystem struct spi_driver_api {
863901 */
864902static inline bool spi_cs_is_gpio (const struct spi_config * config )
865903{
866- return config -> cs .gpio . port != NULL ;
904+ return config -> cs .cs_is_gpio ;
867905}
868906
869907/**
@@ -1291,11 +1329,10 @@ extern const struct rtio_iodev_api spi_iodev_api;
12911329 * @param name Symbolic name to use for defining the iodev
12921330 * @param node_id Devicetree node identifier
12931331 * @param operation_ SPI operational mode
1294- * @param delay_ Chip select delay in microseconds
12951332 */
1296- #define SPI_DT_IODEV_DEFINE (name , node_id , operation_ , delay_ ) \
1333+ #define SPI_DT_IODEV_DEFINE (name , node_id , operation_ ) \
12971334 const struct spi_dt_spec _spi_dt_spec_##name = \
1298- SPI_DT_SPEC_GET(node_id, operation_, delay_); \
1335+ SPI_DT_SPEC_GET(node_id, operation_); \
12991336 RTIO_IODEV_DEFINE(name, &spi_iodev_api, (void *)&_spi_dt_spec_##name)
13001337
13011338/**
0 commit comments