Skip to content

Commit

Permalink
drivers: spip: add SPIP driver support for NPCM4XX
Browse files Browse the repository at this point in the history
Add SPIP driver support for NPCM4XX. (not support slave mode)

Signed-off-by: TY Su <[email protected]>
  • Loading branch information
TYNuv authored and maxdog988 committed Aug 9, 2023
1 parent 7cf9ffc commit f028734
Show file tree
Hide file tree
Showing 12 changed files with 454 additions and 11 deletions.
5 changes: 5 additions & 0 deletions boards/arm/npcm400f_evb/fun_def_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ FUN_DEFINE(DT_NODELABEL(pinctrl_thr2_default), THR2)
FUN_DEFINE(DT_NODELABEL(pinctrl_td4p_default), TD4P)
FUN_DEFINE(DT_NODELABEL(pinctrl_vin3_default), VIN3)
#endif

#if DT_NODE_HAS_STATUS(DT_NODELABEL(spip), okay) && CONFIG_SPIP_NPCM4XX
FUN_DEFINE(DT_NODELABEL(pinctrl_spip_default), SPIP_CS, SPIP_SCLK, SPIP_DIO0, SPIP_DIO1)
FUN_DEFINE(DT_NODELABEL(pinctrl_spip_quad), SPIP_DIO2, SPIP_DIO3)
#endif
3 changes: 3 additions & 0 deletions boards/arm/npcm400f_evb/npcm400f_evb.dts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,6 @@
/* &pinctrl_td4p_default */ /* TD4P - C6 */
&pinctrl_vin3_default>; /* VIN3 - D6 */
};
&spip {
status = "okay";
};
6 changes: 5 additions & 1 deletion boards/arm/npcm400f_evb/npcm400f_evb_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,8 @@ CONFIG_I2C=y

#ADC Driver
CONFIG_ADC=y
CONFIG_ADC_NPCM4XX=y
CONFIG_ADC_NPCM4XX=y

#SPIP Driver
CONFIG_SPI=y
CONFIG_SPIP_NPCM4XX=y
1 change: 1 addition & 0 deletions drivers/spi/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,6 @@ zephyr_library_sources_ifdef(CONFIG_ESP32_SPIM spi_esp32_spim.c)
zephyr_library_sources_ifdef(CONFIG_SPI_TEST spi_test.c)
zephyr_library_sources_ifdef(CONFIG_SPI_PSOC6 spi_psoc6.c)
zephyr_library_sources_ifdef(CONFIG_SPI_NPCM4XX_FIU spi_npcm4xx_fiu.c)
zephyr_library_sources_ifdef(CONFIG_SPIP_NPCM4XX spi_npcm4xx_spip.c)

zephyr_library_sources_ifdef(CONFIG_USERSPACE spi_handlers.c)
2 changes: 2 additions & 0 deletions drivers/spi/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,6 @@ source "drivers/spi/Kconfig.psoc6"

source "drivers/spi/Kconfig.npcm4xx_fiu"

source "drivers/spi/Kconfig.npcm4xx_spip"

endif # SPI
11 changes: 11 additions & 0 deletions drivers/spi/Kconfig.npcm4xx_spip
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# NPCM4XX SPI Driver configuration options

# Copyright (c) 2023 Nuvoton Technology Corporation.
# SPDX-License-Identifier: Apache-2.0

config SPIP_NPCM4XX
bool "Nuvoton NPCM4XX SPI driver SPIP"
default y
depends on SOC_FAMILY_NPCM4XX
help
Enable the SPI driver for NPCM4XX family of processors.
277 changes: 277 additions & 0 deletions drivers/spi/spi_npcm4xx_spip.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
/*
* SPDX-License-Identifier: Apache-2.0
*/

#define DT_DRV_COMPAT nuvoton_npcm4xx_spip

#define LOG_LEVEL CONFIG_SPI_LOG_LEVEL
#include <logging/log.h>
LOG_MODULE_REGISTER(spip_npcm4xx);

#include <drivers/clock_control.h>
#include <drivers/spi.h>
#include <soc.h>
#include "spi_context.h"

/* Device constant configuration parameters */
struct npcm4xx_spip_config {
/* SPIP reg base address */
uintptr_t base;
/* clock configuration */
struct npcm4xx_clk_cfg clk_cfg;
};

/* Device run time data */
struct npcm4xx_spip_data {
struct spi_context ctx;
uint32_t apb3;
};

static void SPI_SET_SS0_HIGH(const struct device *dev)
{
const struct npcm4xx_spip_config *cfg = dev->config;
struct spip_reg *const spip_regs = (struct spip_reg *) cfg->base;

spip_regs->SSCTL &= ~BIT(NPCM4XX_SSCTL_AUTOSS);
spip_regs->SSCTL |= BIT(NPCM4XX_SSCTL_SSACTPOL);
spip_regs->SSCTL |= BIT(NPCM4XX_SSCTL_SS);
}

static void SPI_SET_SS0_LOW(const struct device *dev)
{
const struct npcm4xx_spip_config *cfg = dev->config;
struct spip_reg *const spip_regs = (struct spip_reg *) cfg->base;

spip_regs->SSCTL &= ~BIT(NPCM4XX_SSCTL_AUTOSS);
spip_regs->SSCTL &= ~BIT(NPCM4XX_SSCTL_SSACTPOL);
spip_regs->SSCTL |= BIT(NPCM4XX_SSCTL_SS);
}

static int spip_npcm4xx_configure(const struct device *dev,
const struct spi_config *config)
{
const struct npcm4xx_spip_config *cfg = dev->config;
struct npcm4xx_spip_data *data = dev->data;
struct spip_reg *const spip_regs = (struct spip_reg *) cfg->base;
uint32_t u32Div;
int ret;

if (SPI_WORD_SIZE_GET(config->operation) != 8) {
LOG_ERR("Word sizes other than 8 bits are not supported");
ret = -ENOTSUP;
} else {
spip_regs->CTL &= ~(0x1F << NPCM4XX_CTL_DWIDTH);
spip_regs->CTL |= (SPI_WORD_SIZE_GET(config->operation) << NPCM4XX_CTL_DWIDTH);
}

if (SPI_MODE_GET(config->operation) & SPI_MODE_CPOL) {
spip_regs->CTL |= BIT(NPCM4XX_CTL_CLKPOL);
if (SPI_MODE_GET(config->operation) & SPI_MODE_CPHA) {
spip_regs->CTL &= ~BIT(NPCM4XX_CTL_TXNEG);
spip_regs->CTL &= ~BIT(NPCM4XX_CTL_RXNEG);
} else {
spip_regs->CTL |= BIT(NPCM4XX_CTL_TXNEG);
spip_regs->CTL |= BIT(NPCM4XX_CTL_RXNEG);
}
} else {
spip_regs->CTL &= ~BIT(NPCM4XX_CTL_CLKPOL);
}

if (config->operation & SPI_TRANSFER_LSB) {
spip_regs->CTL |= BIT(NPCM4XX_CTL_LSB);
} else {
spip_regs->CTL &= ~BIT(NPCM4XX_CTL_LSB);
}

if (config->operation & SPI_OP_MODE_SLAVE) {
LOG_ERR("Slave mode is not supported");
ret = -ENOTSUP;
} else {
spip_regs->CTL &= ~BIT(NPCM4XX_CTL_SLAVE);
}

/* Set Bus clock */
if (config->frequency != 0) {
if (config->frequency <= data->apb3) {
u32Div = (data->apb3 / config->frequency) - 1;
if (data->apb3 % config->frequency) {
u32Div += 1;
}
if (u32Div > 0xFF) {
u32Div = 0xFF;
}
}
}

spip_regs->CLKDIV = (spip_regs->CLKDIV & ~0xFF) | u32Div;

/* spip enable */
spip_regs->CTL |= BIT(NPCM4XX_CTL_SPIEN);

return ret;
}

static int spip_npcm4xx_transceive(const struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
const struct npcm4xx_spip_config *cfg = dev->config;
struct npcm4xx_spip_data *data = dev->data;
struct spip_reg *const spip_regs = (struct spip_reg *) cfg->base;

spi_context_lock(&data->ctx, false, NULL, config);
data->ctx.config = config;

int ret, error = 0;
uint8_t txDone;
/* Configure */
ret = spip_npcm4xx_configure(dev, config);
if (ret) {
return -ENOTSUP;
}
ret = 0;
spi_context_buffers_setup(&data->ctx, tx_bufs, rx_bufs, 1);


if (config->operation & SPI_OP_MODE_SLAVE) {
/* Slave */
LOG_ERR("Slave mode is not supported");
ret = -ENOTSUP;
} else {
/* Master */
SPI_SET_SS0_LOW(dev);
if (rx_bufs == NULL) {
/* write data to SPI flash */
while (spi_context_tx_buf_on(&data->ctx)) {
/*TX*/
if ((spip_regs->STATUS & BIT(NPCM4XX_STATUS_TXFULL)) == 0) {
spip_regs->TX = *data->ctx.tx_buf;
spi_context_update_tx(&data->ctx, 1, 1);
}
}
} else {
txDone = 0;
spip_regs->FIFOCTL |= BIT(NPCM4XX_FIFOCTL_RXRST);
while (1) {
/*TX*/
if (spi_context_tx_buf_on(&data->ctx)) {
if (!(spip_regs->STATUS & BIT(NPCM4XX_STATUS_TXFULL))) {
spip_regs->TX = *data->ctx.tx_buf;
spi_context_update_tx(&data->ctx, 1, 1);
}
} else if (!(spip_regs->STATUS & BIT(NPCM4XX_STATUS_BUSY))) {
txDone = 1;
}

/*RX*/
if (spi_context_rx_buf_on(&data->ctx)) {
if (!(spip_regs->STATUS & BIT(NPCM4XX_STATUS_RXEMPTY))) {
*data->ctx.rx_buf = spip_regs->RX;
spi_context_update_rx(&data->ctx, 1, 1);
} else if (txDone == 1) {
ret = -EOVERFLOW;
break;
}
} else {
if (txDone == 1) {
break;
}
}
}
}

do {
if ((spip_regs->STATUS & BIT(NPCM4XX_STATUS_BUSY)) == 0) {
break;
}
} while (1);

SPI_SET_SS0_HIGH(dev);
}
spi_context_release(&data->ctx, error);
if (error != 0) {
ret = error;
}

return ret;
}

#ifdef CONFIG_SPI_ASYNC
static int spip_npcm4xx_transceive_async(const struct device *dev,
const struct spi_config *config,
const struct spi_buf_set *tx_bufs,
const struct spi_buf_set *rx_bufs)
{
return spip_npcm4xx_transceive(dev, config, tx_bufs, rx_bufs);
}
#endif /* CONFIG_SPI_ASYNC */

static int spip_npcm4xx_release(const struct device *dev,
const struct spi_config *config)
{
struct npcm4xx_spip_data *data = dev->data;

spi_context_unlock_unconditionally(&data->ctx);

return 0;
}

static int spip_npcm4xx_init(const struct device *dev)
{
const struct npcm4xx_spip_config *cfg = dev->config;
struct npcm4xx_spip_data *data = dev->data;
const struct device *const clk_dev =
device_get_binding(NPCM4XX_CLK_CTRL_NAME);
uint32_t spip_apb3;
int ret;

if (!device_is_ready(clk_dev)) {
LOG_ERR("%s device not ready", clk_dev->name);
return -ENODEV;
}
/* Turn on device clock first and get source clock freq. */
ret = clock_control_on(clk_dev,
(clock_control_subsys_t)&cfg->clk_cfg);
if (ret < 0) {
LOG_ERR("Turn on SPIP clock fail %d", ret);
return ret;
}

ret = clock_control_get_rate(clk_dev, (clock_control_subsys_t *)
&cfg->clk_cfg, &spip_apb3);

if (ret < 0) {
LOG_ERR("Get ITIM clock rate error %d", ret);
return ret;
}

data->apb3 = spip_apb3;

spi_context_unlock_unconditionally(&data->ctx);
return 0;
}

static const struct spi_driver_api spip_npcm4xx_driver_api = {
.transceive = spip_npcm4xx_transceive,
#ifdef CONFIG_SPI_ASYNC
.transceive_async = spip_npcm4xx_transceive_async,
#endif
.release = spip_npcm4xx_release,
};


static const struct npcm4xx_spip_config spip_npcm4xx_config = {
.base = DT_INST_REG_ADDR(0),
.clk_cfg = NPCM4XX_DT_CLK_CFG_ITEM(0),
};

static struct npcm4xx_spip_data spip_npcm4xx_dev_data = {
SPI_CONTEXT_INIT_LOCK(spip_npcm4xx_dev_data, ctx),
};


DEVICE_DT_INST_DEFINE(0, &spip_npcm4xx_init, NULL,
&spip_npcm4xx_dev_data,
&spip_npcm4xx_config, POST_KERNEL,
CONFIG_SPI_INIT_PRIORITY, &spip_npcm4xx_driver_api);
11 changes: 11 additions & 0 deletions dts/arm/nuvoton/npcm400f.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,17 @@
status = "disabled";
label = "ADC_0";
};

spip: spi@40016000 {
compatible = "nuvoton,npcm4xx-spip";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40016000 0x100>;
clocks = <&pcc NPCM4XX_CLOCK_BUS_APB3 NPCM4XX_PWDWN_CTL4 7>;
pinctrl-0 = <&pinctrl_spip_default &pinctrl_spip_quad>;
label = "SPIP";
status = "disabled";
};
};

soc-id {
Expand Down
2 changes: 2 additions & 0 deletions dts/arm/nuvoton/npcm4xx/npcm4xx-pinctrl.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,6 @@
pinctrl_thr2_default: thr2_default {};
pinctrl_td4p_default: td4p_default {};
pinctrl_vin3_default: vin3_default {};
pinctrl_spip_default: spip_default{};
pinctrl_spip_quad: spip_quad{};
};
14 changes: 14 additions & 0 deletions dts/bindings/spi/nuvoton,npcm4xx-spip.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright (c) 2023 Nuvoton Technology Corporation.
# SPDX-License-Identifier: Apache-2.0

description: Nuvoton, NPCM4XX-SPIP controller node

compatible: "nuvoton,npcm4xx-spip"

include: ["spi-controller.yaml", "nuvoton-pinctrl.yaml"]

properties:
reg:
required: true
clocks:
required: true
Loading

0 comments on commit f028734

Please sign in to comment.