blob: fb6a41d0b1502d0a2414aa0b600d43ea7d6a23a3 [file] [log] [blame]
Soumya Managoli47386932018-02-23 13:04:52 +05301/* Copyright (c) 2010-2011, 2013-2014, 2016, 2018 The Linux Foundation.
2 * All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/types.h>
17#include <linux/uaccess.h>
18#include <linux/spinlock.h>
19#include <linux/mutex.h>
20#include <linux/list.h>
21#include <linux/sched.h>
22#include <linux/wait.h>
23#include <linux/errno.h>
24#include <linux/fs.h>
25#include <linux/debugfs.h>
26#include <linux/platform_device.h>
27#include <linux/delay.h>
28#include <linux/clk.h>
29#include <soc/qcom/smd.h>
30#include <ipc/apr_tal.h>
31
32static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
33 {
34 "apr_audio_svc",
35 "apr_voice_svc",
36 },
37 {
38 "apr_audio_svc",
39 "apr_voice_svc",
40 },
41};
42
43struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
44
45int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
46 struct apr_pkt_priv *pkt_priv, int len)
47{
48 int w_len;
49 unsigned long flags;
50
51 spin_lock_irqsave(&apr_ch->w_lock, flags);
52 if (smd_write_avail(apr_ch->ch) < len) {
53 spin_unlock_irqrestore(&apr_ch->w_lock, flags);
54 return -EAGAIN;
55 }
56
57 w_len = smd_write(apr_ch->ch, data, len);
58 spin_unlock_irqrestore(&apr_ch->w_lock, flags);
59
60 pr_debug("apr_tal:w_len = %d\n", w_len);
61
62 if (w_len != len) {
63 pr_err("apr_tal: Error in write\n");
64 return -ENETRESET;
65 }
66 return w_len;
67}
68
69int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data,
70 struct apr_pkt_priv *pkt_priv, int len)
71{
72 int rc = 0, retries = 0;
73
74 if (!apr_ch->ch)
75 return -EINVAL;
76
77 do {
78 if (rc == -EAGAIN)
79 udelay(50);
80
81 rc = __apr_tal_write(apr_ch, data, pkt_priv, len);
82 } while (rc == -EAGAIN && retries++ < 300);
83
84 if (rc == -EAGAIN)
85 pr_err("apr_tal: TIMEOUT for write\n");
86
87 return rc;
88}
89
90static void apr_tal_notify(void *priv, unsigned int event)
91{
92 struct apr_svc_ch_dev *apr_ch = priv;
93 int len, r_len, sz;
94 int pkt_cnt = 0;
95 unsigned long flags;
96
97 pr_debug("event = %d\n", event);
98 switch (event) {
99 case SMD_EVENT_DATA:
100 pkt_cnt = 0;
101 spin_lock_irqsave(&apr_ch->lock, flags);
102check_pending:
103 len = smd_read_avail(apr_ch->ch);
104 if (len < 0) {
105 pr_err("apr_tal: Invalid Read Event :%d\n", len);
106 spin_unlock_irqrestore(&apr_ch->lock, flags);
107 return;
108 }
109 sz = smd_cur_packet_size(apr_ch->ch);
110 if (sz < 0) {
111 pr_debug("pkt size is zero\n");
112 spin_unlock_irqrestore(&apr_ch->lock, flags);
113 return;
114 }
115 if (!len && !sz && !pkt_cnt)
116 goto check_write_avail;
117 if (!len) {
118 pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
119 spin_unlock_irqrestore(&apr_ch->lock, flags);
120 return;
121 }
122 r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
123 if (len != r_len) {
124 pr_err("apr_tal: Invalid Read\n");
125 spin_unlock_irqrestore(&apr_ch->lock, flags);
126 return;
127 }
128 pkt_cnt++;
129 pr_debug("%d %d %d\n", len, sz, pkt_cnt);
130 if (apr_ch->func)
131 apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
132 goto check_pending;
133check_write_avail:
134 if (smd_write_avail(apr_ch->ch))
135 wake_up(&apr_ch->wait);
136 spin_unlock_irqrestore(&apr_ch->lock, flags);
137 break;
138 case SMD_EVENT_OPEN:
139 pr_debug("apr_tal: SMD_EVENT_OPEN\n");
140 apr_ch->smd_state = 1;
141 wake_up(&apr_ch->wait);
142 break;
143 case SMD_EVENT_CLOSE:
144 pr_debug("apr_tal: SMD_EVENT_CLOSE\n");
145 break;
146 }
147}
148
149int apr_tal_rx_intents_config(struct apr_svc_ch_dev *apr_ch,
150 int num_of_intents, uint32_t size)
151{
152 /* Rx intents configuration is required for Glink
153 * but not for SMD. No-op for this function.
154 */
155 return 0;
156}
157
158struct apr_svc_ch_dev *apr_tal_open(uint32_t clnt, uint32_t dest,
159 uint32_t dl, apr_svc_cb_fn func, void *priv)
160{
161 int rc;
162
163 if ((clnt >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
164 (dl >= APR_DL_MAX)) {
165 pr_err("apr_tal: Invalid params\n");
166 return NULL;
167 }
168
169 if (apr_svc_ch[dl][dest][clnt].ch) {
170 pr_err("apr_tal: This channel alreday openend\n");
171 return NULL;
172 }
173
174 mutex_lock(&apr_svc_ch[dl][dest][clnt].m_lock);
175 if (!apr_svc_ch[dl][dest][clnt].dest_state) {
176 rc = wait_event_timeout(apr_svc_ch[dl][dest][clnt].dest,
177 apr_svc_ch[dl][dest][clnt].dest_state,
178 msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
179 if (rc == 0) {
180 pr_err("apr_tal:open timeout\n");
181 mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
182 return NULL;
183 }
184 pr_debug("apr_tal:Wakeup done\n");
185 apr_svc_ch[dl][dest][clnt].dest_state = 0;
186 }
187 rc = smd_named_open_on_edge(svc_names[dest][clnt], dest,
188 &apr_svc_ch[dl][dest][clnt].ch,
189 &apr_svc_ch[dl][dest][clnt],
190 apr_tal_notify);
191 if (rc < 0) {
192 pr_err("apr_tal: smd_open failed %s\n",
193 svc_names[dest][clnt]);
194 mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
195 return NULL;
196 }
197 rc = wait_event_timeout(apr_svc_ch[dl][dest][clnt].wait,
198 (apr_svc_ch[dl][dest][clnt].smd_state == 1), 5 * HZ);
199 if (rc == 0) {
200 pr_err("apr_tal:TIMEOUT for OPEN event\n");
201 mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
202 apr_tal_close(&apr_svc_ch[dl][dest][clnt]);
203 return NULL;
204 }
205
206 smd_disable_read_intr(apr_svc_ch[dl][dest][clnt].ch);
207
208 if (!apr_svc_ch[dl][dest][clnt].dest_state) {
209 apr_svc_ch[dl][dest][clnt].dest_state = 1;
210 pr_debug("apr_tal:Waiting for apr svc init\n");
211 msleep(200);
212 pr_debug("apr_tal:apr svc init done\n");
213 }
214 apr_svc_ch[dl][dest][clnt].smd_state = 0;
215
216 apr_svc_ch[dl][dest][clnt].func = func;
217 apr_svc_ch[dl][dest][clnt].priv = priv;
218 mutex_unlock(&apr_svc_ch[dl][dest][clnt].m_lock);
219
220 return &apr_svc_ch[dl][dest][clnt];
221}
222
223int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
224{
225 int r;
226
227 if (!apr_ch->ch)
228 return -EINVAL;
229
230 mutex_lock(&apr_ch->m_lock);
231 r = smd_close(apr_ch->ch);
232 apr_ch->ch = NULL;
233 apr_ch->func = NULL;
234 apr_ch->priv = NULL;
235 mutex_unlock(&apr_ch->m_lock);
236 return r;
237}
238
239static int apr_smd_probe(struct platform_device *pdev)
240{
241 int dest;
242 int clnt;
243
244 if (pdev->id == APR_DEST_MODEM) {
245 pr_info("apr_tal:Modem Is Up\n");
246 dest = APR_DEST_MODEM;
247 if (!strcmp(pdev->name, "apr_audio_svc"))
248 clnt = APR_CLIENT_AUDIO;
249 else
250 clnt = APR_CLIENT_VOICE;
251 apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
252 wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
253 } else if (pdev->id == APR_DEST_QDSP6) {
254 pr_info("apr_tal:Q6 Is Up\n");
255 dest = APR_DEST_QDSP6;
256 clnt = APR_CLIENT_AUDIO;
257 apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
258 wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
259 } else
260 pr_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
261
262 return 0;
263}
264
265static struct platform_driver apr_q6_driver = {
266 .probe = apr_smd_probe,
267 .driver = {
268 .name = "apr_audio_svc",
269 .owner = THIS_MODULE,
270 },
271};
272
273static struct platform_driver apr_modem_driver = {
274 .probe = apr_smd_probe,
275 .driver = {
276 .name = "apr_voice_svc",
277 .owner = THIS_MODULE,
278 },
279};
280
281int apr_tal_init(void)
282{
283 int i, j, k;
284
285 for (i = 0; i < APR_DL_MAX; i++)
286 for (j = 0; j < APR_DEST_MAX; j++)
287 for (k = 0; k < APR_CLIENT_MAX; k++) {
288 init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
289 init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
290 spin_lock_init(&apr_svc_ch[i][j][k].lock);
291 spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
292 mutex_init(&apr_svc_ch[i][j][k].m_lock);
293 }
294 platform_driver_register(&apr_q6_driver);
295 platform_driver_register(&apr_modem_driver);
296 return 0;
297}