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
convert_vendor_gpio_direction(enum qca_gpio_direction dir)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
convert_vendor_gpio_pull_type(enum qca_gpio_pull_type 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
convert_vendor_gpio_interrupt_mode(enum qca_gpio_interrupt_mode intr_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
convert_vendor_gpio_output_value(enum qca_gpio_value 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
convert_vendor_gpio_drive(enum qca_gpio_drive 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
convert_vendor_gpio_init_enable(uint32_t internal_config)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
wlan_set_gpio_config(struct wlan_objmgr_psoc * psoc,struct nlattr ** attr)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
wlan_set_gpio_output(struct wlan_objmgr_psoc * psoc,struct nlattr ** attr)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
wlan_cfg80211_start_gpio_config(struct wiphy * wiphy,struct wlan_objmgr_psoc * psoc,const void * data,int data_len)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