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