1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2024-03-24 Oxlm first version
9 */
10
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "fsl_dac.h"
14 #include "fsl_dac14.h"
15
16 #ifdef RT_USING_DAC
17
18 // #define DRV_DEBUG
19 #define DBG_TAG "drv.dac"
20 #ifdef DRV_DEBUG
21 #define DBG_LVL DBG_LOG
22 #else
23 #define DBG_LVL DBG_INFO
24 #endif /* DRV_DEBUG */
25 #include <rtdbg.h>
26
27 struct mcx_dac {
28 struct rt_dac_device mcxn_dac_device;
29 LPDAC_Type *dac_base;
30 clock_attach_id_t clock_attach_id;
31 clock_div_name_t clock_div_name;
32 uint8_t clock_div;
33 uint8_t referenceVoltageSource; /* kDAC_ReferenceVoltageSourceAlt1, VREFH reference pin */
34 uint8_t SOC_CNTRL_BIT;
35 char *name;
36 };
37
38 static struct mcx_dac mcx_dac_obj[] = {
39 #ifdef BSP_USING_DAC0
40 {
41 .dac_base = DAC0,
42 .clock_attach_id = kFRO_HF_to_DAC0,
43 .clock_div_name = kCLOCK_DivDac0Clk,
44 .clock_div = 1u,
45 .referenceVoltageSource = kDAC_ReferenceVoltageSourceAlt1,
46 .SOC_CNTRL_BIT = 4,
47 .name = "dac0",
48 },
49 #endif
50 #ifdef BSP_USING_DAC1
51 {
52 .dac_base = DAC1,
53 .clock_attach_id = kFRO_HF_to_DAC1,
54 .clock_div_name = kCLOCK_DivDac1Clk,
55 .clock_div = 1u,
56 .referenceVoltageSource = kDAC_ReferenceVoltageSourceAlt1,
57 .SOC_CNTRL_BIT = 5,
58 .name = "dac1",
59 },
60 #endif
61 #ifdef BSP_USING_DAC2
62 {
63 .dac_base = DAC2,
64 .clock_attach_id = kFRO_HF_to_DAC2,
65 .clock_div_name = kCLOCK_DivDac2Clk,
66 .clock_div = 1u,
67 .referenceVoltageSource = kDAC_ReferenceVoltageSourceAlt1,
68 .SOC_CNTRL_BIT = 6,
69 .name = "dac2",
70 },
71 #endif
72
73 };
74
mcxn_dac_disabled(struct rt_dac_device * device,rt_uint32_t channel)75 rt_err_t mcxn_dac_disabled(struct rt_dac_device *device, rt_uint32_t channel) {
76 RT_ASSERT(device != RT_NULL);
77 struct mcx_dac *dac = (struct mcx_dac *)device->parent.user_data;
78
79 if (dac->dac_base == DAC2) {
80 DAC14_Deinit(dac->dac_base);
81 } else {
82 DAC_Deinit(dac->dac_base);
83 }
84 return RT_EOK;
85 }
86
mcxn_dac_enabled(struct rt_dac_device * device,rt_uint32_t channel)87 rt_err_t mcxn_dac_enabled(struct rt_dac_device *device, rt_uint32_t channel) {
88 RT_ASSERT(device != RT_NULL);
89 struct mcx_dac *dac = (struct mcx_dac *)device->parent.user_data;
90 dac_config_t dacConfigStruct;
91 dac14_config_t dac14ConfigStruct;
92
93 if (dac->dac_base == DAC2) {
94 DAC14_GetDefaultConfig(&dac14ConfigStruct);
95 dac14ConfigStruct.enableOpampBuffer = true;
96 dac14ConfigStruct.enableDAC = true;
97 DAC14_Init(dac->dac_base, &dac14ConfigStruct);
98 } else {
99 DAC_GetDefaultConfig(&dacConfigStruct);
100 dacConfigStruct.referenceVoltageSource = dac->referenceVoltageSource;
101 DAC_Init(dac->dac_base, &dacConfigStruct);
102 DAC_Enable(dac->dac_base, RT_TRUE);
103 }
104
105 return RT_EOK;
106 }
107
mcxn_dac_write(struct rt_dac_device * device,rt_uint32_t channel,rt_uint32_t * value)108 rt_err_t mcxn_dac_write(struct rt_dac_device *device, rt_uint32_t channel, rt_uint32_t *value) {
109 RT_ASSERT(device != RT_NULL);
110 struct mcx_dac *dac = (struct mcx_dac *)device->parent.user_data;
111
112 if (dac->dac_base == DAC2) {
113 if (*value > 0x3FFFU) {
114 *value = 0x3FFFU;
115 }
116 DAC14_SetData(dac->dac_base, *value);
117 } else {
118 if (*value > 0xFFFU) {
119 *value = 0xFFFU;
120 }
121 DAC_SetData(dac->dac_base, *value);
122 }
123 return RT_EOK;
124 }
125
126 struct rt_dac_ops mcxn_dac_ops = {
127 .disabled = mcxn_dac_disabled,
128 .enabled = mcxn_dac_enabled,
129 .convert = mcxn_dac_write,
130 };
131
mcxn_dac_init(void)132 static int mcxn_dac_init(void) {
133 int i;
134 int dac_num = sizeof(mcx_dac_obj) / sizeof(struct mcx_dac);
135
136 for (i = 0; i < dac_num; i++) {
137 CLOCK_SetClkDiv(mcx_dac_obj[i].clock_div_name, mcx_dac_obj[i].clock_div);
138 CLOCK_AttachClk(mcx_dac_obj[i].clock_attach_id);
139
140 SPC0->ACTIVE_CFG1 |= 0x01; // Enable VREF
141 SPC0->ACTIVE_CFG1 |= (0x01 << mcx_dac_obj[i].SOC_CNTRL_BIT);
142
143 if (RT_EOK != rt_hw_dac_register(&mcx_dac_obj[i].mcxn_dac_device, mcx_dac_obj[i].name, &mcxn_dac_ops,
144 (void *)(mcx_dac_obj + i))) {
145 LOG_E("%s register failed", mcx_dac_obj[i].name);
146 return -RT_ERROR;
147 }
148 }
149
150 return RT_EOK;
151 }
152 INIT_DEVICE_EXPORT(mcxn_dac_init);
153
154 #endif
155