1 /* 2 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved. 3 * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <osdep.h> 19 #include <wmi.h> 20 #include <wmi_unified_priv.h> 21 #include <wmi_unified_gpio_api.h> 22 23 /** 24 * convert_gpio_direction() - Function to convert unified gpio direction 25 * @dir: pointer to enum gpio_direction 26 * 27 * Convert the wmi unified gpio direction to FW TLV WMI gpio direction 28 * 29 * Return: 30 * 0 - Output 31 * 1 - Input 32 */ 33 static uint32_t 34 convert_gpio_direction(enum gpio_direction dir) 35 { 36 switch (dir) { 37 case WMI_HOST_GPIO_INPUT: 38 return WMI_FW_GPIO_INPUT; 39 case WMI_HOST_GPIO_OUTPUT: 40 return WMI_FW_GPIO_OUTPUT; 41 default: 42 return WMI_FW_GPIO_OUTPUT; 43 } 44 } 45 46 /** 47 * convert_gpio_pull_type() - Function to convert unified pull type 48 * @pull_type: pointer to enum gpio_pull_type 49 * 50 * Convert the wmi unified pull type to FW TLV WMI gpio pull type 51 * 52 * Return: FW TLV WMI gpio pull type 53 */ 54 static uint32_t 55 convert_gpio_pull_type(enum gpio_pull_type pull_type) 56 { 57 switch (pull_type) { 58 case WMI_HOST_GPIO_PULL_NONE: 59 return WMI_GPIO_PULL_NONE; 60 case WMI_HOST_GPIO_PULL_UP: 61 return WMI_GPIO_PULL_UP; 62 case WMI_HOST_GPIO_PULL_DOWN: 63 return WMI_GPIO_PULL_DOWN; 64 default: 65 return WMI_GPIO_PULL_NONE; 66 } 67 } 68 69 /** 70 * convert_gpio_interrupt_mode() - Function to convert unified interrupt mode 71 * @intr_mode: pointer to enum gpio_interrupt_mode 72 * 73 * Convert the wmi unified interrupt mode to FW TLV WMI gpio interrupt mode 74 * 75 * Return: FW TLV WMI gpio interrupt mode 76 */ 77 static uint32_t 78 convert_gpio_interrupt_mode(enum gpio_interrupt_mode intr_mode) 79 { 80 switch (intr_mode) { 81 case WMI_HOST_GPIO_INTMODE_DISABLE: 82 return WMI_GPIO_INTTYPE_DISABLE; 83 case WMI_HOST_GPIO_INTMODE_RISING_EDGE: 84 return WMI_GPIO_INTTYPE_RISING_EDGE; 85 case WMI_HOST_GPIO_INTMODE_FALLING_EDGE: 86 return WMI_GPIO_INTTYPE_FALLING_EDGE; 87 case WMI_HOST_GPIO_INTMODE_BOTH_EDGE: 88 return WMI_GPIO_INTTYPE_BOTH_EDGE; 89 case WMI_HOST_GPIO_INTMODE_LEVEL_LOW: 90 return WMI_GPIO_INTTYPE_LEVEL_LOW; 91 case WMI_HOST_GPIO_INTMODE_LEVEL_HIGH: 92 return WMI_GPIO_INTTYPE_LEVEL_HIGH; 93 default: 94 return WMI_GPIO_INTTYPE_DISABLE; 95 } 96 } 97 98 /** 99 * convert_gpio_output_value() - Function to convert unified gpio output value 100 * @value: pointer to enum gpio_value 101 * 102 * Convert the wmi unified gpio output value to FW TLV WMI gpio output value 103 * 104 * Return: 105 * 0 - Output low level 106 * 1 - Output high level 107 */ 108 static uint32_t 109 convert_gpio_output_value(enum gpio_value value) 110 { 111 switch (value) { 112 case WMI_HOST_GPIO_LEVEL_LOW: 113 return 0; 114 case WMI_HOST_GPIO_LEVEL_HIGH: 115 return 1; 116 default: 117 return 0; 118 } 119 } 120 121 /** 122 * send_gpio_config_cmd_tlv() - send gpio config to fw 123 * @wmi_handle: wmi handle 124 * @param: pointer to hold gpio config params 125 * 126 * Send gpio configuration to firmware. 127 * 128 * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure 129 */ 130 static QDF_STATUS 131 send_gpio_config_cmd_tlv(wmi_unified_t wmi_handle, 132 struct gpio_config_params *param) 133 { 134 wmi_gpio_config_cmd_fixed_param *cmd; 135 wmi_buf_t buf; 136 int32_t len; 137 QDF_STATUS ret; 138 139 len = sizeof(*cmd); 140 141 /* Sanity Checks */ 142 if (param->pin_pull_type >= WMI_HOST_GPIO_PULL_MAX || 143 param->pin_intr_mode >= WMI_HOST_GPIO_INTMODE_MAX || 144 param->pin_dir >= WMI_HOST_GPIO_DIR_MAX) { 145 return QDF_STATUS_E_FAILURE; 146 } 147 148 buf = wmi_buf_alloc(wmi_handle, len); 149 if (!buf) 150 return QDF_STATUS_E_FAILURE; 151 152 cmd = (wmi_gpio_config_cmd_fixed_param *)wmi_buf_data(buf); 153 WMITLV_SET_HDR(&cmd->tlv_header, 154 WMITLV_TAG_STRUC_wmi_gpio_config_cmd_fixed_param, 155 WMITLV_GET_STRUCT_TLVLEN( 156 wmi_gpio_config_cmd_fixed_param)); 157 cmd->gpio_num = param->pin_num; 158 cmd->input = convert_gpio_direction(param->pin_dir); 159 cmd->pull_type = convert_gpio_pull_type(param->pin_pull_type); 160 cmd->intr_mode = convert_gpio_interrupt_mode(param->pin_intr_mode); 161 cmd->mux_config_val = param->mux_config_val; 162 cmd->drive = param->drive; 163 cmd->init_enable = param->init_enable; 164 165 wmi_debug("GPIO num %d, input-dir %d, pull_type %d, intr_mode %d" 166 " mux_config_val %d drive %d init_enable %d", 167 cmd->gpio_num, cmd->input, cmd->pull_type, cmd->intr_mode, 168 cmd->mux_config_val, cmd->drive, cmd->init_enable); 169 170 wmi_mtrace(WMI_GPIO_CONFIG_CMDID, NO_SESSION, 0); 171 ret = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), 172 WMI_GPIO_CONFIG_CMDID); 173 174 if (QDF_IS_STATUS_ERROR(ret)) { 175 wmi_err("Sending GPIO config cmd failed"); 176 wmi_buf_free(buf); 177 } 178 179 return ret; 180 } 181 182 /** 183 * send_gpio_output_cmd_tlv() - send gpio output to fw 184 * @wmi_handle: wmi handle 185 * @param: pointer to hold gpio output param 186 * 187 * Send gpio output value to firmware. 188 * 189 * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure 190 */ 191 static QDF_STATUS 192 send_gpio_output_cmd_tlv(wmi_unified_t wmi_handle, 193 struct gpio_output_params *param) 194 { 195 wmi_gpio_output_cmd_fixed_param *cmd; 196 wmi_buf_t buf; 197 int32_t len; 198 QDF_STATUS ret; 199 200 len = sizeof(*cmd); 201 202 /* Sanity Checks */ 203 if (param->pin_set >= WMI_HOST_GPIO_LEVEL_MAX) 204 return QDF_STATUS_E_FAILURE; 205 206 buf = wmi_buf_alloc(wmi_handle, len); 207 if (!buf) 208 return QDF_STATUS_E_FAILURE; 209 210 cmd = (wmi_gpio_output_cmd_fixed_param *)wmi_buf_data(buf); 211 WMITLV_SET_HDR(&cmd->tlv_header, 212 WMITLV_TAG_STRUC_wmi_gpio_output_cmd_fixed_param, 213 WMITLV_GET_STRUCT_TLVLEN( 214 wmi_gpio_output_cmd_fixed_param)); 215 cmd->gpio_num = param->pin_num; 216 cmd->set = convert_gpio_output_value(param->pin_set); 217 218 wmi_debug("GPIO num %d, set %d", cmd->gpio_num, cmd->set); 219 wmi_mtrace(WMI_GPIO_OUTPUT_CMDID, NO_SESSION, 0); 220 ret = wmi_unified_cmd_send(wmi_handle, buf, sizeof(*cmd), 221 WMI_GPIO_OUTPUT_CMDID); 222 223 if (QDF_IS_STATUS_ERROR(ret)) { 224 wmi_err("Sending GPIO output cmd failed"); 225 wmi_buf_free(buf); 226 } 227 228 return ret; 229 } 230 231 void wmi_gpio_attach_tlv(wmi_unified_t wmi_handle) 232 { 233 struct wmi_ops *ops = wmi_handle->ops; 234 235 ops->send_gpio_config_cmd = send_gpio_config_cmd_tlv; 236 ops->send_gpio_output_cmd = send_gpio_output_cmd_tlv; 237 } 238 239