1 | /* |
2 | * Copyright 2012-15 Advanced Micro Devices, Inc. |
3 | * |
4 | * Permission is hereby granted, free of charge, to any person obtaining a |
5 | * copy of this software and associated documentation files (the "Software"), |
6 | * to deal in the Software without restriction, including without limitation |
7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, |
8 | * and/or sell copies of the Software, and to permit persons to whom the |
9 | * Software is furnished to do so, subject to the following conditions: |
10 | * |
11 | * The above copyright notice and this permission notice shall be included in |
12 | * all copies or substantial portions of the Software. |
13 | * |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
17 | * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR |
18 | * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
19 | * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
20 | * OTHER DEALINGS IN THE SOFTWARE. |
21 | * |
22 | * Authors: AMD |
23 | * |
24 | */ |
25 | |
26 | /* |
27 | * Pre-requisites: headers required by header of this unit |
28 | */ |
29 | |
30 | #include "dm_services.h" |
31 | |
32 | #include "include/gpio_interface.h" |
33 | #include "include/gpio_service_interface.h" |
34 | #include "hw_gpio.h" |
35 | #include "hw_translate.h" |
36 | #include "hw_factory.h" |
37 | #include "gpio_service.h" |
38 | |
39 | /* |
40 | * Post-requisites: headers required by this unit |
41 | */ |
42 | |
43 | /* |
44 | * This unit |
45 | */ |
46 | |
47 | /* |
48 | * @brief |
49 | * Public API |
50 | */ |
51 | |
52 | enum gpio_result dal_gpio_open( |
53 | struct gpio *gpio, |
54 | enum gpio_mode mode) |
55 | { |
56 | return dal_gpio_open_ex(gpio, mode); |
57 | } |
58 | |
59 | enum gpio_result dal_gpio_open_ex( |
60 | struct gpio *gpio, |
61 | enum gpio_mode mode) |
62 | { |
63 | if (gpio->pin) { |
64 | BREAK_TO_DEBUGGER(); |
65 | return GPIO_RESULT_ALREADY_OPENED; |
66 | } |
67 | |
68 | // No action if allocation failed during gpio construct |
69 | if (!gpio->hw_container.ddc) { |
70 | BREAK_TO_DEBUGGER(); |
71 | return GPIO_RESULT_NON_SPECIFIC_ERROR; |
72 | } |
73 | gpio->mode = mode; |
74 | |
75 | return dal_gpio_service_open(gpio); |
76 | } |
77 | |
78 | enum gpio_result dal_gpio_get_value( |
79 | const struct gpio *gpio, |
80 | uint32_t *value) |
81 | { |
82 | if (!gpio->pin) { |
83 | BREAK_TO_DEBUGGER(); |
84 | return GPIO_RESULT_NULL_HANDLE; |
85 | } |
86 | |
87 | return gpio->pin->funcs->get_value(gpio->pin, value); |
88 | } |
89 | |
90 | enum gpio_result dal_gpio_set_value( |
91 | const struct gpio *gpio, |
92 | uint32_t value) |
93 | { |
94 | if (!gpio->pin) { |
95 | BREAK_TO_DEBUGGER(); |
96 | return GPIO_RESULT_NULL_HANDLE; |
97 | } |
98 | |
99 | return gpio->pin->funcs->set_value(gpio->pin, value); |
100 | } |
101 | |
102 | enum gpio_mode dal_gpio_get_mode( |
103 | const struct gpio *gpio) |
104 | { |
105 | return gpio->mode; |
106 | } |
107 | |
108 | enum gpio_result dal_gpio_lock_pin( |
109 | struct gpio *gpio) |
110 | { |
111 | return dal_gpio_service_lock(service: gpio->service, id: gpio->id, en: gpio->en); |
112 | } |
113 | |
114 | enum gpio_result dal_gpio_unlock_pin( |
115 | struct gpio *gpio) |
116 | { |
117 | return dal_gpio_service_unlock(service: gpio->service, id: gpio->id, en: gpio->en); |
118 | } |
119 | |
120 | enum gpio_result dal_gpio_change_mode( |
121 | struct gpio *gpio, |
122 | enum gpio_mode mode) |
123 | { |
124 | if (!gpio->pin) { |
125 | BREAK_TO_DEBUGGER(); |
126 | return GPIO_RESULT_NULL_HANDLE; |
127 | } |
128 | |
129 | return gpio->pin->funcs->change_mode(gpio->pin, mode); |
130 | } |
131 | |
132 | enum gpio_id dal_gpio_get_id( |
133 | const struct gpio *gpio) |
134 | { |
135 | return gpio->id; |
136 | } |
137 | |
138 | uint32_t dal_gpio_get_enum( |
139 | const struct gpio *gpio) |
140 | { |
141 | return gpio->en; |
142 | } |
143 | |
144 | enum gpio_result dal_gpio_set_config( |
145 | struct gpio *gpio, |
146 | const struct gpio_config_data *config_data) |
147 | { |
148 | if (!gpio->pin) { |
149 | BREAK_TO_DEBUGGER(); |
150 | return GPIO_RESULT_NULL_HANDLE; |
151 | } |
152 | |
153 | return gpio->pin->funcs->set_config(gpio->pin, config_data); |
154 | } |
155 | |
156 | enum gpio_result dal_gpio_get_pin_info( |
157 | const struct gpio *gpio, |
158 | struct gpio_pin_info *pin_info) |
159 | { |
160 | return gpio->service->translate.funcs->id_to_offset( |
161 | gpio->id, gpio->en, pin_info) ? |
162 | GPIO_RESULT_OK : GPIO_RESULT_INVALID_DATA; |
163 | } |
164 | |
165 | enum sync_source dal_gpio_get_sync_source( |
166 | const struct gpio *gpio) |
167 | { |
168 | switch (gpio->id) { |
169 | case GPIO_ID_GENERIC: |
170 | switch (gpio->en) { |
171 | case GPIO_GENERIC_A: |
172 | return SYNC_SOURCE_IO_GENERIC_A; |
173 | case GPIO_GENERIC_B: |
174 | return SYNC_SOURCE_IO_GENERIC_B; |
175 | case GPIO_GENERIC_C: |
176 | return SYNC_SOURCE_IO_GENERIC_C; |
177 | case GPIO_GENERIC_D: |
178 | return SYNC_SOURCE_IO_GENERIC_D; |
179 | case GPIO_GENERIC_E: |
180 | return SYNC_SOURCE_IO_GENERIC_E; |
181 | case GPIO_GENERIC_F: |
182 | return SYNC_SOURCE_IO_GENERIC_F; |
183 | default: |
184 | return SYNC_SOURCE_NONE; |
185 | } |
186 | break; |
187 | case GPIO_ID_SYNC: |
188 | switch (gpio->en) { |
189 | case GPIO_SYNC_HSYNC_A: |
190 | return SYNC_SOURCE_IO_HSYNC_A; |
191 | case GPIO_SYNC_VSYNC_A: |
192 | return SYNC_SOURCE_IO_VSYNC_A; |
193 | case GPIO_SYNC_HSYNC_B: |
194 | return SYNC_SOURCE_IO_HSYNC_B; |
195 | case GPIO_SYNC_VSYNC_B: |
196 | return SYNC_SOURCE_IO_VSYNC_B; |
197 | default: |
198 | return SYNC_SOURCE_NONE; |
199 | } |
200 | break; |
201 | case GPIO_ID_HPD: |
202 | switch (gpio->en) { |
203 | case GPIO_HPD_1: |
204 | return SYNC_SOURCE_IO_HPD1; |
205 | case GPIO_HPD_2: |
206 | return SYNC_SOURCE_IO_HPD2; |
207 | default: |
208 | return SYNC_SOURCE_NONE; |
209 | } |
210 | break; |
211 | case GPIO_ID_GSL: |
212 | switch (gpio->en) { |
213 | case GPIO_GSL_GENLOCK_CLOCK: |
214 | return SYNC_SOURCE_GSL_IO_GENLOCK_CLOCK; |
215 | case GPIO_GSL_GENLOCK_VSYNC: |
216 | return SYNC_SOURCE_GSL_IO_GENLOCK_VSYNC; |
217 | case GPIO_GSL_SWAPLOCK_A: |
218 | return SYNC_SOURCE_GSL_IO_SWAPLOCK_A; |
219 | case GPIO_GSL_SWAPLOCK_B: |
220 | return SYNC_SOURCE_GSL_IO_SWAPLOCK_B; |
221 | default: |
222 | return SYNC_SOURCE_NONE; |
223 | } |
224 | break; |
225 | default: |
226 | return SYNC_SOURCE_NONE; |
227 | } |
228 | } |
229 | |
230 | enum gpio_pin_output_state dal_gpio_get_output_state( |
231 | const struct gpio *gpio) |
232 | { |
233 | return gpio->output_state; |
234 | } |
235 | |
236 | struct hw_ddc *dal_gpio_get_ddc(struct gpio *gpio) |
237 | { |
238 | return gpio->hw_container.ddc; |
239 | } |
240 | |
241 | struct hw_hpd *dal_gpio_get_hpd(struct gpio *gpio) |
242 | { |
243 | return gpio->hw_container.hpd; |
244 | } |
245 | |
246 | struct hw_generic *dal_gpio_get_generic(struct gpio *gpio) |
247 | { |
248 | return gpio->hw_container.generic; |
249 | } |
250 | |
251 | void dal_gpio_close( |
252 | struct gpio *gpio) |
253 | { |
254 | if (!gpio) |
255 | return; |
256 | |
257 | dal_gpio_service_close(service: gpio->service, ptr: &gpio->pin); |
258 | |
259 | gpio->mode = GPIO_MODE_UNKNOWN; |
260 | } |
261 | |
262 | /* |
263 | * @brief |
264 | * Creation and destruction |
265 | */ |
266 | |
267 | struct gpio *dal_gpio_create( |
268 | struct gpio_service *service, |
269 | enum gpio_id id, |
270 | uint32_t en, |
271 | enum gpio_pin_output_state output_state) |
272 | { |
273 | struct gpio *gpio = kzalloc(size: sizeof(struct gpio), GFP_KERNEL); |
274 | |
275 | if (!gpio) { |
276 | ASSERT_CRITICAL(false); |
277 | return NULL; |
278 | } |
279 | |
280 | gpio->service = service; |
281 | gpio->pin = NULL; |
282 | gpio->id = id; |
283 | gpio->en = en; |
284 | gpio->mode = GPIO_MODE_UNKNOWN; |
285 | gpio->output_state = output_state; |
286 | |
287 | //initialize hw_container union based on id |
288 | switch (gpio->id) { |
289 | case GPIO_ID_DDC_DATA: |
290 | gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en); |
291 | break; |
292 | case GPIO_ID_DDC_CLOCK: |
293 | gpio->service->factory.funcs->init_ddc_data(&gpio->hw_container.ddc, service->ctx, id, en); |
294 | break; |
295 | case GPIO_ID_GENERIC: |
296 | gpio->service->factory.funcs->init_generic(&gpio->hw_container.generic, service->ctx, id, en); |
297 | break; |
298 | case GPIO_ID_HPD: |
299 | gpio->service->factory.funcs->init_hpd(&gpio->hw_container.hpd, service->ctx, id, en); |
300 | break; |
301 | // TODO: currently gpio for sync and gsl does not get created, might need it later |
302 | case GPIO_ID_SYNC: |
303 | break; |
304 | case GPIO_ID_GSL: |
305 | break; |
306 | default: |
307 | ASSERT_CRITICAL(false); |
308 | gpio->pin = NULL; |
309 | } |
310 | |
311 | return gpio; |
312 | } |
313 | |
314 | void dal_gpio_destroy( |
315 | struct gpio **gpio) |
316 | { |
317 | if (!gpio || !*gpio) { |
318 | ASSERT_CRITICAL(false); |
319 | return; |
320 | } |
321 | |
322 | switch ((*gpio)->id) { |
323 | case GPIO_ID_DDC_DATA: |
324 | kfree(objp: (*gpio)->hw_container.ddc); |
325 | (*gpio)->hw_container.ddc = NULL; |
326 | break; |
327 | case GPIO_ID_DDC_CLOCK: |
328 | //TODO: might want to change it to init_ddc_clock |
329 | kfree(objp: (*gpio)->hw_container.ddc); |
330 | (*gpio)->hw_container.ddc = NULL; |
331 | break; |
332 | case GPIO_ID_GENERIC: |
333 | kfree(objp: (*gpio)->hw_container.generic); |
334 | (*gpio)->hw_container.generic = NULL; |
335 | break; |
336 | case GPIO_ID_HPD: |
337 | kfree(objp: (*gpio)->hw_container.hpd); |
338 | (*gpio)->hw_container.hpd = NULL; |
339 | break; |
340 | // TODO: currently gpio for sync and gsl does not get created, might need it later |
341 | case GPIO_ID_SYNC: |
342 | break; |
343 | case GPIO_ID_GSL: |
344 | break; |
345 | default: |
346 | break; |
347 | } |
348 | |
349 | kfree(objp: *gpio); |
350 | |
351 | *gpio = NULL; |
352 | } |
353 | |