blob: 12ac27f86cab1707edbd094147a91826e5148690 [file] [log] [blame]
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08001/* Copyright (c) 2012, 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#include <linux/slab.h>
13#include <linux/mutex.h>
14#include <linux/mfd/wcd9310/wcd9310-slimslave.h>
15
16struct tabla_slim_sch_rx {
17 u32 sph;
18 u32 ch_num;
19 u16 ch_h;
20 u16 grph;
21};
22
23struct tabla_slim_sch_tx {
24 u32 sph;
25 u32 ch_num;
26 u16 ch_h;
27 u16 grph;
28};
29
30struct tabla_slim_sch {
31 struct tabla_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
32 struct tabla_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
33};
34
35static struct tabla_slim_sch sh_ch;
36
37static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la);
38static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la);
39static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab);
40static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab);
41
42int tabla_init_slimslave(struct tabla *tabla, u8 tabla_pgd_la)
43{
44 int ret = 0;
45
46 ret = tabla_alloc_slim_sh_ch_rx(tabla, tabla_pgd_la);
47 if (ret) {
48 pr_err("%s: Failed to alloc rx slimbus shared channels\n",
49 __func__);
50 goto rx_err;
51 }
52 ret = tabla_alloc_slim_sh_ch_tx(tabla, tabla_pgd_la);
53 if (ret) {
54 pr_err("%s: Failed to alloc tx slimbus shared channels\n",
55 __func__);
56 goto tx_err;
57 }
58 return 0;
59tx_err:
60 tabla_dealloc_slim_sh_ch_rx(tabla);
61rx_err:
62 return ret;
63}
64
65
66int tabla_deinit_slimslave(struct tabla *tabla)
67{
68 int ret = 0;
69 ret = tabla_dealloc_slim_sh_ch_rx(tabla);
70 if (ret < 0) {
71 pr_err("%s: fail to dealloc rx slim ports\n", __func__);
72 goto err;
73 }
74 ret = tabla_dealloc_slim_sh_ch_tx(tabla);
75 if (ret < 0) {
76 pr_err("%s: fail to dealloc tx slim ports\n", __func__);
77 goto err;
78 }
79err:
80 return ret;
81}
82
83int tabla_get_channel(struct tabla *tabla,
84 unsigned int *rx_ch,
85 unsigned int *tx_ch)
86{
87 int ch_idx = 0;
88 struct tabla_slim_sch_rx *rx = sh_ch.rx;
89 struct tabla_slim_sch_tx *tx = sh_ch.tx;
90
91 for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++)
92 rx_ch[ch_idx] = rx[ch_idx].ch_num;
93 for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++)
94 tx_ch[ch_idx] = tx[ch_idx].ch_num;
95 return 0;
96}
97
98static int tabla_alloc_slim_sh_ch_rx(struct tabla *tabla, u8 tabla_pgd_la)
99{
100 int ret = 0;
101 u8 ch_idx ;
102 u16 slave_port_id = 0;
103 struct tabla_slim_sch_rx *rx = sh_ch.rx;
104
105 /* DSP requires channel number to be between 128 and 255. For RX port
106 * use channel numbers from 138 to 144, for TX port
107 * use channel numbers from 128 to 137
108 */
109 pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
110 for (ch_idx = 0; ch_idx < SLIM_MAX_RX_PORTS; ch_idx++) {
111 slave_port_id = (ch_idx + 1 +
112 SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
113 rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
114 ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
115 &rx[ch_idx].sph, SLIM_SINK);
116 if (ret < 0) {
117 pr_err("%s: slave port failure id[%d] ret[%d]\n",
118 __func__, slave_port_id, ret);
119 goto err;
120 }
121
122 ret = slim_query_ch(tabla->slim, rx[ch_idx].ch_num,
123 &rx[ch_idx].ch_h);
124 if (ret < 0) {
125 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
126 __func__, rx[ch_idx].ch_num, ret);
127 goto err;
128 }
129 }
130err:
131 return ret;
132}
133
134static int tabla_alloc_slim_sh_ch_tx(struct tabla *tabla, u8 tabla_pgd_la)
135{
136 int ret = 0;
137 u8 ch_idx ;
138 struct tabla_slim_sch_tx *tx = sh_ch.tx;
139 u16 slave_port_id = 0;
140
141 pr_debug("%s: pgd_la[%d]\n", __func__, tabla_pgd_la);
142 /* DSP requires channel number to be between 128 and 255. For RX port
143 * use channel numbers from 138 to 144, for TX port
144 * use channel numbers from 128 to 137
145 */
146 for (ch_idx = 0; ch_idx < SLIM_MAX_TX_PORTS; ch_idx++) {
147 slave_port_id = ch_idx;
148 tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
149 ret = slim_get_slaveport(tabla_pgd_la, slave_port_id,
150 &tx[ch_idx].sph, SLIM_SRC);
151 if (ret < 0) {
152 pr_err("%s: slave port failure id[%d] ret[%d]\n",
153 __func__, slave_port_id, ret);
154 goto err;
155 }
156 ret = slim_query_ch(tabla->slim, tx[ch_idx].ch_num,
157 &tx[ch_idx].ch_h);
158 if (ret < 0) {
159 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
160 __func__, tx[ch_idx].ch_num, ret);
161 goto err;
162 }
163 }
164err:
165 return ret;
166}
167
168static int tabla_dealloc_slim_sh_ch_rx(struct tabla *tab)
169{
170 int idx = 0;
171 int ret = 0;
172 struct tabla_slim_sch_rx *rx = sh_ch.rx;
173 /* slim_dealloc_ch */
174 for (idx = 0; idx < SLIM_MAX_RX_PORTS; idx++) {
175 ret = slim_dealloc_ch(tab->slim, rx[idx].ch_h);
176 if (ret < 0) {
177 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
178 __func__, ret, rx[idx].ch_h);
179 }
180 }
181 memset(sh_ch.rx, 0, sizeof(sh_ch.rx));
182 return ret;
183}
184
185static int tabla_dealloc_slim_sh_ch_tx(struct tabla *tab)
186{
187 int idx = 0;
188 int ret = 0;
189 struct tabla_slim_sch_tx *tx = sh_ch.tx;
190 /* slim_dealloc_ch */
191 for (idx = 0; idx < SLIM_MAX_TX_PORTS; idx++) {
192 ret = slim_dealloc_ch(tab->slim, tx[idx].ch_h);
193 if (ret < 0) {
194 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
195 __func__, ret, tx[idx].ch_h);
196 }
197 }
198 memset(sh_ch.tx, 0, sizeof(sh_ch.tx));
199 return ret;
200}
201
202/* Enable slimbus slave device for RX path */
203int tabla_cfg_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
204 unsigned int ch_cnt, unsigned int rate)
205{
206 u8 i = 0;
207 u16 grph;
208 u32 sph[SLIM_MAX_RX_PORTS] = {0};
209 u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
210 u16 slave_port_id;
211 u8 payload_rx = 0, wm_payload = 0;
212 int ret, idx = 0;
213 unsigned short multi_chan_cfg_reg_addr;
214 struct tabla_slim_sch_rx *rx = sh_ch.rx;
215 struct slim_ch prop;
216
217 /* Configure slave interface device */
218 pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
219
220 for (i = 0; i < ch_cnt; i++) {
221 idx = (ch_num[i] - BASE_CH_NUM -
222 SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
223 ch_h[i] = rx[idx].ch_h;
224 sph[i] = rx[idx].sph;
225 slave_port_id = idx + 1;
226 if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS) ||
227 (slave_port_id == 0)) {
228 pr_err("Slimbus: invalid slave port id: %d",
229 slave_port_id);
230 ret = -EINVAL;
231 goto err;
232 }
233 slave_port_id += SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
234 /* look for the valid port range and chose the
235 * payload accordingly
236 */
237 if ((slave_port_id >
238 SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) &&
Helen Zeng4a7abdb2012-02-21 18:20:46 -0800239 (slave_port_id <=
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800240 SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID)) {
241 payload_rx = payload_rx |
242 (1 <<
243 (slave_port_id -
244 SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID));
245 } else {
246 ret = -EINVAL;
247 goto err;
248 }
249 multi_chan_cfg_reg_addr =
250 SB_PGD_RX_PORT_MULTI_CHANNEL_0(slave_port_id);
251 /* write to interface device */
252 ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
253 payload_rx);
254 if (ret < 0) {
255 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
256 __func__,
257 multi_chan_cfg_reg_addr,
258 payload_rx, ret);
259 goto err;
260 }
261 /* configure the slave port for water mark and enable*/
262 wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
263 SLAVE_PORT_WATER_MARK_SHIFT) +
264 SLAVE_PORT_ENABLE;
265 ret = tabla_interface_reg_write(tab,
266 SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
267 wm_payload);
268 if (ret < 0) {
269 pr_err("%s:watermark set failure for port[%d] ret[%d]",
270 __func__, slave_port_id, ret);
271 }
272 }
273
274 /* slim_define_ch api */
275 prop.prot = SLIM_AUTO_ISO;
276 prop.baser = SLIM_RATE_4000HZ;
277 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
278 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
279 prop.ratem = (rate/4000);
280 prop.sampleszbits = 16;
281
282 ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
283 true, &grph);
284 if (ret < 0) {
285 pr_err("%s: slim_define_ch failed ret[%d]\n",
286 __func__, ret);
287 goto err;
288 }
289 for (i = 0; i < ch_cnt; i++) {
290 ret = slim_connect_sink(tab->slim, &sph[i],
291 1, ch_h[i]);
292 if (ret < 0) {
293 pr_err("%s: slim_connect_sink failed ret[%d]\n",
294 __func__, ret);
295 goto err_close_slim_sch;
296 }
297 }
298 /* slim_control_ch */
299 ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
300 true);
301 if (ret < 0) {
302 pr_err("%s: slim_control_ch failed ret[%d]\n",
303 __func__, ret);
304 goto err_close_slim_sch;
305 }
306 for (i = 0; i < ch_cnt; i++) {
307 idx = (ch_num[i] - BASE_CH_NUM -
308 SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
309 rx[idx].grph = grph;
310 }
311 return 0;
312
313err_close_slim_sch:
314 /* release all acquired handles */
315 tabla_close_slim_sch_rx(tab, ch_num, ch_cnt);
316err:
317 return ret;
318}
319EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_rx);
320
321/* Enable slimbus slave device for RX path */
322int tabla_cfg_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
323 unsigned int ch_cnt, unsigned int rate)
324{
325 u8 i = 0;
326 u8 payload_tx_0 = 0, payload_tx_1 = 0, wm_payload = 0;
327 u16 grph;
328 u32 sph[SLIM_MAX_TX_PORTS] = {0};
329 u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
330 u16 idx = 0, slave_port_id;
331 int ret = 0;
332 unsigned short multi_chan_cfg_reg_addr;
333
334 struct tabla_slim_sch_tx *tx = sh_ch.tx;
335 struct slim_ch prop;
336
337 pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
338 for (i = 0; i < ch_cnt; i++) {
339 idx = (ch_num[i] - BASE_CH_NUM);
340 ch_h[i] = tx[idx].ch_h;
341 sph[i] = tx[idx].sph;
342 slave_port_id = idx ;
343 if ((slave_port_id > SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS) ||
344 (slave_port_id == 0)) {
345 pr_err("SLIMbus: invalid slave port id: %d",
346 slave_port_id);
347 ret = -EINVAL;
348 goto err;
349 }
350 /* look for the valid port range and chose the
351 * payload accordingly
352 */
353 if (slave_port_id <=
354 SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
355 payload_tx_0 = payload_tx_0 | (1 << slave_port_id);
356 } else if (slave_port_id <
357 SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID) {
358 payload_tx_1 = payload_tx_1 |
359 (1 <<
360 (slave_port_id -
361 SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
362 } else {
363 ret = -EINVAL;
364 goto err;
365 }
366 multi_chan_cfg_reg_addr =
367 SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
368 /* write to interface device */
369 ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
370 payload_tx_0);
371 if (ret < 0) {
372 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
373 __func__,
374 multi_chan_cfg_reg_addr,
375 payload_tx_0, ret);
376 goto err;
377 }
378 multi_chan_cfg_reg_addr =
379 SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
380 /* ports 8,9 */
381 ret = tabla_interface_reg_write(tab, multi_chan_cfg_reg_addr,
382 payload_tx_1);
383 if (ret < 0) {
384 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
385 __func__,
386 multi_chan_cfg_reg_addr,
387 payload_tx_1, ret);
388 goto err;
389 }
390 /* configure the slave port for water mark and enable*/
391 wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
392 SLAVE_PORT_WATER_MARK_SHIFT) +
393 SLAVE_PORT_ENABLE;
394 ret = tabla_interface_reg_write(tab,
395 SB_PGD_PORT_CFG_BYTE_ADDR(slave_port_id),
396 wm_payload);
397 if (ret < 0) {
398 pr_err("%s:watermark set failure for port[%d] ret[%d]",
399 __func__,
400 slave_port_id, ret);
401 }
402 }
403
404 /* slim_define_ch api */
405 prop.prot = SLIM_AUTO_ISO;
406 prop.baser = SLIM_RATE_4000HZ;
407 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
408 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
409 prop.ratem = (rate/4000);
410 prop.sampleszbits = 16;
411 ret = slim_define_ch(tab->slim, &prop, ch_h, ch_cnt,
412 true, &grph);
413 if (ret < 0) {
414 pr_err("%s: slim_define_ch failed ret[%d]\n",
415 __func__, ret);
416 goto err;
417 }
418 for (i = 0; i < ch_cnt; i++) {
419 ret = slim_connect_src(tab->slim, sph[i],
420 ch_h[i]);
421 if (ret < 0) {
422 pr_err("%s: slim_connect_src failed ret[%d]\n",
423 __func__, ret);
424 goto err;
425 }
426 }
427 /* slim_control_ch */
428 ret = slim_control_ch(tab->slim, grph, SLIM_CH_ACTIVATE,
429 true);
430 if (ret < 0) {
431 pr_err("%s: slim_control_ch failed ret[%d]\n",
432 __func__, ret);
433 goto err;
434 }
435 for (i = 0; i < ch_cnt; i++) {
436 idx = (ch_num[i] - BASE_CH_NUM);
437 tx[idx].grph = grph;
438 }
439 return 0;
440err:
441 /* release all acquired handles */
442 tabla_close_slim_sch_tx(tab, ch_num, ch_cnt);
443 return ret;
444}
445EXPORT_SYMBOL_GPL(tabla_cfg_slim_sch_tx);
446
447int tabla_close_slim_sch_rx(struct tabla *tab, unsigned int *ch_num,
448 unsigned int ch_cnt)
449{
450 u16 grph = 0;
451 u32 sph[SLIM_MAX_RX_PORTS] = {0};
452 int i = 0 , idx = 0;
453 int ret = 0;
454 struct tabla_slim_sch_rx *rx = sh_ch.rx;
455
456 pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
457 for (i = 0; i < ch_cnt; i++) {
458 idx = (ch_num[i] - BASE_CH_NUM -
459 SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
460 sph[i] = rx[idx].sph;
461 grph = rx[idx].grph;
462 }
463
464 /* slim_disconnect_port */
465 ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
466 if (ret < 0) {
467 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
468 __func__, ret);
469 }
470 /* slim_control_ch (REMOVE) */
471 ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
472 if (ret < 0) {
473 pr_err("%s: slim_control_ch failed ret[%d]\n",
474 __func__, ret);
475 goto err;
476 }
477 for (i = 0; i < ch_cnt; i++) {
478 idx = (ch_num[i] - BASE_CH_NUM -
479 SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS - 1);
480 rx[idx].grph = 0;
481 }
482err:
483 return ret;
484}
485EXPORT_SYMBOL_GPL(tabla_close_slim_sch_rx);
486
487int tabla_close_slim_sch_tx(struct tabla *tab, unsigned int *ch_num,
488 unsigned int ch_cnt)
489{
490 u16 grph = 0;
491 u32 sph[SLIM_MAX_TX_PORTS] = {0};
492 int ret = 0;
493 int i = 0 , idx = 0;
494 struct tabla_slim_sch_tx *tx = sh_ch.tx;
495
496 pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
497 for (i = 0; i < ch_cnt; i++) {
498 idx = (ch_num[i] - BASE_CH_NUM);
499 sph[i] = tx[idx].sph;
500 grph = tx[idx].grph;
501 }
502 /* slim_disconnect_port */
503 ret = slim_disconnect_ports(tab->slim, sph, ch_cnt);
504 if (ret < 0) {
505 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
506 __func__, ret);
507 }
508 /* slim_control_ch (REMOVE) */
509 ret = slim_control_ch(tab->slim, grph, SLIM_CH_REMOVE, true);
510 if (ret < 0) {
511 pr_err("%s: slim_control_ch failed ret[%d]\n",
512 __func__, ret);
513 goto err;
514 }
515 for (i = 0; i < ch_cnt; i++) {
516 idx = (ch_num[i] - BASE_CH_NUM);
517 tx[idx].grph = 0;
518 }
519err:
520 return ret;
521}
522EXPORT_SYMBOL_GPL(tabla_close_slim_sch_tx);