blob: 418da4dd5946fcf6f0899d4aa341b6f054ec843e [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2 *
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/kernel.h>
14#include <linux/module.h>
15#include <linux/types.h>
16#include <linux/uaccess.h>
17#include <linux/spinlock.h>
18#include <linux/mutex.h>
19#include <linux/list.h>
20#include <linux/sched.h>
21#include <linux/wait.h>
22#include <linux/errno.h>
23#include <linux/fs.h>
24#include <linux/debugfs.h>
25#include <linux/platform_device.h>
26#include <linux/delay.h>
27#include <linux/clk.h>
28#include <mach/msm_smd.h>
29#include <mach/qdsp6v2/apr_tal.h>
30
31static char *svc_names[APR_DEST_MAX][APR_CLIENT_MAX] = {
32 {
33 "apr_audio_svc",
34 "apr_voice_svc",
35 },
36 {
37 "apr_audio_svc",
38 "apr_voice_svc",
39 },
40};
41
42struct apr_svc_ch_dev apr_svc_ch[APR_DL_MAX][APR_DEST_MAX][APR_CLIENT_MAX];
43
44int __apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
45{
46 int w_len;
47 unsigned long flags;
48
49
50 spin_lock_irqsave(&apr_ch->w_lock, flags);
51 if (smd_write_avail(apr_ch->ch) < len) {
52 spin_unlock_irqrestore(&apr_ch->w_lock, flags);
53 return -EAGAIN;
54 }
55
56 w_len = smd_write(apr_ch->ch, data, len);
57 spin_unlock_irqrestore(&apr_ch->w_lock, flags);
58 pr_debug("apr_tal:w_len = %d\n", w_len);
59
60 if (w_len != len) {
61 pr_err("apr_tal: Error in write\n");
62 return -ENETRESET;
63 }
64 return w_len;
65}
66
67int apr_tal_write(struct apr_svc_ch_dev *apr_ch, void *data, int len)
68{
69 int rc = 0, retries = 0;
70
71 if (!apr_ch->ch)
72 return -EINVAL;
73
74 do {
75 if (rc == -EAGAIN)
76 udelay(50);
77
78 rc = __apr_tal_write(apr_ch, data, len);
79 } while (rc == -EAGAIN && retries++ < 300);
80
81 if (rc == -EAGAIN)
82 pr_err("apr_tal: TIMEOUT for write\n");
83
84 return rc;
85}
86
87static void apr_tal_notify(void *priv, unsigned event)
88{
89 struct apr_svc_ch_dev *apr_ch = priv;
90 int len, r_len, sz;
91 int pkt_cnt = 0;
92 unsigned long flags;
93
94 pr_debug("event = %d\n", event);
95 switch (event) {
96 case SMD_EVENT_DATA:
97 pkt_cnt = 0;
98 spin_lock_irqsave(&apr_ch->lock, flags);
99check_pending:
100 len = smd_read_avail(apr_ch->ch);
101 if (len < 0) {
102 pr_err("apr_tal: Invalid Read Event :%d\n", len);
103 spin_unlock_irqrestore(&apr_ch->lock, flags);
104 return;
105 }
106 sz = smd_cur_packet_size(apr_ch->ch);
107 if (sz < 0) {
108 pr_debug("pkt size is zero\n");
109 spin_unlock_irqrestore(&apr_ch->lock, flags);
110 return;
111 }
112 if (!len && !sz && !pkt_cnt)
113 goto check_write_avail;
114 if (!len) {
115 pr_debug("len = %d pkt_cnt = %d\n", len, pkt_cnt);
116 spin_unlock_irqrestore(&apr_ch->lock, flags);
117 return;
118 }
119 r_len = smd_read_from_cb(apr_ch->ch, apr_ch->data, len);
120 if (len != r_len) {
121 pr_err("apr_tal: Invalid Read\n");
122 spin_unlock_irqrestore(&apr_ch->lock, flags);
123 return;
124 }
125 pkt_cnt++;
126 pr_debug("%d %d %d\n", len, sz, pkt_cnt);
127 if (apr_ch->func)
128 apr_ch->func(apr_ch->data, r_len, apr_ch->priv);
129 goto check_pending;
130check_write_avail:
131 if (smd_write_avail(apr_ch->ch))
132 wake_up(&apr_ch->wait);
133 spin_unlock_irqrestore(&apr_ch->lock, flags);
134 break;
135 case SMD_EVENT_OPEN:
136 pr_info("apr_tal: SMD_EVENT_OPEN\n");
137 apr_ch->smd_state = 1;
138 wake_up(&apr_ch->wait);
139 break;
140 case SMD_EVENT_CLOSE:
141 pr_info("apr_tal: SMD_EVENT_CLOSE\n");
142 break;
143 }
144}
145
146struct apr_svc_ch_dev *apr_tal_open(uint32_t svc, uint32_t dest,
147 uint32_t dl, apr_svc_cb_fn func, void *priv)
148{
149 int rc;
150
151 if ((svc >= APR_CLIENT_MAX) || (dest >= APR_DEST_MAX) ||
152 (dl >= APR_DL_MAX)) {
153 pr_err("apr_tal: Invalid params\n");
154 return NULL;
155 }
156
157 if (apr_svc_ch[dl][dest][svc].ch) {
158 pr_err("apr_tal: This channel alreday openend\n");
159 return NULL;
160 }
161
162 mutex_lock(&apr_svc_ch[dl][dest][svc].m_lock);
163 if (!apr_svc_ch[dl][dest][svc].dest_state) {
164 rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].dest,
165 apr_svc_ch[dl][dest][svc].dest_state,
166 msecs_to_jiffies(APR_OPEN_TIMEOUT_MS));
167 if (rc == 0) {
168 pr_debug("apr_tal:Open timeout\n");
169 mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
170 return NULL;
171 }
172 pr_debug("apr_tal:Wakeup done\n");
173 apr_svc_ch[dl][dest][svc].dest_state = 0;
174 }
175 rc = smd_named_open_on_edge(svc_names[dest][svc], dest,
176 &apr_svc_ch[dl][dest][svc].ch,
177 &apr_svc_ch[dl][dest][svc],
178 apr_tal_notify);
179 if (rc < 0) {
180 pr_err("apr_tal: smd_open failed %s\n",
181 svc_names[dest][svc]);
182 mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
183 return NULL;
184 }
185 rc = wait_event_timeout(apr_svc_ch[dl][dest][svc].wait,
186 (apr_svc_ch[dl][dest][svc].smd_state == 1), 5 * HZ);
187 if (rc == 0) {
188 pr_err("apr_tal:TIMEOUT for OPEN event\n");
189 mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
190 return NULL;
191 }
192 if (!apr_svc_ch[dl][dest][svc].dest_state) {
193 apr_svc_ch[dl][dest][svc].dest_state = 1;
194 pr_debug("apr_tal:Waiting for apr svc init\n");
195 msleep(200);
196 pr_debug("apr_tal:apr svc init done\n");
197 }
198 apr_svc_ch[dl][dest][svc].smd_state = 0;
199
200 apr_svc_ch[dl][dest][svc].func = func;
201 apr_svc_ch[dl][dest][svc].priv = priv;
202 mutex_unlock(&apr_svc_ch[dl][dest][svc].m_lock);
203
204 return &apr_svc_ch[dl][dest][svc];
205}
206
207int apr_tal_close(struct apr_svc_ch_dev *apr_ch)
208{
209 int r;
210
211 if (!apr_ch->ch)
212 return -EINVAL;
213
214 mutex_lock(&apr_ch->m_lock);
215 r = smd_close(apr_ch->ch);
216 apr_ch->ch = NULL;
217 apr_ch->func = NULL;
218 apr_ch->priv = NULL;
219 mutex_unlock(&apr_ch->m_lock);
220 return r;
221}
222
223static int apr_smd_probe(struct platform_device *pdev)
224{
225 int dest;
226 int clnt;
227
228 if (pdev->id == APR_DEST_MODEM) {
229 pr_info("apr_tal:Modem Is Up\n");
230 dest = APR_DEST_MODEM;
231 clnt = APR_CLIENT_VOICE;
232 apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
233 wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
234 } else if (pdev->id == APR_DEST_QDSP6) {
235 pr_info("apr_tal:Q6 Is Up\n");
236 dest = APR_DEST_QDSP6;
237 clnt = APR_CLIENT_AUDIO;
238 apr_svc_ch[APR_DL_SMD][dest][clnt].dest_state = 1;
239 wake_up(&apr_svc_ch[APR_DL_SMD][dest][clnt].dest);
240 } else
241 pr_err("apr_tal:Invalid Dest Id: %d\n", pdev->id);
242
243 return 0;
244}
245
246static struct platform_driver apr_q6_driver = {
247 .probe = apr_smd_probe,
248 .driver = {
249 .name = "apr_audio_svc",
250 .owner = THIS_MODULE,
251 },
252};
253
254static struct platform_driver apr_modem_driver = {
255 .probe = apr_smd_probe,
256 .driver = {
257 .name = "apr_voice_svc",
258 .owner = THIS_MODULE,
259 },
260};
261
262static int __init apr_tal_init(void)
263{
264 int i, j, k;
265
266 for (i = 0; i < APR_DL_MAX; i++)
267 for (j = 0; j < APR_DEST_MAX; j++)
268 for (k = 0; k < APR_CLIENT_MAX; k++) {
269 init_waitqueue_head(&apr_svc_ch[i][j][k].wait);
270 init_waitqueue_head(&apr_svc_ch[i][j][k].dest);
271 spin_lock_init(&apr_svc_ch[i][j][k].lock);
272 spin_lock_init(&apr_svc_ch[i][j][k].w_lock);
273 mutex_init(&apr_svc_ch[i][j][k].m_lock);
274 }
275 platform_driver_register(&apr_q6_driver);
276 platform_driver_register(&apr_modem_driver);
277 return 0;
278}
279device_initcall(apr_tal_init);