Commit ba9c3a4d authored by HaiLong Yang's avatar HaiLong Yang Committed by Carles Cufi
Browse files

drivers: dac: introduce gd32 dac driver



Add DAC driver for gd32 series SoCs.

Signed-off-by: default avatarHaiLong Yang <cameledyang@pm.me>
parent 222f42f2
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -11,4 +11,5 @@ zephyr_library_sources_ifdef(CONFIG_DAC_DACX0508 dac_dacx0508.c)
zephyr_library_sources_ifdef(CONFIG_DAC_DACX3608	dac_dacx3608.c)
zephyr_library_sources_ifdef(CONFIG_DAC_SHELL		dac_shell.c)
zephyr_library_sources_ifdef(CONFIG_DAC_MCP4725		dac_mcp4725.c)
zephyr_library_sources_ifdef(CONFIG_DAC_GD32		dac_gd32.c)
zephyr_library_sources_ifdef(CONFIG_USERSPACE		dac_handlers.c)
+2 −0
Original line number Diff line number Diff line
@@ -44,4 +44,6 @@ source "drivers/dac/Kconfig.dacx3608"

source "drivers/dac/Kconfig.mcp4725"

source "drivers/dac/Kconfig.gd32"

endif # DAC
+15 −0
Original line number Diff line number Diff line
# DAC configuration options

# Copyright (c) 2021 BrainCo Inc.
#
# SPDX-License-Identifier: Apache-2.0

# Workaround for not being able to have commas in macro arguments
DT_COMPAT_GD_GD32_DAC := gd,gd32-dac

config DAC_GD32
	bool "GD32 DAC driver"
	depends on SOC_FAMILY_GD32
	default $(dt_compat_enabled,$(DT_COMPAT_GD_GD32_DAC))
	help
	  Enable GigaDevice GD32 DAC driver

drivers/dac/dac_gd32.c

0 → 100644
+167 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2021 BrainCo Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#define DT_DRV_COMPAT gd_gd32_dac

#include <errno.h>
#include <drivers/pinctrl.h>
#include <drivers/dac.h>
#include <soc.h>

#include <logging/log.h>
LOG_MODULE_REGISTER(dac_gd32, CONFIG_DAC_LOG_LEVEL);

/**
 * GD32 DAC HAL use different DAC0 interface for 2 or 1 output channels SoCs.
 * Unify the DAC0 interface to DAC0_xx.
 */
#if DT_INST_PROP(0, num_channels) == 1
#define DAC_CTL_DEN0 DAC_CTL_DEN
#define DAC0_R8DH    DAC_R8DH
#define DAC0_R12DH   DAC_R12DH
#endif

struct dac_gd32_config {
	uint32_t reg;
	uint32_t rcu_periph_clock;
	const struct pinctrl_dev_config *pcfg;
	uint32_t num_channels;
	uint32_t reset_val;
};

struct dac_gd32_data {
	uint8_t resolutions[2];
};

static void dac_gd32_enable(uint8_t dacx)
{
	switch (dacx) {
	case 0U:
		DAC_CTL |= DAC_CTL_DEN0;
		break;
#if DT_INST_PROP(0, num_channels) == 2
	case 1U:
		DAC_CTL |= DAC_CTL_DEN1;
		break;
#endif
	}
}

static void dac_gd32_disable(uint8_t dacx)
{
	switch (dacx) {
	case 0U:
		DAC_CTL &= ~DAC_CTL_DEN0;
		break;
#if DT_INST_PROP(0, num_channels) == 2
	case 1U:
		DAC_CTL &= ~DAC_CTL_DEN1;
		break;
#endif
	}
}

static void dac_gd32_write(struct dac_gd32_data *data,
			   uint8_t dacx, uint32_t value)
{
	switch (dacx) {
	case 0U:
		if (data->resolutions[dacx] == 8U) {
			DAC0_R8DH = value;
		} else {
			DAC0_R12DH = value;
		}
		break;
#if DT_INST_PROP(0, num_channels) == 2
	case 1U:
		if (data->resolutions[dacx] == 8U) {
			DAC1_R8DH = value;
		} else {
			DAC1_R12DH = value;
		}
		break;
#endif
	}
}

static int dac_gd32_channel_setup(const struct device *dev,
				  const struct dac_channel_cfg *channel_cfg)
{
	struct dac_gd32_data *data = dev->data;
	const struct dac_gd32_config *config = dev->config;
	uint8_t dacx = channel_cfg->channel_id;

	if (dacx >= config->num_channels) {
		return -ENOTSUP;
	}

	/* GD32 DAC only support 8 or 12 bits resolution */
	if ((channel_cfg->resolution != 8U) &&
	    (channel_cfg->resolution != 12U)) {
		LOG_ERR("Only 8 and 12 bits resolutions are supported!");
		return -ENOTSUP;
	}

	data->resolutions[dacx] = channel_cfg->resolution;

	dac_gd32_disable(dacx);
	dac_gd32_write(data, dacx, config->reset_val);
	dac_gd32_enable(dacx);

	return 0;
}

static int dac_gd32_write_value(const struct device *dev,
				uint8_t dacx, uint32_t value)
{
	struct dac_gd32_data *data = dev->data;
	const struct dac_gd32_config *config = dev->config;

	if (dacx >= config->num_channels) {
		return -ENOTSUP;
	}

	dac_gd32_write(data, dacx, value);

	return 0;
}

struct dac_driver_api dac_gd32_driver_api = {
	.channel_setup = dac_gd32_channel_setup,
	.write_value = dac_gd32_write_value
};

static int dac_gd32_init(const struct device *dev)
{
	const struct dac_gd32_config *cfg = dev->config;
	int ret;

	ret = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
	if (ret < 0) {
		LOG_ERR("Failed to apply pinctrl state");
		return ret;
	}

	rcu_periph_clock_enable(cfg->rcu_periph_clock);

	return 0;
}

PINCTRL_DT_INST_DEFINE(0)

static struct dac_gd32_data dac_gd32_data_0;

static const struct dac_gd32_config dac_gd32_cfg_0 = {
	.reg = DT_INST_REG_ADDR(0),
	.rcu_periph_clock = DT_INST_PROP(0, rcu_periph_clock),
	.pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(0),
	.num_channels = DT_INST_PROP(0, num_channels),
	.reset_val = DT_INST_PROP(0, reset_val),
};

DEVICE_DT_INST_DEFINE(0, &dac_gd32_init, NULL, &dac_gd32_data_0,
		      &dac_gd32_cfg_0, POST_KERNEL, CONFIG_DAC_INIT_PRIORITY,
		      &dac_gd32_driver_api);