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