2 * Copyright 2012-15 Advanced Micro Devices, Inc.
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:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
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.
26 #include <linux/delay.h>
27 #include <linux/slab.h>
29 #include "dm_services.h"
31 #include "include/gpio_interface.h"
32 #include "include/gpio_types.h"
36 #include "reg_helper.h"
37 #include "gpio_regs.h"
41 #define FN(reg_name, field_name) \
42 ddc->shifts->field_name, ddc->masks->field_name
51 static void dal_hw_ddc_destruct(
54 dal_hw_gpio_destruct(&pin
->base
);
57 static void dal_hw_ddc_destroy(
58 struct hw_gpio_pin
**ptr
)
60 struct hw_ddc
*pin
= HW_DDC_FROM_BASE(*ptr
);
62 dal_hw_ddc_destruct(pin
);
69 static enum gpio_result
set_config(
70 struct hw_gpio_pin
*ptr
,
71 const struct gpio_config_data
*config_data
)
73 struct hw_ddc
*ddc
= HW_DDC_FROM_BASE(ptr
);
74 struct hw_gpio
*hw_gpio
= NULL
;
76 uint32_t ddc_data_pd_en
= 0;
77 uint32_t ddc_clk_pd_en
= 0;
78 uint32_t aux_pad_mode
= 0;
82 if (hw_gpio
== NULL
) {
83 ASSERT_CRITICAL(false);
84 return GPIO_RESULT_NULL_HANDLE
;
87 regval
= REG_GET_3(gpio
.MASK_reg
,
88 DC_GPIO_DDC1DATA_PD_EN
, &ddc_data_pd_en
,
89 DC_GPIO_DDC1CLK_PD_EN
, &ddc_clk_pd_en
,
90 AUX_PAD1_MODE
, &aux_pad_mode
);
92 switch (config_data
->config
.ddc
.type
) {
93 case GPIO_DDC_CONFIG_TYPE_MODE_I2C
:
94 /* On plug-in, there is a transient level on the pad
95 * which must be discharged through the internal pull-down.
96 * Enable internal pull-down, 2.5msec discharge time
97 * is required for detection of AUX mode */
98 if (hw_gpio
->base
.en
!= GPIO_DDC_LINE_VIP_PAD
) {
99 if (!ddc_data_pd_en
|| !ddc_clk_pd_en
) {
101 REG_SET_2(gpio
.MASK_reg
, regval
,
102 DC_GPIO_DDC1DATA_PD_EN
, 1,
103 DC_GPIO_DDC1CLK_PD_EN
, 1);
105 if (config_data
->type
==
106 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
111 uint32_t sda_pd_dis
= 0;
112 uint32_t scl_pd_dis
= 0;
114 reg2
= REG_GET_2(gpio
.MASK_reg
,
115 DC_GPIO_SDA_PD_DIS
, &sda_pd_dis
,
116 DC_GPIO_SCL_PD_DIS
, &scl_pd_dis
);
119 REG_SET(gpio
.MASK_reg
, regval
,
120 DC_GPIO_SDA_PD_DIS
, 0);
122 if (config_data
->type
==
123 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
128 REG_SET(gpio
.MASK_reg
, regval
,
129 DC_GPIO_SCL_PD_DIS
, 1);
131 if (config_data
->type
==
132 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
138 /* let pins to get de-asserted
139 * before setting pad to I2C mode */
140 if (config_data
->config
.ddc
.data_en_bit_present
||
141 config_data
->config
.ddc
.clock_en_bit_present
)
142 /* [anaumov] in DAL2, there was
143 * dc_service_delay_in_microseconds(2000); */
146 /* set the I2C pad mode */
147 /* read the register again,
148 * some bits may have been changed */
149 REG_UPDATE(gpio
.MASK_reg
,
153 if (ddc
->regs
->dc_gpio_aux_ctrl_5
!= 0) {
154 REG_UPDATE(dc_gpio_aux_ctrl_5
, DDC_PAD_I2CMODE
, 1);
156 //set DC_IO_aux_rxsel = 2'b01
157 if (ddc
->regs
->phy_aux_cntl
!= 0) {
158 REG_UPDATE(phy_aux_cntl
, AUX_PAD_RXSEL
, 1);
160 return GPIO_RESULT_OK
;
161 case GPIO_DDC_CONFIG_TYPE_MODE_AUX
:
162 /* set the AUX pad mode */
164 REG_SET(gpio
.MASK_reg
, regval
,
167 if (ddc
->regs
->dc_gpio_aux_ctrl_5
!= 0) {
168 REG_UPDATE(dc_gpio_aux_ctrl_5
,
172 return GPIO_RESULT_OK
;
173 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT
:
174 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
175 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
176 REG_UPDATE_3(ddc_setup
,
177 DC_I2C_DDC1_ENABLE
, 1,
178 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 1,
179 DC_I2C_DDC1_EDID_DETECT_MODE
, 0);
180 return GPIO_RESULT_OK
;
183 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT
:
184 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
185 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
186 REG_UPDATE_3(ddc_setup
,
187 DC_I2C_DDC1_ENABLE
, 1,
188 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 1,
189 DC_I2C_DDC1_EDID_DETECT_MODE
, 1);
190 return GPIO_RESULT_OK
;
193 case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING
:
194 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
195 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
196 REG_UPDATE_2(ddc_setup
,
197 DC_I2C_DDC1_ENABLE
, 0,
198 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 0);
199 return GPIO_RESULT_OK
;
206 return GPIO_RESULT_NON_SPECIFIC_ERROR
;
209 static const struct hw_gpio_pin_funcs funcs
= {
210 .destroy
= dal_hw_ddc_destroy
,
211 .open
= dal_hw_gpio_open
,
212 .get_value
= dal_hw_gpio_get_value
,
213 .set_value
= dal_hw_gpio_set_value
,
214 .set_config
= set_config
,
215 .change_mode
= dal_hw_gpio_change_mode
,
216 .close
= dal_hw_gpio_close
,
219 static void dal_hw_ddc_construct(
223 struct dc_context
*ctx
)
225 dal_hw_gpio_construct(&ddc
->base
, id
, en
, ctx
);
226 ddc
->base
.base
.funcs
= &funcs
;
229 void dal_hw_ddc_init(
230 struct hw_ddc
**hw_ddc
,
231 struct dc_context
*ctx
,
235 if ((en
< GPIO_DDC_LINE_MIN
) || (en
> GPIO_DDC_LINE_MAX
)) {
236 ASSERT_CRITICAL(false);
240 *hw_ddc
= kzalloc(sizeof(struct hw_ddc
), GFP_KERNEL
);
242 ASSERT_CRITICAL(false);
246 dal_hw_ddc_construct(*hw_ddc
, id
, en
, ctx
);
249 struct hw_gpio_pin
*dal_hw_ddc_get_pin(struct gpio
*gpio
)
251 struct hw_ddc
*hw_ddc
= dal_gpio_get_ddc(gpio
);
253 return &hw_ddc
->base
.base
;