blob: c72fcc1c2c712102568c83f8b4a8722b6899d1e1 [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);
112};
113
114/* from bolero to WSA events */
115enum {
116 BOLERO_WSA_EVT_TX_CH_HOLD_CLEAR = 1,
117 BOLERO_WSA_EVT_PA_OFF_PRE_SSR,
118 BOLERO_WSA_EVT_SSR_DOWN,
119 BOLERO_WSA_EVT_SSR_UP,
Laxminath Kasam069df142019-09-17 23:43:34 +0530120 BOLERO_WSA_EVT_PA_ON_POST_FSCLK,
Laxminath Kasam2fe71f52020-05-15 00:39:51 +0530121 BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB,
Karthikeyan Mani13485b72019-08-05 17:51:14 -0700122};
123
124struct wsa_ctrl_platform_data {
125 void *handle;
126 int (*update_wsa_event)(void *handle, u16 event, u32 data);
127 int (*register_notifier)(void *handle,
128 struct notifier_block *nblock,
129 bool enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530130};
131
132#define SWR_SLV_MAX_REG_ADDR 0x390
133#define SWR_SLV_START_REG_ADDR 0x40
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530134#define SWR_SLV_MAX_BUF_LEN 25
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530135#define BYTES_PER_LINE 12
136#define SWR_SLV_RD_BUF_LEN 8
137#define SWR_SLV_WR_BUF_LEN 32
138#define SWR_SLV_MAX_DEVICES 2
139
140#define WSA881X_VERSION_ENTRY_SIZE 27
141#define WSA881X_OCP_CTL_TIMER_SEC 2
142#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
143#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
144
145static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
146module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
147MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
148
149static struct wsa881x_priv *dbgwsa881x;
150static struct dentry *debugfs_wsa881x_dent;
151static struct dentry *debugfs_peek;
152static struct dentry *debugfs_poke;
153static struct dentry *debugfs_reg_dump;
154static unsigned int read_data;
155static unsigned int devnum;
156
Meng Wang15c825d2018-09-06 10:49:18 +0800157static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530158 bool enable);
159
160static const char * const wsa_pa_gain_text[] = {
161 "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
162 "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
163 "G_0_DB"
164};
165
166static const struct soc_enum wsa_pa_gain_enum =
167 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
168
169static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
170 struct snd_ctl_elem_value *ucontrol)
171{
Meng Wang15c825d2018-09-06 10:49:18 +0800172 struct snd_soc_component *component =
173 snd_soc_kcontrol_component(kcontrol);
174 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530175
176 ucontrol->value.integer.value[0] = wsa881x->pa_gain;
177
Meng Wang15c825d2018-09-06 10:49:18 +0800178 dev_dbg(component->dev, "%s: PA gain = 0x%x\n", __func__,
179 wsa881x->pa_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530180
181 return 0;
182}
183
184static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
186{
Meng Wang15c825d2018-09-06 10:49:18 +0800187 struct snd_soc_component *component =
188 snd_soc_kcontrol_component(kcontrol);
189 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530190
Meng Wang15c825d2018-09-06 10:49:18 +0800191 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530192 __func__, ucontrol->value.integer.value[0]);
193
194 wsa881x->pa_gain = ucontrol->value.integer.value[0];
195
196 return 0;
197}
198
199static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
200 struct snd_ctl_elem_value *ucontrol)
201{
202
Meng Wang15c825d2018-09-06 10:49:18 +0800203 struct snd_soc_component *component =
204 snd_soc_kcontrol_component(kcontrol);
205 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530206
207 ucontrol->value.integer.value[0] = wsa881x->pa_mute;
208
209 return 0;
210}
211
212static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
213 struct snd_ctl_elem_value *ucontrol)
214{
Meng Wang15c825d2018-09-06 10:49:18 +0800215 struct snd_soc_component *component =
216 snd_soc_kcontrol_component(kcontrol);
217 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530218 int value = ucontrol->value.integer.value[0];
219
Meng Wang15c825d2018-09-06 10:49:18 +0800220 dev_dbg(component->dev, "%s: mute current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530221 __func__, wsa881x->pa_mute, value);
222
223 if (value)
Meng Wang15c825d2018-09-06 10:49:18 +0800224 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
225 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530226 wsa881x->pa_mute = value;
227
228 return 0;
229}
230
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530231static int wsa881x_get_t0_init(struct snd_kcontrol *kcontrol,
232 struct snd_ctl_elem_value *ucontrol)
233{
234
Meng Wang15c825d2018-09-06 10:49:18 +0800235 struct snd_soc_component *component =
236 snd_soc_kcontrol_component(kcontrol);
237 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530238 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
239
240 ucontrol->value.integer.value[0] = pdata->t0_init;
Meng Wang15c825d2018-09-06 10:49:18 +0800241 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530242
243 return 0;
244}
245
246static int wsa881x_set_t0_init(struct snd_kcontrol *kcontrol,
247 struct snd_ctl_elem_value *ucontrol)
248{
Meng Wang15c825d2018-09-06 10:49:18 +0800249 struct snd_soc_component *component =
250 snd_soc_kcontrol_component(kcontrol);
251 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530252 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
253
254 pdata->t0_init = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800255 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530256
257 return 0;
258}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530259
260static const struct snd_kcontrol_new wsa_snd_controls[] = {
261 SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
262 wsa_pa_gain_get, wsa_pa_gain_put),
263 SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
264 wsa881x_get_mute, wsa881x_set_mute),
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530265 SOC_SINGLE_EXT("WSA T0 Init", SND_SOC_NOPM, 0, 1, 0,
266 wsa881x_get_t0_init, wsa881x_set_t0_init),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530267};
268
269static int codec_debug_open(struct inode *inode, struct file *file)
270{
271 file->private_data = inode->i_private;
272 return 0;
273}
274
275static int get_parameters(char *buf, u32 *param1, int num_of_par)
276{
277 char *token;
278 int base, cnt;
279
280 token = strsep(&buf, " ");
281 for (cnt = 0; cnt < num_of_par; cnt++) {
282 if (token) {
283 if ((token[1] == 'x') || (token[1] == 'X'))
284 base = 16;
285 else
286 base = 10;
287
288 if (kstrtou32(token, base, &param1[cnt]) != 0)
289 return -EINVAL;
290
291 token = strsep(&buf, " ");
292 } else
293 return -EINVAL;
294 }
295 return 0;
296}
297
298static ssize_t wsa881x_codec_version_read(struct snd_info_entry *entry,
299 void *file_private_data, struct file *file,
300 char __user *buf, size_t count, loff_t pos)
301{
302 struct wsa881x_priv *wsa881x;
303 char buffer[WSA881X_VERSION_ENTRY_SIZE];
304 int len;
305
306 wsa881x = (struct wsa881x_priv *) entry->private_data;
307 if (!wsa881x) {
308 pr_err("%s: wsa881x priv is null\n", __func__);
309 return -EINVAL;
310 }
311
312 len = snprintf(buffer, sizeof(buffer), "WSA881X-SOUNDWIRE_2_0\n");
313
314 return simple_read_from_buffer(buf, count, &pos, buffer, len);
315}
316
317static struct snd_info_entry_ops wsa881x_codec_info_ops = {
318 .read = wsa881x_codec_version_read,
319};
320
321/*
322 * wsa881x_codec_info_create_codec_entry - creates wsa881x module
323 * @codec_root: The parent directory
Meng Wang15c825d2018-09-06 10:49:18 +0800324 * @component: Codec instance
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530325 *
326 * Creates wsa881x module and version entry under the given
327 * parent directory.
328 *
329 * Return: 0 on success or negative error code on failure.
330 */
331int wsa881x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
Meng Wang15c825d2018-09-06 10:49:18 +0800332 struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530333{
334 struct snd_info_entry *version_entry;
335 struct wsa881x_priv *wsa881x;
336 struct snd_soc_card *card;
337 char name[80];
338
Meng Wang15c825d2018-09-06 10:49:18 +0800339 if (!codec_root || !component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530340 return -EINVAL;
341
Meng Wang15c825d2018-09-06 10:49:18 +0800342 wsa881x = snd_soc_component_get_drvdata(component);
343 card = component->card;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530344 snprintf(name, sizeof(name), "%s.%x", "wsa881x",
345 (u32)wsa881x->swr_slave->addr);
346
347 wsa881x->entry = snd_info_create_subdir(codec_root->module,
348 (const char *)name,
349 codec_root);
350 if (!wsa881x->entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800351 dev_dbg(component->dev, "%s: failed to create wsa881x entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530352 __func__);
353 return -ENOMEM;
354 }
355
356 version_entry = snd_info_create_card_entry(card->snd_card,
357 "version",
358 wsa881x->entry);
359 if (!version_entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800360 dev_dbg(component->dev, "%s: failed to create wsa881x version entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530361 __func__);
362 return -ENOMEM;
363 }
364
365 version_entry->private_data = wsa881x;
366 version_entry->size = WSA881X_VERSION_ENTRY_SIZE;
367 version_entry->content = SNDRV_INFO_CONTENT_DATA;
368 version_entry->c.ops = &wsa881x_codec_info_ops;
369
370 if (snd_info_register(version_entry) < 0) {
371 snd_info_free_entry(version_entry);
372 return -ENOMEM;
373 }
374 wsa881x->version_entry = version_entry;
375
376 return 0;
377}
378EXPORT_SYMBOL(wsa881x_codec_info_create_codec_entry);
379
380static bool is_swr_slv_reg_readable(int reg)
381{
382 bool ret = true;
383
384 if (((reg > 0x46) && (reg < 0x4A)) ||
385 ((reg > 0x4A) && (reg < 0x50)) ||
386 ((reg > 0x55) && (reg < 0xE0)) ||
387 ((reg > 0xE0) && (reg < 0xF0)) ||
388 ((reg > 0xF0) && (reg < 0x100)) ||
389 ((reg > 0x105) && (reg < 0x120)) ||
390 ((reg > 0x128) && (reg < 0x130)) ||
391 ((reg > 0x138) && (reg < 0x200)) ||
392 ((reg > 0x205) && (reg < 0x220)) ||
393 ((reg > 0x228) && (reg < 0x230)) ||
394 ((reg > 0x238) && (reg < 0x300)) ||
395 ((reg > 0x305) && (reg < 0x320)) ||
396 ((reg > 0x328) && (reg < 0x330)) ||
397 ((reg > 0x338) && (reg < 0x400)) ||
398 ((reg > 0x405) && (reg < 0x420)))
399 ret = false;
400
401 return ret;
402}
403
404static ssize_t wsa881x_swrslave_reg_show(char __user *ubuf, size_t count,
405 loff_t *ppos)
406{
407 int i, reg_val, len;
408 ssize_t total = 0;
409 char tmp_buf[SWR_SLV_MAX_BUF_LEN];
410
411 if (!ubuf || !ppos || (devnum == 0))
412 return 0;
413
414 for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
415 i <= SWR_SLV_MAX_REG_ADDR; i++) {
416 if (!is_swr_slv_reg_readable(i))
417 continue;
418 swr_read(dbgwsa881x->swr_slave, devnum,
419 i, &reg_val, 1);
420 len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
421 (reg_val & 0xFF));
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530422 if (len < 0) {
423 pr_err("%s: fail to fill the buffer\n", __func__);
424 total = -EFAULT;
425 goto copy_err;
426 }
427
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530428 if ((total + len) >= count - 1)
429 break;
430 if (copy_to_user((ubuf + total), tmp_buf, len)) {
431 pr_err("%s: fail to copy reg dump\n", __func__);
432 total = -EFAULT;
433 goto copy_err;
434 }
435 *ppos += len;
436 total += len;
437 }
438
439copy_err:
440 return total;
441}
442
443static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
444 size_t count, loff_t *ppos)
445{
446 char lbuf[SWR_SLV_RD_BUF_LEN];
447 char *access_str;
448 ssize_t ret_cnt;
449
450 if (!count || !file || !ppos || !ubuf)
451 return -EINVAL;
452
453 access_str = file->private_data;
454 if (*ppos < 0)
455 return -EINVAL;
456
457 if (!strcmp(access_str, "swrslave_peek")) {
458 snprintf(lbuf, sizeof(lbuf), "0x%x\n", (read_data & 0xFF));
459 ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
460 strnlen(lbuf, 7));
461 } else if (!strcmp(access_str, "swrslave_reg_dump")) {
462 ret_cnt = wsa881x_swrslave_reg_show(ubuf, count, ppos);
463 } else {
464 pr_err("%s: %s not permitted to read\n", __func__, access_str);
465 ret_cnt = -EPERM;
466 }
467 return ret_cnt;
468}
469
470static ssize_t codec_debug_write(struct file *filp,
471 const char __user *ubuf, size_t cnt, loff_t *ppos)
472{
473 char lbuf[SWR_SLV_WR_BUF_LEN];
474 int rc;
475 u32 param[5];
476 char *access_str;
477
478 if (!filp || !ppos || !ubuf)
479 return -EINVAL;
480
481 access_str = filp->private_data;
482 if (cnt > sizeof(lbuf) - 1)
483 return -EINVAL;
484
485 rc = copy_from_user(lbuf, ubuf, cnt);
486 if (rc)
487 return -EFAULT;
488
489 lbuf[cnt] = '\0';
490 if (!strcmp(access_str, "swrslave_poke")) {
491 /* write */
492 rc = get_parameters(lbuf, param, 3);
493 if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (param[1] <= 0xFF) &&
494 (rc == 0))
495 swr_write(dbgwsa881x->swr_slave, param[2],
496 param[0], &param[1]);
497 else
498 rc = -EINVAL;
499 } else if (!strcmp(access_str, "swrslave_peek")) {
500 /* read */
501 rc = get_parameters(lbuf, param, 2);
502 if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))
503 swr_read(dbgwsa881x->swr_slave, param[1],
504 param[0], &read_data, 1);
505 else
506 rc = -EINVAL;
507 } else if (!strcmp(access_str, "swrslave_reg_dump")) {
508 /* reg dump */
509 rc = get_parameters(lbuf, param, 1);
510 if ((rc == 0) && (param[0] > 0) &&
511 (param[0] <= SWR_SLV_MAX_DEVICES))
512 devnum = param[0];
513 else
514 rc = -EINVAL;
515 }
516 if (rc == 0)
517 rc = cnt;
518 else
519 pr_err("%s: rc = %d\n", __func__, rc);
520
521 return rc;
522}
523
524static const struct file_operations codec_debug_ops = {
525 .open = codec_debug_open,
526 .write = codec_debug_write,
527 .read = codec_debug_read,
528};
529
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530530static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x)
531{
532 mutex_lock(&wsa881x->res_lock);
533 if (wsa881x->state != WSA881X_DEV_READY) {
534 regcache_mark_dirty(wsa881x->regmap);
535 regcache_sync(wsa881x->regmap);
536 wsa881x->state = WSA881X_DEV_READY;
537 }
538 mutex_unlock(&wsa881x->res_lock);
539}
540
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530541static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
542 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
543 {WSA881X_SPKR_MISC_CTL1, 0x01, 0},
544 {WSA881X_ADC_EN_DET_TEST_I, 0x01, 0},
545 {WSA881X_ADC_EN_MODU_V, 0x02, 0},
546 {WSA881X_ADC_EN_DET_TEST_V, 0x10, 0},
547 {WSA881X_SPKR_PWRSTG_DBG, 0xA0, 0},
548};
549
550static const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = {
551 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
552 {WSA881X_SPKR_MISC_CTL1, 0x87, 0},
553};
554
555static const struct reg_sequence wsa881x_post_pmu_pa[] = {
556 {WSA881X_SPKR_PWRSTG_DBG, 0x00, 0},
557 {WSA881X_ADC_EN_DET_TEST_V, 0x00, 0},
558 {WSA881X_ADC_EN_MODU_V, 0x00, 0},
559 {WSA881X_ADC_EN_DET_TEST_I, 0x00, 0},
560};
561
562static const struct reg_sequence wsa881x_vi_txfe_en[] = {
563 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
564 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
565 {WSA881X_SPKR_PROT_FE_GAIN, 0xCF, 0},
566};
567
568static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
569 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
570 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
571 {WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0},
572};
573
Meng Wang15c825d2018-09-06 10:49:18 +0800574static int wsa881x_boost_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530575{
Meng Wang15c825d2018-09-06 10:49:18 +0800576 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530577 if (enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800578 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
579 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530580 else
Meng Wang15c825d2018-09-06 10:49:18 +0800581 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
582 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530583 /*
584 * 1.5ms sleep is needed after boost enable/disable as per
585 * HW requirement
586 */
587 usleep_range(1500, 1510);
588 return 0;
589}
590
Meng Wang15c825d2018-09-06 10:49:18 +0800591static int wsa881x_visense_txfe_ctrl(struct snd_soc_component *component,
592 bool enable, u8 isense1_gain,
593 u8 isense2_gain, u8 vsense_gain)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530594{
Meng Wang15c825d2018-09-06 10:49:18 +0800595 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530596
Meng Wang15c825d2018-09-06 10:49:18 +0800597 dev_dbg(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530598 "%s: enable:%d, isense1 gain: %d, isense2 gain: %d, vsense_gain %d\n",
599 __func__, enable, isense1_gain, isense2_gain, vsense_gain);
600
601 if (enable) {
602 regmap_multi_reg_write(wsa881x->regmap,
603 wsa881x_vi_txfe_en_2_0,
604 ARRAY_SIZE(wsa881x_vi_txfe_en_2_0));
605 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800606 snd_soc_component_update_bits(component,
607 WSA881X_SPKR_PROT_FE_VSENSE_VCM,
608 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530609 /*
610 * 200us sleep is needed after visense txfe disable as per
611 * HW requirement.
612 */
613 usleep_range(200, 210);
Meng Wang15c825d2018-09-06 10:49:18 +0800614 snd_soc_component_update_bits(component,
615 WSA881X_SPKR_PROT_FE_GAIN,
616 0x01, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530617 }
618 return 0;
619}
620
Meng Wang15c825d2018-09-06 10:49:18 +0800621static int wsa881x_visense_adc_ctrl(struct snd_soc_component *component,
622 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530623{
624
Meng Wang15c825d2018-09-06 10:49:18 +0800625 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
626 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_V,
627 (0x01 << 7), (enable << 7));
628 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_I,
629 (0x01 << 7), (enable << 7));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530630 return 0;
631}
632
Meng Wang15c825d2018-09-06 10:49:18 +0800633static void wsa881x_bandgap_ctrl(struct snd_soc_component *component,
634 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530635{
Meng Wang15c825d2018-09-06 10:49:18 +0800636 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530637
Meng Wang15c825d2018-09-06 10:49:18 +0800638 dev_dbg(component->dev, "%s: enable:%d, bg_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530639 enable, wsa881x->bg_cnt);
640 mutex_lock(&wsa881x->bg_lock);
641 if (enable) {
642 ++wsa881x->bg_cnt;
643 if (wsa881x->bg_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800644 snd_soc_component_update_bits(component,
645 WSA881X_TEMP_OP,
646 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530647 /* 400usec sleep is needed as per HW requirement */
648 usleep_range(400, 410);
Meng Wang15c825d2018-09-06 10:49:18 +0800649 snd_soc_component_update_bits(component,
650 WSA881X_TEMP_OP,
651 0x04, 0x04);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530652 }
653 } else {
654 --wsa881x->bg_cnt;
655 if (wsa881x->bg_cnt <= 0) {
656 WARN_ON(wsa881x->bg_cnt < 0);
657 wsa881x->bg_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800658 snd_soc_component_update_bits(component,
659 WSA881X_TEMP_OP, 0x04, 0x00);
660 snd_soc_component_update_bits(component,
661 WSA881X_TEMP_OP, 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530662 }
663 }
664 mutex_unlock(&wsa881x->bg_lock);
665}
666
Meng Wang15c825d2018-09-06 10:49:18 +0800667static void wsa881x_clk_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530668{
Meng Wang15c825d2018-09-06 10:49:18 +0800669 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530670
Meng Wang15c825d2018-09-06 10:49:18 +0800671 dev_dbg(component->dev, "%s: enable:%d, clk_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530672 enable, wsa881x->clk_cnt);
673 mutex_lock(&wsa881x->res_lock);
674 if (enable) {
675 ++wsa881x->clk_cnt;
676 if (wsa881x->clk_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800677 snd_soc_component_write(component,
678 WSA881X_CDC_DIG_CLK_CTL, 0x01);
679 snd_soc_component_write(component,
680 WSA881X_CDC_ANA_CLK_CTL, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530681 }
682 } else {
683 --wsa881x->clk_cnt;
684 if (wsa881x->clk_cnt <= 0) {
685 WARN_ON(wsa881x->clk_cnt < 0);
686 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800687 snd_soc_component_write(component,
688 WSA881X_CDC_DIG_CLK_CTL, 0x00);
689 snd_soc_component_write(component,
690 WSA881X_CDC_ANA_CLK_CTL, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530691 }
692 }
693 mutex_unlock(&wsa881x->res_lock);
694}
695
696static int wsa881x_get_compander(struct snd_kcontrol *kcontrol,
697 struct snd_ctl_elem_value *ucontrol)
698{
699
Meng Wang15c825d2018-09-06 10:49:18 +0800700 struct snd_soc_component *component =
701 snd_soc_kcontrol_component(kcontrol);
702 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530703
704 ucontrol->value.integer.value[0] = wsa881x->comp_enable;
705 return 0;
706}
707
708static int wsa881x_set_compander(struct snd_kcontrol *kcontrol,
709 struct snd_ctl_elem_value *ucontrol)
710{
Meng Wang15c825d2018-09-06 10:49:18 +0800711 struct snd_soc_component *component =
712 snd_soc_kcontrol_component(kcontrol);
713 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530714 int value = ucontrol->value.integer.value[0];
715
Meng Wang15c825d2018-09-06 10:49:18 +0800716 dev_dbg(component->dev, "%s: Compander enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530717 __func__, wsa881x->comp_enable, value);
718 wsa881x->comp_enable = value;
719 return 0;
720}
721
722static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
723 struct snd_ctl_elem_value *ucontrol)
724{
725
Meng Wang15c825d2018-09-06 10:49:18 +0800726 struct snd_soc_component *component =
727 snd_soc_kcontrol_component(kcontrol);
728 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530729
730 ucontrol->value.integer.value[0] = wsa881x->boost_enable;
731 return 0;
732}
733
734static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
735 struct snd_ctl_elem_value *ucontrol)
736{
Meng Wang15c825d2018-09-06 10:49:18 +0800737 struct snd_soc_component *component =
738 snd_soc_kcontrol_component(kcontrol);
739 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530740 int value = ucontrol->value.integer.value[0];
741
Meng Wang15c825d2018-09-06 10:49:18 +0800742 dev_dbg(component->dev, "%s: Boost enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530743 __func__, wsa881x->boost_enable, value);
744 wsa881x->boost_enable = value;
745 return 0;
746}
747
748static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
749 struct snd_ctl_elem_value *ucontrol)
750{
751
Meng Wang15c825d2018-09-06 10:49:18 +0800752 struct snd_soc_component *component =
753 snd_soc_kcontrol_component(kcontrol);
754 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530755
756 ucontrol->value.integer.value[0] = wsa881x->visense_enable;
757 return 0;
758}
759
760static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
761 struct snd_ctl_elem_value *ucontrol)
762{
Meng Wang15c825d2018-09-06 10:49:18 +0800763 struct snd_soc_component *component =
764 snd_soc_kcontrol_component(kcontrol);
765 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530766 int value = ucontrol->value.integer.value[0];
767
Meng Wang15c825d2018-09-06 10:49:18 +0800768 dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530769 __func__, wsa881x->visense_enable, value);
770 wsa881x->visense_enable = value;
771 return 0;
772}
773
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800774static int wsa881x_set_boost_level(struct snd_kcontrol *kcontrol,
775 struct snd_ctl_elem_value *ucontrol)
776{
Meng Wang15c825d2018-09-06 10:49:18 +0800777 struct snd_soc_component *component =
778 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800779 u8 wsa_boost_level = 0;
780
Meng Wang15c825d2018-09-06 10:49:18 +0800781 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800782 __func__, ucontrol->value.integer.value[0]);
783
784 wsa_boost_level = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800785 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT1,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800786 0xff, wsa_boost_level);
787
788 return 0;
789}
790
791static int wsa881x_get_boost_level(struct snd_kcontrol *kcontrol,
792 struct snd_ctl_elem_value *ucontrol)
793{
Meng Wang15c825d2018-09-06 10:49:18 +0800794 struct snd_soc_component *component =
795 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800796 u8 wsa_boost_level = 0;
797
Meng Wang15c825d2018-09-06 10:49:18 +0800798 wsa_boost_level = snd_soc_component_read32(component,
799 WSA881X_BOOST_PRESET_OUT1);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800800 ucontrol->value.integer.value[0] = wsa_boost_level;
Meng Wang15c825d2018-09-06 10:49:18 +0800801 dev_dbg(component->dev, "%s: boost level = 0x%x\n", __func__,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800802 wsa_boost_level);
803
804 return 0;
805}
806
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530807static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
808 SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
809 wsa881x_get_compander, wsa881x_set_compander),
810
811 SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
812 wsa881x_get_boost, wsa881x_set_boost),
813
814 SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
815 wsa881x_get_visense, wsa881x_set_visense),
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800816
817 SOC_SINGLE_EXT("Boost Level", SND_SOC_NOPM, 0, 0xff, 0,
818 wsa881x_get_boost_level, wsa881x_set_boost_level),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530819};
820
821static const struct snd_kcontrol_new swr_dac_port[] = {
822 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
823};
824
Meng Wang15c825d2018-09-06 10:49:18 +0800825static int wsa881x_set_port(struct snd_soc_component *component, int port_idx,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530826 u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
827 u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530828{
Meng Wang15c825d2018-09-06 10:49:18 +0800829 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530830
831 *port_id = wsa881x->port[port_idx].port_id;
832 *num_ch = wsa881x->port[port_idx].num_ch;
833 *ch_mask = wsa881x->port[port_idx].ch_mask;
834 *ch_rate = wsa881x->port[port_idx].ch_rate;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530835 *port_type = wsa881x->port[port_idx].port_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530836 return 0;
837}
838
839static int wsa881x_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
840 struct snd_kcontrol *kcontrol, int event)
841{
Meng Wang15c825d2018-09-06 10:49:18 +0800842 struct snd_soc_component *component =
843 snd_soc_dapm_to_component(w->dapm);
844 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530845 u8 port_id[WSA881X_MAX_SWR_PORTS];
846 u8 num_ch[WSA881X_MAX_SWR_PORTS];
847 u8 ch_mask[WSA881X_MAX_SWR_PORTS];
848 u32 ch_rate[WSA881X_MAX_SWR_PORTS];
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530849 u8 port_type[WSA881X_MAX_SWR_PORTS];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530850 u8 num_port = 0;
851
Meng Wang15c825d2018-09-06 10:49:18 +0800852 dev_dbg(component->dev, "%s: event %d name %s\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530853 event, w->name);
854 if (wsa881x == NULL)
855 return -EINVAL;
856
857 switch (event) {
858 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +0800859 wsa881x_set_port(component, SWR_DAC_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530860 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530861 &ch_mask[num_port], &ch_rate[num_port],
862 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530863 ++num_port;
864
865 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800866 wsa881x_set_port(component, SWR_COMP_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530867 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530868 &ch_mask[num_port], &ch_rate[num_port],
869 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530870 ++num_port;
871 }
872 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800873 wsa881x_set_port(component, SWR_BOOST_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530874 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530875 &ch_mask[num_port], &ch_rate[num_port],
876 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530877 ++num_port;
878 }
879 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800880 wsa881x_set_port(component, SWR_VISENSE_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530881 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530882 &ch_mask[num_port], &ch_rate[num_port],
883 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530884 ++num_port;
885 }
886 swr_connect_port(wsa881x->swr_slave, &port_id[0], num_port,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530887 &ch_mask[0], &ch_rate[0], &num_ch[0],
888 &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530889 break;
890 case SND_SOC_DAPM_POST_PMU:
891 break;
892 case SND_SOC_DAPM_PRE_PMD:
893 break;
894 case SND_SOC_DAPM_POST_PMD:
Meng Wang15c825d2018-09-06 10:49:18 +0800895 wsa881x_set_port(component, SWR_DAC_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530896 &port_id[num_port], &num_ch[num_port],
897 &ch_mask[num_port], &ch_rate[num_port],
898 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530899 ++num_port;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530900
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530901 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800902 wsa881x_set_port(component, SWR_COMP_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530903 &port_id[num_port], &num_ch[num_port],
904 &ch_mask[num_port], &ch_rate[num_port],
905 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530906 ++num_port;
907 }
908 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800909 wsa881x_set_port(component, SWR_BOOST_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530910 &port_id[num_port], &num_ch[num_port],
911 &ch_mask[num_port], &ch_rate[num_port],
912 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530913 ++num_port;
914 }
915 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800916 wsa881x_set_port(component, SWR_VISENSE_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530917 &port_id[num_port], &num_ch[num_port],
918 &ch_mask[num_port], &ch_rate[num_port],
919 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530920 ++num_port;
921 }
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530922 swr_disconnect_port(wsa881x->swr_slave, &port_id[0], num_port,
923 &ch_mask[0], &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530924 break;
925 default:
926 break;
927 }
928 return 0;
929}
930
931static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
932 struct snd_kcontrol *kcontrol, int event)
933{
Meng Wang15c825d2018-09-06 10:49:18 +0800934 struct snd_soc_component *component =
935 snd_soc_dapm_to_component(w->dapm);
936 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530937
Meng Wang15c825d2018-09-06 10:49:18 +0800938 dev_dbg(component->dev, "%s: %s %d boost %d visense %d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530939 w->name, event, wsa881x->boost_enable,
940 wsa881x->visense_enable);
941
942 switch (event) {
943 case SND_SOC_DAPM_PRE_PMU:
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530944 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800945 wsa881x_resource_acquire(component, ENABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530946 mutex_unlock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800947 wsa881x_boost_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530948 break;
949 case SND_SOC_DAPM_POST_PMD:
950 swr_slvdev_datapath_control(wsa881x->swr_slave,
951 wsa881x->swr_slave->dev_num,
952 false);
Meng Wang15c825d2018-09-06 10:49:18 +0800953 wsa881x_boost_ctrl(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530954 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800955 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530956 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530957 break;
958 }
959 return 0;
960}
961
Meng Wang15c825d2018-09-06 10:49:18 +0800962static int wsa881x_ramp_pa_gain(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530963 int min_gain, int max_gain, int udelay)
964{
965 int val;
966
967 for (val = min_gain; max_gain <= val; val--) {
Meng Wang15c825d2018-09-06 10:49:18 +0800968 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_GAIN,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530969 0xF0, val << 4);
970 /*
971 * 1ms delay is needed for every step change in gain as per
972 * HW requirement.
973 */
974 usleep_range(udelay, udelay+10);
975 }
976 return 0;
977}
978
979static void wsa881x_ocp_ctl_work(struct work_struct *work)
980{
981 struct wsa881x_priv *wsa881x;
982 struct delayed_work *dwork;
Meng Wang15c825d2018-09-06 10:49:18 +0800983 struct snd_soc_component *component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530984 int temp_val;
985
986 dwork = to_delayed_work(work);
987 wsa881x = container_of(dwork, struct wsa881x_priv, ocp_ctl_work);
988
Prasad Kumpatla71fef462020-01-31 21:38:58 +0530989 if (wsa881x->state == WSA881X_DEV_DOWN)
990 return;
991
Meng Wang15c825d2018-09-06 10:49:18 +0800992 component = wsa881x->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530993 wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
Meng Wang15c825d2018-09-06 10:49:18 +0800994 dev_dbg(component->dev, " temp = %d\n", temp_val);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530995
996 if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
Meng Wang15c825d2018-09-06 10:49:18 +0800997 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
998 0xC0, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530999 else
Meng Wang15c825d2018-09-06 10:49:18 +08001000 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1001 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301002
1003 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1004 msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
1005}
1006
1007static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
1008 struct snd_kcontrol *kcontrol, int event)
1009{
Meng Wang15c825d2018-09-06 10:49:18 +08001010 struct snd_soc_component *component =
1011 snd_soc_dapm_to_component(w->dapm);
1012 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301013 int min_gain, max_gain;
1014
Meng Wang15c825d2018-09-06 10:49:18 +08001015 dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301016 switch (event) {
1017 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +08001018 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1019 0xC0, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301020 regmap_multi_reg_write(wsa881x->regmap,
1021 wsa881x_pre_pmu_pa_2_0,
1022 ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0));
1023 swr_slvdev_datapath_control(wsa881x->swr_slave,
1024 wsa881x->swr_slave->dev_num,
1025 true);
1026 /* Set register mode if compander is not enabled */
1027 if (!wsa881x->comp_enable)
Meng Wang15c825d2018-09-06 10:49:18 +08001028 snd_soc_component_update_bits(component,
1029 WSA881X_SPKR_DRV_GAIN,
1030 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301031 else
Meng Wang15c825d2018-09-06 10:49:18 +08001032 snd_soc_component_update_bits(component,
1033 WSA881X_SPKR_DRV_GAIN,
1034 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301035
1036 break;
1037 case SND_SOC_DAPM_POST_PMU:
Laxminath Kasam069df142019-09-17 23:43:34 +05301038 if (!wsa881x->bolero_dev)
1039 snd_soc_component_update_bits(component,
1040 WSA881X_SPKR_DRV_EN,
1041 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301042 if (!wsa881x->comp_enable) {
1043 max_gain = wsa881x->pa_gain;
1044 /*
1045 * Gain has to set incrementally in 4 steps
1046 * as per HW sequence
1047 */
1048 if (max_gain > G_4P5DB)
1049 min_gain = G_0DB;
1050 else
1051 min_gain = max_gain + 3;
1052 /*
1053 * 1ms delay is needed before change in gain
1054 * as per HW requirement.
1055 */
1056 usleep_range(1000, 1010);
Meng Wang15c825d2018-09-06 10:49:18 +08001057 wsa881x_ramp_pa_gain(component, min_gain, max_gain,
1058 1000);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301059 }
1060 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001061 wsa881x_visense_txfe_ctrl(component, ENABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301062 0x00, 0x03, 0x01);
Meng Wang15c825d2018-09-06 10:49:18 +08001063 snd_soc_component_update_bits(component,
1064 WSA881X_ADC_EN_SEL_IBAIS,
1065 0x07, 0x01);
1066 wsa881x_visense_adc_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301067 }
1068 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1069 msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
1070 /* Force remove group */
1071 swr_remove_from_group(wsa881x->swr_slave,
1072 wsa881x->swr_slave->dev_num);
1073 break;
1074 case SND_SOC_DAPM_POST_PMD:
Laxminath Kasam069df142019-09-17 23:43:34 +05301075 snd_soc_component_update_bits(component,
1076 WSA881X_SPKR_DRV_EN,
1077 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301078 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001079 wsa881x_visense_adc_ctrl(component, DISABLE);
1080 wsa881x_visense_txfe_ctrl(component, DISABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301081 0x00, 0x01, 0x01);
1082 }
1083 cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
Meng Wang15c825d2018-09-06 10:49:18 +08001084 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1085 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301086 break;
1087 }
1088 return 0;
1089}
1090
1091static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
1092 SND_SOC_DAPM_INPUT("IN"),
1093
1094 SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
1095 ARRAY_SIZE(swr_dac_port), wsa881x_enable_swr_dac_port,
1096 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1097 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
1098
1099 SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0,
1100 wsa881x_rdac_event,
1101 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1102
Laxminath Kasam069df142019-09-17 23:43:34 +05301103 SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301104 wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
1105 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1106
1107 SND_SOC_DAPM_OUTPUT("SPKR"),
1108};
1109
1110static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
1111 {"SWR DAC_Port", "Switch", "IN"},
1112 {"RDAC", NULL, "SWR DAC_Port"},
1113 {"SPKR PGA", NULL, "RDAC"},
1114 {"SPKR", NULL, "SPKR PGA"},
1115};
1116
Meng Wang15c825d2018-09-06 10:49:18 +08001117int wsa881x_set_channel_map(struct snd_soc_component *component, u8 *port,
1118 u8 num_port, unsigned int *ch_mask,
1119 unsigned int *ch_rate, u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301120{
Meng Wang15c825d2018-09-06 10:49:18 +08001121 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301122 int i;
1123
1124 if (!port || !ch_mask || !ch_rate ||
1125 (num_port > WSA881X_MAX_SWR_PORTS)) {
Meng Wang15c825d2018-09-06 10:49:18 +08001126 dev_err(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301127 "%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
1128 __func__, port, ch_mask, ch_rate);
1129 return -EINVAL;
1130 }
1131 for (i = 0; i < num_port; i++) {
1132 wsa881x->port[i].port_id = port[i];
1133 wsa881x->port[i].ch_mask = ch_mask[i];
1134 wsa881x->port[i].ch_rate = ch_rate[i];
1135 wsa881x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
Ramprasad Katkame38aed42018-03-07 16:26:49 +05301136 if (port_type)
1137 wsa881x->port[i].port_type = port_type[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301138 }
1139 return 0;
1140}
1141EXPORT_SYMBOL(wsa881x_set_channel_map);
1142
Meng Wang15c825d2018-09-06 10:49:18 +08001143static void wsa881x_init(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301144{
Meng Wang15c825d2018-09-06 10:49:18 +08001145 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301146
Meng Wang15c825d2018-09-06 10:49:18 +08001147 wsa881x->version =
1148 snd_soc_component_read32(component, WSA881X_CHIP_ID1);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301149 wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version);
Vatsal Bucha83716b92017-09-14 12:13:13 +05301150 /* Enable software reset output from soundwire slave */
Meng Wang15c825d2018-09-06 10:49:18 +08001151 snd_soc_component_update_bits(component, WSA881X_SWR_RESET_EN,
1152 0x07, 0x07);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301153 /* Bring out of analog reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001154 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1155 0x02, 0x02);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301156 /* Bring out of digital reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001157 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1158 0x01, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301159
Meng Wang15c825d2018-09-06 10:49:18 +08001160 snd_soc_component_update_bits(component, WSA881X_CLOCK_CONFIG,
1161 0x10, 0x10);
1162 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1163 0x02, 0x02);
1164 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1165 0xC0, 0x80);
1166 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1167 0x06, 0x06);
1168 snd_soc_component_update_bits(component, WSA881X_SPKR_BIAS_INT,
1169 0xFF, 0x00);
1170 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1171 0xF0, 0x40);
1172 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1173 0x0E, 0x0E);
1174 snd_soc_component_update_bits(component, WSA881X_BOOST_LOOP_STABILITY,
1175 0x03, 0x03);
1176 snd_soc_component_update_bits(component, WSA881X_BOOST_MISC2_CTL,
1177 0xFF, 0x14);
1178 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1179 0x80, 0x80);
1180 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1181 0x03, 0x00);
1182 snd_soc_component_update_bits(component,
1183 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1184 0x0C, 0x04);
1185 snd_soc_component_update_bits(component,
1186 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1187 0x03, 0x00);
1188 if (snd_soc_component_read32(component, WSA881X_OTP_REG_0))
1189 snd_soc_component_update_bits(component,
1190 WSA881X_BOOST_PRESET_OUT1,
1191 0xF0, 0x70);
1192 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT2,
1193 0xF0, 0x30);
1194 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
1195 0x08, 0x08);
1196 snd_soc_component_update_bits(component, WSA881X_BOOST_CURRENT_LIMIT,
1197 0x0F, 0x08);
1198 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1199 0x30, 0x30);
1200 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1201 0x0C, 0x00);
1202 snd_soc_component_update_bits(component, WSA881X_OTP_REG_28,
1203 0x3F, 0x3A);
1204 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG1,
1205 0xFF, 0xB2);
1206 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG2,
1207 0xFF, 0x05);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301208}
1209
Meng Wang15c825d2018-09-06 10:49:18 +08001210static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301211 bool enable)
1212{
Meng Wang15c825d2018-09-06 10:49:18 +08001213 wsa881x_clk_ctrl(component, enable);
1214 wsa881x_bandgap_ctrl(component, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301215 return 0;
1216}
1217
Meng Wang15c825d2018-09-06 10:49:18 +08001218static int32_t wsa881x_temp_reg_read(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301219 struct wsa_temp_register *wsa_temp_reg)
1220{
Meng Wang15c825d2018-09-06 10:49:18 +08001221 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301222 struct swr_device *dev;
1223 u8 retry = WSA881X_NUM_RETRY;
1224 u8 devnum = 0;
1225
1226 if (!wsa881x) {
Meng Wang15c825d2018-09-06 10:49:18 +08001227 dev_err(component->dev, "%s: wsa881x is NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301228 return -EINVAL;
1229 }
1230 dev = wsa881x->swr_slave;
1231 if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
1232 while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
1233 retry--) {
1234 /* Retry after 1 msec delay */
1235 usleep_range(1000, 1100);
1236 }
1237 if (retry == 0) {
Meng Wang15c825d2018-09-06 10:49:18 +08001238 dev_err(component->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001239 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301240 __func__, devnum, dev->addr);
1241 return -EINVAL;
1242 }
1243 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301244 wsa881x_regcache_sync(wsa881x);
1245 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001246 wsa881x_resource_acquire(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301247
Meng Wang15c825d2018-09-06 10:49:18 +08001248 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1249 0x01, 0x00);
1250 wsa_temp_reg->dmeas_msb = snd_soc_component_read32(
1251 component, WSA881X_TEMP_MSB);
1252 wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(
1253 component, WSA881X_TEMP_LSB);
1254 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1255 0x01, 0x01);
1256 wsa_temp_reg->d1_msb = snd_soc_component_read32(
1257 component, WSA881X_OTP_REG_1);
1258 wsa_temp_reg->d1_lsb = snd_soc_component_read32(
1259 component, WSA881X_OTP_REG_2);
1260 wsa_temp_reg->d2_msb = snd_soc_component_read32(
1261 component, WSA881X_OTP_REG_3);
1262 wsa_temp_reg->d2_lsb = snd_soc_component_read32(
1263 component, WSA881X_OTP_REG_4);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301264
Meng Wang15c825d2018-09-06 10:49:18 +08001265 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301266 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301267
1268 return 0;
1269}
1270
Meng Wang15c825d2018-09-06 10:49:18 +08001271static int wsa881x_probe(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301272{
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
1276 if (!wsa881x)
1277 return -EINVAL;
Meng Wang15c825d2018-09-06 10:49:18 +08001278 snd_soc_component_init_regmap(component, wsa881x->regmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301279
1280 dev = wsa881x->swr_slave;
Meng Wang15c825d2018-09-06 10:49:18 +08001281 wsa881x->component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301282 mutex_init(&wsa881x->bg_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001283 wsa881x_init(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301284 snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name),
1285 "%s.%x", "wsatz", (u8)dev->addr);
1286 wsa881x->bg_cnt = 0;
1287 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +08001288 wsa881x->tz_pdata.component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301289 wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
1290 wsa881x_init_thermal(&wsa881x->tz_pdata);
Meng Wang15c825d2018-09-06 10:49:18 +08001291 snd_soc_add_component_controls(component, wsa_snd_controls,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301292 ARRAY_SIZE(wsa_snd_controls));
1293 INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
1294 return 0;
1295}
1296
Meng Wang15c825d2018-09-06 10:49:18 +08001297static void wsa881x_remove(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301298{
Meng Wang15c825d2018-09-06 10:49:18 +08001299 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301300
1301 if (wsa881x->tz_pdata.tz_dev)
1302 wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
1303 mutex_destroy(&wsa881x->bg_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301304
Meng Wang15c825d2018-09-06 10:49:18 +08001305 return;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301306}
1307
Meng Wang15c825d2018-09-06 10:49:18 +08001308static const struct snd_soc_component_driver soc_codec_dev_wsa881x = {
1309 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301310 .probe = wsa881x_probe,
1311 .remove = wsa881x_remove,
Meng Wang15c825d2018-09-06 10:49:18 +08001312 .controls = wsa881x_snd_controls,
1313 .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
1314 .dapm_widgets = wsa881x_dapm_widgets,
1315 .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
1316 .dapm_routes = wsa881x_audio_map,
1317 .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301318};
1319
1320static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
1321{
1322 int ret = 0;
1323
1324 if (wsa881x->pd_gpio < 0) {
1325 dev_err(wsa881x->dev, "%s: gpio is not valid %d\n",
1326 __func__, wsa881x->pd_gpio);
1327 return -EINVAL;
1328 }
1329
1330 if (wsa881x->wsa_rst_np) {
1331 if (enable)
1332 ret = msm_cdc_pinctrl_select_active_state(
1333 wsa881x->wsa_rst_np);
1334 else
1335 ret = msm_cdc_pinctrl_select_sleep_state(
1336 wsa881x->wsa_rst_np);
1337 if (ret != 0)
1338 dev_err(wsa881x->dev,
1339 "%s: Failed to turn state %d; ret=%d\n",
1340 __func__, enable, ret);
1341 } else {
1342 if (gpio_is_valid(wsa881x->pd_gpio))
1343 gpio_direction_output(wsa881x->pd_gpio, enable);
1344 }
1345
1346 return ret;
1347}
1348
1349static int wsa881x_gpio_init(struct swr_device *pdev)
1350{
1351 int ret = 0;
1352 struct wsa881x_priv *wsa881x;
1353
1354 wsa881x = swr_get_dev_data(pdev);
1355 if (!wsa881x) {
1356 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1357 return -EINVAL;
1358 }
1359 dev_dbg(&pdev->dev, "%s: gpio %d request with name %s\n",
1360 __func__, wsa881x->pd_gpio, dev_name(&pdev->dev));
1361 ret = gpio_request(wsa881x->pd_gpio, dev_name(&pdev->dev));
1362 if (ret) {
1363 if (ret == -EBUSY) {
1364 /* GPIO was already requested */
1365 dev_dbg(&pdev->dev,
1366 "%s: gpio %d is already set to high\n",
1367 __func__, wsa881x->pd_gpio);
1368 ret = 0;
1369 } else {
1370 dev_err(&pdev->dev, "%s: Failed to request gpio %d, err: %d\n",
1371 __func__, wsa881x->pd_gpio, ret);
1372 }
1373 }
1374 return ret;
1375}
1376
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001377static int wsa881x_event_notify(struct notifier_block *nb,
1378 unsigned long val, void *ptr)
1379{
1380 u16 event = (val & 0xffff);
1381 struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
1382 bolero_nblock);
1383
1384 if (!wsa881x)
1385 return -EINVAL;
1386
1387 switch (event) {
1388 case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
1389 snd_soc_component_update_bits(wsa881x->component,
1390 WSA881X_SPKR_DRV_GAIN,
1391 0xF0, 0xC0);
1392 snd_soc_component_update_bits(wsa881x->component,
1393 WSA881X_SPKR_DRV_EN,
1394 0x80, 0x00);
1395 break;
Laxminath Kasam069df142019-09-17 23:43:34 +05301396 case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
Laxminath Kasam2fe71f52020-05-15 00:39:51 +05301397 case BOLERO_WSA_EVT_PA_ON_POST_FSCLK_ADIE_LB:
Laxminath Kasam069df142019-09-17 23:43:34 +05301398 if ((snd_soc_component_read32(wsa881x->component,
1399 WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
1400 snd_soc_component_update_bits(wsa881x->component,
1401 WSA881X_SPKR_DRV_EN,
1402 0x80, 0x80);
Laxminath Kasamd6b62942019-11-05 12:38:20 +05301403 break;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001404 default:
1405 break;
1406 }
1407
1408 return 0;
1409}
1410
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301411static int wsa881x_swr_probe(struct swr_device *pdev)
1412{
1413 int ret = 0;
1414 struct wsa881x_priv *wsa881x;
1415 u8 devnum = 0;
1416 bool pin_state_current = false;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001417 struct wsa_ctrl_platform_data *plat_data = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301418
1419 wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
1420 GFP_KERNEL);
1421 if (!wsa881x)
1422 return -ENOMEM;
1423 wsa881x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
1424 "qcom,spkr-sd-n-node", 0);
1425 if (!wsa881x->wsa_rst_np) {
1426 dev_dbg(&pdev->dev, "%s: Not using pinctrl, fallback to gpio\n",
1427 __func__);
1428 wsa881x->pd_gpio = of_get_named_gpio(pdev->dev.of_node,
1429 "qcom,spkr-sd-n-gpio", 0);
1430 if (wsa881x->pd_gpio < 0) {
1431 dev_err(&pdev->dev, "%s: %s property is not found %d\n",
1432 __func__, "qcom,spkr-sd-n-gpio",
1433 wsa881x->pd_gpio);
1434 goto err;
1435 }
1436 dev_dbg(&pdev->dev, "%s: reset gpio %d\n", __func__,
1437 wsa881x->pd_gpio);
1438 }
1439 swr_set_dev_data(pdev, wsa881x);
1440
1441 wsa881x->swr_slave = pdev;
1442
1443 if (!wsa881x->wsa_rst_np) {
1444 ret = wsa881x_gpio_init(pdev);
1445 if (ret)
1446 goto err;
1447 }
1448 if (wsa881x->wsa_rst_np)
1449 pin_state_current = msm_cdc_pinctrl_get_state(
1450 wsa881x->wsa_rst_np);
1451 wsa881x_gpio_ctrl(wsa881x, true);
1452 wsa881x->state = WSA881X_DEV_UP;
1453
1454 if (!debugfs_wsa881x_dent) {
1455 dbgwsa881x = wsa881x;
1456 debugfs_wsa881x_dent = debugfs_create_dir(
1457 "wsa881x_swr_slave", 0);
1458 if (!IS_ERR(debugfs_wsa881x_dent)) {
1459 debugfs_peek = debugfs_create_file("swrslave_peek",
1460 S_IFREG | 0444, debugfs_wsa881x_dent,
1461 (void *) "swrslave_peek",
1462 &codec_debug_ops);
1463
1464 debugfs_poke = debugfs_create_file("swrslave_poke",
1465 S_IFREG | 0444, debugfs_wsa881x_dent,
1466 (void *) "swrslave_poke",
1467 &codec_debug_ops);
1468
1469 debugfs_reg_dump = debugfs_create_file(
1470 "swrslave_reg_dump",
1471 S_IFREG | 0444,
1472 debugfs_wsa881x_dent,
1473 (void *) "swrslave_reg_dump",
1474 &codec_debug_ops);
1475 }
1476 }
1477
1478 /*
1479 * Add 5msec delay to provide sufficient time for
1480 * soundwire auto enumeration of slave devices as
1481 * as per HW requirement.
1482 */
1483 usleep_range(5000, 5010);
1484 ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
1485 if (ret) {
1486 dev_dbg(&pdev->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001487 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301488 __func__, devnum, pdev->addr);
1489 goto dev_err;
1490 }
1491 pdev->dev_num = devnum;
1492
1493 wsa881x->regmap = devm_regmap_init_swr(pdev,
1494 &wsa881x_regmap_config);
1495 if (IS_ERR(wsa881x->regmap)) {
1496 ret = PTR_ERR(wsa881x->regmap);
1497 dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
1498 __func__, ret);
1499 goto dev_err;
1500 }
1501
Meng Wang15c825d2018-09-06 10:49:18 +08001502 ret = snd_soc_register_component(&pdev->dev, &soc_codec_dev_wsa881x,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301503 NULL, 0);
1504 if (ret) {
1505 dev_err(&pdev->dev, "%s: Codec registration failed\n",
1506 __func__);
1507 goto dev_err;
1508 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001509
1510 wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
1511 "qcom,bolero-handle", 0);
1512 if (wsa881x->bolero_np) {
1513 wsa881x->bolero_dev =
1514 of_find_device_by_node(wsa881x->bolero_np);
1515 if (wsa881x->bolero_dev) {
1516 plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
1517 if (plat_data) {
1518 wsa881x->bolero_nblock.notifier_call =
1519 wsa881x_event_notify;
1520 if (plat_data->register_notifier)
1521 plat_data->register_notifier(
1522 plat_data->handle,
1523 &wsa881x->bolero_nblock,
1524 true);
1525 wsa881x->register_notifier =
1526 plat_data->register_notifier;
1527 wsa881x->handle = plat_data->handle;
1528 } else {
1529 dev_err(&pdev->dev, "%s: plat data not found\n",
1530 __func__);
1531 }
1532 } else {
1533 dev_err(&pdev->dev, "%s: bolero dev not found\n",
1534 __func__);
1535 }
1536 } else {
1537 dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
1538 }
1539
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301540 mutex_init(&wsa881x->res_lock);
1541 mutex_init(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301542
1543 return 0;
1544
1545dev_err:
1546 if (pin_state_current == false)
1547 wsa881x_gpio_ctrl(wsa881x, false);
1548 swr_remove_device(pdev);
1549err:
1550 return ret;
1551}
1552
1553static int wsa881x_swr_remove(struct swr_device *pdev)
1554{
1555 struct wsa881x_priv *wsa881x;
1556
1557 wsa881x = swr_get_dev_data(pdev);
1558 if (!wsa881x) {
1559 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1560 return -EINVAL;
1561 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001562
1563 if (wsa881x->register_notifier)
1564 wsa881x->register_notifier(wsa881x->handle,
1565 &wsa881x->bolero_nblock, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301566 debugfs_remove_recursive(debugfs_wsa881x_dent);
1567 debugfs_wsa881x_dent = NULL;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301568 mutex_destroy(&wsa881x->res_lock);
1569 mutex_destroy(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001570 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301571 if (wsa881x->pd_gpio)
1572 gpio_free(wsa881x->pd_gpio);
1573 swr_set_dev_data(pdev, NULL);
1574 return 0;
1575}
1576
1577static int wsa881x_swr_up(struct swr_device *pdev)
1578{
1579 int ret;
1580 struct wsa881x_priv *wsa881x;
1581
1582 wsa881x = swr_get_dev_data(pdev);
1583 if (!wsa881x) {
1584 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1585 return -EINVAL;
1586 }
1587 ret = wsa881x_gpio_ctrl(wsa881x, true);
1588 if (ret)
1589 dev_err(&pdev->dev, "%s: Failed to enable gpio\n", __func__);
1590 else
1591 wsa881x->state = WSA881X_DEV_UP;
1592
1593 return ret;
1594}
1595
1596static int wsa881x_swr_down(struct swr_device *pdev)
1597{
1598 struct wsa881x_priv *wsa881x;
1599 int ret;
1600
1601 wsa881x = swr_get_dev_data(pdev);
1602 if (!wsa881x) {
1603 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1604 return -EINVAL;
1605 }
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301606 ret = wsa881x_gpio_ctrl(wsa881x, false);
1607 if (ret)
1608 dev_err(&pdev->dev, "%s: Failed to disable gpio\n", __func__);
1609 else
1610 wsa881x->state = WSA881X_DEV_DOWN;
1611
Prasad Kumpatla71fef462020-01-31 21:38:58 +05301612 if (delayed_work_pending(&wsa881x->ocp_ctl_work))
1613 cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301614 return ret;
1615}
1616
1617static int wsa881x_swr_reset(struct swr_device *pdev)
1618{
1619 struct wsa881x_priv *wsa881x;
1620 u8 retry = WSA881X_NUM_RETRY;
1621 u8 devnum = 0;
1622
1623 wsa881x = swr_get_dev_data(pdev);
1624 if (!wsa881x) {
1625 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1626 return -EINVAL;
1627 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301628 if (wsa881x->state == WSA881X_DEV_READY) {
1629 dev_dbg(&pdev->dev, "%s: device already active\n", __func__);
1630 return 0;
1631 }
1632
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301633 wsa881x->bg_cnt = 0;
1634 wsa881x->clk_cnt = 0;
1635 while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
1636 /* Retry after 1 msec delay */
1637 usleep_range(1000, 1100);
1638 }
1639 pdev->dev_num = devnum;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301640 wsa881x_regcache_sync(wsa881x);
1641
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301642 return 0;
1643}
1644
1645#ifdef CONFIG_PM_SLEEP
1646static int wsa881x_swr_suspend(struct device *dev)
1647{
1648 dev_dbg(dev, "%s: system suspend\n", __func__);
1649 return 0;
1650}
1651
1652static int wsa881x_swr_resume(struct device *dev)
1653{
1654 struct wsa881x_priv *wsa881x = swr_get_dev_data(to_swr_device(dev));
1655
1656 if (!wsa881x) {
1657 dev_err(dev, "%s: wsa881x private data is NULL\n", __func__);
1658 return -EINVAL;
1659 }
1660 dev_dbg(dev, "%s: system resume\n", __func__);
1661 return 0;
1662}
1663#endif /* CONFIG_PM_SLEEP */
1664
1665static const struct dev_pm_ops wsa881x_swr_pm_ops = {
1666 SET_SYSTEM_SLEEP_PM_OPS(wsa881x_swr_suspend, wsa881x_swr_resume)
1667};
1668
1669static const struct swr_device_id wsa881x_swr_id[] = {
1670 {"wsa881x", 0},
1671 {}
1672};
1673
1674static const struct of_device_id wsa881x_swr_dt_match[] = {
1675 {
1676 .compatible = "qcom,wsa881x",
1677 },
1678 {}
1679};
1680
1681static struct swr_driver wsa881x_codec_driver = {
1682 .driver = {
1683 .name = "wsa881x",
1684 .owner = THIS_MODULE,
1685 .pm = &wsa881x_swr_pm_ops,
1686 .of_match_table = wsa881x_swr_dt_match,
1687 },
1688 .probe = wsa881x_swr_probe,
1689 .remove = wsa881x_swr_remove,
1690 .id_table = wsa881x_swr_id,
1691 .device_up = wsa881x_swr_up,
1692 .device_down = wsa881x_swr_down,
1693 .reset_device = wsa881x_swr_reset,
1694};
1695
1696static int __init wsa881x_codec_init(void)
1697{
1698 return swr_driver_register(&wsa881x_codec_driver);
1699}
1700
1701static void __exit wsa881x_codec_exit(void)
1702{
1703 swr_driver_unregister(&wsa881x_codec_driver);
1704}
1705
1706module_init(wsa881x_codec_init);
1707module_exit(wsa881x_codec_exit);
1708
1709MODULE_DESCRIPTION("WSA881x Codec driver");
1710MODULE_LICENSE("GPL v2");