blob: 11d5c3f8e37d8e6f8274538e750bd3311c3baf91 [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,
Karthikeyan Mani13485b72019-08-05 17:51:14 -0700121};
122
123struct wsa_ctrl_platform_data {
124 void *handle;
125 int (*update_wsa_event)(void *handle, u16 event, u32 data);
126 int (*register_notifier)(void *handle,
127 struct notifier_block *nblock,
128 bool enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530129};
130
131#define SWR_SLV_MAX_REG_ADDR 0x390
132#define SWR_SLV_START_REG_ADDR 0x40
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530133#define SWR_SLV_MAX_BUF_LEN 25
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530134#define BYTES_PER_LINE 12
135#define SWR_SLV_RD_BUF_LEN 8
136#define SWR_SLV_WR_BUF_LEN 32
137#define SWR_SLV_MAX_DEVICES 2
138
139#define WSA881X_VERSION_ENTRY_SIZE 27
140#define WSA881X_OCP_CTL_TIMER_SEC 2
141#define WSA881X_OCP_CTL_TEMP_CELSIUS 25
142#define WSA881X_OCP_CTL_POLL_TIMER_SEC 60
143
144static int wsa881x_ocp_poll_timer_sec = WSA881X_OCP_CTL_POLL_TIMER_SEC;
145module_param(wsa881x_ocp_poll_timer_sec, int, 0664);
146MODULE_PARM_DESC(wsa881x_ocp_poll_timer_sec, "timer for ocp ctl polling");
147
148static struct wsa881x_priv *dbgwsa881x;
149static struct dentry *debugfs_wsa881x_dent;
150static struct dentry *debugfs_peek;
151static struct dentry *debugfs_poke;
152static struct dentry *debugfs_reg_dump;
153static unsigned int read_data;
154static unsigned int devnum;
155
Meng Wang15c825d2018-09-06 10:49:18 +0800156static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530157 bool enable);
158
159static const char * const wsa_pa_gain_text[] = {
160 "G_18_DB", "G_16P5_DB", "G_15_DB", "G_13P5_DB", "G_12_DB", "G_10P5_DB",
161 "G_9_DB", "G_7P5_DB", "G_6_DB", "G_4P5_DB", "G_3_DB", "G_1P5_DB",
162 "G_0_DB"
163};
164
165static const struct soc_enum wsa_pa_gain_enum =
166 SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(wsa_pa_gain_text), wsa_pa_gain_text);
167
168static int wsa_pa_gain_get(struct snd_kcontrol *kcontrol,
169 struct snd_ctl_elem_value *ucontrol)
170{
Meng Wang15c825d2018-09-06 10:49:18 +0800171 struct snd_soc_component *component =
172 snd_soc_kcontrol_component(kcontrol);
173 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530174
175 ucontrol->value.integer.value[0] = wsa881x->pa_gain;
176
Meng Wang15c825d2018-09-06 10:49:18 +0800177 dev_dbg(component->dev, "%s: PA gain = 0x%x\n", __func__,
178 wsa881x->pa_gain);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530179
180 return 0;
181}
182
183static int wsa_pa_gain_put(struct snd_kcontrol *kcontrol,
184 struct snd_ctl_elem_value *ucontrol)
185{
Meng Wang15c825d2018-09-06 10:49:18 +0800186 struct snd_soc_component *component =
187 snd_soc_kcontrol_component(kcontrol);
188 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530189
Meng Wang15c825d2018-09-06 10:49:18 +0800190 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530191 __func__, ucontrol->value.integer.value[0]);
192
193 wsa881x->pa_gain = ucontrol->value.integer.value[0];
194
195 return 0;
196}
197
198static int wsa881x_get_mute(struct snd_kcontrol *kcontrol,
199 struct snd_ctl_elem_value *ucontrol)
200{
201
Meng Wang15c825d2018-09-06 10:49:18 +0800202 struct snd_soc_component *component =
203 snd_soc_kcontrol_component(kcontrol);
204 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530205
206 ucontrol->value.integer.value[0] = wsa881x->pa_mute;
207
208 return 0;
209}
210
211static int wsa881x_set_mute(struct snd_kcontrol *kcontrol,
212 struct snd_ctl_elem_value *ucontrol)
213{
Meng Wang15c825d2018-09-06 10:49:18 +0800214 struct snd_soc_component *component =
215 snd_soc_kcontrol_component(kcontrol);
216 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530217 int value = ucontrol->value.integer.value[0];
218
Meng Wang15c825d2018-09-06 10:49:18 +0800219 dev_dbg(component->dev, "%s: mute current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530220 __func__, wsa881x->pa_mute, value);
221
222 if (value)
Meng Wang15c825d2018-09-06 10:49:18 +0800223 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
224 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530225 wsa881x->pa_mute = value;
226
227 return 0;
228}
229
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530230static int wsa881x_get_t0_init(struct snd_kcontrol *kcontrol,
231 struct snd_ctl_elem_value *ucontrol)
232{
233
Meng Wang15c825d2018-09-06 10:49:18 +0800234 struct snd_soc_component *component =
235 snd_soc_kcontrol_component(kcontrol);
236 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530237 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
238
239 ucontrol->value.integer.value[0] = pdata->t0_init;
Meng Wang15c825d2018-09-06 10:49:18 +0800240 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530241
242 return 0;
243}
244
245static int wsa881x_set_t0_init(struct snd_kcontrol *kcontrol,
246 struct snd_ctl_elem_value *ucontrol)
247{
Meng Wang15c825d2018-09-06 10:49:18 +0800248 struct snd_soc_component *component =
249 snd_soc_kcontrol_component(kcontrol);
250 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530251 struct wsa881x_tz_priv *pdata = &wsa881x->tz_pdata;
252
253 pdata->t0_init = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800254 dev_dbg(component->dev, "%s: t0 init %d\n", __func__, pdata->t0_init);
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530255
256 return 0;
257}
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530258
259static const struct snd_kcontrol_new wsa_snd_controls[] = {
260 SOC_ENUM_EXT("WSA PA Gain", wsa_pa_gain_enum,
261 wsa_pa_gain_get, wsa_pa_gain_put),
262 SOC_SINGLE_EXT("WSA PA Mute", SND_SOC_NOPM, 0, 1, 0,
263 wsa881x_get_mute, wsa881x_set_mute),
Sudheer Papothic9dd3be2018-04-06 00:51:48 +0530264 SOC_SINGLE_EXT("WSA T0 Init", SND_SOC_NOPM, 0, 1, 0,
265 wsa881x_get_t0_init, wsa881x_set_t0_init),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530266};
267
268static int codec_debug_open(struct inode *inode, struct file *file)
269{
270 file->private_data = inode->i_private;
271 return 0;
272}
273
274static int get_parameters(char *buf, u32 *param1, int num_of_par)
275{
276 char *token;
277 int base, cnt;
278
279 token = strsep(&buf, " ");
280 for (cnt = 0; cnt < num_of_par; cnt++) {
281 if (token) {
282 if ((token[1] == 'x') || (token[1] == 'X'))
283 base = 16;
284 else
285 base = 10;
286
287 if (kstrtou32(token, base, &param1[cnt]) != 0)
288 return -EINVAL;
289
290 token = strsep(&buf, " ");
291 } else
292 return -EINVAL;
293 }
294 return 0;
295}
296
297static ssize_t wsa881x_codec_version_read(struct snd_info_entry *entry,
298 void *file_private_data, struct file *file,
299 char __user *buf, size_t count, loff_t pos)
300{
301 struct wsa881x_priv *wsa881x;
302 char buffer[WSA881X_VERSION_ENTRY_SIZE];
303 int len;
304
305 wsa881x = (struct wsa881x_priv *) entry->private_data;
306 if (!wsa881x) {
307 pr_err("%s: wsa881x priv is null\n", __func__);
308 return -EINVAL;
309 }
310
311 len = snprintf(buffer, sizeof(buffer), "WSA881X-SOUNDWIRE_2_0\n");
312
313 return simple_read_from_buffer(buf, count, &pos, buffer, len);
314}
315
316static struct snd_info_entry_ops wsa881x_codec_info_ops = {
317 .read = wsa881x_codec_version_read,
318};
319
320/*
321 * wsa881x_codec_info_create_codec_entry - creates wsa881x module
322 * @codec_root: The parent directory
Meng Wang15c825d2018-09-06 10:49:18 +0800323 * @component: Codec instance
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530324 *
325 * Creates wsa881x module and version entry under the given
326 * parent directory.
327 *
328 * Return: 0 on success or negative error code on failure.
329 */
330int wsa881x_codec_info_create_codec_entry(struct snd_info_entry *codec_root,
Meng Wang15c825d2018-09-06 10:49:18 +0800331 struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530332{
333 struct snd_info_entry *version_entry;
334 struct wsa881x_priv *wsa881x;
335 struct snd_soc_card *card;
336 char name[80];
337
Meng Wang15c825d2018-09-06 10:49:18 +0800338 if (!codec_root || !component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530339 return -EINVAL;
340
Meng Wang15c825d2018-09-06 10:49:18 +0800341 wsa881x = snd_soc_component_get_drvdata(component);
342 card = component->card;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530343 snprintf(name, sizeof(name), "%s.%x", "wsa881x",
344 (u32)wsa881x->swr_slave->addr);
345
346 wsa881x->entry = snd_info_create_subdir(codec_root->module,
347 (const char *)name,
348 codec_root);
349 if (!wsa881x->entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800350 dev_dbg(component->dev, "%s: failed to create wsa881x entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530351 __func__);
352 return -ENOMEM;
353 }
354
355 version_entry = snd_info_create_card_entry(card->snd_card,
356 "version",
357 wsa881x->entry);
358 if (!version_entry) {
Meng Wang15c825d2018-09-06 10:49:18 +0800359 dev_dbg(component->dev, "%s: failed to create wsa881x version entry\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530360 __func__);
361 return -ENOMEM;
362 }
363
364 version_entry->private_data = wsa881x;
365 version_entry->size = WSA881X_VERSION_ENTRY_SIZE;
366 version_entry->content = SNDRV_INFO_CONTENT_DATA;
367 version_entry->c.ops = &wsa881x_codec_info_ops;
368
369 if (snd_info_register(version_entry) < 0) {
370 snd_info_free_entry(version_entry);
371 return -ENOMEM;
372 }
373 wsa881x->version_entry = version_entry;
374
375 return 0;
376}
377EXPORT_SYMBOL(wsa881x_codec_info_create_codec_entry);
378
379static bool is_swr_slv_reg_readable(int reg)
380{
381 bool ret = true;
382
383 if (((reg > 0x46) && (reg < 0x4A)) ||
384 ((reg > 0x4A) && (reg < 0x50)) ||
385 ((reg > 0x55) && (reg < 0xE0)) ||
386 ((reg > 0xE0) && (reg < 0xF0)) ||
387 ((reg > 0xF0) && (reg < 0x100)) ||
388 ((reg > 0x105) && (reg < 0x120)) ||
389 ((reg > 0x128) && (reg < 0x130)) ||
390 ((reg > 0x138) && (reg < 0x200)) ||
391 ((reg > 0x205) && (reg < 0x220)) ||
392 ((reg > 0x228) && (reg < 0x230)) ||
393 ((reg > 0x238) && (reg < 0x300)) ||
394 ((reg > 0x305) && (reg < 0x320)) ||
395 ((reg > 0x328) && (reg < 0x330)) ||
396 ((reg > 0x338) && (reg < 0x400)) ||
397 ((reg > 0x405) && (reg < 0x420)))
398 ret = false;
399
400 return ret;
401}
402
403static ssize_t wsa881x_swrslave_reg_show(char __user *ubuf, size_t count,
404 loff_t *ppos)
405{
406 int i, reg_val, len;
407 ssize_t total = 0;
408 char tmp_buf[SWR_SLV_MAX_BUF_LEN];
409
410 if (!ubuf || !ppos || (devnum == 0))
411 return 0;
412
413 for (i = (((int) *ppos / BYTES_PER_LINE) + SWR_SLV_START_REG_ADDR);
414 i <= SWR_SLV_MAX_REG_ADDR; i++) {
415 if (!is_swr_slv_reg_readable(i))
416 continue;
417 swr_read(dbgwsa881x->swr_slave, devnum,
418 i, &reg_val, 1);
419 len = snprintf(tmp_buf, 25, "0x%.3x: 0x%.2x\n", i,
420 (reg_val & 0xFF));
Aditya Bavanari8aacfcf2019-06-21 15:56:39 +0530421 if (len < 0) {
422 pr_err("%s: fail to fill the buffer\n", __func__);
423 total = -EFAULT;
424 goto copy_err;
425 }
426
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530427 if ((total + len) >= count - 1)
428 break;
429 if (copy_to_user((ubuf + total), tmp_buf, len)) {
430 pr_err("%s: fail to copy reg dump\n", __func__);
431 total = -EFAULT;
432 goto copy_err;
433 }
434 *ppos += len;
435 total += len;
436 }
437
438copy_err:
439 return total;
440}
441
442static ssize_t codec_debug_read(struct file *file, char __user *ubuf,
443 size_t count, loff_t *ppos)
444{
445 char lbuf[SWR_SLV_RD_BUF_LEN];
446 char *access_str;
447 ssize_t ret_cnt;
448
449 if (!count || !file || !ppos || !ubuf)
450 return -EINVAL;
451
452 access_str = file->private_data;
453 if (*ppos < 0)
454 return -EINVAL;
455
456 if (!strcmp(access_str, "swrslave_peek")) {
457 snprintf(lbuf, sizeof(lbuf), "0x%x\n", (read_data & 0xFF));
458 ret_cnt = simple_read_from_buffer(ubuf, count, ppos, lbuf,
459 strnlen(lbuf, 7));
460 } else if (!strcmp(access_str, "swrslave_reg_dump")) {
461 ret_cnt = wsa881x_swrslave_reg_show(ubuf, count, ppos);
462 } else {
463 pr_err("%s: %s not permitted to read\n", __func__, access_str);
464 ret_cnt = -EPERM;
465 }
466 return ret_cnt;
467}
468
469static ssize_t codec_debug_write(struct file *filp,
470 const char __user *ubuf, size_t cnt, loff_t *ppos)
471{
472 char lbuf[SWR_SLV_WR_BUF_LEN];
473 int rc;
474 u32 param[5];
475 char *access_str;
476
477 if (!filp || !ppos || !ubuf)
478 return -EINVAL;
479
480 access_str = filp->private_data;
481 if (cnt > sizeof(lbuf) - 1)
482 return -EINVAL;
483
484 rc = copy_from_user(lbuf, ubuf, cnt);
485 if (rc)
486 return -EFAULT;
487
488 lbuf[cnt] = '\0';
489 if (!strcmp(access_str, "swrslave_poke")) {
490 /* write */
491 rc = get_parameters(lbuf, param, 3);
492 if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (param[1] <= 0xFF) &&
493 (rc == 0))
494 swr_write(dbgwsa881x->swr_slave, param[2],
495 param[0], &param[1]);
496 else
497 rc = -EINVAL;
498 } else if (!strcmp(access_str, "swrslave_peek")) {
499 /* read */
500 rc = get_parameters(lbuf, param, 2);
501 if ((param[0] <= SWR_SLV_MAX_REG_ADDR) && (rc == 0))
502 swr_read(dbgwsa881x->swr_slave, param[1],
503 param[0], &read_data, 1);
504 else
505 rc = -EINVAL;
506 } else if (!strcmp(access_str, "swrslave_reg_dump")) {
507 /* reg dump */
508 rc = get_parameters(lbuf, param, 1);
509 if ((rc == 0) && (param[0] > 0) &&
510 (param[0] <= SWR_SLV_MAX_DEVICES))
511 devnum = param[0];
512 else
513 rc = -EINVAL;
514 }
515 if (rc == 0)
516 rc = cnt;
517 else
518 pr_err("%s: rc = %d\n", __func__, rc);
519
520 return rc;
521}
522
523static const struct file_operations codec_debug_ops = {
524 .open = codec_debug_open,
525 .write = codec_debug_write,
526 .read = codec_debug_read,
527};
528
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530529static void wsa881x_regcache_sync(struct wsa881x_priv *wsa881x)
530{
531 mutex_lock(&wsa881x->res_lock);
532 if (wsa881x->state != WSA881X_DEV_READY) {
533 regcache_mark_dirty(wsa881x->regmap);
534 regcache_sync(wsa881x->regmap);
535 wsa881x->state = WSA881X_DEV_READY;
536 }
537 mutex_unlock(&wsa881x->res_lock);
538}
539
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530540static const struct reg_sequence wsa881x_pre_pmu_pa[] = {
541 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
542 {WSA881X_SPKR_MISC_CTL1, 0x01, 0},
543 {WSA881X_ADC_EN_DET_TEST_I, 0x01, 0},
544 {WSA881X_ADC_EN_MODU_V, 0x02, 0},
545 {WSA881X_ADC_EN_DET_TEST_V, 0x10, 0},
546 {WSA881X_SPKR_PWRSTG_DBG, 0xA0, 0},
547};
548
549static const struct reg_sequence wsa881x_pre_pmu_pa_2_0[] = {
550 {WSA881X_SPKR_DRV_GAIN, 0x41, 0},
551 {WSA881X_SPKR_MISC_CTL1, 0x87, 0},
552};
553
554static const struct reg_sequence wsa881x_post_pmu_pa[] = {
555 {WSA881X_SPKR_PWRSTG_DBG, 0x00, 0},
556 {WSA881X_ADC_EN_DET_TEST_V, 0x00, 0},
557 {WSA881X_ADC_EN_MODU_V, 0x00, 0},
558 {WSA881X_ADC_EN_DET_TEST_I, 0x00, 0},
559};
560
561static const struct reg_sequence wsa881x_vi_txfe_en[] = {
562 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
563 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
564 {WSA881X_SPKR_PROT_FE_GAIN, 0xCF, 0},
565};
566
567static const struct reg_sequence wsa881x_vi_txfe_en_2_0[] = {
568 {WSA881X_SPKR_PROT_FE_VSENSE_VCM, 0x85, 0},
569 {WSA881X_SPKR_PROT_ATEST2, 0x0A, 0},
570 {WSA881X_SPKR_PROT_FE_GAIN, 0x47, 0},
571};
572
Meng Wang15c825d2018-09-06 10:49:18 +0800573static int wsa881x_boost_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530574{
Meng Wang15c825d2018-09-06 10:49:18 +0800575 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530576 if (enable)
Meng Wang15c825d2018-09-06 10:49:18 +0800577 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
578 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530579 else
Meng Wang15c825d2018-09-06 10:49:18 +0800580 snd_soc_component_update_bits(component, WSA881X_BOOST_EN_CTL,
581 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530582 /*
583 * 1.5ms sleep is needed after boost enable/disable as per
584 * HW requirement
585 */
586 usleep_range(1500, 1510);
587 return 0;
588}
589
Meng Wang15c825d2018-09-06 10:49:18 +0800590static int wsa881x_visense_txfe_ctrl(struct snd_soc_component *component,
591 bool enable, u8 isense1_gain,
592 u8 isense2_gain, u8 vsense_gain)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530593{
Meng Wang15c825d2018-09-06 10:49:18 +0800594 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530595
Meng Wang15c825d2018-09-06 10:49:18 +0800596 dev_dbg(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530597 "%s: enable:%d, isense1 gain: %d, isense2 gain: %d, vsense_gain %d\n",
598 __func__, enable, isense1_gain, isense2_gain, vsense_gain);
599
600 if (enable) {
601 regmap_multi_reg_write(wsa881x->regmap,
602 wsa881x_vi_txfe_en_2_0,
603 ARRAY_SIZE(wsa881x_vi_txfe_en_2_0));
604 } else {
Meng Wang15c825d2018-09-06 10:49:18 +0800605 snd_soc_component_update_bits(component,
606 WSA881X_SPKR_PROT_FE_VSENSE_VCM,
607 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530608 /*
609 * 200us sleep is needed after visense txfe disable as per
610 * HW requirement.
611 */
612 usleep_range(200, 210);
Meng Wang15c825d2018-09-06 10:49:18 +0800613 snd_soc_component_update_bits(component,
614 WSA881X_SPKR_PROT_FE_GAIN,
615 0x01, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530616 }
617 return 0;
618}
619
Meng Wang15c825d2018-09-06 10:49:18 +0800620static int wsa881x_visense_adc_ctrl(struct snd_soc_component *component,
621 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530622{
623
Meng Wang15c825d2018-09-06 10:49:18 +0800624 dev_dbg(component->dev, "%s: enable:%d\n", __func__, enable);
625 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_V,
626 (0x01 << 7), (enable << 7));
627 snd_soc_component_update_bits(component, WSA881X_ADC_EN_MODU_I,
628 (0x01 << 7), (enable << 7));
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530629 return 0;
630}
631
Meng Wang15c825d2018-09-06 10:49:18 +0800632static void wsa881x_bandgap_ctrl(struct snd_soc_component *component,
633 bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530634{
Meng Wang15c825d2018-09-06 10:49:18 +0800635 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530636
Meng Wang15c825d2018-09-06 10:49:18 +0800637 dev_dbg(component->dev, "%s: enable:%d, bg_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530638 enable, wsa881x->bg_cnt);
639 mutex_lock(&wsa881x->bg_lock);
640 if (enable) {
641 ++wsa881x->bg_cnt;
642 if (wsa881x->bg_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800643 snd_soc_component_update_bits(component,
644 WSA881X_TEMP_OP,
645 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530646 /* 400usec sleep is needed as per HW requirement */
647 usleep_range(400, 410);
Meng Wang15c825d2018-09-06 10:49:18 +0800648 snd_soc_component_update_bits(component,
649 WSA881X_TEMP_OP,
650 0x04, 0x04);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530651 }
652 } else {
653 --wsa881x->bg_cnt;
654 if (wsa881x->bg_cnt <= 0) {
655 WARN_ON(wsa881x->bg_cnt < 0);
656 wsa881x->bg_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800657 snd_soc_component_update_bits(component,
658 WSA881X_TEMP_OP, 0x04, 0x00);
659 snd_soc_component_update_bits(component,
660 WSA881X_TEMP_OP, 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530661 }
662 }
663 mutex_unlock(&wsa881x->bg_lock);
664}
665
Meng Wang15c825d2018-09-06 10:49:18 +0800666static void wsa881x_clk_ctrl(struct snd_soc_component *component, bool enable)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530667{
Meng Wang15c825d2018-09-06 10:49:18 +0800668 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530669
Meng Wang15c825d2018-09-06 10:49:18 +0800670 dev_dbg(component->dev, "%s: enable:%d, clk_count:%d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530671 enable, wsa881x->clk_cnt);
672 mutex_lock(&wsa881x->res_lock);
673 if (enable) {
674 ++wsa881x->clk_cnt;
675 if (wsa881x->clk_cnt == 1) {
Meng Wang15c825d2018-09-06 10:49:18 +0800676 snd_soc_component_write(component,
677 WSA881X_CDC_DIG_CLK_CTL, 0x01);
678 snd_soc_component_write(component,
679 WSA881X_CDC_ANA_CLK_CTL, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530680 }
681 } else {
682 --wsa881x->clk_cnt;
683 if (wsa881x->clk_cnt <= 0) {
684 WARN_ON(wsa881x->clk_cnt < 0);
685 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +0800686 snd_soc_component_write(component,
687 WSA881X_CDC_DIG_CLK_CTL, 0x00);
688 snd_soc_component_write(component,
689 WSA881X_CDC_ANA_CLK_CTL, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530690 }
691 }
692 mutex_unlock(&wsa881x->res_lock);
693}
694
695static int wsa881x_get_compander(struct snd_kcontrol *kcontrol,
696 struct snd_ctl_elem_value *ucontrol)
697{
698
Meng Wang15c825d2018-09-06 10:49:18 +0800699 struct snd_soc_component *component =
700 snd_soc_kcontrol_component(kcontrol);
701 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530702
703 ucontrol->value.integer.value[0] = wsa881x->comp_enable;
704 return 0;
705}
706
707static int wsa881x_set_compander(struct snd_kcontrol *kcontrol,
708 struct snd_ctl_elem_value *ucontrol)
709{
Meng Wang15c825d2018-09-06 10:49:18 +0800710 struct snd_soc_component *component =
711 snd_soc_kcontrol_component(kcontrol);
712 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530713 int value = ucontrol->value.integer.value[0];
714
Meng Wang15c825d2018-09-06 10:49:18 +0800715 dev_dbg(component->dev, "%s: Compander enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530716 __func__, wsa881x->comp_enable, value);
717 wsa881x->comp_enable = value;
718 return 0;
719}
720
721static int wsa881x_get_boost(struct snd_kcontrol *kcontrol,
722 struct snd_ctl_elem_value *ucontrol)
723{
724
Meng Wang15c825d2018-09-06 10:49:18 +0800725 struct snd_soc_component *component =
726 snd_soc_kcontrol_component(kcontrol);
727 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530728
729 ucontrol->value.integer.value[0] = wsa881x->boost_enable;
730 return 0;
731}
732
733static int wsa881x_set_boost(struct snd_kcontrol *kcontrol,
734 struct snd_ctl_elem_value *ucontrol)
735{
Meng Wang15c825d2018-09-06 10:49:18 +0800736 struct snd_soc_component *component =
737 snd_soc_kcontrol_component(kcontrol);
738 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530739 int value = ucontrol->value.integer.value[0];
740
Meng Wang15c825d2018-09-06 10:49:18 +0800741 dev_dbg(component->dev, "%s: Boost enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530742 __func__, wsa881x->boost_enable, value);
743 wsa881x->boost_enable = value;
744 return 0;
745}
746
747static int wsa881x_get_visense(struct snd_kcontrol *kcontrol,
748 struct snd_ctl_elem_value *ucontrol)
749{
750
Meng Wang15c825d2018-09-06 10:49:18 +0800751 struct snd_soc_component *component =
752 snd_soc_kcontrol_component(kcontrol);
753 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530754
755 ucontrol->value.integer.value[0] = wsa881x->visense_enable;
756 return 0;
757}
758
759static int wsa881x_set_visense(struct snd_kcontrol *kcontrol,
760 struct snd_ctl_elem_value *ucontrol)
761{
Meng Wang15c825d2018-09-06 10:49:18 +0800762 struct snd_soc_component *component =
763 snd_soc_kcontrol_component(kcontrol);
764 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530765 int value = ucontrol->value.integer.value[0];
766
Meng Wang15c825d2018-09-06 10:49:18 +0800767 dev_dbg(component->dev, "%s: VIsense enable current %d, new %d\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530768 __func__, wsa881x->visense_enable, value);
769 wsa881x->visense_enable = value;
770 return 0;
771}
772
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800773static int wsa881x_set_boost_level(struct snd_kcontrol *kcontrol,
774 struct snd_ctl_elem_value *ucontrol)
775{
Meng Wang15c825d2018-09-06 10:49:18 +0800776 struct snd_soc_component *component =
777 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800778 u8 wsa_boost_level = 0;
779
Meng Wang15c825d2018-09-06 10:49:18 +0800780 dev_dbg(component->dev, "%s: ucontrol->value.integer.value[0] = %ld\n",
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800781 __func__, ucontrol->value.integer.value[0]);
782
783 wsa_boost_level = ucontrol->value.integer.value[0];
Meng Wang15c825d2018-09-06 10:49:18 +0800784 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT1,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800785 0xff, wsa_boost_level);
786
787 return 0;
788}
789
790static int wsa881x_get_boost_level(struct snd_kcontrol *kcontrol,
791 struct snd_ctl_elem_value *ucontrol)
792{
Meng Wang15c825d2018-09-06 10:49:18 +0800793 struct snd_soc_component *component =
794 snd_soc_kcontrol_component(kcontrol);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800795 u8 wsa_boost_level = 0;
796
Meng Wang15c825d2018-09-06 10:49:18 +0800797 wsa_boost_level = snd_soc_component_read32(component,
798 WSA881X_BOOST_PRESET_OUT1);
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800799 ucontrol->value.integer.value[0] = wsa_boost_level;
Meng Wang15c825d2018-09-06 10:49:18 +0800800 dev_dbg(component->dev, "%s: boost level = 0x%x\n", __func__,
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800801 wsa_boost_level);
802
803 return 0;
804}
805
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530806static const struct snd_kcontrol_new wsa881x_snd_controls[] = {
807 SOC_SINGLE_EXT("COMP Switch", SND_SOC_NOPM, 0, 1, 0,
808 wsa881x_get_compander, wsa881x_set_compander),
809
810 SOC_SINGLE_EXT("BOOST Switch", SND_SOC_NOPM, 0, 1, 0,
811 wsa881x_get_boost, wsa881x_set_boost),
812
813 SOC_SINGLE_EXT("VISENSE Switch", SND_SOC_NOPM, 0, 1, 0,
814 wsa881x_get_visense, wsa881x_set_visense),
Xiaojun Sangfa21d8c2017-09-22 17:05:02 +0800815
816 SOC_SINGLE_EXT("Boost Level", SND_SOC_NOPM, 0, 0xff, 0,
817 wsa881x_get_boost_level, wsa881x_set_boost_level),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530818};
819
820static const struct snd_kcontrol_new swr_dac_port[] = {
821 SOC_DAPM_SINGLE("Switch", SND_SOC_NOPM, 0, 1, 0)
822};
823
Meng Wang15c825d2018-09-06 10:49:18 +0800824static int wsa881x_set_port(struct snd_soc_component *component, int port_idx,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530825 u8 *port_id, u8 *num_ch, u8 *ch_mask, u32 *ch_rate,
826 u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530827{
Meng Wang15c825d2018-09-06 10:49:18 +0800828 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530829
830 *port_id = wsa881x->port[port_idx].port_id;
831 *num_ch = wsa881x->port[port_idx].num_ch;
832 *ch_mask = wsa881x->port[port_idx].ch_mask;
833 *ch_rate = wsa881x->port[port_idx].ch_rate;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530834 *port_type = wsa881x->port[port_idx].port_type;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530835 return 0;
836}
837
838static int wsa881x_enable_swr_dac_port(struct snd_soc_dapm_widget *w,
839 struct snd_kcontrol *kcontrol, int event)
840{
Meng Wang15c825d2018-09-06 10:49:18 +0800841 struct snd_soc_component *component =
842 snd_soc_dapm_to_component(w->dapm);
843 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530844 u8 port_id[WSA881X_MAX_SWR_PORTS];
845 u8 num_ch[WSA881X_MAX_SWR_PORTS];
846 u8 ch_mask[WSA881X_MAX_SWR_PORTS];
847 u32 ch_rate[WSA881X_MAX_SWR_PORTS];
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530848 u8 port_type[WSA881X_MAX_SWR_PORTS];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530849 u8 num_port = 0;
850
Meng Wang15c825d2018-09-06 10:49:18 +0800851 dev_dbg(component->dev, "%s: event %d name %s\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530852 event, w->name);
853 if (wsa881x == NULL)
854 return -EINVAL;
855
856 switch (event) {
857 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +0800858 wsa881x_set_port(component, SWR_DAC_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530859 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530860 &ch_mask[num_port], &ch_rate[num_port],
861 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530862 ++num_port;
863
864 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800865 wsa881x_set_port(component, SWR_COMP_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530866 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530867 &ch_mask[num_port], &ch_rate[num_port],
868 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530869 ++num_port;
870 }
871 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800872 wsa881x_set_port(component, SWR_BOOST_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530873 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530874 &ch_mask[num_port], &ch_rate[num_port],
875 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530876 ++num_port;
877 }
878 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800879 wsa881x_set_port(component, SWR_VISENSE_PORT,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530880 &port_id[num_port], &num_ch[num_port],
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530881 &ch_mask[num_port], &ch_rate[num_port],
882 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530883 ++num_port;
884 }
885 swr_connect_port(wsa881x->swr_slave, &port_id[0], num_port,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530886 &ch_mask[0], &ch_rate[0], &num_ch[0],
887 &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530888 break;
889 case SND_SOC_DAPM_POST_PMU:
890 break;
891 case SND_SOC_DAPM_PRE_PMD:
892 break;
893 case SND_SOC_DAPM_POST_PMD:
Meng Wang15c825d2018-09-06 10:49:18 +0800894 wsa881x_set_port(component, SWR_DAC_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530895 &port_id[num_port], &num_ch[num_port],
896 &ch_mask[num_port], &ch_rate[num_port],
897 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530898 ++num_port;
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530899
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530900 if (wsa881x->comp_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800901 wsa881x_set_port(component, SWR_COMP_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530902 &port_id[num_port], &num_ch[num_port],
903 &ch_mask[num_port], &ch_rate[num_port],
904 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530905 ++num_port;
906 }
907 if (wsa881x->boost_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800908 wsa881x_set_port(component, SWR_BOOST_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530909 &port_id[num_port], &num_ch[num_port],
910 &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->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +0800915 wsa881x_set_port(component, SWR_VISENSE_PORT,
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530916 &port_id[num_port], &num_ch[num_port],
917 &ch_mask[num_port], &ch_rate[num_port],
918 &port_type[num_port]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530919 ++num_port;
920 }
Ramprasad Katkame38aed42018-03-07 16:26:49 +0530921 swr_disconnect_port(wsa881x->swr_slave, &port_id[0], num_port,
922 &ch_mask[0], &port_type[0]);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530923 break;
924 default:
925 break;
926 }
927 return 0;
928}
929
930static int wsa881x_rdac_event(struct snd_soc_dapm_widget *w,
931 struct snd_kcontrol *kcontrol, int event)
932{
Meng Wang15c825d2018-09-06 10:49:18 +0800933 struct snd_soc_component *component =
934 snd_soc_dapm_to_component(w->dapm);
935 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530936
Meng Wang15c825d2018-09-06 10:49:18 +0800937 dev_dbg(component->dev, "%s: %s %d boost %d visense %d\n", __func__,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530938 w->name, event, wsa881x->boost_enable,
939 wsa881x->visense_enable);
940
941 switch (event) {
942 case SND_SOC_DAPM_PRE_PMU:
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530943 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800944 wsa881x_resource_acquire(component, ENABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530945 mutex_unlock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800946 wsa881x_boost_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530947 break;
948 case SND_SOC_DAPM_POST_PMD:
949 swr_slvdev_datapath_control(wsa881x->swr_slave,
950 wsa881x->swr_slave->dev_num,
951 false);
Meng Wang15c825d2018-09-06 10:49:18 +0800952 wsa881x_boost_ctrl(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530953 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +0800954 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +0530955 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530956 break;
957 }
958 return 0;
959}
960
Meng Wang15c825d2018-09-06 10:49:18 +0800961static int wsa881x_ramp_pa_gain(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530962 int min_gain, int max_gain, int udelay)
963{
964 int val;
965
966 for (val = min_gain; max_gain <= val; val--) {
Meng Wang15c825d2018-09-06 10:49:18 +0800967 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_GAIN,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530968 0xF0, val << 4);
969 /*
970 * 1ms delay is needed for every step change in gain as per
971 * HW requirement.
972 */
973 usleep_range(udelay, udelay+10);
974 }
975 return 0;
976}
977
978static void wsa881x_ocp_ctl_work(struct work_struct *work)
979{
980 struct wsa881x_priv *wsa881x;
981 struct delayed_work *dwork;
Meng Wang15c825d2018-09-06 10:49:18 +0800982 struct snd_soc_component *component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530983 int temp_val;
984
985 dwork = to_delayed_work(work);
986 wsa881x = container_of(dwork, struct wsa881x_priv, ocp_ctl_work);
987
Meng Wang15c825d2018-09-06 10:49:18 +0800988 component = wsa881x->component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530989 wsa881x_get_temp(wsa881x->tz_pdata.tz_dev, &temp_val);
Meng Wang15c825d2018-09-06 10:49:18 +0800990 dev_dbg(component->dev, " temp = %d\n", temp_val);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530991
992 if (temp_val <= WSA881X_OCP_CTL_TEMP_CELSIUS)
Meng Wang15c825d2018-09-06 10:49:18 +0800993 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
994 0xC0, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530995 else
Meng Wang15c825d2018-09-06 10:49:18 +0800996 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
997 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +0530998
999 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1000 msecs_to_jiffies(wsa881x_ocp_poll_timer_sec * 1000));
1001}
1002
1003static int wsa881x_spkr_pa_event(struct snd_soc_dapm_widget *w,
1004 struct snd_kcontrol *kcontrol, int event)
1005{
Meng Wang15c825d2018-09-06 10:49:18 +08001006 struct snd_soc_component *component =
1007 snd_soc_dapm_to_component(w->dapm);
1008 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301009 int min_gain, max_gain;
1010
Meng Wang15c825d2018-09-06 10:49:18 +08001011 dev_dbg(component->dev, "%s: %s %d\n", __func__, w->name, event);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301012 switch (event) {
1013 case SND_SOC_DAPM_PRE_PMU:
Meng Wang15c825d2018-09-06 10:49:18 +08001014 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1015 0xC0, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301016 regmap_multi_reg_write(wsa881x->regmap,
1017 wsa881x_pre_pmu_pa_2_0,
1018 ARRAY_SIZE(wsa881x_pre_pmu_pa_2_0));
1019 swr_slvdev_datapath_control(wsa881x->swr_slave,
1020 wsa881x->swr_slave->dev_num,
1021 true);
1022 /* Set register mode if compander is not enabled */
1023 if (!wsa881x->comp_enable)
Meng Wang15c825d2018-09-06 10:49:18 +08001024 snd_soc_component_update_bits(component,
1025 WSA881X_SPKR_DRV_GAIN,
1026 0x08, 0x08);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301027 else
Meng Wang15c825d2018-09-06 10:49:18 +08001028 snd_soc_component_update_bits(component,
1029 WSA881X_SPKR_DRV_GAIN,
1030 0x08, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301031
1032 break;
1033 case SND_SOC_DAPM_POST_PMU:
Laxminath Kasam069df142019-09-17 23:43:34 +05301034 if (!wsa881x->bolero_dev)
1035 snd_soc_component_update_bits(component,
1036 WSA881X_SPKR_DRV_EN,
1037 0x80, 0x80);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301038 if (!wsa881x->comp_enable) {
1039 max_gain = wsa881x->pa_gain;
1040 /*
1041 * Gain has to set incrementally in 4 steps
1042 * as per HW sequence
1043 */
1044 if (max_gain > G_4P5DB)
1045 min_gain = G_0DB;
1046 else
1047 min_gain = max_gain + 3;
1048 /*
1049 * 1ms delay is needed before change in gain
1050 * as per HW requirement.
1051 */
1052 usleep_range(1000, 1010);
Meng Wang15c825d2018-09-06 10:49:18 +08001053 wsa881x_ramp_pa_gain(component, min_gain, max_gain,
1054 1000);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301055 }
1056 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001057 wsa881x_visense_txfe_ctrl(component, ENABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301058 0x00, 0x03, 0x01);
Meng Wang15c825d2018-09-06 10:49:18 +08001059 snd_soc_component_update_bits(component,
1060 WSA881X_ADC_EN_SEL_IBAIS,
1061 0x07, 0x01);
1062 wsa881x_visense_adc_ctrl(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301063 }
1064 schedule_delayed_work(&wsa881x->ocp_ctl_work,
1065 msecs_to_jiffies(WSA881X_OCP_CTL_TIMER_SEC * 1000));
1066 /* Force remove group */
1067 swr_remove_from_group(wsa881x->swr_slave,
1068 wsa881x->swr_slave->dev_num);
1069 break;
1070 case SND_SOC_DAPM_POST_PMD:
Laxminath Kasam069df142019-09-17 23:43:34 +05301071 snd_soc_component_update_bits(component,
1072 WSA881X_SPKR_DRV_EN,
1073 0x80, 0x00);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301074 if (wsa881x->visense_enable) {
Meng Wang15c825d2018-09-06 10:49:18 +08001075 wsa881x_visense_adc_ctrl(component, DISABLE);
1076 wsa881x_visense_txfe_ctrl(component, DISABLE,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301077 0x00, 0x01, 0x01);
1078 }
1079 cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
Meng Wang15c825d2018-09-06 10:49:18 +08001080 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1081 0xC0, 0xC0);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301082 break;
1083 }
1084 return 0;
1085}
1086
1087static const struct snd_soc_dapm_widget wsa881x_dapm_widgets[] = {
1088 SND_SOC_DAPM_INPUT("IN"),
1089
1090 SND_SOC_DAPM_MIXER_E("SWR DAC_Port", SND_SOC_NOPM, 0, 0, swr_dac_port,
1091 ARRAY_SIZE(swr_dac_port), wsa881x_enable_swr_dac_port,
1092 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
1093 SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
1094
1095 SND_SOC_DAPM_DAC_E("RDAC", NULL, WSA881X_SPKR_DAC_CTL, 7, 0,
1096 wsa881x_rdac_event,
1097 SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD),
1098
Laxminath Kasam069df142019-09-17 23:43:34 +05301099 SND_SOC_DAPM_PGA_E("SPKR PGA", SND_SOC_NOPM, 0, 0, NULL, 0,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301100 wsa881x_spkr_pa_event, SND_SOC_DAPM_PRE_PMU |
1101 SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_POST_PMD),
1102
1103 SND_SOC_DAPM_OUTPUT("SPKR"),
1104};
1105
1106static const struct snd_soc_dapm_route wsa881x_audio_map[] = {
1107 {"SWR DAC_Port", "Switch", "IN"},
1108 {"RDAC", NULL, "SWR DAC_Port"},
1109 {"SPKR PGA", NULL, "RDAC"},
1110 {"SPKR", NULL, "SPKR PGA"},
1111};
1112
Meng Wang15c825d2018-09-06 10:49:18 +08001113int wsa881x_set_channel_map(struct snd_soc_component *component, u8 *port,
1114 u8 num_port, unsigned int *ch_mask,
1115 unsigned int *ch_rate, u8 *port_type)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301116{
Meng Wang15c825d2018-09-06 10:49:18 +08001117 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301118 int i;
1119
1120 if (!port || !ch_mask || !ch_rate ||
1121 (num_port > WSA881X_MAX_SWR_PORTS)) {
Meng Wang15c825d2018-09-06 10:49:18 +08001122 dev_err(component->dev,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301123 "%s: Invalid port=%pK, ch_mask=%pK, ch_rate=%pK\n",
1124 __func__, port, ch_mask, ch_rate);
1125 return -EINVAL;
1126 }
1127 for (i = 0; i < num_port; i++) {
1128 wsa881x->port[i].port_id = port[i];
1129 wsa881x->port[i].ch_mask = ch_mask[i];
1130 wsa881x->port[i].ch_rate = ch_rate[i];
1131 wsa881x->port[i].num_ch = __sw_hweight8(ch_mask[i]);
Ramprasad Katkame38aed42018-03-07 16:26:49 +05301132 if (port_type)
1133 wsa881x->port[i].port_type = port_type[i];
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301134 }
1135 return 0;
1136}
1137EXPORT_SYMBOL(wsa881x_set_channel_map);
1138
Meng Wang15c825d2018-09-06 10:49:18 +08001139static void wsa881x_init(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301140{
Meng Wang15c825d2018-09-06 10:49:18 +08001141 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301142
Meng Wang15c825d2018-09-06 10:49:18 +08001143 wsa881x->version =
1144 snd_soc_component_read32(component, WSA881X_CHIP_ID1);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301145 wsa881x_regmap_defaults(wsa881x->regmap, wsa881x->version);
Vatsal Bucha83716b92017-09-14 12:13:13 +05301146 /* Enable software reset output from soundwire slave */
Meng Wang15c825d2018-09-06 10:49:18 +08001147 snd_soc_component_update_bits(component, WSA881X_SWR_RESET_EN,
1148 0x07, 0x07);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301149 /* Bring out of analog reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001150 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1151 0x02, 0x02);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301152 /* Bring out of digital reset */
Meng Wang15c825d2018-09-06 10:49:18 +08001153 snd_soc_component_update_bits(component, WSA881X_CDC_RST_CTL,
1154 0x01, 0x01);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301155
Meng Wang15c825d2018-09-06 10:49:18 +08001156 snd_soc_component_update_bits(component, WSA881X_CLOCK_CONFIG,
1157 0x10, 0x10);
1158 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1159 0x02, 0x02);
1160 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1161 0xC0, 0x80);
1162 snd_soc_component_update_bits(component, WSA881X_SPKR_MISC_CTL1,
1163 0x06, 0x06);
1164 snd_soc_component_update_bits(component, WSA881X_SPKR_BIAS_INT,
1165 0xFF, 0x00);
1166 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1167 0xF0, 0x40);
1168 snd_soc_component_update_bits(component, WSA881X_SPKR_PA_INT,
1169 0x0E, 0x0E);
1170 snd_soc_component_update_bits(component, WSA881X_BOOST_LOOP_STABILITY,
1171 0x03, 0x03);
1172 snd_soc_component_update_bits(component, WSA881X_BOOST_MISC2_CTL,
1173 0xFF, 0x14);
1174 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1175 0x80, 0x80);
1176 snd_soc_component_update_bits(component, WSA881X_BOOST_START_CTL,
1177 0x03, 0x00);
1178 snd_soc_component_update_bits(component,
1179 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1180 0x0C, 0x04);
1181 snd_soc_component_update_bits(component,
1182 WSA881X_BOOST_SLOPE_COMP_ISENSE_FB,
1183 0x03, 0x00);
1184 if (snd_soc_component_read32(component, WSA881X_OTP_REG_0))
1185 snd_soc_component_update_bits(component,
1186 WSA881X_BOOST_PRESET_OUT1,
1187 0xF0, 0x70);
1188 snd_soc_component_update_bits(component, WSA881X_BOOST_PRESET_OUT2,
1189 0xF0, 0x30);
1190 snd_soc_component_update_bits(component, WSA881X_SPKR_DRV_EN,
1191 0x08, 0x08);
1192 snd_soc_component_update_bits(component, WSA881X_BOOST_CURRENT_LIMIT,
1193 0x0F, 0x08);
1194 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1195 0x30, 0x30);
1196 snd_soc_component_update_bits(component, WSA881X_SPKR_OCP_CTL,
1197 0x0C, 0x00);
1198 snd_soc_component_update_bits(component, WSA881X_OTP_REG_28,
1199 0x3F, 0x3A);
1200 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG1,
1201 0xFF, 0xB2);
1202 snd_soc_component_update_bits(component, WSA881X_BONGO_RESRV_REG2,
1203 0xFF, 0x05);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301204}
1205
Meng Wang15c825d2018-09-06 10:49:18 +08001206static int32_t wsa881x_resource_acquire(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301207 bool enable)
1208{
Meng Wang15c825d2018-09-06 10:49:18 +08001209 wsa881x_clk_ctrl(component, enable);
1210 wsa881x_bandgap_ctrl(component, enable);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301211 return 0;
1212}
1213
Meng Wang15c825d2018-09-06 10:49:18 +08001214static int32_t wsa881x_temp_reg_read(struct snd_soc_component *component,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301215 struct wsa_temp_register *wsa_temp_reg)
1216{
Meng Wang15c825d2018-09-06 10:49:18 +08001217 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301218 struct swr_device *dev;
1219 u8 retry = WSA881X_NUM_RETRY;
1220 u8 devnum = 0;
1221
1222 if (!wsa881x) {
Meng Wang15c825d2018-09-06 10:49:18 +08001223 dev_err(component->dev, "%s: wsa881x is NULL\n", __func__);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301224 return -EINVAL;
1225 }
1226 dev = wsa881x->swr_slave;
1227 if (dev && (wsa881x->state == WSA881X_DEV_DOWN)) {
1228 while (swr_get_logical_dev_num(dev, dev->addr, &devnum) &&
1229 retry--) {
1230 /* Retry after 1 msec delay */
1231 usleep_range(1000, 1100);
1232 }
1233 if (retry == 0) {
Meng Wang15c825d2018-09-06 10:49:18 +08001234 dev_err(component->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001235 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301236 __func__, devnum, dev->addr);
1237 return -EINVAL;
1238 }
1239 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301240 wsa881x_regcache_sync(wsa881x);
1241 mutex_lock(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001242 wsa881x_resource_acquire(component, ENABLE);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301243
Meng Wang15c825d2018-09-06 10:49:18 +08001244 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1245 0x01, 0x00);
1246 wsa_temp_reg->dmeas_msb = snd_soc_component_read32(
1247 component, WSA881X_TEMP_MSB);
1248 wsa_temp_reg->dmeas_lsb = snd_soc_component_read32(
1249 component, WSA881X_TEMP_LSB);
1250 snd_soc_component_update_bits(component, WSA881X_TADC_VALUE_CTL,
1251 0x01, 0x01);
1252 wsa_temp_reg->d1_msb = snd_soc_component_read32(
1253 component, WSA881X_OTP_REG_1);
1254 wsa_temp_reg->d1_lsb = snd_soc_component_read32(
1255 component, WSA881X_OTP_REG_2);
1256 wsa_temp_reg->d2_msb = snd_soc_component_read32(
1257 component, WSA881X_OTP_REG_3);
1258 wsa_temp_reg->d2_lsb = snd_soc_component_read32(
1259 component, WSA881X_OTP_REG_4);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301260
Meng Wang15c825d2018-09-06 10:49:18 +08001261 wsa881x_resource_acquire(component, DISABLE);
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301262 mutex_unlock(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301263
1264 return 0;
1265}
1266
Meng Wang15c825d2018-09-06 10:49:18 +08001267static int wsa881x_probe(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301268{
Meng Wang15c825d2018-09-06 10:49:18 +08001269 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301270 struct swr_device *dev;
1271
1272 if (!wsa881x)
1273 return -EINVAL;
Meng Wang15c825d2018-09-06 10:49:18 +08001274 snd_soc_component_init_regmap(component, wsa881x->regmap);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301275
1276 dev = wsa881x->swr_slave;
Meng Wang15c825d2018-09-06 10:49:18 +08001277 wsa881x->component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301278 mutex_init(&wsa881x->bg_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001279 wsa881x_init(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301280 snprintf(wsa881x->tz_pdata.name, sizeof(wsa881x->tz_pdata.name),
1281 "%s.%x", "wsatz", (u8)dev->addr);
1282 wsa881x->bg_cnt = 0;
1283 wsa881x->clk_cnt = 0;
Meng Wang15c825d2018-09-06 10:49:18 +08001284 wsa881x->tz_pdata.component = component;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301285 wsa881x->tz_pdata.wsa_temp_reg_read = wsa881x_temp_reg_read;
1286 wsa881x_init_thermal(&wsa881x->tz_pdata);
Meng Wang15c825d2018-09-06 10:49:18 +08001287 snd_soc_add_component_controls(component, wsa_snd_controls,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301288 ARRAY_SIZE(wsa_snd_controls));
1289 INIT_DELAYED_WORK(&wsa881x->ocp_ctl_work, wsa881x_ocp_ctl_work);
1290 return 0;
1291}
1292
Meng Wang15c825d2018-09-06 10:49:18 +08001293static void wsa881x_remove(struct snd_soc_component *component)
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301294{
Meng Wang15c825d2018-09-06 10:49:18 +08001295 struct wsa881x_priv *wsa881x = snd_soc_component_get_drvdata(component);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301296
1297 if (wsa881x->tz_pdata.tz_dev)
1298 wsa881x_deinit_thermal(wsa881x->tz_pdata.tz_dev);
1299 mutex_destroy(&wsa881x->bg_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301300
Meng Wang15c825d2018-09-06 10:49:18 +08001301 return;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301302}
1303
Meng Wang15c825d2018-09-06 10:49:18 +08001304static const struct snd_soc_component_driver soc_codec_dev_wsa881x = {
1305 .name = DRV_NAME,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301306 .probe = wsa881x_probe,
1307 .remove = wsa881x_remove,
Meng Wang15c825d2018-09-06 10:49:18 +08001308 .controls = wsa881x_snd_controls,
1309 .num_controls = ARRAY_SIZE(wsa881x_snd_controls),
1310 .dapm_widgets = wsa881x_dapm_widgets,
1311 .num_dapm_widgets = ARRAY_SIZE(wsa881x_dapm_widgets),
1312 .dapm_routes = wsa881x_audio_map,
1313 .num_dapm_routes = ARRAY_SIZE(wsa881x_audio_map),
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301314};
1315
1316static int wsa881x_gpio_ctrl(struct wsa881x_priv *wsa881x, bool enable)
1317{
1318 int ret = 0;
1319
1320 if (wsa881x->pd_gpio < 0) {
1321 dev_err(wsa881x->dev, "%s: gpio is not valid %d\n",
1322 __func__, wsa881x->pd_gpio);
1323 return -EINVAL;
1324 }
1325
1326 if (wsa881x->wsa_rst_np) {
1327 if (enable)
1328 ret = msm_cdc_pinctrl_select_active_state(
1329 wsa881x->wsa_rst_np);
1330 else
1331 ret = msm_cdc_pinctrl_select_sleep_state(
1332 wsa881x->wsa_rst_np);
1333 if (ret != 0)
1334 dev_err(wsa881x->dev,
1335 "%s: Failed to turn state %d; ret=%d\n",
1336 __func__, enable, ret);
1337 } else {
1338 if (gpio_is_valid(wsa881x->pd_gpio))
1339 gpio_direction_output(wsa881x->pd_gpio, enable);
1340 }
1341
1342 return ret;
1343}
1344
1345static int wsa881x_gpio_init(struct swr_device *pdev)
1346{
1347 int ret = 0;
1348 struct wsa881x_priv *wsa881x;
1349
1350 wsa881x = swr_get_dev_data(pdev);
1351 if (!wsa881x) {
1352 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1353 return -EINVAL;
1354 }
1355 dev_dbg(&pdev->dev, "%s: gpio %d request with name %s\n",
1356 __func__, wsa881x->pd_gpio, dev_name(&pdev->dev));
1357 ret = gpio_request(wsa881x->pd_gpio, dev_name(&pdev->dev));
1358 if (ret) {
1359 if (ret == -EBUSY) {
1360 /* GPIO was already requested */
1361 dev_dbg(&pdev->dev,
1362 "%s: gpio %d is already set to high\n",
1363 __func__, wsa881x->pd_gpio);
1364 ret = 0;
1365 } else {
1366 dev_err(&pdev->dev, "%s: Failed to request gpio %d, err: %d\n",
1367 __func__, wsa881x->pd_gpio, ret);
1368 }
1369 }
1370 return ret;
1371}
1372
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001373static int wsa881x_event_notify(struct notifier_block *nb,
1374 unsigned long val, void *ptr)
1375{
1376 u16 event = (val & 0xffff);
1377 struct wsa881x_priv *wsa881x = container_of(nb, struct wsa881x_priv,
1378 bolero_nblock);
1379
1380 if (!wsa881x)
1381 return -EINVAL;
1382
1383 switch (event) {
1384 case BOLERO_WSA_EVT_PA_OFF_PRE_SSR:
1385 snd_soc_component_update_bits(wsa881x->component,
1386 WSA881X_SPKR_DRV_GAIN,
1387 0xF0, 0xC0);
1388 snd_soc_component_update_bits(wsa881x->component,
1389 WSA881X_SPKR_DRV_EN,
1390 0x80, 0x00);
1391 break;
Laxminath Kasam069df142019-09-17 23:43:34 +05301392 case BOLERO_WSA_EVT_PA_ON_POST_FSCLK:
1393 if ((snd_soc_component_read32(wsa881x->component,
1394 WSA881X_SPKR_DAC_CTL) & 0x80) == 0x80)
1395 snd_soc_component_update_bits(wsa881x->component,
1396 WSA881X_SPKR_DRV_EN,
1397 0x80, 0x80);
Laxminath Kasamd6b62942019-11-05 12:38:20 +05301398 break;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001399 default:
1400 break;
1401 }
1402
1403 return 0;
1404}
1405
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301406static int wsa881x_swr_probe(struct swr_device *pdev)
1407{
1408 int ret = 0;
1409 struct wsa881x_priv *wsa881x;
1410 u8 devnum = 0;
1411 bool pin_state_current = false;
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001412 struct wsa_ctrl_platform_data *plat_data = NULL;
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301413
1414 wsa881x = devm_kzalloc(&pdev->dev, sizeof(struct wsa881x_priv),
1415 GFP_KERNEL);
1416 if (!wsa881x)
1417 return -ENOMEM;
1418 wsa881x->wsa_rst_np = of_parse_phandle(pdev->dev.of_node,
1419 "qcom,spkr-sd-n-node", 0);
1420 if (!wsa881x->wsa_rst_np) {
1421 dev_dbg(&pdev->dev, "%s: Not using pinctrl, fallback to gpio\n",
1422 __func__);
1423 wsa881x->pd_gpio = of_get_named_gpio(pdev->dev.of_node,
1424 "qcom,spkr-sd-n-gpio", 0);
1425 if (wsa881x->pd_gpio < 0) {
1426 dev_err(&pdev->dev, "%s: %s property is not found %d\n",
1427 __func__, "qcom,spkr-sd-n-gpio",
1428 wsa881x->pd_gpio);
1429 goto err;
1430 }
1431 dev_dbg(&pdev->dev, "%s: reset gpio %d\n", __func__,
1432 wsa881x->pd_gpio);
1433 }
1434 swr_set_dev_data(pdev, wsa881x);
1435
1436 wsa881x->swr_slave = pdev;
1437
1438 if (!wsa881x->wsa_rst_np) {
1439 ret = wsa881x_gpio_init(pdev);
1440 if (ret)
1441 goto err;
1442 }
1443 if (wsa881x->wsa_rst_np)
1444 pin_state_current = msm_cdc_pinctrl_get_state(
1445 wsa881x->wsa_rst_np);
1446 wsa881x_gpio_ctrl(wsa881x, true);
1447 wsa881x->state = WSA881X_DEV_UP;
1448
1449 if (!debugfs_wsa881x_dent) {
1450 dbgwsa881x = wsa881x;
1451 debugfs_wsa881x_dent = debugfs_create_dir(
1452 "wsa881x_swr_slave", 0);
1453 if (!IS_ERR(debugfs_wsa881x_dent)) {
1454 debugfs_peek = debugfs_create_file("swrslave_peek",
1455 S_IFREG | 0444, debugfs_wsa881x_dent,
1456 (void *) "swrslave_peek",
1457 &codec_debug_ops);
1458
1459 debugfs_poke = debugfs_create_file("swrslave_poke",
1460 S_IFREG | 0444, debugfs_wsa881x_dent,
1461 (void *) "swrslave_poke",
1462 &codec_debug_ops);
1463
1464 debugfs_reg_dump = debugfs_create_file(
1465 "swrslave_reg_dump",
1466 S_IFREG | 0444,
1467 debugfs_wsa881x_dent,
1468 (void *) "swrslave_reg_dump",
1469 &codec_debug_ops);
1470 }
1471 }
1472
1473 /*
1474 * Add 5msec delay to provide sufficient time for
1475 * soundwire auto enumeration of slave devices as
1476 * as per HW requirement.
1477 */
1478 usleep_range(5000, 5010);
1479 ret = swr_get_logical_dev_num(pdev, pdev->addr, &devnum);
1480 if (ret) {
1481 dev_dbg(&pdev->dev,
Xiao Lid8bb93c2020-01-07 12:59:05 +08001482 "%s get devnum %d for dev addr %llx failed\n",
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301483 __func__, devnum, pdev->addr);
1484 goto dev_err;
1485 }
1486 pdev->dev_num = devnum;
1487
1488 wsa881x->regmap = devm_regmap_init_swr(pdev,
1489 &wsa881x_regmap_config);
1490 if (IS_ERR(wsa881x->regmap)) {
1491 ret = PTR_ERR(wsa881x->regmap);
1492 dev_err(&pdev->dev, "%s: regmap_init failed %d\n",
1493 __func__, ret);
1494 goto dev_err;
1495 }
1496
Meng Wang15c825d2018-09-06 10:49:18 +08001497 ret = snd_soc_register_component(&pdev->dev, &soc_codec_dev_wsa881x,
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301498 NULL, 0);
1499 if (ret) {
1500 dev_err(&pdev->dev, "%s: Codec registration failed\n",
1501 __func__);
1502 goto dev_err;
1503 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001504
1505 wsa881x->bolero_np = of_parse_phandle(pdev->dev.of_node,
1506 "qcom,bolero-handle", 0);
1507 if (wsa881x->bolero_np) {
1508 wsa881x->bolero_dev =
1509 of_find_device_by_node(wsa881x->bolero_np);
1510 if (wsa881x->bolero_dev) {
1511 plat_data = dev_get_platdata(&wsa881x->bolero_dev->dev);
1512 if (plat_data) {
1513 wsa881x->bolero_nblock.notifier_call =
1514 wsa881x_event_notify;
1515 if (plat_data->register_notifier)
1516 plat_data->register_notifier(
1517 plat_data->handle,
1518 &wsa881x->bolero_nblock,
1519 true);
1520 wsa881x->register_notifier =
1521 plat_data->register_notifier;
1522 wsa881x->handle = plat_data->handle;
1523 } else {
1524 dev_err(&pdev->dev, "%s: plat data not found\n",
1525 __func__);
1526 }
1527 } else {
1528 dev_err(&pdev->dev, "%s: bolero dev not found\n",
1529 __func__);
1530 }
1531 } else {
1532 dev_info(&pdev->dev, "%s: bolero node not found\n", __func__);
1533 }
1534
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301535 mutex_init(&wsa881x->res_lock);
1536 mutex_init(&wsa881x->temp_lock);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301537
1538 return 0;
1539
1540dev_err:
1541 if (pin_state_current == false)
1542 wsa881x_gpio_ctrl(wsa881x, false);
1543 swr_remove_device(pdev);
1544err:
1545 return ret;
1546}
1547
1548static int wsa881x_swr_remove(struct swr_device *pdev)
1549{
1550 struct wsa881x_priv *wsa881x;
1551
1552 wsa881x = swr_get_dev_data(pdev);
1553 if (!wsa881x) {
1554 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1555 return -EINVAL;
1556 }
Karthikeyan Mani13485b72019-08-05 17:51:14 -07001557
1558 if (wsa881x->register_notifier)
1559 wsa881x->register_notifier(wsa881x->handle,
1560 &wsa881x->bolero_nblock, false);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301561 debugfs_remove_recursive(debugfs_wsa881x_dent);
1562 debugfs_wsa881x_dent = NULL;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301563 mutex_destroy(&wsa881x->res_lock);
1564 mutex_destroy(&wsa881x->temp_lock);
Meng Wang15c825d2018-09-06 10:49:18 +08001565 snd_soc_unregister_component(&pdev->dev);
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301566 if (wsa881x->pd_gpio)
1567 gpio_free(wsa881x->pd_gpio);
1568 swr_set_dev_data(pdev, NULL);
1569 return 0;
1570}
1571
1572static int wsa881x_swr_up(struct swr_device *pdev)
1573{
1574 int ret;
1575 struct wsa881x_priv *wsa881x;
1576
1577 wsa881x = swr_get_dev_data(pdev);
1578 if (!wsa881x) {
1579 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1580 return -EINVAL;
1581 }
1582 ret = wsa881x_gpio_ctrl(wsa881x, true);
1583 if (ret)
1584 dev_err(&pdev->dev, "%s: Failed to enable gpio\n", __func__);
1585 else
1586 wsa881x->state = WSA881X_DEV_UP;
1587
1588 return ret;
1589}
1590
1591static int wsa881x_swr_down(struct swr_device *pdev)
1592{
1593 struct wsa881x_priv *wsa881x;
1594 int ret;
1595
1596 wsa881x = swr_get_dev_data(pdev);
1597 if (!wsa881x) {
1598 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1599 return -EINVAL;
1600 }
1601 if (delayed_work_pending(&wsa881x->ocp_ctl_work))
1602 cancel_delayed_work_sync(&wsa881x->ocp_ctl_work);
1603 ret = wsa881x_gpio_ctrl(wsa881x, false);
1604 if (ret)
1605 dev_err(&pdev->dev, "%s: Failed to disable gpio\n", __func__);
1606 else
1607 wsa881x->state = WSA881X_DEV_DOWN;
1608
1609 return ret;
1610}
1611
1612static int wsa881x_swr_reset(struct swr_device *pdev)
1613{
1614 struct wsa881x_priv *wsa881x;
1615 u8 retry = WSA881X_NUM_RETRY;
1616 u8 devnum = 0;
1617
1618 wsa881x = swr_get_dev_data(pdev);
1619 if (!wsa881x) {
1620 dev_err(&pdev->dev, "%s: wsa881x is NULL\n", __func__);
1621 return -EINVAL;
1622 }
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301623 if (wsa881x->state == WSA881X_DEV_READY) {
1624 dev_dbg(&pdev->dev, "%s: device already active\n", __func__);
1625 return 0;
1626 }
1627
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301628 wsa881x->bg_cnt = 0;
1629 wsa881x->clk_cnt = 0;
1630 while (swr_get_logical_dev_num(pdev, pdev->addr, &devnum) && retry--) {
1631 /* Retry after 1 msec delay */
1632 usleep_range(1000, 1100);
1633 }
1634 pdev->dev_num = devnum;
Laxminath Kasamc0684fc2018-07-31 19:26:56 +05301635 wsa881x_regcache_sync(wsa881x);
1636
Asish Bhattacharya8e2277f2017-07-20 18:31:55 +05301637 return 0;
1638}
1639
1640#ifdef CONFIG_PM_SLEEP
1641static int wsa881x_swr_suspend(struct device *dev)
1642{
1643 dev_dbg(dev, "%s: system suspend\n", __func__);
1644 return 0;
1645}
1646
1647static int wsa881x_swr_resume(struct device *dev)
1648{
1649 struct wsa881x_priv *wsa881x = swr_get_dev_data(to_swr_device(dev));
1650
1651 if (!wsa881x) {
1652 dev_err(dev, "%s: wsa881x private data is NULL\n", __func__);
1653 return -EINVAL;
1654 }
1655 dev_dbg(dev, "%s: system resume\n", __func__);
1656 return 0;
1657}
1658#endif /* CONFIG_PM_SLEEP */
1659
1660static const struct dev_pm_ops wsa881x_swr_pm_ops = {
1661 SET_SYSTEM_SLEEP_PM_OPS(wsa881x_swr_suspend, wsa881x_swr_resume)
1662};
1663
1664static const struct swr_device_id wsa881x_swr_id[] = {
1665 {"wsa881x", 0},
1666 {}
1667};
1668
1669static const struct of_device_id wsa881x_swr_dt_match[] = {
1670 {
1671 .compatible = "qcom,wsa881x",
1672 },
1673 {}
1674};
1675
1676static struct swr_driver wsa881x_codec_driver = {
1677 .driver = {
1678 .name = "wsa881x",
1679 .owner = THIS_MODULE,
1680 .pm = &wsa881x_swr_pm_ops,
1681 .of_match_table = wsa881x_swr_dt_match,
1682 },
1683 .probe = wsa881x_swr_probe,
1684 .remove = wsa881x_swr_remove,
1685 .id_table = wsa881x_swr_id,
1686 .device_up = wsa881x_swr_up,
1687 .device_down = wsa881x_swr_down,
1688 .reset_device = wsa881x_swr_reset,
1689};
1690
1691static int __init wsa881x_codec_init(void)
1692{
1693 return swr_driver_register(&wsa881x_codec_driver);
1694}
1695
1696static void __exit wsa881x_codec_exit(void)
1697{
1698 swr_driver_unregister(&wsa881x_codec_driver);
1699}
1700
1701module_init(wsa881x_codec_init);
1702module_exit(wsa881x_codec_exit);
1703
1704MODULE_DESCRIPTION("WSA881x Codec driver");
1705MODULE_LICENSE("GPL v2");