Skip to content

Commit a60f93d

Browse files
decsnyjhedberg
authored andcommitted
include: drivers: spi.h: Get CS delay parameters from DT
The CS delay parameter did not make a distinction between the setup and hold time of the CS, and also did not specify very fine control which can be done usually by a native controller CS. So use the new nanosecond DT properties to get the delay values and make distinction. Add deprecation warning if consumer supplies the delay parameter and make it still work the old way in that case for backward compatibility following API lifecycle process. Update driver API version to 1.1.0 due to this change Signed-off-by: Declan Snyder <[email protected]>
1 parent 186ce62 commit a60f93d

File tree

4 files changed

+103
-50
lines changed

4 files changed

+103
-50
lines changed

doc/releases/migration-guide-4.3.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ Phy
8181
clock-reference. The selection directly depends on the value on OTGHSSEL (OTG_HS PHY kernel
8282
clock source selection) located in the RCC_CCIPR2 register.
8383

84+
SPI
85+
===
86+
87+
* The macros :c:macro:`SPI_CS_CONTROL_INIT` :c:macro:`SPI_CS_CONTROL_INIT_INST`,
88+
:c:macro:`SPI_CONFIG_DT`, :c:macro:`SPI_CONFIG_DT_INST`, :c:macro:`SPI_DT_SPEC_GET`,
89+
and :c:macro:`SPI_DT_SPEC_INST_GET` have been changed so that they do not need to be
90+
provided a delay parameter anymore. This is because the timing parameters of a SPI peripheral
91+
chip select should now be specified in DT with the
92+
``spi-cs-setup-delay-ns`` and ``spi-cs-hold-delay-ns`` properties.
93+
(:github:`87427`).
94+
8495
Sensors
8596
=======
8697

doc/releases/release-notes-4.3.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ Deprecated APIs and options
6262
===========================
6363

6464
* :dtcompatible:`maxim,ds3231` is deprecated in favor of :dtcompatible:`maxim,ds3231-rtc`.
65+
* Providing a third agument to :c:macro:`SPI_CONFIG_DT`, :c:macro:`SPI_CONFIG_DT_INST`,
66+
:c:macro:`SPI_DT_SPEC_GET`, :c:macro:`SPI_DT_SPEC_INST_GET` is deprecated. Providing a
67+
second argument to :c:macro:`SPI_CS_CONTROL_INIT` is deprecated. Use new DT properties
68+
``spi-cs-setup-delay-ns`` and ``spi-cs-hold-delay-ns`` to specify delay instead.
6569

6670
* :c:enum:`bt_hci_bus` was deprecated as it was not used. :c:macro:`BT_DT_HCI_BUS_GET` should be
6771
used instead.

include/zephyr/drivers/mipi_dbi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ extern "C" {
6767
DT_REG_ADDR_RAW(node_id), \
6868
{}), \
6969
.delay = (delay_), \
70+
.cs_is_gpio = true, \
7071
}, \
7172
}
7273

include/zephyr/drivers/spi.h

Lines changed: 87 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
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
*/
244244
struct 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
*/
864902
static 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

Comments
 (0)