1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * Description: Low-power management operations for peripheral devices.
15 *
16 * Create: 2021-4-28
17 */
18
19 #include "lpm_dev_ops.h"
20 #include "securec.h"
21 #include "irmalloc.h"
22 #include "soc_osal.h"
23
24 #define ops_(a, b) ((a) ? (a) : (b))
25
26 static lpm_dev_ops_t *g_dev_ops = NULL;
27 static lpm_clock_init_callback g_display_clocks_init_handler = NULL;
28
lpm_dev_ops_init(void)29 bool lpm_dev_ops_init(void)
30 {
31 if (g_dev_ops != NULL) {
32 return false;
33 }
34 uint32_t irq_sts = osal_irq_lock();
35 g_dev_ops = irmalloc(sizeof(lpm_dev_ops_t) * DEV_MAX);
36 if (g_dev_ops == NULL) {
37 osal_irq_restore(irq_sts);
38 return false;
39 }
40 if (memset_s(g_dev_ops, sizeof(lpm_dev_ops_t) * DEV_MAX, 0, sizeof(lpm_dev_ops_t) * DEV_MAX) != EOK) {
41 osal_irq_restore(irq_sts);
42 return false;
43 }
44 osal_irq_restore(irq_sts);
45
46 return true;
47 }
48
lpm_dev_ops_deinit(void)49 bool lpm_dev_ops_deinit(void)
50 {
51 if (g_dev_ops == NULL) {
52 return false;
53 }
54 uint32_t irq_sts = osal_irq_lock();
55 irfree(g_dev_ops);
56 g_dev_ops = NULL;
57 osal_irq_restore(irq_sts);
58
59 return true;
60 }
61
lpm_dev_ops_register(lpm_dev_id_t id,lpm_dev_ops_t * ops)62 bool lpm_dev_ops_register(lpm_dev_id_t id, lpm_dev_ops_t *ops)
63 {
64 if (id >= DEV_MAX || (g_dev_ops == NULL) || (ops == NULL)) {
65 return false;
66 }
67 uint32_t irq_sts = osal_irq_lock();
68 if (memcpy_s(&g_dev_ops[id], sizeof(lpm_dev_ops_t), ops, sizeof(lpm_dev_ops_t)) != EOK) {
69 osal_irq_restore(irq_sts);
70 return false;
71 }
72 osal_irq_restore(irq_sts);
73
74 return true;
75 }
76
lpm_dev_ops_unregister(lpm_dev_id_t id)77 bool lpm_dev_ops_unregister(lpm_dev_id_t id)
78 {
79 if (id >= DEV_MAX || (g_dev_ops == NULL)) {
80 return false;
81 }
82 uint32_t irq_sts = osal_irq_lock();
83 if (memset_s(&g_dev_ops[id], sizeof(lpm_dev_ops_t), 0, sizeof(lpm_dev_ops_t)) != EOK) {
84 osal_irq_restore(irq_sts);
85 return false;
86 }
87 osal_irq_restore(irq_sts);
88
89 return true;
90 }
91
lpm_dev_ops_update(lpm_dev_id_t id,lpm_dev_ops_t * ops)92 int lpm_dev_ops_update(lpm_dev_id_t id, lpm_dev_ops_t *ops)
93 {
94 if (id >= DEV_MAX || ops == NULL) {
95 return LPM_RET_ERR;
96 }
97
98 if (g_dev_ops == NULL) {
99 return LPM_RET_UNINIT;
100 }
101 uint32_t irq_sts = osal_irq_lock();
102 g_dev_ops[id].power_on = ops_(ops->power_on, g_dev_ops[id].power_on);
103 g_dev_ops[id].power_sts = ops_(ops->power_sts, g_dev_ops[id].power_sts);
104 g_dev_ops[id].set_voltage = ops_(ops->set_voltage, g_dev_ops[id].set_voltage);
105 g_dev_ops[id].get_voltage = ops_(ops->get_voltage, g_dev_ops[id].get_voltage);
106 g_dev_ops[id].clock_en = ops_(ops->clock_en, g_dev_ops[id].clock_en);
107 g_dev_ops[id].clock_sts = ops_(ops->clock_sts, g_dev_ops[id].clock_sts);
108 g_dev_ops[id].set_freq = ops_(ops->set_freq, g_dev_ops[id].set_freq);
109 g_dev_ops[id].get_freq = ops_(ops->get_freq, g_dev_ops[id].get_freq);
110 g_dev_ops[id].set_div_num = ops_(ops->set_div_num, g_dev_ops[id].set_div_num);
111 g_dev_ops[id].get_div_num = ops_(ops->get_div_num, g_dev_ops[id].get_div_num);
112 g_dev_ops[id].sub_clken = ops_(ops->sub_clken, g_dev_ops[id].sub_clken);
113 g_dev_ops[id].resume = ops_(ops->resume, g_dev_ops[id].resume);
114 g_dev_ops[id].suspend = ops_(ops->suspend, g_dev_ops[id].suspend);
115 osal_irq_restore(irq_sts);
116 return LPM_RET_OK;
117 }
118
lpm_dev_power_on(lpm_dev_id_t id,bool on)119 int lpm_dev_power_on(lpm_dev_id_t id, bool on)
120 {
121 if (g_dev_ops == NULL) {
122 return LPM_RET_ERR;
123 }
124 if (g_dev_ops[id].power_on) {
125 return g_dev_ops[id].power_on(on);
126 } else {
127 return LPM_RET_NOREG;
128 }
129 }
130
lpm_dev_get_power_sts(lpm_dev_id_t id)131 int lpm_dev_get_power_sts(lpm_dev_id_t id)
132 {
133 if (g_dev_ops == NULL) {
134 return LPM_RET_ERR;
135 }
136 if (g_dev_ops[id].power_sts) {
137 return g_dev_ops[id].power_sts();
138 } else {
139 return LPM_RET_NOREG;
140 }
141 }
142
lpm_dev_set_voltage(lpm_dev_id_t id,int vset)143 int lpm_dev_set_voltage(lpm_dev_id_t id, int vset)
144 {
145 if (g_dev_ops == NULL) {
146 return LPM_RET_ERR;
147 }
148 if (g_dev_ops[id].set_voltage) {
149 return g_dev_ops[id].set_voltage(vset);
150 } else {
151 return LPM_RET_NOREG;
152 }
153 }
154
lpm_dev_get_voltage(lpm_dev_id_t id)155 int lpm_dev_get_voltage(lpm_dev_id_t id)
156 {
157 if (g_dev_ops == NULL) {
158 return LPM_RET_ERR;
159 }
160 if (g_dev_ops[id].get_voltage) {
161 return g_dev_ops[id].get_voltage();
162 } else {
163 return LPM_RET_NOREG;
164 }
165 }
166
lpm_dev_clock_en(lpm_dev_id_t id,bool on)167 int lpm_dev_clock_en(lpm_dev_id_t id, bool on)
168 {
169 if (g_dev_ops == NULL) {
170 return LPM_RET_ERR;
171 }
172 if (g_dev_ops[id].clock_en) {
173 return g_dev_ops[id].clock_en(on);
174 } else {
175 return LPM_RET_NOREG;
176 }
177 }
178
lpm_dev_get_clock_sts(lpm_dev_id_t id)179 int lpm_dev_get_clock_sts(lpm_dev_id_t id)
180 {
181 if (g_dev_ops == NULL) {
182 return LPM_RET_ERR;
183 }
184 if (g_dev_ops[id].clock_sts) {
185 return g_dev_ops[id].clock_sts();
186 } else {
187 return LPM_RET_NOREG;
188 }
189 }
190
lpm_dev_set_freq(lpm_dev_id_t id,int freq)191 int lpm_dev_set_freq(lpm_dev_id_t id, int freq)
192 {
193 if (g_dev_ops == NULL) {
194 return LPM_RET_ERR;
195 }
196 if (g_dev_ops[id].set_freq) {
197 return g_dev_ops[id].set_freq(freq);
198 } else {
199 return LPM_RET_NOREG;
200 }
201 }
202
lpm_dev_get_freq(lpm_dev_id_t id)203 int lpm_dev_get_freq(lpm_dev_id_t id)
204 {
205 if (g_dev_ops == NULL) {
206 return LPM_RET_ERR;
207 }
208 if (g_dev_ops[id].get_freq) {
209 return g_dev_ops[id].get_freq();
210 } else {
211 return LPM_RET_NOREG;
212 }
213 }
214
lpm_dev_set_div_num(lpm_dev_id_t id,int clk_div)215 int lpm_dev_set_div_num(lpm_dev_id_t id, int clk_div)
216 {
217 if (g_dev_ops == NULL) {
218 return LPM_RET_ERR;
219 }
220 if (g_dev_ops[id].set_div_num) {
221 return g_dev_ops[id].set_div_num(clk_div);
222 } else {
223 return LPM_RET_NOREG;
224 }
225 }
226
lpm_dev_get_div_num(lpm_dev_id_t id)227 int lpm_dev_get_div_num(lpm_dev_id_t id)
228 {
229 if (g_dev_ops == NULL) {
230 return LPM_RET_ERR;
231 }
232 if (g_dev_ops[id].get_div_num) {
233 return g_dev_ops[id].get_div_num();
234 } else {
235 return LPM_RET_NOREG;
236 }
237 }
238
lpm_dev_sub_bus_clken(lpm_dev_id_t id,int bus,bool on)239 int lpm_dev_sub_bus_clken(lpm_dev_id_t id, int bus, bool on)
240 {
241 if (g_dev_ops == NULL) {
242 return LPM_RET_ERR;
243 }
244 if (g_dev_ops[id].sub_clken) {
245 return g_dev_ops[id].sub_clken(bus, on);
246 } else {
247 return LPM_RET_NOREG;
248 }
249 }
250
lpm_display_clocks_init_register_callback(lpm_clock_init_callback callback)251 void lpm_display_clocks_init_register_callback(lpm_clock_init_callback callback)
252 {
253 if (callback != NULL) {
254 g_display_clocks_init_handler = callback;
255 }
256 }
257
lpm_display_clocks_init(void)258 void lpm_display_clocks_init(void)
259 {
260 if (g_display_clocks_init_handler != NULL) {
261 g_display_clocks_init_handler();
262 }
263 }