blob: f2d71b62e65807052f83a334969359563a4bfccd [file] [log] [blame]
Joonwoo Park3cf3a942013-02-13 14:18:22 -08001/* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -08002 *
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>
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053014#include <linux/mfd/wcd9xxx/wcd9xxx-slimslave.h>
Joonwoo Parka7172112012-07-23 16:03:49 -070015#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
16
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053017struct wcd9xxx_slim_sch {
Joonwoo Parka7172112012-07-23 16:03:49 -070018 u16 rx_port_ch_reg_base;
19 u16 port_tx_cfg_reg_base;
20 u16 port_rx_cfg_reg_base;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080021};
22
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053023static struct wcd9xxx_slim_sch sh_ch;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080024
Kuirong Wang906ac472012-07-09 12:54:44 -070025static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
26 u8 wcd9xxx_pgd_la, u32 cnt,
27 struct wcd9xxx_ch *channels, u32 path);
28
29static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
30 u32 cnt, struct wcd9xxx_ch *channels);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080031
Joonwoo Parka7172112012-07-23 16:03:49 -070032static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
33{
Joonwoo Park3cf3a942013-02-13 14:18:22 -080034 if (wcd9xxx->slim_slave_type == WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA) {
35 sh_ch.rx_port_ch_reg_base = 0x180;
Joonwoo Parka7172112012-07-23 16:03:49 -070036 sh_ch.port_rx_cfg_reg_base = 0x040;
Kuirong Wang906ac472012-07-09 12:54:44 -070037 sh_ch.port_tx_cfg_reg_base = 0x040;
38 } else {
39 sh_ch.rx_port_ch_reg_base =
40 0x180 - (TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
41 sh_ch.port_rx_cfg_reg_base =
Joonwoo Park3cf3a942013-02-13 14:18:22 -080042 0x040 - TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
Joonwoo Parka7172112012-07-23 16:03:49 -070043 sh_ch.port_tx_cfg_reg_base = 0x050;
Joonwoo Parka7172112012-07-23 16:03:49 -070044 }
45
46 return 0;
47}
48
Kuirong Wang906ac472012-07-09 12:54:44 -070049
50int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
51 unsigned int tx_num, unsigned int *tx_slot,
52 unsigned int rx_num, unsigned int *rx_slot)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080053{
54 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -070055 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080056
Joonwoo Parka7172112012-07-23 16:03:49 -070057 ret = wcd9xxx_configure_ports(wcd9xxx);
58 if (ret) {
59 pr_err("%s: Failed to configure register address offset\n",
60 __func__);
61 goto err;
62 }
63
Kuirong Wang906ac472012-07-09 12:54:44 -070064 if (wcd9xxx->rx_chs) {
65 wcd9xxx->num_rx_port = rx_num;
66 for (i = 0; i < rx_num; i++) {
67 wcd9xxx->rx_chs[i].ch_num = rx_slot[i];
68 INIT_LIST_HEAD(&wcd9xxx->rx_chs[i].list);
69 }
70 ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
71 wcd9xxx->num_rx_port,
72 wcd9xxx->rx_chs,
73 SLIM_SINK);
74 if (ret) {
75 pr_err("%s: Failed to alloc %d rx slimbus channels\n",
76 __func__, wcd9xxx->num_rx_port);
77 kfree(wcd9xxx->rx_chs);
78 wcd9xxx->rx_chs = NULL;
79 wcd9xxx->num_rx_port = 0;
80 }
81 } else {
82 pr_err("Not able to allocate memory for %d slimbus rx ports\n",
83 wcd9xxx->num_rx_port);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080084 }
Kuirong Wang906ac472012-07-09 12:54:44 -070085
86 if (wcd9xxx->tx_chs) {
87 wcd9xxx->num_tx_port = tx_num;
88 for (i = 0; i < tx_num; i++) {
89 wcd9xxx->tx_chs[i].ch_num = tx_slot[i];
90 INIT_LIST_HEAD(&wcd9xxx->tx_chs[i].list);
91 }
92 ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
93 wcd9xxx->num_tx_port,
94 wcd9xxx->tx_chs,
95 SLIM_SRC);
96 if (ret) {
97 pr_err("%s: Failed to alloc %d tx slimbus channels\n",
98 __func__, wcd9xxx->num_tx_port);
99 kfree(wcd9xxx->tx_chs);
100 wcd9xxx->tx_chs = NULL;
101 wcd9xxx->num_tx_port = 0;
102 }
103 } else {
104 pr_err("Not able to allocate memory for %d slimbus tx ports\n",
105 wcd9xxx->num_tx_port);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800106 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700107
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800108 return 0;
Joonwoo Parka7172112012-07-23 16:03:49 -0700109err:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800110 return ret;
111}
112
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530113int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800114{
Kuirong Wang906ac472012-07-09 12:54:44 -0700115 if (wcd9xxx->num_rx_port) {
116 wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
117 wcd9xxx->num_rx_port,
118 wcd9xxx->rx_chs);
119 wcd9xxx->num_rx_port = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800120 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700121 if (wcd9xxx->num_tx_port) {
122 wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
123 wcd9xxx->num_tx_port,
124 wcd9xxx->tx_chs);
125 wcd9xxx->num_tx_port = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800126 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800127 return 0;
128}
129
Kuirong Wang906ac472012-07-09 12:54:44 -0700130
131static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
132 u8 wcd9xxx_pgd_la, u32 cnt,
133 struct wcd9xxx_ch *channels, u32 path)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800134{
135 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700136 u32 ch_idx ;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800137
Kuirong Wang906ac472012-07-09 12:54:44 -0700138 /* The slimbus channel allocation seem take longer time
139 * so do the allocation up front to avoid delay in start of
140 * playback
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800141 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530142 pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
Kuirong Wang906ac472012-07-09 12:54:44 -0700143 for (ch_idx = 0; ch_idx < cnt; ch_idx++) {
144 ret = slim_get_slaveport(wcd9xxx_pgd_la,
145 channels[ch_idx].port,
146 &channels[ch_idx].sph, path);
147 pr_debug("%s: pgd_la[%d] channels[%d].port[%d]\n"
148 "channels[%d].sph[%d] path[%d]\n",
149 __func__, wcd9xxx_pgd_la, ch_idx,
150 channels[ch_idx].port,
151 ch_idx, channels[ch_idx].sph, path);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800152 if (ret < 0) {
153 pr_err("%s: slave port failure id[%d] ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700154 __func__, channels[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800155 goto err;
156 }
157
Kuirong Wang906ac472012-07-09 12:54:44 -0700158 ret = slim_query_ch(wcd9xxx->slim,
159 channels[ch_idx].ch_num,
160 &channels[ch_idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800161 if (ret < 0) {
162 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700163 __func__, channels[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800164 goto err;
165 }
166 }
167err:
168 return ret;
169}
170
Kuirong Wang906ac472012-07-09 12:54:44 -0700171static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
172 u32 cnt, struct wcd9xxx_ch *channels)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800173{
174 int idx = 0;
175 int ret = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800176 /* slim_dealloc_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700177 for (idx = 0; idx < cnt; idx++) {
178 ret = slim_dealloc_ch(slim, channels[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800179 if (ret < 0) {
180 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700181 __func__, ret, channels[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800182 }
183 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800184 return ret;
185}
186
187/* Enable slimbus slave device for RX path */
Kuirong Wang906ac472012-07-09 12:54:44 -0700188int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
189 struct list_head *wcd9xxx_ch_list,
190 unsigned int rate, unsigned int bit_width,
191 u16 *grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800192{
Kuirong Wang906ac472012-07-09 12:54:44 -0700193 u8 ch_cnt = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800194 u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
Kuirong Wang906ac472012-07-09 12:54:44 -0700195 u8 payload = 0;
196 u16 codec_port = 0;
197 int ret;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800198 struct slim_ch prop;
Kuirong Wang906ac472012-07-09 12:54:44 -0700199 struct wcd9xxx_ch *rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800200
201 /* Configure slave interface device */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800202
Kuirong Wang906ac472012-07-09 12:54:44 -0700203 list_for_each_entry(rx, wcd9xxx_ch_list, list) {
204 payload |= 1 << rx->shift;
205 ch_h[ch_cnt] = rx->ch_h;
206 ch_cnt++;
207 pr_debug("list ch->ch_h %d ch->sph %d\n", rx->ch_h, rx->sph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800208 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700209 pr_debug("%s: ch_cnt[%d] rate=%d WATER_MARK_VAL %d\n",
210 __func__, ch_cnt, rate, WATER_MARK_VAL);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800211 /* slim_define_ch api */
212 prop.prot = SLIM_AUTO_ISO;
213 prop.baser = SLIM_RATE_4000HZ;
214 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
215 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
216 prop.ratem = (rate/4000);
Bhalchandra Gajare5b40c532013-02-19 13:36:47 -0800217 prop.sampleszbits = bit_width;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800218
Kuirong Wang906ac472012-07-09 12:54:44 -0700219 pr_debug("Before slim_define_ch:\n"
220 "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
221 ch_cnt, ch_h[0], ch_h[1], *grph);
222 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
223 true, grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800224 if (ret < 0) {
225 pr_err("%s: slim_define_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700226 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800227 goto err;
228 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700229
230 list_for_each_entry(rx, wcd9xxx_ch_list, list) {
231 codec_port = rx->port;
232 pr_debug("%s: codec_port %d rx 0x%x, payload %d\n"
233 "sh_ch.rx_port_ch_reg_base0 0x%x\n"
234 "sh_ch.port_rx_cfg_reg_base 0x%x\n",
235 __func__, codec_port, (u32)rx, payload,
236 sh_ch.rx_port_ch_reg_base,
237 sh_ch.port_rx_cfg_reg_base);
238
239 /* look for the valid port range and chose the
240 * payload accordingly
241 */
242 /* write to interface device */
243 ret = wcd9xxx_interface_reg_write(wcd9xxx,
244 SB_PGD_RX_PORT_MULTI_CHANNEL_0(
245 sh_ch.rx_port_ch_reg_base, codec_port),
246 payload);
247
248 if (ret < 0) {
249 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
250 __func__,
251 SB_PGD_RX_PORT_MULTI_CHANNEL_0(
252 sh_ch.rx_port_ch_reg_base, codec_port),
253 payload, ret);
254 goto err;
255 }
256 /* configure the slave port for water mark and enable*/
257 ret = wcd9xxx_interface_reg_write(wcd9xxx,
258 SB_PGD_PORT_CFG_BYTE_ADDR(
259 sh_ch.port_rx_cfg_reg_base, codec_port),
260 WATER_MARK_VAL);
261 if (ret < 0) {
262 pr_err("%s:watermark set failure for port[%d] ret[%d]",
263 __func__, codec_port, ret);
264 }
265
266 ret = slim_connect_sink(wcd9xxx->slim, &rx->sph, 1, rx->ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800267 if (ret < 0) {
268 pr_err("%s: slim_connect_sink failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700269 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800270 goto err_close_slim_sch;
271 }
272 }
273 /* slim_control_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700274 ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
275 true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800276 if (ret < 0) {
277 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700278 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800279 goto err_close_slim_sch;
280 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800281 return 0;
282
283err_close_slim_sch:
284 /* release all acquired handles */
Kuirong Wang906ac472012-07-09 12:54:44 -0700285 wcd9xxx_close_slim_sch_rx(wcd9xxx, wcd9xxx_ch_list, *grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800286err:
287 return ret;
288}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530289EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800290
291/* Enable slimbus slave device for RX path */
Kuirong Wang906ac472012-07-09 12:54:44 -0700292int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
293 struct list_head *wcd9xxx_ch_list,
294 unsigned int rate, unsigned int bit_width,
295 u16 *grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800296{
Kuirong Wang906ac472012-07-09 12:54:44 -0700297 u16 ch_cnt = 0;
298 u16 payload = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800299 u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
Kuirong Wang906ac472012-07-09 12:54:44 -0700300 u16 codec_port;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800301 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700302 struct wcd9xxx_ch *tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800303
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800304 struct slim_ch prop;
305
Kuirong Wang906ac472012-07-09 12:54:44 -0700306 list_for_each_entry(tx, wcd9xxx_ch_list, list) {
307 payload |= 1 << tx->shift;
308 ch_h[ch_cnt] = tx->ch_h;
309 ch_cnt++;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800310 }
311
312 /* slim_define_ch api */
313 prop.prot = SLIM_AUTO_ISO;
314 prop.baser = SLIM_RATE_4000HZ;
315 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
316 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
317 prop.ratem = (rate/4000);
318 prop.sampleszbits = 16;
Kuirong Wang906ac472012-07-09 12:54:44 -0700319 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
320 true, grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800321 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -0700322 pr_err("%s: slim_define_ch failed ret[%d]\n",
323 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800324 goto err;
325 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700326
327 pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
328 list_for_each_entry(tx, wcd9xxx_ch_list, list) {
329 codec_port = tx->port;
330 pr_debug("%s: codec_port %d rx 0x%x, payload 0x%x\n",
331 __func__, codec_port, (u32)tx, payload);
332 /* write to interface device */
333 ret = wcd9xxx_interface_reg_write(wcd9xxx,
334 SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
335 payload & 0x00FF);
336 if (ret < 0) {
337 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
338 __func__,
339 SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
340 payload, ret);
341 goto err;
342 }
343 /* ports 8,9 */
344 ret = wcd9xxx_interface_reg_write(wcd9xxx,
345 SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
346 (payload & 0xFF00)>>8);
347 if (ret < 0) {
348 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
349 __func__,
350 SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
351 payload, ret);
352 goto err;
353 }
354 /* configure the slave port for water mark and enable*/
355 ret = wcd9xxx_interface_reg_write(wcd9xxx,
356 SB_PGD_PORT_CFG_BYTE_ADDR(
357 sh_ch.port_tx_cfg_reg_base, codec_port),
358 WATER_MARK_VAL);
359 if (ret < 0) {
360 pr_err("%s:watermark set failure for port[%d] ret[%d]",
361 __func__, codec_port, ret);
362 }
363
364 ret = slim_connect_src(wcd9xxx->slim, tx->sph, tx->ch_h);
365
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800366 if (ret < 0) {
367 pr_err("%s: slim_connect_src failed ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700368 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800369 goto err;
370 }
371 }
372 /* slim_control_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700373 ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
374 true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800375 if (ret < 0) {
376 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700377 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800378 goto err;
379 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800380 return 0;
381err:
382 /* release all acquired handles */
Kuirong Wang906ac472012-07-09 12:54:44 -0700383 wcd9xxx_close_slim_sch_tx(wcd9xxx, wcd9xxx_ch_list, *grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800384 return ret;
385}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530386EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800387
Kuirong Wang906ac472012-07-09 12:54:44 -0700388int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
389 struct list_head *wcd9xxx_ch_list, u16 grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800390{
Kuirong Wang906ac472012-07-09 12:54:44 -0700391 u32 sph[SLIM_MAX_RX_PORTS] = {0};
392 int ch_cnt = 0 ;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800393 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700394 struct wcd9xxx_ch *rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800395
Kuirong Wang906ac472012-07-09 12:54:44 -0700396 list_for_each_entry(rx, wcd9xxx_ch_list, list)
397 sph[ch_cnt++] = rx->sph;
398
399 pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", __func__, ch_cnt,
400 sph[0], sph[1]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800401
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800402 /* slim_control_ch (REMOVE) */
Kuirong Wang906ac472012-07-09 12:54:44 -0700403 pr_debug("%s before slim_control_ch grph %d\n", __func__, grph);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530404 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800405 if (ret < 0) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700406 pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800407 goto err;
408 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800409err:
410 return ret;
411}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530412EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800413
Kuirong Wang906ac472012-07-09 12:54:44 -0700414int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
415 struct list_head *wcd9xxx_ch_list,
416 u16 grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800417{
Kuirong Wang906ac472012-07-09 12:54:44 -0700418 u32 sph[SLIM_MAX_TX_PORTS] = {0};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800419 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700420 int ch_cnt = 0 ;
421 struct wcd9xxx_ch *tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800422
Kuirong Wang906ac472012-07-09 12:54:44 -0700423 pr_debug("%s\n", __func__);
424 list_for_each_entry(tx, wcd9xxx_ch_list, list)
425 sph[ch_cnt++] = tx->sph;
426
427 pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n",
428 __func__, ch_cnt, sph[0], sph[1]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800429 /* slim_control_ch (REMOVE) */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530430 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800431 if (ret < 0) {
432 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700433 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800434 goto err;
435 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800436err:
437 return ret;
438}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530439EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700440
441int wcd9xxx_get_slave_port(unsigned int ch_num)
442{
443 int ret = 0;
444
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700445 ret = (ch_num - BASE_CH_NUM);
Kuirong Wang906ac472012-07-09 12:54:44 -0700446 pr_debug("%s: ch_num[%d] slave port[%d]\n", __func__, ch_num, ret);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700447 if (ret < 0) {
448 pr_err("%s: Error:- Invalid slave port found = %d\n",
449 __func__, ret);
450 return -EINVAL;
451 }
452 return ret;
453}
454EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700455
Kuirong Wang906ac472012-07-09 12:54:44 -0700456int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
457 struct list_head *wcd9xxx_ch_list, u16 grph)
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700458{
Kuirong Wang906ac472012-07-09 12:54:44 -0700459 u32 sph[SLIM_MAX_TX_PORTS + SLIM_MAX_RX_PORTS] = {0};
460 int ch_cnt = 0 ;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700461 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700462 struct wcd9xxx_ch *slim_ch;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700463
Kuirong Wang906ac472012-07-09 12:54:44 -0700464 list_for_each_entry(slim_ch, wcd9xxx_ch_list, list)
465 sph[ch_cnt++] = slim_ch->sph;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700466
467 /* slim_disconnect_port */
468 ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
469 if (ret < 0) {
470 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
471 __func__, ret);
472 }
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700473 return ret;
474}
475EXPORT_SYMBOL_GPL(wcd9xxx_disconnect_port);
Kuirong Wangdcc392e2012-10-19 00:33:38 -0700476
477/* This function is called with mutex acquired */
478int wcd9xxx_rx_vport_validation(u32 port_id,
479 struct list_head *codec_dai_list)
480{
481 struct wcd9xxx_ch *ch;
482 int ret = 0;
483
484 pr_debug("%s: port_id %u\n", __func__, port_id);
485
486 list_for_each_entry(ch,
487 codec_dai_list, list) {
488 pr_debug("%s: ch->port %u\n", __func__, ch->port);
489 if (ch->port == port_id) {
490 ret = -EINVAL;
491 break;
492 }
493 }
494 return ret;
495}
496EXPORT_SYMBOL_GPL(wcd9xxx_rx_vport_validation);
497
498
499/* This function is called with mutex acquired */
500int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id,
501 struct wcd9xxx_codec_dai_data *codec_dai)
502{
503 struct wcd9xxx_ch *ch;
504 int ret = 0;
505 u32 index;
506 u32 size = sizeof(vtable) * 8;
507 pr_debug("%s: vtable 0x%x port_id %u size %d\n", __func__,
508 vtable, port_id, size);
509 for_each_set_bit(index, (unsigned long *)&vtable, size) {
510 list_for_each_entry(ch,
511 &codec_dai[index].wcd9xxx_ch_list,
512 list) {
513 pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
514 __func__, index, ch->port, vtable);
515 if (ch->port == port_id) {
516 pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
517 __func__, port_id + 1,
518 (index + 1)/2);
519 ret = -EINVAL;
520 break;
521 }
522 }
523 if (ret)
524 break;
525 }
526 return ret;
527}
528EXPORT_SYMBOL_GPL(wcd9xxx_tx_vport_validation);