1 /*
2 * Copyright (c) 2020 Henrik Brix Andersen <henrik@brixandersen.dk>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #define DT_DRV_COMPAT nxp_kinetis_dac
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/dac.h>
11 #include <zephyr/logging/log.h>
12
13 #include <fsl_dac.h>
14
15 LOG_MODULE_REGISTER(dac_mcux_dac, CONFIG_DAC_LOG_LEVEL);
16
17 struct mcux_dac_config {
18 DAC_Type *base;
19 dac_reference_voltage_source_t reference;
20 bool low_power;
21 };
22
23 struct mcux_dac_data {
24 bool configured;
25 };
26
mcux_dac_channel_setup(const struct device * dev,const struct dac_channel_cfg * channel_cfg)27 static int mcux_dac_channel_setup(const struct device *dev,
28 const struct dac_channel_cfg *channel_cfg)
29 {
30 const struct mcux_dac_config *config = dev->config;
31 struct mcux_dac_data *data = dev->data;
32 dac_config_t dac_config;
33
34 if (channel_cfg->channel_id != 0) {
35 LOG_ERR("unsupported channel %d", channel_cfg->channel_id);
36 return -ENOTSUP;
37 }
38
39 if (channel_cfg->resolution != 12) {
40 LOG_ERR("unsupported resolution %d", channel_cfg->resolution);
41 return -ENOTSUP;
42 }
43
44 if (channel_cfg->internal) {
45 LOG_ERR("Internal channels not supported");
46 return -ENOTSUP;
47 }
48
49 DAC_GetDefaultConfig(&dac_config);
50 dac_config.enableLowPowerMode = config->low_power;
51 dac_config.referenceVoltageSource = config->reference;
52
53 DAC_Init(config->base, &dac_config);
54
55 data->configured = true;
56
57 return 0;
58 }
59
mcux_dac_write_value(const struct device * dev,uint8_t channel,uint32_t value)60 static int mcux_dac_write_value(const struct device *dev, uint8_t channel,
61 uint32_t value)
62 {
63 const struct mcux_dac_config *config = dev->config;
64 struct mcux_dac_data *data = dev->data;
65
66 if (!data->configured) {
67 LOG_ERR("channel not initialized");
68 return -EINVAL;
69 }
70
71 if (channel != 0) {
72 LOG_ERR("unsupported channel %d", channel);
73 return -ENOTSUP;
74 }
75
76 if (value >= 4096) {
77 LOG_ERR("value %d out of range", value);
78 return -EINVAL;
79 }
80
81 /* Static operation */
82 DAC_EnableBuffer(config->base, false);
83
84 DAC_SetBufferValue(config->base, 0, value);
85 DAC_Enable(config->base, true);
86
87 return 0;
88 }
89
90 static DEVICE_API(dac, mcux_dac_driver_api) = {
91 .channel_setup = mcux_dac_channel_setup,
92 .write_value = mcux_dac_write_value,
93 };
94
95 #define TO_DAC_VREF_SRC(val) \
96 _DO_CONCAT(kDAC_ReferenceVoltageSourceVref, val)
97
98 #define MCUX_DAC_INIT(n) \
99 static struct mcux_dac_data mcux_dac_data_##n; \
100 \
101 static const struct mcux_dac_config mcux_dac_config_##n = { \
102 .base = (DAC_Type *)DT_INST_REG_ADDR(n), \
103 .reference = \
104 TO_DAC_VREF_SRC(DT_INST_PROP(n, voltage_reference)), \
105 .low_power = DT_INST_PROP(n, low_power_mode), \
106 }; \
107 \
108 DEVICE_DT_INST_DEFINE(n, NULL, NULL, \
109 &mcux_dac_data_##n, \
110 &mcux_dac_config_##n, \
111 POST_KERNEL, CONFIG_DAC_INIT_PRIORITY, \
112 &mcux_dac_driver_api);
113
114 DT_INST_FOREACH_STATUS_OKAY(MCUX_DAC_INIT)
115