Explorar o código

qcacmn: Add GPIO configuration OSIF code

Add OSIF APIs for GPIO config

Change-Id: I091c3b21a7dd12dfee5aa5f05d3d1d0557d16792
Chaoli Zhou %!s(int64=4) %!d(string=hai) anos
pai
achega
ef806a62d2

+ 57 - 0
os_if/linux/gpio/inc/wlan_cfg80211_gpio.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: wlan_cfg80211_gpio.h
+ *
+ * This Header file provide declaration for cfg80211 command handler API
+ */
+
+#ifndef __WLAN_CFG80211_GPIO_CFG_H__
+#define __WLAN_CFG80211_GPIO_CFG_H__
+
+#include <wlan_objmgr_cmn.h>
+#include <qdf_types.h>
+#include <net/cfg80211.h>
+#include <qca_vendor.h>
+
+#ifdef WLAN_FEATURE_GPIO_CFG
+
+extern const struct nla_policy
+	wlan_cfg80211_gpio_config_policy
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX + 1];
+
+/**
+ * wlan_cfg80211_start_gpio_config() - set GPIO config
+ * @psoc: pointer to psoc common object
+ * @data: Pointer to the data to be passed via vendor interface
+ * @data_len: Length of the data to be passed
+ *
+ * Return: Return the Success or Failure code
+ */
+int wlan_cfg80211_start_gpio_config(struct wiphy *wiphy,
+				    struct wlan_objmgr_psoc *psoc,
+				    const void *data, int data_len);
+#else
+static inline
+int wlan_cfg80211_start_gpio_config(struct wiphy *wiphy,
+				    struct wlan_objmgr_psoc *psoc,
+				    const void *data, int data_len)
+{
+	return 0;
+}
+#endif /* WLAN_FEATURE_GPIO_CFG */
+#endif /* __WLAN_CFG80211_GPIO_CFG_H__ */

+ 301 - 0
os_if/linux/gpio/src/wlan_cfg80211_gpio.c

@@ -0,0 +1,301 @@
+/*
+ * Copyright (c) 2020, The Linux Foundation. All rights reserved.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/**
+ * DOC: defines driver functions interfacing with linux kernel
+ */
+
+#include <qdf_list.h>
+#include <qdf_status.h>
+#include <linux/wireless.h>
+#include <linux/netdevice.h>
+#include <wlan_cfg80211.h>
+#include <wlan_osif_priv.h>
+#include <wlan_gpio_ucfg_api.h>
+#include <wlan_cfg80211_gpio.h>
+#include "qdf_module.h"
+
+const struct nla_policy
+wlan_cfg80211_gpio_config_policy[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX + 1] = {
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+	[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR] = {
+						.type = NLA_U32,
+						.len = sizeof(uint32_t) },
+};
+
+/**
+ * convert_vendor_gpio_direction() - Function to convert vendor gpio direction
+ * @dir: pointer to enum qca_gpio_direction
+ *
+ * Convert the vendor gpio direction to wmi unified gpio direction
+ *
+ * Return: wmi unified gpio direction
+ */
+static enum gpio_direction
+convert_vendor_gpio_direction(enum qca_gpio_direction dir)
+{
+	switch (dir) {
+	case QCA_WLAN_GPIO_INPUT:
+		return WMI_HOST_GPIO_INPUT;
+	case QCA_WLAN_GPIO_OUTPUT:
+		return WMI_HOST_GPIO_OUTPUT;
+	default:
+		return WMI_HOST_GPIO_INPUT;
+	}
+}
+
+/**
+ * convert_vendor_gpio_pull_type() - Function to convert vendor pull type
+ * @pull_type: pointer to enum qca_gpio_pull_type
+ *
+ * Convert the vendor pull type to wmi unified pull type
+ *
+ * Return: wmi unified gpio pull type
+ */
+static enum gpio_pull_type
+convert_vendor_gpio_pull_type(enum qca_gpio_pull_type pull_type)
+{
+	switch (pull_type) {
+	case QCA_WLAN_GPIO_PULL_NONE:
+		return WMI_HOST_GPIO_PULL_NONE;
+	case QCA_WLAN_GPIO_PULL_UP:
+		return WMI_HOST_GPIO_PULL_UP;
+	case QCA_WLAN_GPIO_PULL_DOWN:
+		return WMI_HOST_GPIO_PULL_DOWN;
+	default:
+		return WMI_HOST_GPIO_PULL_NONE;
+	}
+}
+
+/**
+ * convert_vendor_gpio_interrupt_mode() - Function to convert
+ * vendor interrupt mode
+ * @intr_mode: pointer to enum qca_gpio_interrupt_mode
+ *
+ * Convert the vendor interrupt mode to wmi unified interrupt mode
+ *
+ * Return: wmi unified gpio interrupt mode
+ */
+static enum gpio_interrupt_mode
+convert_vendor_gpio_interrupt_mode(enum qca_gpio_interrupt_mode intr_mode)
+{
+	switch (intr_mode) {
+	case QCA_WLAN_GPIO_INTMODE_DISABLE:
+		return WMI_HOST_GPIO_INTMODE_DISABLE;
+	case QCA_WLAN_GPIO_INTMODE_RISING_EDGE:
+		return WMI_HOST_GPIO_INTMODE_RISING_EDGE;
+	case QCA_WLAN_GPIO_INTMODE_FALLING_EDGE:
+		return WMI_HOST_GPIO_INTMODE_FALLING_EDGE;
+	case QCA_WLAN_GPIO_INTMODE_BOTH_EDGE:
+		return WMI_HOST_GPIO_INTMODE_BOTH_EDGE;
+	case QCA_WLAN_GPIO_INTMODE_LEVEL_LOW:
+		return WMI_HOST_GPIO_INTMODE_LEVEL_LOW;
+	case QCA_WLAN_GPIO_INTMODE_LEVEL_HIGH:
+		return WMI_HOST_GPIO_INTMODE_LEVEL_HIGH;
+	default:
+		return WMI_HOST_GPIO_INTMODE_DISABLE;
+	}
+}
+
+/**
+ * convert_vendor_gpio_output_value() - Function to convert vendor
+ * gpio output value
+ * @value: pointer to enum qca_gpio_value
+ *
+ * Convert the vendor gpio value to wmi unified gpio output value
+ *
+ * Return: wmi unified gpio output value
+ */
+static enum gpio_value
+convert_vendor_gpio_output_value(enum qca_gpio_value value)
+{
+	switch (value) {
+	case QCA_WLAN_GPIO_LEVEL_LOW:
+		return WMI_HOST_GPIO_LEVEL_LOW;
+	case QCA_WLAN_GPIO_LEVEL_HIGH:
+		return WMI_HOST_GPIO_LEVEL_HIGH;
+	default:
+		return WMI_HOST_GPIO_LEVEL_LOW;
+	}
+}
+
+/**
+ * wlan_set_gpio_config() - set the gpio configuration info
+ * @psoc: the pointer of wlan_objmgr_psoc
+ * @attr: list of attributes
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int
+wlan_set_gpio_config(struct wlan_objmgr_psoc *psoc,
+		     struct nlattr **attr)
+{
+	struct gpio_config_params cfg_param;
+	struct nlattr *gpio_attr;
+	enum qca_gpio_direction pin_dir;
+	enum qca_gpio_pull_type pull_type;
+	enum qca_gpio_interrupt_mode intr_mode;
+	QDF_STATUS status;
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM];
+	if (!gpio_attr) {
+		osif_err("attr gpio number failed");
+		return -EINVAL;
+	}
+	cfg_param.pin_num = nla_get_u32(gpio_attr);
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_DIR];
+	if (!gpio_attr) {
+		osif_err("attr gpio dir failed");
+		return -EINVAL;
+	}
+	pin_dir = nla_get_u32(gpio_attr);
+	if (pin_dir >= QCA_WLAN_GPIO_DIR_MAX) {
+		osif_err("attr gpio direction invalid");
+		return -EINVAL;
+	}
+	cfg_param.pin_dir = convert_vendor_gpio_direction(pin_dir);
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PULL_TYPE];
+	if (!gpio_attr) {
+		osif_err("attr gpio pull failed");
+		return -EINVAL;
+	}
+	pull_type = nla_get_u32(gpio_attr);
+	if (pull_type >= QCA_WLAN_GPIO_PULL_MAX) {
+		osif_err("attr gpio pull type invalid");
+		return -EINVAL;
+	}
+	cfg_param.pin_pull_type = convert_vendor_gpio_pull_type(pull_type);
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_INTR_MODE];
+	if (!gpio_attr) {
+		osif_err("attr gpio interrupt mode failed");
+		return -EINVAL;
+	}
+	intr_mode = nla_get_u32(gpio_attr);
+	if (intr_mode >= QCA_WLAN_GPIO_INTMODE_MAX) {
+		osif_err("attr gpio interrupt mode invalid");
+		return -EINVAL;
+	}
+	cfg_param.pin_intr_mode = convert_vendor_gpio_interrupt_mode(intr_mode);
+
+	status = ucfg_set_gpio_config(psoc, &cfg_param);
+	return status;
+}
+
+/**
+ * wlan_set_gpio_output() - set the gpio output info
+ * @psoc: the pointer of wlan_objmgr_psoc
+ * @attr: list of attributes
+ *
+ * Return: 0 on success; errno on failure
+ */
+static int
+wlan_set_gpio_output(struct wlan_objmgr_psoc *psoc,
+		     struct nlattr **attr)
+{
+	struct gpio_output_params out_param;
+	struct nlattr *gpio_attr;
+	enum qca_gpio_value pin_set;
+	QDF_STATUS status;
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_PINNUM];
+	if (!gpio_attr) {
+		osif_err("attr gpio number failed");
+		return -EINVAL;
+	}
+	out_param.pin_num = nla_get_u32(gpio_attr);
+
+	gpio_attr = attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_VALUE];
+	if (!gpio_attr) {
+		osif_err("attr gpio value failed");
+		return -EINVAL;
+	}
+	pin_set = nla_get_u32(gpio_attr);
+	if (pin_set >= QCA_WLAN_GPIO_LEVEL_MAX) {
+		osif_err("attr gpio level invalid");
+		return -EINVAL;
+	}
+	out_param.pin_set = convert_vendor_gpio_output_value(pin_set);
+
+	status = ucfg_set_gpio_output(psoc, &out_param);
+	return status;
+}
+
+/**
+ * wlan_cfg80211_start_gpio_config - Set the gpio configuration
+ * @wiphy: pointer to wiphy
+ * @psoc: the pointer of wlan_objmgr_psoc
+ * @data: pointer to data
+ * @data_len: data length
+ *
+ * __wlan_cfg80211_set_gpio_config will forward the GPIO setting to FW by
+ * WMI_GPIO_CONFIG/OUTPUT_CMDID
+ *
+ * Return: 0 on success; errno on failure
+ */
+int
+wlan_cfg80211_start_gpio_config(struct wiphy *wiphy,
+				struct wlan_objmgr_psoc *psoc,
+				const void *data,
+				int data_len)
+{
+	uint32_t command;
+	struct nlattr *attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX + 1];
+	int ret;
+
+	if (wlan_cfg80211_nla_parse(attr, QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_MAX,
+				    data, data_len,
+				    wlan_cfg80211_gpio_config_policy)) {
+		return -EINVAL;
+	}
+
+	if (attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND]) {
+		command = nla_get_u32(
+			attr[QCA_WLAN_VENDOR_ATTR_GPIO_PARAM_COMMAND]);
+
+		if (command == QCA_WLAN_VENDOR_GPIO_CONFIG) {
+			ret = wlan_set_gpio_config(psoc, attr);
+		} else if (command == QCA_WLAN_VENDOR_GPIO_OUTPUT) {
+			ret = wlan_set_gpio_output(psoc, attr);
+		} else {
+			osif_err("Invalid command");
+			return -EINVAL;
+		}
+	} else {
+		osif_err("Invalid command");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+qdf_export_symbol(wlan_cfg80211_start_gpio_config);
+