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