/******************************************************************************
 *
 * Copyright(c) 2019 Realtek Corporation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 ******************************************************************************/
#include "gpio.h"

u32 mac_sel_uart_tx_pin(struct mac_ax_adapter *adapter,
			enum mac_ax_uart_tx_pin uart_pin)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	struct mac_ax_gpio_info *info = &adapter->gpio_info;
	u8 val = MAC_REG_R8(R_AX_CAL_TIMER + 3);
	u32 ret = MACSUCCESS;

	switch (uart_pin) {
	case MAC_AX_UART_TX_GPIO5:
		val |= BIT(6);
		if (!info->uart_tx_gpio5)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	case MAC_AX_UART_TX_GPIO7:
		val &= ~(BIT(7) | BIT(6));
		if (!info->uart_tx_gpio7)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	case MAC_AX_UART_TX_GPIO8:
		val |= BIT(7);
		if (!info->uart_tx_gpio8)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	case MAC_AX_UART_TX_GPIO5_GPIO8:
		val |= (BIT(6) | BIT(7));
		if (!info->uart_tx_gpio8 || !info->uart_tx_gpio5)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	default:
		PLTFM_MSG_ERR("Wrong UART GPIO\n");
		ret = MACNOITEM;
		break;
	}

	MAC_REG_W8(R_AX_CAL_TIMER + 3, val);

	return ret;
}

u32 mac_sel_uart_rx_pin(struct mac_ax_adapter *adapter,
			enum mac_ax_uart_rx_pin uart_pin)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	struct mac_ax_gpio_info *info = &adapter->gpio_info;
	u8 val = MAC_REG_R8(R_AX_CAL_TIMER + 3);
	u32 ret = MACSUCCESS;

	switch (uart_pin) {
	case MAC_AX_UART_RX_GPIO6:
		val &= ~BIT(5);
		if (!info->uart_rx_gpio6)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	case MAC_AX_UART_RX_GPIO14:
		val |= BIT(5);
		if (!info->uart_rx_gpio14)
			PLTFM_MSG_WARN("Pinmux function is not switched\n");
		break;
	default:
		PLTFM_MSG_ERR("Wrong UART GPIO\n");
		ret = MACNOITEM;
		break;
	}

	MAC_REG_W8(R_AX_CAL_TIMER + 3, val);

	return ret;
}

u32 mac_pinmux_switch(struct mac_ax_adapter *adapter,
		      enum mac_ax_gpio_func gpio_func,
		      const struct mac_ax_pinmux_list *list,
		      u32 list_size, u32 gpio_id)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	enum pinmux_name pinmux;
	struct mac_ax_pinmux_list const *cur_list;
	u32 i;
	u8 val;

	switch (gpio_func) {
	case MAC_AX_GPIO_SW_IO_0:
	case MAC_AX_GPIO_SW_IO_1:
	case MAC_AX_GPIO_SW_IO_2:
	case MAC_AX_GPIO_SW_IO_3:
	case MAC_AX_GPIO_SW_IO_4:
	case MAC_AX_GPIO_SW_IO_5:
	case MAC_AX_GPIO_SW_IO_6:
	case MAC_AX_GPIO_SW_IO_7:
	case MAC_AX_GPIO_SW_IO_8:
	case MAC_AX_GPIO_SW_IO_9:
	case MAC_AX_GPIO_SW_IO_10:
	case MAC_AX_GPIO_SW_IO_11:
	case MAC_AX_GPIO_SW_IO_12:
	case MAC_AX_GPIO_SW_IO_13:
	case MAC_AX_GPIO_SW_IO_14:
	case MAC_AX_GPIO_SW_IO_15:
		pinmux = MAC_AX_SW_IO;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO5:
	case MAC_AX_GPIO_UART_TX_GPIO7:
	case MAC_AX_GPIO_UART_TX_GPIO8:
		pinmux = MAC_AX_WL_UART_TX;
		break;
	case MAC_AX_GPIO_UART_RX_GPIO6:
	case MAC_AX_GPIO_UART_RX_GPIO14:
		pinmux = MAC_AX_WL_UART_RX;
		break;
	default:
		PLTFM_MSG_ERR("Wrong GPIO function\n");
		return MACNOITEM;
	}

	cur_list = list;
	for (i = 0; i < list_size; i++) {
		val = MAC_REG_R8(cur_list->offset);
		val &= ~(cur_list->msk);

		if (pinmux == cur_list->func) {
			val |= (cur_list->value & cur_list->msk);
			MAC_REG_W8(cur_list->offset, val);
			break;
		}

		val |= (~cur_list->value & cur_list->msk);
		MAC_REG_W8(cur_list->offset, val);

		cur_list++;
	}

	if (i ==  list_size) {
		PLTFM_MSG_ERR("Get pinmux function error\n");
		return MACNOITEM;
	}

	switch (pinmux) {
	case MAC_AX_WL_UART_TX:
	case MAC_AX_WL_UART_RX:
		val = MAC_REG_R8(R_AX_WCPU_FW_CTRL + 3);
		MAC_REG_W8(R_AX_WCPU_FW_CTRL + 3, val | BIT(7));
		break;
	default:
		break;
	}

	return MACSUCCESS;
}

u32 mac_pinmux_record(struct mac_ax_adapter *adapter,
		      enum mac_ax_gpio_func func, u8 val)
{
	struct mac_ax_gpio_info *info = &adapter->gpio_info;

	switch (func) {
	case MAC_AX_GPIO_SW_IO_0:
		info->sw_io_0 = val;
		break;
	case MAC_AX_GPIO_SW_IO_1:
		info->sw_io_1 = val;
		break;
	case MAC_AX_GPIO_SW_IO_2:
		info->sw_io_2 = val;
		break;
	case MAC_AX_GPIO_SW_IO_3:
		info->sw_io_3 = val;
		break;
	case MAC_AX_GPIO_SW_IO_4:
		info->sw_io_4 = val;
		break;
	case MAC_AX_GPIO_SW_IO_5:
		info->sw_io_5 = val;
		break;
	case MAC_AX_GPIO_SW_IO_6:
		info->sw_io_6 = val;
		break;
	case MAC_AX_GPIO_SW_IO_7:
		info->sw_io_7 = val;
		break;
	case MAC_AX_GPIO_SW_IO_8:
		info->sw_io_8 = val;
		break;
	case MAC_AX_GPIO_SW_IO_9:
		info->sw_io_9 = val;
		break;
	case MAC_AX_GPIO_SW_IO_10:
		info->sw_io_10 = val;
		break;
	case MAC_AX_GPIO_SW_IO_11:
		info->sw_io_11 = val;
		break;
	case MAC_AX_GPIO_SW_IO_12:
		info->sw_io_12 = val;
		break;
	case MAC_AX_GPIO_SW_IO_13:
		info->sw_io_13 = val;
		break;
	case MAC_AX_GPIO_SW_IO_14:
		info->sw_io_14 = val;
		break;
	case MAC_AX_GPIO_SW_IO_15:
		info->sw_io_15 = val;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO5:
		info->uart_tx_gpio5 = val;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO7:
		info->uart_tx_gpio7 = val;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO8:
		info->uart_tx_gpio8 = val;
		break;
	case MAC_AX_GPIO_UART_RX_GPIO6:
		info->uart_rx_gpio6 = val;
		break;
	case MAC_AX_GPIO_UART_RX_GPIO14:
		info->uart_rx_gpio14 = val;
		break;
	default:
		PLTFM_MSG_ERR("Wrong GPIO function\n");
		return MACNOITEM;
	}

	return MACSUCCESS;
}

u32 mac_pinmux_status(struct mac_ax_adapter *adapter,
		      enum mac_ax_gpio_func func)
{
	struct mac_ax_gpio_info *info = &adapter->gpio_info;
	u32 ret = MACSUCCESS;

	switch (func) {
	case MAC_AX_GPIO_SW_IO_0:
		if (info->sw_io_0)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_1:
		if (info->sw_io_1)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_2:
		if (info->sw_io_2)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_3:
		if (info->sw_io_3)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_4:
		if (info->sw_io_4)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_5:
		if (info->sw_io_5 || info->uart_tx_gpio5 ||
		    info->uart_tx_gpio7 || info->uart_tx_gpio8)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO5:
		if (info->sw_io_5 || info->uart_tx_gpio5)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_6:
		if (info->sw_io_6 || info->uart_rx_gpio6 ||
		    info->uart_rx_gpio14)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_UART_RX_GPIO6:
		if (info->sw_io_6 || info->uart_rx_gpio6)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_7:
		if (info->sw_io_7 || info->uart_tx_gpio5 ||
		    info->uart_tx_gpio7 || info->uart_tx_gpio8)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO7:
		if (info->sw_io_7 || info->uart_tx_gpio7)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_8:
		if (info->sw_io_8 || info->uart_tx_gpio5 ||
		    info->uart_tx_gpio7 || info->uart_tx_gpio8)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_UART_TX_GPIO8:
		if (info->sw_io_8 || info->uart_tx_gpio8)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_9:
		if (info->sw_io_9)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_10:
		if (info->sw_io_10)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_11:
		if (info->sw_io_11)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_12:
		if (info->sw_io_12)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_13:
		if (info->sw_io_13)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_14:
		if (info->sw_io_14 || info->uart_rx_gpio6 ||
		    info->uart_rx_gpio14)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_UART_RX_GPIO14:
		if (info->sw_io_14 || info->uart_rx_gpio14)
			goto GPIO_USED;
		break;
	case MAC_AX_GPIO_SW_IO_15:
		if (info->sw_io_15)
			goto GPIO_USED;
		break;
	default:
		ret = MACNOITEM;
		PLTFM_MSG_ERR("Wrong GPIO function\n");
	}

	return ret;
GPIO_USED:
	ret = MACGPIOUSED;
	return ret;
}

u32 mac_pinmux_free_func(struct mac_ax_adapter *adapter,
			 enum mac_ax_gpio_func func)
{
	return mac_pinmux_record(adapter, func, 0);
}

u8 get_led_gpio(u8 led_id)
{
/* LED 0 -> GPIO8 */
	switch (led_id) {
	case 0:
		return 8;
	default:
		return 0xFF;
	}
}

u32 mac_set_led_mode(struct mac_ax_adapter *adapter,
		     enum mac_ax_led_mode mode, u8 led_id)
{
#define LED_MODE_SW_CTRL 0
#define LED_MODE_AON 1
#define LED_MODE_TRX_ON 2
#define LED_MODE_TRX_OFF 3
#define LED_MODE_TX_ON 4
#define LED_MODE_TX_OFF 5
#define LED_MODE_RX_ON 6
#define LED_MODE_RX_OFF 7
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	struct mac_ax_ops *mac_ops = adapter->ops;
	u32 val, ret;
	u8 tmp, gpio;

	gpio = get_led_gpio(led_id);
	if (gpio == 0xFF) {
		PLTFM_MSG_ERR("%s: Wrong LED ID: %d", __func__, led_id);
		ret = MACNOITEM;
		goto END;
	}

	val = MAC_REG_R32(R_AX_LED_CFG);

	switch (mode) {
	case MAC_AX_LED_MODE_TRX_ON:
		tmp = LED_MODE_TRX_ON;
		break;
	case MAC_AX_LED_MODE_TX_ON:
		tmp = LED_MODE_TX_ON;
		break;
	case MAC_AX_LED_MODE_RX_ON:
		tmp = LED_MODE_RX_ON;
		break;
	case MAC_AX_LED_MODE_SW_CTRL_OD:
		/* use SW IO to control LED */
		ret = mac_set_sw_gpio_mode(adapter,
					   RTW_AX_SW_IO_MODE_OUTPUT_OD, 8);
		if (ret)
			PLTFM_MSG_ERR("%s: config SW GPIO fail: %d",
				      __func__, ret);
		goto END;
	case MAC_AX_LED_MODE_SW_CTRL_PP:
		/* use SW IO to control LED */
		ret = mac_set_sw_gpio_mode(adapter,
					   RTW_AX_SW_IO_MODE_OUTPUT_PP, 8);
		if (ret)
			PLTFM_MSG_ERR("%s: config SW GPIO fail: %d",
				      __func__, ret);
		goto END;
	default:
		PLTFM_MSG_ERR("%s: Wrong LED mode: %d", __func__, mode);
		return MACNOITEM;
	}

	ret = mac_ops->set_gpio_func(adapter, RTW_MAC_GPIO_WL_LED, gpio);
	if (ret) {
		PLTFM_MSG_ERR("%s: Config LED pinmux fail", __func__);
		goto END;
	}

	val = SET_CLR_WORD(val, tmp, B_AX_LED2CM);
	val = val & ~(B_AX_LED2_EN);
	MAC_REG_W32(R_AX_LED_CFG, val);

END:
	return ret;
}

u32 mac_led_ctrl(struct mac_ax_adapter *adapter,
		 u8 high, u8 led_id)
{
	u32 ret = MACSUCCESS;
	u8 gpio;

	gpio = get_led_gpio(led_id);
	if (gpio == 0xFF) {
		PLTFM_MSG_ERR("%s: Wrong LED ID: %d", __func__, led_id);
		ret = MACNOITEM;
		goto END;
	}

	/* use SW IO to control LED */
	ret = mac_sw_gpio_ctrl(adapter, high, gpio);

END:
	return ret;
}

u32 _mac_set_sw_gpio_mode(struct mac_ax_adapter *adapter,
			  u8 output, u8 gpio)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	u32 reg;
	u16 val16;
	u8 in_out;

	if (gpio <= 7) {
		reg = R_AX_GPIO_PIN_CTRL + 2;
	} else if (gpio >= 8 && gpio <= 15) {
		reg = R_AX_GPIO_EXT_CTRL + 2;
		gpio = gpio - 8;
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT || MAC_AX_8851E_SUPPORT || MAC_AX_8852D_SUPPORT
	} else if (gpio >= 16 && gpio <= 18 &&
		   (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8851E) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8852D))) {
		reg = R_AX_GPIO_16_TO_18_EXT_CTRL + 2;
		gpio = gpio - 16;
#endif
	} else {
		PLTFM_MSG_ERR("%s: Wrong GPIO num: %d", __func__, gpio);
		return MACNOITEM;
	}

	in_out = (output == 0) ? 0 : 1;

	val16 = MAC_REG_R16(reg);
	val16 = (val16 & ~((u16)BIT(gpio) | (u16)BIT(gpio + 8))) |
		      (u16)(in_out << gpio) | (u16)(in_out << gpio << 8);
	MAC_REG_W16(reg, val16);

	return MACSUCCESS;
}

u32 mac_set_sw_gpio_mode(struct mac_ax_adapter *adapter,
			 enum rtw_gpio_mode mode, u8 gpio)
{
	struct mac_ax_ops *mac_ops = adapter->ops;
	struct mac_ax_gpio_info *gpio_info = &adapter->gpio_info;
	u32 ret;

	ret = mac_ops->set_gpio_func(adapter, RTW_MAC_GPIO_SW_IO, gpio);
	if (ret) {
		PLTFM_MSG_ERR("%s: Config SW IO pinmux fail", __func__);
		return ret;
	}

	switch (mode) {
	case RTW_AX_SW_IO_MODE_INPUT:
		ret = _mac_set_sw_gpio_mode(adapter, 0, gpio);
		break;
	case RTW_AX_SW_IO_MODE_OUTPUT_OD:
		ret = _mac_set_sw_gpio_mode(adapter, 0, gpio);
		gpio_info->sw_io_output[gpio] = MAC_AX_SW_IO_OUT_OD;
		break;
	case RTW_AX_SW_IO_MODE_OUTPUT_PP:
		ret = _mac_set_sw_gpio_mode(adapter, 1, gpio);
		gpio_info->sw_io_output[gpio] = MAC_AX_SW_IO_OUT_PP;
		break;
	default:
		PLTFM_MSG_ERR("%s: Wrong SW GPIO mode: %d", __func__, mode);
		ret = MACNOITEM;
		break;
	}

	return ret;
}

u32 mac_sw_gpio_ctrl(struct mac_ax_adapter *adapter,
		     u8 high, u8 gpio)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	struct mac_ax_gpio_info *gpio_info = &adapter->gpio_info;
	u32 reg, ret;
	u8 ctrl, val8;

	if (gpio >= RTW_MAC_GPIO_MAX) {
		PLTFM_MSG_ERR("%s: Wrong GPIO num: %d", __func__, gpio);
		return MACNOITEM;
	}

	if (high && gpio_info->sw_io_output[gpio] == MAC_AX_SW_IO_OUT_OD) {
		ret = _mac_set_sw_gpio_mode(adapter, 0, gpio);
	} else {
		ret = _mac_set_sw_gpio_mode(adapter, 1, gpio);
		if (ret) {
			PLTFM_MSG_ERR("%s: Set GPIO mode fail\n", __func__);
			goto END;
		}

		if (gpio <= 7) {
			reg = R_AX_GPIO_PIN_CTRL + 1;
		} else if (gpio >= 8 && gpio <= 15) {
			reg = R_AX_GPIO_EXT_CTRL + 1;
			gpio = gpio - 8;
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT || MAC_AX_8851E_SUPPORT || MAC_AX_8852D_SUPPORT
		} else if (gpio >= 16 && gpio <= 18 &&
			   (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
			    is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB) ||
			    is_chip_id(adapter, MAC_AX_CHIP_ID_8851E) ||
			    is_chip_id(adapter, MAC_AX_CHIP_ID_8852D))) {
			reg = R_AX_GPIO_16_TO_18_EXT_CTRL + 1;
			gpio = gpio - 16;
#endif
		} else {
			PLTFM_MSG_ERR("%s: Wrong GPIO num: %d", __func__, gpio);
			return MACNOITEM;
		}

		ctrl = (high == 0) ? 0 : 1;

		val8 = MAC_REG_R8(reg);
		val8 = (val8 & ~((u8)BIT(gpio))) | (u8)(ctrl << gpio);
		MAC_REG_W8(reg, val8);
	}

END:
	return ret;
}

enum rtw_mac_gfunc mac_get_gpio_status(struct mac_ax_adapter *adapter,
				       const struct mac_ax_pin_list *list)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	u8 val;
	enum rtw_mac_gfunc curr = RTW_MAC_GPIO_INVALID;

	while (list && list->func != RTW_MAC_GPIO_LAST) {
		/* first fit list*/
		if (curr != list->func &&
		    list->offset >= R_AX_GPIO0_7_FUNC_SEL &&
		    list->offset <= R_AX_LED1_FUNC_SEL) {
			curr = list->func;
			val = MAC_REG_R8(list->offset);
			if ((val & list->msk) == list->value)
				return list->func;
		}
		list++;
	}

	return RTW_MAC_GPIO_INVALID;
}

u32 mac_cfg_wps(struct mac_ax_adapter *adapter,
		struct mac_ax_cfg_wps *wps)
{
	u32 ret;
	struct fwcmd_cfg_wps *ptr;
	struct mac_ax_gpio_info *info = &adapter->gpio_info;
	struct h2c_info h2c_info = {0};

	if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
		PLTFM_MSG_WARN("%s fw not ready\n", __func__);
		return MACFWNONRDY;
	}

	h2c_info.agg_en = 0;
	h2c_info.content_len = sizeof(struct fwcmd_cfg_wps);
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_MISC;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_CFG_WPS;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	ptr = (struct fwcmd_cfg_wps *)PLTFM_MALLOC(h2c_info.content_len);
	if (!ptr)
		return MACBUFALLOC;
	PLTFM_MEMSET(ptr, 0, sizeof(struct fwcmd_cfg_wps));

	ptr->dword0 = cpu_to_le32((wps->en ? FWCMD_H2C_CFG_WPS_EN : 0) |
				  SET_WORD(wps->gpio,
					   FWCMD_H2C_CFG_WPS_GPIO) |
				  SET_WORD(wps->interval,
					   FWCMD_H2C_CFG_WPS_INTL));

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)ptr);
	PLTFM_FREE(ptr, h2c_info.content_len);
	if (ret != MACSUCCESS)
		return ret;

	if (info->status[wps->gpio] != RTW_MAC_GPIO_DFLT &&
	    info->status[wps->gpio] != RTW_MAC_GPIO_SW_IO)
		PLTFM_MSG_WARN("The gpio%d is %d\n",
			       wps->gpio, info->status[wps->gpio]);

	info->status[wps->gpio] = RTW_MAC_GPIO_SW_IO;

	return MACSUCCESS;
}

u32 mac_get_gpio_val(struct mac_ax_adapter *adapter, u8 gpio, u8 *val)
{
	struct mac_ax_intf_ops *ops = adapter->ops->intf_ops;
	u32 reg;

	if (gpio <= 7) {
		reg = R_AX_GPIO_PIN_CTRL;
	} else if (gpio >= 8 && gpio <= 15) {
		reg = R_AX_GPIO_EXT_CTRL;
		gpio = gpio - 8;
#if MAC_AX_8852C_SUPPORT || MAC_AX_8192XB_SUPPORT || MAC_AX_8851E_SUPPORT || MAC_AX_8852D_SUPPORT
	} else if (gpio >= 16 && gpio <= 18 &&
		   (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8851E) ||
		    is_chip_id(adapter, MAC_AX_CHIP_ID_8852D))) {
		reg = R_AX_GPIO_16_TO_18_EXT_CTRL;
		gpio = gpio - 16;
#endif
	} else {
		PLTFM_MSG_ERR("%s: Wrong GPIO num: %d", __func__, gpio);
		return MACNOITEM;
	}

	*val = !!(MAC_REG_R8(reg) & BIT(gpio));

	return MACSUCCESS;
}

u32 mac_get_wl_dis_gpio(struct mac_ax_adapter *adapter, u8 *gpio)
{
#define MAC_AX_HCI_SEL_SDIO_UART 0
#define MAC_AX_HCI_SEL_USB_MULT 1
#define MAC_AX_HCI_SEL_PCIE_UART 2
#define MAC_AX_HCI_SEL_PCIE_USB 3
#define MAC_AX_HCI_SEL_SDIO_MULT 4
#define MAC_AX_HCI_SEL_RSVD 5
#define MAC_AX_HCI_SEL_PCIE_GEN1_UART 6
#define MAC_AX_HCI_SEL_PCIE_GEN1_USB 7
	struct mac_ax_intf_ops *ops = adapter_to_intf_ops(adapter);
	u32 val;

	val = MAC_REG_R32(R_AX_SYS_STATUS1);
	val = GET_FIELD(val, B_AX_HCI_SEL_V4);

#if MAC_AX_8852A_SUPPORT
	/* In AP, */
	/*   MAC_AX_HCI_SEL_PCIE_UART and MAC_AX_HCI_SEL_SDIO_UART */
	/*   are only supported in 2G eFEM, not in 5G/5G 6G*/
	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852A)) {
		switch (val) {
#ifdef PHL_FEATURE_AP
		case MAC_AX_HCI_SEL_PCIE_UART:
		case MAC_AX_HCI_SEL_SDIO_UART:
			*gpio = 9;
			break;
#else
		case MAC_AX_HCI_SEL_USB_MULT:
		case MAC_AX_HCI_SEL_PCIE_UART:
		case MAC_AX_HCI_SEL_PCIE_USB:
			*gpio = 9;
			break;
		case MAC_AX_HCI_SEL_SDIO_UART:
			*gpio = 15;
			break;
#endif
		default:
			PLTFM_MSG_ERR("%s: Wrong HCI\n", __func__);
			return MACNOITEM;
		}
	}
#endif

#if MAC_AX_8852B_SUPPORT || MAC_AX_8851B_SUPPORT || MAC_AX_8852BT_SUPPORT
	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852B) ||
	    is_chip_id(adapter, MAC_AX_CHIP_ID_8851B) ||
	    is_chip_id(adapter, MAC_AX_CHIP_ID_8852BT)) {
		switch (val) {
		case MAC_AX_HCI_SEL_USB_MULT:
		case MAC_AX_HCI_SEL_PCIE_UART:
		case MAC_AX_HCI_SEL_PCIE_USB:
		case MAC_AX_HCI_SEL_PCIE_GEN1_UART:
		case MAC_AX_HCI_SEL_PCIE_GEN1_USB:
			*gpio = 9;
			break;
		case MAC_AX_HCI_SEL_SDIO_UART:
		case MAC_AX_HCI_SEL_SDIO_MULT:
			*gpio = 15;
			break;
		default:
			PLTFM_MSG_ERR("%s: Wrong HCI\n", __func__);
			return MACNOITEM;
		}
	}
#endif

#if MAC_AX_8852C_SUPPORT || MAC_AX_8851E_SUPPORT || MAC_AX_8852D_SUPPORT
	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8852C) ||
	    is_chip_id(adapter, MAC_AX_CHIP_ID_8851E) ||
	    is_chip_id(adapter, MAC_AX_CHIP_ID_8852D)) {
		switch (val) {
		case MAC_AX_HCI_SEL_PCIE_USB:
		case MAC_AX_HCI_SEL_PCIE_UART:
		case MAC_AX_HCI_SEL_PCIE_GEN1_UART:
		case MAC_AX_HCI_SEL_PCIE_GEN1_USB:
			*gpio = 9;
			break;
		case MAC_AX_HCI_SEL_SDIO_UART:
		case MAC_AX_HCI_SEL_SDIO_MULT:
			*gpio = 17;
			break;
		default:
			PLTFM_MSG_ERR("%s: Wrong HCI\n", __func__);
			return MACNOITEM;
		}
	}
#endif

#if MAC_AX_8192XB_SUPPORT
	if (is_chip_id(adapter, MAC_AX_CHIP_ID_8192XB)) {
		switch (val) {
		case MAC_AX_HCI_SEL_USB_MULT: /* USB */
		case MAC_AX_HCI_SEL_PCIE_USB: /* PCIE */
			*gpio = 9;
			break;
		case MAC_AX_HCI_SEL_SDIO_MULT: /* SDIO */
			*gpio = 15;
			break;
		default:
			PLTFM_MSG_ERR("%s: Wrong HCI\n", __func__);
			return MACNOITEM;
		}
	}
#endif

	return MACSUCCESS;
}

u32 mac_get_wl_dis_val(struct mac_ax_adapter *adapter, u8 *val)
{
	u8 gpio;
	u32 ret;
	struct mac_ax_ops *ops = adapter_to_mac_ops(adapter);

	ret = mac_get_wl_dis_gpio(adapter, &gpio);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("%s: Get WL_DIS GPIO fail\n", __func__);
		return ret;
	}

	ret = ops->set_sw_gpio_mode(adapter, RTW_AX_SW_IO_MODE_INPUT, gpio);
	if (ret != MACSUCCESS) {
		PLTFM_MSG_ERR("%s: Set SW output mode fail\n", __func__);
		return ret;
	}

	return ops->get_gpio_val(adapter, gpio, val);
}

u32 mac_get_uart_fw_dbg_gpio(struct mac_ax_adapter *adapter, u8 *uart_tx_gpio, u8 *uart_rx_gpio)
{
	if (adapter->gpio_info.uart_tx_gpio == 0xFF &&
	    adapter->gpio_info.uart_rx_gpio == 0xFF) {
		/* not initialized*/
		return MACNOTSUP;
	}

	*uart_tx_gpio = adapter->gpio_info.uart_tx_gpio;
	*uart_rx_gpio = adapter->gpio_info.uart_rx_gpio;

	return MACSUCCESS;
}

u32 mac_bcn_cnt_gpio(struct mac_ax_adapter *adapter,
		     struct rtw_hal_mac_bcn_cnt_gpio_info *bcn_cnt_gpio)
{
	struct fwcmd_bcn_cnt_gpio *ptr;
	struct h2c_info h2c_info = {0};
	u32 ret;

	if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
		PLTFM_MSG_WARN("%s fw not ready\n", __func__);
		return MACFWNONRDY;
	}

	if (bcn_cnt_gpio->rx_bcn_en == 0 && bcn_cnt_gpio->tx_bcn_en == 0) {
		PLTFM_MSG_ERR("%s: Disable TRX becaon GPIO\n", __func__);
		return MACFWNOSUPPORT;
	}

	h2c_info.agg_en = 0;
	h2c_info.content_len = sizeof(struct fwcmd_bcn_cnt_gpio);
	h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
	h2c_info.h2c_class = FWCMD_H2C_CL_FW_OFLD;
	h2c_info.h2c_func = FWCMD_H2C_FUNC_BCN_CNT_GPIO;
	h2c_info.rec_ack = 0;
	h2c_info.done_ack = 0;

	ptr = (struct fwcmd_bcn_cnt_gpio *)PLTFM_MALLOC(h2c_info.content_len);
	if (!ptr)
		return MACBUFALLOC;
	PLTFM_MEMSET(ptr, 0, sizeof(struct fwcmd_bcn_cnt_gpio));

	PLTFM_MEMCPY(ptr, bcn_cnt_gpio, sizeof(struct fwcmd_bcn_cnt_gpio));

	ret = mac_h2c_common(adapter, &h2c_info, (u32 *)ptr);
	PLTFM_FREE(ptr, h2c_info.content_len);
	if (ret != MACSUCCESS)
		return ret;

	return MACSUCCESS;
}

u32 mac_bcn_sync_rpt(struct mac_ax_adapter *adapter,
		     struct rtw_hal_mac_bcn_sync_rpt *ret_rpt)
{
	struct rtw_hal_mac_bcn_sync_rpt *rpt;

	rpt = &adapter->bcn_sync_rpt;
	PLTFM_MUTEX_LOCK(&adapter->bcn_sync_info.lock);
	PLTFM_MEMCPY(ret_rpt, rpt, sizeof(struct rtw_hal_mac_bcn_sync_rpt));
	rpt->valid = 0;
	PLTFM_MUTEX_UNLOCK(&adapter->bcn_sync_info.lock);
	return MACSUCCESS;
}
