1 /* 2 * Copyright (c) 2020, 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 /** 18 * DOC: defines driver functions interfacing with linux kernel 19 */ 20 21 #include <qdf_list.h> 22 #include <qdf_status.h> 23 #include <linux/wireless.h> 24 #include <linux/netdevice.h> 25 #include <wlan_cfg80211.h> 26 #include <wlan_osif_priv.h> 27 #include <wlan_gpio_ucfg_api.h> 28 #include <wlan_cfg80211_gpio.h> 29 #include "qdf_module.h" 30 31 const struct nla_policy 32 wlan_cfg80211_gpio_config_policy[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX + 1] = { 33 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND] = { 34 .type = NLA_U32, 35 .len = sizeof(uint32_t) }, 36 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM] = { 37 .type = NLA_U32, 38 .len = sizeof(uint32_t) }, 39 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE] = { 40 .type = NLA_U32, 41 .len = sizeof(uint32_t) }, 42 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE] = { 43 .type = NLA_U32, 44 .len = sizeof(uint32_t) }, 45 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE] = { 46 .type = NLA_U32, 47 .len = sizeof(uint32_t) }, 48 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR] = { 49 .type = NLA_U32, 50 .len = sizeof(uint32_t) }, 51 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG] = { 52 .type = NLA_U32, 53 .len = sizeof(uint32_t) }, 54 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE] = { 55 .type = NLA_U32, 56 .len = sizeof(uint32_t) }, 57 [QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG] = { 58 .type = NLA_U32, 59 .len = sizeof(uint32_t) }, 60 }; 61 62 /** 63 * convert_vendor_gpio_direction() - Function to convert vendor gpio direction 64 * @dir: pointer to enum qca_gpio_direction 65 * 66 * Convert the vendor gpio direction to wmi unified gpio direction 67 * 68 * Return: wmi unified gpio direction 69 */ 70 static enum gpio_direction 71 convert_vendor_gpio_direction(enum qca_gpio_direction dir) 72 { 73 switch (dir) { 74 case QCA_WLAN_GPIO_INPUT: 75 return WMI_HOST_GPIO_INPUT; 76 case QCA_WLAN_GPIO_OUTPUT: 77 return WMI_HOST_GPIO_OUTPUT; 78 default: 79 return WMI_HOST_GPIO_INPUT; 80 } 81 } 82 83 /** 84 * convert_vendor_gpio_pull_type() - Function to convert vendor pull type 85 * @pull_type: pointer to enum qca_gpio_pull_type 86 * 87 * Convert the vendor pull type to wmi unified pull type 88 * 89 * Return: wmi unified gpio pull type 90 */ 91 static enum gpio_pull_type 92 convert_vendor_gpio_pull_type(enum qca_gpio_pull_type pull_type) 93 { 94 switch (pull_type) { 95 case QCA_WLAN_GPIO_PULL_NONE: 96 return WMI_HOST_GPIO_PULL_NONE; 97 case QCA_WLAN_GPIO_PULL_UP: 98 return WMI_HOST_GPIO_PULL_UP; 99 case QCA_WLAN_GPIO_PULL_DOWN: 100 return WMI_HOST_GPIO_PULL_DOWN; 101 default: 102 return WMI_HOST_GPIO_PULL_NONE; 103 } 104 } 105 106 /** 107 * convert_vendor_gpio_interrupt_mode() - Function to convert 108 * vendor interrupt mode 109 * @intr_mode: pointer to enum qca_gpio_interrupt_mode 110 * 111 * Convert the vendor interrupt mode to wmi unified interrupt mode 112 * 113 * Return: wmi unified gpio interrupt mode 114 */ 115 static enum gpio_interrupt_mode 116 convert_vendor_gpio_interrupt_mode(enum qca_gpio_interrupt_mode intr_mode) 117 { 118 switch (intr_mode) { 119 case QCA_WLAN_GPIO_INTMODE_DISABLE: 120 return WMI_HOST_GPIO_INTMODE_DISABLE; 121 case QCA_WLAN_GPIO_INTMODE_RISING_EDGE: 122 return WMI_HOST_GPIO_INTMODE_RISING_EDGE; 123 case QCA_WLAN_GPIO_INTMODE_FALLING_EDGE: 124 return WMI_HOST_GPIO_INTMODE_FALLING_EDGE; 125 case QCA_WLAN_GPIO_INTMODE_BOTH_EDGE: 126 return WMI_HOST_GPIO_INTMODE_BOTH_EDGE; 127 case QCA_WLAN_GPIO_INTMODE_LEVEL_LOW: 128 return WMI_HOST_GPIO_INTMODE_LEVEL_LOW; 129 case QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH: 130 return WMI_HOST_GPIO_INTMODE_LEVEL_HIGH; 131 default: 132 return WMI_HOST_GPIO_INTMODE_DISABLE; 133 } 134 } 135 136 /** 137 * convert_vendor_gpio_output_value() - Function to convert vendor 138 * gpio output value 139 * @value: pointer to enum qca_gpio_value 140 * 141 * Convert the vendor gpio value to wmi unified gpio output value 142 * 143 * Return: wmi unified gpio output value 144 */ 145 static enum gpio_value 146 convert_vendor_gpio_output_value(enum qca_gpio_value value) 147 { 148 switch (value) { 149 case QCA_WLAN_GPIO_LEVEL_LOW: 150 return WMI_HOST_GPIO_LEVEL_LOW; 151 case QCA_WLAN_GPIO_LEVEL_HIGH: 152 return WMI_HOST_GPIO_LEVEL_HIGH; 153 default: 154 return WMI_HOST_GPIO_LEVEL_LOW; 155 } 156 } 157 158 /** 159 * convert_vendor_gpio_drive() - Function to convert vendor 160 * gpio drive 161 * @drive: value of enum gpio_drive 162 * 163 * Convert the vendor gpio drive to wmi unified gpio output drive 164 * 165 * Return: wmi unified gpio output drive config 166 */ 167 static enum gpio_drive 168 convert_vendor_gpio_drive(enum qca_gpio_drive drive) 169 { 170 switch (drive) { 171 case QCA_WLAN_GPIO_DRIVE_2MA: 172 return WMI_HOST_GPIO_DRIVE_2MA; 173 case QCA_WLAN_GPIO_DRIVE_4MA: 174 return WMI_HOST_GPIO_DRIVE_4MA; 175 case QCA_WLAN_GPIO_DRIVE_6MA: 176 return WMI_HOST_GPIO_DRIVE_6MA; 177 case QCA_WLAN_GPIO_DRIVE_8MA: 178 return WMI_HOST_GPIO_DRIVE_8MA; 179 case QCA_WLAN_GPIO_DRIVE_10MA: 180 return WMI_HOST_GPIO_DRIVE_10MA; 181 case QCA_WLAN_GPIO_DRIVE_12MA: 182 return WMI_HOST_GPIO_DRIVE_12MA; 183 case QCA_WLAN_GPIO_DRIVE_14MA: 184 return WMI_HOST_GPIO_DRIVE_14MA; 185 case QCA_WLAN_GPIO_DRIVE_16MA: 186 return WMI_HOST_GPIO_DRIVE_16MA; 187 default: 188 return WMI_HOST_GPIO_DRIVE_2MA; 189 } 190 } 191 192 /** 193 * convert_vendor_gpio_init_enable() - Function to convert vendor 194 * gpio init_enable 195 * @internal_config: Param to decide whether to use internal config 196 * 197 * Convert the vendor internal_config to wmi unified gpio output init_enable 198 * 199 * Return: wmi unified gpio output init_enable config 200 */ 201 static enum gpio_init_enable 202 convert_vendor_gpio_init_enable(uint32_t internal_config) 203 { 204 if(internal_config) 205 return WMI_HOST_GPIO_INIT_DISABLE; 206 else 207 return WMI_HOST_GPIO_INIT_ENABLE; 208 } 209 210 /** 211 * wlan_set_gpio_config() - set the gpio configuration info 212 * @psoc: the pointer of wlan_objmgr_psoc 213 * @attr: list of attributes 214 * 215 * Return: 0 on success; errno on failure 216 */ 217 static int 218 wlan_set_gpio_config(struct wlan_objmgr_psoc *psoc, 219 struct nlattr **attr) 220 { 221 struct gpio_config_params cfg_param; 222 struct nlattr *gpio_attr; 223 enum qca_gpio_direction pin_dir; 224 enum qca_gpio_pull_type pull_type; 225 enum qca_gpio_interrupt_mode intr_mode; 226 enum qca_gpio_drive drive; 227 uint32_t internal_config; 228 QDF_STATUS status; 229 230 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM]; 231 if (!gpio_attr) { 232 osif_err_rl("attr gpio number failed"); 233 return -EINVAL; 234 } 235 cfg_param.pin_num = nla_get_u32(gpio_attr); 236 237 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR]; 238 if (!gpio_attr) { 239 osif_err_rl("attr gpio dir failed"); 240 return -EINVAL; 241 } 242 pin_dir = nla_get_u32(gpio_attr); 243 if (pin_dir >= QCA_WLAN_GPIO_DIR_MAX) { 244 osif_err_rl("attr gpio direction invalid"); 245 return -EINVAL; 246 } 247 cfg_param.pin_dir = convert_vendor_gpio_direction(pin_dir); 248 249 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE]; 250 if (!gpio_attr) { 251 osif_err_rl("attr gpio pull failed"); 252 return -EINVAL; 253 } 254 pull_type = nla_get_u32(gpio_attr); 255 if (pull_type >= QCA_WLAN_GPIO_PULL_MAX) { 256 osif_err_rl("attr gpio pull type invalid"); 257 return -EINVAL; 258 } 259 cfg_param.pin_pull_type = convert_vendor_gpio_pull_type(pull_type); 260 261 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE]; 262 if (!gpio_attr) { 263 osif_err_rl("attr gpio interrupt mode failed"); 264 return -EINVAL; 265 } 266 intr_mode = nla_get_u32(gpio_attr); 267 if (intr_mode >= QCA_WLAN_GPIO_INTMODE_MAX) { 268 osif_err_rl("attr gpio interrupt mode invalid"); 269 return -EINVAL; 270 } 271 cfg_param.pin_intr_mode = convert_vendor_gpio_interrupt_mode(intr_mode); 272 273 /* Below are optional parameters. Initialize to zero */ 274 cfg_param.mux_config_val = WMI_HOST_GPIO_MUX_DEFAULT; 275 cfg_param.drive = WMI_HOST_GPIO_DRIVE_2MA; 276 cfg_param.init_enable = WMI_HOST_GPIO_INIT_DISABLE; 277 278 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MUX_CONFIG]; 279 if (gpio_attr) { 280 cfg_param.mux_config_val = nla_get_u32(gpio_attr); 281 } 282 283 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DRIVE]; 284 if (gpio_attr) { 285 drive = nla_get_u32(gpio_attr); 286 if (drive >= QCA_WLAN_GPIO_DRIVE_MAX) { 287 osif_err_rl("attr gpio drive invalid"); 288 return -EINVAL; 289 } 290 cfg_param.drive = convert_vendor_gpio_drive(drive); 291 } 292 293 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTERNAL_CONFIG]; 294 if (gpio_attr) { 295 internal_config = nla_get_u32(gpio_attr); 296 cfg_param.init_enable = 297 convert_vendor_gpio_init_enable(internal_config); 298 } 299 300 status = ucfg_set_gpio_config(psoc, &cfg_param); 301 return status; 302 } 303 304 /** 305 * wlan_set_gpio_output() - set the gpio output info 306 * @psoc: the pointer of wlan_objmgr_psoc 307 * @attr: list of attributes 308 * 309 * Return: 0 on success; errno on failure 310 */ 311 static int 312 wlan_set_gpio_output(struct wlan_objmgr_psoc *psoc, 313 struct nlattr **attr) 314 { 315 struct gpio_output_params out_param; 316 struct nlattr *gpio_attr; 317 enum qca_gpio_value pin_set; 318 QDF_STATUS status; 319 320 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM]; 321 if (!gpio_attr) { 322 osif_err_rl("attr gpio number failed"); 323 return -EINVAL; 324 } 325 out_param.pin_num = nla_get_u32(gpio_attr); 326 327 gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE]; 328 if (!gpio_attr) { 329 osif_err_rl("attr gpio value failed"); 330 return -EINVAL; 331 } 332 pin_set = nla_get_u32(gpio_attr); 333 if (pin_set >= QCA_WLAN_GPIO_LEVEL_MAX) { 334 osif_err_rl("attr gpio level invalid"); 335 return -EINVAL; 336 } 337 out_param.pin_set = convert_vendor_gpio_output_value(pin_set); 338 339 status = ucfg_set_gpio_output(psoc, &out_param); 340 return status; 341 } 342 343 /** 344 * wlan_cfg80211_start_gpio_config - Set the gpio configuration 345 * @wiphy: pointer to wiphy 346 * @psoc: the pointer of wlan_objmgr_psoc 347 * @data: pointer to data 348 * @data_len: data length 349 * 350 * __wlan_cfg80211_set_gpio_config will forward the GPIO setting to FW by 351 * WMI_GPIO_CONFIG/OUTPUT_CMDID 352 * 353 * Return: 0 on success; errno on failure 354 */ 355 int 356 wlan_cfg80211_start_gpio_config(struct wiphy *wiphy, 357 struct wlan_objmgr_psoc *psoc, 358 const void *data, 359 int data_len) 360 { 361 uint32_t command; 362 struct nlattr *attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX + 1]; 363 int ret; 364 365 if (wlan_cfg80211_nla_parse(attr, QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX, 366 data, data_len, 367 wlan_cfg80211_gpio_config_policy)) { 368 return -EINVAL; 369 } 370 371 if (attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND]) { 372 command = nla_get_u32( 373 attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND]); 374 375 if (command == QCA_WLAN_VENDOR_GPIO_CONFIG) { 376 ret = wlan_set_gpio_config(psoc, attr); 377 } else if (command == QCA_WLAN_VENDOR_GPIO_OUTPUT) { 378 ret = wlan_set_gpio_output(psoc, attr); 379 } else { 380 osif_err_rl("Invalid command"); 381 return -EINVAL; 382 } 383 } else { 384 osif_err_rl("Invalid command"); 385 return -EINVAL; 386 } 387 388 return ret; 389 } 390 qdf_export_symbol(wlan_cfg80211_start_gpio_config); 391 392