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