1 /*
2  * Copyright 2023 NXP
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #define DT_DRV_COMPAT nxp_gau_dac
8 
9 #include <zephyr/drivers/dac.h>
10 
11 #include <fsl_dac.h>
12 
13 #define LOG_LEVEL CONFIG_DAC_LOG_LEVEL
14 #include <zephyr/logging/log.h>
15 #include <zephyr/irq.h>
16 LOG_MODULE_REGISTER(nxp_gau_dac);
17 
18 struct nxp_gau_dac_config {
19 	DAC_Type *base;
20 	dac_conversion_rate_t conversion_rate : 2;
21 	dac_reference_voltage_source_t voltage_ref : 1;
22 	dac_output_voltage_range_t output_range : 2;
23 };
24 
convert_channel_id(uint8_t channel_id)25 static inline dac_channel_id_t convert_channel_id(uint8_t channel_id)
26 {
27 	switch (channel_id) {
28 	case 0: return kDAC_ChannelA;
29 	case 1: return kDAC_ChannelB;
30 	default:
31 		LOG_ERR("Invalid DAC channel ID");
32 		return -EINVAL;
33 	};
34 }
35 
nxp_gau_dac_channel_setup(const struct device * dev,const struct dac_channel_cfg * channel_cfg)36 static int nxp_gau_dac_channel_setup(const struct device *dev,
37 			const struct dac_channel_cfg *channel_cfg)
38 {
39 	const struct nxp_gau_dac_config *config = dev->config;
40 	dac_channel_config_t dac_channel_config = {0};
41 	bool use_internal = true;
42 
43 	if (channel_cfg->resolution != 10) {
44 		LOG_ERR("DAC only support 10 bit resolution");
45 		return -EINVAL;
46 	}
47 
48 	if (channel_cfg->internal && channel_cfg->buffered) {
49 		LOG_ERR("DAC output can not be buffered and internal");
50 		return -EINVAL;
51 	} else if (channel_cfg->buffered) {
52 		/* External and internal output are mutually exclusive */
53 		LOG_WRN("Note: buffering DAC output to pad disconnects internal output");
54 		use_internal = false;
55 	}
56 
57 	dac_channel_config.waveType = kDAC_WaveNormal;
58 	dac_channel_config.outMode =
59 		use_internal ? kDAC_ChannelOutputInternal : kDAC_ChannelOutputPAD;
60 	dac_channel_config.timingMode = kDAC_NonTimingCorrelated;
61 	dac_channel_config.enableTrigger = false;
62 	dac_channel_config.enableDMA = false;
63 	dac_channel_config.enableConversion = true;
64 
65 	DAC_SetChannelConfig(config->base,
66 			(uint32_t)convert_channel_id(channel_cfg->channel_id),
67 			&dac_channel_config);
68 
69 	return 0;
70 };
71 
nxp_gau_dac_write_value(const struct device * dev,uint8_t channel,uint32_t value)72 static int nxp_gau_dac_write_value(const struct device *dev,
73 				uint8_t channel, uint32_t value)
74 {
75 	const struct nxp_gau_dac_config *config = dev->config;
76 
77 	DAC_SetChannelData(config->base,
78 			(uint32_t)convert_channel_id(channel),
79 			(uint16_t)value);
80 	return 0;
81 };
82 
83 static DEVICE_API(dac, nxp_gau_dac_driver_api) = {
84 	.channel_setup = nxp_gau_dac_channel_setup,
85 	.write_value = nxp_gau_dac_write_value,
86 };
87 
nxp_gau_dac_init(const struct device * dev)88 static int nxp_gau_dac_init(const struct device *dev)
89 {
90 	const struct nxp_gau_dac_config *config = dev->config;
91 	dac_config_t dac_cfg;
92 
93 	DAC_GetDefaultConfig(&dac_cfg);
94 
95 	dac_cfg.conversionRate = config->conversion_rate;
96 	dac_cfg.refSource = config->voltage_ref;
97 	dac_cfg.rangeSelect = config->output_range;
98 
99 	DAC_Init(config->base, &dac_cfg);
100 
101 	return 0;
102 };
103 
104 #define NXP_GAU_DAC_INIT(inst)							\
105 										\
106 	const struct nxp_gau_dac_config nxp_gau_dac_##inst##_config = {		\
107 		.base = (DAC_Type *) DT_INST_REG_ADDR(inst),			\
108 		.voltage_ref = DT_INST_ENUM_IDX(inst, nxp_dac_reference),	\
109 		.conversion_rate = DT_INST_ENUM_IDX(inst, nxp_conversion_rate),	\
110 		.output_range = DT_INST_ENUM_IDX(inst,				\
111 						nxp_output_voltage_range),	\
112 	};									\
113 										\
114 										\
115 	DEVICE_DT_INST_DEFINE(inst, &nxp_gau_dac_init, NULL,			\
116 				NULL,						\
117 				&nxp_gau_dac_##inst##_config,			\
118 				POST_KERNEL, CONFIG_DAC_INIT_PRIORITY,		\
119 				&nxp_gau_dac_driver_api);
120 
121 DT_INST_FOREACH_STATUS_OKAY(NXP_GAU_DAC_INIT)
122