1 // Copyright 2019-2020 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #include <string.h>
17 #include "esp_log.h"
18 #include "esp_err.h"
19 #include "esp_pm.h"
20 #include "freertos/FreeRTOS.h"
21 #include "freertos/semphr.h"
22 #include "freertos/timers.h"
23 #include "driver/rtc_io.h"
24 #include "driver/dac.h"
25 #include "soc/dac_periph.h"
26 #include "hal/dac_hal.h"
27 
28 static const char *DAC_TAG = "DAC";
29 
30 #define DAC_CHECK(a, str, ret_val) ({                                               \
31     if (!(a)) {                                                                     \
32         ESP_LOGE(DAC_TAG,"%s:%d (%s):%s", __FILE__, __LINE__, __FUNCTION__, str);   \
33         return (ret_val);                                                           \
34     }                                                                               \
35 })
36 
37 extern portMUX_TYPE rtc_spinlock; //TODO: Will be placed in the appropriate position after the rtc module is finished.
38 #define DAC_ENTER_CRITICAL()  portENTER_CRITICAL(&rtc_spinlock)
39 #define DAC_EXIT_CRITICAL()  portEXIT_CRITICAL(&rtc_spinlock)
40 
41 #ifdef CONFIG_PM_ENABLE
42 static esp_pm_lock_handle_t s_dac_digi_lock = NULL;
43 #endif  //CONFIG_PM_ENABLE
44 
45 /*---------------------------------------------------------------
46                     Digital controller setting
47 ---------------------------------------------------------------*/
48 
dac_digi_init(void)49 esp_err_t dac_digi_init(void)
50 {
51     DAC_ENTER_CRITICAL();
52     dac_hal_digi_init();
53     DAC_EXIT_CRITICAL();
54 
55     return ESP_OK;
56 }
57 
dac_digi_deinit(void)58 esp_err_t dac_digi_deinit(void)
59 {
60 #ifdef CONFIG_PM_ENABLE
61     if (s_dac_digi_lock) {
62         esp_pm_lock_delete(s_dac_digi_lock);
63         s_dac_digi_lock = NULL;
64     }
65 #endif
66     DAC_ENTER_CRITICAL();
67     dac_hal_digi_deinit();
68     DAC_EXIT_CRITICAL();
69 
70     return ESP_OK;
71 }
72 
dac_digi_controller_config(const dac_digi_config_t * cfg)73 esp_err_t dac_digi_controller_config(const dac_digi_config_t *cfg)
74 {
75     DAC_CHECK(cfg->mode < DAC_CONV_MAX, "DAC mode error", ESP_ERR_INVALID_ARG);
76     DAC_CHECK(cfg->interval > 0 && cfg->interval < 4096, "DAC interval error", ESP_ERR_INVALID_ARG);
77     DAC_CHECK(cfg->dig_clk.div_num < 256, "DAC clk div_num error", ESP_ERR_INVALID_ARG);
78     DAC_CHECK(cfg->dig_clk.div_b > 0 && cfg->dig_clk.div_b < 64, "DAC clk div_b error", ESP_ERR_INVALID_ARG);
79     DAC_CHECK(cfg->dig_clk.div_a < 64, "DAC clk div_a error", ESP_ERR_INVALID_ARG);
80 #ifdef CONFIG_PM_ENABLE
81     esp_err_t err;
82     if (s_dac_digi_lock == NULL) {
83         if (cfg->dig_clk.use_apll) {
84             err = esp_pm_lock_create(ESP_PM_NO_LIGHT_SLEEP, 0, "dac_dma", &s_dac_digi_lock);
85         } else {
86             err = esp_pm_lock_create(ESP_PM_APB_FREQ_MAX, 0, "dac_dma", &s_dac_digi_lock);
87         }
88         if (err != ESP_OK) {
89             s_dac_digi_lock = NULL;
90             ESP_LOGE(DAC_TAG, "DAC-DMA pm lock error");
91             return err;
92         }
93     }
94 #endif //CONFIG_PM_ENABLE
95 
96     DAC_ENTER_CRITICAL();
97     dac_hal_digi_controller_config(cfg);
98     DAC_EXIT_CRITICAL();
99 
100     return ESP_OK;
101 }
102 
dac_digi_start(void)103 esp_err_t dac_digi_start(void)
104 {
105 #ifdef CONFIG_PM_ENABLE
106     DAC_CHECK((s_dac_digi_lock), "Should start after call `dac_digi_controller_config`", ESP_FAIL);
107     esp_pm_lock_acquire(s_dac_digi_lock);
108 #endif
109     DAC_ENTER_CRITICAL();
110     dac_hal_digi_start();
111     DAC_EXIT_CRITICAL();
112 
113     return ESP_OK;
114 }
115 
dac_digi_stop(void)116 esp_err_t dac_digi_stop(void)
117 {
118 #ifdef CONFIG_PM_ENABLE
119     if (s_dac_digi_lock) {
120         esp_pm_lock_release(s_dac_digi_lock);
121     }
122 #endif
123     DAC_ENTER_CRITICAL();
124     dac_hal_digi_stop();
125     DAC_EXIT_CRITICAL();
126 
127     return ESP_OK;
128 }
129 
dac_digi_fifo_reset(void)130 esp_err_t dac_digi_fifo_reset(void)
131 {
132     DAC_ENTER_CRITICAL();
133     dac_hal_digi_fifo_reset();
134     DAC_EXIT_CRITICAL();
135 
136     return ESP_OK;
137 }
138 
dac_digi_reset(void)139 esp_err_t dac_digi_reset(void)
140 {
141     DAC_ENTER_CRITICAL();
142     dac_hal_digi_reset();
143     DAC_EXIT_CRITICAL();
144 
145     return ESP_OK;
146 }
147