-
Notifications
You must be signed in to change notification settings - Fork 147
Expand file tree
/
Copy pathwcd9335.c
More file actions
14695 lines (12898 loc) · 449 KB
/
wcd9335.c
File metadata and controls
14695 lines (12898 loc) · 449 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
*Copyright (C) 2018, Laster K. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/firmware.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/device.h>
#include <linux/printk.h>
#include <linux/ratelimit.h>
#include <linux/debugfs.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/mfd/wcd9xxx/core.h>
#include <linux/mfd/wcd9xxx/wcd9xxx_registers.h>
#include <linux/mfd/wcd9335/registers.h>
#include <linux/mfd/wcd9xxx/pdata.h>
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/soundwire/swr-wcd.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/soc-dapm.h>
#include <sound/tlv.h>
#include <sound/info.h>
#include <sound/sounddebug.h>
#include "wcd9335.h"
#include "wcd-mbhc-v2.h"
#include "wcd9xxx-common-v2.h"
#include "wcd9xxx-resmgr-v2.h"
#include "wcd_cpe_core.h"
#include "wcdcal-hwdep.h"
#define TASHA_RX_PORT_START_NUMBER 16
#define WCD9335_RATES_MASK (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\
SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000 |\
SNDRV_PCM_RATE_384000)
/* Fractional Rates */
#define WCD9335_FRAC_RATES_MASK (SNDRV_PCM_RATE_44100)
#define WCD9335_MIX_RATES_MASK (SNDRV_PCM_RATE_48000 |\
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_192000)
#define TASHA_FORMATS_S16_S24_LE (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S24_3LE)
#define TASHA_FORMATS_S16_S24_S32_LE (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S24_3LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define TASHA_FORMATS (SNDRV_PCM_FMTBIT_S16_LE)
/*
* Timeout in milli seconds and it is the wait time for
* slim channel removal interrupt to receive.
*/
#define TASHA_SLIM_CLOSE_TIMEOUT 1000
#define TASHA_SLIM_IRQ_OVERFLOW (1 << 0)
#define TASHA_SLIM_IRQ_UNDERFLOW (1 << 1)
#define TASHA_SLIM_IRQ_PORT_CLOSED (1 << 2)
#define TASHA_MCLK_CLK_12P288MHZ 12288000
#define TASHA_MCLK_CLK_9P6MHZ 9600000
#define TASHA_SLIM_PGD_PORT_INT_TX_EN0 (TASHA_SLIM_PGD_PORT_INT_EN0 + 2)
#define TASHA_NUM_INTERPOLATORS 9
#define TASHA_NUM_DECIMATORS 9
#define BYTE_BIT_MASK(nr) (1 << ((nr) % BITS_PER_BYTE))
#define TASHA_MAD_AUDIO_FIRMWARE_PATH "wcd9335/wcd9335_mad_audio.bin"
#define TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS (1 << 0)
#define TASHA_CPE_SS_ERR_STATUS_WDOG_BITE (1 << 1)
#define TASHA_CPE_FATAL_IRQS \
(TASHA_CPE_SS_ERR_STATUS_WDOG_BITE | \
TASHA_CPE_SS_ERR_STATUS_MEM_ACCESS)
#define SLIM_BW_CLK_GEAR_9 6200000
#define SLIM_BW_UNVOTE 0
#define CPE_FLL_CLK_75MHZ 75000000
#define CPE_FLL_CLK_150MHZ 150000000
#define WCD9335_REG_BITS 8
#define WCD9335_MAX_VALID_ADC_MUX 13
#define WCD9335_INVALID_ADC_MUX 9
#define TASHA_DIG_CORE_REG_MIN WCD9335_CDC_ANC0_CLK_RESET_CTL
#define TASHA_DIG_CORE_REG_MAX 0xDFF
/* Convert from vout ctl to micbias voltage in mV */
#define WCD_VOUT_CTL_TO_MICB(v) (1000 + v * 50)
#define TASHA_ZDET_NUM_MEASUREMENTS 150
#define TASHA_MBHC_GET_C1(c) ((c & 0xC000) >> 14)
#define TASHA_MBHC_GET_X1(x) (x & 0x3FFF)
/* z value compared in milliOhm */
#define TASHA_MBHC_IS_SECOND_RAMP_REQUIRED(z) ((z > 400000) || (z < 32000))
#define TASHA_MBHC_ZDET_CONST (86 * 16384)
#define TASHA_VERSION_ENTRY_SIZE 17
#define WCD9335_AMIC_PWR_LEVEL_LP 0
#define WCD9335_AMIC_PWR_LEVEL_DEFAULT 1
#define WCD9335_AMIC_PWR_LEVEL_HP 2
#define WCD9335_AMIC_PWR_LVL_MASK 0x60
#define WCD9335_AMIC_PWR_LVL_SHIFT 0x5
#define WCD9335_DEC_PWR_LVL_MASK 0x06
#define WCD9335_DEC_PWR_LVL_LP 0x02
#define WCD9335_DEC_PWR_LVL_HP 0x04
#define WCD9335_DEC_PWR_LVL_DF 0x00
#define CALCULATE_VOUT_D(req_mv) (((req_mv - 650) * 10) / 25)
static int cpe_debug_mode;
#define TASHA_MAX_MICBIAS 4
#define DAPM_MICBIAS1_STANDALONE "MIC BIAS1 Standalone"
#define DAPM_MICBIAS2_STANDALONE "MIC BIAS2 Standalone"
#define DAPM_MICBIAS3_STANDALONE "MIC BIAS3 Standalone"
#define DAPM_MICBIAS4_STANDALONE "MIC BIAS4 Standalone"
#define DAPM_LDO_H_STANDALONE "LDO_H"
module_param(cpe_debug_mode, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(cpe_debug_mode, "boot cpe in debug mode");
#define TASHA_DIG_CORE_COLLAPSE_TIMER_MS (5 * 1000)
#define MAX_ON_DEMAND_SUPPLY_NAME_LENGTH 64
static char on_demand_supply_name[][MAX_ON_DEMAND_SUPPLY_NAME_LENGTH] = {
"cdc-vdd-mic-bias",
};
enum {
POWER_COLLAPSE,
POWER_RESUME,
};
enum tasha_sido_voltage {
SIDO_VOLTAGE_SVS_MV = 950,
SIDO_VOLTAGE_NOMINAL_MV = 1100,
};
static enum codec_variant codec_ver;
static int huwifi_mode = 1;
module_param(huwifi_mode, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(huwifi_mode, "enable/disable l UHQA Mode");
static int low_distort_amp = 1;
module_param(low_distort_amp, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(low_distort_amp, "enable/disable l Class AB Mode");
static int dig_core_collapse_enable = 0;
module_param(dig_core_collapse_enable, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(dig_core_collapse_enable, "enable/disable power gating");
/* dig_core_collapse timer in seconds */
static int dig_core_collapse_timer = (TASHA_DIG_CORE_COLLAPSE_TIMER_MS/1000);
module_param(dig_core_collapse_timer, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(dig_core_collapse_timer, "timer for power gating");
/* SVS Scaling enable/disable */
static int svs_scaling_enabled = 1;
module_param(svs_scaling_enabled, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(svs_scaling_enabled, "enable/disable svs scaling");
/* SVS buck setting */
static int sido_buck_svs_voltage = SIDO_VOLTAGE_SVS_MV;
module_param(sido_buck_svs_voltage, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(sido_buck_svs_voltage,
"setting for SVS voltage for SIDO BUCK");
#define TASHA_TX_UNMUTE_DELAY_MS 25
static u32 tx_unmute_delay = TASHA_TX_UNMUTE_DELAY_MS;
module_param(tx_unmute_delay, int,
S_IRUGO | S_IWUSR | S_IWGRP);
MODULE_PARM_DESC(tx_unmute_delay, "delay to unmute the tx path");
static struct afe_param_slimbus_slave_port_cfg tasha_slimbus_slave_port_cfg = {
.minor_version = 1,
.slimbus_dev_id = AFE_SLIMBUS_DEVICE_1,
.slave_dev_pgd_la = 0,
.slave_dev_intfdev_la = 0,
.bit_width = 16,
.data_format = 0,
.num_channels = 1
};
struct tasha_mbhc_zdet_param {
u16 ldo_ctl;
u16 noff;
u16 nshift;
u16 btn5;
u16 btn6;
u16 btn7;
};
static struct afe_param_cdc_reg_page_cfg tasha_cdc_reg_page_cfg = {
.minor_version = AFE_API_VERSION_CDC_REG_PAGE_CFG,
.enable = 1,
.proc_id = AFE_CDC_REG_PAGE_ASSIGN_PROC_ID_1,
};
static struct afe_param_cdc_reg_cfg audio_reg_cfg[] = {
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_MAIN_CTL_1),
HW_MAD_AUDIO_ENABLE, 0x1, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_3),
HW_MAD_AUDIO_SLEEP_TIME, 0xF, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_SOC_MAD_AUDIO_CTL_4),
HW_MAD_TX_AUDIO_SWITCH_OFF, 0x1, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
MAD_AUDIO_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
MAD_AUDIO_INT_MASK_REG, 0x1, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
MAD_AUDIO_INT_STATUS_REG, 0x1, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
MAD_AUDIO_INT_CLEAR_REG, 0x1, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
VBAT_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
VBAT_INT_MASK_REG, 0x08, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
VBAT_INT_STATUS_REG, 0x08, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
VBAT_INT_CLEAR_REG, 0x08, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_CFG),
VBAT_RELEASE_INT_DEST_SELECT_REG, 0x2, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_MASK3),
VBAT_RELEASE_INT_MASK_REG, 0x10, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_STATUS3),
VBAT_RELEASE_INT_STATUS_REG, 0x10, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_INTR_PIN2_CLEAR3),
VBAT_RELEASE_INT_CLEAR_REG, 0x10, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE),
SB_PGD_PORT_TX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1
},
{
1,
(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_TX_BASE),
SB_PGD_PORT_TX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1
},
{
1,
(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE),
SB_PGD_PORT_RX_WATERMARK_N, 0x1E, WCD9335_REG_BITS, 0x1
},
{
1,
(TASHA_REGISTER_START_OFFSET + TASHA_SB_PGD_PORT_RX_BASE),
SB_PGD_PORT_RX_ENABLE_N, 0x1, WCD9335_REG_BITS, 0x1
},
{ 1,
(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL),
AANC_FF_GAIN_ADAPTIVE, 0x4, WCD9335_REG_BITS, 0
},
{ 1,
(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_IIR_ADAPT_CTL),
AANC_FFGAIN_ADAPTIVE_EN, 0x8, WCD9335_REG_BITS, 0
},
{
1,
(TASHA_REGISTER_START_OFFSET + WCD9335_CDC_ANC0_FF_A_GAIN_CTL),
AANC_GAIN_CONTROL, 0xFF, WCD9335_REG_BITS, 0
},
};
static struct afe_param_cdc_reg_cfg_data tasha_audio_reg_cfg = {
.num_registers = ARRAY_SIZE(audio_reg_cfg),
.reg_data = audio_reg_cfg,
};
static struct afe_param_id_cdc_aanc_version tasha_cdc_aanc_version = {
.cdc_aanc_minor_version = AFE_API_VERSION_CDC_AANC_VERSION,
.aanc_hw_version = AANC_HW_BLOCK_VERSION_2,
};
enum {
VI_SENSE_1,
VI_SENSE_2,
AIF4_SWITCH_VALUE,
AUDIO_NOMINAL,
CPE_NOMINAL,
HPH_PA_DELAY,
SB_CLK_GEAR,
CLASSH_CONFIG,
ANC_MIC_AMIC1,
ANC_MIC_AMIC2,
ANC_MIC_AMIC3,
ANC_MIC_AMIC4,
ANC_MIC_AMIC5,
ANC_MIC_AMIC6,
};
enum {
AIF1_PB = 0,
AIF1_CAP,
AIF2_PB,
AIF2_CAP,
AIF3_PB,
AIF3_CAP,
AIF4_PB,
AIF4_CAP,
AIF5_PB,
AIF_MIX1_PB,
AIF4_MAD_TX,
AIF4_VIFEED,
AIF5_CPE_TX,
NUM_CODEC_DAIS,
};
enum {
INTn_1_MIX_INP_SEL_ZERO = 0,
INTn_1_MIX_INP_SEL_DEC0,
INTn_1_MIX_INP_SEL_DEC1,
INTn_1_MIX_INP_SEL_IIR0,
INTn_1_MIX_INP_SEL_IIR1,
INTn_1_MIX_INP_SEL_RX0,
INTn_1_MIX_INP_SEL_RX1,
INTn_1_MIX_INP_SEL_RX2,
INTn_1_MIX_INP_SEL_RX3,
INTn_1_MIX_INP_SEL_RX4,
INTn_1_MIX_INP_SEL_RX5,
INTn_1_MIX_INP_SEL_RX6,
INTn_1_MIX_INP_SEL_RX7,
};
#define IS_VALID_NATIVE_FIFO_PORT(inp) \
((inp >= INTn_1_MIX_INP_SEL_RX0) && \
(inp <= INTn_1_MIX_INP_SEL_RX3))
enum {
INTn_2_INP_SEL_ZERO = 0,
INTn_2_INP_SEL_RX0,
INTn_2_INP_SEL_RX1,
INTn_2_INP_SEL_RX2,
INTn_2_INP_SEL_RX3,
INTn_2_INP_SEL_RX4,
INTn_2_INP_SEL_RX5,
INTn_2_INP_SEL_RX6,
INTn_2_INP_SEL_RX7,
INTn_2_INP_SEL_PROXIMITY,
};
enum {
INTERP_EAR = 0,
INTERP_HPHL,
INTERP_HPHR,
INTERP_LO1,
INTERP_LO2,
INTERP_LO3,
INTERP_LO4,
INTERP_SPKR1,
INTERP_SPKR2,
};
struct interp_sample_rate {
int sample_rate;
int rate_val;
};
static struct interp_sample_rate int_prim_sample_rate_val[] = {
{8000, 0x0}, /* 8K */
{16000, 0x1}, /* 16K */
{24000, -EINVAL},/* 24K */
{32000, 0x3}, /* 32K */
{48000, 0x4}, /* 48K */
{96000, 0x5}, /* 96K */
{192000, 0x6}, /* 192K */
{384000, 0x7}, /* 384K */
{44100, 0x8}, /* 44.1K */
};
static struct interp_sample_rate int_mix_sample_rate_val[] = {
{48000, 0x4}, /* 48K */
{96000, 0x5}, /* 96K */
{192000, 0x6}, /* 192K */
{384000, 0x7}, /* 384K */
};
static const struct wcd9xxx_ch tasha_rx_chs[TASHA_RX_MAX] = {
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER, 0),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 1, 1),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 2, 2),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 3, 3),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 4, 4),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 5, 5),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 6, 6),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 7, 7),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 8, 8),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 9, 9),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 10, 10),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 11, 11),
WCD9XXX_CH(TASHA_RX_PORT_START_NUMBER + 12, 12),
};
static const struct wcd9xxx_ch tasha_tx_chs[TASHA_TX_MAX] = {
WCD9XXX_CH(0, 0),
WCD9XXX_CH(1, 1),
WCD9XXX_CH(2, 2),
WCD9XXX_CH(3, 3),
WCD9XXX_CH(4, 4),
WCD9XXX_CH(5, 5),
WCD9XXX_CH(6, 6),
WCD9XXX_CH(7, 7),
WCD9XXX_CH(8, 8),
WCD9XXX_CH(9, 9),
WCD9XXX_CH(10, 10),
WCD9XXX_CH(11, 11),
WCD9XXX_CH(12, 12),
WCD9XXX_CH(13, 13),
WCD9XXX_CH(14, 14),
WCD9XXX_CH(15, 15),
};
static const u32 vport_slim_check_table[NUM_CODEC_DAIS] = {
/* Needs to define in the same order of DAI enum definitions */
0,
BIT(AIF2_CAP) | BIT(AIF3_CAP) | BIT(AIF4_CAP) |
BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
0,
BIT(AIF1_CAP) | BIT(AIF3_CAP) | BIT(AIF4_CAP) |
BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
0,
BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF4_CAP) |
BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
0,
BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) |
BIT(AIF4_MAD_TX) | BIT(AIF5_CPE_TX),
0,
0,
BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) |
BIT(AIF4_CAP) | BIT(AIF5_CPE_TX),
0,
BIT(AIF1_CAP) | BIT(AIF2_CAP) | BIT(AIF3_CAP) |
BIT(AIF4_CAP) | BIT(AIF4_MAD_TX),
};
static const u32 vport_i2s_check_table[NUM_CODEC_DAIS] = {
0, /* AIF1_PB */
BIT(AIF2_CAP), /* AIF1_CAP */
0, /* AIF2_PB */
BIT(AIF1_CAP), /* AIF2_CAP */
};
/* Codec supports 2 IIR filters */
enum {
IIR0 = 0,
IIR1,
IIR_MAX,
};
/* Each IIR has 5 Filter Stages */
enum {
BAND1 = 0,
BAND2,
BAND3,
BAND4,
BAND5,
BAND_MAX,
};
enum {
COMPANDER_1, /* HPH_L */
COMPANDER_2, /* HPH_R */
COMPANDER_3, /* LO1_DIFF */
COMPANDER_4, /* LO2_DIFF */
COMPANDER_5, /* LO3_SE */
COMPANDER_6, /* LO4_SE */
COMPANDER_7, /* SWR SPK CH1 */
COMPANDER_8, /* SWR SPK CH2 */
COMPANDER_MAX,
};
enum {
SRC_IN_HPHL,
SRC_IN_LO1,
SRC_IN_HPHR,
SRC_IN_LO2,
SRC_IN_SPKRL,
SRC_IN_LO3,
SRC_IN_SPKRR,
SRC_IN_LO4,
};
enum {
SPLINE_SRC0,
SPLINE_SRC1,
SPLINE_SRC2,
SPLINE_SRC3,
SPLINE_SRC_MAX,
};
static const DECLARE_TLV_DB_SCALE(digital_gain, 0, 1, 0);
static const DECLARE_TLV_DB_SCALE(line_gain, 0, 7, 1);
static const DECLARE_TLV_DB_SCALE(analog_gain, 0, 25, 1);
static struct snd_soc_dai_driver tasha_dai[];
static int wcd9335_get_micb_vout_ctl_val(u32 micb_mv);
static int tasha_config_compander(struct snd_soc_codec *, int, int);
static void tasha_codec_set_tx_hold(struct snd_soc_codec *, u16, bool);
static int tasha_codec_internal_rco_ctrl(struct snd_soc_codec *codec,
bool enable);
/* Hold instance to soundwire platform device */
struct tasha_swr_ctrl_data {
struct platform_device *swr_pdev;
struct ida swr_ida;
};
struct wcd_swr_ctrl_platform_data {
void *handle; /* holds codec private data */
int (*read)(void *handle, int reg);
int (*write)(void *handle, int reg, int val);
int (*bulk_write)(void *handle, u32 *reg, u32 *val, size_t len);
int (*clk)(void *handle, bool enable);
int (*handle_irq)(void *handle,
irqreturn_t (*swrm_irq_handler)(int irq,
void *data),
void *swrm_handle,
int action);
};
static struct wcd_mbhc_register
wcd_mbhc_registers[WCD_MBHC_REG_FUNC_MAX] = {
WCD_MBHC_REGISTER("WCD_MBHC_L_DET_EN",
WCD9335_ANA_MBHC_MECH, 0x80, 7, 0),
WCD_MBHC_REGISTER("WCD_MBHC_GND_DET_EN",
WCD9335_ANA_MBHC_MECH, 0x40, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MECH_DETECTION_TYPE",
WCD9335_ANA_MBHC_MECH, 0x20, 5, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MIC_CLAMP_CTL",
WCD9335_MBHC_PLUG_DETECT_CTL, 0x30, 4, 0),
WCD_MBHC_REGISTER("WCD_MBHC_ELECT_DETECTION_TYPE",
WCD9335_ANA_MBHC_ELECT, 0x08, 3, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_CTRL",
WCD9335_MBHC_PLUG_DETECT_CTL, 0xC0, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HS_L_DET_PULL_UP_COMP_CTRL",
WCD9335_ANA_MBHC_MECH, 0x04, 2, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PLUG_TYPE",
WCD9335_ANA_MBHC_MECH, 0x10, 4, 0),
WCD_MBHC_REGISTER("WCD_MBHC_GND_PLUG_TYPE",
WCD9335_ANA_MBHC_MECH, 0x08, 3, 0),
WCD_MBHC_REGISTER("WCD_MBHC_SW_HPH_LP_100K_TO_GND",
WCD9335_ANA_MBHC_MECH, 0x01, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_ELECT_SCHMT_ISRC",
WCD9335_ANA_MBHC_ELECT, 0x06, 1, 0),
WCD_MBHC_REGISTER("WCD_MBHC_FSM_EN",
WCD9335_ANA_MBHC_ELECT, 0x80, 7, 0),
WCD_MBHC_REGISTER("WCD_MBHC_INSREM_DBNC",
WCD9335_MBHC_PLUG_DETECT_CTL, 0x0F, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_BTN_DBNC",
WCD9335_MBHC_CTL_1, 0x03, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HS_VREF",
WCD9335_MBHC_CTL_2, 0x03, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HS_COMP_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x08, 3, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MIC_SCHMT_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x20, 5, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_SCHMT_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x80, 7, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHR_SCHMT_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x40, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_OCP_FSM_EN",
WCD9335_HPH_OCP_CTL, 0x10, 4, 0),
WCD_MBHC_REGISTER("WCD_MBHC_BTN_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0x07, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_BTN_ISRC_CTL",
WCD9335_ANA_MBHC_ELECT, 0x70, 4, 0),
WCD_MBHC_REGISTER("WCD_MBHC_ELECT_RESULT",
WCD9335_ANA_MBHC_RESULT_3, 0xFF, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MICB_CTRL",
WCD9335_ANA_MICB2, 0xC0, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPH_CNP_WG_TIME",
WCD9335_HPH_CNP_WG_TIME, 0xFF, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHR_PA_EN",
WCD9335_ANA_HPH, 0x40, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPHL_PA_EN",
WCD9335_ANA_HPH, 0x80, 7, 0),
WCD_MBHC_REGISTER("WCD_MBHC_HPH_PA_EN",
WCD9335_ANA_HPH, 0xC0, 6, 0),
WCD_MBHC_REGISTER("WCD_MBHC_SWCH_LEVEL_REMOVE",
WCD9335_ANA_MBHC_RESULT_3, 0x10, 4, 0),
/*
* Initialize moisture register as "0" and based on codec
* version, the register, mask fields get populated.
* Register "0" is not a valid register for MBHC.
*/
WCD_MBHC_REGISTER("WCD_MBHC_MOISTURE_VREF",
0, 0, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_PULLDOWN_CTRL",
0, 0, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_ANC_DET_EN",
WCD9335_ANA_MBHC_ZDET, 0x01, 0, 0),
/*
* MBHC FSM status register is only available in Tasha 2.0.
* So, init with 0 later once the version is known, then values
* will be updated.
*/
WCD_MBHC_REGISTER("WCD_MBHC_FSM_STATUS",
0, 0, 0, 0),
WCD_MBHC_REGISTER("WCD_MBHC_MUX_CTL",
WCD9335_MBHC_CTL_2, 0x70, 4, 0),
};
static const struct wcd_mbhc_intr intr_ids = {
.mbhc_sw_intr = WCD9335_IRQ_MBHC_SW_DET,
.mbhc_btn_press_intr = WCD9335_IRQ_MBHC_BUTTON_PRESS_DET,
.mbhc_btn_release_intr = WCD9335_IRQ_MBHC_BUTTON_RELEASE_DET,
.mbhc_hs_ins_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_LEG_DET,
.mbhc_hs_rem_intr = WCD9335_IRQ_MBHC_ELECT_INS_REM_DET,
.hph_left_ocp = WCD9335_IRQ_HPH_PA_OCPL_FAULT,
.hph_right_ocp = WCD9335_IRQ_HPH_PA_OCPR_FAULT,
};
struct wcd_vbat {
bool is_enabled;
bool adc_config;
/* Variables to cache Vbat ADC output values */
u16 dcp1;
u16 dcp2;
};
struct hpf_work {
struct tasha_priv *tasha;
u8 decimator;
u8 hpf_cut_off_freq;
struct delayed_work dwork;
};
struct tx_mute_work {
struct tasha_priv *tasha;
u8 decimator;
struct delayed_work dwork;
};
struct tasha_priv {
struct device *dev;
struct wcd9xxx *wcd9xxx;
struct snd_soc_codec *codec;
u32 adc_count;
u32 rx_bias_count;
s32 dmic_0_1_clk_cnt;
s32 dmic_2_3_clk_cnt;
s32 dmic_4_5_clk_cnt;
s32 ldo_h_users;
s32 micb_ref[TASHA_MAX_MICBIAS];
s32 pullup_ref[TASHA_MAX_MICBIAS];
u32 anc_slot;
bool anc_func;
/* Vbat module */
struct wcd_vbat vbat;
/* cal info for codec */
struct fw_info *fw_data;
/*track tasha interface type*/
u8 intf_type;
/* num of slim ports required */
struct wcd9xxx_codec_dai_data dai[NUM_CODEC_DAIS];
/* SoundWire data structure */
struct tasha_swr_ctrl_data *swr_ctrl_data;
int nr;
/*compander*/
int comp_enabled[COMPANDER_MAX];
/* Maintain the status of AUX PGA */
int aux_pga_cnt;
u8 aux_l_gain;
u8 aux_r_gain;
bool spkr_pa_widget_on;
struct regulator *spkdrv_reg;
struct regulator *spkdrv2_reg;
bool mbhc_started;
/* class h specific data */
struct wcd_clsh_cdc_data clsh_d;
struct afe_param_cdc_slimbus_slave_cfg slimbus_slave_cfg;
/*
* list used to save/restore registers at start and
* end of impedance measurement
*/
struct list_head reg_save_restore;
/* handle to cpe core */
struct wcd_cpe_core *cpe_core;
u32 current_cpe_clk_freq;
enum tasha_sido_voltage sido_voltage;
int sido_ccl_cnt;
u32 ana_rx_supplies;
/* Multiplication factor used for impedance detection */
int zdet_gain_mul_fact;
/* to track the status */
unsigned long status_mask;
struct work_struct swr_add_devices_work;
struct wcd_swr_ctrl_platform_data swr_plat_data;
/* Port values for Rx and Tx codec_dai */
unsigned int rx_port_value[TASHA_RX_MAX];
unsigned int tx_port_value;
unsigned int vi_feed_value;
/* Tasha Interpolator Mode Select for EAR, HPH_L and HPH_R */
u32 hph_mode;
u16 prim_int_users[TASHA_NUM_INTERPOLATORS];
int spl_src_users[SPLINE_SRC_MAX];
struct wcd9xxx_resmgr_v2 *resmgr;
struct delayed_work power_gate_work;
struct mutex power_lock;
struct mutex sido_lock;
/* mbhc module */
struct wcd_mbhc mbhc;
struct blocking_notifier_head notifier;
struct mutex micb_lock;
struct clk *wcd_ext_clk;
struct clk *wcd_native_clk;
struct mutex swr_read_lock;
struct mutex swr_write_lock;
struct mutex swr_clk_lock;
int swr_clk_users;
int native_clk_users;
int (*zdet_gpio_cb)(struct snd_soc_codec *codec, bool high);
struct snd_info_entry *entry;
struct snd_info_entry *version_entry;
int power_active_ref;
struct on_demand_supply on_demand_list[ON_DEMAND_SUPPLIES_MAX];
int (*machine_codec_event_cb)(struct snd_soc_codec *codec,
enum wcd9335_codec_event);
int spkr_gain_offset;
int spkr_mode;
struct hpf_work tx_hpf_work[TASHA_NUM_DECIMATORS];
struct tx_mute_work tx_mute_dwork[TASHA_NUM_DECIMATORS];
int hph_l_gain;
int hph_r_gain;
int rx_7_count;
int rx_8_count;
bool clk_mode;
bool clk_internal;
/* Bridge I2S RX AND TX Mode */
bool mi2srx_bridge_mode;
bool mi2stx_bridge_mode;
/* Lock to protect mclk enablement */
struct mutex mclk_lock;
};
static int tasha_codec_vote_max_bw(struct snd_soc_codec *codec,
bool vote);
static const struct tasha_reg_mask_val tasha_spkr_default[] = {
{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x80},
{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x80},
{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x01},
{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x01},
{WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x50},
{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x50},
};
static const struct tasha_reg_mask_val tasha_spkr_mode1[] = {
{WCD9335_CDC_COMPANDER7_CTL3, 0x80, 0x00},
{WCD9335_CDC_COMPANDER8_CTL3, 0x80, 0x00},
{WCD9335_CDC_COMPANDER7_CTL7, 0x01, 0x00},
{WCD9335_CDC_COMPANDER8_CTL7, 0x01, 0x00},
{WCD9335_CDC_BOOST0_BOOST_CTL, 0x7C, 0x44},
{WCD9335_CDC_BOOST1_BOOST_CTL, 0x7C, 0x44},
};
enum
{
NO_DEVICE = 0,
HS_WITH_MIC = 1,
HS_WITHOUT_MIC = 2,
};
struct tasha_priv *priv_headset_type;
static ssize_t wcd9xxx_print_name(struct switch_dev *sdev, char *buf)
{
switch (switch_get_state(sdev))
{
case NO_DEVICE:
return sprintf(buf, "No Device\n");
case HS_WITH_MIC:
if(priv_headset_type->mbhc.mbhc_cfg->headset_type == 1) {
return sprintf(buf, "American Headset\n");
} else {
return sprintf(buf, "Headset\n");
}
case HS_WITHOUT_MIC:
return sprintf(buf, "Handset\n");
}
return -EINVAL;
}
/**
* tasha_set_spkr_gain_offset - offset the speaker path
* gain with the given offset value.
*
* @codec: codec instance
* @offset: Indicates speaker path gain offset value.
*
* Returns 0 on success or -EINVAL on error.
*/
int tasha_set_spkr_gain_offset(struct snd_soc_codec *codec, int offset)
{
struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
if (!priv)
return -EINVAL;
priv->spkr_gain_offset = offset;
return 0;
}
EXPORT_SYMBOL(tasha_set_spkr_gain_offset);
/**
* tasha_set_spkr_mode - Configures speaker compander and smartboost
* settings based on speaker mode.
*
* @codec: codec instance
* @mode: Indicates speaker configuration mode.
*
* Returns 0 on success or -EINVAL on error.
*/
int tasha_set_spkr_mode(struct snd_soc_codec *codec, int mode)
{
struct tasha_priv *priv = snd_soc_codec_get_drvdata(codec);
int i;
const struct tasha_reg_mask_val *regs;
int size;
if (!priv)
return -EINVAL;
switch (mode) {
case SPKR_MODE_1:
regs = tasha_spkr_mode1;
size = ARRAY_SIZE(tasha_spkr_mode1);
break;
default:
regs = tasha_spkr_default;
size = ARRAY_SIZE(tasha_spkr_default);
break;
}
priv->spkr_mode = mode;
for (i = 0; i < size; i++)
snd_soc_update_bits(codec, regs[i].reg,
regs[i].mask, regs[i].val);
return 0;
}
EXPORT_SYMBOL(tasha_set_spkr_mode);
static void tasha_enable_sido_buck(struct snd_soc_codec *codec)
{
struct tasha_priv *tasha = snd_soc_codec_get_drvdata(codec);
snd_soc_update_bits(codec, WCD9335_ANA_RCO, 0x80, 0x80);
snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL, 0x02, 0x02);
/* 100us sleep needed after IREF settings */
usleep_range(100, 110);
snd_soc_update_bits(codec, WCD9335_ANA_BUCK_CTL, 0x04, 0x04);
/* 100us sleep needed after VREF settings */
usleep_range(100, 110);
tasha->resmgr->sido_input_src = SIDO_SOURCE_RCO_BG;
}
static void tasha_cdc_sido_ccl_enable(struct tasha_priv *tasha, bool ccl_flag)
{
struct snd_soc_codec *codec = tasha->codec;
if (!codec)
return;
if (!TASHA_IS_2_0(tasha->wcd9xxx->version)) {
dev_dbg(codec->dev, "%s: tasha version < 2p0, return\n",
__func__);
return;
}
dev_dbg(codec->dev, "%s: sido_ccl_cnt=%d, ccl_flag:%d\n",
__func__, tasha->sido_ccl_cnt, ccl_flag);
if (ccl_flag) {
if (++tasha->sido_ccl_cnt == 1)
snd_soc_update_bits(codec,
WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x6E);
} else {
if (tasha->sido_ccl_cnt == 0) {
dev_dbg(codec->dev, "%s: sido_ccl already disabled\n",
__func__);
return;
}
if (--tasha->sido_ccl_cnt == 0)
snd_soc_update_bits(codec,
WCD9335_SIDO_SIDO_CCL_10, 0xFF, 0x02);
}
}
static bool tasha_cdc_is_svs_enabled(struct tasha_priv *tasha)