blob: 1430c9e34fde0eedf862e1a65d283c952fe05a9d [file] [log] [blame]
Ashish Jain19ef2602018-05-10 16:49:46 +05301/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
Laxminath Kasamd1f36192017-08-03 18:54:01 +05302 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#include <linux/init.h>
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/mutex.h>
17#include <linux/errno.h>
18#include <linux/fs.h>
19#include <linux/uaccess.h>
20#include <linux/slab.h>
21#include <linux/list.h>
22#include <linux/cdev.h>
23#include <linux/platform_device.h>
24#include <linux/vmalloc.h>
Ashish Jain19ef2602018-05-10 16:49:46 +053025#include <linux/of_device.h>
Laxminath Kasamd1f36192017-08-03 18:54:01 +053026#include <soc/qcom/glink.h>
27#include "sound/wcd-dsp-glink.h"
28
29#define WDSP_GLINK_DRIVER_NAME "wcd-dsp-glink"
30#define WDSP_MAX_WRITE_SIZE (256 * 1024)
31#define WDSP_MAX_READ_SIZE (4 * 1024)
32#define WDSP_MAX_NO_OF_INTENTS (20)
33#define WDSP_MAX_NO_OF_CHANNELS (10)
34#define WDSP_WRITE_PKT_SIZE (sizeof(struct wdsp_write_pkt))
35#define WDSP_REG_PKT_SIZE (sizeof(struct wdsp_reg_pkt))
36#define WDSP_CMD_PKT_SIZE (sizeof(struct wdsp_cmd_pkt))
37#define WDSP_CH_CFG_SIZE (sizeof(struct wdsp_glink_ch_cfg))
38
39#define MINOR_NUMBER_COUNT 1
40#define WDSP_EDGE "wdsp"
41#define RESP_QUEUE_SIZE 3
42#define QOS_PKT_SIZE 1024
43#define TIMEOUT_MS 1000
Ashish Jain19ef2602018-05-10 16:49:46 +053044#define GLINK_EDGE_MAX 16
Laxminath Kasamd1f36192017-08-03 18:54:01 +053045
46struct wdsp_glink_dev {
47 struct class *cls;
48 struct device *dev;
49 struct cdev cdev;
50 dev_t dev_num;
Ashish Jain19ef2602018-05-10 16:49:46 +053051 char glink_edge[GLINK_EDGE_MAX];
Laxminath Kasamd1f36192017-08-03 18:54:01 +053052};
53
54struct wdsp_glink_rsp_que {
55 /* Size of valid data in buffer */
56 u32 buf_size;
57
58 /* Response buffer */
59 u8 buf[WDSP_MAX_READ_SIZE];
60};
61
62struct wdsp_glink_tx_buf {
63 struct work_struct tx_work;
64 struct work_struct free_tx_work;
65
66 /* Glink channel information */
67 struct wdsp_glink_ch *ch;
68
69 /* Tx buffer to send to glink */
70 u8 buf[0];
71};
72
73struct wdsp_glink_ch {
74 struct wdsp_glink_priv *wpriv;
75
76 /* Glink channel handle */
77 void *handle;
78
79 /* Channel states like connect, disconnect */
80 int channel_state;
81 struct mutex mutex;
82
83 /* To free up the channel memory */
84 bool free_mem;
85
86 /* Glink local channel open work */
87 struct work_struct lcl_ch_open_wrk;
88
89 /* Glink local channel close work */
90 struct work_struct lcl_ch_cls_wrk;
91
92 /* Wait for ch connect state before sending any command */
93 wait_queue_head_t ch_connect_wait;
94
Bala Kishore Patic756a942018-09-24 17:33:46 +053095 /* Wait for ch local and remote disconnect before channel free */
96 wait_queue_head_t ch_free_wait;
97
Laxminath Kasamd1f36192017-08-03 18:54:01 +053098 /*
99 * Glink channel configuration. This has to be the last
100 * member of the strucuture as it has variable size
101 */
102 struct wdsp_glink_ch_cfg ch_cfg;
103};
104
105struct wdsp_glink_state {
106 /* Glink link state information */
107 enum glink_link_state link_state;
108 void *handle;
109};
110
111struct wdsp_glink_priv {
112 /* Respone buffer related */
113 u8 rsp_cnt;
114 struct wdsp_glink_rsp_que rsp[RESP_QUEUE_SIZE];
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800115 u8 write_idx;
116 u8 read_idx;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530117 struct completion rsp_complete;
118 struct mutex rsp_mutex;
119
120 /* Glink channel related */
121 struct mutex glink_mutex;
122 struct wdsp_glink_state glink_state;
123 struct wdsp_glink_ch **ch;
124 u8 no_of_channels;
125 struct work_struct ch_open_cls_wrk;
126 struct workqueue_struct *work_queue;
Ashish Jain19ef2602018-05-10 16:49:46 +0530127 const char *glink_edge;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530128
129 wait_queue_head_t link_state_wait;
130
131 struct device *dev;
132};
133
134static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch);
135static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch);
136
137/*
138 * wdsp_glink_free_tx_buf_work - Work function to free tx pkt
139 * work: Work structure
140 */
141static void wdsp_glink_free_tx_buf_work(struct work_struct *work)
142{
143 struct wdsp_glink_tx_buf *tx_buf;
144
145 tx_buf = container_of(work, struct wdsp_glink_tx_buf,
146 free_tx_work);
147 vfree(tx_buf);
148}
149
150/*
151 * wdsp_glink_free_tx_buf - Function to free tx buffer
152 * priv: Pointer to the channel
153 * pkt_priv: Pointer to the tx buffer
154 */
155static void wdsp_glink_free_tx_buf(const void *priv, const void *pkt_priv)
156{
157 struct wdsp_glink_tx_buf *tx_buf = (struct wdsp_glink_tx_buf *)pkt_priv;
158 struct wdsp_glink_priv *wpriv;
159 struct wdsp_glink_ch *ch;
160
161 if (!priv) {
162 pr_err("%s: Invalid priv\n", __func__);
163 return;
164 }
165 if (!tx_buf) {
166 pr_err("%s: Invalid tx_buf\n", __func__);
167 return;
168 }
169
170 ch = (struct wdsp_glink_ch *)priv;
171 wpriv = ch->wpriv;
172 /* Work queue to free tx pkt */
173 INIT_WORK(&tx_buf->free_tx_work, wdsp_glink_free_tx_buf_work);
174 queue_work(wpriv->work_queue, &tx_buf->free_tx_work);
175}
176
177/*
178 * wdsp_glink_notify_rx - Glink notify rx callback for responses
179 * handle: Opaque Channel handle returned by GLink
180 * priv: Private pointer to the channel
181 * pkt_priv: Private pointer to the packet
182 * ptr: Pointer to the Rx data
183 * size: Size of the Rx data
184 */
185static void wdsp_glink_notify_rx(void *handle, const void *priv,
186 const void *pkt_priv, const void *ptr,
187 size_t size)
188{
189 u8 *rx_buf;
190 u8 rsp_cnt;
191 struct wdsp_glink_ch *ch;
192 struct wdsp_glink_priv *wpriv;
193
194 if (!ptr || !priv) {
195 pr_err("%s: Invalid parameters\n", __func__);
196 return;
197 }
198
199 ch = (struct wdsp_glink_ch *)priv;
200 wpriv = ch->wpriv;
201 rx_buf = (u8 *)ptr;
202 if (size > WDSP_MAX_READ_SIZE) {
203 dev_err(wpriv->dev, "%s: Size %zd is greater than allowed %d\n",
204 __func__, size, WDSP_MAX_READ_SIZE);
205 size = WDSP_MAX_READ_SIZE;
206 }
207
208 mutex_lock(&wpriv->rsp_mutex);
209 rsp_cnt = wpriv->rsp_cnt;
210 if (rsp_cnt >= RESP_QUEUE_SIZE) {
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800211 dev_err(wpriv->dev, "%s: Resp Queue is Full. Ignore latest and keep oldest.\n",
212 __func__);
213 mutex_unlock(&wpriv->rsp_mutex);
214 glink_rx_done(handle, ptr, true);
215 return;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530216 }
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800217 dev_dbg(wpriv->dev, "%s: rsp_cnt = %d copy into buffer %d\n",
218 __func__, rsp_cnt, wpriv->write_idx);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530219
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800220 memcpy(wpriv->rsp[wpriv->write_idx].buf, rx_buf, size);
221 wpriv->rsp[wpriv->write_idx].buf_size = size;
222
223 wpriv->write_idx = (wpriv->write_idx + 1) % RESP_QUEUE_SIZE;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530224 wpriv->rsp_cnt = ++rsp_cnt;
225 mutex_unlock(&wpriv->rsp_mutex);
226
227 glink_rx_done(handle, ptr, true);
228 complete(&wpriv->rsp_complete);
229}
230
231/*
232 * wdsp_glink_notify_tx_done - Glink notify tx done callback to
233 * free tx buffer
234 * handle: Opaque Channel handle returned by GLink
235 * priv: Private pointer to the channel
236 * pkt_priv: Private pointer to the packet
237 * ptr: Pointer to the Tx data
238 */
239static void wdsp_glink_notify_tx_done(void *handle, const void *priv,
240 const void *pkt_priv, const void *ptr)
241{
242 wdsp_glink_free_tx_buf(priv, pkt_priv);
243}
244/*
245 * wdsp_glink_notify_tx_abort - Glink notify tx abort callback to
246 * free tx buffer
247 * handle: Opaque Channel handle returned by GLink
248 * priv: Private pointer to the channel
249 * pkt_priv: Private pointer to the packet
250 */
251static void wdsp_glink_notify_tx_abort(void *handle, const void *priv,
252 const void *pkt_priv)
253{
254 wdsp_glink_free_tx_buf(priv, pkt_priv);
255}
256
257/*
258 * wdsp_glink_notify_rx_intent_req - Glink notify rx intent request callback
259 * to queue buffer to receive from remote client
260 * handle: Opaque channel handle returned by GLink
261 * priv: Private pointer to the channel
262 * req_size: Size of intent to be queued
263 */
264static bool wdsp_glink_notify_rx_intent_req(void *handle, const void *priv,
265 size_t req_size)
266{
267 struct wdsp_glink_priv *wpriv;
268 struct wdsp_glink_ch *ch;
269 int rc = 0;
270 bool ret = false;
271
272 if (!priv) {
273 pr_err("%s: Invalid priv\n", __func__);
274 goto done;
275 }
276 if (req_size > WDSP_MAX_READ_SIZE) {
277 pr_err("%s: Invalid req_size %zd\n", __func__, req_size);
278 goto done;
279 }
280
281 ch = (struct wdsp_glink_ch *)priv;
282 wpriv = ch->wpriv;
283
284 dev_dbg(wpriv->dev, "%s: intent size %zd requested for ch name %s",
285 __func__, req_size, ch->ch_cfg.name);
286
287 mutex_lock(&ch->mutex);
288 rc = glink_queue_rx_intent(ch->handle, ch, req_size);
289 if (rc < 0) {
290 dev_err(wpriv->dev, "%s: Failed to queue rx intent, rc = %d\n",
291 __func__, rc);
292 mutex_unlock(&ch->mutex);
293 goto done;
294 }
295 mutex_unlock(&ch->mutex);
296 ret = true;
297
298done:
299 return ret;
300}
301
302/*
303 * wdsp_glink_lcl_ch_open_wrk - Work function to open channel again
304 * when local disconnect event happens
305 * work: Work structure
306 */
307static void wdsp_glink_lcl_ch_open_wrk(struct work_struct *work)
308{
309 struct wdsp_glink_ch *ch;
310
311 ch = container_of(work, struct wdsp_glink_ch,
312 lcl_ch_open_wrk);
313
314 wdsp_glink_open_ch(ch);
315}
316
317/*
318 * wdsp_glink_lcl_ch_cls_wrk - Work function to close channel locally
319 * when remote disconnect event happens
320 * work: Work structure
321 */
322static void wdsp_glink_lcl_ch_cls_wrk(struct work_struct *work)
323{
324 struct wdsp_glink_ch *ch;
325
326 ch = container_of(work, struct wdsp_glink_ch,
327 lcl_ch_cls_wrk);
328
329 wdsp_glink_close_ch(ch);
330}
331
332/*
333 * wdsp_glink_notify_state - Glink channel state information event callback
334 * handle: Opaque Channel handle returned by GLink
335 * priv: Private pointer to the channel
336 * event: channel state event
337 */
338static void wdsp_glink_notify_state(void *handle, const void *priv,
339 unsigned int event)
340{
341 struct wdsp_glink_priv *wpriv;
342 struct wdsp_glink_ch *ch;
343 int i, ret = 0;
344
345 if (!priv) {
346 pr_err("%s: Invalid priv\n", __func__);
347 return;
348 }
349
350 ch = (struct wdsp_glink_ch *)priv;
351 wpriv = ch->wpriv;
352
353 mutex_lock(&ch->mutex);
354 ch->channel_state = event;
355 if (event == GLINK_CONNECTED) {
Bala Kishore Patic756a942018-09-24 17:33:46 +0530356 dev_info_ratelimited(wpriv->dev, "%s: glink channel: %s connected\n",
357 __func__, ch->ch_cfg.name);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530358
359 for (i = 0; i < ch->ch_cfg.no_of_intents; i++) {
360 dev_dbg(wpriv->dev, "%s: intent_size = %d\n", __func__,
361 ch->ch_cfg.intents_size[i]);
362 ret = glink_queue_rx_intent(ch->handle, ch,
363 ch->ch_cfg.intents_size[i]);
364 if (ret < 0)
365 dev_warn(wpriv->dev, "%s: Failed to queue intent %d of size %d\n",
366 __func__, i,
367 ch->ch_cfg.intents_size[i]);
368 }
369
370 ret = glink_qos_latency(ch->handle, ch->ch_cfg.latency_in_us,
371 QOS_PKT_SIZE);
372 if (ret < 0)
373 dev_warn(wpriv->dev, "%s: Failed to request qos %d for ch %s\n",
374 __func__, ch->ch_cfg.latency_in_us,
375 ch->ch_cfg.name);
376
377 wake_up(&ch->ch_connect_wait);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530378 } else if (event == GLINK_LOCAL_DISCONNECTED) {
379 /*
380 * Don't use dev_dbg here as dev may not be valid if channel
381 * closed from driver close.
382 */
Bala Kishore Patic756a942018-09-24 17:33:46 +0530383 pr_info_ratelimited("%s: channel: %s disconnected locally\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530384 __func__, ch->ch_cfg.name);
385 mutex_unlock(&ch->mutex);
386
Bala Kishore Patic756a942018-09-24 17:33:46 +0530387 ch->free_mem = true;
388 wake_up(&ch->ch_free_wait);
389 return;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530390 } else if (event == GLINK_REMOTE_DISCONNECTED) {
Bala Kishore Patic756a942018-09-24 17:33:46 +0530391 pr_info_ratelimited("%s: remote channel: %s disconnected remotely\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530392 __func__, ch->ch_cfg.name);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530393 /*
394 * If remote disconnect happens, local side also has
395 * to close the channel as per glink design in a
396 * separate work_queue.
397 */
Bala Kishore Patic756a942018-09-24 17:33:46 +0530398 if (wpriv && wpriv->work_queue != NULL)
399 queue_work(wpriv->work_queue, &ch->lcl_ch_cls_wrk);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530400 }
Bala Kishore Patic756a942018-09-24 17:33:46 +0530401 mutex_unlock(&ch->mutex);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530402}
403
404/*
405 * wdsp_glink_close_ch - Internal function to close glink channel
406 * ch: Glink Channel structure.
407 */
408static int wdsp_glink_close_ch(struct wdsp_glink_ch *ch)
409{
410 struct wdsp_glink_priv *wpriv = ch->wpriv;
411 int ret = 0;
412
413 mutex_lock(&wpriv->glink_mutex);
414 if (ch->handle) {
415 ret = glink_close(ch->handle);
Bala Kishore Patic756a942018-09-24 17:33:46 +0530416 ch->handle = NULL;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530417 if (ret < 0) {
418 dev_err(wpriv->dev, "%s: glink_close is failed, ret = %d\n",
419 __func__, ret);
420 } else {
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530421 dev_dbg(wpriv->dev, "%s: ch %s is closed\n", __func__,
422 ch->ch_cfg.name);
423 }
424 } else {
425 dev_dbg(wpriv->dev, "%s: ch %s is already closed\n", __func__,
426 ch->ch_cfg.name);
427 }
428 mutex_unlock(&wpriv->glink_mutex);
429
430
431 return ret;
432}
433
434/*
435 * wdsp_glink_open_ch - Internal function to open glink channel
436 * ch: Glink Channel structure.
437 */
438static int wdsp_glink_open_ch(struct wdsp_glink_ch *ch)
439{
440 struct wdsp_glink_priv *wpriv = ch->wpriv;
441 struct glink_open_config open_cfg;
442 int ret = 0;
443
444 mutex_lock(&wpriv->glink_mutex);
445 if (!ch->handle) {
446 memset(&open_cfg, 0, sizeof(open_cfg));
447 open_cfg.options = GLINK_OPT_INITIAL_XPORT;
Ashish Jain19ef2602018-05-10 16:49:46 +0530448 open_cfg.edge = wpriv->glink_edge;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530449 open_cfg.notify_rx = wdsp_glink_notify_rx;
450 open_cfg.notify_tx_done = wdsp_glink_notify_tx_done;
451 open_cfg.notify_tx_abort = wdsp_glink_notify_tx_abort;
452 open_cfg.notify_state = wdsp_glink_notify_state;
453 open_cfg.notify_rx_intent_req = wdsp_glink_notify_rx_intent_req;
454 open_cfg.priv = ch;
455 open_cfg.name = ch->ch_cfg.name;
456
457 dev_dbg(wpriv->dev, "%s: ch->ch_cfg.name = %s, latency_in_us = %d, intents = %d\n",
458 __func__, ch->ch_cfg.name, ch->ch_cfg.latency_in_us,
459 ch->ch_cfg.no_of_intents);
460
461 ch->handle = glink_open(&open_cfg);
462 if (IS_ERR_OR_NULL(ch->handle)) {
463 dev_err(wpriv->dev, "%s: glink_open failed for ch %s\n",
464 __func__, ch->ch_cfg.name);
465 ch->handle = NULL;
466 ret = -EINVAL;
467 }
Bala Kishore Patic756a942018-09-24 17:33:46 +0530468 ch->free_mem = false;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530469 } else {
470 dev_err(wpriv->dev, "%s: ch %s is already opened\n", __func__,
471 ch->ch_cfg.name);
472 }
473 mutex_unlock(&wpriv->glink_mutex);
474
475 return ret;
476}
477
478/*
479 * wdsp_glink_close_all_ch - Internal function to close all glink channels
480 * wpriv: Wdsp_glink private structure
481 */
482static void wdsp_glink_close_all_ch(struct wdsp_glink_priv *wpriv)
483{
484 int i;
485
486 for (i = 0; i < wpriv->no_of_channels; i++)
487 if (wpriv->ch && wpriv->ch[i])
488 wdsp_glink_close_ch(wpriv->ch[i]);
489}
490
491/*
492 * wdsp_glink_open_all_ch - Internal function to open all glink channels
493 * wpriv: Wdsp_glink private structure
494 */
495static int wdsp_glink_open_all_ch(struct wdsp_glink_priv *wpriv)
496{
497 int ret = 0, i, j;
498
499 for (i = 0; i < wpriv->no_of_channels; i++) {
500 if (wpriv->ch && wpriv->ch[i]) {
501 ret = wdsp_glink_open_ch(wpriv->ch[i]);
502 if (ret < 0)
503 goto err_open;
504 }
505 }
506 goto done;
507
508err_open:
509 for (j = 0; j < i; j++)
Bala Kishore Patic756a942018-09-24 17:33:46 +0530510 if (wpriv->ch[j])
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530511 wdsp_glink_close_ch(wpriv->ch[j]);
512
513done:
514 return ret;
515}
516
517/*
518 * wdsp_glink_ch_open_wq - Work function to open glink channels
519 * work: Work structure
520 */
521static void wdsp_glink_ch_open_cls_wrk(struct work_struct *work)
522{
523 struct wdsp_glink_priv *wpriv;
524
525 wpriv = container_of(work, struct wdsp_glink_priv,
526 ch_open_cls_wrk);
527
528 if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
529 dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_DOWN\n",
530 __func__);
531
532 wdsp_glink_close_all_ch(wpriv);
533 } else if (wpriv->glink_state.link_state == GLINK_LINK_STATE_UP) {
534 dev_info(wpriv->dev, "%s: GLINK_LINK_STATE_UP\n",
535 __func__);
536
537 wdsp_glink_open_all_ch(wpriv);
538 }
539}
540
541/*
542 * wdsp_glink_link_state_cb - Glink link state callback to inform
543 * about link states
544 * cb_info: Glink link state callback information structure
545 * priv: Private structure of link state passed while register
546 */
547static void wdsp_glink_link_state_cb(struct glink_link_state_cb_info *cb_info,
548 void *priv)
549{
550 struct wdsp_glink_priv *wpriv;
551
552 if (!cb_info || !priv) {
553 pr_err("%s: Invalid parameters\n", __func__);
554 return;
555 }
556
557 wpriv = (struct wdsp_glink_priv *)priv;
558
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530559 wpriv->glink_state.link_state = cb_info->link_state;
560 wake_up(&wpriv->link_state_wait);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530561
562 queue_work(wpriv->work_queue, &wpriv->ch_open_cls_wrk);
563}
564
565/*
566 * wdsp_glink_ch_info_init- Internal function to allocate channel memory
567 * and register with glink
568 * wpriv: Wdsp_glink private structure.
569 * pkt: Glink registration packet contains glink channel information.
570 * pkt_size: Size of the pkt.
571 */
572static int wdsp_glink_ch_info_init(struct wdsp_glink_priv *wpriv,
573 struct wdsp_reg_pkt *pkt, size_t pkt_size)
574{
575 int ret = 0, i, j;
576 struct glink_link_info link_info;
577 struct wdsp_glink_ch_cfg *ch_cfg;
578 struct wdsp_glink_ch **ch;
579 u8 no_of_channels;
580 u8 *payload;
581 u32 ch_size, ch_cfg_size;
582 size_t size = WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE;
583
584 mutex_lock(&wpriv->glink_mutex);
585 if (wpriv->ch) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700586 dev_err_ratelimited(wpriv->dev, "%s: glink ch memory is already allocated\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530587 __func__);
588 ret = -EINVAL;
589 goto done;
590 }
591 payload = (u8 *)pkt->payload;
592 no_of_channels = pkt->no_of_channels;
593
594 if (no_of_channels > WDSP_MAX_NO_OF_CHANNELS) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700595 dev_err_ratelimited(wpriv->dev, "%s: no_of_channels: %d but max allowed are %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530596 __func__, no_of_channels, WDSP_MAX_NO_OF_CHANNELS);
597 ret = -EINVAL;
598 goto done;
599 }
600 ch = kcalloc(no_of_channels, sizeof(struct wdsp_glink_ch *),
601 GFP_ATOMIC);
602 if (!ch) {
603 ret = -ENOMEM;
604 goto done;
605 }
606 wpriv->ch = ch;
607 wpriv->no_of_channels = no_of_channels;
608
609 for (i = 0; i < no_of_channels; i++) {
610 ch_cfg = (struct wdsp_glink_ch_cfg *)payload;
611
612 size += WDSP_CH_CFG_SIZE;
613 if (size > pkt_size) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700614 dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530615 __func__, size, pkt_size);
616 ret = -EINVAL;
617 goto err_ch_mem;
618 }
619 if (ch_cfg->no_of_intents > WDSP_MAX_NO_OF_INTENTS) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700620 dev_err_ratelimited(wpriv->dev, "%s: Invalid no_of_intents = %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530621 __func__, ch_cfg->no_of_intents);
622 ret = -EINVAL;
623 goto err_ch_mem;
624 }
625 size += (sizeof(u32) * ch_cfg->no_of_intents);
626 if (size > pkt_size) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700627 dev_err_ratelimited(wpriv->dev, "%s: Invalid size = %zd, pkt_size = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530628 __func__, size, pkt_size);
629 ret = -EINVAL;
630 goto err_ch_mem;
631 }
632
633 ch_cfg_size = sizeof(struct wdsp_glink_ch_cfg) +
634 (sizeof(u32) * ch_cfg->no_of_intents);
635 ch_size = sizeof(struct wdsp_glink_ch) +
636 (sizeof(u32) * ch_cfg->no_of_intents);
637
638 dev_dbg(wpriv->dev, "%s: channels: %d ch_cfg_size: %d, size: %zd, pkt_size: %zd",
639 __func__, no_of_channels, ch_cfg_size, size, pkt_size);
640
641 ch[i] = kzalloc(ch_size, GFP_KERNEL);
642 if (!ch[i]) {
643 ret = -ENOMEM;
644 goto err_ch_mem;
645 }
646 ch[i]->channel_state = GLINK_LOCAL_DISCONNECTED;
Bala Kishore Patic756a942018-09-24 17:33:46 +0530647 ch[i]->free_mem = true;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530648 memcpy(&ch[i]->ch_cfg, payload, ch_cfg_size);
649 payload += ch_cfg_size;
650
Vidyakumar Athota87c83b72017-09-19 12:06:46 -0700651 /* check ch name is valid string or not */
652 for (j = 0; j < WDSP_CH_NAME_MAX_LEN; j++) {
653 if (ch[i]->ch_cfg.name[j] == '\0')
654 break;
655 }
656
657 if (j == WDSP_CH_NAME_MAX_LEN) {
658 dev_err_ratelimited(wpriv->dev, "%s: Wrong channel name\n",
659 __func__);
660 kfree(ch[i]);
661 ch[i] = NULL;
662 ret = -EINVAL;
663 goto err_ch_mem;
664 }
665
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530666 mutex_init(&ch[i]->mutex);
667 ch[i]->wpriv = wpriv;
668 INIT_WORK(&ch[i]->lcl_ch_open_wrk, wdsp_glink_lcl_ch_open_wrk);
669 INIT_WORK(&ch[i]->lcl_ch_cls_wrk, wdsp_glink_lcl_ch_cls_wrk);
670 init_waitqueue_head(&ch[i]->ch_connect_wait);
Bala Kishore Patic756a942018-09-24 17:33:46 +0530671 init_waitqueue_head(&ch[i]->ch_free_wait);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530672 }
673
674 INIT_WORK(&wpriv->ch_open_cls_wrk, wdsp_glink_ch_open_cls_wrk);
675
676 /* Register glink link_state notification */
677 link_info.glink_link_state_notif_cb = wdsp_glink_link_state_cb;
678 link_info.transport = NULL;
Ashish Jain19ef2602018-05-10 16:49:46 +0530679 link_info.edge = wpriv->glink_edge;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530680
681 wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
682 wpriv->glink_state.handle = glink_register_link_state_cb(&link_info,
683 wpriv);
684 if (!wpriv->glink_state.handle) {
685 dev_err(wpriv->dev, "%s: Unable to register wdsp link state\n",
686 __func__);
687 ret = -EINVAL;
688 goto err_ch_mem;
689 }
690 goto done;
691
692err_ch_mem:
693 for (j = 0; j < i; j++) {
694 mutex_destroy(&ch[j]->mutex);
695 kfree(wpriv->ch[j]);
696 wpriv->ch[j] = NULL;
697 }
698 kfree(wpriv->ch);
699 wpriv->ch = NULL;
700 wpriv->no_of_channels = 0;
701
702done:
703 mutex_unlock(&wpriv->glink_mutex);
704 return ret;
705}
706
707/*
708 * wdsp_glink_tx_buf_work - Work queue function to send tx buffer to glink
709 * work: Work structure
710 */
711static void wdsp_glink_tx_buf_work(struct work_struct *work)
712{
713 struct wdsp_glink_priv *wpriv;
714 struct wdsp_glink_ch *ch;
715 struct wdsp_glink_tx_buf *tx_buf;
716 struct wdsp_write_pkt *wpkt;
717 struct wdsp_cmd_pkt *cpkt;
718 int ret = 0;
719
720 tx_buf = container_of(work, struct wdsp_glink_tx_buf,
721 tx_work);
722 ch = tx_buf->ch;
723 wpriv = ch->wpriv;
724 wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
725 cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
726 dev_dbg(wpriv->dev, "%s: ch name = %s, payload size = %d\n",
727 __func__, cpkt->ch_name, cpkt->payload_size);
728
729 mutex_lock(&tx_buf->ch->mutex);
730 if (ch->channel_state == GLINK_CONNECTED) {
731 mutex_unlock(&tx_buf->ch->mutex);
732 ret = glink_tx(ch->handle, tx_buf,
733 cpkt->payload, cpkt->payload_size,
734 GLINK_TX_REQ_INTENT);
735 if (ret < 0) {
736 dev_err(wpriv->dev, "%s: glink tx failed, ret = %d\n",
737 __func__, ret);
738 /*
739 * If glink_tx() is failed then free tx_buf here as
740 * there won't be any tx_done notification to
741 * free the buffer.
742 */
743 vfree(tx_buf);
744 }
745 } else {
746 mutex_unlock(&tx_buf->ch->mutex);
747 dev_err(wpriv->dev, "%s: channel %s is not in connected state\n",
748 __func__, ch->ch_cfg.name);
749 /*
750 * Free tx_buf here as there won't be any tx_done
751 * notification in this case also.
752 */
753 vfree(tx_buf);
754 }
755}
756
757/*
758 * wdsp_glink_read - Read API to send the data to userspace
759 * file: Pointer to the file structure
760 * buf: Pointer to the userspace buffer
761 * count: Number bytes to read from the file
762 * ppos: Pointer to the position into the file
763 */
764static ssize_t wdsp_glink_read(struct file *file, char __user *buf,
765 size_t count, loff_t *ppos)
766{
767 int ret = 0, ret1 = 0;
768 struct wdsp_glink_rsp_que *rsp;
769 struct wdsp_glink_priv *wpriv;
770
771 wpriv = (struct wdsp_glink_priv *)file->private_data;
772 if (!wpriv) {
773 pr_err("%s: Invalid private data\n", __func__);
774 ret = -EINVAL;
775 goto done;
776 }
777
778 if (count > WDSP_MAX_READ_SIZE) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700779 dev_info_ratelimited(wpriv->dev, "%s: count = %zd is more than WDSP_MAX_READ_SIZE\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530780 __func__, count);
781 count = WDSP_MAX_READ_SIZE;
782 }
783 /*
784 * Complete signal has given from glink rx notification callback
785 * or from flush API. Also use interruptible wait_for_completion API
786 * to allow the system to go in suspend.
787 */
788 ret = wait_for_completion_interruptible(&wpriv->rsp_complete);
789 if (ret)
790 goto done;
791
792 mutex_lock(&wpriv->rsp_mutex);
793 if (wpriv->rsp_cnt) {
794 wpriv->rsp_cnt--;
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800795 dev_dbg(wpriv->dev, "%s: rsp_cnt=%d read from buffer %d\n",
796 __func__, wpriv->rsp_cnt, wpriv->read_idx);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530797
Xiaojun Sangd156ab82018-06-06 11:29:56 +0800798 rsp = &wpriv->rsp[wpriv->read_idx];
799 wpriv->read_idx = (wpriv->read_idx + 1) % RESP_QUEUE_SIZE;
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530800 if (count < rsp->buf_size) {
801 ret1 = copy_to_user(buf, &rsp->buf, count);
802 /* Return the number of bytes copied */
803 ret = count;
804 } else {
805 ret1 = copy_to_user(buf, &rsp->buf, rsp->buf_size);
806 /* Return the number of bytes copied */
807 ret = rsp->buf_size;
808 }
809
810 if (ret1) {
811 mutex_unlock(&wpriv->rsp_mutex);
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700812 dev_err_ratelimited(wpriv->dev, "%s: copy_to_user failed %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530813 __func__, ret);
814 ret = -EFAULT;
815 goto done;
816 }
817 } else {
818 /*
819 * This will execute only if flush API is called or
820 * something wrong with ref_cnt
821 */
822 dev_dbg(wpriv->dev, "%s: resp count = %d\n", __func__,
823 wpriv->rsp_cnt);
824 ret = -EINVAL;
825 }
826 mutex_unlock(&wpriv->rsp_mutex);
827
828done:
829 return ret;
830}
831
832/*
833 * wdsp_glink_write - Write API to receive the data from userspace
834 * file: Pointer to the file structure
835 * buf: Pointer to the userspace buffer
836 * count: Number bytes to read from the file
837 * ppos: Pointer to the position into the file
838 */
839static ssize_t wdsp_glink_write(struct file *file, const char __user *buf,
840 size_t count, loff_t *ppos)
841{
842 int ret = 0, i, tx_buf_size;
843 struct wdsp_write_pkt *wpkt;
844 struct wdsp_cmd_pkt *cpkt;
845 struct wdsp_glink_tx_buf *tx_buf;
846 struct wdsp_glink_priv *wpriv;
847 size_t pkt_max_size;
848
849 wpriv = (struct wdsp_glink_priv *)file->private_data;
850 if (!wpriv) {
851 pr_err("%s: Invalid private data\n", __func__);
852 ret = -EINVAL;
853 goto done;
854 }
855
856 if ((count < WDSP_WRITE_PKT_SIZE) ||
857 (count > WDSP_MAX_WRITE_SIZE)) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700858 dev_err_ratelimited(wpriv->dev, "%s: Invalid count = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530859 __func__, count);
860 ret = -EINVAL;
861 goto done;
862 }
863
864 dev_dbg(wpriv->dev, "%s: count = %zd\n", __func__, count);
865
866 tx_buf_size = count + sizeof(struct wdsp_glink_tx_buf);
867 tx_buf = vzalloc(tx_buf_size);
868 if (!tx_buf) {
869 ret = -ENOMEM;
870 goto done;
871 }
872
873 ret = copy_from_user(tx_buf->buf, buf, count);
874 if (ret) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700875 dev_err_ratelimited(wpriv->dev, "%s: copy_from_user failed %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530876 __func__, ret);
877 ret = -EFAULT;
878 goto free_buf;
879 }
880
881 wpkt = (struct wdsp_write_pkt *)tx_buf->buf;
882 switch (wpkt->pkt_type) {
883 case WDSP_REG_PKT:
884 if (count < (WDSP_WRITE_PKT_SIZE + WDSP_REG_PKT_SIZE +
885 WDSP_CH_CFG_SIZE)) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700886 dev_err_ratelimited(wpriv->dev, "%s: Invalid reg pkt size = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530887 __func__, count);
888 ret = -EINVAL;
889 goto free_buf;
890 }
891 ret = wdsp_glink_ch_info_init(wpriv,
892 (struct wdsp_reg_pkt *)wpkt->payload,
893 count);
894 if (ret < 0)
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700895 dev_err_ratelimited(wpriv->dev, "%s: glink register failed, ret = %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530896 __func__, ret);
897 vfree(tx_buf);
898 break;
899 case WDSP_READY_PKT:
900 ret = wait_event_timeout(wpriv->link_state_wait,
901 (wpriv->glink_state.link_state ==
902 GLINK_LINK_STATE_UP),
903 msecs_to_jiffies(TIMEOUT_MS));
904 if (!ret) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700905 dev_err_ratelimited(wpriv->dev, "%s: Link state wait timeout\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530906 __func__);
907 ret = -ETIMEDOUT;
908 goto free_buf;
909 }
910 ret = 0;
911 vfree(tx_buf);
912 break;
913 case WDSP_CMD_PKT:
914 if (count <= (WDSP_WRITE_PKT_SIZE + WDSP_CMD_PKT_SIZE)) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700915 dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt size = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530916 __func__, count);
917 ret = -EINVAL;
918 goto free_buf;
919 }
920 mutex_lock(&wpriv->glink_mutex);
921 if (wpriv->glink_state.link_state == GLINK_LINK_STATE_DOWN) {
922 mutex_unlock(&wpriv->glink_mutex);
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700923 dev_err_ratelimited(wpriv->dev, "%s: Link state is Down\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530924 __func__);
925
926 ret = -ENETRESET;
927 goto free_buf;
928 }
929 mutex_unlock(&wpriv->glink_mutex);
930 cpkt = (struct wdsp_cmd_pkt *)wpkt->payload;
931 pkt_max_size = sizeof(struct wdsp_write_pkt) +
932 sizeof(struct wdsp_cmd_pkt) +
933 cpkt->payload_size;
934 if (count < pkt_max_size) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700935 dev_err_ratelimited(wpriv->dev, "%s: Invalid cmd pkt count = %zd, pkt_size = %zd\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530936 __func__, count, pkt_max_size);
937 ret = -EINVAL;
938 goto free_buf;
939 }
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530940 for (i = 0; i < wpriv->no_of_channels; i++) {
941 if (wpriv->ch && wpriv->ch[i] &&
942 (!strcmp(cpkt->ch_name,
943 wpriv->ch[i]->ch_cfg.name))) {
944 tx_buf->ch = wpriv->ch[i];
945 break;
946 }
947 }
948 if (!tx_buf->ch) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700949 dev_err_ratelimited(wpriv->dev, "%s: Failed to get glink channel\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530950 __func__);
951 ret = -EINVAL;
952 goto free_buf;
953 }
Vidyakumar Athota87c83b72017-09-19 12:06:46 -0700954 dev_dbg(wpriv->dev, "%s: requested ch_name: %s, pkt_size: %zd\n",
955 __func__, cpkt->ch_name, pkt_max_size);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530956
957 ret = wait_event_timeout(tx_buf->ch->ch_connect_wait,
958 (tx_buf->ch->channel_state ==
959 GLINK_CONNECTED),
960 msecs_to_jiffies(TIMEOUT_MS));
961 if (!ret) {
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700962 dev_err_ratelimited(wpriv->dev, "%s: glink channel %s is not in connected state %d\n",
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530963 __func__, tx_buf->ch->ch_cfg.name,
964 tx_buf->ch->channel_state);
965 ret = -ETIMEDOUT;
966 goto free_buf;
967 }
968 ret = 0;
969
970 INIT_WORK(&tx_buf->tx_work, wdsp_glink_tx_buf_work);
971 queue_work(wpriv->work_queue, &tx_buf->tx_work);
972 break;
973 default:
Vidyakumar Athota60871bd2017-09-08 11:26:51 -0700974 dev_err_ratelimited(wpriv->dev, "%s: Invalid packet type\n",
975 __func__);
Laxminath Kasamd1f36192017-08-03 18:54:01 +0530976 ret = -EINVAL;
977 vfree(tx_buf);
978 break;
979 }
980 goto done;
981
982free_buf:
983 vfree(tx_buf);
984
985done:
986 return ret;
987}
988
989/*
990 * wdsp_glink_open - Open API to initialize private data
991 * inode: Pointer to the inode structure
992 * file: Pointer to the file structure
993 */
994static int wdsp_glink_open(struct inode *inode, struct file *file)
995{
996 int ret = 0;
997 struct wdsp_glink_priv *wpriv;
998 struct wdsp_glink_dev *wdev;
999
1000 if (!inode->i_cdev) {
1001 pr_err("%s: cdev is NULL\n", __func__);
1002 ret = -EINVAL;
1003 goto done;
1004 }
1005 wdev = container_of(inode->i_cdev, struct wdsp_glink_dev, cdev);
1006
1007 wpriv = kzalloc(sizeof(struct wdsp_glink_priv), GFP_KERNEL);
1008 if (!wpriv) {
1009 ret = -ENOMEM;
1010 goto done;
1011 }
1012 wpriv->dev = wdev->dev;
1013 wpriv->work_queue = create_singlethread_workqueue("wdsp_glink_wq");
1014 if (!wpriv->work_queue) {
1015 dev_err(wpriv->dev, "%s: Error creating wdsp_glink_wq\n",
1016 __func__);
1017 ret = -EINVAL;
1018 goto err_wq;
1019 }
1020
Ashish Jain19ef2602018-05-10 16:49:46 +05301021 wpriv->glink_edge = wdev->glink_edge;
Vidyakumar Athota60871bd2017-09-08 11:26:51 -07001022 wpriv->glink_state.link_state = GLINK_LINK_STATE_DOWN;
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301023 init_completion(&wpriv->rsp_complete);
1024 init_waitqueue_head(&wpriv->link_state_wait);
1025 mutex_init(&wpriv->rsp_mutex);
1026 mutex_init(&wpriv->glink_mutex);
1027 file->private_data = wpriv;
1028
1029 goto done;
1030
1031err_wq:
1032 kfree(wpriv);
1033
1034done:
1035 return ret;
1036}
1037
1038/*
1039 * wdsp_glink_flush - Flush API to unblock read.
1040 * file: Pointer to the file structure
1041 * id: Lock owner ID
1042 */
1043static int wdsp_glink_flush(struct file *file, fl_owner_t id)
1044{
1045 struct wdsp_glink_priv *wpriv;
1046
1047 wpriv = (struct wdsp_glink_priv *)file->private_data;
1048 if (!wpriv) {
1049 pr_err("%s: Invalid private data\n", __func__);
1050 return -EINVAL;
1051 }
1052
1053 complete(&wpriv->rsp_complete);
1054
1055 return 0;
1056}
1057
1058/*
1059 * wdsp_glink_release - Release API to clean up resources.
1060 * Whenever a file structure is shared across multiple threads,
1061 * release won't be invoked until all copies are closed
1062 * (file->f_count.counter should be 0). If we need to flush pending
1063 * data when any copy is closed, you should implement the flush method.
1064 *
1065 * inode: Pointer to the inode structure
1066 * file: Pointer to the file structure
1067 */
1068static int wdsp_glink_release(struct inode *inode, struct file *file)
1069{
1070 int i, ret = 0;
1071 struct wdsp_glink_priv *wpriv;
1072
1073 wpriv = (struct wdsp_glink_priv *)file->private_data;
1074 if (!wpriv) {
1075 pr_err("%s: Invalid private data\n", __func__);
1076 ret = -EINVAL;
1077 goto done;
1078 }
1079
Bala Kishore Patic756a942018-09-24 17:33:46 +05301080 dev_info_ratelimited(wpriv->dev, "%s: closing wdsp_glink driver\n", __func__);
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301081 if (wpriv->glink_state.handle)
1082 glink_unregister_link_state_cb(wpriv->glink_state.handle);
1083
1084 flush_workqueue(wpriv->work_queue);
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301085
1086 /*
Bala Kishore Patic756a942018-09-24 17:33:46 +05301087 * Wait for channel local and remote disconnect state notifications
1088 * before freeing channel memory.
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301089 */
Bala Kishore Patic756a942018-09-24 17:33:46 +05301090 for (i = 0; i < wpriv->no_of_channels; i++) {
1091 if (wpriv->ch && wpriv->ch[i]) {
1092 /*
1093 * Only close glink channel from here if REMOTE has
1094 * not already disconnected it.
1095 */
1096 wdsp_glink_close_ch(wpriv->ch[i]);
1097
1098 ret = wait_event_timeout(wpriv->ch[i]->ch_free_wait,
1099 (wpriv->ch[i]->free_mem == true),
1100 msecs_to_jiffies(TIMEOUT_MS));
1101 if (!ret) {
1102 pr_err("%s: glink ch %s failed to notify states properly %d\n",
1103 __func__, wpriv->ch[i]->ch_cfg.name,
1104 wpriv->ch[i]->channel_state);
1105 ret = -EINVAL;
1106 goto done;
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301107 }
1108 }
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301109 }
1110
Bala Kishore Patic756a942018-09-24 17:33:46 +05301111 flush_workqueue(wpriv->work_queue);
1112 destroy_workqueue(wpriv->work_queue);
1113 wpriv->work_queue = NULL;
1114
1115 for (i = 0; i < wpriv->no_of_channels; i++) {
1116 if (wpriv->ch && wpriv->ch[i]) {
1117 kfree(wpriv->ch[i]);
1118 wpriv->ch[i] = NULL;
1119 }
1120 }
1121 kfree(wpriv->ch);
1122 wpriv->ch = NULL;
1123
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301124 mutex_destroy(&wpriv->glink_mutex);
1125 mutex_destroy(&wpriv->rsp_mutex);
1126 kfree(wpriv);
1127 file->private_data = NULL;
1128
1129done:
1130 return ret;
1131}
1132
1133static const struct file_operations wdsp_glink_fops = {
1134 .owner = THIS_MODULE,
1135 .open = wdsp_glink_open,
1136 .read = wdsp_glink_read,
1137 .write = wdsp_glink_write,
1138 .flush = wdsp_glink_flush,
1139 .release = wdsp_glink_release,
1140};
1141
1142/*
1143 * wdsp_glink_probe - Driver probe to expose char device
1144 * pdev: Pointer to device tree data.
1145 */
1146static int wdsp_glink_probe(struct platform_device *pdev)
1147{
1148 int ret;
1149 struct wdsp_glink_dev *wdev;
Ashish Jain19ef2602018-05-10 16:49:46 +05301150 const char *str = NULL;
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301151
1152 wdev = devm_kzalloc(&pdev->dev, sizeof(*wdev), GFP_KERNEL);
1153 if (!wdev) {
1154 ret = -ENOMEM;
1155 goto done;
1156 }
1157
1158 ret = alloc_chrdev_region(&wdev->dev_num, 0, MINOR_NUMBER_COUNT,
1159 WDSP_GLINK_DRIVER_NAME);
1160 if (ret < 0) {
1161 dev_err(&pdev->dev, "%s: Failed to alloc char dev, err = %d\n",
1162 __func__, ret);
1163 goto err_chrdev;
1164 }
1165
1166 wdev->cls = class_create(THIS_MODULE, WDSP_GLINK_DRIVER_NAME);
1167 if (IS_ERR(wdev->cls)) {
1168 ret = PTR_ERR(wdev->cls);
1169 dev_err(&pdev->dev, "%s: Failed to create class, err = %d\n",
1170 __func__, ret);
1171 goto err_class;
1172 }
1173
1174 wdev->dev = device_create(wdev->cls, NULL, wdev->dev_num,
1175 NULL, WDSP_GLINK_DRIVER_NAME);
1176 if (IS_ERR(wdev->dev)) {
1177 ret = PTR_ERR(wdev->dev);
1178 dev_err(&pdev->dev, "%s: Failed to create device, err = %d\n",
1179 __func__, ret);
1180 goto err_dev_create;
1181 }
1182
1183 cdev_init(&wdev->cdev, &wdsp_glink_fops);
1184 ret = cdev_add(&wdev->cdev, wdev->dev_num, MINOR_NUMBER_COUNT);
1185 if (ret < 0) {
1186 dev_err(&pdev->dev, "%s: Failed to register char dev, err = %d\n",
1187 __func__, ret);
1188 goto err_cdev_add;
1189 }
Ashish Jain19ef2602018-05-10 16:49:46 +05301190 ret = of_property_read_string(pdev->dev.of_node,
1191 "qcom,msm-codec-glink-edge", &str);
1192 if (ret < 0) {
1193 strlcpy(wdev->glink_edge, WDSP_EDGE, GLINK_EDGE_MAX);
1194 dev_info(&pdev->dev,
1195 "%s: qcom,msm-codec-glink-edge not set use default %s\n",
1196 __func__, wdev->glink_edge);
1197 ret = 0;
1198 } else {
1199 strlcpy(wdev->glink_edge, str, GLINK_EDGE_MAX);
1200 dev_info(&pdev->dev, "%s: glink edge is %s\n", __func__,
1201 wdev->glink_edge);
1202 }
1203
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301204 platform_set_drvdata(pdev, wdev);
1205 goto done;
1206
1207err_cdev_add:
1208 device_destroy(wdev->cls, wdev->dev_num);
1209
1210err_dev_create:
1211 class_destroy(wdev->cls);
1212
1213err_class:
1214 unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
1215
1216err_chrdev:
1217 devm_kfree(&pdev->dev, wdev);
1218
1219done:
1220 return ret;
1221}
1222
1223/*
1224 * wdsp_glink_remove - Driver remove to handle cleanup
1225 * pdev: Pointer to device tree data.
1226 */
1227static int wdsp_glink_remove(struct platform_device *pdev)
1228{
1229 struct wdsp_glink_dev *wdev = platform_get_drvdata(pdev);
1230
1231 if (wdev) {
1232 cdev_del(&wdev->cdev);
1233 device_destroy(wdev->cls, wdev->dev_num);
1234 class_destroy(wdev->cls);
1235 unregister_chrdev_region(0, MINOR_NUMBER_COUNT);
1236 devm_kfree(&pdev->dev, wdev);
1237 } else {
1238 dev_err(&pdev->dev, "%s: Invalid device data\n", __func__);
1239 }
1240
1241 return 0;
1242}
1243
1244static const struct of_device_id wdsp_glink_of_match[] = {
1245 {.compatible = "qcom,wcd-dsp-glink"},
1246 { }
1247};
1248MODULE_DEVICE_TABLE(of, wdsp_glink_of_match);
1249
1250static struct platform_driver wdsp_glink_driver = {
1251 .probe = wdsp_glink_probe,
1252 .remove = wdsp_glink_remove,
1253 .driver = {
1254 .name = WDSP_GLINK_DRIVER_NAME,
1255 .owner = THIS_MODULE,
1256 .of_match_table = wdsp_glink_of_match,
1257 },
1258};
1259
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301260static int __init wdsp_glink_init(void)
1261{
1262 return platform_driver_register(&wdsp_glink_driver);
1263}
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301264
Laxminath Kasam8b1366a2017-10-05 01:44:16 +05301265static void __exit wdsp_glink_exit(void)
1266{
1267 platform_driver_unregister(&wdsp_glink_driver);
1268}
1269
1270module_init(wdsp_glink_init);
1271module_exit(wdsp_glink_exit);
Laxminath Kasamd1f36192017-08-03 18:54:01 +05301272MODULE_DESCRIPTION("SoC WCD_DSP GLINK Driver");
1273MODULE_LICENSE("GPL v2");