<commit_before>/*
 * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT espressif_esp32_spi

/* Include esp-idf headers first to avoid redefining BIT() macro */
#include <hal/spi_hal.h>
#include <esp_attr.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL);

#include <soc.h>
#include <soc/soc_memory_types.h>
#include <zephyr/drivers/spi.h>
#ifndef CONFIG_SOC_ESP32C3
#include <zephyr/drivers/interrupt_controller/intc_esp32.h>
#else
#include <hal/gdma_hal.h>
#include <hal/gdma_ll.h>
#include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
#endif
#include <zephyr/drivers/clock_control.h>
#include "spi_context.h"
#include "spi_esp32_spim.h"

#ifdef CONFIG_SOC_ESP32C3
#define ISR_HANDLER isr_handler_t
#else
#define ISR_HANDLER intr_handler_t
#endif

static bool spi_esp32_transfer_ongoing(struct spi_esp32_data *data)
{
	return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx);
}

static inline void spi_esp32_complete(const struct device *dev,
				      struct spi_esp32_data *data,
				      spi_dev_t *spi, int status)
{
#ifdef CONFIG_SPI_ESP32_INTERRUPT
	spi_ll_disable_int(spi);
	spi_ll_clear_int_stat(spi);
#endif

	spi_context_cs_control(&data->ctx, false);

#ifdef CONFIG_SPI_ESP32_INTERRUPT
	spi_context_complete(&data->ctx, dev, status);
#endif

}

static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
{
	struct spi_esp32_data *data = dev->data;
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_context *ctx = &data->ctx;
	spi_hal_context_t *hal = &data->hal;
	spi_hal_dev_config_t *hal_dev = &data->dev_config;
	spi_hal_trans_config_t *hal_trans = &data->trans_config;
	size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
	chunk_len = MIN(chunk_len, SOC_SPI_MAXIMUM_BUFFER_SIZE);
	size_t bit_len = chunk_len << 3;
	uint8_t *rx_temp = NULL;
	uint8_t *tx_temp = NULL;

	if (cfg->dma_enabled) {
		/* bit_len needs to be at least one byte long when using DMA */
		bit_len = !bit_len ? 8 : bit_len;
		if (ctx->tx_buf && !esp_ptr_dma_capable((uint32_t *)&ctx->tx_buf[0])) {
			tx_temp = k_malloc(ctx->tx_len);
			if (!tx_temp) {
				LOG_ERR("Error allocating temp buffer Tx");
				return -ENOMEM;
			}
			memcpy(tx_temp, &ctx->tx_buf[0], ctx->tx_len);
		}
		if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) ||
				    ((int)&ctx->rx_buf[0] % 4 != 0))) {
			/* The rx buffer need to be length of
			 * multiples of 32 bits to avoid heap
			 * corruption.
			 */
			rx_temp = k_calloc(((ctx->rx_len << 3) + 31) / 8, sizeof(uint8_t));
			if (!rx_temp) {
				LOG_ERR("Error allocating temp buffer Rx");
				return -ENOMEM;
			}
		}
	}

	/* clean up and prepare SPI hal */
	memset((uint32_t *)hal->hw->data_buf, 0, sizeof(hal->hw->data_buf));
	hal_trans->send_buffer = tx_temp ? tx_temp : (uint8_t *)ctx->tx_buf;
	hal_trans->rcv_buffer = rx_temp ? rx_temp : ctx->rx_buf;
	hal_trans->tx_bitlen = bit_len;
	hal_trans->rx_bitlen = bit_len;

	/* configure SPI */
	spi_hal_setup_trans(hal, hal_dev, hal_trans);
	spi_hal_prepare_data(hal, hal_dev, hal_trans);

	/* send data */
	spi_hal_user_start(hal);
	spi_context_update_tx(&data->ctx, data->dfs, chunk_len);

	while (!spi_hal_usr_is_done(hal)) {
		/* nop */
	}

	/* read data */
	spi_hal_fetch_result(hal);

	if (rx_temp) {
		memcpy(&ctx->rx_buf[0], rx_temp, chunk_len);
	}

	spi_context_update_rx(&data->ctx, data->dfs, chunk_len);

	if (tx_temp) {
		k_free(tx_temp);
	}

	if (rx_temp) {
		k_free(rx_temp);
	}

	return 0;
}

#ifdef CONFIG_SPI_ESP32_INTERRUPT
static void IRAM_ATTR spi_esp32_isr(void *arg)
{
	const struct device *dev = (const struct device *)arg;
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_esp32_data *data = dev->data;

	do {
		spi_esp32_transfer(dev);
	} while (spi_esp32_transfer_ongoing(data));

	spi_esp32_complete(dev, data, cfg->spi, 0);
}
#endif

static int spi_esp32_init_dma(const struct device *dev)
{
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_esp32_data *data = dev->data;
	uint8_t channel_offset;

	LOG_ERR("DMA");
	if (clock_control_on(cfg->clock_dev, (clock_control_subsys_t)cfg->dma_clk_src)) {
		LOG_ERR("Could not enable DMA clock");
		return -EIO;
	}

#ifdef CONFIG_SOC_ESP32C3
	gdma_hal_init(&data->hal_gdma, 0);
	gdma_ll_enable_clock(data->hal_gdma.dev, true);
	gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
	gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
	gdma_ll_tx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, 0);
	gdma_ll_rx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, 0);
	channel_offset = 0;
#else<commit_msg>drivers: spi: esp32xx: remove unnecessary log<commit_after>/*
 * Copyright (c) 2020 Espressif Systems (Shanghai) Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT espressif_esp32_spi

/* Include esp-idf headers first to avoid redefining BIT() macro */
#include <hal/spi_hal.h>
#include <esp_attr.h>

#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(esp32_spi, CONFIG_SPI_LOG_LEVEL);

#include <soc.h>
#include <soc/soc_memory_types.h>
#include <zephyr/drivers/spi.h>
#ifndef CONFIG_SOC_ESP32C3
#include <zephyr/drivers/interrupt_controller/intc_esp32.h>
#else
#include <hal/gdma_hal.h>
#include <hal/gdma_ll.h>
#include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
#endif
#include <zephyr/drivers/clock_control.h>
#include "spi_context.h"
#include "spi_esp32_spim.h"

#ifdef CONFIG_SOC_ESP32C3
#define ISR_HANDLER isr_handler_t
#else
#define ISR_HANDLER intr_handler_t
#endif

static bool spi_esp32_transfer_ongoing(struct spi_esp32_data *data)
{
	return spi_context_tx_on(&data->ctx) || spi_context_rx_on(&data->ctx);
}

static inline void spi_esp32_complete(const struct device *dev,
				      struct spi_esp32_data *data,
				      spi_dev_t *spi, int status)
{
#ifdef CONFIG_SPI_ESP32_INTERRUPT
	spi_ll_disable_int(spi);
	spi_ll_clear_int_stat(spi);
#endif

	spi_context_cs_control(&data->ctx, false);

#ifdef CONFIG_SPI_ESP32_INTERRUPT
	spi_context_complete(&data->ctx, dev, status);
#endif

}

static int IRAM_ATTR spi_esp32_transfer(const struct device *dev)
{
	struct spi_esp32_data *data = dev->data;
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_context *ctx = &data->ctx;
	spi_hal_context_t *hal = &data->hal;
	spi_hal_dev_config_t *hal_dev = &data->dev_config;
	spi_hal_trans_config_t *hal_trans = &data->trans_config;
	size_t chunk_len = spi_context_max_continuous_chunk(&data->ctx);
	chunk_len = MIN(chunk_len, SOC_SPI_MAXIMUM_BUFFER_SIZE);
	size_t bit_len = chunk_len << 3;
	uint8_t *rx_temp = NULL;
	uint8_t *tx_temp = NULL;

	if (cfg->dma_enabled) {
		/* bit_len needs to be at least one byte long when using DMA */
		bit_len = !bit_len ? 8 : bit_len;
		if (ctx->tx_buf && !esp_ptr_dma_capable((uint32_t *)&ctx->tx_buf[0])) {
			tx_temp = k_malloc(ctx->tx_len);
			if (!tx_temp) {
				LOG_ERR("Error allocating temp buffer Tx");
				return -ENOMEM;
			}
			memcpy(tx_temp, &ctx->tx_buf[0], ctx->tx_len);
		}
		if (ctx->rx_buf && (!esp_ptr_dma_capable((uint32_t *)&ctx->rx_buf[0]) ||
				    ((int)&ctx->rx_buf[0] % 4 != 0))) {
			/* The rx buffer need to be length of
			 * multiples of 32 bits to avoid heap
			 * corruption.
			 */
			rx_temp = k_calloc(((ctx->rx_len << 3) + 31) / 8, sizeof(uint8_t));
			if (!rx_temp) {
				LOG_ERR("Error allocating temp buffer Rx");
				return -ENOMEM;
			}
		}
	}

	/* clean up and prepare SPI hal */
	memset((uint32_t *)hal->hw->data_buf, 0, sizeof(hal->hw->data_buf));
	hal_trans->send_buffer = tx_temp ? tx_temp : (uint8_t *)ctx->tx_buf;
	hal_trans->rcv_buffer = rx_temp ? rx_temp : ctx->rx_buf;
	hal_trans->tx_bitlen = bit_len;
	hal_trans->rx_bitlen = bit_len;

	/* configure SPI */
	spi_hal_setup_trans(hal, hal_dev, hal_trans);
	spi_hal_prepare_data(hal, hal_dev, hal_trans);

	/* send data */
	spi_hal_user_start(hal);
	spi_context_update_tx(&data->ctx, data->dfs, chunk_len);

	while (!spi_hal_usr_is_done(hal)) {
		/* nop */
	}

	/* read data */
	spi_hal_fetch_result(hal);

	if (rx_temp) {
		memcpy(&ctx->rx_buf[0], rx_temp, chunk_len);
	}

	spi_context_update_rx(&data->ctx, data->dfs, chunk_len);

	if (tx_temp) {
		k_free(tx_temp);
	}

	if (rx_temp) {
		k_free(rx_temp);
	}

	return 0;
}

#ifdef CONFIG_SPI_ESP32_INTERRUPT
static void IRAM_ATTR spi_esp32_isr(void *arg)
{
	const struct device *dev = (const struct device *)arg;
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_esp32_data *data = dev->data;

	do {
		spi_esp32_transfer(dev);
	} while (spi_esp32_transfer_ongoing(data));

	spi_esp32_complete(dev, data, cfg->spi, 0);
}
#endif

static int spi_esp32_init_dma(const struct device *dev)
{
	const struct spi_esp32_config *cfg = dev->config;
	struct spi_esp32_data *data = dev->data;
	uint8_t channel_offset;

	if (clock_control_on(cfg->clock_dev, (clock_control_subsys_t)cfg->dma_clk_src)) {
		LOG_ERR("Could not enable DMA clock");
		return -EIO;
	}

#ifdef CONFIG_SOC_ESP32C3
	gdma_hal_init(&data->hal_gdma, 0);
	gdma_ll_enable_clock(data->hal_gdma.dev, true);
	gdma_ll_tx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
	gdma_ll_rx_reset_channel(data->hal_gdma.dev, cfg->dma_host);
	gdma_ll_tx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, 0);
	gdma_ll_rx_connect_to_periph(data->hal_gdma.dev, cfg->dma_host, 0);
	channel_offset = 0;
#else
{'fraction_non_alphanumeric': 0.13462562573223985, 'fraction_numerical': 0.020875492597720736, 'mean_word_length': 5.11328125, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1656076', 'n_tokens_mistral': 4117, 'n_tokens_neox': 3826, 'n_words': 719}