brintos

brintos / linux-shallow public Read only

0
0
Text · 49.3 KiB · 1702f26 Raw
1593 lines · c
1// SPDX-License-Identifier: GPL-2.02//3// cs35l41-lib.c -- CS35L41 Common functions for HDA and ASoC Audio drivers4//5// Copyright 2017-2021 Cirrus Logic, Inc.6//7// Author: David Rhodes <david.rhodes@cirrus.com>8// Author: Lucas Tanure <lucas.tanure@cirrus.com>9 10#include <linux/dev_printk.h>11#include <linux/module.h>12#include <linux/regmap.h>13#include <linux/regulator/consumer.h>14#include <linux/slab.h>15#include <linux/firmware/cirrus/wmfw.h>16 17#include <sound/cs35l41.h>18 19#define CS35L41_FIRMWARE_OLD_VERSION 0x001C00 /* v0.28.0 */20 21static const struct reg_default cs35l41_reg[] = {22	{ CS35L41_PWR_CTRL1,			0x00000000 },23	{ CS35L41_PWR_CTRL2,			0x00000000 },24	{ CS35L41_PWR_CTRL3,			0x01000010 },25	{ CS35L41_GPIO_PAD_CONTROL,		0x00000000 },26	{ CS35L41_GLOBAL_CLK_CTRL,		0x00000003 },27	{ CS35L41_TST_FS_MON0,			0x00020016 },28	{ CS35L41_BSTCVRT_COEFF,		0x00002424 },29	{ CS35L41_BSTCVRT_SLOPE_LBST,		0x00007500 },30	{ CS35L41_BSTCVRT_PEAK_CUR,		0x0000004A },31	{ CS35L41_SP_ENABLES,			0x00000000 },32	{ CS35L41_SP_RATE_CTRL,			0x00000028 },33	{ CS35L41_SP_FORMAT,			0x18180200 },34	{ CS35L41_SP_HIZ_CTRL,			0x00000002 },35	{ CS35L41_SP_FRAME_TX_SLOT,		0x03020100 },36	{ CS35L41_SP_FRAME_RX_SLOT,		0x00000100 },37	{ CS35L41_SP_TX_WL,			0x00000018 },38	{ CS35L41_SP_RX_WL,			0x00000018 },39	{ CS35L41_DAC_PCM1_SRC,			0x00000008 },40	{ CS35L41_ASP_TX1_SRC,			0x00000018 },41	{ CS35L41_ASP_TX2_SRC,			0x00000019 },42	{ CS35L41_ASP_TX3_SRC,			0x00000000 },43	{ CS35L41_ASP_TX4_SRC,			0x00000000 },44	{ CS35L41_DSP1_RX1_SRC,			0x00000008 },45	{ CS35L41_DSP1_RX2_SRC,			0x00000009 },46	{ CS35L41_DSP1_RX3_SRC,			0x00000018 },47	{ CS35L41_DSP1_RX4_SRC,			0x00000019 },48	{ CS35L41_DSP1_RX5_SRC,			0x00000020 },49	{ CS35L41_DSP1_RX6_SRC,			0x00000021 },50	{ CS35L41_DSP1_RX7_SRC,			0x0000003A },51	{ CS35L41_DSP1_RX8_SRC,			0x0000003B },52	{ CS35L41_NGATE1_SRC,			0x00000008 },53	{ CS35L41_NGATE2_SRC,			0x00000009 },54	{ CS35L41_AMP_DIG_VOL_CTRL,		0x00008000 },55	{ CS35L41_CLASSH_CFG,			0x000B0405 },56	{ CS35L41_WKFET_CFG,			0x00000111 },57	{ CS35L41_NG_CFG,			0x00000033 },58	{ CS35L41_AMP_GAIN_CTRL,		0x00000000 },59	{ CS35L41_IRQ1_MASK1,			0xFFFFFFFF },60	{ CS35L41_IRQ1_MASK2,			0xFFFFFFFF },61	{ CS35L41_IRQ1_MASK3,			0xFFFF87FF },62	{ CS35L41_IRQ1_MASK4,			0xFEFFFFFF },63	{ CS35L41_GPIO1_CTRL1,			0x81000001 },64	{ CS35L41_GPIO2_CTRL1,			0x81000001 },65	{ CS35L41_MIXER_NGATE_CFG,		0x00000000 },66	{ CS35L41_MIXER_NGATE_CH1_CFG,		0x00000303 },67	{ CS35L41_MIXER_NGATE_CH2_CFG,		0x00000303 },68	{ CS35L41_DSP1_CCM_CORE_CTRL,		0x00000101 },69};70 71static bool cs35l41_readable_reg(struct device *dev, unsigned int reg)72{73	switch (reg) {74	case CS35L41_DEVID:75	case CS35L41_REVID:76	case CS35L41_FABID:77	case CS35L41_RELID:78	case CS35L41_OTPID:79	case CS35L41_SFT_RESET:80	case CS35L41_TEST_KEY_CTL:81	case CS35L41_USER_KEY_CTL:82	case CS35L41_OTP_CTRL0:83	case CS35L41_OTP_CTRL3:84	case CS35L41_OTP_CTRL4:85	case CS35L41_OTP_CTRL5:86	case CS35L41_OTP_CTRL6:87	case CS35L41_OTP_CTRL7:88	case CS35L41_OTP_CTRL8:89	case CS35L41_PWR_CTRL1:90	case CS35L41_PWR_CTRL2:91	case CS35L41_PWR_CTRL3:92	case CS35L41_CTRL_OVRRIDE:93	case CS35L41_AMP_OUT_MUTE:94	case CS35L41_PROTECT_REL_ERR_IGN:95	case CS35L41_GPIO_PAD_CONTROL:96	case CS35L41_JTAG_CONTROL:97	case CS35L41_PWRMGT_CTL:98	case CS35L41_WAKESRC_CTL:99	case CS35L41_PWRMGT_STS:100	case CS35L41_PLL_CLK_CTRL:101	case CS35L41_DSP_CLK_CTRL:102	case CS35L41_GLOBAL_CLK_CTRL:103	case CS35L41_DATA_FS_SEL:104	case CS35L41_TST_FS_MON0:105	case CS35L41_MDSYNC_EN:106	case CS35L41_MDSYNC_TX_ID:107	case CS35L41_MDSYNC_PWR_CTRL:108	case CS35L41_MDSYNC_DATA_TX:109	case CS35L41_MDSYNC_TX_STATUS:110	case CS35L41_MDSYNC_DATA_RX:111	case CS35L41_MDSYNC_RX_STATUS:112	case CS35L41_MDSYNC_ERR_STATUS:113	case CS35L41_MDSYNC_SYNC_PTE2:114	case CS35L41_MDSYNC_SYNC_PTE3:115	case CS35L41_MDSYNC_SYNC_MSM_STATUS:116	case CS35L41_BSTCVRT_VCTRL1:117	case CS35L41_BSTCVRT_VCTRL2:118	case CS35L41_BSTCVRT_PEAK_CUR:119	case CS35L41_BSTCVRT_SFT_RAMP:120	case CS35L41_BSTCVRT_COEFF:121	case CS35L41_BSTCVRT_SLOPE_LBST:122	case CS35L41_BSTCVRT_SW_FREQ:123	case CS35L41_BSTCVRT_DCM_CTRL:124	case CS35L41_BSTCVRT_DCM_MODE_FORCE:125	case CS35L41_BSTCVRT_OVERVOLT_CTRL:126	case CS35L41_VI_VOL_POL:127	case CS35L41_DTEMP_WARN_THLD:128	case CS35L41_DTEMP_CFG:129	case CS35L41_DTEMP_EN:130	case CS35L41_VPVBST_FS_SEL:131	case CS35L41_SP_ENABLES:132	case CS35L41_SP_RATE_CTRL:133	case CS35L41_SP_FORMAT:134	case CS35L41_SP_HIZ_CTRL:135	case CS35L41_SP_FRAME_TX_SLOT:136	case CS35L41_SP_FRAME_RX_SLOT:137	case CS35L41_SP_TX_WL:138	case CS35L41_SP_RX_WL:139	case CS35L41_DAC_PCM1_SRC:140	case CS35L41_ASP_TX1_SRC:141	case CS35L41_ASP_TX2_SRC:142	case CS35L41_ASP_TX3_SRC:143	case CS35L41_ASP_TX4_SRC:144	case CS35L41_DSP1_RX1_SRC:145	case CS35L41_DSP1_RX2_SRC:146	case CS35L41_DSP1_RX3_SRC:147	case CS35L41_DSP1_RX4_SRC:148	case CS35L41_DSP1_RX5_SRC:149	case CS35L41_DSP1_RX6_SRC:150	case CS35L41_DSP1_RX7_SRC:151	case CS35L41_DSP1_RX8_SRC:152	case CS35L41_NGATE1_SRC:153	case CS35L41_NGATE2_SRC:154	case CS35L41_AMP_DIG_VOL_CTRL:155	case CS35L41_VPBR_CFG:156	case CS35L41_VBBR_CFG:157	case CS35L41_VPBR_STATUS:158	case CS35L41_VBBR_STATUS:159	case CS35L41_OVERTEMP_CFG:160	case CS35L41_AMP_ERR_VOL:161	case CS35L41_VOL_STATUS_TO_DSP:162	case CS35L41_CLASSH_CFG:163	case CS35L41_WKFET_CFG:164	case CS35L41_NG_CFG:165	case CS35L41_AMP_GAIN_CTRL:166	case CS35L41_DAC_MSM_CFG:167	case CS35L41_IRQ1_CFG:168	case CS35L41_IRQ1_STATUS:169	case CS35L41_IRQ1_STATUS1:170	case CS35L41_IRQ1_STATUS2:171	case CS35L41_IRQ1_STATUS3:172	case CS35L41_IRQ1_STATUS4:173	case CS35L41_IRQ1_RAW_STATUS1:174	case CS35L41_IRQ1_RAW_STATUS2:175	case CS35L41_IRQ1_RAW_STATUS3:176	case CS35L41_IRQ1_RAW_STATUS4:177	case CS35L41_IRQ1_MASK1:178	case CS35L41_IRQ1_MASK2:179	case CS35L41_IRQ1_MASK3:180	case CS35L41_IRQ1_MASK4:181	case CS35L41_IRQ1_FRC1:182	case CS35L41_IRQ1_FRC2:183	case CS35L41_IRQ1_FRC3:184	case CS35L41_IRQ1_FRC4:185	case CS35L41_IRQ1_EDGE1:186	case CS35L41_IRQ1_EDGE4:187	case CS35L41_IRQ1_POL1:188	case CS35L41_IRQ1_POL2:189	case CS35L41_IRQ1_POL3:190	case CS35L41_IRQ1_POL4:191	case CS35L41_IRQ1_DB3:192	case CS35L41_IRQ2_CFG:193	case CS35L41_IRQ2_STATUS:194	case CS35L41_IRQ2_STATUS1:195	case CS35L41_IRQ2_STATUS2:196	case CS35L41_IRQ2_STATUS3:197	case CS35L41_IRQ2_STATUS4:198	case CS35L41_IRQ2_RAW_STATUS1:199	case CS35L41_IRQ2_RAW_STATUS2:200	case CS35L41_IRQ2_RAW_STATUS3:201	case CS35L41_IRQ2_RAW_STATUS4:202	case CS35L41_IRQ2_MASK1:203	case CS35L41_IRQ2_MASK2:204	case CS35L41_IRQ2_MASK3:205	case CS35L41_IRQ2_MASK4:206	case CS35L41_IRQ2_FRC1:207	case CS35L41_IRQ2_FRC2:208	case CS35L41_IRQ2_FRC3:209	case CS35L41_IRQ2_FRC4:210	case CS35L41_IRQ2_EDGE1:211	case CS35L41_IRQ2_EDGE4:212	case CS35L41_IRQ2_POL1:213	case CS35L41_IRQ2_POL2:214	case CS35L41_IRQ2_POL3:215	case CS35L41_IRQ2_POL4:216	case CS35L41_IRQ2_DB3:217	case CS35L41_GPIO_STATUS1:218	case CS35L41_GPIO1_CTRL1:219	case CS35L41_GPIO2_CTRL1:220	case CS35L41_MIXER_NGATE_CFG:221	case CS35L41_MIXER_NGATE_CH1_CFG:222	case CS35L41_MIXER_NGATE_CH2_CFG:223	case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:224	case CS35L41_CLOCK_DETECT_1:225	case CS35L41_DIE_STS1:226	case CS35L41_DIE_STS2:227	case CS35L41_TEMP_CAL1:228	case CS35L41_TEMP_CAL2:229	case CS35L41_DSP1_TIMESTAMP_COUNT:230	case CS35L41_DSP1_SYS_ID:231	case CS35L41_DSP1_SYS_VERSION:232	case CS35L41_DSP1_SYS_CORE_ID:233	case CS35L41_DSP1_SYS_AHB_ADDR:234	case CS35L41_DSP1_SYS_XSRAM_SIZE:235	case CS35L41_DSP1_SYS_YSRAM_SIZE:236	case CS35L41_DSP1_SYS_PSRAM_SIZE:237	case CS35L41_DSP1_SYS_PM_BOOT_SIZE:238	case CS35L41_DSP1_SYS_FEATURES:239	case CS35L41_DSP1_SYS_FIR_FILTERS:240	case CS35L41_DSP1_SYS_LMS_FILTERS:241	case CS35L41_DSP1_SYS_XM_BANK_SIZE:242	case CS35L41_DSP1_SYS_YM_BANK_SIZE:243	case CS35L41_DSP1_SYS_PM_BANK_SIZE:244	case CS35L41_DSP1_RX1_RATE:245	case CS35L41_DSP1_RX2_RATE:246	case CS35L41_DSP1_RX3_RATE:247	case CS35L41_DSP1_RX4_RATE:248	case CS35L41_DSP1_RX5_RATE:249	case CS35L41_DSP1_RX6_RATE:250	case CS35L41_DSP1_RX7_RATE:251	case CS35L41_DSP1_RX8_RATE:252	case CS35L41_DSP1_TX1_RATE:253	case CS35L41_DSP1_TX2_RATE:254	case CS35L41_DSP1_TX3_RATE:255	case CS35L41_DSP1_TX4_RATE:256	case CS35L41_DSP1_TX5_RATE:257	case CS35L41_DSP1_TX6_RATE:258	case CS35L41_DSP1_TX7_RATE:259	case CS35L41_DSP1_TX8_RATE:260	case CS35L41_DSP1_SCRATCH1:261	case CS35L41_DSP1_SCRATCH2:262	case CS35L41_DSP1_SCRATCH3:263	case CS35L41_DSP1_SCRATCH4:264	case CS35L41_DSP1_CCM_CORE_CTRL:265	case CS35L41_DSP1_CCM_CLK_OVERRIDE:266	case CS35L41_DSP1_XM_MSTR_EN:267	case CS35L41_DSP1_XM_CORE_PRI:268	case CS35L41_DSP1_XM_AHB_PACK_PL_PRI:269	case CS35L41_DSP1_XM_AHB_UP_PL_PRI:270	case CS35L41_DSP1_XM_ACCEL_PL0_PRI:271	case CS35L41_DSP1_XM_NPL0_PRI:272	case CS35L41_DSP1_YM_MSTR_EN:273	case CS35L41_DSP1_YM_CORE_PRI:274	case CS35L41_DSP1_YM_AHB_PACK_PL_PRI:275	case CS35L41_DSP1_YM_AHB_UP_PL_PRI:276	case CS35L41_DSP1_YM_ACCEL_PL0_PRI:277	case CS35L41_DSP1_YM_NPL0_PRI:278	case CS35L41_DSP1_MPU_XM_ACCESS0:279	case CS35L41_DSP1_MPU_YM_ACCESS0:280	case CS35L41_DSP1_MPU_WNDW_ACCESS0:281	case CS35L41_DSP1_MPU_XREG_ACCESS0:282	case CS35L41_DSP1_MPU_YREG_ACCESS0:283	case CS35L41_DSP1_MPU_XM_ACCESS1:284	case CS35L41_DSP1_MPU_YM_ACCESS1:285	case CS35L41_DSP1_MPU_WNDW_ACCESS1:286	case CS35L41_DSP1_MPU_XREG_ACCESS1:287	case CS35L41_DSP1_MPU_YREG_ACCESS1:288	case CS35L41_DSP1_MPU_XM_ACCESS2:289	case CS35L41_DSP1_MPU_YM_ACCESS2:290	case CS35L41_DSP1_MPU_WNDW_ACCESS2:291	case CS35L41_DSP1_MPU_XREG_ACCESS2:292	case CS35L41_DSP1_MPU_YREG_ACCESS2:293	case CS35L41_DSP1_MPU_XM_ACCESS3:294	case CS35L41_DSP1_MPU_YM_ACCESS3:295	case CS35L41_DSP1_MPU_WNDW_ACCESS3:296	case CS35L41_DSP1_MPU_XREG_ACCESS3:297	case CS35L41_DSP1_MPU_YREG_ACCESS3:298	case CS35L41_DSP1_MPU_XM_VIO_ADDR:299	case CS35L41_DSP1_MPU_XM_VIO_STATUS:300	case CS35L41_DSP1_MPU_YM_VIO_ADDR:301	case CS35L41_DSP1_MPU_YM_VIO_STATUS:302	case CS35L41_DSP1_MPU_PM_VIO_ADDR:303	case CS35L41_DSP1_MPU_PM_VIO_STATUS:304	case CS35L41_DSP1_MPU_LOCK_CONFIG:305	case CS35L41_DSP1_MPU_WDT_RST_CTRL:306	case CS35L41_OTP_TRIM_1:307	case CS35L41_OTP_TRIM_2:308	case CS35L41_OTP_TRIM_3:309	case CS35L41_OTP_TRIM_4:310	case CS35L41_OTP_TRIM_5:311	case CS35L41_OTP_TRIM_6:312	case CS35L41_OTP_TRIM_7:313	case CS35L41_OTP_TRIM_8:314	case CS35L41_OTP_TRIM_9:315	case CS35L41_OTP_TRIM_10:316	case CS35L41_OTP_TRIM_11:317	case CS35L41_OTP_TRIM_12:318	case CS35L41_OTP_TRIM_13:319	case CS35L41_OTP_TRIM_14:320	case CS35L41_OTP_TRIM_15:321	case CS35L41_OTP_TRIM_16:322	case CS35L41_OTP_TRIM_17:323	case CS35L41_OTP_TRIM_18:324	case CS35L41_OTP_TRIM_19:325	case CS35L41_OTP_TRIM_20:326	case CS35L41_OTP_TRIM_21:327	case CS35L41_OTP_TRIM_22:328	case CS35L41_OTP_TRIM_23:329	case CS35L41_OTP_TRIM_24:330	case CS35L41_OTP_TRIM_25:331	case CS35L41_OTP_TRIM_26:332	case CS35L41_OTP_TRIM_27:333	case CS35L41_OTP_TRIM_28:334	case CS35L41_OTP_TRIM_29:335	case CS35L41_OTP_TRIM_30:336	case CS35L41_OTP_TRIM_31:337	case CS35L41_OTP_TRIM_32:338	case CS35L41_OTP_TRIM_33:339	case CS35L41_OTP_TRIM_34:340	case CS35L41_OTP_TRIM_35:341	case CS35L41_OTP_TRIM_36:342	case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:343	case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:344	case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046:345	case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093:346	case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:347	case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:348	case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:349	case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:350	/*test regs*/351	case CS35L41_PLL_OVR:352	case CS35L41_BST_TEST_DUTY:353	case CS35L41_DIGPWM_IOCTRL:354		return true;355	default:356		return false;357	}358}359 360static bool cs35l41_precious_reg(struct device *dev, unsigned int reg)361{362	switch (reg) {363	case CS35L41_TEST_KEY_CTL:364	case CS35L41_USER_KEY_CTL:365	case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:366	case CS35L41_TST_FS_MON0:367	case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:368	case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:369	case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:370		return true;371	default:372		return false;373	}374}375 376static bool cs35l41_volatile_reg(struct device *dev, unsigned int reg)377{378	switch (reg) {379	case CS35L41_DEVID:380	case CS35L41_SFT_RESET:381	case CS35L41_FABID:382	case CS35L41_REVID:383	case CS35L41_OTPID:384	case CS35L41_TEST_KEY_CTL:385	case CS35L41_USER_KEY_CTL:386	case CS35L41_PWRMGT_CTL:387	case CS35L41_WAKESRC_CTL:388	case CS35L41_PWRMGT_STS:389	case CS35L41_DTEMP_EN:390	case CS35L41_IRQ1_STATUS:391	case CS35L41_IRQ1_STATUS1:392	case CS35L41_IRQ1_STATUS2:393	case CS35L41_IRQ1_STATUS3:394	case CS35L41_IRQ1_STATUS4:395	case CS35L41_IRQ1_RAW_STATUS1:396	case CS35L41_IRQ1_RAW_STATUS2:397	case CS35L41_IRQ1_RAW_STATUS3:398	case CS35L41_IRQ1_RAW_STATUS4:399	case CS35L41_IRQ2_STATUS:400	case CS35L41_IRQ2_STATUS1:401	case CS35L41_IRQ2_STATUS2:402	case CS35L41_IRQ2_STATUS3:403	case CS35L41_IRQ2_STATUS4:404	case CS35L41_IRQ2_RAW_STATUS1:405	case CS35L41_IRQ2_RAW_STATUS2:406	case CS35L41_IRQ2_RAW_STATUS3:407	case CS35L41_IRQ2_RAW_STATUS4:408	case CS35L41_GPIO_STATUS1:409	case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8:410	case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068:411	case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046:412	case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093:413	case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532:414	case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022:415	case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045:416	case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114:417	case CS35L41_DSP1_SCRATCH1:418	case CS35L41_DSP1_SCRATCH2:419	case CS35L41_DSP1_SCRATCH3:420	case CS35L41_DSP1_SCRATCH4:421	case CS35L41_DSP1_CCM_CLK_OVERRIDE ... CS35L41_DSP1_WDT_STATUS:422	case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31:423		return true;424	default:425		return false;426	}427}428 429static const struct cs35l41_otp_packed_element_t otp_map_1[] = {430	/* addr         shift   size */431	{ 0x00002030,	0,	4 }, /*TRIM_OSC_FREQ_TRIM*/432	{ 0x00002030,	7,	1 }, /*TRIM_OSC_TRIM_DONE*/433	{ 0x0000208c,	24,	6 }, /*TST_DIGREG_VREF_TRIM*/434	{ 0x00002090,	14,	4 }, /*TST_REF_TRIM*/435	{ 0x00002090,	10,	4 }, /*TST_REF_TEMPCO_TRIM*/436	{ 0x0000300C,	11,	4 }, /*PLL_LDOA_TST_VREF_TRIM*/437	{ 0x0000394C,	23,	2 }, /*BST_ATEST_CM_VOFF*/438	{ 0x00003950,	0,	7 }, /*BST_ATRIM_IADC_OFFSET*/439	{ 0x00003950,	8,	7 }, /*BST_ATRIM_IADC_GAIN1*/440	{ 0x00003950,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/441	{ 0x00003950,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/442	{ 0x00003954,	0,	7 }, /*BST_ATRIM_IADC_OFFSET2*/443	{ 0x00003954,	8,	7 }, /*BST_ATRIM_IADC_GAIN2*/444	{ 0x00003954,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/445	{ 0x00003954,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/446	{ 0x00003958,	0,	7 }, /*BST_ATRIM_IADC_OFFSET3*/447	{ 0x00003958,	8,	7 }, /*BST_ATRIM_IADC_GAIN3*/448	{ 0x00003958,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/449	{ 0x00003958,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/450	{ 0x0000395C,	0,	7 }, /*BST_ATRIM_IADC_OFFSET4*/451	{ 0x0000395C,	8,	7 }, /*BST_ATRIM_IADC_GAIN4*/452	{ 0x0000395C,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/453	{ 0x0000395C,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/454	{ 0x0000416C,	0,	8 }, /*VMON_GAIN_OTP_VAL*/455	{ 0x00004160,	0,	7 }, /*VMON_OFFSET_OTP_VAL*/456	{ 0x0000416C,	8,	8 }, /*IMON_GAIN_OTP_VAL*/457	{ 0x00004160,	16,	10 }, /*IMON_OFFSET_OTP_VAL*/458	{ 0x0000416C,	16,	12 }, /*VMON_CM_GAIN_OTP_VAL*/459	{ 0x0000416C,	28,	1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/460	{ 0x00004170,	0,	6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/461	{ 0x00004170,	6,	1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/462	{ 0x00004170,	8,	6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/463	{ 0x00004170,	14,	1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/464	{ 0x00004170,	16,	9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/465	{ 0x00004360,	0,	5 }, /*TEMP_GAIN_OTP_VAL*/466	{ 0x00004360,	6,	9 }, /*TEMP_OFFSET_OTP_VAL*/467	{ 0x00004448,	0,	8 }, /*VP_SARADC_OFFSET*/468	{ 0x00004448,	8,	8 }, /*VP_GAIN_INDEX*/469	{ 0x00004448,	16,	8 }, /*VBST_SARADC_OFFSET*/470	{ 0x00004448,	24,	8 }, /*VBST_GAIN_INDEX*/471	{ 0x0000444C,	0,	3 }, /*ANA_SELINVREF*/472	{ 0x00006E30,	0,	5 }, /*GAIN_ERR_COEFF_0*/473	{ 0x00006E30,	8,	5 }, /*GAIN_ERR_COEFF_1*/474	{ 0x00006E30,	16,	5 }, /*GAIN_ERR_COEFF_2*/475	{ 0x00006E30,	24,	5 }, /*GAIN_ERR_COEFF_3*/476	{ 0x00006E34,	0,	5 }, /*GAIN_ERR_COEFF_4*/477	{ 0x00006E34,	8,	5 }, /*GAIN_ERR_COEFF_5*/478	{ 0x00006E34,	16,	5 }, /*GAIN_ERR_COEFF_6*/479	{ 0x00006E34,	24,	5 }, /*GAIN_ERR_COEFF_7*/480	{ 0x00006E38,	0,	5 }, /*GAIN_ERR_COEFF_8*/481	{ 0x00006E38,	8,	5 }, /*GAIN_ERR_COEFF_9*/482	{ 0x00006E38,	16,	5 }, /*GAIN_ERR_COEFF_10*/483	{ 0x00006E38,	24,	5 }, /*GAIN_ERR_COEFF_11*/484	{ 0x00006E3C,	0,	5 }, /*GAIN_ERR_COEFF_12*/485	{ 0x00006E3C,	8,	5 }, /*GAIN_ERR_COEFF_13*/486	{ 0x00006E3C,	16,	5 }, /*GAIN_ERR_COEFF_14*/487	{ 0x00006E3C,	24,	5 }, /*GAIN_ERR_COEFF_15*/488	{ 0x00006E40,	0,	5 }, /*GAIN_ERR_COEFF_16*/489	{ 0x00006E40,	8,	5 }, /*GAIN_ERR_COEFF_17*/490	{ 0x00006E40,	16,	5 }, /*GAIN_ERR_COEFF_18*/491	{ 0x00006E40,	24,	5 }, /*GAIN_ERR_COEFF_19*/492	{ 0x00006E44,	0,	5 }, /*GAIN_ERR_COEFF_20*/493	{ 0x00006E48,	0,	10 }, /*VOFF_GAIN_0*/494	{ 0x00006E48,	10,	10 }, /*VOFF_GAIN_1*/495	{ 0x00006E48,	20,	10 }, /*VOFF_GAIN_2*/496	{ 0x00006E4C,	0,	10 }, /*VOFF_GAIN_3*/497	{ 0x00006E4C,	10,	10 }, /*VOFF_GAIN_4*/498	{ 0x00006E4C,	20,	10 }, /*VOFF_GAIN_5*/499	{ 0x00006E50,	0,	10 }, /*VOFF_GAIN_6*/500	{ 0x00006E50,	10,	10 }, /*VOFF_GAIN_7*/501	{ 0x00006E50,	20,	10 }, /*VOFF_GAIN_8*/502	{ 0x00006E54,	0,	10 }, /*VOFF_GAIN_9*/503	{ 0x00006E54,	10,	10 }, /*VOFF_GAIN_10*/504	{ 0x00006E54,	20,	10 }, /*VOFF_GAIN_11*/505	{ 0x00006E58,	0,	10 }, /*VOFF_GAIN_12*/506	{ 0x00006E58,	10,	10 }, /*VOFF_GAIN_13*/507	{ 0x00006E58,	20,	10 }, /*VOFF_GAIN_14*/508	{ 0x00006E5C,	0,	10 }, /*VOFF_GAIN_15*/509	{ 0x00006E5C,	10,	10 }, /*VOFF_GAIN_16*/510	{ 0x00006E5C,	20,	10 }, /*VOFF_GAIN_17*/511	{ 0x00006E60,	0,	10 }, /*VOFF_GAIN_18*/512	{ 0x00006E60,	10,	10 }, /*VOFF_GAIN_19*/513	{ 0x00006E60,	20,	10 }, /*VOFF_GAIN_20*/514	{ 0x00006E64,	0,	10 }, /*VOFF_INT1*/515	{ 0x00007418,	7,	5 }, /*DS_SPK_INT1_CAP_TRIM*/516	{ 0x0000741C,	0,	5 }, /*DS_SPK_INT2_CAP_TRIM*/517	{ 0x0000741C,	11,	4 }, /*DS_SPK_LPF_CAP_TRIM*/518	{ 0x0000741C,	19,	4 }, /*DS_SPK_QUAN_CAP_TRIM*/519	{ 0x00007434,	17,	1 }, /*FORCE_CAL*/520	{ 0x00007434,	18,	7 }, /*CAL_OVERRIDE*/521	{ 0x00007068,	0,	9 }, /*MODIX*/522	{ 0x0000410C,	7,	1 }, /*VIMON_DLY_NOT_COMB*/523	{ 0x0000400C,	0,	7 }, /*VIMON_DLY*/524	{ 0x00000000,	0,	1 }, /*extra bit*/525	{ 0x00017040,	0,	8 }, /*X_COORDINATE*/526	{ 0x00017040,	8,	8 }, /*Y_COORDINATE*/527	{ 0x00017040,	16,	8 }, /*WAFER_ID*/528	{ 0x00017040,	24,	8 }, /*DVS*/529	{ 0x00017044,	0,	24 }, /*LOT_NUMBER*/530};531 532static const struct cs35l41_otp_packed_element_t otp_map_2[] = {533	/* addr         shift   size */534	{ 0x00002030,	0,	4 }, /*TRIM_OSC_FREQ_TRIM*/535	{ 0x00002030,	7,	1 }, /*TRIM_OSC_TRIM_DONE*/536	{ 0x0000208c,	24,	6 }, /*TST_DIGREG_VREF_TRIM*/537	{ 0x00002090,	14,	4 }, /*TST_REF_TRIM*/538	{ 0x00002090,	10,	4 }, /*TST_REF_TEMPCO_TRIM*/539	{ 0x0000300C,	11,	4 }, /*PLL_LDOA_TST_VREF_TRIM*/540	{ 0x0000394C,	23,	2 }, /*BST_ATEST_CM_VOFF*/541	{ 0x00003950,	0,	7 }, /*BST_ATRIM_IADC_OFFSET*/542	{ 0x00003950,	8,	7 }, /*BST_ATRIM_IADC_GAIN1*/543	{ 0x00003950,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET1*/544	{ 0x00003950,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN1*/545	{ 0x00003954,	0,	7 }, /*BST_ATRIM_IADC_OFFSET2*/546	{ 0x00003954,	8,	7 }, /*BST_ATRIM_IADC_GAIN2*/547	{ 0x00003954,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET2*/548	{ 0x00003954,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN2*/549	{ 0x00003958,	0,	7 }, /*BST_ATRIM_IADC_OFFSET3*/550	{ 0x00003958,	8,	7 }, /*BST_ATRIM_IADC_GAIN3*/551	{ 0x00003958,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET3*/552	{ 0x00003958,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN3*/553	{ 0x0000395C,	0,	7 }, /*BST_ATRIM_IADC_OFFSET4*/554	{ 0x0000395C,	8,	7 }, /*BST_ATRIM_IADC_GAIN4*/555	{ 0x0000395C,	16,	8 }, /*BST_ATRIM_IPKCOMP_OFFSET4*/556	{ 0x0000395C,	24,	8 }, /*BST_ATRIM_IPKCOMP_GAIN4*/557	{ 0x0000416C,	0,	8 }, /*VMON_GAIN_OTP_VAL*/558	{ 0x00004160,	0,	7 }, /*VMON_OFFSET_OTP_VAL*/559	{ 0x0000416C,	8,	8 }, /*IMON_GAIN_OTP_VAL*/560	{ 0x00004160,	16,	10 }, /*IMON_OFFSET_OTP_VAL*/561	{ 0x0000416C,	16,	12 }, /*VMON_CM_GAIN_OTP_VAL*/562	{ 0x0000416C,	28,	1 }, /*VMON_CM_GAIN_SIGN_OTP_VAL*/563	{ 0x00004170,	0,	6 }, /*IMON_CAL_TEMPCO_OTP_VAL*/564	{ 0x00004170,	6,	1 }, /*IMON_CAL_TEMPCO_SIGN_OTP*/565	{ 0x00004170,	8,	6 }, /*IMON_CAL_TEMPCO2_OTP_VAL*/566	{ 0x00004170,	14,	1 }, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/567	{ 0x00004170,	16,	9 }, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/568	{ 0x00004360,	0,	5 }, /*TEMP_GAIN_OTP_VAL*/569	{ 0x00004360,	6,	9 }, /*TEMP_OFFSET_OTP_VAL*/570	{ 0x00004448,	0,	8 }, /*VP_SARADC_OFFSET*/571	{ 0x00004448,	8,	8 }, /*VP_GAIN_INDEX*/572	{ 0x00004448,	16,	8 }, /*VBST_SARADC_OFFSET*/573	{ 0x00004448,	24,	8 }, /*VBST_GAIN_INDEX*/574	{ 0x0000444C,	0,	3 }, /*ANA_SELINVREF*/575	{ 0x00006E30,	0,	5 }, /*GAIN_ERR_COEFF_0*/576	{ 0x00006E30,	8,	5 }, /*GAIN_ERR_COEFF_1*/577	{ 0x00006E30,	16,	5 }, /*GAIN_ERR_COEFF_2*/578	{ 0x00006E30,	24,	5 }, /*GAIN_ERR_COEFF_3*/579	{ 0x00006E34,	0,	5 }, /*GAIN_ERR_COEFF_4*/580	{ 0x00006E34,	8,	5 }, /*GAIN_ERR_COEFF_5*/581	{ 0x00006E34,	16,	5 }, /*GAIN_ERR_COEFF_6*/582	{ 0x00006E34,	24,	5 }, /*GAIN_ERR_COEFF_7*/583	{ 0x00006E38,	0,	5 }, /*GAIN_ERR_COEFF_8*/584	{ 0x00006E38,	8,	5 }, /*GAIN_ERR_COEFF_9*/585	{ 0x00006E38,	16,	5 }, /*GAIN_ERR_COEFF_10*/586	{ 0x00006E38,	24,	5 }, /*GAIN_ERR_COEFF_11*/587	{ 0x00006E3C,	0,	5 }, /*GAIN_ERR_COEFF_12*/588	{ 0x00006E3C,	8,	5 }, /*GAIN_ERR_COEFF_13*/589	{ 0x00006E3C,	16,	5 }, /*GAIN_ERR_COEFF_14*/590	{ 0x00006E3C,	24,	5 }, /*GAIN_ERR_COEFF_15*/591	{ 0x00006E40,	0,	5 }, /*GAIN_ERR_COEFF_16*/592	{ 0x00006E40,	8,	5 }, /*GAIN_ERR_COEFF_17*/593	{ 0x00006E40,	16,	5 }, /*GAIN_ERR_COEFF_18*/594	{ 0x00006E40,	24,	5 }, /*GAIN_ERR_COEFF_19*/595	{ 0x00006E44,	0,	5 }, /*GAIN_ERR_COEFF_20*/596	{ 0x00006E48,	0,	10 }, /*VOFF_GAIN_0*/597	{ 0x00006E48,	10,	10 }, /*VOFF_GAIN_1*/598	{ 0x00006E48,	20,	10 }, /*VOFF_GAIN_2*/599	{ 0x00006E4C,	0,	10 }, /*VOFF_GAIN_3*/600	{ 0x00006E4C,	10,	10 }, /*VOFF_GAIN_4*/601	{ 0x00006E4C,	20,	10 }, /*VOFF_GAIN_5*/602	{ 0x00006E50,	0,	10 }, /*VOFF_GAIN_6*/603	{ 0x00006E50,	10,	10 }, /*VOFF_GAIN_7*/604	{ 0x00006E50,	20,	10 }, /*VOFF_GAIN_8*/605	{ 0x00006E54,	0,	10 }, /*VOFF_GAIN_9*/606	{ 0x00006E54,	10,	10 }, /*VOFF_GAIN_10*/607	{ 0x00006E54,	20,	10 }, /*VOFF_GAIN_11*/608	{ 0x00006E58,	0,	10 }, /*VOFF_GAIN_12*/609	{ 0x00006E58,	10,	10 }, /*VOFF_GAIN_13*/610	{ 0x00006E58,	20,	10 }, /*VOFF_GAIN_14*/611	{ 0x00006E5C,	0,	10 }, /*VOFF_GAIN_15*/612	{ 0x00006E5C,	10,	10 }, /*VOFF_GAIN_16*/613	{ 0x00006E5C,	20,	10 }, /*VOFF_GAIN_17*/614	{ 0x00006E60,	0,	10 }, /*VOFF_GAIN_18*/615	{ 0x00006E60,	10,	10 }, /*VOFF_GAIN_19*/616	{ 0x00006E60,	20,	10 }, /*VOFF_GAIN_20*/617	{ 0x00006E64,	0,	10 }, /*VOFF_INT1*/618	{ 0x00007418,	7,	5 }, /*DS_SPK_INT1_CAP_TRIM*/619	{ 0x0000741C,	0,	5 }, /*DS_SPK_INT2_CAP_TRIM*/620	{ 0x0000741C,	11,	4 }, /*DS_SPK_LPF_CAP_TRIM*/621	{ 0x0000741C,	19,	4 }, /*DS_SPK_QUAN_CAP_TRIM*/622	{ 0x00007434,	17,	1 }, /*FORCE_CAL*/623	{ 0x00007434,	18,	7 }, /*CAL_OVERRIDE*/624	{ 0x00007068,	0,	9 }, /*MODIX*/625	{ 0x0000410C,	7,	1 }, /*VIMON_DLY_NOT_COMB*/626	{ 0x0000400C,	0,	7 }, /*VIMON_DLY*/627	{ 0x00004000,	11,	1 }, /*VMON_POL*/628	{ 0x00017040,	0,	8 }, /*X_COORDINATE*/629	{ 0x00017040,	8,	8 }, /*Y_COORDINATE*/630	{ 0x00017040,	16,	8 }, /*WAFER_ID*/631	{ 0x00017040,	24,	8 }, /*DVS*/632	{ 0x00017044,	0,	24 }, /*LOT_NUMBER*/633};634 635static const struct reg_sequence cs35l41_reva0_errata_patch[] = {636	{ 0x00003854,			 0x05180240 },637	{ CS35L41_VIMON_SPKMON_RESYNC,	 0x00000000 },638	{ 0x00004310,			 0x00000000 },639	{ CS35L41_VPVBST_FS_SEL,	 0x00000000 },640	{ CS35L41_OTP_TRIM_30,		 0x9091A1C8 },641	{ 0x00003014,			 0x0200EE0E },642	{ CS35L41_BSTCVRT_DCM_CTRL,	 0x00000051 },643	{ 0x00000054,			 0x00000004 },644	{ CS35L41_IRQ1_DB3,		 0x00000000 },645	{ CS35L41_IRQ2_DB3,		 0x00000000 },646	{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },647	{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },648	{ CS35L41_PWR_CTRL2,		 0x00000000 },649	{ CS35L41_AMP_GAIN_CTRL,	 0x00000000 },650	{ CS35L41_ASP_TX3_SRC,		 0x00000000 },651	{ CS35L41_ASP_TX4_SRC,		 0x00000000 },652};653 654static const struct reg_sequence cs35l41_revb0_errata_patch[] = {655	{ CS35L41_VIMON_SPKMON_RESYNC,	 0x00000000 },656	{ 0x00004310,			 0x00000000 },657	{ CS35L41_VPVBST_FS_SEL,	 0x00000000 },658	{ CS35L41_BSTCVRT_DCM_CTRL,	 0x00000051 },659	{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },660	{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },661	{ CS35L41_PWR_CTRL2,		 0x00000000 },662	{ CS35L41_AMP_GAIN_CTRL,	 0x00000000 },663	{ CS35L41_ASP_TX3_SRC,		 0x00000000 },664	{ CS35L41_ASP_TX4_SRC,		 0x00000000 },665};666 667static const struct reg_sequence cs35l41_revb2_errata_patch[] = {668	{ CS35L41_VIMON_SPKMON_RESYNC,	 0x00000000 },669	{ 0x00004310,			 0x00000000 },670	{ CS35L41_VPVBST_FS_SEL,	 0x00000000 },671	{ CS35L41_BSTCVRT_DCM_CTRL,	 0x00000051 },672	{ CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000 },673	{ CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000 },674	{ CS35L41_PWR_CTRL2,		 0x00000000 },675	{ CS35L41_AMP_GAIN_CTRL,	 0x00000000 },676	{ CS35L41_ASP_TX3_SRC,		 0x00000000 },677	{ CS35L41_ASP_TX4_SRC,		 0x00000000 },678};679 680static const struct reg_sequence cs35l41_fs_errata_patch[] = {681	{ CS35L41_DSP1_RX1_RATE,	0x00000001 },682	{ CS35L41_DSP1_RX2_RATE,	0x00000001 },683	{ CS35L41_DSP1_RX3_RATE,	0x00000001 },684	{ CS35L41_DSP1_RX4_RATE,	0x00000001 },685	{ CS35L41_DSP1_RX5_RATE,	0x00000001 },686	{ CS35L41_DSP1_RX6_RATE,	0x00000001 },687	{ CS35L41_DSP1_RX7_RATE,	0x00000001 },688	{ CS35L41_DSP1_RX8_RATE,	0x00000001 },689	{ CS35L41_DSP1_TX1_RATE,	0x00000001 },690	{ CS35L41_DSP1_TX2_RATE,	0x00000001 },691	{ CS35L41_DSP1_TX3_RATE,	0x00000001 },692	{ CS35L41_DSP1_TX4_RATE,	0x00000001 },693	{ CS35L41_DSP1_TX5_RATE,	0x00000001 },694	{ CS35L41_DSP1_TX6_RATE,	0x00000001 },695	{ CS35L41_DSP1_TX7_RATE,	0x00000001 },696	{ CS35L41_DSP1_TX8_RATE,	0x00000001 },697};698 699static const struct cs35l41_otp_map_element_t cs35l41_otp_map_map[] = {700	{701		.id = 0x01,702		.map = otp_map_1,703		.num_elements = ARRAY_SIZE(otp_map_1),704		.bit_offset = 16,705		.word_offset = 2,706	},707	{708		.id = 0x02,709		.map = otp_map_2,710		.num_elements = ARRAY_SIZE(otp_map_2),711		.bit_offset = 16,712		.word_offset = 2,713	},714	{715		.id = 0x03,716		.map = otp_map_2,717		.num_elements = ARRAY_SIZE(otp_map_2),718		.bit_offset = 16,719		.word_offset = 2,720	},721	{722		.id = 0x06,723		.map = otp_map_2,724		.num_elements = ARRAY_SIZE(otp_map_2),725		.bit_offset = 16,726		.word_offset = 2,727	},728	{729		.id = 0x08,730		.map = otp_map_1,731		.num_elements = ARRAY_SIZE(otp_map_1),732		.bit_offset = 16,733		.word_offset = 2,734	},735};736 737struct regmap_config cs35l41_regmap_i2c = {738	.reg_bits = 32,739	.val_bits = 32,740	.reg_stride = CS35L41_REGSTRIDE,741	.reg_format_endian = REGMAP_ENDIAN_BIG,742	.val_format_endian = REGMAP_ENDIAN_BIG,743	.max_register = CS35L41_LASTREG,744	.reg_defaults = cs35l41_reg,745	.num_reg_defaults = ARRAY_SIZE(cs35l41_reg),746	.volatile_reg = cs35l41_volatile_reg,747	.readable_reg = cs35l41_readable_reg,748	.precious_reg = cs35l41_precious_reg,749	.cache_type = REGCACHE_MAPLE,750};751EXPORT_SYMBOL_GPL(cs35l41_regmap_i2c);752 753struct regmap_config cs35l41_regmap_spi = {754	.reg_bits = 32,755	.val_bits = 32,756	.pad_bits = 16,757	.reg_stride = CS35L41_REGSTRIDE,758	.reg_format_endian = REGMAP_ENDIAN_BIG,759	.val_format_endian = REGMAP_ENDIAN_BIG,760	.max_register = CS35L41_LASTREG,761	.reg_defaults = cs35l41_reg,762	.num_reg_defaults = ARRAY_SIZE(cs35l41_reg),763	.volatile_reg = cs35l41_volatile_reg,764	.readable_reg = cs35l41_readable_reg,765	.precious_reg = cs35l41_precious_reg,766	.cache_type = REGCACHE_MAPLE,767};768EXPORT_SYMBOL_GPL(cs35l41_regmap_spi);769 770static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id)771{772	int i;773 774	for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) {775		if (cs35l41_otp_map_map[i].id == otp_id)776			return &cs35l41_otp_map_map[i];777	}778 779	return NULL;780}781 782int cs35l41_test_key_unlock(struct device *dev, struct regmap *regmap)783{784	static const struct reg_sequence unlock[] = {785		{ CS35L41_TEST_KEY_CTL, 0x00000055 },786		{ CS35L41_TEST_KEY_CTL, 0x000000AA },787	};788	int ret;789 790	ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock));791	if (ret)792		dev_err(dev, "Failed to unlock test key: %d\n", ret);793 794	return ret;795}796EXPORT_SYMBOL_GPL(cs35l41_test_key_unlock);797 798int cs35l41_test_key_lock(struct device *dev, struct regmap *regmap)799{800	static const struct reg_sequence unlock[] = {801		{ CS35L41_TEST_KEY_CTL, 0x000000CC },802		{ CS35L41_TEST_KEY_CTL, 0x00000033 },803	};804	int ret;805 806	ret = regmap_multi_reg_write(regmap, unlock, ARRAY_SIZE(unlock));807	if (ret)808		dev_err(dev, "Failed to lock test key: %d\n", ret);809 810	return ret;811}812EXPORT_SYMBOL_GPL(cs35l41_test_key_lock);813 814/* Must be called with the TEST_KEY unlocked */815int cs35l41_otp_unpack(struct device *dev, struct regmap *regmap)816{817	const struct cs35l41_otp_map_element_t *otp_map_match;818	const struct cs35l41_otp_packed_element_t *otp_map;819	int bit_offset, word_offset, ret, i;820	unsigned int bit_sum = 8;821	u32 otp_val, otp_id_reg;822	u32 *otp_mem;823 824	otp_mem = kmalloc_array(CS35L41_OTP_SIZE_WORDS, sizeof(*otp_mem), GFP_KERNEL);825	if (!otp_mem)826		return -ENOMEM;827 828	ret = regmap_read(regmap, CS35L41_OTPID, &otp_id_reg);829	if (ret) {830		dev_err(dev, "Read OTP ID failed: %d\n", ret);831		goto err_otp_unpack;832	}833 834	otp_map_match = cs35l41_find_otp_map(otp_id_reg);835 836	if (!otp_map_match) {837		dev_err(dev, "OTP Map matching ID %d not found\n", otp_id_reg);838		ret = -EINVAL;839		goto err_otp_unpack;840	}841 842	ret = regmap_bulk_read(regmap, CS35L41_OTP_MEM0, otp_mem, CS35L41_OTP_SIZE_WORDS);843	if (ret) {844		dev_err(dev, "Read OTP Mem failed: %d\n", ret);845		goto err_otp_unpack;846	}847 848	otp_map = otp_map_match->map;849 850	bit_offset = otp_map_match->bit_offset;851	word_offset = otp_map_match->word_offset;852 853	for (i = 0; i < otp_map_match->num_elements; i++) {854		dev_dbg(dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d, otp_map[i].size = %u\n",855			bit_offset, word_offset, bit_sum % 32, otp_map[i].size);856		if (bit_offset + otp_map[i].size - 1 >= 32) {857			otp_val = (otp_mem[word_offset] &858					GENMASK(31, bit_offset)) >> bit_offset;859			otp_val |= (otp_mem[++word_offset] &860					GENMASK(bit_offset + otp_map[i].size - 33, 0)) <<861					(32 - bit_offset);862			bit_offset += otp_map[i].size - 32;863		} else if (bit_offset + otp_map[i].size - 1 >= 0) {864			otp_val = (otp_mem[word_offset] &865				   GENMASK(bit_offset + otp_map[i].size - 1, bit_offset)866				  ) >> bit_offset;867			bit_offset += otp_map[i].size;868		} else /* both bit_offset and otp_map[i].size are 0 */869			otp_val = 0;870 871		bit_sum += otp_map[i].size;872 873		if (bit_offset == 32) {874			bit_offset = 0;875			word_offset++;876		}877 878		if (otp_map[i].reg != 0) {879			ret = regmap_update_bits(regmap, otp_map[i].reg,880						 GENMASK(otp_map[i].shift + otp_map[i].size - 1,881							 otp_map[i].shift),882						 otp_val << otp_map[i].shift);883			if (ret < 0) {884				dev_err(dev, "Write OTP val failed: %d\n", ret);885				goto err_otp_unpack;886			}887		}888	}889 890	ret = 0;891 892err_otp_unpack:893	kfree(otp_mem);894 895	return ret;896}897EXPORT_SYMBOL_GPL(cs35l41_otp_unpack);898 899/* Must be called with the TEST_KEY unlocked */900int cs35l41_register_errata_patch(struct device *dev, struct regmap *reg, unsigned int reg_revid)901{902	char *rev;903	int ret;904 905	switch (reg_revid) {906	case CS35L41_REVID_A0:907		ret = regmap_register_patch(reg, cs35l41_reva0_errata_patch,908					    ARRAY_SIZE(cs35l41_reva0_errata_patch));909		rev = "A0";910		break;911	case CS35L41_REVID_B0:912		ret = regmap_register_patch(reg, cs35l41_revb0_errata_patch,913					    ARRAY_SIZE(cs35l41_revb0_errata_patch));914		rev = "B0";915		break;916	case CS35L41_REVID_B2:917		ret = regmap_register_patch(reg, cs35l41_revb2_errata_patch,918					    ARRAY_SIZE(cs35l41_revb2_errata_patch));919		rev = "B2";920		break;921	default:922		ret = -EINVAL;923		rev = "XX";924		break;925	}926 927	if (ret)928		dev_err(dev, "Failed to apply %s errata patch: %d\n", rev, ret);929 930	ret = regmap_write(reg, CS35L41_DSP1_CCM_CORE_CTRL, 0);931	if (ret < 0)932		dev_err(dev, "Write CCM_CORE_CTRL failed: %d\n", ret);933 934	return ret;935}936EXPORT_SYMBOL_GPL(cs35l41_register_errata_patch);937 938int cs35l41_set_channels(struct device *dev, struct regmap *reg,939			 unsigned int tx_num, const unsigned int *tx_slot,940			 unsigned int rx_num, const unsigned int *rx_slot)941{942	unsigned int val, mask;943	int i;944 945	if (tx_num > 4 || rx_num > 2)946		return -EINVAL;947 948	val = 0;949	mask = 0;950	for (i = 0; i < rx_num; i++) {951		dev_dbg(dev, "rx slot %d position = %d\n", i, rx_slot[i]);952		val |= rx_slot[i] << (i * 8);953		mask |= 0x3F << (i * 8);954	}955	regmap_update_bits(reg, CS35L41_SP_FRAME_RX_SLOT, mask, val);956 957	val = 0;958	mask = 0;959	for (i = 0; i < tx_num; i++) {960		dev_dbg(dev, "tx slot %d position = %d\n", i, tx_slot[i]);961		val |= tx_slot[i] << (i * 8);962		mask |= 0x3F << (i * 8);963	}964	regmap_update_bits(reg, CS35L41_SP_FRAME_TX_SLOT, mask, val);965 966	return 0;967}968EXPORT_SYMBOL_GPL(cs35l41_set_channels);969 970static const unsigned char cs35l41_bst_k1_table[4][5] = {971	{ 0x24, 0x32, 0x32, 0x4F, 0x57 },972	{ 0x24, 0x32, 0x32, 0x4F, 0x57 },973	{ 0x40, 0x32, 0x32, 0x4F, 0x57 },974	{ 0x40, 0x32, 0x32, 0x4F, 0x57 }975};976 977static const unsigned char cs35l41_bst_k2_table[4][5] = {978	{ 0x24, 0x49, 0x66, 0xA3, 0xEA },979	{ 0x24, 0x49, 0x66, 0xA3, 0xEA },980	{ 0x48, 0x49, 0x66, 0xA3, 0xEA },981	{ 0x48, 0x49, 0x66, 0xA3, 0xEA }982};983 984static const unsigned char cs35l41_bst_slope_table[4] = {985	0x75, 0x6B, 0x3B, 0x28986};987 988static int cs35l41_boost_config(struct device *dev, struct regmap *regmap, int boost_ind,989				int boost_cap, int boost_ipk)990{991	unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled;992	int ret;993 994	switch (boost_ind) {995	case 1000:	/* 1.0 uH */996		bst_lbst_val = 0;997		break;998	case 1200:	/* 1.2 uH */999		bst_lbst_val = 1;1000		break;1001	case 1500:	/* 1.5 uH */1002		bst_lbst_val = 2;1003		break;1004	case 2200:	/* 2.2 uH */1005		bst_lbst_val = 3;1006		break;1007	default:1008		dev_err(dev, "Invalid boost inductor value: %d nH\n", boost_ind);1009		return -EINVAL;1010	}1011 1012	switch (boost_cap) {1013	case 0 ... 19:1014		bst_cbst_range = 0;1015		break;1016	case 20 ... 50:1017		bst_cbst_range = 1;1018		break;1019	case 51 ... 100:1020		bst_cbst_range = 2;1021		break;1022	case 101 ... 200:1023		bst_cbst_range = 3;1024		break;1025	default:1026		if (boost_cap < 0) {1027			dev_err(dev, "Invalid boost capacitor value: %d nH\n", boost_cap);1028			return -EINVAL;1029		}1030		/* 201 uF and greater */1031		bst_cbst_range = 4;1032	}1033 1034	if (boost_ipk < 1600 || boost_ipk > 4500) {1035		dev_err(dev, "Invalid boost inductor peak current: %d mA\n", boost_ipk);1036		return -EINVAL;1037	}1038 1039	ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF,1040				 CS35L41_BST_K1_MASK | CS35L41_BST_K2_MASK,1041				 cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range]1042					<< CS35L41_BST_K1_SHIFT |1043				 cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range]1044					<< CS35L41_BST_K2_SHIFT);1045	if (ret) {1046		dev_err(dev, "Failed to write boost coefficients: %d\n", ret);1047		return ret;1048	}1049 1050	ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST,1051				 CS35L41_BST_SLOPE_MASK | CS35L41_BST_LBST_VAL_MASK,1052				 cs35l41_bst_slope_table[bst_lbst_val]1053					<< CS35L41_BST_SLOPE_SHIFT |1054				 bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT);1055	if (ret) {1056		dev_err(dev, "Failed to write boost slope/inductor value: %d\n", ret);1057		return ret;1058	}1059 1060	bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10;1061 1062	ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, CS35L41_BST_IPK_MASK,1063				 bst_ipk_scaled << CS35L41_BST_IPK_SHIFT);1064	if (ret) {1065		dev_err(dev, "Failed to write boost inductor peak current: %d\n", ret);1066		return ret;1067	}1068 1069	regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,1070			   CS35L41_BST_EN_DEFAULT << CS35L41_BST_EN_SHIFT);1071 1072	return 0;1073}1074 1075static const struct reg_sequence cs35l41_safe_to_reset[] = {1076	{ 0x00000040,			0x00000055 },1077	{ 0x00000040,			0x000000AA },1078	{ 0x0000393C,			0x000000C0, 6000},1079	{ 0x0000393C,			0x00000000 },1080	{ 0x00007414,			0x00C82222 },1081	{ 0x0000742C,			0x00000000 },1082	{ 0x00000040,			0x000000CC },1083	{ 0x00000040,			0x00000033 },1084};1085 1086static const struct reg_sequence cs35l41_active_to_safe_start[] = {1087	{ 0x00000040,			0x00000055 },1088	{ 0x00000040,			0x000000AA },1089	{ 0x00007438,			0x00585941 },1090	{ CS35L41_PWR_CTRL1,		0x00000000 },1091	{ 0x0000742C,			0x00000009 },1092};1093 1094static const struct reg_sequence cs35l41_active_to_safe_end[] = {1095	{ 0x00007438,			0x00580941 },1096	{ 0x00000040,			0x000000CC },1097	{ 0x00000040,			0x00000033 },1098};1099 1100static const struct reg_sequence cs35l41_safe_to_active_start[] = {1101	{ 0x00000040,			0x00000055 },1102	{ 0x00000040,			0x000000AA },1103	{ 0x0000742C,			0x0000000F },1104	{ 0x0000742C,			0x00000079 },1105	{ 0x00007438,			0x00585941 },1106	{ CS35L41_PWR_CTRL1,		0x00000001 }, // GLOBAL_EN = 11107};1108 1109static const struct reg_sequence cs35l41_safe_to_active_en_spk[] = {1110	{ 0x0000742C,			0x000000F9 },1111	{ 0x00007438,			0x00580941 },1112};1113 1114static const struct reg_sequence cs35l41_reset_to_safe[] = {1115	{ 0x00000040,			0x00000055 },1116	{ 0x00000040,			0x000000AA },1117	{ 0x00007438,			0x00585941 },1118	{ 0x00007414,			0x08C82222 },1119	{ 0x0000742C,			0x00000009 },1120	{ 0x00000040,			0x000000CC },1121	{ 0x00000040,			0x00000033 },1122};1123 1124static const struct reg_sequence cs35l41_actv_seq[] = {1125	/* SYNC_BST_CTL_RX_EN = 1; SYNC_BST_CTL_TX_EN = 1 */1126	{CS35L41_MDSYNC_EN,        0x00003000},1127	/* BST_CTL_SEL = MDSYNC */1128	{CS35L41_BSTCVRT_VCTRL2,    0x00000002},1129};1130 1131static const struct reg_sequence cs35l41_pass_seq[] = {1132	/* SYNC_BST_CTL_RX_EN = 0; SYNC_BST_CTL_TX_EN = 1 */1133	{CS35L41_MDSYNC_EN,        0x00001000},1134	/* BST_EN = 0 */1135	{CS35L41_PWR_CTRL2,        0x00003300},1136	/* BST_CTL_SEL = MDSYNC */1137	{CS35L41_BSTCVRT_VCTRL2,    0x00000002},1138};1139 1140int cs35l41_init_boost(struct device *dev, struct regmap *regmap,1141		       struct cs35l41_hw_cfg *hw_cfg)1142{1143	int ret;1144 1145	switch (hw_cfg->bst_type) {1146	case CS35L41_SHD_BOOST_ACTV:1147		regmap_multi_reg_write(regmap, cs35l41_actv_seq, ARRAY_SIZE(cs35l41_actv_seq));1148		fallthrough;1149	case CS35L41_INT_BOOST:1150		ret = cs35l41_boost_config(dev, regmap, hw_cfg->bst_ind,1151					   hw_cfg->bst_cap, hw_cfg->bst_ipk);1152		if (ret)1153			dev_err(dev, "Error in Boost DT config: %d\n", ret);1154		break;1155	case CS35L41_EXT_BOOST:1156	case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:1157		/* Only CLSA0100 doesn't use GPIO as VSPK switch, but even on that laptop we can1158		 * toggle GPIO1 as is not connected to anything.1159		 * There will be no other device without VSPK switch.1160		 */1161		regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);1162		regmap_multi_reg_write(regmap, cs35l41_reset_to_safe,1163				       ARRAY_SIZE(cs35l41_reset_to_safe));1164		ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL2, CS35L41_BST_EN_MASK,1165					 CS35L41_BST_DIS_FET_OFF << CS35L41_BST_EN_SHIFT);1166		break;1167	case CS35L41_SHD_BOOST_PASS:1168		ret = regmap_multi_reg_write(regmap, cs35l41_pass_seq,1169					     ARRAY_SIZE(cs35l41_pass_seq));1170		break;1171	default:1172		dev_err(dev, "Boost type %d not supported\n", hw_cfg->bst_type);1173		ret = -EINVAL;1174		break;1175	}1176 1177	return ret;1178}1179EXPORT_SYMBOL_GPL(cs35l41_init_boost);1180 1181bool cs35l41_safe_reset(struct regmap *regmap, enum cs35l41_boost_type b_type)1182{1183	switch (b_type) {1184	/* There is only one laptop that doesn't have VSPK switch. */1185	case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:1186		return false;1187	case CS35L41_EXT_BOOST:1188		regmap_write(regmap, CS35L41_GPIO1_CTRL1, 0x00000001);1189		regmap_multi_reg_write(regmap, cs35l41_safe_to_reset,1190				       ARRAY_SIZE(cs35l41_safe_to_reset));1191		return true;1192	default:1193		return true;1194	}1195}1196EXPORT_SYMBOL_GPL(cs35l41_safe_reset);1197 1198/*1199 * Enabling the CS35L41_SHD_BOOST_ACTV and CS35L41_SHD_BOOST_PASS shared boosts1200 * does also require a call to cs35l41_mdsync_up(), but not before getting the1201 * PLL Lock signal.1202 *1203 * PLL Lock seems to be triggered soon after snd_pcm_start() is executed and1204 * SNDRV_PCM_TRIGGER_START command is processed, which happens (long) after the1205 * SND_SOC_DAPM_PRE_PMU event handler is invoked as part of snd_pcm_prepare().1206 *1207 * This event handler is where cs35l41_global_enable() is normally called from,1208 * but waiting for PLL Lock here will time out. Increasing the wait duration1209 * will not help, as the only consequence of it would be to add an unnecessary1210 * delay in the invocation of snd_pcm_start().1211 *1212 * Trying to move the wait in the SNDRV_PCM_TRIGGER_START callback is not a1213 * solution either, as the trigger is executed in an IRQ-off atomic context.1214 *1215 * The current approach is to invoke cs35l41_mdsync_up() right after receiving1216 * the PLL Lock interrupt, in the IRQ handler.1217 */1218int cs35l41_global_enable(struct device *dev, struct regmap *regmap, enum cs35l41_boost_type b_type,1219			  int enable, struct cs_dsp *dsp)1220{1221	int ret;1222	unsigned int gpio1_func, pad_control, pwr_ctrl1, pwr_ctrl3, int_status, pup_pdn_mask;1223	unsigned int pwr_ctl1_val;1224	struct reg_sequence cs35l41_mdsync_down_seq[] = {1225		{CS35L41_PWR_CTRL3,		0},1226		{CS35L41_GPIO_PAD_CONTROL,	0},1227		{CS35L41_PWR_CTRL1,		0, 3000},1228	};1229 1230	pup_pdn_mask = enable ? CS35L41_PUP_DONE_MASK : CS35L41_PDN_DONE_MASK;1231 1232	ret = regmap_read(regmap, CS35L41_PWR_CTRL1, &pwr_ctl1_val);1233	if (ret)1234		return ret;1235 1236	if ((pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && enable) {1237		dev_dbg(dev, "Cannot set Global Enable - already set.\n");1238		return 0;1239	} else if (!(pwr_ctl1_val & CS35L41_GLOBAL_EN_MASK) && !enable) {1240		dev_dbg(dev, "Cannot unset Global Enable - not set.\n");1241		return 0;1242	}1243 1244	switch (b_type) {1245	case CS35L41_SHD_BOOST_ACTV:1246	case CS35L41_SHD_BOOST_PASS:1247		regmap_read(regmap, CS35L41_PWR_CTRL3, &pwr_ctrl3);1248		regmap_read(regmap, CS35L41_GPIO_PAD_CONTROL, &pad_control);1249 1250		pwr_ctrl3 &= ~CS35L41_SYNC_EN_MASK;1251		pwr_ctrl1 = enable << CS35L41_GLOBAL_EN_SHIFT;1252 1253		gpio1_func = enable ? CS35L41_GPIO1_MDSYNC : CS35L41_GPIO1_HIZ;1254		gpio1_func <<= CS35L41_GPIO1_CTRL_SHIFT;1255 1256		pad_control &= ~CS35L41_GPIO1_CTRL_MASK;1257		pad_control |= gpio1_func & CS35L41_GPIO1_CTRL_MASK;1258 1259		cs35l41_mdsync_down_seq[0].def = pwr_ctrl3;1260		cs35l41_mdsync_down_seq[1].def = pad_control;1261		cs35l41_mdsync_down_seq[2].def = pwr_ctrl1;1262 1263		ret = regmap_multi_reg_write(regmap, cs35l41_mdsync_down_seq,1264					     ARRAY_SIZE(cs35l41_mdsync_down_seq));1265		/* Activation to be completed later via cs35l41_mdsync_up() */1266		if (ret || enable)1267			return ret;1268 1269		ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1,1270					int_status, int_status & pup_pdn_mask,1271					1000, 100000);1272		if (ret)1273			dev_err(dev, "Enable(%d) failed: %d\n", enable, ret);1274 1275		/* Clear PUP/PDN status */1276		regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask);1277		break;1278	case CS35L41_INT_BOOST:1279		ret = regmap_update_bits(regmap, CS35L41_PWR_CTRL1, CS35L41_GLOBAL_EN_MASK,1280					 enable << CS35L41_GLOBAL_EN_SHIFT);1281		if (ret) {1282			dev_err(dev, "CS35L41_PWR_CTRL1 set failed: %d\n", ret);1283			return ret;1284		}1285 1286		ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1,1287					int_status, int_status & pup_pdn_mask,1288					1000, 100000);1289		if (ret)1290			dev_err(dev, "Enable(%d) failed: %d\n", enable, ret);1291 1292		/* Clear PUP/PDN status */1293		regmap_write(regmap, CS35L41_IRQ1_STATUS1, pup_pdn_mask);1294		break;1295	case CS35L41_EXT_BOOST:1296	case CS35L41_EXT_BOOST_NO_VSPK_SWITCH:1297		if (enable) {1298			/* Test Key is unlocked here */1299			ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_start,1300						     ARRAY_SIZE(cs35l41_safe_to_active_start));1301			if (ret)1302				return ret;1303 1304			ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status,1305				       int_status & CS35L41_PUP_DONE_MASK, 1000, 100000);1306			if (ret) {1307				dev_err(dev, "Failed waiting for CS35L41_PUP_DONE_MASK: %d\n", ret);1308				/* Lock the test key, it was unlocked during the multi_reg_write */1309				cs35l41_test_key_lock(dev, regmap);1310				return ret;1311			}1312			regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PUP_DONE_MASK);1313 1314			if (dsp->running && dsp->fw_id_version > CS35L41_FIRMWARE_OLD_VERSION)1315				ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,1316								CSPL_MBOX_CMD_SPK_OUT_ENABLE);1317			else1318				ret = regmap_multi_reg_write(regmap, cs35l41_safe_to_active_en_spk,1319							ARRAY_SIZE(cs35l41_safe_to_active_en_spk));1320 1321			/* Lock the test key, it was unlocked during the multi_reg_write */1322			cs35l41_test_key_lock(dev, regmap);1323		} else {1324			/* Test Key is unlocked here */1325			ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_start,1326						     ARRAY_SIZE(cs35l41_active_to_safe_start));1327			if (ret) {1328				/* Lock the test key, it was unlocked during the multi_reg_write */1329				cs35l41_test_key_lock(dev, regmap);1330				return ret;1331			}1332 1333			ret = regmap_read_poll_timeout(regmap, CS35L41_IRQ1_STATUS1, int_status,1334				       int_status & CS35L41_PDN_DONE_MASK, 1000, 100000);1335			if (ret) {1336				dev_err(dev, "Failed waiting for CS35L41_PDN_DONE_MASK: %d\n", ret);1337				/* Lock the test key, it was unlocked during the multi_reg_write */1338				cs35l41_test_key_lock(dev, regmap);1339				return ret;1340			}1341			regmap_write(regmap, CS35L41_IRQ1_STATUS1, CS35L41_PDN_DONE_MASK);1342 1343			/* Test Key is locked here */1344			ret = regmap_multi_reg_write(regmap, cs35l41_active_to_safe_end,1345						     ARRAY_SIZE(cs35l41_active_to_safe_end));1346		}1347		break;1348	default:1349		ret = -EINVAL;1350		break;1351	}1352 1353	return ret;1354}1355EXPORT_SYMBOL_GPL(cs35l41_global_enable);1356 1357/*1358 * To be called after receiving the IRQ Lock interrupt, in order to complete1359 * any shared boost activation initiated by cs35l41_global_enable().1360 */1361int cs35l41_mdsync_up(struct regmap *regmap)1362{1363	return regmap_update_bits(regmap, CS35L41_PWR_CTRL3,1364				  CS35L41_SYNC_EN_MASK, CS35L41_SYNC_EN_MASK);1365}1366EXPORT_SYMBOL_GPL(cs35l41_mdsync_up);1367 1368int cs35l41_gpio_config(struct regmap *regmap, struct cs35l41_hw_cfg *hw_cfg)1369{1370	struct cs35l41_gpio_cfg *gpio1 = &hw_cfg->gpio1;1371	struct cs35l41_gpio_cfg *gpio2 = &hw_cfg->gpio2;1372	int irq_pol = IRQF_TRIGGER_NONE;1373 1374	regmap_update_bits(regmap, CS35L41_GPIO1_CTRL1,1375			   CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,1376			   gpio1->pol_inv << CS35L41_GPIO_POL_SHIFT |1377			   !gpio1->out_en << CS35L41_GPIO_DIR_SHIFT);1378 1379	regmap_update_bits(regmap, CS35L41_GPIO2_CTRL1,1380			   CS35L41_GPIO_POL_MASK | CS35L41_GPIO_DIR_MASK,1381			   gpio2->pol_inv << CS35L41_GPIO_POL_SHIFT |1382			   !gpio2->out_en << CS35L41_GPIO_DIR_SHIFT);1383 1384	if (gpio1->valid)1385		regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO1_CTRL_MASK,1386				   gpio1->func << CS35L41_GPIO1_CTRL_SHIFT);1387 1388	if (gpio2->valid) {1389		regmap_update_bits(regmap, CS35L41_GPIO_PAD_CONTROL, CS35L41_GPIO2_CTRL_MASK,1390				   gpio2->func << CS35L41_GPIO2_CTRL_SHIFT);1391 1392		switch (gpio2->func) {1393		case CS35L41_GPIO2_INT_PUSH_PULL_LOW:1394		case CS35L41_GPIO2_INT_OPEN_DRAIN:1395			irq_pol = IRQF_TRIGGER_LOW;1396			break;1397		case CS35L41_GPIO2_INT_PUSH_PULL_HIGH:1398			irq_pol = IRQF_TRIGGER_HIGH;1399			break;1400		default:1401			break;1402		}1403	}1404 1405	return irq_pol;1406}1407EXPORT_SYMBOL_GPL(cs35l41_gpio_config);1408 1409static const struct cs_dsp_region cs35l41_dsp1_regions[] = {1410	{ .type = WMFW_HALO_PM_PACKED,	.base = CS35L41_DSP1_PMEM_0 },1411	{ .type = WMFW_HALO_XM_PACKED,	.base = CS35L41_DSP1_XMEM_PACK_0 },1412	{ .type = WMFW_HALO_YM_PACKED,	.base = CS35L41_DSP1_YMEM_PACK_0 },1413	{. type = WMFW_ADSP2_XM,	.base = CS35L41_DSP1_XMEM_UNPACK24_0},1414	{. type = WMFW_ADSP2_YM,	.base = CS35L41_DSP1_YMEM_UNPACK24_0},1415};1416 1417void cs35l41_configure_cs_dsp(struct device *dev, struct regmap *reg, struct cs_dsp *dsp)1418{1419	dsp->num = 1;1420	dsp->type = WMFW_HALO;1421	dsp->rev = 0;1422	dsp->dev = dev;1423	dsp->regmap = reg;1424	dsp->base = CS35L41_DSP1_CTRL_BASE;1425	dsp->base_sysinfo = CS35L41_DSP1_SYS_ID;1426	dsp->mem = cs35l41_dsp1_regions;1427	dsp->num_mems = ARRAY_SIZE(cs35l41_dsp1_regions);1428	dsp->lock_regions = 0xFFFFFFFF;1429}1430EXPORT_SYMBOL_GPL(cs35l41_configure_cs_dsp);1431 1432static bool cs35l41_check_cspl_mbox_sts(enum cs35l41_cspl_mbox_cmd cmd,1433					enum cs35l41_cspl_mbox_status sts)1434{1435	switch (cmd) {1436	case CSPL_MBOX_CMD_NONE:1437	case CSPL_MBOX_CMD_UNKNOWN_CMD:1438		return true;1439	case CSPL_MBOX_CMD_PAUSE:1440	case CSPL_MBOX_CMD_OUT_OF_HIBERNATE:1441		return (sts == CSPL_MBOX_STS_PAUSED);1442	case CSPL_MBOX_CMD_RESUME:1443		return (sts == CSPL_MBOX_STS_RUNNING);1444	case CSPL_MBOX_CMD_REINIT:1445		return (sts == CSPL_MBOX_STS_RUNNING);1446	case CSPL_MBOX_CMD_STOP_PRE_REINIT:1447		return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT);1448	case CSPL_MBOX_CMD_SPK_OUT_ENABLE:1449		return (sts == CSPL_MBOX_STS_RUNNING);1450	default:1451		return false;1452	}1453}1454 1455int cs35l41_set_cspl_mbox_cmd(struct device *dev, struct regmap *regmap,1456			      enum cs35l41_cspl_mbox_cmd cmd)1457{1458	unsigned int sts = 0, i;1459	int ret;1460 1461	// Set mailbox cmd1462	ret = regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, cmd);1463	if (ret < 0) {1464		if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)1465			dev_err(dev, "Failed to write MBOX: %d\n", ret);1466		return ret;1467	}1468 1469	// Read mailbox status and verify it is appropriate for the given cmd1470	for (i = 0; i < 5; i++) {1471		usleep_range(1000, 1100);1472 1473		ret = regmap_read(regmap, CS35L41_DSP_MBOX_2, &sts);1474		if (ret < 0) {1475			dev_err(dev, "Failed to read MBOX STS: %d\n", ret);1476			continue;1477		}1478 1479		if (sts == CSPL_MBOX_STS_ERROR || sts == CSPL_MBOX_STS_ERROR2) {1480			dev_err(dev, "CSPL Error Detected\n");1481			return -EINVAL;1482		}1483 1484		if (!cs35l41_check_cspl_mbox_sts(cmd, sts))1485			dev_dbg(dev, "[%u] cmd %u returned invalid sts %u", i, cmd, sts);1486		else1487			return 0;1488	}1489 1490	if (cmd != CSPL_MBOX_CMD_OUT_OF_HIBERNATE)1491		dev_err(dev, "Failed to set mailbox cmd %u (status %u)\n", cmd, sts);1492 1493	return -ENOMSG;1494}1495EXPORT_SYMBOL_GPL(cs35l41_set_cspl_mbox_cmd);1496 1497int cs35l41_write_fs_errata(struct device *dev, struct regmap *regmap)1498{1499	int ret;1500 1501	ret = regmap_multi_reg_write(regmap, cs35l41_fs_errata_patch,1502				     ARRAY_SIZE(cs35l41_fs_errata_patch));1503	if (ret < 0)1504		dev_err(dev, "Failed to write fs errata: %d\n", ret);1505 1506	return ret;1507}1508EXPORT_SYMBOL_GPL(cs35l41_write_fs_errata);1509 1510int cs35l41_enter_hibernate(struct device *dev, struct regmap *regmap,1511			    enum cs35l41_boost_type b_type)1512{1513	if (!cs35l41_safe_reset(regmap, b_type)) {1514		dev_dbg(dev, "System does not support Suspend\n");1515		return -EINVAL;1516	}1517 1518	dev_dbg(dev, "Enter hibernate\n");1519	regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);1520	regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);1521 1522	// Don't wait for ACK since bus activity would wake the device1523	regmap_write(regmap, CS35L41_DSP_VIRT1_MBOX_1, CSPL_MBOX_CMD_HIBERNATE);1524 1525	return 0;1526}1527EXPORT_SYMBOL_GPL(cs35l41_enter_hibernate);1528 1529static void cs35l41_wait_for_pwrmgt_sts(struct device *dev, struct regmap *regmap)1530{1531	const int pwrmgt_retries = 10;1532	unsigned int sts;1533	int i, ret;1534 1535	for (i = 0; i < pwrmgt_retries; i++) {1536		ret = regmap_read(regmap, CS35L41_PWRMGT_STS, &sts);1537		if (ret)1538			dev_err(dev, "Failed to read PWRMGT_STS: %d\n", ret);1539		else if (!(sts & CS35L41_WR_PEND_STS_MASK))1540			return;1541 1542		udelay(20);1543	}1544 1545	dev_err(dev, "Timed out reading PWRMGT_STS\n");1546}1547 1548int cs35l41_exit_hibernate(struct device *dev, struct regmap *regmap)1549{1550	const int wake_retries = 20;1551	const int sleep_retries = 5;1552	int ret, i, j;1553 1554	for (i = 0; i < sleep_retries; i++) {1555		dev_dbg(dev, "Exit hibernate\n");1556 1557		for (j = 0; j < wake_retries; j++) {1558			ret = cs35l41_set_cspl_mbox_cmd(dev, regmap,1559							CSPL_MBOX_CMD_OUT_OF_HIBERNATE);1560			if (!ret)1561				break;1562 1563			usleep_range(100, 200);1564		}1565 1566		if (j < wake_retries) {1567			dev_dbg(dev, "Wake success at cycle: %d\n", j);1568			return 0;1569		}1570 1571		dev_err(dev, "Wake failed, re-enter hibernate: %d\n", ret);1572 1573		cs35l41_wait_for_pwrmgt_sts(dev, regmap);1574		regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0088);1575 1576		cs35l41_wait_for_pwrmgt_sts(dev, regmap);1577		regmap_write(regmap, CS35L41_WAKESRC_CTL, 0x0188);1578 1579		cs35l41_wait_for_pwrmgt_sts(dev, regmap);1580		regmap_write(regmap, CS35L41_PWRMGT_CTL, 0x3);1581	}1582 1583	dev_err(dev, "Timed out waking device\n");1584 1585	return -ETIMEDOUT;1586}1587EXPORT_SYMBOL_GPL(cs35l41_exit_hibernate);1588 1589MODULE_DESCRIPTION("CS35L41 library");1590MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, <david.rhodes@cirrus.com>");1591MODULE_AUTHOR("Lucas Tanure, Cirrus Logic Inc, <tanureal@opensource.cirrus.com>");1592MODULE_LICENSE("GPL");1593