blob: 71c68acb6cc166e538611b771bf7f9c84331b3dc [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>
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
17#define WCD9XXX_CHIP_ID_TAIKO 0x00000201
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080018
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053019struct wcd9xxx_slim_sch_rx {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080020 u32 sph;
21 u32 ch_num;
22 u16 ch_h;
23 u16 grph;
24};
25
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053026struct wcd9xxx_slim_sch_tx {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080027 u32 sph;
28 u32 ch_num;
29 u16 ch_h;
30 u16 grph;
31};
32
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053033struct wcd9xxx_slim_sch {
34 struct wcd9xxx_slim_sch_rx rx[SLIM_MAX_RX_PORTS];
35 struct wcd9xxx_slim_sch_tx tx[SLIM_MAX_TX_PORTS];
Joonwoo Parka7172112012-07-23 16:03:49 -070036
37 u16 rx_port_start_offset;
38 u16 num_rx_slave_port;
39 u16 port_ch_0_start_port_id;
40 u16 port_ch_0_end_port_id;
41 u16 pgd_tx_port_ch_1_end_port_id;
42 u16 rx_port_ch_reg_base;
43 u16 port_tx_cfg_reg_base;
44 u16 port_rx_cfg_reg_base;
45 int number_of_tx_slave_dev_ports;
46 int number_of_rx_slave_dev_ports;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080047};
48
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053049static struct wcd9xxx_slim_sch sh_ch;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080050
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053051static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
Joonwoo Parka7172112012-07-23 16:03:49 -070052 u8 wcd9xxx_pgd_la);
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +053053static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
54 u8 wcd9xxx_pgd_la);
55static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx);
56static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -080057
Joonwoo Parka7172112012-07-23 16:03:49 -070058static int wcd9xxx_configure_ports(struct wcd9xxx *wcd9xxx)
59{
60 int i;
61 u32 id;
62 for (i = 0; i < 4; i++)
63 ((u8 *)&id)[i] = wcd9xxx_reg_read(wcd9xxx,
64 WCD9XXX_A_CHIP_ID_BYTE_0 + i);
65 id = cpu_to_be32(id);
66 pr_debug("%s: chip id 0x%08x\n", __func__, id);
67 if (id != WCD9XXX_CHIP_ID_TAIKO) {
68 sh_ch.rx_port_start_offset =
69 TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
70 sh_ch.num_rx_slave_port =
71 TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
72 sh_ch.port_ch_0_start_port_id =
73 TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
74 sh_ch.port_ch_0_end_port_id =
75 TABLA_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
76 sh_ch.pgd_tx_port_ch_1_end_port_id =
77 TABLA_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
78
79 sh_ch.rx_port_ch_reg_base =
80 0x180 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS * 4);
81 sh_ch.port_rx_cfg_reg_base =
82 0x040 + (TABLA_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS);
83 sh_ch.port_tx_cfg_reg_base = 0x040;
84
85 sh_ch.number_of_tx_slave_dev_ports =
86 TABLA_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
87 sh_ch.number_of_rx_slave_dev_ports =
88 TABLA_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
89 } else {
90 sh_ch.rx_port_start_offset =
91 TAIKO_SB_PGD_OFFSET_OF_RX_SLAVE_DEV_PORTS;
92 sh_ch.num_rx_slave_port =
93 TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
94 sh_ch.port_ch_0_start_port_id =
95 TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_START_PORT_ID;
96 sh_ch.port_ch_0_end_port_id =
97 TAIKO_SB_PGD_RX_PORT_MULTI_CHANNEL_0_END_PORT_ID;
98 sh_ch.pgd_tx_port_ch_1_end_port_id =
99 TAIKO_SB_PGD_TX_PORT_MULTI_CHANNEL_1_END_PORT_ID;
100
101 sh_ch.rx_port_ch_reg_base = 0x180;
102 sh_ch.port_rx_cfg_reg_base = 0x040;
103 sh_ch.port_tx_cfg_reg_base = 0x050;
104
105 sh_ch.number_of_tx_slave_dev_ports =
106 TAIKO_SB_PGD_MAX_NUMBER_OF_TX_SLAVE_DEV_PORTS;
107 sh_ch.number_of_rx_slave_dev_ports =
108 TAIKO_SB_PGD_MAX_NUMBER_OF_RX_SLAVE_DEV_PORTS;
109 }
110
111 return 0;
112}
113
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530114int wcd9xxx_init_slimslave(struct wcd9xxx *wcd9xxx, u8 wcd9xxx_pgd_la)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800115{
116 int ret = 0;
117
Joonwoo Parka7172112012-07-23 16:03:49 -0700118 ret = wcd9xxx_configure_ports(wcd9xxx);
119 if (ret) {
120 pr_err("%s: Failed to configure register address offset\n",
121 __func__);
122 goto err;
123 }
124
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530125 ret = wcd9xxx_alloc_slim_sh_ch_rx(wcd9xxx, wcd9xxx_pgd_la);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800126 if (ret) {
127 pr_err("%s: Failed to alloc rx slimbus shared channels\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700128 __func__);
129 goto err;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800130 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530131 ret = wcd9xxx_alloc_slim_sh_ch_tx(wcd9xxx, wcd9xxx_pgd_la);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800132 if (ret) {
133 pr_err("%s: Failed to alloc tx slimbus shared channels\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700134 __func__);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800135 goto tx_err;
136 }
137 return 0;
138tx_err:
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530139 wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
Joonwoo Parka7172112012-07-23 16:03:49 -0700140err:
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800141 return ret;
142}
143
144
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530145int wcd9xxx_deinit_slimslave(struct wcd9xxx *wcd9xxx)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800146{
147 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530148 ret = wcd9xxx_dealloc_slim_sh_ch_rx(wcd9xxx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800149 if (ret < 0) {
150 pr_err("%s: fail to dealloc rx slim ports\n", __func__);
151 goto err;
152 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530153 ret = wcd9xxx_dealloc_slim_sh_ch_tx(wcd9xxx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800154 if (ret < 0) {
155 pr_err("%s: fail to dealloc tx slim ports\n", __func__);
156 goto err;
157 }
158err:
159 return ret;
160}
161
Joonwoo Parka7172112012-07-23 16:03:49 -0700162int wcd9xxx_get_channel(struct wcd9xxx *wcd9xxx, unsigned int *rx_ch,
163 unsigned int *tx_ch)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800164{
165 int ch_idx = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530166 struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
167 struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800168
Joonwoo Parka7172112012-07-23 16:03:49 -0700169 for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports; ch_idx++)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800170 rx_ch[ch_idx] = rx[ch_idx].ch_num;
Joonwoo Parka7172112012-07-23 16:03:49 -0700171 for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports; ch_idx++)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800172 tx_ch[ch_idx] = tx[ch_idx].ch_num;
173 return 0;
174}
175
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530176static int wcd9xxx_alloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx,
Joonwoo Parka7172112012-07-23 16:03:49 -0700177 u8 wcd9xxx_pgd_la)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800178{
179 int ret = 0;
180 u8 ch_idx ;
181 u16 slave_port_id = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530182 struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800183
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530184 /*
185 * DSP requires channel number to be between 128 and 255.
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800186 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530187 pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
Joonwoo Parka7172112012-07-23 16:03:49 -0700188 for (ch_idx = 0; ch_idx < sh_ch.number_of_rx_slave_dev_ports;
189 ch_idx++) {
190 slave_port_id = (ch_idx + sh_ch.rx_port_start_offset);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800191 rx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530192 ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800193 &rx[ch_idx].sph, SLIM_SINK);
194 if (ret < 0) {
195 pr_err("%s: slave port failure id[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700196 __func__, slave_port_id, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800197 goto err;
198 }
199
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530200 ret = slim_query_ch(wcd9xxx->slim, rx[ch_idx].ch_num,
Joonwoo Parka7172112012-07-23 16:03:49 -0700201 &rx[ch_idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800202 if (ret < 0) {
203 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700204 __func__, rx[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800205 goto err;
206 }
Joonwoo Parka7172112012-07-23 16:03:49 -0700207 pr_debug("%s:ch_num=%d ch_h=%d sph=%d la=%d slave_port_id %d\n",
208 __func__, rx[ch_idx].ch_num, rx[ch_idx].ch_h,
209 rx[ch_idx].sph, wcd9xxx_pgd_la, slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800210 }
211err:
212 return ret;
213}
214
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530215static int wcd9xxx_alloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx,
Joonwoo Parka7172112012-07-23 16:03:49 -0700216 u8 wcd9xxx_pgd_la)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800217{
218 int ret = 0;
Joonwoo Parka7172112012-07-23 16:03:49 -0700219 u8 ch_idx;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530220 struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800221 u16 slave_port_id = 0;
222
Swaminathan Sathappan362a17c2012-04-25 18:09:46 -0700223 pr_debug("%s: pgd_la[%d]\n", __func__, wcd9xxx_pgd_la);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800224 /* DSP requires channel number to be between 128 and 255. For RX port
225 * use channel numbers from 138 to 144, for TX port
226 * use channel numbers from 128 to 137
227 */
Joonwoo Parka7172112012-07-23 16:03:49 -0700228 for (ch_idx = 0; ch_idx < sh_ch.number_of_tx_slave_dev_ports;
229 ch_idx++) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800230 slave_port_id = ch_idx;
231 tx[ch_idx].ch_num = slave_port_id + BASE_CH_NUM;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530232 ret = slim_get_slaveport(wcd9xxx_pgd_la, slave_port_id,
Joonwoo Parka7172112012-07-23 16:03:49 -0700233 &tx[ch_idx].sph, SLIM_SRC);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800234 if (ret < 0) {
235 pr_err("%s: slave port failure id[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700236 __func__, slave_port_id, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800237 goto err;
238 }
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530239 ret = slim_query_ch(wcd9xxx->slim, tx[ch_idx].ch_num,
Joonwoo Parka7172112012-07-23 16:03:49 -0700240 &tx[ch_idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800241 if (ret < 0) {
242 pr_err("%s: slim_query_ch failed ch-num[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700243 __func__, tx[ch_idx].ch_num, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800244 goto err;
245 }
246 }
247err:
248 return ret;
249}
250
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530251static int wcd9xxx_dealloc_slim_sh_ch_rx(struct wcd9xxx *wcd9xxx)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800252{
253 int idx = 0;
254 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530255 struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800256 /* slim_dealloc_ch */
Joonwoo Parka7172112012-07-23 16:03:49 -0700257 for (idx = 0; idx < sh_ch.number_of_rx_slave_dev_ports; idx++) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530258 ret = slim_dealloc_ch(wcd9xxx->slim, rx[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800259 if (ret < 0) {
260 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
261 __func__, ret, rx[idx].ch_h);
262 }
263 }
264 memset(sh_ch.rx, 0, sizeof(sh_ch.rx));
265 return ret;
266}
267
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530268static int wcd9xxx_dealloc_slim_sh_ch_tx(struct wcd9xxx *wcd9xxx)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800269{
270 int idx = 0;
271 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530272 struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800273 /* slim_dealloc_ch */
Joonwoo Parka7172112012-07-23 16:03:49 -0700274 for (idx = 0; idx < sh_ch.number_of_tx_slave_dev_ports; idx++) {
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530275 ret = slim_dealloc_ch(wcd9xxx->slim, tx[idx].ch_h);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800276 if (ret < 0) {
277 pr_err("%s: slim_dealloc_ch fail ret[%d] ch_h[%d]\n",
278 __func__, ret, tx[idx].ch_h);
279 }
280 }
281 memset(sh_ch.tx, 0, sizeof(sh_ch.tx));
282 return ret;
283}
284
285/* Enable slimbus slave device for RX path */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530286int wcd9xxx_cfg_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
Joonwoo Parka7172112012-07-23 16:03:49 -0700287 unsigned int ch_cnt, unsigned int rate)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800288{
Joonwoo Parka7172112012-07-23 16:03:49 -0700289 u8 i;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800290 u16 grph;
291 u32 sph[SLIM_MAX_RX_PORTS] = {0};
292 u16 ch_h[SLIM_MAX_RX_PORTS] = {0};
293 u16 slave_port_id;
294 u8 payload_rx = 0, wm_payload = 0;
295 int ret, idx = 0;
296 unsigned short multi_chan_cfg_reg_addr;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530297 struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800298 struct slim_ch prop;
299
300 /* Configure slave interface device */
Swaminathan Sathappan362a17c2012-04-25 18:09:46 -0700301 pr_debug("%s: ch_cnt[%d] rate=%d\n", __func__, ch_cnt, rate);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800302
303 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700304 idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800305 ch_h[i] = rx[idx].ch_h;
306 sph[i] = rx[idx].sph;
Joonwoo Parka7172112012-07-23 16:03:49 -0700307 slave_port_id = idx;
308 pr_debug("%s: idx %d, ch_h %d, sph %d\n",
309 __func__, idx, ch_h[i], sph[i]);
310 if ((slave_port_id > sh_ch.num_rx_slave_port)) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800311 pr_err("Slimbus: invalid slave port id: %d",
Joonwoo Parka7172112012-07-23 16:03:49 -0700312 slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800313 ret = -EINVAL;
314 goto err;
315 }
Joonwoo Parka7172112012-07-23 16:03:49 -0700316 slave_port_id += sh_ch.rx_port_start_offset;
317 pr_debug("%s: slave_port_id %d\n", __func__, slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800318 /* look for the valid port range and chose the
319 * payload accordingly
320 */
Joonwoo Parka7172112012-07-23 16:03:49 -0700321 if ((slave_port_id > sh_ch.pgd_tx_port_ch_1_end_port_id) &&
322 (slave_port_id <= sh_ch.port_ch_0_end_port_id)) {
323 payload_rx = payload_rx |
324 (1 << (slave_port_id -
325 sh_ch.port_ch_0_start_port_id));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800326 } else {
327 ret = -EINVAL;
328 goto err;
329 }
Joonwoo Parka7172112012-07-23 16:03:49 -0700330
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800331 multi_chan_cfg_reg_addr =
Joonwoo Parka7172112012-07-23 16:03:49 -0700332 SB_PGD_RX_PORT_MULTI_CHANNEL_0(sh_ch.rx_port_ch_reg_base,
333 idx);
334 pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
335 multi_chan_cfg_reg_addr);
336
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800337 /* write to interface device */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530338 ret = wcd9xxx_interface_reg_write(wcd9xxx,
Joonwoo Parka7172112012-07-23 16:03:49 -0700339 multi_chan_cfg_reg_addr,
340 payload_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800341 if (ret < 0) {
342 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700343 __func__, multi_chan_cfg_reg_addr,
344 payload_rx, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800345 goto err;
346 }
347 /* configure the slave port for water mark and enable*/
348 wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
Joonwoo Parka7172112012-07-23 16:03:49 -0700349 SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
350 ret = wcd9xxx_interface_reg_write(
351 wcd9xxx,
352 SB_PGD_PORT_CFG_BYTE_ADDR(
353 sh_ch.port_rx_cfg_reg_base, idx),
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800354 wm_payload);
355 if (ret < 0) {
356 pr_err("%s:watermark set failure for port[%d] ret[%d]",
357 __func__, slave_port_id, ret);
358 }
359 }
360
361 /* slim_define_ch api */
362 prop.prot = SLIM_AUTO_ISO;
363 prop.baser = SLIM_RATE_4000HZ;
364 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
365 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
366 prop.ratem = (rate/4000);
367 prop.sampleszbits = 16;
368
Joonwoo Parka7172112012-07-23 16:03:49 -0700369 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800370 if (ret < 0) {
371 pr_err("%s: slim_define_ch failed ret[%d]\n",
372 __func__, ret);
373 goto err;
374 }
375 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700376 ret = slim_connect_sink(wcd9xxx->slim, &sph[i], 1, ch_h[i]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800377 if (ret < 0) {
378 pr_err("%s: slim_connect_sink failed ret[%d]\n",
379 __func__, ret);
380 goto err_close_slim_sch;
381 }
382 }
383 /* slim_control_ch */
Joonwoo Parka7172112012-07-23 16:03:49 -0700384 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800385 if (ret < 0) {
386 pr_err("%s: slim_control_ch failed ret[%d]\n",
387 __func__, ret);
388 goto err_close_slim_sch;
389 }
390 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700391 idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800392 rx[idx].grph = grph;
393 }
394 return 0;
395
396err_close_slim_sch:
397 /* release all acquired handles */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530398 wcd9xxx_close_slim_sch_rx(wcd9xxx, ch_num, ch_cnt);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800399err:
400 return ret;
401}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530402EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800403
404/* Enable slimbus slave device for RX path */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530405int wcd9xxx_cfg_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
Joonwoo Parka7172112012-07-23 16:03:49 -0700406 unsigned int ch_cnt, unsigned int rate)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800407{
408 u8 i = 0;
409 u8 payload_tx_0 = 0, payload_tx_1 = 0, wm_payload = 0;
410 u16 grph;
411 u32 sph[SLIM_MAX_TX_PORTS] = {0};
412 u16 ch_h[SLIM_MAX_TX_PORTS] = {0};
413 u16 idx = 0, slave_port_id;
414 int ret = 0;
Joonwoo Parka7172112012-07-23 16:03:49 -0700415 unsigned short multi_chan_cfg_reg_addr;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800416
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530417 struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800418 struct slim_ch prop;
419
420 pr_debug("%s: ch_cnt[%d] rate[%d]\n", __func__, ch_cnt, rate);
421 for (i = 0; i < ch_cnt; i++) {
422 idx = (ch_num[i] - BASE_CH_NUM);
423 ch_h[i] = tx[idx].ch_h;
424 sph[i] = tx[idx].sph;
Joonwoo Parka7172112012-07-23 16:03:49 -0700425 slave_port_id = idx;
426 pr_debug("%s: idx %d, ch_h %d, sph %d, slave_port_id %d\n",
427 __func__, idx, ch_h[i], sph[i], slave_port_id);
428 if (slave_port_id > sh_ch.number_of_tx_slave_dev_ports) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800429 pr_err("SLIMbus: invalid slave port id: %d",
Joonwoo Parka7172112012-07-23 16:03:49 -0700430 slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800431 ret = -EINVAL;
432 goto err;
433 }
434 /* look for the valid port range and chose the
435 * payload accordingly
436 */
437 if (slave_port_id <=
Joonwoo Parka7172112012-07-23 16:03:49 -0700438 SB_PGD_TX_PORT_MULTI_CHANNEL_0_END_PORT_ID) {
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800439 payload_tx_0 = payload_tx_0 | (1 << slave_port_id);
Kiran Kandi1e6371d2012-03-29 11:48:57 -0700440 } else if (slave_port_id <=
Joonwoo Parka7172112012-07-23 16:03:49 -0700441 sh_ch.pgd_tx_port_ch_1_end_port_id) {
442 payload_tx_1 = payload_tx_1 |
443 (1 << (slave_port_id -
444 SB_PGD_TX_PORT_MULTI_CHANNEL_1_START_PORT_ID));
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800445 } else {
Joonwoo Parka7172112012-07-23 16:03:49 -0700446 pr_err("%s: slave port id %d error\n", __func__,
447 slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800448 ret = -EINVAL;
449 goto err;
450 }
451 multi_chan_cfg_reg_addr =
Joonwoo Parka7172112012-07-23 16:03:49 -0700452 SB_PGD_TX_PORT_MULTI_CHANNEL_0(slave_port_id);
453 pr_debug("%s: multi_chan_cfg_reg_addr 0x%x\n", __func__,
454 multi_chan_cfg_reg_addr);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800455 /* write to interface device */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530456 ret = wcd9xxx_interface_reg_write(wcd9xxx,
457 multi_chan_cfg_reg_addr,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800458 payload_tx_0);
459 if (ret < 0) {
460 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700461 __func__, multi_chan_cfg_reg_addr, payload_tx_0,
462 ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800463 goto err;
464 }
465 multi_chan_cfg_reg_addr =
Joonwoo Parka7172112012-07-23 16:03:49 -0700466 SB_PGD_TX_PORT_MULTI_CHANNEL_1(slave_port_id);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800467 /* ports 8,9 */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530468 ret = wcd9xxx_interface_reg_write(wcd9xxx,
Joonwoo Parka7172112012-07-23 16:03:49 -0700469 multi_chan_cfg_reg_addr,
470 payload_tx_1);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800471 if (ret < 0) {
472 pr_err("%s:Intf-dev fail reg[%d] payload[%d] ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700473 __func__, multi_chan_cfg_reg_addr,
474 payload_tx_1, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800475 goto err;
476 }
477 /* configure the slave port for water mark and enable*/
478 wm_payload = (SLAVE_PORT_WATER_MARK_VALUE <<
Joonwoo Parka7172112012-07-23 16:03:49 -0700479 SLAVE_PORT_WATER_MARK_SHIFT) + SLAVE_PORT_ENABLE;
480 pr_debug("%s: tx_cfg_reg 0x%x wm 0x%x\n", __func__,
481 SB_PGD_PORT_CFG_BYTE_ADDR(sh_ch.port_tx_cfg_reg_base,
482 slave_port_id), wm_payload);
483 ret = wcd9xxx_interface_reg_write(
484 wcd9xxx,
485 SB_PGD_PORT_CFG_BYTE_ADDR(
486 sh_ch.port_tx_cfg_reg_base,
487 slave_port_id),
488 wm_payload);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800489 if (ret < 0) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700490 pr_err("%s: watermark set failure for port[%d] ret[%d]",
491 __func__, slave_port_id, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800492 }
493 }
494
495 /* slim_define_ch api */
496 prop.prot = SLIM_AUTO_ISO;
497 prop.baser = SLIM_RATE_4000HZ;
498 prop.dataf = SLIM_CH_DATAF_NOT_DEFINED;
499 prop.auxf = SLIM_CH_AUXF_NOT_APPLICABLE;
500 prop.ratem = (rate/4000);
501 prop.sampleszbits = 16;
Joonwoo Parka7172112012-07-23 16:03:49 -0700502 ret = slim_define_ch(wcd9xxx->slim, &prop, ch_h, ch_cnt, true, &grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800503 if (ret < 0) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700504 pr_err("%s: slim_define_ch failed ret[%d]\n", __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800505 goto err;
506 }
507 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700508 ret = slim_connect_src(wcd9xxx->slim, sph[i], ch_h[i]);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800509 if (ret < 0) {
510 pr_err("%s: slim_connect_src failed ret[%d]\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700511 __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800512 goto err;
513 }
514 }
515 /* slim_control_ch */
Joonwoo Parka7172112012-07-23 16:03:49 -0700516 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_ACTIVATE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800517 if (ret < 0) {
518 pr_err("%s: slim_control_ch failed ret[%d]\n",
519 __func__, ret);
520 goto err;
521 }
522 for (i = 0; i < ch_cnt; i++) {
523 idx = (ch_num[i] - BASE_CH_NUM);
524 tx[idx].grph = grph;
525 }
526 return 0;
527err:
528 /* release all acquired handles */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530529 wcd9xxx_close_slim_sch_tx(wcd9xxx, ch_num, ch_cnt);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800530 return ret;
531}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530532EXPORT_SYMBOL_GPL(wcd9xxx_cfg_slim_sch_tx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800533
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530534int wcd9xxx_close_slim_sch_rx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800535 unsigned int ch_cnt)
536{
537 u16 grph = 0;
538 u32 sph[SLIM_MAX_RX_PORTS] = {0};
539 int i = 0 , idx = 0;
540 int ret = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530541 struct wcd9xxx_slim_sch_rx *rx = sh_ch.rx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800542
Swaminathan Sathappan362a17c2012-04-25 18:09:46 -0700543 pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800544 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700545 idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
Kiran Kandie408b842012-05-17 19:48:04 -0700546 if (idx < 0) {
547 pr_err("%s: Error:-Invalid index found = %d\n",
Joonwoo Parka7172112012-07-23 16:03:49 -0700548 __func__, idx);
Kiran Kandie408b842012-05-17 19:48:04 -0700549 ret = -EINVAL;
550 goto err;
551 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800552 sph[i] = rx[idx].sph;
553 grph = rx[idx].grph;
Joonwoo Parka7172112012-07-23 16:03:49 -0700554 pr_debug("%s: ch_num[%d] %d, idx %d, sph[%d] %x, grph %x\n",
555 __func__, i, ch_num[i], idx, i, sph[i], grph);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800556 }
557
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800558 /* slim_control_ch (REMOVE) */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530559 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800560 if (ret < 0) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700561 pr_err("%s: slim_control_ch failed ret[%d]\n", __func__, ret);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800562 goto err;
563 }
Swaminathan Sathappancb89d7d2012-08-01 13:20:20 -0700564 /* slim_disconnect_port */
565 ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
566 if (ret < 0) {
567 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
568 __func__, ret);
569 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800570 for (i = 0; i < ch_cnt; i++) {
Joonwoo Parka7172112012-07-23 16:03:49 -0700571 idx = (ch_num[i] - BASE_CH_NUM - sh_ch.rx_port_start_offset);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800572 rx[idx].grph = 0;
573 }
574err:
575 return ret;
576}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530577EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_rx);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800578
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530579int wcd9xxx_close_slim_sch_tx(struct wcd9xxx *wcd9xxx, unsigned int *ch_num,
Joonwoo Parka7172112012-07-23 16:03:49 -0700580 unsigned int ch_cnt)
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800581{
582 u16 grph = 0;
583 u32 sph[SLIM_MAX_TX_PORTS] = {0};
584 int ret = 0;
585 int i = 0 , idx = 0;
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530586 struct wcd9xxx_slim_sch_tx *tx = sh_ch.tx;
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800587
Swaminathan Sathappan362a17c2012-04-25 18:09:46 -0700588 pr_debug("%s: ch_cnt[%d]\n", __func__, ch_cnt);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800589 for (i = 0; i < ch_cnt; i++) {
590 idx = (ch_num[i] - BASE_CH_NUM);
Kiran Kandie408b842012-05-17 19:48:04 -0700591 if (idx < 0) {
592 pr_err("%s: Error:- Invalid index found = %d\n",
593 __func__, idx);
594 ret = -EINVAL;
595 goto err;
596 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800597 sph[i] = tx[idx].sph;
598 grph = tx[idx].grph;
599 }
Jay Wanga19be7b2012-06-15 18:29:33 -0700600 /* slim_disconnect_port */
601 ret = slim_disconnect_ports(wcd9xxx->slim, sph, ch_cnt);
602 if (ret < 0) {
603 pr_err("%s: slim_disconnect_ports failed ret[%d]\n",
604 __func__, ret);
605 }
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800606 /* slim_control_ch (REMOVE) */
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530607 ret = slim_control_ch(wcd9xxx->slim, grph, SLIM_CH_REMOVE, true);
Bharath Ramachandramurthy9c79f132011-11-28 11:18:57 -0800608 if (ret < 0) {
609 pr_err("%s: slim_control_ch failed ret[%d]\n",
610 __func__, ret);
611 goto err;
612 }
613 for (i = 0; i < ch_cnt; i++) {
614 idx = (ch_num[i] - BASE_CH_NUM);
615 tx[idx].grph = 0;
616 }
617err:
618 return ret;
619}
Asish Bhattacharyab1aeae22012-02-15 08:29:28 +0530620EXPORT_SYMBOL_GPL(wcd9xxx_close_slim_sch_tx);
Swaminathan Sathappan2aa4c042012-06-26 13:08:45 -0700621
622int wcd9xxx_get_slave_port(unsigned int ch_num)
623{
624 int ret = 0;
625
626 pr_debug("%s: ch_num[%d]\n", __func__, ch_num);
627 ret = (ch_num - BASE_CH_NUM);
628 if (ret < 0) {
629 pr_err("%s: Error:- Invalid slave port found = %d\n",
630 __func__, ret);
631 return -EINVAL;
632 }
633 return ret;
634}
635EXPORT_SYMBOL_GPL(wcd9xxx_get_slave_port);