blob: cd3da4d642d998da935e66d312710b88a2160576 [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>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053021#include <dsp/msm_audio_ion.h>
22#include <dsp/q6adm-v2.h>
Laxminath Kasam8b1366a2017-10-05 01:44:16 +053023#include <dsp/msm-dts-srs-tm-config.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053024
25static int srs_port_id[AFE_MAX_PORTS] = {-1};
26static int srs_copp_idx[AFE_MAX_PORTS] = {-1};
27static union srs_trumedia_params_u msm_srs_trumedia_params;
28static struct ion_client *ion_client;
29static struct ion_handle *ion_handle;
30static struct param_outband po;
31static atomic_t ref_cnt;
32#define ION_MEM_SIZE (8 * 1024)
33
34static int set_port_id(int port_id, int copp_idx)
35{
36 int index = adm_validate_and_get_port_index(port_id);
37
38 if (index < 0) {
39 pr_err("%s: Invalid port idx %d port_id %#x\n", __func__, index,
40 port_id);
41 return -EINVAL;
42 }
43 srs_port_id[index] = port_id;
44 srs_copp_idx[index] = copp_idx;
45 return 0;
46}
47
48static void msm_dts_srs_tm_send_params(__s32 port_id, __u32 techs)
49{
50 __s32 index = adm_validate_and_get_port_index(port_id);
51
52 if (index < 0) {
53 pr_err("%s: Invalid port idx %d port_id 0x%x\n",
54 __func__, index, port_id);
55 return;
56 }
57 if ((srs_copp_idx[index] < 0) ||
58 (srs_copp_idx[index] >= MAX_COPPS_PER_PORT)) {
59 pr_debug("%s: send params called before copp open. so, caching\n",
60 __func__);
61 return;
62 }
63 pr_debug("SRS %s: called, port_id = %d, techs flags = %u\n",
64 __func__, port_id, techs);
65 /* force all if techs is set to 1 */
66 if (techs == 1)
67 techs = 0xFFFFFFFF;
68
69 if (techs & (1 << SRS_ID_WOWHD))
70 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_WOWHD,
71 (void *)&msm_srs_trumedia_params.srs_params.wowhd);
72 if (techs & (1 << SRS_ID_CSHP))
73 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_CSHP,
74 (void *)&msm_srs_trumedia_params.srs_params.cshp);
75 if (techs & (1 << SRS_ID_HPF))
76 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HPF,
77 (void *)&msm_srs_trumedia_params.srs_params.hpf);
78 if (techs & (1 << SRS_ID_AEQ))
79 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_AEQ,
80 (void *)&msm_srs_trumedia_params.srs_params.aeq);
81 if (techs & (1 << SRS_ID_HL))
82 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_HL,
83 (void *)&msm_srs_trumedia_params.srs_params.hl);
84 if (techs & (1 << SRS_ID_GEQ))
85 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GEQ,
86 (void *)&msm_srs_trumedia_params.srs_params.geq);
87 if (techs & (1 << SRS_ID_GLOBAL))
88 srs_trumedia_open(port_id, srs_copp_idx[index], SRS_ID_GLOBAL,
89 (void *)&msm_srs_trumedia_params.srs_params.global);
90}
91
92
93static int msm_dts_srs_trumedia_control_get(struct snd_kcontrol *kcontrol,
94 struct snd_ctl_elem_value *ucontrol)
95{
96 ucontrol->value.integer.value[0] = 0;
97 return 0;
98}
99
100static int msm_dts_srs_trumedia_control_set_(int port_id,
101 struct snd_kcontrol *kcontrol,
102 struct snd_ctl_elem_value *ucontrol)
103{
104
105 __u16 offset, value, max = sizeof(msm_srs_trumedia_params) >> 1;
106
107 if (SRS_CMD_UPLOAD ==
108 (ucontrol->value.integer.value[0] & SRS_CMD_UPLOAD)) {
109 __u32 techs = ucontrol->value.integer.value[0] & 0xFF;
110 __s32 index = adm_validate_and_get_port_index(port_id);
111
112 if (index < 0) {
113 pr_err("%s: Invalid port idx %d port_id 0x%x\n",
114 __func__, index, port_id);
115 return -EINVAL;
116 }
117 pr_debug("SRS %s: send params request, flag = %u\n",
118 __func__, techs);
119 if (srs_port_id[index] >= 0 && techs)
120 msm_dts_srs_tm_send_params(port_id, techs);
121 return 0;
122 }
123 offset = (__u16)((ucontrol->value.integer.value[0] &
124 SRS_PARAM_OFFSET_MASK) >> 16);
125 value = (__u16)(ucontrol->value.integer.value[0] &
126 SRS_PARAM_VALUE_MASK);
127 if (offset < max) {
128 msm_srs_trumedia_params.raw_params[offset] = value;
129 pr_debug("SRS %s: index set... (max %d, requested %d, value 0x%X)\n",
130 __func__, max, offset, value);
131 } else {
132 pr_err("SRS %s: index out of bounds! (max %d, requested %d)\n",
133 __func__, max, offset);
134 }
135 return 0;
136}
137
138static int msm_dts_srs_trumedia_control_set(struct snd_kcontrol *kcontrol,
139 struct snd_ctl_elem_value *ucontrol)
140{
141 int ret, port_id;
142
143 pr_debug("SRS control normal called\n");
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530144 msm_dts_srs_acquire_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530145 port_id = SLIMBUS_0_RX;
146 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530147 msm_dts_srs_release_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530148 return ret;
149}
150
151static int msm_dts_srs_trumedia_control_i2s_set(struct snd_kcontrol *kcontrol,
152 struct snd_ctl_elem_value *ucontrol)
153{
154 int ret, port_id;
155
156 pr_debug("SRS control I2S called\n");
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530157 msm_dts_srs_acquire_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530158 port_id = PRIMARY_I2S_RX;
159 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530160 msm_dts_srs_release_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530161 return ret;
162}
163
164static int msm_dts_srs_trumedia_control_mi2s_set(struct snd_kcontrol *kcontrol,
165 struct snd_ctl_elem_value *ucontrol)
166{
167 int ret, port_id;
168
169 pr_debug("SRS control MI2S called\n");
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530170 msm_dts_srs_acquire_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530171 port_id = AFE_PORT_ID_PRIMARY_MI2S_RX;
172 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530173 msm_dts_srs_release_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530174 return ret;
175}
176
177static int msm_dts_srs_trumedia_control_hdmi_set(struct snd_kcontrol *kcontrol,
178 struct snd_ctl_elem_value *ucontrol)
179{
180 int ret, port_id;
181
182 pr_debug("SRS control HDMI called\n");
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530183 msm_dts_srs_acquire_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530184 port_id = HDMI_RX;
185 ret = msm_dts_srs_trumedia_control_set_(port_id, kcontrol, ucontrol);
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530186 msm_dts_srs_release_lock();
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530187 return ret;
188}
189
190static const struct snd_kcontrol_new lpa_srs_trumedia_controls[] = {
191 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
192 .name = "SRS TruMedia",
193 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
194 SNDRV_CTL_ELEM_ACCESS_READWRITE,
195 .info = snd_soc_info_volsw,
196 .get = msm_dts_srs_trumedia_control_get,
197 .put = msm_dts_srs_trumedia_control_set,
198 .private_value = ((unsigned long)&(struct soc_mixer_control)
199 {.reg = SND_SOC_NOPM,
200 .rreg = SND_SOC_NOPM,
201 .shift = 0,
202 .rshift = 0,
203 .max = 0xFFFFFFFF,
204 .platform_max = 0xFFFFFFFF,
205 .invert = 0
206 })
207 }
208};
209
210static const struct snd_kcontrol_new lpa_srs_trumedia_controls_hdmi[] = {
211 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
212 .name = "SRS TruMedia HDMI",
213 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
214 SNDRV_CTL_ELEM_ACCESS_READWRITE,
215 .info = snd_soc_info_volsw,
216 .get = msm_dts_srs_trumedia_control_get,
217 .put = msm_dts_srs_trumedia_control_hdmi_set,
218 .private_value = ((unsigned long)&(struct soc_mixer_control)
219 {.reg = SND_SOC_NOPM,
220 .rreg = SND_SOC_NOPM,
221 .shift = 0,
222 .rshift = 0,
223 .max = 0xFFFFFFFF,
224 .platform_max = 0xFFFFFFFF,
225 .invert = 0
226 })
227 }
228};
229
230static const struct snd_kcontrol_new lpa_srs_trumedia_controls_i2s[] = {
231 {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
232 .name = "SRS TruMedia I2S",
233 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
234 SNDRV_CTL_ELEM_ACCESS_READWRITE,
235 .info = snd_soc_info_volsw,
236 .get = msm_dts_srs_trumedia_control_get,
237 .put = msm_dts_srs_trumedia_control_i2s_set,
238 .private_value = ((unsigned long)&(struct soc_mixer_control)
239 {.reg = SND_SOC_NOPM,
240 .rreg = SND_SOC_NOPM,
241 .shift = 0,
242 .rshift = 0,
243 .max = 0xFFFFFFFF,
244 .platform_max = 0xFFFFFFFF,
245 .invert = 0
246 })
247 }
248};
249
250static const struct snd_kcontrol_new lpa_srs_trumedia_controls_mi2s[] = {
251 {
252 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
253 .name = "SRS TruMedia MI2S",
254 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
255 SNDRV_CTL_ELEM_ACCESS_READWRITE,
256 .info = snd_soc_info_volsw,
257 .get = msm_dts_srs_trumedia_control_get,
258 .put = msm_dts_srs_trumedia_control_mi2s_set,
259 .private_value = ((unsigned long)&(struct soc_mixer_control)
260 {
261 .reg = SND_SOC_NOPM,
262 .rreg = SND_SOC_NOPM,
263 .shift = 0,
264 .rshift = 0,
265 .max = 0xFFFFFFFF,
266 .platform_max = 0xFFFFFFFF,
267 .invert = 0
268 })
269 }
270};
271
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530272/**
273 * msm_dts_srs_tm_add_controls -
274 * Add DTS SRS module controls
275 *
276 * @platform: component to which controls can be registered
277 *
278 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530279void msm_dts_srs_tm_add_controls(struct snd_soc_platform *platform)
280{
281 snd_soc_add_platform_controls(platform,
282 lpa_srs_trumedia_controls,
283 ARRAY_SIZE(lpa_srs_trumedia_controls));
284
285 snd_soc_add_platform_controls(platform,
286 lpa_srs_trumedia_controls_hdmi,
287 ARRAY_SIZE(lpa_srs_trumedia_controls_hdmi));
288
289 snd_soc_add_platform_controls(platform,
290 lpa_srs_trumedia_controls_i2s,
291 ARRAY_SIZE(lpa_srs_trumedia_controls_i2s));
292 snd_soc_add_platform_controls(platform,
293 lpa_srs_trumedia_controls_mi2s,
294 ARRAY_SIZE(lpa_srs_trumedia_controls_mi2s));
295}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530296EXPORT_SYMBOL(msm_dts_srs_tm_add_controls);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530297
298static int reg_ion_mem(void)
299{
300 int rc;
301
302 rc = msm_audio_ion_alloc("SRS_TRUMEDIA", &ion_client, &ion_handle,
303 ION_MEM_SIZE, &po.paddr, (size_t *)&po.size,
304 &po.kvaddr);
305 if (rc != 0)
306 pr_err("%s: failed to allocate memory.\n", __func__);
307 pr_debug("%s: exited ion_client = %pK, ion_handle = %pK, phys_addr = %lu, length = %d, vaddr = %pK, rc = 0x%x\n",
308 __func__, ion_client, ion_handle, (long)po.paddr,
309 (unsigned int)po.size, po.kvaddr, rc);
310 return rc;
311}
312
313void msm_dts_srs_tm_ion_memmap(struct param_outband *po_)
314{
315 if (po.kvaddr == NULL) {
316 pr_debug("%s: callingreg_ion_mem()\n", __func__);
317 reg_ion_mem();
318 }
319 po_->size = ION_MEM_SIZE;
320 po_->kvaddr = po.kvaddr;
321 po_->paddr = po.paddr;
322}
323
324static void unreg_ion_mem(void)
325{
326 msm_audio_ion_free(ion_client, ion_handle);
327 po.kvaddr = NULL;
328 po.paddr = 0;
329 po.size = 0;
330}
331
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530332/**
333 * msm_dts_srs_tm_deinit -
334 * De-Initializes DTS SRS module
335 *
336 * @port_id: Port ID number
337 *
338 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530339void msm_dts_srs_tm_deinit(int port_id)
340{
341 set_port_id(port_id, -1);
342 atomic_dec(&ref_cnt);
343 if (po.kvaddr != NULL) {
344 if (!atomic_read(&ref_cnt)) {
345 pr_debug("%s: calling unreg_ion_mem()\n", __func__);
346 unreg_ion_mem();
347 }
348 }
349}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530350EXPORT_SYMBOL(msm_dts_srs_tm_deinit);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530351
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530352/**
353 * msm_dts_srs_tm_init -
354 * Initializes DTS SRS module
355 *
356 * @port_id: Port ID number
357 * @copp_idx: COPP index
358 *
359 */
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530360void msm_dts_srs_tm_init(int port_id, int copp_idx)
361{
362 int cur_ref_cnt = 0;
363
364 if (set_port_id(port_id, copp_idx) < 0) {
365 pr_err("%s: Invalid port_id: %d\n", __func__, port_id);
366 return;
367 }
368
369 cur_ref_cnt = atomic_read(&ref_cnt);
370 atomic_inc(&ref_cnt);
371 if (!cur_ref_cnt && po.kvaddr == NULL) {
372 pr_debug("%s: calling reg_ion_mem()\n", __func__);
373 if (reg_ion_mem() != 0) {
374 atomic_dec(&ref_cnt);
375 po.kvaddr = NULL;
376 return;
377 }
378 }
379 msm_dts_srs_tm_send_params(port_id, 1);
380}
Laxminath Kasam8b1366a2017-10-05 01:44:16 +0530381EXPORT_SYMBOL(msm_dts_srs_tm_init);