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