xref: /openbsd-src/sys/dev/pci/drm/amd/display/dc/gpio/gpio_service.c (revision 4dffd2f41b5f094a6904331cec9bf3b5d08cc1c6)
1fb4d8502Sjsg /*
2fb4d8502Sjsg  * Copyright 2012-15 Advanced Micro Devices, Inc.
3fb4d8502Sjsg  *
4fb4d8502Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5fb4d8502Sjsg  * copy of this software and associated documentation files (the "Software"),
6fb4d8502Sjsg  * to deal in the Software without restriction, including without limitation
7fb4d8502Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fb4d8502Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9fb4d8502Sjsg  * Software is furnished to do so, subject to the following conditions:
10fb4d8502Sjsg  *
11fb4d8502Sjsg  * The above copyright notice and this permission notice shall be included in
12fb4d8502Sjsg  * all copies or substantial portions of the Software.
13fb4d8502Sjsg  *
14fb4d8502Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fb4d8502Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fb4d8502Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17fb4d8502Sjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18fb4d8502Sjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19fb4d8502Sjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20fb4d8502Sjsg  * OTHER DEALINGS IN THE SOFTWARE.
21fb4d8502Sjsg  *
22fb4d8502Sjsg  * Authors: AMD
23fb4d8502Sjsg  *
24fb4d8502Sjsg  */
25fb4d8502Sjsg 
26fb4d8502Sjsg /*
27fb4d8502Sjsg  * Pre-requisites: headers required by header of this unit
28fb4d8502Sjsg  */
29fb4d8502Sjsg 
30fb4d8502Sjsg #include "dm_services.h"
31fb4d8502Sjsg #include "include/gpio_interface.h"
32fb4d8502Sjsg #include "include/gpio_service_interface.h"
33fb4d8502Sjsg #include "hw_translate.h"
34fb4d8502Sjsg #include "hw_factory.h"
35fb4d8502Sjsg 
36fb4d8502Sjsg /*
37fb4d8502Sjsg  * Header of this unit
38fb4d8502Sjsg  */
39fb4d8502Sjsg 
40fb4d8502Sjsg #include "gpio_service.h"
41fb4d8502Sjsg 
42fb4d8502Sjsg /*
43fb4d8502Sjsg  * Post-requisites: headers required by this unit
44fb4d8502Sjsg  */
45fb4d8502Sjsg 
46fb4d8502Sjsg #include "hw_gpio.h"
47fb4d8502Sjsg 
48fb4d8502Sjsg /*
49fb4d8502Sjsg  * @brief
50fb4d8502Sjsg  * Public API.
51fb4d8502Sjsg  */
52fb4d8502Sjsg 
53fb4d8502Sjsg struct gpio_service *dal_gpio_service_create(
545ca02815Sjsg 	enum dce_version dce_version,
555ca02815Sjsg 	enum dce_environment dce_environment,
56fb4d8502Sjsg 	struct dc_context *ctx)
57fb4d8502Sjsg {
58fb4d8502Sjsg 	struct gpio_service *service;
59*4dffd2f4Sjsg 	int32_t index_of_id;
60fb4d8502Sjsg 
61fb4d8502Sjsg 	service = kzalloc(sizeof(struct gpio_service), GFP_KERNEL);
62fb4d8502Sjsg 
63fb4d8502Sjsg 	if (!service) {
64fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
65fb4d8502Sjsg 		return NULL;
66fb4d8502Sjsg 	}
67fb4d8502Sjsg 
685ca02815Sjsg 	if (!dal_hw_translate_init(&service->translate, dce_version,
695ca02815Sjsg 			dce_environment)) {
70fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
71fb4d8502Sjsg 		goto failure_1;
72fb4d8502Sjsg 	}
73fb4d8502Sjsg 
745ca02815Sjsg 	if (!dal_hw_factory_init(&service->factory, dce_version,
755ca02815Sjsg 			dce_environment)) {
76fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
77fb4d8502Sjsg 		goto failure_1;
78fb4d8502Sjsg 	}
79fb4d8502Sjsg 
80c349dbc7Sjsg 	/* allocate and initialize busyness storage */
81fb4d8502Sjsg 	{
82fb4d8502Sjsg 		index_of_id = 0;
83fb4d8502Sjsg 		service->ctx = ctx;
84fb4d8502Sjsg 
85fb4d8502Sjsg 		do {
86fb4d8502Sjsg 			uint32_t number_of_bits =
87fb4d8502Sjsg 				service->factory.number_of_pins[index_of_id];
88c349dbc7Sjsg 			uint32_t i = 0;
89fb4d8502Sjsg 
90fb4d8502Sjsg 			if (number_of_bits)  {
91c349dbc7Sjsg 				service->busyness[index_of_id] =
92c349dbc7Sjsg 					kcalloc(number_of_bits, sizeof(char),
93fb4d8502Sjsg 						GFP_KERNEL);
94fb4d8502Sjsg 
95c349dbc7Sjsg 				if (!service->busyness[index_of_id]) {
96fb4d8502Sjsg 					BREAK_TO_DEBUGGER();
97fb4d8502Sjsg 					goto failure_2;
98fb4d8502Sjsg 				}
99fb4d8502Sjsg 
100fb4d8502Sjsg 				do {
101c349dbc7Sjsg 					service->busyness[index_of_id][i] = 0;
102c349dbc7Sjsg 					++i;
103c349dbc7Sjsg 				} while (i < number_of_bits);
104c349dbc7Sjsg 			} else {
105c349dbc7Sjsg 				service->busyness[index_of_id] = NULL;
106c349dbc7Sjsg 			}
107fb4d8502Sjsg 
108fb4d8502Sjsg 			++index_of_id;
109fb4d8502Sjsg 		} while (index_of_id < GPIO_ID_COUNT);
110fb4d8502Sjsg 	}
111fb4d8502Sjsg 
112fb4d8502Sjsg 	return service;
113fb4d8502Sjsg 
114fb4d8502Sjsg failure_2:
115*4dffd2f4Sjsg 	while (index_of_id > 0) {
116fb4d8502Sjsg 		--index_of_id;
117c349dbc7Sjsg 		kfree(service->busyness[index_of_id]);
118fb4d8502Sjsg 	}
119fb4d8502Sjsg 
120fb4d8502Sjsg failure_1:
121fb4d8502Sjsg 	kfree(service);
122fb4d8502Sjsg 
123fb4d8502Sjsg 	return NULL;
124fb4d8502Sjsg }
125fb4d8502Sjsg 
126fb4d8502Sjsg struct gpio *dal_gpio_service_create_irq(
127fb4d8502Sjsg 	struct gpio_service *service,
128fb4d8502Sjsg 	uint32_t offset,
129fb4d8502Sjsg 	uint32_t mask)
130fb4d8502Sjsg {
131fb4d8502Sjsg 	enum gpio_id id;
132fb4d8502Sjsg 	uint32_t en;
133fb4d8502Sjsg 
134fb4d8502Sjsg 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
135fb4d8502Sjsg 		ASSERT_CRITICAL(false);
136fb4d8502Sjsg 		return NULL;
137fb4d8502Sjsg 	}
138fb4d8502Sjsg 
139fb4d8502Sjsg 	return dal_gpio_create_irq(service, id, en);
140fb4d8502Sjsg }
141fb4d8502Sjsg 
142c349dbc7Sjsg struct gpio *dal_gpio_service_create_generic_mux(
143c349dbc7Sjsg 	struct gpio_service *service,
144c349dbc7Sjsg 	uint32_t offset,
145c349dbc7Sjsg 	uint32_t mask)
146c349dbc7Sjsg {
147c349dbc7Sjsg 	enum gpio_id id;
148c349dbc7Sjsg 	uint32_t en;
149c349dbc7Sjsg 	struct gpio *generic;
150c349dbc7Sjsg 
151c349dbc7Sjsg 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {
152c349dbc7Sjsg 		ASSERT_CRITICAL(false);
153c349dbc7Sjsg 		return NULL;
154c349dbc7Sjsg 	}
155c349dbc7Sjsg 
156c349dbc7Sjsg 	generic = dal_gpio_create(
157c349dbc7Sjsg 		service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
158c349dbc7Sjsg 
159c349dbc7Sjsg 	return generic;
160c349dbc7Sjsg }
161c349dbc7Sjsg 
162c349dbc7Sjsg void dal_gpio_destroy_generic_mux(
163c349dbc7Sjsg 	struct gpio **mux)
164c349dbc7Sjsg {
165c349dbc7Sjsg 	if (!mux || !*mux) {
166c349dbc7Sjsg 		ASSERT_CRITICAL(false);
167c349dbc7Sjsg 		return;
168c349dbc7Sjsg 	}
169c349dbc7Sjsg 
170c349dbc7Sjsg 	dal_gpio_destroy(mux);
171c349dbc7Sjsg 	kfree(*mux);
172c349dbc7Sjsg 
173c349dbc7Sjsg 	*mux = NULL;
174c349dbc7Sjsg }
175c349dbc7Sjsg 
176c349dbc7Sjsg struct gpio_pin_info dal_gpio_get_generic_pin_info(
177c349dbc7Sjsg 	struct gpio_service *service,
178c349dbc7Sjsg 	enum gpio_id id,
179c349dbc7Sjsg 	uint32_t en)
180c349dbc7Sjsg {
181c349dbc7Sjsg 	struct gpio_pin_info pin;
182c349dbc7Sjsg 
183c349dbc7Sjsg 	if (service->translate.funcs->id_to_offset) {
184c349dbc7Sjsg 		service->translate.funcs->id_to_offset(id, en, &pin);
185c349dbc7Sjsg 	} else {
186c349dbc7Sjsg 		pin.mask = 0xFFFFFFFF;
187c349dbc7Sjsg 		pin.offset = 0xFFFFFFFF;
188c349dbc7Sjsg 	}
189c349dbc7Sjsg 
190c349dbc7Sjsg 	return pin;
191c349dbc7Sjsg }
192c349dbc7Sjsg 
193fb4d8502Sjsg void dal_gpio_service_destroy(
194fb4d8502Sjsg 	struct gpio_service **ptr)
195fb4d8502Sjsg {
196fb4d8502Sjsg 	if (!ptr || !*ptr) {
197fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
198fb4d8502Sjsg 		return;
199fb4d8502Sjsg 	}
200fb4d8502Sjsg 
201fb4d8502Sjsg 	/* free business storage */
202fb4d8502Sjsg 	{
203fb4d8502Sjsg 		uint32_t index_of_id = 0;
204fb4d8502Sjsg 
205fb4d8502Sjsg 		do {
206c349dbc7Sjsg 			kfree((*ptr)->busyness[index_of_id]);
207fb4d8502Sjsg 
208fb4d8502Sjsg 			++index_of_id;
209fb4d8502Sjsg 		} while (index_of_id < GPIO_ID_COUNT);
210fb4d8502Sjsg 	}
211fb4d8502Sjsg 
212fb4d8502Sjsg 	kfree(*ptr);
213fb4d8502Sjsg 
214fb4d8502Sjsg 	*ptr = NULL;
215fb4d8502Sjsg }
216fb4d8502Sjsg 
217c349dbc7Sjsg enum gpio_result dal_mux_setup_config(
218c349dbc7Sjsg 	struct gpio *mux,
219c349dbc7Sjsg 	struct gpio_generic_mux_config *config)
220c349dbc7Sjsg {
221c349dbc7Sjsg 	struct gpio_config_data config_data;
222c349dbc7Sjsg 
223c349dbc7Sjsg 	if (!config)
224c349dbc7Sjsg 		return GPIO_RESULT_INVALID_DATA;
225c349dbc7Sjsg 
226c349dbc7Sjsg 	config_data.config.generic_mux = *config;
227c349dbc7Sjsg 	config_data.type = GPIO_CONFIG_TYPE_GENERIC_MUX;
228c349dbc7Sjsg 
229c349dbc7Sjsg 	return dal_gpio_set_config(mux, &config_data);
230c349dbc7Sjsg }
231c349dbc7Sjsg 
232fb4d8502Sjsg /*
233fb4d8502Sjsg  * @brief
234fb4d8502Sjsg  * Private API.
235fb4d8502Sjsg  */
236fb4d8502Sjsg 
237fb4d8502Sjsg static bool is_pin_busy(
238fb4d8502Sjsg 	const struct gpio_service *service,
239fb4d8502Sjsg 	enum gpio_id id,
240fb4d8502Sjsg 	uint32_t en)
241fb4d8502Sjsg {
242a691e319Sjsg 	if (id == GPIO_ID_UNKNOWN)
243a691e319Sjsg 		return false;
244a691e319Sjsg 
245c349dbc7Sjsg 	return service->busyness[id][en];
246fb4d8502Sjsg }
247fb4d8502Sjsg 
248fb4d8502Sjsg static void set_pin_busy(
249fb4d8502Sjsg 	struct gpio_service *service,
250fb4d8502Sjsg 	enum gpio_id id,
251fb4d8502Sjsg 	uint32_t en)
252fb4d8502Sjsg {
253a691e319Sjsg 	if (id == GPIO_ID_UNKNOWN)
254a691e319Sjsg 		return;
255a691e319Sjsg 
256c349dbc7Sjsg 	service->busyness[id][en] = true;
257fb4d8502Sjsg }
258fb4d8502Sjsg 
259fb4d8502Sjsg static void set_pin_free(
260fb4d8502Sjsg 	struct gpio_service *service,
261fb4d8502Sjsg 	enum gpio_id id,
262fb4d8502Sjsg 	uint32_t en)
263fb4d8502Sjsg {
264a691e319Sjsg 	if (id == GPIO_ID_UNKNOWN)
265a691e319Sjsg 		return;
266a691e319Sjsg 
267c349dbc7Sjsg 	service->busyness[id][en] = false;
268c349dbc7Sjsg }
269fb4d8502Sjsg 
270c349dbc7Sjsg enum gpio_result dal_gpio_service_lock(
271c349dbc7Sjsg 	struct gpio_service *service,
272c349dbc7Sjsg 	enum gpio_id id,
273c349dbc7Sjsg 	uint32_t en)
274c349dbc7Sjsg {
275a691e319Sjsg 	if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) {
276c349dbc7Sjsg 		ASSERT_CRITICAL(false);
277c349dbc7Sjsg 		return GPIO_RESULT_OPEN_FAILED;
278c349dbc7Sjsg 	}
279c349dbc7Sjsg 
280c349dbc7Sjsg 	set_pin_busy(service, id, en);
281c349dbc7Sjsg 	return GPIO_RESULT_OK;
282c349dbc7Sjsg }
283c349dbc7Sjsg 
284c349dbc7Sjsg enum gpio_result dal_gpio_service_unlock(
285c349dbc7Sjsg 	struct gpio_service *service,
286c349dbc7Sjsg 	enum gpio_id id,
287c349dbc7Sjsg 	uint32_t en)
288c349dbc7Sjsg {
289a691e319Sjsg 	if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) {
290c349dbc7Sjsg 		ASSERT_CRITICAL(false);
291c349dbc7Sjsg 		return GPIO_RESULT_OPEN_FAILED;
292c349dbc7Sjsg 	}
293c349dbc7Sjsg 
294c349dbc7Sjsg 	set_pin_free(service, id, en);
295c349dbc7Sjsg 	return GPIO_RESULT_OK;
296fb4d8502Sjsg }
297fb4d8502Sjsg 
298fb4d8502Sjsg enum gpio_result dal_gpio_service_open(
299c349dbc7Sjsg 	struct gpio *gpio)
300fb4d8502Sjsg {
301c349dbc7Sjsg 	struct gpio_service *service = gpio->service;
302c349dbc7Sjsg 	enum gpio_id id = gpio->id;
303c349dbc7Sjsg 	uint32_t en = gpio->en;
304c349dbc7Sjsg 	enum gpio_mode mode = gpio->mode;
305c349dbc7Sjsg 
306c349dbc7Sjsg 	struct hw_gpio_pin **pin = &gpio->pin;
307c349dbc7Sjsg 
308fb4d8502Sjsg 
309fb4d8502Sjsg 	if (!service->busyness[id]) {
310fb4d8502Sjsg 		ASSERT_CRITICAL(false);
311fb4d8502Sjsg 		return GPIO_RESULT_OPEN_FAILED;
312fb4d8502Sjsg 	}
313fb4d8502Sjsg 
314fb4d8502Sjsg 	if (is_pin_busy(service, id, en)) {
315fb4d8502Sjsg 		ASSERT_CRITICAL(false);
316fb4d8502Sjsg 		return GPIO_RESULT_DEVICE_BUSY;
317fb4d8502Sjsg 	}
318fb4d8502Sjsg 
319fb4d8502Sjsg 	switch (id) {
320fb4d8502Sjsg 	case GPIO_ID_DDC_DATA:
321c349dbc7Sjsg 		*pin = service->factory.funcs->get_ddc_pin(gpio);
322c349dbc7Sjsg 		service->factory.funcs->define_ddc_registers(*pin, en);
323fb4d8502Sjsg 	break;
324fb4d8502Sjsg 	case GPIO_ID_DDC_CLOCK:
325c349dbc7Sjsg 		*pin = service->factory.funcs->get_ddc_pin(gpio);
326c349dbc7Sjsg 		service->factory.funcs->define_ddc_registers(*pin, en);
327fb4d8502Sjsg 	break;
328fb4d8502Sjsg 	case GPIO_ID_GENERIC:
329c349dbc7Sjsg 		*pin = service->factory.funcs->get_generic_pin(gpio);
330c349dbc7Sjsg 		service->factory.funcs->define_generic_registers(*pin, en);
331fb4d8502Sjsg 	break;
332fb4d8502Sjsg 	case GPIO_ID_HPD:
333c349dbc7Sjsg 		*pin = service->factory.funcs->get_hpd_pin(gpio);
334c349dbc7Sjsg 		service->factory.funcs->define_hpd_registers(*pin, en);
335fb4d8502Sjsg 	break;
336c349dbc7Sjsg 
337c349dbc7Sjsg 	//TODO: gsl and sync support? create_sync and create_gsl are NULL
338fb4d8502Sjsg 	case GPIO_ID_SYNC:
339fb4d8502Sjsg 	case GPIO_ID_GSL:
340fb4d8502Sjsg 	break;
341fb4d8502Sjsg 	default:
342fb4d8502Sjsg 		ASSERT_CRITICAL(false);
343fb4d8502Sjsg 		return GPIO_RESULT_NON_SPECIFIC_ERROR;
344fb4d8502Sjsg 	}
345fb4d8502Sjsg 
346c349dbc7Sjsg 	if (!*pin) {
347fb4d8502Sjsg 		ASSERT_CRITICAL(false);
348fb4d8502Sjsg 		return GPIO_RESULT_NON_SPECIFIC_ERROR;
349fb4d8502Sjsg 	}
350fb4d8502Sjsg 
351c349dbc7Sjsg 	if (!(*pin)->funcs->open(*pin, mode)) {
352fb4d8502Sjsg 		ASSERT_CRITICAL(false);
353c349dbc7Sjsg 		dal_gpio_service_close(service, pin);
354fb4d8502Sjsg 		return GPIO_RESULT_OPEN_FAILED;
355fb4d8502Sjsg 	}
356fb4d8502Sjsg 
357fb4d8502Sjsg 	set_pin_busy(service, id, en);
358fb4d8502Sjsg 	return GPIO_RESULT_OK;
359fb4d8502Sjsg }
360fb4d8502Sjsg 
361fb4d8502Sjsg void dal_gpio_service_close(
362fb4d8502Sjsg 	struct gpio_service *service,
363fb4d8502Sjsg 	struct hw_gpio_pin **ptr)
364fb4d8502Sjsg {
365fb4d8502Sjsg 	struct hw_gpio_pin *pin;
366fb4d8502Sjsg 
367fb4d8502Sjsg 	if (!ptr) {
368fb4d8502Sjsg 		ASSERT_CRITICAL(false);
369fb4d8502Sjsg 		return;
370fb4d8502Sjsg 	}
371fb4d8502Sjsg 
372fb4d8502Sjsg 	pin = *ptr;
373fb4d8502Sjsg 
374fb4d8502Sjsg 	if (pin) {
375fb4d8502Sjsg 		set_pin_free(service, pin->id, pin->en);
376fb4d8502Sjsg 
377fb4d8502Sjsg 		pin->funcs->close(pin);
378fb4d8502Sjsg 
379c349dbc7Sjsg 		*ptr = NULL;
380fb4d8502Sjsg 	}
381fb4d8502Sjsg }
382fb4d8502Sjsg 
383fb4d8502Sjsg enum dc_irq_source dal_irq_get_source(
384fb4d8502Sjsg 	const struct gpio *irq)
385fb4d8502Sjsg {
386fb4d8502Sjsg 	enum gpio_id id = dal_gpio_get_id(irq);
387fb4d8502Sjsg 
388fb4d8502Sjsg 	switch (id) {
389fb4d8502Sjsg 	case GPIO_ID_HPD:
390fb4d8502Sjsg 		return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1 +
391fb4d8502Sjsg 			dal_gpio_get_enum(irq));
392fb4d8502Sjsg 	case GPIO_ID_GPIO_PAD:
393fb4d8502Sjsg 		return (enum dc_irq_source)(DC_IRQ_SOURCE_GPIOPAD0 +
394fb4d8502Sjsg 			dal_gpio_get_enum(irq));
395fb4d8502Sjsg 	default:
396fb4d8502Sjsg 		return DC_IRQ_SOURCE_INVALID;
397fb4d8502Sjsg 	}
398fb4d8502Sjsg }
399fb4d8502Sjsg 
400fb4d8502Sjsg enum dc_irq_source dal_irq_get_rx_source(
401fb4d8502Sjsg 	const struct gpio *irq)
402fb4d8502Sjsg {
403fb4d8502Sjsg 	enum gpio_id id = dal_gpio_get_id(irq);
404fb4d8502Sjsg 
405fb4d8502Sjsg 	switch (id) {
406fb4d8502Sjsg 	case GPIO_ID_HPD:
407fb4d8502Sjsg 		return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1RX +
408fb4d8502Sjsg 			dal_gpio_get_enum(irq));
409fb4d8502Sjsg 	default:
410fb4d8502Sjsg 		return DC_IRQ_SOURCE_INVALID;
411fb4d8502Sjsg 	}
412fb4d8502Sjsg }
413fb4d8502Sjsg 
414fb4d8502Sjsg enum gpio_result dal_irq_setup_hpd_filter(
415fb4d8502Sjsg 	struct gpio *irq,
416fb4d8502Sjsg 	struct gpio_hpd_config *config)
417fb4d8502Sjsg {
418fb4d8502Sjsg 	struct gpio_config_data config_data;
419fb4d8502Sjsg 
420fb4d8502Sjsg 	if (!config)
421fb4d8502Sjsg 		return GPIO_RESULT_INVALID_DATA;
422fb4d8502Sjsg 
423fb4d8502Sjsg 	config_data.type = GPIO_CONFIG_TYPE_HPD;
424fb4d8502Sjsg 	config_data.config.hpd = *config;
425fb4d8502Sjsg 
426fb4d8502Sjsg 	return dal_gpio_set_config(irq, &config_data);
427fb4d8502Sjsg }
428fb4d8502Sjsg 
429fb4d8502Sjsg /*
430fb4d8502Sjsg  * @brief
431fb4d8502Sjsg  * Creation and destruction
432fb4d8502Sjsg  */
433fb4d8502Sjsg 
434fb4d8502Sjsg struct gpio *dal_gpio_create_irq(
435fb4d8502Sjsg 	struct gpio_service *service,
436fb4d8502Sjsg 	enum gpio_id id,
437fb4d8502Sjsg 	uint32_t en)
438fb4d8502Sjsg {
439fb4d8502Sjsg 	struct gpio *irq;
440fb4d8502Sjsg 
441fb4d8502Sjsg 	switch (id) {
442fb4d8502Sjsg 	case GPIO_ID_HPD:
443fb4d8502Sjsg 	case GPIO_ID_GPIO_PAD:
444fb4d8502Sjsg 	break;
445fb4d8502Sjsg 	default:
446fb4d8502Sjsg 		id = GPIO_ID_HPD;
447fb4d8502Sjsg 		ASSERT_CRITICAL(false);
448fb4d8502Sjsg 		return NULL;
449fb4d8502Sjsg 	}
450fb4d8502Sjsg 
451fb4d8502Sjsg 	irq = dal_gpio_create(
452fb4d8502Sjsg 		service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
453fb4d8502Sjsg 
454fb4d8502Sjsg 	if (irq)
455fb4d8502Sjsg 		return irq;
456fb4d8502Sjsg 
457fb4d8502Sjsg 	ASSERT_CRITICAL(false);
458fb4d8502Sjsg 	return NULL;
459fb4d8502Sjsg }
460fb4d8502Sjsg 
461fb4d8502Sjsg void dal_gpio_destroy_irq(
462fb4d8502Sjsg 	struct gpio **irq)
463fb4d8502Sjsg {
464fb4d8502Sjsg 	if (!irq || !*irq) {
465fb4d8502Sjsg 		ASSERT_CRITICAL(false);
466fb4d8502Sjsg 		return;
467fb4d8502Sjsg 	}
468fb4d8502Sjsg 
469fb4d8502Sjsg 	dal_gpio_destroy(irq);
470fb4d8502Sjsg 	kfree(*irq);
471fb4d8502Sjsg 
472fb4d8502Sjsg 	*irq = NULL;
473fb4d8502Sjsg }
474fb4d8502Sjsg 
475fb4d8502Sjsg struct ddc *dal_gpio_create_ddc(
476fb4d8502Sjsg 	struct gpio_service *service,
477fb4d8502Sjsg 	uint32_t offset,
478fb4d8502Sjsg 	uint32_t mask,
479fb4d8502Sjsg 	struct gpio_ddc_hw_info *info)
480fb4d8502Sjsg {
481fb4d8502Sjsg 	enum gpio_id id;
482fb4d8502Sjsg 	uint32_t en;
483fb4d8502Sjsg 	struct ddc *ddc;
484fb4d8502Sjsg 
485fb4d8502Sjsg 	if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en))
486fb4d8502Sjsg 		return NULL;
487fb4d8502Sjsg 
488fb4d8502Sjsg 	ddc = kzalloc(sizeof(struct ddc), GFP_KERNEL);
489fb4d8502Sjsg 
490fb4d8502Sjsg 	if (!ddc) {
491fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
492fb4d8502Sjsg 		return NULL;
493fb4d8502Sjsg 	}
494fb4d8502Sjsg 
495fb4d8502Sjsg 	ddc->pin_data = dal_gpio_create(
496fb4d8502Sjsg 		service, GPIO_ID_DDC_DATA, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
497fb4d8502Sjsg 
498fb4d8502Sjsg 	if (!ddc->pin_data) {
499fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
500fb4d8502Sjsg 		goto failure_1;
501fb4d8502Sjsg 	}
502fb4d8502Sjsg 
503fb4d8502Sjsg 	ddc->pin_clock = dal_gpio_create(
504fb4d8502Sjsg 		service, GPIO_ID_DDC_CLOCK, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);
505fb4d8502Sjsg 
506fb4d8502Sjsg 	if (!ddc->pin_clock) {
507fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
508fb4d8502Sjsg 		goto failure_2;
509fb4d8502Sjsg 	}
510fb4d8502Sjsg 
511fb4d8502Sjsg 	ddc->hw_info = *info;
512fb4d8502Sjsg 
513fb4d8502Sjsg 	ddc->ctx = service->ctx;
514fb4d8502Sjsg 
515fb4d8502Sjsg 	return ddc;
516fb4d8502Sjsg 
517fb4d8502Sjsg failure_2:
518fb4d8502Sjsg 	dal_gpio_destroy(&ddc->pin_data);
519fb4d8502Sjsg 
520fb4d8502Sjsg failure_1:
521fb4d8502Sjsg 	kfree(ddc);
522fb4d8502Sjsg 
523fb4d8502Sjsg 	return NULL;
524fb4d8502Sjsg }
525fb4d8502Sjsg 
526fb4d8502Sjsg void dal_gpio_destroy_ddc(
527fb4d8502Sjsg 	struct ddc **ddc)
528fb4d8502Sjsg {
529fb4d8502Sjsg 	if (!ddc || !*ddc) {
530fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
531fb4d8502Sjsg 		return;
532fb4d8502Sjsg 	}
533fb4d8502Sjsg 
534fb4d8502Sjsg 	dal_ddc_close(*ddc);
535fb4d8502Sjsg 	dal_gpio_destroy(&(*ddc)->pin_data);
536fb4d8502Sjsg 	dal_gpio_destroy(&(*ddc)->pin_clock);
537fb4d8502Sjsg 	kfree(*ddc);
538fb4d8502Sjsg 
539fb4d8502Sjsg 	*ddc = NULL;
540fb4d8502Sjsg }
541fb4d8502Sjsg 
542fb4d8502Sjsg enum gpio_result dal_ddc_open(
543fb4d8502Sjsg 	struct ddc *ddc,
544fb4d8502Sjsg 	enum gpio_mode mode,
545fb4d8502Sjsg 	enum gpio_ddc_config_type config_type)
546fb4d8502Sjsg {
547fb4d8502Sjsg 	enum gpio_result result;
548fb4d8502Sjsg 
549fb4d8502Sjsg 	struct gpio_config_data config_data;
550fb4d8502Sjsg 	struct hw_gpio *hw_data;
551fb4d8502Sjsg 	struct hw_gpio *hw_clock;
552fb4d8502Sjsg 
553fb4d8502Sjsg 	result = dal_gpio_open_ex(ddc->pin_data, mode);
554fb4d8502Sjsg 
555fb4d8502Sjsg 	if (result != GPIO_RESULT_OK) {
556fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
557fb4d8502Sjsg 		return result;
558fb4d8502Sjsg 	}
559fb4d8502Sjsg 
560fb4d8502Sjsg 	result = dal_gpio_open_ex(ddc->pin_clock, mode);
561fb4d8502Sjsg 
562fb4d8502Sjsg 	if (result != GPIO_RESULT_OK) {
563fb4d8502Sjsg 		BREAK_TO_DEBUGGER();
564fb4d8502Sjsg 		goto failure;
565fb4d8502Sjsg 	}
566fb4d8502Sjsg 
567fb4d8502Sjsg 	/* DDC clock and data pins should belong
568fb4d8502Sjsg 	 * to the same DDC block id,
569fb4d8502Sjsg 	 * we use the data pin to set the pad mode. */
570fb4d8502Sjsg 
571fb4d8502Sjsg 	if (mode == GPIO_MODE_INPUT)
572fb4d8502Sjsg 		/* this is from detect_sink_type,
573fb4d8502Sjsg 		 * we need extra delay there */
574fb4d8502Sjsg 		config_data.type = GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE;
575fb4d8502Sjsg 	else
576fb4d8502Sjsg 		config_data.type = GPIO_CONFIG_TYPE_DDC;
577fb4d8502Sjsg 
578fb4d8502Sjsg 	config_data.config.ddc.type = config_type;
579fb4d8502Sjsg 
580fb4d8502Sjsg 	hw_data = FROM_HW_GPIO_PIN(ddc->pin_data->pin);
581fb4d8502Sjsg 	hw_clock = FROM_HW_GPIO_PIN(ddc->pin_clock->pin);
582fb4d8502Sjsg 
583fb4d8502Sjsg 	config_data.config.ddc.data_en_bit_present = hw_data->store.en != 0;
584fb4d8502Sjsg 	config_data.config.ddc.clock_en_bit_present = hw_clock->store.en != 0;
585fb4d8502Sjsg 
586fb4d8502Sjsg 	result = dal_gpio_set_config(ddc->pin_data, &config_data);
587fb4d8502Sjsg 
588fb4d8502Sjsg 	if (result == GPIO_RESULT_OK)
589fb4d8502Sjsg 		return result;
590fb4d8502Sjsg 
591fb4d8502Sjsg 	BREAK_TO_DEBUGGER();
592fb4d8502Sjsg 
593fb4d8502Sjsg 	dal_gpio_close(ddc->pin_clock);
594fb4d8502Sjsg 
595fb4d8502Sjsg failure:
596fb4d8502Sjsg 	dal_gpio_close(ddc->pin_data);
597fb4d8502Sjsg 
598fb4d8502Sjsg 	return result;
599fb4d8502Sjsg }
600fb4d8502Sjsg 
601fb4d8502Sjsg enum gpio_result dal_ddc_change_mode(
602fb4d8502Sjsg 	struct ddc *ddc,
603fb4d8502Sjsg 	enum gpio_mode mode)
604fb4d8502Sjsg {
605fb4d8502Sjsg 	enum gpio_result result;
606fb4d8502Sjsg 
607fb4d8502Sjsg 	enum gpio_mode original_mode =
608fb4d8502Sjsg 		dal_gpio_get_mode(ddc->pin_data);
609fb4d8502Sjsg 
610fb4d8502Sjsg 	result = dal_gpio_change_mode(ddc->pin_data, mode);
611fb4d8502Sjsg 
612fb4d8502Sjsg 	/* [anaumov] DAL2 code returns GPIO_RESULT_NON_SPECIFIC_ERROR
613fb4d8502Sjsg 	 * in case of failures;
614fb4d8502Sjsg 	 * set_mode() is so that, in case of failure,
615fb4d8502Sjsg 	 * we must explicitly set original mode */
616fb4d8502Sjsg 
617fb4d8502Sjsg 	if (result != GPIO_RESULT_OK)
618fb4d8502Sjsg 		goto failure;
619fb4d8502Sjsg 
620fb4d8502Sjsg 	result = dal_gpio_change_mode(ddc->pin_clock, mode);
621fb4d8502Sjsg 
622fb4d8502Sjsg 	if (result == GPIO_RESULT_OK)
623fb4d8502Sjsg 		return result;
624fb4d8502Sjsg 
625fb4d8502Sjsg 	dal_gpio_change_mode(ddc->pin_clock, original_mode);
626fb4d8502Sjsg 
627fb4d8502Sjsg failure:
628fb4d8502Sjsg 	dal_gpio_change_mode(ddc->pin_data, original_mode);
629fb4d8502Sjsg 
630fb4d8502Sjsg 	return result;
631fb4d8502Sjsg }
632fb4d8502Sjsg 
633fb4d8502Sjsg enum gpio_ddc_line dal_ddc_get_line(
634fb4d8502Sjsg 	const struct ddc *ddc)
635fb4d8502Sjsg {
636fb4d8502Sjsg 	return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data);
637fb4d8502Sjsg }
638fb4d8502Sjsg 
639fb4d8502Sjsg enum gpio_result dal_ddc_set_config(
640fb4d8502Sjsg 	struct ddc *ddc,
641fb4d8502Sjsg 	enum gpio_ddc_config_type config_type)
642fb4d8502Sjsg {
643fb4d8502Sjsg 	struct gpio_config_data config_data;
644fb4d8502Sjsg 
645fb4d8502Sjsg 	config_data.type = GPIO_CONFIG_TYPE_DDC;
646fb4d8502Sjsg 
647fb4d8502Sjsg 	config_data.config.ddc.type = config_type;
648fb4d8502Sjsg 	config_data.config.ddc.data_en_bit_present = false;
649fb4d8502Sjsg 	config_data.config.ddc.clock_en_bit_present = false;
650fb4d8502Sjsg 
651fb4d8502Sjsg 	return dal_gpio_set_config(ddc->pin_data, &config_data);
652fb4d8502Sjsg }
653fb4d8502Sjsg 
654fb4d8502Sjsg void dal_ddc_close(
655fb4d8502Sjsg 	struct ddc *ddc)
656fb4d8502Sjsg {
6571bb76ff1Sjsg 	if (ddc != NULL) {
658fb4d8502Sjsg 		dal_gpio_close(ddc->pin_clock);
659fb4d8502Sjsg 		dal_gpio_close(ddc->pin_data);
660fb4d8502Sjsg 	}
6611bb76ff1Sjsg }
662fb4d8502Sjsg 
663