blob: 40cee705ea9d27e8dc44186c2116c7f064398a4a [file] [log] [blame]
Yuanyuan Liud9f7a362016-01-22 14:27:12 -08001/*
2 * Copyright (c) 2016 The Linux Foundation. All rights reserved.
3 *
4 * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5 *
6 *
7 * Permission to use, copy, modify, and/or distribute this software for
8 * any purpose with or without fee is hereby granted, provided that the
9 * above copyright notice and this permission notice appear in all
10 * copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19 * PERFORMANCE OF THIS SOFTWARE.
20 */
21
22/*
23 * This file was originally distributed by Qualcomm Atheros, Inc.
24 * under proprietary terms before Copyright ownership was assigned
25 * to the Linux Foundation.
26 */
27
28#include <linux/platform_device.h>
29#include <linux/err.h>
30#include <linux/list.h>
31#include <linux/slab.h>
32
33#ifdef CONFIG_ICNSS
34#include <soc/qcom/icnss.h>
35#endif
36
37#include "pld_common.h"
38#include "pld_internal.h"
39
40#ifdef CONFIG_ICNSS
41/**
42 * pld_snoc_probe() - Probe function for platform driver
43 * @dev: device
44 *
45 * The probe function will be called when platform device
46 * is detected.
47 *
48 * Return: int
49 */
50static int pld_snoc_probe(struct device *dev)
51{
52 struct pld_context *pld_context;
53 unsigned long flags;
54 struct dev_node *dev_node;
55 int ret = 0;
56
57 pld_context = pld_get_global_context();
58 if (!pld_context) {
59 ret = -ENODEV;
60 goto out;
61 }
62
63 dev_node = kzalloc(sizeof(*dev_node), GFP_KERNEL);
64 if (dev_node == NULL) {
65 ret = -ENOMEM;
66 goto out;
67 }
68 dev_node->dev = dev;
69 dev_node->bus_type = PLD_BUS_TYPE_SNOC;
70
71 spin_lock_irqsave(&pld_context->pld_lock, flags);
72 list_add_tail(&dev_node->list, &pld_context->dev_list);
73 spin_unlock_irqrestore(&pld_context->pld_lock, flags);
74
75 return pld_context->ops->probe(dev, PLD_BUS_TYPE_SNOC,
76 NULL, NULL);
77
78out:
79 return ret;
80}
81
82/**
83 * pld_snoc_remove() - Remove function for platform device
84 * @dev: device
85 *
86 * The remove function will be called when platform device
87 * is disconnected
88 *
89 * Return: void
90 */
91static void pld_snoc_remove(struct device *dev)
92{
93 struct pld_context *pld_context;
94 unsigned long flags;
95 struct dev_node *dev_node, *tmp;
96
97 pld_context = pld_get_global_context();
98
99 if (!pld_context)
100 return;
101
102 spin_lock_irqsave(&pld_context->pld_lock, flags);
103 list_for_each_entry_safe(dev_node, tmp, &pld_context->dev_list, list) {
104 if (dev_node->dev == dev) {
105 list_del(&dev_node->list);
106 kfree(dev_node);
107 }
108 }
109 spin_unlock_irqrestore(&pld_context->pld_lock, flags);
110
111 pld_context->ops->remove(dev, PLD_BUS_TYPE_SNOC);
112}
113
114/**
115 * pld_snoc_reinit() - SSR re-initialize function for platform device
116 * @dev: device
117 *
118 * During subsystem restart(SSR), this function will be called to
119 * re-initialize platform device.
120 *
121 * Return: int
122 */
123static int pld_snoc_reinit(struct device *dev)
124{
125 struct pld_context *pld_context;
126
127 pld_context = pld_get_global_context();
128 if (pld_context->ops->reinit)
129 return pld_context->ops->reinit(dev, PLD_BUS_TYPE_SNOC,
130 NULL, NULL);
131
132 return -ENODEV;
133}
134
135/**
136 * pld_snoc_shutdown() - SSR shutdown function for platform device
137 * @dev: device
138 *
139 * During SSR, this function will be called to shutdown platform device.
140 *
141 * Return: void
142 */
143static void pld_snoc_shutdown(struct device *dev)
144{
145 struct pld_context *pld_context;
146
147 pld_context = pld_get_global_context();
148 if (pld_context->ops->shutdown)
149 pld_context->ops->shutdown(dev, PLD_BUS_TYPE_SNOC);
150}
151
152/**
153 * pld_snoc_crash_shutdown() - Crash shutdown function for platform device
154 * @dev: device
155 *
156 * This function will be called when a crash is detected, it will shutdown
157 * platform device.
158 *
159 * Return: void
160 */
161static void pld_snoc_crash_shutdown(void *dev)
162{
163 struct pld_context *pld_context;
164
165 pld_context = pld_get_global_context();
166 if (pld_context->ops->crash_shutdown)
167 pld_context->ops->crash_shutdown(dev, PLD_BUS_TYPE_SNOC);
168}
169
170/**
171 * pld_snoc_suspend() - Suspend callback function for power management
172 * @dev: device
173 * @state: power state
174 *
175 * This function is to suspend the platform device when power management
176 * is enabled.
177 *
178 * Return: void
179 */
180static int pld_snoc_suspend(struct device *dev, pm_message_t state)
181{
182 struct pld_context *pld_context;
183
184 pld_context = pld_get_global_context();
185 return pld_context->ops->suspend(dev, PLD_BUS_TYPE_SNOC, state);
186}
187
188/**
189 * pld_snoc_resume() - Resume callback function for power management
190 * @pdev: device
191 *
192 * This function is to resume the platform device when power management
193 * is enabled.
194 *
195 * Return: void
196 */
197static int pld_snoc_resume(struct device *dev)
198{
199 struct pld_context *pld_context;
200
201 pld_context = pld_get_global_context();
202 return pld_context->ops->resume(dev, PLD_BUS_TYPE_SNOC);
203}
204
205struct icnss_driver_ops pld_snoc_ops = {
206 .name = "pld_snoc",
207 .probe = pld_snoc_probe,
208 .remove = pld_snoc_remove,
209 .shutdown = pld_snoc_shutdown,
210 .reinit = pld_snoc_reinit,
211 .crash_shutdown = pld_snoc_crash_shutdown,
212 .suspend = pld_snoc_suspend,
213 .resume = pld_snoc_resume,
214};
215
216/**
217 * pld_snoc_register_driver() - Register platform device callback functions
218 *
219 * Return: int
220 */
221int pld_snoc_register_driver(void)
222{
223 return icnss_register_driver(&pld_snoc_ops);
224}
225
226/**
227 * pld_snoc_unregister_driver() - Unregister platform device callback functions
228 *
229 * Return: void
230 */
231void pld_snoc_unregister_driver(void)
232{
233 icnss_unregister_driver(&pld_snoc_ops);
234}
235
236/**
237 * pld_snoc_wlan_enable() - Enable WLAN
238 * @config: WLAN configuration data
239 * @mode: WLAN mode
240 * @host_version: host software version
241 *
242 * This function enables WLAN FW. It passed WLAN configuration data,
243 * WLAN mode and host software version to FW.
244 *
245 * Return: 0 for success
246 * Non zero failure code for errors
247 */
248int pld_snoc_wlan_enable(struct pld_wlan_enable_cfg *config,
249 enum pld_driver_mode mode, const char *host_version)
250{
251 struct icnss_wlan_enable_cfg cfg;
252 enum icnss_driver_mode icnss_mode;
253
254 cfg.num_ce_tgt_cfg = config->num_ce_tgt_cfg;
255 cfg.ce_tgt_cfg = (struct ce_tgt_pipe_cfg *)
256 config->ce_tgt_cfg;
257 cfg.num_ce_svc_pipe_cfg = config->num_ce_svc_pipe_cfg;
258 cfg.ce_svc_cfg = (struct ce_svc_pipe_cfg *)
259 config->ce_svc_cfg;
260 cfg.num_shadow_reg_cfg = config->num_shadow_reg_cfg;
261 cfg.shadow_reg_cfg = (struct icnss_shadow_reg_cfg *)
262 config->shadow_reg_cfg;
263
264 switch (mode) {
265 case PLD_FTM:
266 icnss_mode = ICNSS_FTM;
267 break;
268 case PLD_EPPING:
269 icnss_mode = ICNSS_EPPING;
270 break;
271 default:
272 icnss_mode = ICNSS_MISSION;
273 break;
274 }
275 return icnss_wlan_enable(&cfg, icnss_mode, host_version);
276}
277
278/**
279 * pld_snoc_wlan_disable() - Disable WLAN
280 * @mode: WLAN mode
281 *
282 * This function disables WLAN FW. It passes WLAN mode to FW.
283 *
284 * Return: 0 for success
285 * Non zero failure code for errors
286 */
287int pld_snoc_wlan_disable(enum pld_driver_mode mode)
288{
289 return icnss_wlan_disable(ICNSS_OFF);
290}
291
292/**
293 * pld_snoc_get_soc_info() - Get SOC information
294 * @info: buffer to SOC information
295 *
296 * Return SOC info to the buffer.
297 *
298 * Return: 0 for success
299 * Non zero failure code for errors
300 */
301int pld_snoc_get_soc_info(struct pld_soc_info *info)
302{
303 int ret = 0;
304 struct icnss_soc_info icnss_info;
305
306 if (info == NULL)
307 return -ENODEV;
308
309 ret = icnss_get_soc_info(&icnss_info);
310 if (0 != ret)
311 return ret;
312
313 memcpy(info, &icnss_info, sizeof(*info));
314 return 0;
315}
316
317#endif