blob: 5fea2d27a40fbf5c3d2ca1bd4e69419de23aee60 [file] [log] [blame]
Mangesh Kunchamwar4e1e7182018-04-26 17:58:58 +05301/*
2 * Copyright (c) 2015, 2017 - 2018 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/kernel.h>
15#include <linux/platform_device.h>
16#include <linux/ioctl.h>
17#include <sound/hwdep.h>
18#include <sound/msmcal-hwdep.h>
19#include <sound/soc.h>
20#include "q6afecal-hwdep.h"
21
22const int cal_size_info[Q6AFE_MAX_CAL] = {
23 [Q6AFE_VAD_CORE_CAL] = 132,
24};
25
26const char *cal_name_info[Q6AFE_MAX_CAL] = {
27 [Q6AFE_VAD_CORE_CAL] = "vad_core",
28};
29
30#define AFE_HW_NAME_LENGTH 40
31
32/*
33 * q6afecal_get_fw_cal -
34 * To get calibration from AFE HW dependent node
35 *
36 * @fw_data: pointer to firmware data
37 * type: AFE calibration type
38 *
39 */
40struct firmware_cal *q6afecal_get_fw_cal(struct afe_fw_info *fw_data,
41 enum q6afe_cal_type type)
42{
43 if (!fw_data) {
44 pr_err("%s: fw_data is NULL\n", __func__);
45 return NULL;
46 }
47 if (type >= Q6AFE_MAX_CAL ||
48 type < Q6AFE_MIN_CAL) {
49 pr_err("%s: wrong cal type sent %d\n", __func__, type);
50 return NULL;
51 }
52 mutex_lock(&fw_data->lock);
53 if (!test_bit(Q6AFECAL_RECEIVED,
54 &fw_data->q6afecal_state[type])) {
55 pr_err("%s: cal not sent by userspace %d\n",
56 __func__, type);
57 mutex_unlock(&fw_data->lock);
58 return NULL;
59 }
60 set_bit(Q6AFECAL_INITIALISED, &fw_data->q6afecal_state[type]);
61 mutex_unlock(&fw_data->lock);
62 return fw_data->fw[type];
63}
64EXPORT_SYMBOL(q6afecal_get_fw_cal);
65
66static int q6afecal_hwdep_ioctl_shared(struct snd_hwdep *hw,
67 struct q6afecal_ioctl_buffer fw_user)
68{
69 struct afe_fw_info *fw_data = hw->private_data;
70 struct firmware_cal **fw = fw_data->fw;
71 void *data;
72
73 if (!test_bit(fw_user.cal_type, fw_data->cal_bit)) {
74 pr_err("%s: q6afe didn't set this %d!!\n",
75 __func__, fw_user.cal_type);
76 return -EFAULT;
77 }
78 if (fw_user.cal_type >= Q6AFE_MAX_CAL ||
79 fw_user.cal_type < Q6AFE_MIN_CAL) {
80 pr_err("%s: wrong cal type sent %d\n",
81 __func__, fw_user.cal_type);
82 return -EFAULT;
83 }
84 if (fw_user.size > cal_size_info[fw_user.cal_type] ||
85 fw_user.size <= 0) {
86 pr_err("%s: incorrect firmware size %d for %s\n",
87 __func__, fw_user.size,
88 cal_name_info[fw_user.cal_type]);
89 return -EFAULT;
90 }
91 data = fw[fw_user.cal_type]->data;
92 if (copy_from_user(data, fw_user.buffer, fw_user.size))
93 return -EFAULT;
94 fw[fw_user.cal_type]->size = fw_user.size;
95 mutex_lock(&fw_data->lock);
96 set_bit(Q6AFECAL_RECEIVED, &fw_data->q6afecal_state[fw_user.cal_type]);
97 mutex_unlock(&fw_data->lock);
98 return 0;
99}
100
101#ifdef CONFIG_COMPAT
102struct q6afecal_ioctl_buffer32 {
103 u32 size;
104 compat_uptr_t buffer;
105 enum q6afe_cal_type cal_type;
106};
107
108enum {
109 SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32 =
110 _IOW('U', 0x1, struct q6afecal_ioctl_buffer32),
111};
112
113static int q6afecal_hwdep_ioctl_compat(struct snd_hwdep *hw, struct file *file,
114 unsigned int cmd, unsigned long arg)
115{
116 struct q6afecal_ioctl_buffer __user *argp = (void __user *)arg;
117 struct q6afecal_ioctl_buffer32 fw_user32;
118 struct q6afecal_ioctl_buffer fw_user_compat;
119
120 if (cmd != SNDRV_CTL_IOCTL_HWDEP_CAL_TYPE32) {
121 pr_err("%s: wrong ioctl command sent %u!\n", __func__, cmd);
122 return -ENOIOCTLCMD;
123 }
124 if (copy_from_user(&fw_user32, argp, sizeof(fw_user32))) {
125 pr_err("%s: failed to copy\n", __func__);
126 return -EFAULT;
127 }
128 fw_user_compat.size = fw_user32.size;
129 fw_user_compat.buffer = compat_ptr(fw_user32.buffer);
130 fw_user_compat.cal_type = fw_user32.cal_type;
131 return q6afecal_hwdep_ioctl_shared(hw, fw_user_compat);
132}
133#else
134#define q6afecal_hwdep_ioctl_compat NULL
135#endif
136
137static int q6afecal_hwdep_ioctl(struct snd_hwdep *hw, struct file *file,
138 unsigned int cmd, unsigned long arg)
139{
140 struct q6afecal_ioctl_buffer __user *argp = (void __user *)arg;
141 struct q6afecal_ioctl_buffer fw_user;
142
143 if (cmd != SNDRV_IOCTL_HWDEP_VAD_CAL_TYPE) {
144 pr_err("%s: wrong ioctl command sent %d!\n", __func__, cmd);
145 return -ENOIOCTLCMD;
146 }
147 if (copy_from_user(&fw_user, argp, sizeof(fw_user))) {
148 pr_err("%s: failed to copy\n", __func__);
149 return -EFAULT;
150 }
151 return q6afecal_hwdep_ioctl_shared(hw, fw_user);
152}
153
154static int q6afecal_hwdep_release(struct snd_hwdep *hw, struct file *file)
155{
156 struct afe_fw_info *fw_data = hw->private_data;
157
158 mutex_lock(&fw_data->lock);
159 /* clear all the calibrations */
160 memset(fw_data->q6afecal_state, 0,
161 sizeof(fw_data->q6afecal_state));
162 mutex_unlock(&fw_data->lock);
163 return 0;
164}
165
166/**
167 * q6afe_cal_create_hwdep -
168 * for creating HW dependent node for AFE
169 *
170 * @data: Pointer to hold fw data
171 * @node: node type
172 * @card: Pointer to sound card
173 *
174 */
175int q6afe_cal_create_hwdep(void *data, int node, void *card)
176{
177 char hwname[AFE_HW_NAME_LENGTH];
178 struct snd_hwdep *hwdep;
179 struct firmware_cal **fw;
180 struct afe_fw_info *fw_data = data;
181 int err, cal_bit;
182
183 if (!fw_data || !card) {
184 pr_err("%s: Invalid parameters\n", __func__);
185 return -EINVAL;
186 }
187
188 fw = fw_data->fw;
189 snprintf(hwname, strlen("Q6AFE"), "Q6AFE");
190 err = snd_hwdep_new(((struct snd_soc_card *)card)->snd_card,
191 hwname, node, &hwdep);
192 if (err < 0) {
193 pr_err("%s: new hwdep for q6afe failed %d\n", __func__, err);
194 return err;
195 }
196 snprintf(hwdep->name, strlen("Q6AFECAL"), "Q6AFECAL");
197 hwdep->iface = SNDRV_HWDEP_IFACE_AUDIO_BE;
198 hwdep->private_data = fw_data;
199 hwdep->ops.ioctl_compat = q6afecal_hwdep_ioctl_compat;
200 hwdep->ops.ioctl = q6afecal_hwdep_ioctl;
201 hwdep->ops.release = q6afecal_hwdep_release;
202 mutex_init(&fw_data->lock);
203
204 for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) {
205 set_bit(Q6AFECAL_UNINITIALISED,
206 &fw_data->q6afecal_state[cal_bit]);
207 fw[cal_bit] = kzalloc(sizeof *(fw[cal_bit]), GFP_KERNEL);
208 if (!fw[cal_bit]) {
209 pr_err("%s: no memory for %s cal\n",
210 __func__, cal_name_info[cal_bit]);
211 goto end;
212 }
213 }
214 for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) {
215 fw[cal_bit]->data = kzalloc(cal_size_info[cal_bit],
216 GFP_KERNEL);
217 if (!fw[cal_bit]->data)
218 goto exit;
219 set_bit(Q6AFECAL_INITIALISED,
220 &fw_data->q6afecal_state[cal_bit]);
221 }
222 return 0;
223exit:
224 for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) {
225 kfree(fw[cal_bit]->data);
226 fw[cal_bit]->data = NULL;
227 }
228end:
229 for_each_set_bit(cal_bit, fw_data->cal_bit, Q6AFE_MAX_CAL) {
230 kfree(fw[cal_bit]);
231 fw[cal_bit] = NULL;
232 }
233 return -ENOMEM;
234}
235EXPORT_SYMBOL(q6afe_cal_create_hwdep);