diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi b/boards/arm/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi index f3cb57d7395..7a92cc56f9b 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro-pinctrl.dtsi @@ -31,4 +31,28 @@ bias-pull-up; }; }; + + spi_controller: spi_controller { + group1 { + pinmux = < SMARTBOND_PINMUX(SPI_CLK, 0, 21) >, + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; + + spi2_controller: spi2_controller { + group1 { + pinmux = < SMARTBOND_PINMUX(SPI2_CLK, 1, 3) >, + ; + output-enable; + }; + group2 { + pinmux = ; + input-enable; + }; + }; }; diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.dts b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.dts index 18a561624c7..fc84a64195f 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.dts +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.dts @@ -149,3 +149,15 @@ pinctrl-0 = <&i2c2_default>; pinctrl-names = "default"; }; + +&spi { + status = "okay"; + pinctrl-0 = <&spi_controller>; + pinctrl-names = "default"; +}; + +&spi2 { + status = "okay"; + pinctrl-0 = <&spi2_controller>; + pinctrl-names = "default"; +}; diff --git a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml index 2c02084deb7..8cb5c85eab0 100644 --- a/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml +++ b/boards/arm/da1469x_dk_pro/da1469x_dk_pro.yaml @@ -12,3 +12,4 @@ supported: - gpio - watchdog - i2c + - spi diff --git a/boards/arm/da1469x_dk_pro/doc/index.rst b/boards/arm/da1469x_dk_pro/doc/index.rst index a29bab16df9..f45c1f333fe 100644 --- a/boards/arm/da1469x_dk_pro/doc/index.rst +++ b/boards/arm/da1469x_dk_pro/doc/index.rst @@ -45,6 +45,8 @@ hardware features: +-----------+------------+----------------------+ | UART | on-chip | serial | +-----------+------------+----------------------+ +| SPI | on-chip | spi | ++-----------+------------+----------------------+ Other hardware features, including the Configurable MAC (CMAC) controller, are currently not supported by the port. diff --git a/drivers/pinctrl/pinctrl_smartbond.c b/drivers/pinctrl/pinctrl_smartbond.c index 180b46fd69f..dc314af13c2 100644 --- a/drivers/pinctrl/pinctrl_smartbond.c +++ b/drivers/pinctrl/pinctrl_smartbond.c @@ -38,6 +38,8 @@ static void pinctrl_configure_pin(const pinctrl_soc_pin_t *pin) reg_val |= 0x01 << GPIO_P0_00_MODE_REG_PUPD_Pos; } else if (pin->bias_pull_down) { reg_val |= 0x02 << GPIO_P0_00_MODE_REG_PUPD_Pos; + } else if (pin->output_enable) { + reg_val |= 0x03 << GPIO_P0_00_MODE_REG_PUPD_Pos; } *reg = reg_val; diff --git a/drivers/spi/CMakeLists.txt b/drivers/spi/CMakeLists.txt index b889c0213d5..ff67d15547e 100644 --- a/drivers/spi/CMakeLists.txt +++ b/drivers/spi/CMakeLists.txt @@ -35,6 +35,7 @@ zephyr_library_sources_ifdef(CONFIG_SPI_ANDES_ATCSPI200 spi_andes_atcspi200.c) zephyr_library_sources_ifdef(CONFIG_NXP_S32_SPI spi_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_SPI_XMC4XXX spi_xmc4xxx.c) zephyr_library_sources_ifdef(CONFIG_SPI_PW spi_pw.c) +zephyr_library_sources_ifdef(CONFIG_SPI_SMARTBOND spi_smartbond.c) zephyr_library_sources_ifdef(CONFIG_SPI_RTIO spi_rtio.c) zephyr_library_sources_ifdef(CONFIG_SPI_ASYNC spi_signal.c) diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index aea11e27c55..749b286a991 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig @@ -119,4 +119,6 @@ source "drivers/spi/Kconfig.xmc4xxx" source "drivers/spi/Kconfig.pw" +source "drivers/spi/Kconfig.smartbond" + endif # SPI diff --git a/drivers/spi/Kconfig.smartbond b/drivers/spi/Kconfig.smartbond new file mode 100644 index 00000000000..9c003eb915d --- /dev/null +++ b/drivers/spi/Kconfig.smartbond @@ -0,0 +1,9 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +config SPI_SMARTBOND + bool "Renesas SmartBond(tm) SPI driver" + default y + depends on DT_HAS_RENESAS_SMARTBOND_SPI_ENABLED + help + Enables SPI driver for Renesas SmartBond(tm) DA1469x series MCU. diff --git a/drivers/spi/spi_smartbond.c b/drivers/spi/spi_smartbond.c new file mode 100644 index 00000000000..7f44c0f29aa --- /dev/null +++ b/drivers/spi/spi_smartbond.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2022 Renesas Electronics Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT renesas_smartbond_spi + +#define LOG_LEVEL CONFIG_SPI_LOG_LEVEL +#include +LOG_MODULE_REGISTER(spi_smartbond); + +#include "spi_context.h" + +#include +#include +#include + +#include + +#define DIVN_CLK 32000000 /* divN_clk 32MHz */ +#define SCLK_FREQ_2MHZ (DIVN_CLK / 14) /* 2.285714MHz*/ +#define SCLK_FREQ_4MHZ (DIVN_CLK / 8) /* 4MHz */ +#define SCLK_FREQ_8MHZ (DIVN_CLK / 4) /* 8MHz */ +#define SCLK_FREQ_16MHZ (DIVN_CLK / 2) /* 16MHz */ + +struct spi_smartbond_cfg { + SPI_Type *regs; + int periph_clock_config; + const struct pinctrl_dev_config *pcfg; +}; + +struct spi_smartbond_data { + struct spi_context ctx; + uint8_t dfs; +}; + +static inline void spi_smartbond_enable(const struct spi_smartbond_cfg *cfg, bool enable) +{ + if (enable) { + cfg->regs->SPI_CTRL_REG |= SPI_SPI_CTRL_REG_SPI_ON_Msk; + cfg->regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_RST_Msk; + } else { + cfg->regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_ON_Msk; + cfg->regs->SPI_CTRL_REG |= SPI_SPI_CTRL_REG_SPI_RST_Msk; + } +} + +static inline bool spi_smartbond_isenabled(const struct spi_smartbond_cfg *cfg) +{ + return (!!(cfg->regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_ON_Msk)) && + (!(cfg->regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_RST_Msk)); +} + +static inline int spi_smartbond_set_speed(const struct spi_smartbond_cfg *cfg, + const uint32_t frequency) +{ + if (frequency < SCLK_FREQ_2MHZ) { + LOG_ERR("Frequency is lower than minimal SCLK %d", SCLK_FREQ_2MHZ); + return -ENOTSUP; + } else if (frequency < SCLK_FREQ_4MHZ) { + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_CLK_Msk) | + 3UL << SPI_SPI_CTRL_REG_SPI_CLK_Pos; + } else if (frequency < SCLK_FREQ_8MHZ) { + cfg->regs->SPI_CTRL_REG = (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_CLK_Msk); + } else if (frequency < SCLK_FREQ_16MHZ) { + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_CLK_Msk) | + 1UL << SPI_SPI_CTRL_REG_SPI_CLK_Pos; + } else { + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_CLK_Msk) | + 2UL << SPI_SPI_CTRL_REG_SPI_CLK_Pos; + } + return 0; +} + +static inline int spi_smartbond_set_word_size(const struct spi_smartbond_cfg *cfg, + struct spi_smartbond_data *data, + const uint32_t operation) +{ + switch (SPI_WORD_SIZE_GET(operation)) { + case 8: + data->dfs = 1; + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_WORD_Msk); + break; + case 16: + data->dfs = 2; + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_WORD_Msk) | + (1UL << SPI_SPI_CTRL_REG_SPI_WORD_Pos); + break; + case 32: + data->dfs = 4; + cfg->regs->SPI_CTRL_REG = + (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_WORD_Msk) | + (2UL << SPI_SPI_CTRL_REG_SPI_WORD_Pos); + break; + default: + LOG_ERR("Word size not supported"); + return -ENOTSUP; + } + + return 0; +} + +static int spi_smartbond_configure(const struct spi_smartbond_cfg *cfg, + struct spi_smartbond_data *data, + const struct spi_config *spi_cfg) +{ + int rc; + + if (spi_context_configured(&data->ctx, spi_cfg)) { + return 0; + } + + if (spi_cfg->operation & SPI_OP_MODE_SLAVE) { + LOG_ERR("Slave mode not yet supported"); + return -ENOTSUP; + } + + if (spi_cfg->operation & SPI_HALF_DUPLEX) { + LOG_ERR("Half-duplex not supported"); + return -ENOTSUP; + } + + if (IS_ENABLED(CONFIG_SPI_EXTENDED_MODES) && + (spi_cfg->operation & SPI_LINES_MASK) != SPI_LINES_SINGLE) { + LOG_ERR("Only single line mode is supported"); + return -ENOTSUP; + } + + if (spi_cfg->operation & SPI_MODE_LOOP) { + LOG_ERR("Loopback mode is not supported"); + return -ENOTSUP; + } + + if (spi_smartbond_isenabled(cfg)) { + spi_smartbond_enable(cfg, false); + } + + rc = spi_smartbond_set_speed(cfg, spi_cfg->frequency); + if (rc) { + return rc; + } + + cfg->regs->SPI_CTRL_REG = + (spi_cfg->operation & SPI_MODE_CPOL) + ? (cfg->regs->SPI_CTRL_REG | SPI_SPI_CTRL_REG_SPI_POL_Msk) + : (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_POL_Msk); + + cfg->regs->SPI_CTRL_REG = + (spi_cfg->operation & SPI_MODE_CPHA) + ? (cfg->regs->SPI_CTRL_REG | SPI_SPI_CTRL_REG_SPI_PHA_Msk) + : (cfg->regs->SPI_CTRL_REG & ~SPI_SPI_CTRL_REG_SPI_PHA_Msk); + + rc = spi_smartbond_set_word_size(cfg, data, spi_cfg->operation); + if (rc) { + return rc; + } + + cfg->regs->SPI_CTRL_REG &= ~(SPI_SPI_CTRL_REG_SPI_FIFO_MODE_Msk); + + spi_smartbond_enable(cfg, true); + + cfg->regs->SPI_CTRL_REG &= ~SPI_SPI_CTRL_REG_SPI_MINT_Msk; + + data->ctx.config = spi_cfg; + + return 0; +} + +static int spi_smartbond_transceive(const struct device *dev, const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs) +{ + const struct spi_smartbond_cfg *cfg = dev->config; + struct spi_smartbond_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + uint32_t bitmask; + int rc; + + spi_context_lock(&data->ctx, false, NULL, NULL, spi_cfg); + rc = spi_smartbond_configure(cfg, data, spi_cfg); + if (rc == 0) { + spi_context_buffers_setup(ctx, tx_bufs, rx_bufs, data->dfs); + spi_context_cs_control(ctx, true); + + bitmask = ~((~0UL) << SPI_WORD_SIZE_GET(data->ctx.config->operation)); + while (spi_context_tx_buf_on(ctx) || spi_context_rx_buf_on(ctx)) { + if (spi_context_tx_buf_on(ctx)) { + cfg->regs->SPI_RX_TX_REG = (*(uint32_t *)ctx->tx_buf) & bitmask; + spi_context_update_tx(ctx, data->dfs, 1); + } else { + cfg->regs->SPI_RX_TX_REG = 0UL; + } + + while (!(cfg->regs->SPI_CTRL_REG & SPI_SPI_CTRL_REG_SPI_INT_BIT_Msk)) { + }; + if (spi_context_rx_buf_on(ctx)) { + (*(uint32_t *)ctx->rx_buf) = cfg->regs->SPI_RX_TX_REG & bitmask; + spi_context_update_rx(ctx, data->dfs, 1); + } else { + (void)cfg->regs->SPI_RX_TX_REG; + } + cfg->regs->SPI_CLEAR_INT_REG = 1UL; + } + } + spi_context_cs_control(ctx, false); + spi_context_release(&data->ctx, rc); + + return rc; +} +#ifdef CONFIG_SPI_ASYNC +static int spi_smartbond_transceive_async(const struct device *dev, + const struct spi_config *spi_cfg, + const struct spi_buf_set *tx_bufs, + const struct spi_buf_set *rx_bufs, spi_callback_t cb, + void *userdata) +{ + return -ENOTSUP; +} +#endif + +static int spi_smartbond_release(const struct device *dev, const struct spi_config *spi_cfg) +{ + struct spi_smartbond_data *data = dev->data; + struct spi_context *ctx = &data->ctx; + + if (!spi_context_configured(ctx, spi_cfg)) { + LOG_ERR("SPI configuration was not the last one to be used"); + return -EINVAL; + } + + spi_context_unlock_unconditionally(ctx); + + return 0; +} + +static const struct spi_driver_api spi_smartbond_driver_api = { + .transceive = spi_smartbond_transceive, +#ifdef CONFIG_SPI_ASYNC + .transceive_async = spi_smartbond_transceive_async, +#endif + .release = spi_smartbond_release, +}; + +static int spi_smartbond_init(const struct device *dev) +{ + const struct spi_smartbond_cfg *cfg = dev->config; + struct spi_smartbond_data *data = dev->data; + int rc; + + CRG_COM->RESET_CLK_COM_REG = cfg->periph_clock_config << 1; + CRG_COM->SET_CLK_COM_REG = cfg->periph_clock_config; + + rc = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT); + if (rc < 0) { + LOG_ERR("Failed to configure SPI pins"); + return rc; + } + + rc = spi_context_cs_configure_all(&data->ctx); + if (rc < 0) { + LOG_ERR("Failed to configure CS pins: %d", rc); + return rc; + } + + spi_context_unlock_unconditionally(&data->ctx); + + return 0; +} + +#define SPI_SMARTBOND_DEVICE(id) \ + PINCTRL_DT_INST_DEFINE(id); \ + static const struct spi_smartbond_cfg spi_smartbond_##id##_cfg = { \ + .regs = (SPI_Type *)DT_INST_REG_ADDR(id), \ + .periph_clock_config = DT_INST_PROP(id, periph_clock_config), \ + .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(id), \ + }; \ + static struct spi_smartbond_data spi_smartbond_##id##_data = { \ + SPI_CONTEXT_INIT_LOCK(spi_smartbond_##id##_data, ctx), \ + SPI_CONTEXT_INIT_SYNC(spi_smartbond_##id##_data, ctx), \ + SPI_CONTEXT_CS_GPIOS_INITIALIZE(DT_DRV_INST(id), ctx)}; \ + DEVICE_DT_INST_DEFINE(id, spi_smartbond_init, NULL, &spi_smartbond_##id##_data, \ + &spi_smartbond_##id##_cfg, POST_KERNEL, CONFIG_SPI_INIT_PRIORITY, \ + &spi_smartbond_driver_api); + +DT_INST_FOREACH_STATUS_OKAY(SPI_SMARTBOND_DEVICE) diff --git a/dts/arm/renesas/smartbond/da1469x.dtsi b/dts/arm/renesas/smartbond/da1469x.dtsi index ed44a2f4f92..72b12efba60 100644 --- a/dts/arm/renesas/smartbond/da1469x.dtsi +++ b/dts/arm/renesas/smartbond/da1469x.dtsi @@ -178,6 +178,25 @@ reg = <0x50020700 0x100>; periph-clock-config = <0x0800>; interrupts = <9 0>; + }; + + spi: spi@50020300 { + compatible = "renesas,smartbond-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50020300 0x100>; + periph-clock-config = <0x20>; + interrupts = <10 0>; + status = "disabled"; + }; + + spi2: spi@50020400 { + compatible = "renesas,smartbond-spi"; + #address-cells = <1>; + #size-cells = <0>; + reg = <0x50020400 0x100>; + periph-clock-config = <0x80>; + interrupts = <11 0>; status = "disabled"; }; }; diff --git a/dts/bindings/spi/renesas,smartbond-spi.yaml b/dts/bindings/spi/renesas,smartbond-spi.yaml new file mode 100644 index 00000000000..bd2b29f1862 --- /dev/null +++ b/dts/bindings/spi/renesas,smartbond-spi.yaml @@ -0,0 +1,20 @@ +# Copyright (c) 2022 Renesas Electronics Corporation +# SPDX-License-Identifier: Apache-2.0 + +description: Renesas SmartBond(tm) SPI + +compatible: "renesas,smartbond-spi" + +include: [spi-controller.yaml, pinctrl-device.yaml] + +properties: + reg: + required: true + + interrupts: + required: true + + periph-clock-config: + type: int + description: Peripheral clock register configuration (COM domain) + required: true diff --git a/soc/arm/renesas_smartbond/da1469x/pinctrl_soc.h b/soc/arm/renesas_smartbond/da1469x/pinctrl_soc.h index 8e91f07a6b6..9a726d70db4 100644 --- a/soc/arm/renesas_smartbond/da1469x/pinctrl_soc.h +++ b/soc/arm/renesas_smartbond/da1469x/pinctrl_soc.h @@ -15,6 +15,8 @@ struct smartbond_pinctrl_soc_pin { uint32_t pin : 5; uint32_t bias_pull_up : 1; uint32_t bias_pull_down : 1; + uint32_t output_enable : 1; + uint32_t input_enable : 1; }; typedef struct smartbond_pinctrl_soc_pin pinctrl_soc_pin_t; @@ -26,6 +28,8 @@ typedef struct smartbond_pinctrl_soc_pin pinctrl_soc_pin_t; SMARTBOND_GET_PIN(DT_PROP_BY_IDX(node_id, prop, idx)), \ DT_PROP(node_id, bias_pull_up), \ DT_PROP(node_id, bias_pull_down), \ + DT_PROP(node_id, output_enable), \ + DT_PROP(node_id, input_enable), \ }, #define Z_PINCTRL_STATE_PINS_INIT(node_id, prop) \