blob: 81262b5820f4ffbe44b94a9d5f3c34b2f0913cf5 [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 Park1277cb62013-03-19 14:16:51 -070034 if (wcd9xxx->codec_type->slim_slave_type ==
35 WCD9XXX_SLIM_SLAVE_ADDR_TYPE_TABLA) {
Joonwoo Park3cf3a942013-02-13 14:18:22 -080036 sh_ch.rx_port_ch_reg_base = 0x180;
Joonwoo Parka7172112012-07-23 16:03:49 -070037 sh_ch.port_rx_cfg_reg_base = 0x040;
Kuirong Wang906ac472012-07-09 12:54:44 -070038 sh_ch.port_tx_cfg_reg_base = 0x040;
39 } else {
40 sh_ch.rx_port_ch_reg_base =
41 0x180 - (TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
42 sh_ch.port_rx_cfg_reg_base =
Joonwoo Park3cf3a942013-02-13 14:18:22 -080043 0x040 - TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
Joonwoo Parka7172112012-07-23 16:03:49 -070044 sh_ch.port_tx_cfg_reg_base = 0x050;
Joonwoo Parka7172112012-07-23 16:03:49 -070045 }
46
47 return 0;
48}
49
Kuirong Wang906ac472012-07-09 12:54:44 -070050
51int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la,
52 unsigned int tx_num, unsigned int *tx_slot,
53 unsigned int rx_num, unsigned int *rx_slot)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080054{
55 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -070056 int i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080057
Joonwoo Parka7172112012-07-23 16:03:49 -070058 ret = wcd9xxx_configure_ports(wcd9xxx);
59 if (ret) {
60 pr_err("%s: Failed to configure register address offset\n",
61 __func__);
62 goto err;
63 }
64
Kuirong Wang906ac472012-07-09 12:54:44 -070065 if (wcd9xxx->rx_chs) {
66 wcd9xxx->num_rx_port = rx_num;
67 for (i = 0; i < rx_num; i++) {
68 wcd9xxx->rx_chs[i].ch_num = rx_slot[i];
69 INIT_LIST_HEAD(&wcd9xxx->rx_chs[i].list);
70 }
71 ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
72 wcd9xxx->num_rx_port,
73 wcd9xxx->rx_chs,
74 SLIM_SINK);
75 if (ret) {
76 pr_err("%s: Failed to alloc %d rx slimbus channels\n",
77 __func__, wcd9xxx->num_rx_port);
78 kfree(wcd9xxx->rx_chs);
79 wcd9xxx->rx_chs = NULL;
80 wcd9xxx->num_rx_port = 0;
81 }
82 } else {
83 pr_err("Not able to allocate memory for %d slimbus rx ports\n",
84 wcd9xxx->num_rx_port);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080085 }
Kuirong Wang906ac472012-07-09 12:54:44 -070086
87 if (wcd9xxx->tx_chs) {
88 wcd9xxx->num_tx_port = tx_num;
89 for (i = 0; i < tx_num; i++) {
90 wcd9xxx->tx_chs[i].ch_num = tx_slot[i];
91 INIT_LIST_HEAD(&wcd9xxx->tx_chs[i].list);
92 }
93 ret = wcd9xxx_alloc_slim_sh_ch(wcd9xxx, wcd9xxx_pgd_la,
94 wcd9xxx->num_tx_port,
95 wcd9xxx->tx_chs,
96 SLIM_SRC);
97 if (ret) {
98 pr_err("%s: Failed to alloc %d tx slimbus channels\n",
99 __func__, wcd9xxx->num_tx_port);
100 kfree(wcd9xxx->tx_chs);
101 wcd9xxx->tx_chs = NULL;
102 wcd9xxx->num_tx_port = 0;
103 }
104 } else {
105 pr_err("Not able to allocate memory for %d slimbus tx ports\n",
106 wcd9xxx->num_tx_port);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800107 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700108
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800109 return 0;
Joonwoo Parka7172112012-07-23 16:03:49 -0700110err:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800111 return ret;
112}
113
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530114int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800115{
Kuirong Wang906ac472012-07-09 12:54:44 -0700116 if (wcd9xxx->num_rx_port) {
117 wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
118 wcd9xxx->num_rx_port,
119 wcd9xxx->rx_chs);
120 wcd9xxx->num_rx_port = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800121 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700122 if (wcd9xxx->num_tx_port) {
123 wcd9xxx_dealloc_slim_sh_ch(wcd9xxx->slim,
124 wcd9xxx->num_tx_port,
125 wcd9xxx->tx_chs);
126 wcd9xxx->num_tx_port = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800127 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800128 return 0;
129}
130
Kuirong Wang906ac472012-07-09 12:54:44 -0700131
132static int wcd9xxx_alloc_slim_sh_ch(struct wcd9xxx *wcd9xxx,
133 u8 wcd9xxx_pgd_la, u32 cnt,
134 struct wcd9xxx_ch *channels, u32 path)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800135{
136 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700137 u32 ch_idx ;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800138
Kuirong Wang906ac472012-07-09 12:54:44 -0700139 /* The slimbus channel allocation seem take longer time
140 * so do the allocation up front to avoid delay in start of
141 * playback
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800142 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530143 pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
Kuirong Wang906ac472012-07-09 12:54:44 -0700144 for (ch_idx = 0; ch_idx < cnt; ch_idx++) {
145 ret = slim_get_slaveport(wcd9xxx_pgd_la,
146 channels[ch_idx].port,
147 &channels[ch_idx].sph, path);
148 pr_debug("%s: pgd_la[%d] channels[%d].port[%d]\n"
149 "channels[%d].sph[%d] path[%d]\n",
150 __func__, wcd9xxx_pgd_la, ch_idx,
151 channels[ch_idx].port,
152 ch_idx, channels[ch_idx].sph, path);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800153 if (ret < 0) {
154 pr_err("%s: slave port failure id[%d] ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700155 __func__, channels[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800156 goto err;
157 }
158
Kuirong Wang906ac472012-07-09 12:54:44 -0700159 ret = slim_query_ch(wcd9xxx->slim,
160 channels[ch_idx].ch_num,
161 &channels[ch_idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800162 if (ret < 0) {
163 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700164 __func__, channels[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800165 goto err;
166 }
167 }
168err:
169 return ret;
170}
171
Kuirong Wang906ac472012-07-09 12:54:44 -0700172static int wcd9xxx_dealloc_slim_sh_ch(struct slim_device *slim,
173 u32 cnt, struct wcd9xxx_ch *channels)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800174{
175 int idx = 0;
176 int ret = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800177 /* slim_dealloc_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700178 for (idx = 0; idx < cnt; idx++) {
179 ret = slim_dealloc_ch(slim, channels[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800180 if (ret < 0) {
181 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700182 __func__, ret, channels[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800183 }
184 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800185 return ret;
186}
187
188/* Enable slimbus slave device for RX path */
Kuirong Wang906ac472012-07-09 12:54:44 -0700189int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx,
190 struct list_head *wcd9xxx_ch_list,
191 unsigned int rate, unsigned int bit_width,
192 u16 *grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800193{
Kuirong Wang906ac472012-07-09 12:54:44 -0700194 u8 ch_cnt = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800195 u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
Kuirong Wang906ac472012-07-09 12:54:44 -0700196 u8 payload = 0;
197 u16 codec_port = 0;
198 int ret;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800199 struct slim_ch prop;
Kuirong Wang906ac472012-07-09 12:54:44 -0700200 struct wcd9xxx_ch *rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800201
202 /* Configure slave interface device */
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800203
Kuirong Wang906ac472012-07-09 12:54:44 -0700204 list_for_each_entry(rx, wcd9xxx_ch_list, list) {
205 payload |= 1 << rx->shift;
206 ch_h[ch_cnt] = rx->ch_h;
207 ch_cnt++;
208 pr_debug("list ch->ch_h %d ch->sph %d\n", rx->ch_h, rx->sph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800209 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700210 pr_debug("%s: ch_cnt[%d] rate=%d WATER_MARK_VAL %d\n",
211 __func__, ch_cnt, rate, WATER_MARK_VAL);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800212 /* slim_define_ch api */
213 prop.prot = SLIM_AUTO_ISO;
214 prop.baser = SLIM_RATE_4000HZ;
215 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
216 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
217 prop.ratem = (rate/4000);
Bhalchandra Gajare5b40c532013-02-19 13:36:47 -0800218 prop.sampleszbits = bit_width;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800219
Kuirong Wang906ac472012-07-09 12:54:44 -0700220 pr_debug("Before slim_define_ch:\n"
221 "ch_cnt %d,ch_h[0] %d ch_h[1] %d, grph %d\n",
222 ch_cnt, ch_h[0], ch_h[1], *grph);
223 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
224 true, grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800225 if (ret < 0) {
226 pr_err("%s: slim_define_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700227 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800228 goto err;
229 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700230
231 list_for_each_entry(rx, wcd9xxx_ch_list, list) {
232 codec_port = rx->port;
233 pr_debug("%s: codec_port %d rx 0x%x, payload %d\n"
234 "sh_ch.rx_port_ch_reg_base0 0x%x\n"
235 "sh_ch.port_rx_cfg_reg_base 0x%x\n",
236 __func__, codec_port, (u32)rx, payload,
237 sh_ch.rx_port_ch_reg_base,
238 sh_ch.port_rx_cfg_reg_base);
239
240 /* look for the valid port range and chose the
241 * payload accordingly
242 */
243 /* write to interface device */
244 ret = wcd9xxx_interface_reg_write(wcd9xxx,
245 SB_PGD_RX_PORT_MULTI_CHANNEL_0(
246 sh_ch.rx_port_ch_reg_base, codec_port),
247 payload);
248
249 if (ret < 0) {
250 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
251 __func__,
252 SB_PGD_RX_PORT_MULTI_CHANNEL_0(
253 sh_ch.rx_port_ch_reg_base, codec_port),
254 payload, ret);
255 goto err;
256 }
257 /* configure the slave port for water mark and enable*/
258 ret = wcd9xxx_interface_reg_write(wcd9xxx,
259 SB_PGD_PORT_CFG_BYTE_ADDR(
260 sh_ch.port_rx_cfg_reg_base, codec_port),
261 WATER_MARK_VAL);
262 if (ret < 0) {
263 pr_err("%s:watermark set failure for port[%d] ret[%d]",
264 __func__, codec_port, ret);
265 }
266
267 ret = slim_connect_sink(wcd9xxx->slim, &rx->sph, 1, rx->ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800268 if (ret < 0) {
269 pr_err("%s: slim_connect_sink failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700270 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800271 goto err_close_slim_sch;
272 }
273 }
274 /* slim_control_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700275 ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
276 true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800277 if (ret < 0) {
278 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700279 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800280 goto err_close_slim_sch;
281 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800282 return 0;
283
284err_close_slim_sch:
285 /* release all acquired handles */
Kuirong Wang906ac472012-07-09 12:54:44 -0700286 wcd9xxx_close_slim_sch_rx(wcd9xxx, wcd9xxx_ch_list, *grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800287err:
288 return ret;
289}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530290EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800291
292/* Enable slimbus slave device for RX path */
Kuirong Wang906ac472012-07-09 12:54:44 -0700293int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx,
294 struct list_head *wcd9xxx_ch_list,
295 unsigned int rate, unsigned int bit_width,
296 u16 *grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800297{
Kuirong Wang906ac472012-07-09 12:54:44 -0700298 u16 ch_cnt = 0;
299 u16 payload = 0;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800300 u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
Kuirong Wang906ac472012-07-09 12:54:44 -0700301 u16 codec_port;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800302 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700303 struct wcd9xxx_ch *tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800304
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800305 struct slim_ch prop;
306
Kuirong Wang906ac472012-07-09 12:54:44 -0700307 list_for_each_entry(tx, wcd9xxx_ch_list, list) {
308 payload |= 1 << tx->shift;
309 ch_h[ch_cnt] = tx->ch_h;
310 ch_cnt++;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800311 }
312
313 /* slim_define_ch api */
314 prop.prot = SLIM_AUTO_ISO;
315 prop.baser = SLIM_RATE_4000HZ;
316 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
317 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
318 prop.ratem = (rate/4000);
319 prop.sampleszbits = 16;
Kuirong Wang906ac472012-07-09 12:54:44 -0700320 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt,
321 true, grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800322 if (ret < 0) {
Kuirong Wang906ac472012-07-09 12:54:44 -0700323 pr_err("%s: slim_define_ch failed ret[%d]\n",
324 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800325 goto err;
326 }
Kuirong Wang906ac472012-07-09 12:54:44 -0700327
328 pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
329 list_for_each_entry(tx, wcd9xxx_ch_list, list) {
330 codec_port = tx->port;
331 pr_debug("%s: codec_port %d rx 0x%x, payload 0x%x\n",
332 __func__, codec_port, (u32)tx, payload);
333 /* write to interface device */
334 ret = wcd9xxx_interface_reg_write(wcd9xxx,
335 SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
336 payload & 0x00FF);
337 if (ret < 0) {
338 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
339 __func__,
340 SB_PGD_TX_PORT_MULTI_CHANNEL_0(codec_port),
341 payload, ret);
342 goto err;
343 }
344 /* ports 8,9 */
345 ret = wcd9xxx_interface_reg_write(wcd9xxx,
346 SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
347 (payload & 0xFF00)>>8);
348 if (ret < 0) {
349 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
350 __func__,
351 SB_PGD_TX_PORT_MULTI_CHANNEL_1(codec_port),
352 payload, ret);
353 goto err;
354 }
355 /* configure the slave port for water mark and enable*/
356 ret = wcd9xxx_interface_reg_write(wcd9xxx,
357 SB_PGD_PORT_CFG_BYTE_ADDR(
358 sh_ch.port_tx_cfg_reg_base, codec_port),
359 WATER_MARK_VAL);
360 if (ret < 0) {
361 pr_err("%s:watermark set failure for port[%d] ret[%d]",
362 __func__, codec_port, ret);
363 }
364
365 ret = slim_connect_src(wcd9xxx->slim, tx->sph, tx->ch_h);
366
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800367 if (ret < 0) {
368 pr_err("%s: slim_connect_src failed ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700369 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800370 goto err;
371 }
372 }
373 /* slim_control_ch */
Kuirong Wang906ac472012-07-09 12:54:44 -0700374 ret = slim_control_ch(wcd9xxx->slim, *grph, SLIM_CH_ACTIVATE,
375 true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800376 if (ret < 0) {
377 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700378 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800379 goto err;
380 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800381 return 0;
382err:
383 /* release all acquired handles */
Kuirong Wang906ac472012-07-09 12:54:44 -0700384 wcd9xxx_close_slim_sch_tx(wcd9xxx, wcd9xxx_ch_list, *grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800385 return ret;
386}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530387EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800388
Kuirong Wang906ac472012-07-09 12:54:44 -0700389int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx,
390 struct list_head *wcd9xxx_ch_list, u16 grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800391{
Kuirong Wang906ac472012-07-09 12:54:44 -0700392 u32 sph[SLIM_MAX_RX_PORTS] = {0};
393 int ch_cnt = 0 ;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800394 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700395 struct wcd9xxx_ch *rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800396
Kuirong Wang906ac472012-07-09 12:54:44 -0700397 list_for_each_entry(rx, wcd9xxx_ch_list, list)
398 sph[ch_cnt++] = rx->sph;
399
400 pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n", __func__, ch_cnt,
401 sph[0], sph[1]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800402
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800403 /* slim_control_ch (REMOVE) */
Kuirong Wang906ac472012-07-09 12:54:44 -0700404 pr_debug("%s before slim_control_ch grph %d\n", __func__, grph);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530405 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800406 if (ret < 0) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700407 pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800408 goto err;
409 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800410err:
411 return ret;
412}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530413EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800414
Kuirong Wang906ac472012-07-09 12:54:44 -0700415int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx,
416 struct list_head *wcd9xxx_ch_list,
417 u16 grph)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800418{
Kuirong Wang906ac472012-07-09 12:54:44 -0700419 u32 sph[SLIM_MAX_TX_PORTS] = {0};
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800420 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700421 int ch_cnt = 0 ;
422 struct wcd9xxx_ch *tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800423
Kuirong Wang906ac472012-07-09 12:54:44 -0700424 pr_debug("%s\n", __func__);
425 list_for_each_entry(tx, wcd9xxx_ch_list, list)
426 sph[ch_cnt++] = tx->sph;
427
428 pr_debug("%s ch_cht %d, sph[0] %d sph[1] %d\n",
429 __func__, ch_cnt, sph[0], sph[1]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800430 /* slim_control_ch (REMOVE) */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530431 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800432 if (ret < 0) {
433 pr_err("%s: slim_control_ch failed ret[%d]\n",
Kuirong Wang906ac472012-07-09 12:54:44 -0700434 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800435 goto err;
436 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800437err:
438 return ret;
439}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530440EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700441
442int wcd9xxx_get_slave_port(unsigned int ch_num)
443{
444 int ret = 0;
445
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700446 ret = (ch_num - BASE_CH_NUM);
Kuirong Wang906ac472012-07-09 12:54:44 -0700447 pr_debug("%s: ch_num[%d] slave port[%d]\n", __func__, ch_num, ret);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700448 if (ret < 0) {
449 pr_err("%s: Error:- Invalid slave port found = %d\n",
450 __func__, ret);
451 return -EINVAL;
452 }
453 return ret;
454}
455EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700456
Kuirong Wang906ac472012-07-09 12:54:44 -0700457int wcd9xxx_disconnect_port(struct wcd9xxx *wcd9xxx,
458 struct list_head *wcd9xxx_ch_list, u16 grph)
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700459{
Kuirong Wang906ac472012-07-09 12:54:44 -0700460 u32 sph[SLIM_MAX_TX_PORTS + SLIM_MAX_RX_PORTS] = {0};
461 int ch_cnt = 0 ;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700462 int ret = 0;
Kuirong Wang906ac472012-07-09 12:54:44 -0700463 struct wcd9xxx_ch *slim_ch;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700464
Kuirong Wang906ac472012-07-09 12:54:44 -0700465 list_for_each_entry(slim_ch, wcd9xxx_ch_list, list)
466 sph[ch_cnt++] = slim_ch->sph;
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700467
468 /* slim_disconnect_port */
469 ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
470 if (ret < 0) {
471 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
472 __func__, ret);
473 }
Swaminathan Sathappan53773982012-08-10 21:02:14 -0700474 return ret;
475}
476EXPORT_SYMBOL_GPL(wcd9xxx_disconnect_port);
Kuirong Wangdcc392e2012-10-19 00:33:38 -0700477
478/* This function is called with mutex acquired */
479int wcd9xxx_rx_vport_validation(u32 port_id,
480 struct list_head *codec_dai_list)
481{
482 struct wcd9xxx_ch *ch;
483 int ret = 0;
484
485 pr_debug("%s: port_id %u\n", __func__, port_id);
486
487 list_for_each_entry(ch,
488 codec_dai_list, list) {
489 pr_debug("%s: ch->port %u\n", __func__, ch->port);
490 if (ch->port == port_id) {
491 ret = -EINVAL;
492 break;
493 }
494 }
495 return ret;
496}
497EXPORT_SYMBOL_GPL(wcd9xxx_rx_vport_validation);
498
499
500/* This function is called with mutex acquired */
501int wcd9xxx_tx_vport_validation(u32 vtable, u32 port_id,
502 struct wcd9xxx_codec_dai_data *codec_dai)
503{
504 struct wcd9xxx_ch *ch;
505 int ret = 0;
506 u32 index;
507 u32 size = sizeof(vtable) * 8;
508 pr_debug("%s: vtable 0x%x port_id %u size %d\n", __func__,
509 vtable, port_id, size);
510 for_each_set_bit(index, (unsigned long *)&vtable, size) {
511 list_for_each_entry(ch,
512 &codec_dai[index].wcd9xxx_ch_list,
513 list) {
514 pr_debug("%s: index %u ch->port %u vtable 0x%x\n",
515 __func__, index, ch->port, vtable);
516 if (ch->port == port_id) {
517 pr_err("%s: TX%u is used by AIF%u_CAP Mixer\n",
518 __func__, port_id + 1,
519 (index + 1)/2);
520 ret = -EINVAL;
521 break;
522 }
523 }
524 if (ret)
525 break;
526 }
527 return ret;
528}
529EXPORT_SYMBOL_GPL(wcd9xxx_tx_vport_validation);