blob: 52f29d886ab58b8cefb4dd340b58c9b7c5af4e37 [file] [log] [blame]
Meng Wang43bbb872018-12-10 12:32:05 +08001// SPDX-License-Identifier: GPL-2.0-only
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05302/*
Xiao Lid8bb93c2020-01-07 12:59:05 +08003 * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05304 */
5
6#include <linux/module.h>
7#include <linux/init.h>
8#include <linux/slab.h>
9#include <linux/platform_device.h>
10#include <linux/device.h>
11#include <linux/printk.h>
12#include <linux/bitops.h>
13#include <linux/regulator/consumer.h>
14#include <linux/pm_runtime.h>
15#include <linux/delay.h>
16#include <linux/kernel.h>
17#include <linux/gpio.h>
18#include <linux/of_gpio.h>
Karthikeyan Mani13485b72019-08-05 17:51:14 -070019#include <linux/of_platform.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053020#include <linux/regmap.h>
21#include <linux/debugfs.h>
Laxminath Kasam605b42f2017-08-01 22:02:15 +053022#include <soc/soundwire.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053023#include <sound/pcm.h>
24#include <sound/pcm_params.h>
25#include <sound/soc.h>
26#include <sound/soc-dapm.h>
27#include <sound/tlv.h>
Meng Wang11a25cf2018-10-31 14:11:26 +080028#include <asoc/msm-cdc-pinctrl.h>
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053029#include "wsa881x.h"
30#include "wsa881x-temp-sensor.h"
31
Meng Wang15c825d2018-09-06 10:49:18 +080032#define DRV_NAME "wsa-codec"
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053033#define WSA881X_NUM_RETRY 5
34
35enum {
36 G_18DB = 0,
37 G_16P5DB,
38 G_15DB,
39 G_13P5DB,
40 G_12DB,
41 G_10P5DB,
42 G_9DB,
43 G_7P5DB,
44 G_6DB,
45 G_4P5DB,
46 G_3DB,
47 G_1P5DB,
48 G_0DB,
49};
50
51enum {
52 DISABLE = 0,
53 ENABLE,
54};
55
56enum {
57 SWR_DAC_PORT,
58 SWR_COMP_PORT,
59 SWR_BOOST_PORT,
60 SWR_VISENSE_PORT,
61};
62
63struct swr_port {
64 u8 port_id;
65 u8 ch_mask;
66 u32 ch_rate;
67 u8 num_ch;
Ramprasad Katkame38aed42018-03-07 16:26:49 +053068 u8 port_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053069};
70
71enum {
72 WSA881X_DEV_DOWN,
73 WSA881X_DEV_UP,
Laxminath Kasamc0684fc2018-07-31 19:26:56 +053074 WSA881X_DEV_READY,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053075};
76
77/*
78 * Private data Structure for wsa881x. All parameters related to
79 * WSA881X codec needs to be defined here.
80 */
81struct wsa881x_priv {
82 struct regmap *regmap;
83 struct device *dev;
84 struct swr_device *swr_slave;
Meng Wang15c825d2018-09-06 10:49:18 +080085 struct snd_soc_component *component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053086 bool comp_enable;
87 bool boost_enable;
88 bool visense_enable;
89 u8 pa_gain;
90 struct swr_port port[WSA881X_MAX_SWR_PORTS];
91 int pd_gpio;
92 struct wsa881x_tz_priv tz_pdata;
93 int bg_cnt;
94 int clk_cnt;
95 int version;
96 struct mutex bg_lock;
97 struct mutex res_lock;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +053098 struct mutex temp_lock;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +053099 struct snd_info_entry *entry;
100 struct snd_info_entry *version_entry;
101 int state;
102 struct delayed_work ocp_ctl_work;
103 struct device_node *wsa_rst_np;
104 int pa_mute;
Karthikeyan Mani13485b72019-08-05 17:51:14 -0700105 struct device_node *bolero_np;
106 struct platform_device* bolero_dev;
107 struct notifier_block bolero_nblock;
108 void *handle;
109 int (*register_notifier)(void *handle,
110 struct notifier_block *nblock,
111 bool enable);
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530112 struct dentry *debugfs_dent;
113 struct dentry *debugfs_peek;
114 struct dentry *debugfs_poke;
115 struct dentry *debugfs_reg_dump;
116 unsigned int read_data;
Karthikeyan Mani13485b72019-08-05 17:51:14 -0700117};
118
119/* from bolero to WSA events */
120enum {
121 BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
122 BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
123 BOLERO_WSA_EVT_SSR_DOWN,
124 BOLERO_WSA_EVT_SSR_UP,
Laxminath Kasam069df142019-09-17 23:43:34 +0530125 BOLERO_WSA_EVT_PA_ON_POST_FSCLK,
Laxminath Kasam2fe71f52020-05-15 00:39:51 +0530126 BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB,
Karthikeyan Mani13485b72019-08-05 17:51:14 -0700127};
128
129struct wsa_ctrl_platform_data {
130 void *handle;
131 int (*update_wsa_event)(void *handle, u16 event, u32 data);
132 int (*register_notifier)(void *handle,
133 struct notifier_block *nblock,
134 bool enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530135};
136
137#define SWR_SLV_MAX_REG_ADDR 0x390
138#define SWR_SLV_START_REG_ADDR 0x40
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530139#define SWR_SLV_MAX_BUF_LEN 25
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530140#define BYTES_PER_LINE 12
141#define SWR_SLV_RD_BUF_LEN 8
142#define SWR_SLV_WR_BUF_LEN 32
143#define SWR_SLV_MAX_DEVICES 2
144
145#define WSA881X_VERSION_ENTRY_SIZE 27
146#define WSA881X_OCP_CTL_TIMER_SEC 2
147#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
148#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
149
150static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
151module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
152MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
153
Meng Wang15c825d2018-09-06 10:49:18 +0800154static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530155 bool enable);
156
157static const char * const wsa_pa_gain_text[] = {
158 "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
159 "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
160 "G_0_DB"
161};
162
163static const struct soc_enum wsa_pa_gain_enum =
164 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
165
166static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
167 struct snd_ctl_elem_value *ucontrol)
168{
Meng Wang15c825d2018-09-06 10:49:18 +0800169 struct snd_soc_component *component =
170 snd_soc_kcontrol_component(kcontrol);
171 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530172
173 ucontrol->value.integer.value[0] = wsa881x->pa_gain;
174
Meng Wang15c825d2018-09-06 10:49:18 +0800175 dev_dbg(component->dev, "%s: PA gain = 0x%x\n", __func__,
176 wsa881x->pa_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530177
178 return 0;
179}
180
181static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
182 struct snd_ctl_elem_value *ucontrol)
183{
Meng Wang15c825d2018-09-06 10:49:18 +0800184 struct snd_soc_component *component =
185 snd_soc_kcontrol_component(kcontrol);
186 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530187
Meng Wang15c825d2018-09-06 10:49:18 +0800188 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530189 __func__, ucontrol->value.integer.value[0]);
190
191 wsa881x->pa_gain = ucontrol->value.integer.value[0];
192
193 return 0;
194}
195
196static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
197 struct snd_ctl_elem_value *ucontrol)
198{
199
Meng Wang15c825d2018-09-06 10:49:18 +0800200 struct snd_soc_component *component =
201 snd_soc_kcontrol_component(kcontrol);
202 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530203
204 ucontrol->value.integer.value[0] = wsa881x->pa_mute;
205
206 return 0;
207}
208
209static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
210 struct snd_ctl_elem_value *ucontrol)
211{
Meng Wang15c825d2018-09-06 10:49:18 +0800212 struct snd_soc_component *component =
213 snd_soc_kcontrol_component(kcontrol);
214 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530215 int value = ucontrol->value.integer.value[0];
216
Meng Wang15c825d2018-09-06 10:49:18 +0800217 dev_dbg(component->dev, "%s: mute current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530218 __func__, wsa881x->pa_mute, value);
219
220 if (value)
Meng Wang15c825d2018-09-06 10:49:18 +0800221 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
222 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530223 wsa881x->pa_mute = value;
224
225 return 0;
226}
227
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530228static int wsa881x_get_t0_init(struct snd_kcontrol *kcontrol,
229 struct snd_ctl_elem_value *ucontrol)
230{
231
Meng Wang15c825d2018-09-06 10:49:18 +0800232 struct snd_soc_component *component =
233 snd_soc_kcontrol_component(kcontrol);
234 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530235 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
236
237 ucontrol->value.integer.value[0] = pdata->t0_init;
Meng Wang15c825d2018-09-06 10:49:18 +0800238 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530239
240 return 0;
241}
242
243static int wsa881x_set_t0_init(struct snd_kcontrol *kcontrol,
244 struct snd_ctl_elem_value *ucontrol)
245{
Meng Wang15c825d2018-09-06 10:49:18 +0800246 struct snd_soc_component *component =
247 snd_soc_kcontrol_component(kcontrol);
248 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530249 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
250
251 pdata->t0_init = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800252 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530253
254 return 0;
255}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530256
257static const struct snd_kcontrol_new wsa_snd_controls[] = {
258 SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
259 wsa_pa_gain_get, wsa_pa_gain_put),
260 SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
261 wsa881x_get_mute, wsa881x_set_mute),
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530262 SOC_SINGLE_EXT("WSA T0 Init", SND_SOC_NOPM, 0, 1, 0,
263 wsa881x_get_t0_init, wsa881x_set_t0_init),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530264};
265
266static int codec_debug_open(struct inode *inode, struct file *file)
267{
268 file->private_data = inode->i_private;
269 return 0;
270}
271
272static int get_parameters(char *buf, u32 *param1, int num_of_par)
273{
274 char *token;
275 int base, cnt;
276
277 token = strsep(&buf, " ");
278 for (cnt = 0; cnt < num_of_par; cnt++) {
279 if (token) {
280 if ((token[1] == 'x') || (token[1] == 'X'))
281 base = 16;
282 else
283 base = 10;
284
285 if (kstrtou32(token, base, &param1[cnt]) != 0)
286 return -EINVAL;
287
288 token = strsep(&buf, " ");
289 } else
290 return -EINVAL;
291 }
292 return 0;
293}
294
295static ssize_t wsa881x_codec_version_read(struct snd_info_entry *entry,
296 void *file_private_data, struct file *file,
297 char __user *buf, size_t count, loff_t pos)
298{
299 struct wsa881x_priv *wsa881x;
300 char buffer[WSA881X_VERSION_ENTRY_SIZE];
301 int len;
302
303 wsa881x = (struct wsa881x_priv *) entry->private_data;
304 if (!wsa881x) {
305 pr_err("%s: wsa881x priv is null\n", __func__);
306 return -EINVAL;
307 }
308
309 len = snprintf(buffer, sizeof(buffer), "WSA881X-SOUNDWIRE_2_0\n");
310
311 return simple_read_from_buffer(buf, count, &pos, buffer, len);
312}
313
314static struct snd_info_entry_ops wsa881x_codec_info_ops = {
315 .read = wsa881x_codec_version_read,
316};
317
318/*
319 * wsa881x_codec_info_create_codec_entry - creates wsa881x module
320 * @codec_root: The parent directory
Meng Wang15c825d2018-09-06 10:49:18 +0800321 * @component: Codec instance
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530322 *
323 * Creates wsa881x module and version entry under the given
324 * parent directory.
325 *
326 * Return: 0 on success or negative error code on failure.
327 */
328int wsa881x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
Meng Wang15c825d2018-09-06 10:49:18 +0800329 struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530330{
331 struct snd_info_entry *version_entry;
332 struct wsa881x_priv *wsa881x;
333 struct snd_soc_card *card;
334 char name[80];
335
Meng Wang15c825d2018-09-06 10:49:18 +0800336 if (!codec_root || !component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530337 return -EINVAL;
338
Meng Wang15c825d2018-09-06 10:49:18 +0800339 wsa881x = snd_soc_component_get_drvdata(component);
340 card = component->card;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530341 snprintf(name, sizeof(name), "%s.%x", "wsa881x",
342 (u32)wsa881x->swr_slave->addr);
343
344 wsa881x->entry = snd_info_create_subdir(codec_root->module,
345 (const char *)name,
346 codec_root);
347 if (!wsa881x->entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800348 dev_dbg(component->dev, "%s: failed to create wsa881x entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530349 __func__);
350 return -ENOMEM;
351 }
352
353 version_entry = snd_info_create_card_entry(card->snd_card,
354 "version",
355 wsa881x->entry);
356 if (!version_entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800357 dev_dbg(component->dev, "%s: failed to create wsa881x version entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530358 __func__);
359 return -ENOMEM;
360 }
361
362 version_entry->private_data = wsa881x;
363 version_entry->size = WSA881X_VERSION_ENTRY_SIZE;
364 version_entry->content = SNDRV_INFO_CONTENT_DATA;
365 version_entry->c.ops = &wsa881x_codec_info_ops;
366
367 if (snd_info_register(version_entry) < 0) {
368 snd_info_free_entry(version_entry);
369 return -ENOMEM;
370 }
371 wsa881x->version_entry = version_entry;
372
373 return 0;
374}
375EXPORT_SYMBOL(wsa881x_codec_info_create_codec_entry);
376
377static bool is_swr_slv_reg_readable(int reg)
378{
379 bool ret = true;
380
381 if (((reg > 0x46) && (reg < 0x4A)) ||
382 ((reg > 0x4A) && (reg < 0x50)) ||
383 ((reg > 0x55) && (reg < 0xE0)) ||
384 ((reg > 0xE0) && (reg < 0xF0)) ||
385 ((reg > 0xF0) && (reg < 0x100)) ||
386 ((reg > 0x105) && (reg < 0x120)) ||
387 ((reg > 0x128) && (reg < 0x130)) ||
388 ((reg > 0x138) && (reg < 0x200)) ||
389 ((reg > 0x205) && (reg < 0x220)) ||
390 ((reg > 0x228) && (reg < 0x230)) ||
391 ((reg > 0x238) && (reg < 0x300)) ||
392 ((reg > 0x305) && (reg < 0x320)) ||
393 ((reg > 0x328) && (reg < 0x330)) ||
394 ((reg > 0x338) && (reg < 0x400)) ||
395 ((reg > 0x405) && (reg < 0x420)))
396 ret = false;
397
398 return ret;
399}
400
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530401static ssize_t wsa881x_swrslave_reg_show(struct swr_device *pdev, char __user *ubuf,
402 size_t count, loff_t *ppos)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530403{
404 int i, reg_val, len;
405 ssize_t total = 0;
406 char tmp_buf[SWR_SLV_MAX_BUF_LEN];
407
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530408 if (!ubuf || !ppos)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530409 return 0;
410
411 for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530412 i <= SWR_SLV_MAX_REG_ADDR; i++) {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530413 if (!is_swr_slv_reg_readable(i))
414 continue;
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530415 swr_read(pdev, pdev->dev_num, i, &reg_val, 1);
416 len = snprintf(tmp_buf, sizeof(tmp_buf), "0x%.3x: 0x%.2x\n", i,
417 (reg_val & 0xFF));
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530418 if (len < 0) {
419 pr_err("%s: fail to fill the buffer\n", __func__);
420 total = -EFAULT;
421 goto copy_err;
422 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530423 if ((total + len) >= count - 1)
424 break;
425 if (copy_to_user((ubuf + total), tmp_buf, len)) {
426 pr_err("%s: fail to copy reg dump\n", __func__);
427 total = -EFAULT;
428 goto copy_err;
429 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530430 total += len;
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530431 *ppos += len;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530432 }
433
434copy_err:
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530435 *ppos = SWR_SLV_MAX_REG_ADDR * BYTES_PER_LINE;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530436 return total;
437}
438
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530439static ssize_t codec_debug_dump(struct file *file, char __user *ubuf,
440 size_t count, loff_t *ppos)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530441{
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530442 struct swr_device *pdev;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530443
444 if (!count || !file || !ppos || !ubuf)
445 return -EINVAL;
446
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530447 pdev = file->private_data;
448 if (!pdev)
449 return -EINVAL;
450
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530451 if (*ppos < 0)
452 return -EINVAL;
453
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530454 return wsa881x_swrslave_reg_show(pdev, ubuf, count, ppos);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530455}
456
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530457static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
458 size_t count, loff_t *ppos)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530459{
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530460 char lbuf[SWR_SLV_RD_BUF_LEN];
461 struct swr_device *pdev = NULL;
462 struct wsa881x_priv *wsa881x = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530463
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530464 if (!count || !file || !ppos || !ubuf)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530465 return -EINVAL;
466
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530467 pdev = file->private_data;
468 if (!pdev)
469 return -EINVAL;
470
471 wsa881x = swr_get_dev_data(pdev);
472 if (!wsa881x)
473 return -EINVAL;
474
475 if (*ppos < 0)
476 return -EINVAL;
477
478 snprintf(lbuf, sizeof(lbuf), "0x%x\n",
479 (wsa881x->read_data & 0xFF));
480
481 return simple_read_from_buffer(ubuf, count, ppos, lbuf,
482 strnlen(lbuf, 7));
483}
484
485static ssize_t codec_debug_peek_write(struct file *file,
486 const char __user *ubuf, size_t cnt, loff_t *ppos)
487{
488 char lbuf[SWR_SLV_WR_BUF_LEN];
489 int rc = 0;
490 u32 param[5];
491 struct swr_device *pdev = NULL;
492 struct wsa881x_priv *wsa881x = NULL;
493
494 if (!cnt || !file || !ppos || !ubuf)
495 return -EINVAL;
496
497 pdev = file->private_data;
498 if (!pdev)
499 return -EINVAL;
500
501 wsa881x = swr_get_dev_data(pdev);
502 if (!wsa881x)
503 return -EINVAL;
504
505 if (*ppos < 0)
506 return -EINVAL;
507
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530508 if (cnt > sizeof(lbuf) - 1)
509 return -EINVAL;
510
511 rc = copy_from_user(lbuf, ubuf, cnt);
512 if (rc)
513 return -EFAULT;
514
515 lbuf[cnt] = '\0';
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530516 rc = get_parameters(lbuf, param, 1);
517 if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0)))
518 return -EINVAL;
519 swr_read(pdev, pdev->dev_num, param[0], &wsa881x->read_data, 1);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530520 if (rc == 0)
521 rc = cnt;
522 else
523 pr_err("%s: rc = %d\n", __func__, rc);
524
525 return rc;
526}
527
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530528static ssize_t codec_debug_write(struct file *file,
529 const char __user *ubuf, size_t cnt, loff_t *ppos)
530{
531 char lbuf[SWR_SLV_WR_BUF_LEN];
532 int rc = 0;
533 u32 param[5];
534 struct swr_device *pdev;
535
536 if (!file || !ppos || !ubuf)
537 return -EINVAL;
538
539 pdev = file->private_data;
540 if (!pdev)
541 return -EINVAL;
542
543 if (cnt > sizeof(lbuf) - 1)
544 return -EINVAL;
545
546 rc = copy_from_user(lbuf, ubuf, cnt);
547 if (rc)
548 return -EFAULT;
549
550 lbuf[cnt] = '\0';
551 rc = get_parameters(lbuf, param, 2);
552 if (!((param[0] <= SWR_SLV_MAX_REG_ADDR) &&
553 (param[1] <= 0xFF) && (rc == 0)))
554 return -EINVAL;
555 swr_write(pdev, pdev->dev_num, param[0], &param[1]);
556 if (rc == 0)
557 rc = cnt;
558 else
559 pr_err("%s: rc = %d\n", __func__, rc);
560
561 return rc;
562}
563
564static const struct file_operations codec_debug_write_ops = {
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530565 .open = codec_debug_open,
566 .write = codec_debug_write,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530567};
568
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +0530569static const struct file_operations codec_debug_read_ops = {
570 .open = codec_debug_open,
571 .read = codec_debug_read,
572 .write = codec_debug_peek_write,
573};
574
575static const struct file_operations codec_debug_dump_ops = {
576 .open = codec_debug_open,
577 .read = codec_debug_dump,
578};
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530579static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x)
580{
581 mutex_lock(&wsa881x->res_lock);
582 if (wsa881x->state != WSA881X_DEV_READY) {
583 regcache_mark_dirty(wsa881x->regmap);
584 regcache_sync(wsa881x->regmap);
585 wsa881x->state = WSA881X_DEV_READY;
586 }
587 mutex_unlock(&wsa881x->res_lock);
588}
589
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530590static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
591 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
592 {WSA881X_SPKR_MISC_CTL1, 0x01, 0},
593 {WSA881X_ADC_EN_DET_TEST_I, 0x01, 0},
594 {WSA881X_ADC_EN_MODU_V, 0x02, 0},
595 {WSA881X_ADC_EN_DET_TEST_V, 0x10, 0},
596 {WSA881X_SPKR_PWRSTG_DBG, 0xA0, 0},
597};
598
599static const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = {
600 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
601 {WSA881X_SPKR_MISC_CTL1, 0x87, 0},
602};
603
604static const struct reg_sequence wsa881x_post_pmu_pa[] = {
605 {WSA881X_SPKR_PWRSTG_DBG, 0x00, 0},
606 {WSA881X_ADC_EN_DET_TEST_V, 0x00, 0},
607 {WSA881X_ADC_EN_MODU_V, 0x00, 0},
608 {WSA881X_ADC_EN_DET_TEST_I, 0x00, 0},
609};
610
611static const struct reg_sequence wsa881x_vi_txfe_en[] = {
612 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
613 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
614 {WSA881X_SPKR_PROT_FE_GAIN, 0xCF, 0},
615};
616
617static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
618 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
619 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
620 {WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0},
621};
622
Meng Wang15c825d2018-09-06 10:49:18 +0800623static int wsa881x_boost_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530624{
Meng Wang15c825d2018-09-06 10:49:18 +0800625 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530626 if (enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800627 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
628 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530629 else
Meng Wang15c825d2018-09-06 10:49:18 +0800630 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
631 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530632 /*
633 * 1.5ms sleep is needed after boost enable/disable as per
634 * HW requirement
635 */
636 usleep_range(1500, 1510);
637 return 0;
638}
639
Meng Wang15c825d2018-09-06 10:49:18 +0800640static int wsa881x_visense_txfe_ctrl(struct snd_soc_component *component,
641 bool enable, u8 isense1_gain,
642 u8 isense2_gain, u8 vsense_gain)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530643{
Meng Wang15c825d2018-09-06 10:49:18 +0800644 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530645
Meng Wang15c825d2018-09-06 10:49:18 +0800646 dev_dbg(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530647 "%s: enable:%d, isense1 gain: %d, isense2 gain: %d, vsense_gain %d\n",
648 __func__, enable, isense1_gain, isense2_gain, vsense_gain);
649
650 if (enable) {
651 regmap_multi_reg_write(wsa881x->regmap,
652 wsa881x_vi_txfe_en_2_0,
653 ARRAY_SIZE(wsa881x_vi_txfe_en_2_0));
654 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800655 snd_soc_component_update_bits(component,
656 WSA881X_SPKR_PROT_FE_VSENSE_VCM,
657 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530658 /*
659 * 200us sleep is needed after visense txfe disable as per
660 * HW requirement.
661 */
662 usleep_range(200, 210);
Meng Wang15c825d2018-09-06 10:49:18 +0800663 snd_soc_component_update_bits(component,
664 WSA881X_SPKR_PROT_FE_GAIN,
665 0x01, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530666 }
667 return 0;
668}
669
Meng Wang15c825d2018-09-06 10:49:18 +0800670static int wsa881x_visense_adc_ctrl(struct snd_soc_component *component,
671 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530672{
673
Meng Wang15c825d2018-09-06 10:49:18 +0800674 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
675 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_V,
676 (0x01 << 7), (enable << 7));
677 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_I,
678 (0x01 << 7), (enable << 7));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530679 return 0;
680}
681
Meng Wang15c825d2018-09-06 10:49:18 +0800682static void wsa881x_bandgap_ctrl(struct snd_soc_component *component,
683 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530684{
Meng Wang15c825d2018-09-06 10:49:18 +0800685 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530686
Meng Wang15c825d2018-09-06 10:49:18 +0800687 dev_dbg(component->dev, "%s: enable:%d, bg_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530688 enable, wsa881x->bg_cnt);
689 mutex_lock(&wsa881x->bg_lock);
690 if (enable) {
691 ++wsa881x->bg_cnt;
692 if (wsa881x->bg_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800693 snd_soc_component_update_bits(component,
694 WSA881X_TEMP_OP,
695 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530696 /* 400usec sleep is needed as per HW requirement */
697 usleep_range(400, 410);
Meng Wang15c825d2018-09-06 10:49:18 +0800698 snd_soc_component_update_bits(component,
699 WSA881X_TEMP_OP,
700 0x04, 0x04);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530701 }
702 } else {
703 --wsa881x->bg_cnt;
704 if (wsa881x->bg_cnt <= 0) {
705 WARN_ON(wsa881x->bg_cnt < 0);
706 wsa881x->bg_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800707 snd_soc_component_update_bits(component,
708 WSA881X_TEMP_OP, 0x04, 0x00);
709 snd_soc_component_update_bits(component,
710 WSA881X_TEMP_OP, 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530711 }
712 }
713 mutex_unlock(&wsa881x->bg_lock);
714}
715
Meng Wang15c825d2018-09-06 10:49:18 +0800716static void wsa881x_clk_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530717{
Meng Wang15c825d2018-09-06 10:49:18 +0800718 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530719
Meng Wang15c825d2018-09-06 10:49:18 +0800720 dev_dbg(component->dev, "%s: enable:%d, clk_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530721 enable, wsa881x->clk_cnt);
722 mutex_lock(&wsa881x->res_lock);
723 if (enable) {
724 ++wsa881x->clk_cnt;
725 if (wsa881x->clk_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800726 snd_soc_component_write(component,
727 WSA881X_CDC_DIG_CLK_CTL, 0x01);
728 snd_soc_component_write(component,
729 WSA881X_CDC_ANA_CLK_CTL, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530730 }
731 } else {
732 --wsa881x->clk_cnt;
733 if (wsa881x->clk_cnt <= 0) {
734 WARN_ON(wsa881x->clk_cnt < 0);
735 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800736 snd_soc_component_write(component,
737 WSA881X_CDC_DIG_CLK_CTL, 0x00);
738 snd_soc_component_write(component,
739 WSA881X_CDC_ANA_CLK_CTL, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530740 }
741 }
742 mutex_unlock(&wsa881x->res_lock);
743}
744
745static int wsa881x_get_compander(struct snd_kcontrol *kcontrol,
746 struct snd_ctl_elem_value *ucontrol)
747{
748
Meng Wang15c825d2018-09-06 10:49:18 +0800749 struct snd_soc_component *component =
750 snd_soc_kcontrol_component(kcontrol);
751 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530752
753 ucontrol->value.integer.value[0] = wsa881x->comp_enable;
754 return 0;
755}
756
757static int wsa881x_set_compander(struct snd_kcontrol *kcontrol,
758 struct snd_ctl_elem_value *ucontrol)
759{
Meng Wang15c825d2018-09-06 10:49:18 +0800760 struct snd_soc_component *component =
761 snd_soc_kcontrol_component(kcontrol);
762 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530763 int value = ucontrol->value.integer.value[0];
764
Meng Wang15c825d2018-09-06 10:49:18 +0800765 dev_dbg(component->dev, "%s: Compander enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530766 __func__, wsa881x->comp_enable, value);
767 wsa881x->comp_enable = value;
768 return 0;
769}
770
771static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
772 struct snd_ctl_elem_value *ucontrol)
773{
774
Meng Wang15c825d2018-09-06 10:49:18 +0800775 struct snd_soc_component *component =
776 snd_soc_kcontrol_component(kcontrol);
777 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530778
779 ucontrol->value.integer.value[0] = wsa881x->boost_enable;
780 return 0;
781}
782
783static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
784 struct snd_ctl_elem_value *ucontrol)
785{
Meng Wang15c825d2018-09-06 10:49:18 +0800786 struct snd_soc_component *component =
787 snd_soc_kcontrol_component(kcontrol);
788 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530789 int value = ucontrol->value.integer.value[0];
790
Meng Wang15c825d2018-09-06 10:49:18 +0800791 dev_dbg(component->dev, "%s: Boost enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530792 __func__, wsa881x->boost_enable, value);
793 wsa881x->boost_enable = value;
794 return 0;
795}
796
797static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
798 struct snd_ctl_elem_value *ucontrol)
799{
800
Meng Wang15c825d2018-09-06 10:49:18 +0800801 struct snd_soc_component *component =
802 snd_soc_kcontrol_component(kcontrol);
803 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530804
805 ucontrol->value.integer.value[0] = wsa881x->visense_enable;
806 return 0;
807}
808
809static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
810 struct snd_ctl_elem_value *ucontrol)
811{
Meng Wang15c825d2018-09-06 10:49:18 +0800812 struct snd_soc_component *component =
813 snd_soc_kcontrol_component(kcontrol);
814 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530815 int value = ucontrol->value.integer.value[0];
816
Meng Wang15c825d2018-09-06 10:49:18 +0800817 dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530818 __func__, wsa881x->visense_enable, value);
819 wsa881x->visense_enable = value;
820 return 0;
821}
822
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800823static int wsa881x_set_boost_level(struct snd_kcontrol *kcontrol,
824 struct snd_ctl_elem_value *ucontrol)
825{
Meng Wang15c825d2018-09-06 10:49:18 +0800826 struct snd_soc_component *component =
827 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800828 u8 wsa_boost_level = 0;
829
Meng Wang15c825d2018-09-06 10:49:18 +0800830 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800831 __func__, ucontrol->value.integer.value[0]);
832
833 wsa_boost_level = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800834 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT1,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800835 0xff, wsa_boost_level);
836
837 return 0;
838}
839
840static int wsa881x_get_boost_level(struct snd_kcontrol *kcontrol,
841 struct snd_ctl_elem_value *ucontrol)
842{
Meng Wang15c825d2018-09-06 10:49:18 +0800843 struct snd_soc_component *component =
844 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800845 u8 wsa_boost_level = 0;
846
Meng Wang15c825d2018-09-06 10:49:18 +0800847 wsa_boost_level = snd_soc_component_read32(component,
848 WSA881X_BOOST_PRESET_OUT1);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800849 ucontrol->value.integer.value[0] = wsa_boost_level;
Meng Wang15c825d2018-09-06 10:49:18 +0800850 dev_dbg(component->dev, "%s: boost level = 0x%x\n", __func__,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800851 wsa_boost_level);
852
853 return 0;
854}
855
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530856static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
857 SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
858 wsa881x_get_compander, wsa881x_set_compander),
859
860 SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
861 wsa881x_get_boost, wsa881x_set_boost),
862
863 SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
864 wsa881x_get_visense, wsa881x_set_visense),
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800865
866 SOC_SINGLE_EXT("Boost Level", SND_SOC_NOPM, 0, 0xff, 0,
867 wsa881x_get_boost_level, wsa881x_set_boost_level),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530868};
869
870static const struct snd_kcontrol_new swr_dac_port[] = {
871 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
872};
873
Meng Wang15c825d2018-09-06 10:49:18 +0800874static int wsa881x_set_port(struct snd_soc_component *component, int port_idx,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530875 u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
876 u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530877{
Meng Wang15c825d2018-09-06 10:49:18 +0800878 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530879
880 *port_id = wsa881x->port[port_idx].port_id;
881 *num_ch = wsa881x->port[port_idx].num_ch;
882 *ch_mask = wsa881x->port[port_idx].ch_mask;
883 *ch_rate = wsa881x->port[port_idx].ch_rate;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530884 *port_type = wsa881x->port[port_idx].port_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530885 return 0;
886}
887
888static int wsa881x_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
889 struct snd_kcontrol *kcontrol, int event)
890{
Meng Wang15c825d2018-09-06 10:49:18 +0800891 struct snd_soc_component *component =
892 snd_soc_dapm_to_component(w->dapm);
893 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530894 u8 port_id[WSA881X_MAX_SWR_PORTS];
895 u8 num_ch[WSA881X_MAX_SWR_PORTS];
896 u8 ch_mask[WSA881X_MAX_SWR_PORTS];
897 u32 ch_rate[WSA881X_MAX_SWR_PORTS];
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530898 u8 port_type[WSA881X_MAX_SWR_PORTS];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530899 u8 num_port = 0;
900
Meng Wang15c825d2018-09-06 10:49:18 +0800901 dev_dbg(component->dev, "%s: event %d name %s\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530902 event, w->name);
903 if (wsa881x == NULL)
904 return -EINVAL;
905
906 switch (event) {
907 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +0800908 wsa881x_set_port(component, SWR_DAC_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530909 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530910 &ch_mask[num_port], &ch_rate[num_port],
911 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530912 ++num_port;
913
914 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800915 wsa881x_set_port(component, SWR_COMP_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530916 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530917 &ch_mask[num_port], &ch_rate[num_port],
918 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530919 ++num_port;
920 }
921 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800922 wsa881x_set_port(component, SWR_BOOST_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530923 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530924 &ch_mask[num_port], &ch_rate[num_port],
925 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530926 ++num_port;
927 }
928 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800929 wsa881x_set_port(component, SWR_VISENSE_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530930 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530931 &ch_mask[num_port], &ch_rate[num_port],
932 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530933 ++num_port;
934 }
935 swr_connect_port(wsa881x->swr_slave, &port_id[0], num_port,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530936 &ch_mask[0], &ch_rate[0], &num_ch[0],
937 &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530938 break;
939 case SND_SOC_DAPM_POST_PMU:
940 break;
941 case SND_SOC_DAPM_PRE_PMD:
942 break;
943 case SND_SOC_DAPM_POST_PMD:
Meng Wang15c825d2018-09-06 10:49:18 +0800944 wsa881x_set_port(component, SWR_DAC_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530945 &port_id[num_port], &num_ch[num_port],
946 &ch_mask[num_port], &ch_rate[num_port],
947 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530948 ++num_port;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530949
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530950 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800951 wsa881x_set_port(component, SWR_COMP_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530952 &port_id[num_port], &num_ch[num_port],
953 &ch_mask[num_port], &ch_rate[num_port],
954 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530955 ++num_port;
956 }
957 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800958 wsa881x_set_port(component, SWR_BOOST_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530959 &port_id[num_port], &num_ch[num_port],
960 &ch_mask[num_port], &ch_rate[num_port],
961 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962 ++num_port;
963 }
964 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800965 wsa881x_set_port(component, SWR_VISENSE_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530966 &port_id[num_port], &num_ch[num_port],
967 &ch_mask[num_port], &ch_rate[num_port],
968 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530969 ++num_port;
970 }
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530971 swr_disconnect_port(wsa881x->swr_slave, &port_id[0], num_port,
972 &ch_mask[0], &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530973 break;
974 default:
975 break;
976 }
977 return 0;
978}
979
980static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
981 struct snd_kcontrol *kcontrol, int event)
982{
Meng Wang15c825d2018-09-06 10:49:18 +0800983 struct snd_soc_component *component =
984 snd_soc_dapm_to_component(w->dapm);
985 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530986
Meng Wang15c825d2018-09-06 10:49:18 +0800987 dev_dbg(component->dev, "%s: %s %d boost %d visense %d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530988 w->name, event, wsa881x->boost_enable,
989 wsa881x->visense_enable);
990
991 switch (event) {
992 case SND_SOC_DAPM_PRE_PMU:
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530993 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800994 wsa881x_resource_acquire(component, ENABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530995 mutex_unlock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800996 wsa881x_boost_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530997 break;
998 case SND_SOC_DAPM_POST_PMD:
999 swr_slvdev_datapath_control(wsa881x->swr_slave,
1000 wsa881x->swr_slave->dev_num,
1001 false);
Meng Wang15c825d2018-09-06 10:49:18 +08001002 wsa881x_boost_ctrl(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301003 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001004 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301005 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301006 break;
1007 }
1008 return 0;
1009}
1010
Meng Wang15c825d2018-09-06 10:49:18 +08001011static int wsa881x_ramp_pa_gain(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301012 int min_gain, int max_gain, int udelay)
1013{
1014 int val;
1015
1016 for (val = min_gain; max_gain <= val; val--) {
Meng Wang15c825d2018-09-06 10:49:18 +08001017 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_GAIN,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301018 0xF0, val << 4);
1019 /*
1020 * 1ms delay is needed for every step change in gain as per
1021 * HW requirement.
1022 */
1023 usleep_range(udelay, udelay+10);
1024 }
1025 return 0;
1026}
1027
1028static void wsa881x_ocp_ctl_work(struct work_struct *work)
1029{
1030 struct wsa881x_priv *wsa881x;
1031 struct delayed_work *dwork;
Meng Wang15c825d2018-09-06 10:49:18 +08001032 struct snd_soc_component *component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301033 int temp_val;
1034
1035 dwork = to_delayed_work(work);
1036 wsa881x = container_of(dwork, struct wsa881x_priv, ocp_ctl_work);
1037
Prasad Kumpatla71fef462020-01-31 21:38:58 +05301038 if (wsa881x->state == WSA881X_DEV_DOWN)
1039 return;
1040
Meng Wang15c825d2018-09-06 10:49:18 +08001041 component = wsa881x->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301042 wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
Meng Wang15c825d2018-09-06 10:49:18 +08001043 dev_dbg(component->dev, " temp = %d\n", temp_val);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301044
1045 if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
Meng Wang15c825d2018-09-06 10:49:18 +08001046 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1047 0xC0, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301048 else
Meng Wang15c825d2018-09-06 10:49:18 +08001049 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1050 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301051
1052 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1053 msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
1054}
1055
1056static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
1057 struct snd_kcontrol *kcontrol, int event)
1058{
Meng Wang15c825d2018-09-06 10:49:18 +08001059 struct snd_soc_component *component =
1060 snd_soc_dapm_to_component(w->dapm);
1061 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301062 int min_gain, max_gain;
1063
Meng Wang15c825d2018-09-06 10:49:18 +08001064 dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301065 switch (event) {
1066 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +08001067 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1068 0xC0, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301069 regmap_multi_reg_write(wsa881x->regmap,
1070 wsa881x_pre_pmu_pa_2_0,
1071 ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0));
1072 swr_slvdev_datapath_control(wsa881x->swr_slave,
1073 wsa881x->swr_slave->dev_num,
1074 true);
1075 /* Set register mode if compander is not enabled */
1076 if (!wsa881x->comp_enable)
Meng Wang15c825d2018-09-06 10:49:18 +08001077 snd_soc_component_update_bits(component,
1078 WSA881X_SPKR_DRV_GAIN,
1079 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301080 else
Meng Wang15c825d2018-09-06 10:49:18 +08001081 snd_soc_component_update_bits(component,
1082 WSA881X_SPKR_DRV_GAIN,
1083 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301084
1085 break;
1086 case SND_SOC_DAPM_POST_PMU:
Laxminath Kasam069df142019-09-17 23:43:34 +05301087 if (!wsa881x->bolero_dev)
1088 snd_soc_component_update_bits(component,
1089 WSA881X_SPKR_DRV_EN,
1090 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301091 if (!wsa881x->comp_enable) {
1092 max_gain = wsa881x->pa_gain;
1093 /*
1094 * Gain has to set incrementally in 4 steps
1095 * as per HW sequence
1096 */
1097 if (max_gain > G_4P5DB)
1098 min_gain = G_0DB;
1099 else
1100 min_gain = max_gain + 3;
1101 /*
1102 * 1ms delay is needed before change in gain
1103 * as per HW requirement.
1104 */
1105 usleep_range(1000, 1010);
Meng Wang15c825d2018-09-06 10:49:18 +08001106 wsa881x_ramp_pa_gain(component, min_gain, max_gain,
1107 1000);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301108 }
1109 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001110 wsa881x_visense_txfe_ctrl(component, ENABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301111 0x00, 0x03, 0x01);
Meng Wang15c825d2018-09-06 10:49:18 +08001112 snd_soc_component_update_bits(component,
1113 WSA881X_ADC_EN_SEL_IBAIS,
1114 0x07, 0x01);
1115 wsa881x_visense_adc_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301116 }
1117 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1118 msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
1119 /* Force remove group */
1120 swr_remove_from_group(wsa881x->swr_slave,
1121 wsa881x->swr_slave->dev_num);
1122 break;
1123 case SND_SOC_DAPM_POST_PMD:
Laxminath Kasam069df142019-09-17 23:43:34 +05301124 snd_soc_component_update_bits(component,
1125 WSA881X_SPKR_DRV_EN,
1126 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301127 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001128 wsa881x_visense_adc_ctrl(component, DISABLE);
Laxminath Kasamf813d502020-07-01 17:01:55 +05301129 snd_soc_component_update_bits(component,
1130 WSA881X_ADC_EN_SEL_IBAIS,
1131 0x07, 0x00);
Meng Wang15c825d2018-09-06 10:49:18 +08001132 wsa881x_visense_txfe_ctrl(component, DISABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301133 0x00, 0x01, 0x01);
1134 }
1135 cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
Meng Wang15c825d2018-09-06 10:49:18 +08001136 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1137 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301138 break;
1139 }
1140 return 0;
1141}
1142
1143static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
1144 SND_SOC_DAPM_INPUT("IN"),
1145
1146 SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
1147 ARRAY_SIZE(swr_dac_port), wsa881x_enable_swr_dac_port,
1148 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1149 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
1150
1151 SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0,
1152 wsa881x_rdac_event,
1153 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1154
Laxminath Kasam069df142019-09-17 23:43:34 +05301155 SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301156 wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
1157 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1158
1159 SND_SOC_DAPM_OUTPUT("SPKR"),
1160};
1161
1162static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
1163 {"SWR DAC_Port", "Switch", "IN"},
1164 {"RDAC", NULL, "SWR DAC_Port"},
1165 {"SPKR PGA", NULL, "RDAC"},
1166 {"SPKR", NULL, "SPKR PGA"},
1167};
1168
Meng Wang15c825d2018-09-06 10:49:18 +08001169int wsa881x_set_channel_map(struct snd_soc_component *component, u8 *port,
1170 u8 num_port, unsigned int *ch_mask,
1171 unsigned int *ch_rate, u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301172{
Meng Wang15c825d2018-09-06 10:49:18 +08001173 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301174 int i;
1175
1176 if (!port || !ch_mask || !ch_rate ||
1177 (num_port > WSA881X_MAX_SWR_PORTS)) {
Meng Wang15c825d2018-09-06 10:49:18 +08001178 dev_err(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301179 "%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
1180 __func__, port, ch_mask, ch_rate);
1181 return -EINVAL;
1182 }
1183 for (i = 0; i < num_port; i++) {
1184 wsa881x->port[i].port_id = port[i];
1185 wsa881x->port[i].ch_mask = ch_mask[i];
1186 wsa881x->port[i].ch_rate = ch_rate[i];
1187 wsa881x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
Ramprasad Katkame38aed42018-03-07 16:26:49 +05301188 if (port_type)
1189 wsa881x->port[i].port_type = port_type[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301190 }
1191 return 0;
1192}
1193EXPORT_SYMBOL(wsa881x_set_channel_map);
1194
Meng Wang15c825d2018-09-06 10:49:18 +08001195static void wsa881x_init(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301196{
Meng Wang15c825d2018-09-06 10:49:18 +08001197 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301198
Meng Wang15c825d2018-09-06 10:49:18 +08001199 wsa881x->version =
1200 snd_soc_component_read32(component, WSA881X_CHIP_ID1);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301201 wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version);
Vatsal Bucha83716b92017-09-14 12:13:13 +05301202 /* Enable software reset output from soundwire slave */
Meng Wang15c825d2018-09-06 10:49:18 +08001203 snd_soc_component_update_bits(component, WSA881X_SWR_RESET_EN,
1204 0x07, 0x07);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301205 /* Bring out of analog reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001206 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1207 0x02, 0x02);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301208 /* Bring out of digital reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001209 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1210 0x01, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301211
Meng Wang15c825d2018-09-06 10:49:18 +08001212 snd_soc_component_update_bits(component, WSA881X_CLOCK_CONFIG,
1213 0x10, 0x10);
1214 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1215 0x02, 0x02);
1216 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1217 0xC0, 0x80);
1218 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1219 0x06, 0x06);
1220 snd_soc_component_update_bits(component, WSA881X_SPKR_BIAS_INT,
1221 0xFF, 0x00);
1222 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1223 0xF0, 0x40);
1224 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1225 0x0E, 0x0E);
1226 snd_soc_component_update_bits(component, WSA881X_BOOST_LOOP_STABILITY,
1227 0x03, 0x03);
1228 snd_soc_component_update_bits(component, WSA881X_BOOST_MISC2_CTL,
1229 0xFF, 0x14);
1230 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1231 0x80, 0x80);
1232 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1233 0x03, 0x00);
1234 snd_soc_component_update_bits(component,
1235 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1236 0x0C, 0x04);
1237 snd_soc_component_update_bits(component,
1238 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1239 0x03, 0x00);
1240 if (snd_soc_component_read32(component, WSA881X_OTP_REG_0))
1241 snd_soc_component_update_bits(component,
1242 WSA881X_BOOST_PRESET_OUT1,
1243 0xF0, 0x70);
1244 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT2,
1245 0xF0, 0x30);
1246 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
1247 0x08, 0x08);
1248 snd_soc_component_update_bits(component, WSA881X_BOOST_CURRENT_LIMIT,
1249 0x0F, 0x08);
1250 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1251 0x30, 0x30);
1252 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1253 0x0C, 0x00);
1254 snd_soc_component_update_bits(component, WSA881X_OTP_REG_28,
1255 0x3F, 0x3A);
1256 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG1,
1257 0xFF, 0xB2);
1258 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG2,
1259 0xFF, 0x05);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301260}
1261
Meng Wang15c825d2018-09-06 10:49:18 +08001262static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301263 bool enable)
1264{
Meng Wang15c825d2018-09-06 10:49:18 +08001265 wsa881x_clk_ctrl(component, enable);
1266 wsa881x_bandgap_ctrl(component, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301267 return 0;
1268}
1269
Meng Wang15c825d2018-09-06 10:49:18 +08001270static int32_t wsa881x_temp_reg_read(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301271 struct wsa_temp_register *wsa_temp_reg)
1272{
Meng Wang15c825d2018-09-06 10:49:18 +08001273 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301274 struct swr_device *dev;
1275 u8 retry = WSA881X_NUM_RETRY;
1276 u8 devnum = 0;
1277
1278 if (!wsa881x) {
Meng Wang15c825d2018-09-06 10:49:18 +08001279 dev_err(component->dev, "%s: wsa881x is NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301280 return -EINVAL;
1281 }
1282 dev = wsa881x->swr_slave;
1283 if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
1284 while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
1285 retry--) {
1286 /* Retry after 1 msec delay */
1287 usleep_range(1000, 1100);
1288 }
1289 if (retry == 0) {
Meng Wang15c825d2018-09-06 10:49:18 +08001290 dev_err(component->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001291 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301292 __func__, devnum, dev->addr);
1293 return -EINVAL;
1294 }
1295 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301296 wsa881x_regcache_sync(wsa881x);
1297 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001298 wsa881x_resource_acquire(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301299
Meng Wang15c825d2018-09-06 10:49:18 +08001300 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1301 0x01, 0x00);
1302 wsa_temp_reg->dmeas_msb = snd_soc_component_read32(
1303 component, WSA881X_TEMP_MSB);
1304 wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(
1305 component, WSA881X_TEMP_LSB);
1306 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1307 0x01, 0x01);
1308 wsa_temp_reg->d1_msb = snd_soc_component_read32(
1309 component, WSA881X_OTP_REG_1);
1310 wsa_temp_reg->d1_lsb = snd_soc_component_read32(
1311 component, WSA881X_OTP_REG_2);
1312 wsa_temp_reg->d2_msb = snd_soc_component_read32(
1313 component, WSA881X_OTP_REG_3);
1314 wsa_temp_reg->d2_lsb = snd_soc_component_read32(
1315 component, WSA881X_OTP_REG_4);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301316
Meng Wang15c825d2018-09-06 10:49:18 +08001317 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301318 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301319
1320 return 0;
1321}
1322
Meng Wang15c825d2018-09-06 10:49:18 +08001323static int wsa881x_probe(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301324{
Meng Wang15c825d2018-09-06 10:49:18 +08001325 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301326 struct swr_device *dev;
1327
1328 if (!wsa881x)
1329 return -EINVAL;
Meng Wang15c825d2018-09-06 10:49:18 +08001330 snd_soc_component_init_regmap(component, wsa881x->regmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301331
1332 dev = wsa881x->swr_slave;
Meng Wang15c825d2018-09-06 10:49:18 +08001333 wsa881x->component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301334 mutex_init(&wsa881x->bg_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001335 wsa881x_init(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301336 snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name),
1337 "%s.%x", "wsatz", (u8)dev->addr);
1338 wsa881x->bg_cnt = 0;
1339 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +08001340 wsa881x->tz_pdata.component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301341 wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
1342 wsa881x_init_thermal(&wsa881x->tz_pdata);
Meng Wang15c825d2018-09-06 10:49:18 +08001343 snd_soc_add_component_controls(component, wsa_snd_controls,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301344 ARRAY_SIZE(wsa_snd_controls));
1345 INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
1346 return 0;
1347}
1348
Meng Wang15c825d2018-09-06 10:49:18 +08001349static void wsa881x_remove(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301350{
Meng Wang15c825d2018-09-06 10:49:18 +08001351 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301352
1353 if (wsa881x->tz_pdata.tz_dev)
1354 wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
1355 mutex_destroy(&wsa881x->bg_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301356
Meng Wang15c825d2018-09-06 10:49:18 +08001357 return;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301358}
1359
Meng Wang15c825d2018-09-06 10:49:18 +08001360static const struct snd_soc_component_driver soc_codec_dev_wsa881x = {
1361 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301362 .probe = wsa881x_probe,
1363 .remove = wsa881x_remove,
Meng Wang15c825d2018-09-06 10:49:18 +08001364 .controls = wsa881x_snd_controls,
1365 .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
1366 .dapm_widgets = wsa881x_dapm_widgets,
1367 .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
1368 .dapm_routes = wsa881x_audio_map,
1369 .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301370};
1371
1372static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
1373{
1374 int ret = 0;
1375
1376 if (wsa881x->pd_gpio < 0) {
1377 dev_err(wsa881x->dev, "%s: gpio is not valid %d\n",
1378 __func__, wsa881x->pd_gpio);
1379 return -EINVAL;
1380 }
1381
1382 if (wsa881x->wsa_rst_np) {
1383 if (enable)
1384 ret = msm_cdc_pinctrl_select_active_state(
1385 wsa881x->wsa_rst_np);
1386 else
1387 ret = msm_cdc_pinctrl_select_sleep_state(
1388 wsa881x->wsa_rst_np);
1389 if (ret != 0)
1390 dev_err(wsa881x->dev,
1391 "%s: Failed to turn state %d; ret=%d\n",
1392 __func__, enable, ret);
1393 } else {
1394 if (gpio_is_valid(wsa881x->pd_gpio))
1395 gpio_direction_output(wsa881x->pd_gpio, enable);
1396 }
1397
1398 return ret;
1399}
1400
1401static int wsa881x_gpio_init(struct swr_device *pdev)
1402{
1403 int ret = 0;
1404 struct wsa881x_priv *wsa881x;
1405
1406 wsa881x = swr_get_dev_data(pdev);
1407 if (!wsa881x) {
1408 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1409 return -EINVAL;
1410 }
1411 dev_dbg(&pdev->dev, "%s: gpio %d request with name %s\n",
1412 __func__, wsa881x->pd_gpio, dev_name(&pdev->dev));
1413 ret = gpio_request(wsa881x->pd_gpio, dev_name(&pdev->dev));
1414 if (ret) {
1415 if (ret == -EBUSY) {
1416 /* GPIO was already requested */
1417 dev_dbg(&pdev->dev,
1418 "%s: gpio %d is already set to high\n",
1419 __func__, wsa881x->pd_gpio);
1420 ret = 0;
1421 } else {
1422 dev_err(&pdev->dev, "%s: Failed to request gpio %d, err: %d\n",
1423 __func__, wsa881x->pd_gpio, ret);
1424 }
1425 }
1426 return ret;
1427}
1428
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001429static int wsa881x_event_notify(struct notifier_block *nb,
1430 unsigned long val, void *ptr)
1431{
1432 u16 event = (val & 0xffff);
1433 struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
1434 bolero_nblock);
1435
1436 if (!wsa881x)
1437 return -EINVAL;
1438
1439 switch (event) {
1440 case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
1441 snd_soc_component_update_bits(wsa881x->component,
1442 WSA881X_SPKR_DRV_GAIN,
1443 0xF0, 0xC0);
1444 snd_soc_component_update_bits(wsa881x->component,
1445 WSA881X_SPKR_DRV_EN,
1446 0x80, 0x00);
1447 break;
Laxminath Kasam069df142019-09-17 23:43:34 +05301448 case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
Laxminath Kasam2fe71f52020-05-15 00:39:51 +05301449 case BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB:
Laxminath Kasam069df142019-09-17 23:43:34 +05301450 if ((snd_soc_component_read32(wsa881x->component,
1451 WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
1452 snd_soc_component_update_bits(wsa881x->component,
1453 WSA881X_SPKR_DRV_EN,
1454 0x80, 0x80);
Laxminath Kasamd6b62942019-11-05 12:38:20 +05301455 break;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001456 default:
1457 break;
1458 }
1459
1460 return 0;
1461}
1462
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301463static int wsa881x_swr_probe(struct swr_device *pdev)
1464{
1465 int ret = 0;
1466 struct wsa881x_priv *wsa881x;
1467 u8 devnum = 0;
1468 bool pin_state_current = false;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001469 struct wsa_ctrl_platform_data *plat_data = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301470
1471 wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
1472 GFP_KERNEL);
1473 if (!wsa881x)
1474 return -ENOMEM;
1475 wsa881x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
1476 "qcom,spkr-sd-n-node", 0);
1477 if (!wsa881x->wsa_rst_np) {
1478 dev_dbg(&pdev->dev, "%s: Not using pinctrl, fallback to gpio\n",
1479 __func__);
1480 wsa881x->pd_gpio = of_get_named_gpio(pdev->dev.of_node,
1481 "qcom,spkr-sd-n-gpio", 0);
1482 if (wsa881x->pd_gpio < 0) {
1483 dev_err(&pdev->dev, "%s: %s property is not found %d\n",
1484 __func__, "qcom,spkr-sd-n-gpio",
1485 wsa881x->pd_gpio);
1486 goto err;
1487 }
1488 dev_dbg(&pdev->dev, "%s: reset gpio %d\n", __func__,
1489 wsa881x->pd_gpio);
1490 }
1491 swr_set_dev_data(pdev, wsa881x);
1492
1493 wsa881x->swr_slave = pdev;
1494
1495 if (!wsa881x->wsa_rst_np) {
1496 ret = wsa881x_gpio_init(pdev);
1497 if (ret)
1498 goto err;
1499 }
1500 if (wsa881x->wsa_rst_np)
1501 pin_state_current = msm_cdc_pinctrl_get_state(
1502 wsa881x->wsa_rst_np);
1503 wsa881x_gpio_ctrl(wsa881x, true);
1504 wsa881x->state = WSA881X_DEV_UP;
1505
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +05301506 if (!wsa881x->debugfs_dent) {
1507 wsa881x->debugfs_dent = debugfs_create_dir(
1508 dev_name(&pdev->dev), 0);
1509 if (!IS_ERR(wsa881x->debugfs_dent)) {
1510 wsa881x->debugfs_peek =
1511 debugfs_create_file("swrslave_peek",
1512 S_IFREG | 0444,
1513 wsa881x->debugfs_dent,
1514 (void *) pdev,
1515 &codec_debug_read_ops);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301516
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +05301517 wsa881x->debugfs_poke =
1518 debugfs_create_file("swrslave_poke",
1519 S_IFREG | 0444,
1520 wsa881x->debugfs_dent,
1521 (void *) pdev,
1522 &codec_debug_write_ops);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301523
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +05301524 wsa881x->debugfs_reg_dump =
1525 debugfs_create_file(
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301526 "swrslave_reg_dump",
1527 S_IFREG | 0444,
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +05301528 wsa881x->debugfs_dent,
1529 (void *) pdev,
1530 &codec_debug_dump_ops);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301531 }
1532 }
1533
1534 /*
1535 * Add 5msec delay to provide sufficient time for
1536 * soundwire auto enumeration of slave devices as
1537 * as per HW requirement.
1538 */
1539 usleep_range(5000, 5010);
1540 ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
1541 if (ret) {
1542 dev_dbg(&pdev->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001543 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301544 __func__, devnum, pdev->addr);
1545 goto dev_err;
1546 }
1547 pdev->dev_num = devnum;
1548
1549 wsa881x->regmap = devm_regmap_init_swr(pdev,
1550 &wsa881x_regmap_config);
1551 if (IS_ERR(wsa881x->regmap)) {
1552 ret = PTR_ERR(wsa881x->regmap);
1553 dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
1554 __func__, ret);
1555 goto dev_err;
1556 }
1557
Meng Wang15c825d2018-09-06 10:49:18 +08001558 ret = snd_soc_register_component(&pdev->dev, &soc_codec_dev_wsa881x,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301559 NULL, 0);
1560 if (ret) {
1561 dev_err(&pdev->dev, "%s: Codec registration failed\n",
1562 __func__);
1563 goto dev_err;
1564 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001565
1566 wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
1567 "qcom,bolero-handle", 0);
1568 if (wsa881x->bolero_np) {
1569 wsa881x->bolero_dev =
1570 of_find_device_by_node(wsa881x->bolero_np);
1571 if (wsa881x->bolero_dev) {
1572 plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
1573 if (plat_data) {
1574 wsa881x->bolero_nblock.notifier_call =
1575 wsa881x_event_notify;
1576 if (plat_data->register_notifier)
1577 plat_data->register_notifier(
1578 plat_data->handle,
1579 &wsa881x->bolero_nblock,
1580 true);
1581 wsa881x->register_notifier =
1582 plat_data->register_notifier;
1583 wsa881x->handle = plat_data->handle;
1584 } else {
1585 dev_err(&pdev->dev, "%s: plat data not found\n",
1586 __func__);
1587 }
1588 } else {
1589 dev_err(&pdev->dev, "%s: bolero dev not found\n",
1590 __func__);
1591 }
1592 } else {
1593 dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
1594 }
1595
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301596 mutex_init(&wsa881x->res_lock);
1597 mutex_init(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301598
1599 return 0;
1600
1601dev_err:
1602 if (pin_state_current == false)
1603 wsa881x_gpio_ctrl(wsa881x, false);
1604 swr_remove_device(pdev);
1605err:
1606 return ret;
1607}
1608
1609static int wsa881x_swr_remove(struct swr_device *pdev)
1610{
1611 struct wsa881x_priv *wsa881x;
1612
1613 wsa881x = swr_get_dev_data(pdev);
1614 if (!wsa881x) {
1615 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1616 return -EINVAL;
1617 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001618
1619 if (wsa881x->register_notifier)
1620 wsa881x->register_notifier(wsa881x->handle,
1621 &wsa881x->bolero_nblock, false);
Shashi Kant Mauryab5e20f62020-11-19 17:33:42 +05301622 debugfs_remove_recursive(wsa881x->debugfs_dent);
1623 wsa881x->debugfs_dent = NULL;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301624 mutex_destroy(&wsa881x->res_lock);
1625 mutex_destroy(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001626 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301627 if (wsa881x->pd_gpio)
1628 gpio_free(wsa881x->pd_gpio);
1629 swr_set_dev_data(pdev, NULL);
1630 return 0;
1631}
1632
1633static int wsa881x_swr_up(struct swr_device *pdev)
1634{
1635 int ret;
1636 struct wsa881x_priv *wsa881x;
1637
1638 wsa881x = swr_get_dev_data(pdev);
1639 if (!wsa881x) {
1640 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1641 return -EINVAL;
1642 }
1643 ret = wsa881x_gpio_ctrl(wsa881x, true);
1644 if (ret)
1645 dev_err(&pdev->dev, "%s: Failed to enable gpio\n", __func__);
1646 else
1647 wsa881x->state = WSA881X_DEV_UP;
1648
1649 return ret;
1650}
1651
1652static int wsa881x_swr_down(struct swr_device *pdev)
1653{
1654 struct wsa881x_priv *wsa881x;
1655 int ret;
1656
1657 wsa881x = swr_get_dev_data(pdev);
1658 if (!wsa881x) {
1659 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1660 return -EINVAL;
1661 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301662 ret = wsa881x_gpio_ctrl(wsa881x, false);
1663 if (ret)
1664 dev_err(&pdev->dev, "%s: Failed to disable gpio\n", __func__);
1665 else
1666 wsa881x->state = WSA881X_DEV_DOWN;
1667
1668 return ret;
1669}
1670
1671static int wsa881x_swr_reset(struct swr_device *pdev)
1672{
1673 struct wsa881x_priv *wsa881x;
1674 u8 retry = WSA881X_NUM_RETRY;
1675 u8 devnum = 0;
1676
1677 wsa881x = swr_get_dev_data(pdev);
1678 if (!wsa881x) {
1679 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1680 return -EINVAL;
1681 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301682 if (wsa881x->state == WSA881X_DEV_READY) {
1683 dev_dbg(&pdev->dev, "%s: device already active\n", __func__);
1684 return 0;
1685 }
1686
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301687 wsa881x->bg_cnt = 0;
1688 wsa881x->clk_cnt = 0;
1689 while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
1690 /* Retry after 1 msec delay */
1691 usleep_range(1000, 1100);
1692 }
1693 pdev->dev_num = devnum;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301694 wsa881x_regcache_sync(wsa881x);
1695
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301696 return 0;
1697}
1698
1699#ifdef CONFIG_PM_SLEEP
1700static int wsa881x_swr_suspend(struct device *dev)
1701{
1702 dev_dbg(dev, "%s: system suspend\n", __func__);
1703 return 0;
1704}
1705
1706static int wsa881x_swr_resume(struct device *dev)
1707{
1708 struct wsa881x_priv *wsa881x = swr_get_dev_data(to_swr_device(dev));
1709
1710 if (!wsa881x) {
1711 dev_err(dev, "%s: wsa881x private data is NULL\n", __func__);
1712 return -EINVAL;
1713 }
1714 dev_dbg(dev, "%s: system resume\n", __func__);
1715 return 0;
1716}
1717#endif /* CONFIG_PM_SLEEP */
1718
1719static const struct dev_pm_ops wsa881x_swr_pm_ops = {
1720 SET_SYSTEM_SLEEP_PM_OPS(wsa881x_swr_suspend, wsa881x_swr_resume)
1721};
1722
1723static const struct swr_device_id wsa881x_swr_id[] = {
1724 {"wsa881x", 0},
1725 {}
1726};
1727
1728static const struct of_device_id wsa881x_swr_dt_match[] = {
1729 {
1730 .compatible = "qcom,wsa881x",
1731 },
1732 {}
1733};
1734
1735static struct swr_driver wsa881x_codec_driver = {
1736 .driver = {
1737 .name = "wsa881x",
1738 .owner = THIS_MODULE,
1739 .pm = &wsa881x_swr_pm_ops,
1740 .of_match_table = wsa881x_swr_dt_match,
1741 },
1742 .probe = wsa881x_swr_probe,
1743 .remove = wsa881x_swr_remove,
1744 .id_table = wsa881x_swr_id,
1745 .device_up = wsa881x_swr_up,
1746 .device_down = wsa881x_swr_down,
1747 .reset_device = wsa881x_swr_reset,
1748};
1749
1750static int __init wsa881x_codec_init(void)
1751{
1752 return swr_driver_register(&wsa881x_codec_driver);
1753}
1754
1755static void __exit wsa881x_codec_exit(void)
1756{
1757 swr_driver_unregister(&wsa881x_codec_driver);
1758}
1759
1760module_init(wsa881x_codec_init);
1761module_exit(wsa881x_codec_exit);
1762
1763MODULE_DESCRIPTION("WSA881x Codec driver");
1764MODULE_LICENSE("GPL v2");