Skip to content

Commit 07e6bf3

Browse files
committed
drivers: spi: spi_infineon_pdl: add device_deinit hook
Add an ifx_cat1_spi_deinit() implementation and register it via SPI_DEVICE_DT_INST_DEINIT_DEFINE so device_deinit(dev) succeeds on the Infineon PSE84 / CAT1 SCB SPI driver. Without this hook the upstream tests/drivers/spi/spi_loopback test_spi_deinit case returns -ENOTSUP and skips. The deinit: - returns -EBUSY while a transfer is still in flight, to avoid tearing down the SCB block in the middle of a transaction. The busy check is consolidated into ifx_cat1_spi_is_busy(), which reports busy while the SPI context still holds outstanding tx/rx buffers (spi_context_tx_on()/spi_context_rx_on()), while Cy_SCB_SPI_IsBusBusy() is active, or while an async transfer is still pending. The large-chunk DMA path drives the transfer purely through the DMA channels without setting data->pending, and Cy_SCB_SPI_IsBusBusy() can read idle between FIFO-paced DMA bursts, so the SPI context buffer state is used as the authoritative in-flight indicator that covers both the FIFO and DMA paths for synchronous and asynchronous transfers, - unregisters the deep-sleep SysPm callback (only when CONFIG_PM=y), - disables the SCB IRQ, - disables and deinits the SCB SPI block via PDL (Cy_SCB_SPI_Disable / Cy_SCB_SPI_DeInit), - stops the rx and tx DMA channels, mirroring ifx_cat1_spi_release() (only when CONFIG_SPI_INFINEON_DMA=y). The deinit function and its reference in the device definition are guarded by CONFIG_DEVICE_DEINIT_SUPPORT, matching the pattern used by drivers/spi/spi_nrfx_spim.c and drivers/spi/spi_bflb.c. Also drop the unused dma_configured field from struct ifx_cat1_spi_data: it was never read and never set to true anywhere in the driver. Verified on kit_pse84_eval/pse846gps2dbzc4a/m55: - [spi_loopback.test_spi_deinit] PASS - [spi_loopback.test_spi_deinit_busy] PASS (device_deinit() returns -EBUSY while an 8192-byte DMA transfer is in flight, then succeeds and re-inits once the bus is idle) Assisted-by: GitHub Copilot (Claude) Signed-off-by: Bill Waters <bill.waters@infineon.com>
1 parent be39a96 commit 07e6bf3

1 file changed

Lines changed: 70 additions & 14 deletions

File tree

drivers/spi/spi_infineon_pdl.c

Lines changed: 70 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ struct ifx_cat1_spi_data {
9999
struct spi_context ctx;
100100
uint8_t dfs_value;
101101
size_t chunk_len;
102-
bool dma_configured;
103102

104103
#ifdef CONFIG_SPI_INFINEON_DMA
105104
struct ifx_cat1_dma_stream dma_rx;
@@ -593,8 +592,12 @@ static int ifx_cat1_spi_release(const struct device *dev, const struct spi_confi
593592
#ifdef CONFIG_SPI_INFINEON_DMA
594593
struct ifx_cat1_spi_data *const data = dev->data;
595594

596-
dma_stop(data->dma_tx.dev_dma, data->dma_tx.dma_channel);
597-
dma_stop(data->dma_rx.dev_dma, data->dma_rx.dma_channel);
595+
if (data->dma_tx.dev_dma != NULL) {
596+
dma_stop(data->dma_tx.dev_dma, data->dma_tx.dma_channel);
597+
}
598+
if (data->dma_rx.dev_dma != NULL) {
599+
dma_stop(data->dma_rx.dev_dma, data->dma_rx.dma_channel);
600+
}
598601
#endif
599602

600603
return 0;
@@ -608,6 +611,64 @@ static DEVICE_API(spi, ifx_cat1_spi_api) = {
608611
.release = ifx_cat1_spi_release,
609612
};
610613

614+
bool ifx_cat1_spi_is_busy(const struct device *dev)
615+
{
616+
struct ifx_cat1_spi_data *const data = dev->data;
617+
const struct ifx_cat1_spi_config *const config = dev->config;
618+
struct spi_context *ctx = &data->ctx;
619+
620+
/* On the large-chunk DMA path the transfer runs entirely through the DMA
621+
* channels without setting data->pending, and Cy_SCB_SPI_IsBusBusy() can
622+
* briefly read idle between FIFO-paced DMA bursts. The SPI context still
623+
* holds the outstanding buffers until the transfer completes, so use it as
624+
* the authoritative in-flight indicator that covers every transfer path.
625+
*/
626+
if (spi_context_tx_on(ctx) || spi_context_rx_on(ctx)) {
627+
return true;
628+
}
629+
630+
return Cy_SCB_SPI_IsBusBusy(config->reg_addr) || (data->pending != IFX_SPI_PENDING_NONE);
631+
}
632+
633+
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
634+
static int ifx_cat1_spi_deinit(const struct device *dev)
635+
{
636+
const struct ifx_cat1_spi_config *const config = dev->config;
637+
struct ifx_cat1_spi_data *const data = dev->data;
638+
639+
if (ifx_cat1_spi_is_busy(dev)) {
640+
return -EBUSY;
641+
}
642+
643+
#ifdef CONFIG_PM
644+
Cy_SysPm_UnregisterCallback(&data->spi_deep_sleep);
645+
#endif
646+
irq_disable(config->irq_num);
647+
Cy_SCB_SPI_Disable(config->reg_addr, NULL);
648+
Cy_SCB_SPI_DeInit(config->reg_addr);
649+
650+
#ifdef CONFIG_SPI_INFINEON_DMA
651+
/* An instance built with DMA support may still have no dmas assigned in
652+
* devicetree, in which case dev_dma is NULL. Skip those channels.
653+
*/
654+
if (data->dma_tx.dev_dma != NULL) {
655+
dma_stop(data->dma_tx.dev_dma, data->dma_tx.dma_channel);
656+
}
657+
if (data->dma_rx.dev_dma != NULL) {
658+
dma_stop(data->dma_rx.dev_dma, data->dma_rx.dma_channel);
659+
}
660+
#endif
661+
662+
/* HW reset above: clear cached config so the next transceive after
663+
* device_init() takes the full reconfigure path instead of being
664+
* short-circuited by spi_context_configured().
665+
*/
666+
data->ctx.config = NULL;
667+
668+
return 0;
669+
}
670+
#endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
671+
611672
static int ifx_cat1_spi_init(const struct device *dev)
612673
{
613674
struct ifx_cat1_spi_data *const data = dev->data;
@@ -815,9 +876,12 @@ static int ifx_cat1_spi_init(const struct device *dev)
815876
CY_SYSPM_SKIP_BEFORE_TRANSITION, \
816877
&spi_cat1_config_##n.spi_deep_sleep_param, NULL, NULL, 1}}; \
817878
\
818-
DEVICE_DT_INST_DEFINE(n, &ifx_cat1_spi_init, NULL, &spi_cat1_data_##n, \
819-
&spi_cat1_config_##n, POST_KERNEL, \
820-
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ifx_cat1_spi_api);
879+
SPI_DEVICE_DT_INST_DEINIT_DEFINE(n, &ifx_cat1_spi_init, \
880+
COND_CODE_1(CONFIG_DEVICE_DEINIT_SUPPORT, \
881+
(&ifx_cat1_spi_deinit), (NULL)), \
882+
NULL, &spi_cat1_data_##n, &spi_cat1_config_##n, \
883+
POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
884+
&ifx_cat1_spi_api);
821885

822886
DT_INST_FOREACH_STATUS_OKAY(IFX_CAT1_SPI_INIT)
823887

@@ -901,14 +965,6 @@ cy_rslt_t ifx_cat1_spi_transfer_async(const struct device *dev, const uint8_t *t
901965
return spi_status == CY_SCB_SPI_SUCCESS ? CY_RSLT_SUCCESS : IFX_SPI_RSLT_TRANSFER_ERROR;
902966
}
903967

904-
bool ifx_cat1_spi_is_busy(const struct device *dev)
905-
{
906-
struct ifx_cat1_spi_data *const data = dev->data;
907-
const struct ifx_cat1_spi_config *const config = dev->config;
908-
909-
return Cy_SCB_SPI_IsBusBusy(config->reg_addr) || (data->pending != IFX_SPI_PENDING_NONE);
910-
}
911-
912968
cy_rslt_t ifx_cat1_spi_abort_async(const struct device *dev)
913969
{
914970
struct ifx_cat1_spi_data *const data = dev->data;

0 commit comments

Comments
 (0)