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