blob: 78174afb9b4778ab90119e601e5531cd3d335531 [file] [log] [blame]
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301/*
2 * Copyright (c) 2012-2014, 2016-2017, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/err.h>
15#include <linux/module.h>
16#include <linux/bitops.h>
17#include <linux/mutex.h>
18#include <linux/atomic.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053019#include <sound/asound.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053020#include <sound/control.h>
21#include <asoc/msm-dts-srs-tm-config.h>
22#include <dsp/msm_audio_ion.h>
23#include <dsp/q6adm-v2.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053024#include "msm-pcm-routing-v2.h"
25
26static int srs_port_id[AFE_MAX_PORTS] = {-1};
27static int srs_copp_idx[AFE_MAX_PORTS] = {-1};
28static union srs_trumedia_params_u msm_srs_trumedia_params;
29static struct ion_client *ion_client;
30static struct ion_handle *ion_handle;
31static struct param_outband po;
32static atomic_t ref_cnt;
33#define ION_MEM_SIZE (8 * 1024)
34
35static int set_port_id(int port_id, int copp_idx)
36{
37 int index = adm_validate_and_get_port_index(port_id);
38
39 if (index < 0) {
40 pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
41 port_id);
42 return -EINVAL;
43 }
44 srs_port_id[index] = port_id;
45 srs_copp_idx[index] = copp_idx;
46 return 0;
47}
48
49static void msm_dts_srs_tm_send_params(__s32 port_id, __u32 techs)
50{
51 __s32 index = adm_validate_and_get_port_index(port_id);
52
53 if (index < 0) {
54 pr_err("%s: Invalid port idx %d port_id 0x%x\n",
55 __func__, index, port_id);
56 return;
57 }
58 if ((srs_copp_idx[index] < 0) ||
59 (srs_copp_idx[index] >= MAX_COPPS_PER_PORT)) {
60 pr_debug("%s: send params called before copp open. so, caching\n",
61 __func__);
62 return;
63 }
64 pr_debug("SRS %s: called, port_id = %d, techs flags = %u\n",
65 __func__, port_id, techs);
66 /* force all if techs is set to 1 */
67 if (techs == 1)
68 techs = 0xFFFFFFFF;
69
70 if (techs & (1 << SRS_ID_WOWHD))
71 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_WOWHD,
72 (void *)&msm_srs_trumedia_params.srs_params.wowhd);
73 if (techs & (1 << SRS_ID_CSHP))
74 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_CSHP,
75 (void *)&msm_srs_trumedia_params.srs_params.cshp);
76 if (techs & (1 << SRS_ID_HPF))
77 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HPF,
78 (void *)&msm_srs_trumedia_params.srs_params.hpf);
79 if (techs & (1 << SRS_ID_AEQ))
80 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_AEQ,
81 (void *)&msm_srs_trumedia_params.srs_params.aeq);
82 if (techs & (1 << SRS_ID_HL))
83 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HL,
84 (void *)&msm_srs_trumedia_params.srs_params.hl);
85 if (techs & (1 << SRS_ID_GEQ))
86 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GEQ,
87 (void *)&msm_srs_trumedia_params.srs_params.geq);
88 if (techs & (1 << SRS_ID_GLOBAL))
89 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GLOBAL,
90 (void *)&msm_srs_trumedia_params.srs_params.global);
91}
92
93
94static int msm_dts_srs_trumedia_control_get(struct snd_kcontrol *kcontrol,
95 struct snd_ctl_elem_value *ucontrol)
96{
97 ucontrol->value.integer.value[0] = 0;
98 return 0;
99}
100
101static int msm_dts_srs_trumedia_control_set_(int port_id,
102 struct snd_kcontrol *kcontrol,
103 struct snd_ctl_elem_value *ucontrol)
104{
105
106 __u16 offset, value, max = sizeof(msm_srs_trumedia_params) >> 1;
107
108 if (SRS_CMD_UPLOAD ==
109 (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
110 __u32 techs = ucontrol->value.integer.value[0] & 0xFF;
111 __s32 index = adm_validate_and_get_port_index(port_id);
112
113 if (index < 0) {
114 pr_err("%s: Invalid port idx %d port_id 0x%x\n",
115 __func__, index, port_id);
116 return -EINVAL;
117 }
118 pr_debug("SRS %s: send params request, flag = %u\n",
119 __func__, techs);
120 if (srs_port_id[index] >= 0 && techs)
121 msm_dts_srs_tm_send_params(port_id, techs);
122 return 0;
123 }
124 offset = (__u16)((ucontrol->value.integer.value[0] &
125 SRS_PARAM_OFFSET_MASK) >> 16);
126 value = (__u16)(ucontrol->value.integer.value[0] &
127 SRS_PARAM_VALUE_MASK);
128 if (offset < max) {
129 msm_srs_trumedia_params.raw_params[offset] = value;
130 pr_debug("SRS %s: index set... (max %d, requested %d, value 0x%X)\n",
131 __func__, max, offset, value);
132 } else {
133 pr_err("SRS %s: index out of bounds! (max %d, requested %d)\n",
134 __func__, max, offset);
135 }
136 return 0;
137}
138
139static int msm_dts_srs_trumedia_control_set(struct snd_kcontrol *kcontrol,
140 struct snd_ctl_elem_value *ucontrol)
141{
142 int ret, port_id;
143
144 pr_debug("SRS control normal called\n");
145 msm_pcm_routing_acquire_lock();
146 port_id = SLIMBUS_0_RX;
147 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
148 msm_pcm_routing_release_lock();
149 return ret;
150}
151
152static int msm_dts_srs_trumedia_control_i2s_set(struct snd_kcontrol *kcontrol,
153 struct snd_ctl_elem_value *ucontrol)
154{
155 int ret, port_id;
156
157 pr_debug("SRS control I2S called\n");
158 msm_pcm_routing_acquire_lock();
159 port_id = PRIMARY_I2S_RX;
160 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
161 msm_pcm_routing_release_lock();
162 return ret;
163}
164
165static int msm_dts_srs_trumedia_control_mi2s_set(struct snd_kcontrol *kcontrol,
166 struct snd_ctl_elem_value *ucontrol)
167{
168 int ret, port_id;
169
170 pr_debug("SRS control MI2S called\n");
171 msm_pcm_routing_acquire_lock();
172 port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
173 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
174 msm_pcm_routing_release_lock();
175 return ret;
176}
177
178static int msm_dts_srs_trumedia_control_hdmi_set(struct snd_kcontrol *kcontrol,
179 struct snd_ctl_elem_value *ucontrol)
180{
181 int ret, port_id;
182
183 pr_debug("SRS control HDMI called\n");
184 msm_pcm_routing_acquire_lock();
185 port_id = HDMI_RX;
186 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
187 msm_pcm_routing_release_lock();
188 return ret;
189}
190
191static const struct snd_kcontrol_new lpa_srs_trumedia_controls[] = {
192 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
193 .name = "SRS TruMedia",
194 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
195 SNDRV_CTL_ELEM_ACCESS_READWRITE,
196 .info = snd_soc_info_volsw,
197 .get = msm_dts_srs_trumedia_control_get,
198 .put = msm_dts_srs_trumedia_control_set,
199 .private_value = ((unsigned long)&(struct soc_mixer_control)
200 {.reg = SND_SOC_NOPM,
201 .rreg = SND_SOC_NOPM,
202 .shift = 0,
203 .rshift = 0,
204 .max = 0xFFFFFFFF,
205 .platform_max = 0xFFFFFFFF,
206 .invert = 0
207 })
208 }
209};
210
211static const struct snd_kcontrol_new lpa_srs_trumedia_controls_hdmi[] = {
212 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
213 .name = "SRS TruMedia HDMI",
214 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
215 SNDRV_CTL_ELEM_ACCESS_READWRITE,
216 .info = snd_soc_info_volsw,
217 .get = msm_dts_srs_trumedia_control_get,
218 .put = msm_dts_srs_trumedia_control_hdmi_set,
219 .private_value = ((unsigned long)&(struct soc_mixer_control)
220 {.reg = SND_SOC_NOPM,
221 .rreg = SND_SOC_NOPM,
222 .shift = 0,
223 .rshift = 0,
224 .max = 0xFFFFFFFF,
225 .platform_max = 0xFFFFFFFF,
226 .invert = 0
227 })
228 }
229};
230
231static const struct snd_kcontrol_new lpa_srs_trumedia_controls_i2s[] = {
232 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
233 .name = "SRS TruMedia I2S",
234 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
235 SNDRV_CTL_ELEM_ACCESS_READWRITE,
236 .info = snd_soc_info_volsw,
237 .get = msm_dts_srs_trumedia_control_get,
238 .put = msm_dts_srs_trumedia_control_i2s_set,
239 .private_value = ((unsigned long)&(struct soc_mixer_control)
240 {.reg = SND_SOC_NOPM,
241 .rreg = SND_SOC_NOPM,
242 .shift = 0,
243 .rshift = 0,
244 .max = 0xFFFFFFFF,
245 .platform_max = 0xFFFFFFFF,
246 .invert = 0
247 })
248 }
249};
250
251static const struct snd_kcontrol_new lpa_srs_trumedia_controls_mi2s[] = {
252 {
253 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
254 .name = "SRS TruMedia MI2S",
255 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
256 SNDRV_CTL_ELEM_ACCESS_READWRITE,
257 .info = snd_soc_info_volsw,
258 .get = msm_dts_srs_trumedia_control_get,
259 .put = msm_dts_srs_trumedia_control_mi2s_set,
260 .private_value = ((unsigned long)&(struct soc_mixer_control)
261 {
262 .reg = SND_SOC_NOPM,
263 .rreg = SND_SOC_NOPM,
264 .shift = 0,
265 .rshift = 0,
266 .max = 0xFFFFFFFF,
267 .platform_max = 0xFFFFFFFF,
268 .invert = 0
269 })
270 }
271};
272
273void msm_dts_srs_tm_add_controls(struct snd_soc_platform *platform)
274{
275 snd_soc_add_platform_controls(platform,
276 lpa_srs_trumedia_controls,
277 ARRAY_SIZE(lpa_srs_trumedia_controls));
278
279 snd_soc_add_platform_controls(platform,
280 lpa_srs_trumedia_controls_hdmi,
281 ARRAY_SIZE(lpa_srs_trumedia_controls_hdmi));
282
283 snd_soc_add_platform_controls(platform,
284 lpa_srs_trumedia_controls_i2s,
285 ARRAY_SIZE(lpa_srs_trumedia_controls_i2s));
286 snd_soc_add_platform_controls(platform,
287 lpa_srs_trumedia_controls_mi2s,
288 ARRAY_SIZE(lpa_srs_trumedia_controls_mi2s));
289}
290
291static int reg_ion_mem(void)
292{
293 int rc;
294
295 rc = msm_audio_ion_alloc("SRS_TRUMEDIA", &ion_client, &ion_handle,
296 ION_MEM_SIZE, &po.paddr, (size_t *)&po.size,
297 &po.kvaddr);
298 if (rc != 0)
299 pr_err("%s: failed to allocate memory.\n", __func__);
300 pr_debug("%s: exited ion_client = %pK, ion_handle = %pK, phys_addr = %lu, length = %d, vaddr = %pK, rc = 0x%x\n",
301 __func__, ion_client, ion_handle, (long)po.paddr,
302 (unsigned int)po.size, po.kvaddr, rc);
303 return rc;
304}
305
306void msm_dts_srs_tm_ion_memmap(struct param_outband *po_)
307{
308 if (po.kvaddr == NULL) {
309 pr_debug("%s: callingreg_ion_mem()\n", __func__);
310 reg_ion_mem();
311 }
312 po_->size = ION_MEM_SIZE;
313 po_->kvaddr = po.kvaddr;
314 po_->paddr = po.paddr;
315}
316
317static void unreg_ion_mem(void)
318{
319 msm_audio_ion_free(ion_client, ion_handle);
320 po.kvaddr = NULL;
321 po.paddr = 0;
322 po.size = 0;
323}
324
325void msm_dts_srs_tm_deinit(int port_id)
326{
327 set_port_id(port_id, -1);
328 atomic_dec(&ref_cnt);
329 if (po.kvaddr != NULL) {
330 if (!atomic_read(&ref_cnt)) {
331 pr_debug("%s: calling unreg_ion_mem()\n", __func__);
332 unreg_ion_mem();
333 }
334 }
335}
336
337void msm_dts_srs_tm_init(int port_id, int copp_idx)
338{
339 int cur_ref_cnt = 0;
340
341 if (set_port_id(port_id, copp_idx) < 0) {
342 pr_err("%s: Invalid port_id: %d\n", __func__, port_id);
343 return;
344 }
345
346 cur_ref_cnt = atomic_read(&ref_cnt);
347 atomic_inc(&ref_cnt);
348 if (!cur_ref_cnt && po.kvaddr == NULL) {
349 pr_debug("%s: calling reg_ion_mem()\n", __func__);
350 if (reg_ion_mem() != 0) {
351 atomic_dec(&ref_cnt);
352 po.kvaddr = NULL;
353 return;
354 }
355 }
356 msm_dts_srs_tm_send_params(port_id, 1);
357}