198615454SKuninori Morimoto /* 298615454SKuninori Morimoto * DA7210 ALSA Soc codec driver 398615454SKuninori Morimoto * 498615454SKuninori Morimoto * Copyright (c) 2009 Dialog Semiconductor 598615454SKuninori Morimoto * Written by David Chen <Dajun.chen@diasemi.com> 698615454SKuninori Morimoto * 798615454SKuninori Morimoto * Copyright (C) 2009 Renesas Solutions Corp. 898615454SKuninori Morimoto * Cleanups by Kuninori Morimoto <morimoto.kuninori@renesas.com> 998615454SKuninori Morimoto * 1098615454SKuninori Morimoto * Tested on SuperH Ecovec24 board with S16/S24 LE in 48KHz using I2S 1198615454SKuninori Morimoto * 1298615454SKuninori Morimoto * This program is free software; you can redistribute it and/or modify it 1398615454SKuninori Morimoto * under the terms of the GNU General Public License as published by the 1498615454SKuninori Morimoto * Free Software Foundation; either version 2 of the License, or (at your 1598615454SKuninori Morimoto * option) any later version. 1698615454SKuninori Morimoto */ 1798615454SKuninori Morimoto 1898615454SKuninori Morimoto #include <linux/delay.h> 1998615454SKuninori Morimoto #include <linux/i2c.h> 20aa0e25caSAshish Chavan #include <linux/spi/spi.h> 2133593b52SAshish Chavan #include <linux/regmap.h> 225a0e3ad6STejun Heo #include <linux/slab.h> 23da155d5bSPaul Gortmaker #include <linux/module.h> 2498615454SKuninori Morimoto #include <sound/pcm.h> 2598615454SKuninori Morimoto #include <sound/pcm_params.h> 26ce6120ccSLiam Girdwood #include <sound/soc.h> 2798615454SKuninori Morimoto #include <sound/initval.h> 28a7e7cd5bSKuninori Morimoto #include <sound/tlv.h> 2998615454SKuninori Morimoto 3098615454SKuninori Morimoto /* DA7210 register space */ 31aa0e25caSAshish Chavan #define DA7210_PAGE_CONTROL 0x00 32de5eaf84SAshish Chavan #define DA7210_CONTROL 0x01 3398615454SKuninori Morimoto #define DA7210_STATUS 0x02 3498615454SKuninori Morimoto #define DA7210_STARTUP1 0x03 356950c60dSAshish Chavan #define DA7210_STARTUP2 0x04 366950c60dSAshish Chavan #define DA7210_STARTUP3 0x05 3798615454SKuninori Morimoto #define DA7210_MIC_L 0x07 3898615454SKuninori Morimoto #define DA7210_MIC_R 0x08 39de5eaf84SAshish Chavan #define DA7210_AUX1_L 0x09 40de5eaf84SAshish Chavan #define DA7210_AUX1_R 0x0A 415eda1949SAshish Chavan #define DA7210_AUX2 0x0B 42de5eaf84SAshish Chavan #define DA7210_IN_GAIN 0x0C 4398615454SKuninori Morimoto #define DA7210_INMIX_L 0x0D 4498615454SKuninori Morimoto #define DA7210_INMIX_R 0x0E 4598615454SKuninori Morimoto #define DA7210_ADC_HPF 0x0F 4698615454SKuninori Morimoto #define DA7210_ADC 0x10 470ee6e9e7SAshish Chavan #define DA7210_ADC_EQ1_2 0X11 480ee6e9e7SAshish Chavan #define DA7210_ADC_EQ3_4 0x12 490ee6e9e7SAshish Chavan #define DA7210_ADC_EQ5 0x13 5098615454SKuninori Morimoto #define DA7210_DAC_HPF 0x14 5198615454SKuninori Morimoto #define DA7210_DAC_L 0x15 5298615454SKuninori Morimoto #define DA7210_DAC_R 0x16 5398615454SKuninori Morimoto #define DA7210_DAC_SEL 0x17 545eda1949SAshish Chavan #define DA7210_SOFTMUTE 0x18 550ee6e9e7SAshish Chavan #define DA7210_DAC_EQ1_2 0x19 560ee6e9e7SAshish Chavan #define DA7210_DAC_EQ3_4 0x1A 570ee6e9e7SAshish Chavan #define DA7210_DAC_EQ5 0x1B 5898615454SKuninori Morimoto #define DA7210_OUTMIX_L 0x1C 5998615454SKuninori Morimoto #define DA7210_OUTMIX_R 0x1D 6052082d8fSAshish Chavan #define DA7210_OUT1_L 0x1E 6152082d8fSAshish Chavan #define DA7210_OUT1_R 0x1F 6252082d8fSAshish Chavan #define DA7210_OUT2 0x20 6398615454SKuninori Morimoto #define DA7210_HP_L_VOL 0x21 6498615454SKuninori Morimoto #define DA7210_HP_R_VOL 0x22 6598615454SKuninori Morimoto #define DA7210_HP_CFG 0x23 665eda1949SAshish Chavan #define DA7210_ZERO_CROSS 0x24 6798615454SKuninori Morimoto #define DA7210_DAI_SRC_SEL 0x25 6898615454SKuninori Morimoto #define DA7210_DAI_CFG1 0x26 6998615454SKuninori Morimoto #define DA7210_DAI_CFG3 0x28 70960b3b4bSKuninori Morimoto #define DA7210_PLL_DIV1 0x29 71960b3b4bSKuninori Morimoto #define DA7210_PLL_DIV2 0x2A 7298615454SKuninori Morimoto #define DA7210_PLL_DIV3 0x2B 7398615454SKuninori Morimoto #define DA7210_PLL 0x2C 74de5eaf84SAshish Chavan #define DA7210_ALC_MAX 0x83 75de5eaf84SAshish Chavan #define DA7210_ALC_MIN 0x84 76de5eaf84SAshish Chavan #define DA7210_ALC_NOIS 0x85 77de5eaf84SAshish Chavan #define DA7210_ALC_ATT 0x86 78de5eaf84SAshish Chavan #define DA7210_ALC_REL 0x87 79de5eaf84SAshish Chavan #define DA7210_ALC_DEL 0x88 80960b3b4bSKuninori Morimoto #define DA7210_A_HID_UNLOCK 0x8A 81960b3b4bSKuninori Morimoto #define DA7210_A_TEST_UNLOCK 0x8B 82960b3b4bSKuninori Morimoto #define DA7210_A_PLL1 0x90 83960b3b4bSKuninori Morimoto #define DA7210_A_CP_MODE 0xA7 8498615454SKuninori Morimoto 8598615454SKuninori Morimoto /* STARTUP1 bit fields */ 8698615454SKuninori Morimoto #define DA7210_SC_MST_EN (1 << 0) 8798615454SKuninori Morimoto 8898615454SKuninori Morimoto /* MIC_L bit fields */ 8998615454SKuninori Morimoto #define DA7210_MICBIAS_EN (1 << 6) 9098615454SKuninori Morimoto #define DA7210_MIC_L_EN (1 << 7) 9198615454SKuninori Morimoto 9298615454SKuninori Morimoto /* MIC_R bit fields */ 9398615454SKuninori Morimoto #define DA7210_MIC_R_EN (1 << 7) 9498615454SKuninori Morimoto 9598615454SKuninori Morimoto /* INMIX_L bit fields */ 9698615454SKuninori Morimoto #define DA7210_IN_L_EN (1 << 7) 9798615454SKuninori Morimoto 9898615454SKuninori Morimoto /* INMIX_R bit fields */ 9998615454SKuninori Morimoto #define DA7210_IN_R_EN (1 << 7) 10098615454SKuninori Morimoto 10198615454SKuninori Morimoto /* ADC bit fields */ 102de5eaf84SAshish Chavan #define DA7210_ADC_ALC_EN (1 << 0) 10398615454SKuninori Morimoto #define DA7210_ADC_L_EN (1 << 3) 10498615454SKuninori Morimoto #define DA7210_ADC_R_EN (1 << 7) 10598615454SKuninori Morimoto 1063a9d6202SKuninori Morimoto /* DAC/ADC HPF fields */ 1073a9d6202SKuninori Morimoto #define DA7210_VOICE_F0_MASK (0x7 << 4) 1083a9d6202SKuninori Morimoto #define DA7210_VOICE_F0_25 (1 << 4) 1093a9d6202SKuninori Morimoto #define DA7210_VOICE_EN (1 << 7) 110c2151433SMark Brown 11198615454SKuninori Morimoto /* DAC_SEL bit fields */ 11298615454SKuninori Morimoto #define DA7210_DAC_L_SRC_DAI_L (4 << 0) 11398615454SKuninori Morimoto #define DA7210_DAC_L_EN (1 << 3) 11498615454SKuninori Morimoto #define DA7210_DAC_R_SRC_DAI_R (5 << 4) 11598615454SKuninori Morimoto #define DA7210_DAC_R_EN (1 << 7) 11698615454SKuninori Morimoto 11798615454SKuninori Morimoto /* OUTMIX_L bit fields */ 11898615454SKuninori Morimoto #define DA7210_OUT_L_EN (1 << 7) 11998615454SKuninori Morimoto 12098615454SKuninori Morimoto /* OUTMIX_R bit fields */ 12198615454SKuninori Morimoto #define DA7210_OUT_R_EN (1 << 7) 12298615454SKuninori Morimoto 12398615454SKuninori Morimoto /* HP_CFG bit fields */ 12498615454SKuninori Morimoto #define DA7210_HP_2CAP_MODE (1 << 1) 12598615454SKuninori Morimoto #define DA7210_HP_SENSE_EN (1 << 2) 12698615454SKuninori Morimoto #define DA7210_HP_L_EN (1 << 3) 12798615454SKuninori Morimoto #define DA7210_HP_MODE (1 << 6) 12898615454SKuninori Morimoto #define DA7210_HP_R_EN (1 << 7) 12998615454SKuninori Morimoto 13098615454SKuninori Morimoto /* DAI_SRC_SEL bit fields */ 13198615454SKuninori Morimoto #define DA7210_DAI_OUT_L_SRC (6 << 0) 13298615454SKuninori Morimoto #define DA7210_DAI_OUT_R_SRC (7 << 4) 13398615454SKuninori Morimoto 13498615454SKuninori Morimoto /* DAI_CFG1 bit fields */ 13598615454SKuninori Morimoto #define DA7210_DAI_WORD_S16_LE (0 << 0) 1360f8ea586SAshish Chavan #define DA7210_DAI_WORD_S20_3LE (1 << 0) 13798615454SKuninori Morimoto #define DA7210_DAI_WORD_S24_LE (2 << 0) 1380f8ea586SAshish Chavan #define DA7210_DAI_WORD_S32_LE (3 << 0) 13998615454SKuninori Morimoto #define DA7210_DAI_FLEN_64BIT (1 << 2) 1400f8ea586SAshish Chavan #define DA7210_DAI_MODE_SLAVE (0 << 7) 14198615454SKuninori Morimoto #define DA7210_DAI_MODE_MASTER (1 << 7) 14298615454SKuninori Morimoto 14398615454SKuninori Morimoto /* DAI_CFG3 bit fields */ 14498615454SKuninori Morimoto #define DA7210_DAI_FORMAT_I2SMODE (0 << 0) 1450f8ea586SAshish Chavan #define DA7210_DAI_FORMAT_LEFT_J (1 << 0) 1460f8ea586SAshish Chavan #define DA7210_DAI_FORMAT_RIGHT_J (2 << 0) 14798615454SKuninori Morimoto #define DA7210_DAI_OE (1 << 3) 14898615454SKuninori Morimoto #define DA7210_DAI_EN (1 << 7) 14998615454SKuninori Morimoto 15098615454SKuninori Morimoto /*PLL_DIV3 bit fields */ 151570aa7baSAshish Chavan #define DA7210_PLL_DIV_L_MASK (0xF << 0) 15298615454SKuninori Morimoto #define DA7210_MCLK_RANGE_10_20_MHZ (1 << 4) 15398615454SKuninori Morimoto #define DA7210_PLL_BYP (1 << 6) 15498615454SKuninori Morimoto 15598615454SKuninori Morimoto /* PLL bit fields */ 1563a9d6202SKuninori Morimoto #define DA7210_PLL_FS_MASK (0xF << 0) 1573a9d6202SKuninori Morimoto #define DA7210_PLL_FS_8000 (0x1 << 0) 158960b3b4bSKuninori Morimoto #define DA7210_PLL_FS_11025 (0x2 << 0) 1593a9d6202SKuninori Morimoto #define DA7210_PLL_FS_12000 (0x3 << 0) 1603a9d6202SKuninori Morimoto #define DA7210_PLL_FS_16000 (0x5 << 0) 161960b3b4bSKuninori Morimoto #define DA7210_PLL_FS_22050 (0x6 << 0) 1623a9d6202SKuninori Morimoto #define DA7210_PLL_FS_24000 (0x7 << 0) 1633a9d6202SKuninori Morimoto #define DA7210_PLL_FS_32000 (0x9 << 0) 164960b3b4bSKuninori Morimoto #define DA7210_PLL_FS_44100 (0xA << 0) 1653a9d6202SKuninori Morimoto #define DA7210_PLL_FS_48000 (0xB << 0) 166960b3b4bSKuninori Morimoto #define DA7210_PLL_FS_88200 (0xE << 0) 1673a9d6202SKuninori Morimoto #define DA7210_PLL_FS_96000 (0xF << 0) 168570aa7baSAshish Chavan #define DA7210_MCLK_DET_EN (0x1 << 5) 169570aa7baSAshish Chavan #define DA7210_MCLK_SRM_EN (0x1 << 6) 170960b3b4bSKuninori Morimoto #define DA7210_PLL_EN (0x1 << 7) 17198615454SKuninori Morimoto 1725eda1949SAshish Chavan /* SOFTMUTE bit fields */ 1735eda1949SAshish Chavan #define DA7210_RAMP_EN (1 << 6) 1745eda1949SAshish Chavan 175de5eaf84SAshish Chavan /* CONTROL bit fields */ 176570aa7baSAshish Chavan #define DA7210_REG_EN (1 << 0) 177570aa7baSAshish Chavan #define DA7210_BIAS_EN (1 << 2) 178de5eaf84SAshish Chavan #define DA7210_NOISE_SUP_EN (1 << 3) 179de5eaf84SAshish Chavan 180de5eaf84SAshish Chavan /* IN_GAIN bit fields */ 181de5eaf84SAshish Chavan #define DA7210_INPGA_L_VOL (0x0F << 0) 182de5eaf84SAshish Chavan #define DA7210_INPGA_R_VOL (0xF0 << 0) 183de5eaf84SAshish Chavan 184de5eaf84SAshish Chavan /* ZERO_CROSS bit fields */ 185de5eaf84SAshish Chavan #define DA7210_AUX1_L_ZC (1 << 0) 186de5eaf84SAshish Chavan #define DA7210_AUX1_R_ZC (1 << 1) 187de5eaf84SAshish Chavan #define DA7210_HP_L_ZC (1 << 6) 188de5eaf84SAshish Chavan #define DA7210_HP_R_ZC (1 << 7) 189de5eaf84SAshish Chavan 190de5eaf84SAshish Chavan /* AUX1_L bit fields */ 191de5eaf84SAshish Chavan #define DA7210_AUX1_L_VOL (0x3F << 0) 19224b6f263SAshish Chavan #define DA7210_AUX1_L_EN (1 << 7) 193de5eaf84SAshish Chavan 194de5eaf84SAshish Chavan /* AUX1_R bit fields */ 195de5eaf84SAshish Chavan #define DA7210_AUX1_R_VOL (0x3F << 0) 19624b6f263SAshish Chavan #define DA7210_AUX1_R_EN (1 << 7) 19724b6f263SAshish Chavan 19824b6f263SAshish Chavan /* AUX2 bit fields */ 19924b6f263SAshish Chavan #define DA7210_AUX2_EN (1 << 3) 200de5eaf84SAshish Chavan 201de5eaf84SAshish Chavan /* Minimum INPGA and AUX1 volume to enable noise suppression */ 202de5eaf84SAshish Chavan #define DA7210_INPGA_MIN_VOL_NS 0x0A /* 10.5dB */ 203de5eaf84SAshish Chavan #define DA7210_AUX1_MIN_VOL_NS 0x35 /* 6dB */ 204de5eaf84SAshish Chavan 20552082d8fSAshish Chavan /* OUT1_L bit fields */ 20652082d8fSAshish Chavan #define DA7210_OUT1_L_EN (1 << 7) 20752082d8fSAshish Chavan 20852082d8fSAshish Chavan /* OUT1_R bit fields */ 20952082d8fSAshish Chavan #define DA7210_OUT1_R_EN (1 << 7) 21052082d8fSAshish Chavan 21152082d8fSAshish Chavan /* OUT2 bit fields */ 21252082d8fSAshish Chavan #define DA7210_OUT2_OUTMIX_R (1 << 5) 21352082d8fSAshish Chavan #define DA7210_OUT2_OUTMIX_L (1 << 6) 21452082d8fSAshish Chavan #define DA7210_OUT2_EN (1 << 7) 21552082d8fSAshish Chavan 216570aa7baSAshish Chavan struct pll_div { 217570aa7baSAshish Chavan int fref; 218570aa7baSAshish Chavan int fout; 219570aa7baSAshish Chavan u8 div1; 220570aa7baSAshish Chavan u8 div2; 221570aa7baSAshish Chavan u8 div3; 222570aa7baSAshish Chavan u8 mode; /* 0 = slave, 1 = master */ 223570aa7baSAshish Chavan }; 224570aa7baSAshish Chavan 225570aa7baSAshish Chavan /* PLL dividers table */ 226570aa7baSAshish Chavan static const struct pll_div da7210_pll_div[] = { 227570aa7baSAshish Chavan /* for MASTER mode, fs = 44.1Khz */ 228570aa7baSAshish Chavan { 12000000, 2822400, 0xE8, 0x6C, 0x2, 1}, /* MCLK=12Mhz */ 229570aa7baSAshish Chavan { 13000000, 2822400, 0xDF, 0x28, 0xC, 1}, /* MCLK=13Mhz */ 230570aa7baSAshish Chavan { 13500000, 2822400, 0xDB, 0x0A, 0xD, 1}, /* MCLK=13.5Mhz */ 231570aa7baSAshish Chavan { 14400000, 2822400, 0xD4, 0x5A, 0x2, 1}, /* MCLK=14.4Mhz */ 232570aa7baSAshish Chavan { 19200000, 2822400, 0xBB, 0x43, 0x9, 1}, /* MCLK=19.2Mhz */ 233570aa7baSAshish Chavan { 19680000, 2822400, 0xB9, 0x6D, 0xA, 1}, /* MCLK=19.68Mhz */ 234570aa7baSAshish Chavan { 19800000, 2822400, 0xB8, 0xFB, 0xB, 1}, /* MCLK=19.8Mhz */ 235570aa7baSAshish Chavan /* for MASTER mode, fs = 48Khz */ 236570aa7baSAshish Chavan { 12000000, 3072000, 0xF3, 0x12, 0x7, 1}, /* MCLK=12Mhz */ 237570aa7baSAshish Chavan { 13000000, 3072000, 0xE8, 0xFD, 0x5, 1}, /* MCLK=13Mhz */ 238570aa7baSAshish Chavan { 13500000, 3072000, 0xE4, 0x82, 0x3, 1}, /* MCLK=13.5Mhz */ 239570aa7baSAshish Chavan { 14400000, 3072000, 0xDD, 0x3A, 0x0, 1}, /* MCLK=14.4Mhz */ 240570aa7baSAshish Chavan { 19200000, 3072000, 0xC1, 0xEB, 0x8, 1}, /* MCLK=19.2Mhz */ 241570aa7baSAshish Chavan { 19680000, 3072000, 0xBF, 0xEC, 0x0, 1}, /* MCLK=19.68Mhz */ 242570aa7baSAshish Chavan { 19800000, 3072000, 0xBF, 0x70, 0x0, 1}, /* MCLK=19.8Mhz */ 243570aa7baSAshish Chavan /* for SLAVE mode with SRM */ 244570aa7baSAshish Chavan { 12000000, 2822400, 0xED, 0xBF, 0x5, 0}, /* MCLK=12Mhz */ 245570aa7baSAshish Chavan { 13000000, 2822400, 0xE4, 0x13, 0x0, 0}, /* MCLK=13Mhz */ 246570aa7baSAshish Chavan { 13500000, 2822400, 0xDF, 0xC6, 0x8, 0}, /* MCLK=13.5Mhz */ 247570aa7baSAshish Chavan { 14400000, 2822400, 0xD8, 0xCA, 0x1, 0}, /* MCLK=14.4Mhz */ 248570aa7baSAshish Chavan { 19200000, 2822400, 0xBE, 0x97, 0x9, 0}, /* MCLK=19.2Mhz */ 249570aa7baSAshish Chavan { 19680000, 2822400, 0xBC, 0xAC, 0xD, 0}, /* MCLK=19.68Mhz */ 250570aa7baSAshish Chavan { 19800000, 2822400, 0xBC, 0x35, 0xE, 0}, /* MCLK=19.8Mhz */ 251570aa7baSAshish Chavan }; 252570aa7baSAshish Chavan 253570aa7baSAshish Chavan enum clk_src { 254570aa7baSAshish Chavan DA7210_CLKSRC_MCLK 255570aa7baSAshish Chavan }; 256570aa7baSAshish Chavan 25798615454SKuninori Morimoto #define DA7210_VERSION "0.0.1" 25898615454SKuninori Morimoto 259a7e7cd5bSKuninori Morimoto /* 260a7e7cd5bSKuninori Morimoto * Playback Volume 261a7e7cd5bSKuninori Morimoto * 262a7e7cd5bSKuninori Morimoto * max : 0x3F (+15.0 dB) 263a7e7cd5bSKuninori Morimoto * (1.5 dB step) 264a7e7cd5bSKuninori Morimoto * min : 0x11 (-54.0 dB) 265a7e7cd5bSKuninori Morimoto * mute : 0x10 266a7e7cd5bSKuninori Morimoto * reserved : 0x00 - 0x0F 267a7e7cd5bSKuninori Morimoto * 268a7e7cd5bSKuninori Morimoto * Reserved area are considered as "mute". 269a7e7cd5bSKuninori Morimoto */ 2707a0e67b6SAshish Chavan static const unsigned int hp_out_tlv[] = { 2717a0e67b6SAshish Chavan TLV_DB_RANGE_HEAD(2), 2727a0e67b6SAshish Chavan 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 2737a0e67b6SAshish Chavan /* -54 dB to +15 dB */ 2747a0e67b6SAshish Chavan 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0), 2757a0e67b6SAshish Chavan }; 276a7e7cd5bSKuninori Morimoto 27752082d8fSAshish Chavan static const unsigned int lineout_vol_tlv[] = { 27852082d8fSAshish Chavan TLV_DB_RANGE_HEAD(2), 27952082d8fSAshish Chavan 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 28052082d8fSAshish Chavan /* -54dB to 15dB */ 28152082d8fSAshish Chavan 0x11, 0x3f, TLV_DB_SCALE_ITEM(-5400, 150, 0) 28252082d8fSAshish Chavan }; 28352082d8fSAshish Chavan 28452082d8fSAshish Chavan static const unsigned int mono_vol_tlv[] = { 28552082d8fSAshish Chavan TLV_DB_RANGE_HEAD(2), 28652082d8fSAshish Chavan 0x0, 0x2, TLV_DB_SCALE_ITEM(-1800, 0, 1), 28752082d8fSAshish Chavan /* -18dB to 6dB */ 28852082d8fSAshish Chavan 0x3, 0x7, TLV_DB_SCALE_ITEM(-1800, 600, 0) 28952082d8fSAshish Chavan }; 29052082d8fSAshish Chavan 29124b6f263SAshish Chavan static const unsigned int aux1_vol_tlv[] = { 29224b6f263SAshish Chavan TLV_DB_RANGE_HEAD(2), 29324b6f263SAshish Chavan 0x0, 0x10, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), 29424b6f263SAshish Chavan /* -48dB to 21dB */ 29524b6f263SAshish Chavan 0x11, 0x3f, TLV_DB_SCALE_ITEM(-4800, 150, 0) 29624b6f263SAshish Chavan }; 29724b6f263SAshish Chavan 2980ee6e9e7SAshish Chavan static const DECLARE_TLV_DB_SCALE(eq_gain_tlv, -1050, 150, 0); 2990ee6e9e7SAshish Chavan static const DECLARE_TLV_DB_SCALE(adc_eq_master_gain_tlv, -1800, 600, 1); 30052082d8fSAshish Chavan static const DECLARE_TLV_DB_SCALE(dac_gain_tlv, -7725, 75, 0); 30124b6f263SAshish Chavan static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, -600, 600, 0); 30224b6f263SAshish Chavan static const DECLARE_TLV_DB_SCALE(aux2_vol_tlv, -600, 600, 0); 30324b6f263SAshish Chavan static const DECLARE_TLV_DB_SCALE(inpga_gain_tlv, -450, 150, 0); 3040ee6e9e7SAshish Chavan 3054ced2b96SAshish Chavan /* ADC and DAC high pass filter f0 value */ 306f4034147SMark Brown static const char * const da7210_hpf_cutoff_txt[] = { 3074ced2b96SAshish Chavan "Fs/8192*pi", "Fs/4096*pi", "Fs/2048*pi", "Fs/1024*pi" 3084ced2b96SAshish Chavan }; 3094ced2b96SAshish Chavan 310e34042d8STakashi Iwai static SOC_ENUM_SINGLE_DECL(da7210_dac_hpf_cutoff, 311e34042d8STakashi Iwai DA7210_DAC_HPF, 0, da7210_hpf_cutoff_txt); 3124ced2b96SAshish Chavan 313e34042d8STakashi Iwai static SOC_ENUM_SINGLE_DECL(da7210_adc_hpf_cutoff, 314e34042d8STakashi Iwai DA7210_ADC_HPF, 0, da7210_hpf_cutoff_txt); 3154ced2b96SAshish Chavan 3164ced2b96SAshish Chavan /* ADC and DAC voice (8kHz) high pass cutoff value */ 317f4034147SMark Brown static const char * const da7210_vf_cutoff_txt[] = { 3184ced2b96SAshish Chavan "2.5Hz", "25Hz", "50Hz", "100Hz", "150Hz", "200Hz", "300Hz", "400Hz" 3194ced2b96SAshish Chavan }; 3204ced2b96SAshish Chavan 321e34042d8STakashi Iwai static SOC_ENUM_SINGLE_DECL(da7210_dac_vf_cutoff, 322e34042d8STakashi Iwai DA7210_DAC_HPF, 4, da7210_vf_cutoff_txt); 3234ced2b96SAshish Chavan 324e34042d8STakashi Iwai static SOC_ENUM_SINGLE_DECL(da7210_adc_vf_cutoff, 325e34042d8STakashi Iwai DA7210_ADC_HPF, 4, da7210_vf_cutoff_txt); 3264ced2b96SAshish Chavan 3275eda1949SAshish Chavan static const char *da7210_hp_mode_txt[] = { 3285eda1949SAshish Chavan "Class H", "Class G" 3295eda1949SAshish Chavan }; 3305eda1949SAshish Chavan 331e34042d8STakashi Iwai static SOC_ENUM_SINGLE_DECL(da7210_hp_mode_sel, 332e34042d8STakashi Iwai DA7210_HP_CFG, 0, da7210_hp_mode_txt); 3335eda1949SAshish Chavan 334de5eaf84SAshish Chavan /* ALC can be enabled only if noise suppression is disabled */ 335de5eaf84SAshish Chavan static int da7210_put_alc_sw(struct snd_kcontrol *kcontrol, 336de5eaf84SAshish Chavan struct snd_ctl_elem_value *ucontrol) 337de5eaf84SAshish Chavan { 338ea53bf77SLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 339de5eaf84SAshish Chavan 340de5eaf84SAshish Chavan if (ucontrol->value.integer.value[0]) { 341de5eaf84SAshish Chavan /* Check if noise suppression is enabled */ 342de5eaf84SAshish Chavan if (snd_soc_read(codec, DA7210_CONTROL) & DA7210_NOISE_SUP_EN) { 343de5eaf84SAshish Chavan dev_dbg(codec->dev, 344de5eaf84SAshish Chavan "Disable noise suppression to enable ALC\n"); 345de5eaf84SAshish Chavan return -EINVAL; 346de5eaf84SAshish Chavan } 347de5eaf84SAshish Chavan } 348de5eaf84SAshish Chavan /* If all conditions are met or we are actually disabling ALC */ 349de5eaf84SAshish Chavan return snd_soc_put_volsw(kcontrol, ucontrol); 350de5eaf84SAshish Chavan } 351de5eaf84SAshish Chavan 352de5eaf84SAshish Chavan /* Noise suppression can be enabled only if following conditions are met 353de5eaf84SAshish Chavan * ALC disabled 354de5eaf84SAshish Chavan * ZC enabled for HP and AUX1 PGA 355de5eaf84SAshish Chavan * INPGA_L_VOL and INPGA_R_VOL >= 10.5 dB 356de5eaf84SAshish Chavan * AUX1_L_VOL and AUX1_R_VOL >= 6 dB 357de5eaf84SAshish Chavan */ 358de5eaf84SAshish Chavan static int da7210_put_noise_sup_sw(struct snd_kcontrol *kcontrol, 359de5eaf84SAshish Chavan struct snd_ctl_elem_value *ucontrol) 360de5eaf84SAshish Chavan { 361ea53bf77SLars-Peter Clausen struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); 362de5eaf84SAshish Chavan u8 val; 363de5eaf84SAshish Chavan 364de5eaf84SAshish Chavan if (ucontrol->value.integer.value[0]) { 365de5eaf84SAshish Chavan /* Check if ALC is enabled */ 366de5eaf84SAshish Chavan if (snd_soc_read(codec, DA7210_ADC) & DA7210_ADC_ALC_EN) 367de5eaf84SAshish Chavan goto err; 368de5eaf84SAshish Chavan 369de5eaf84SAshish Chavan /* Check ZC for HP and AUX1 PGA */ 370de5eaf84SAshish Chavan if ((snd_soc_read(codec, DA7210_ZERO_CROSS) & 371de5eaf84SAshish Chavan (DA7210_AUX1_L_ZC | DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | 372de5eaf84SAshish Chavan DA7210_HP_R_ZC)) != (DA7210_AUX1_L_ZC | 373de5eaf84SAshish Chavan DA7210_AUX1_R_ZC | DA7210_HP_L_ZC | DA7210_HP_R_ZC)) 374de5eaf84SAshish Chavan goto err; 375de5eaf84SAshish Chavan 376de5eaf84SAshish Chavan /* Check INPGA_L_VOL and INPGA_R_VOL */ 377de5eaf84SAshish Chavan val = snd_soc_read(codec, DA7210_IN_GAIN); 378de5eaf84SAshish Chavan if (((val & DA7210_INPGA_L_VOL) < DA7210_INPGA_MIN_VOL_NS) || 379de5eaf84SAshish Chavan (((val & DA7210_INPGA_R_VOL) >> 4) < 380de5eaf84SAshish Chavan DA7210_INPGA_MIN_VOL_NS)) 381de5eaf84SAshish Chavan goto err; 382de5eaf84SAshish Chavan 383de5eaf84SAshish Chavan /* Check AUX1_L_VOL and AUX1_R_VOL */ 384de5eaf84SAshish Chavan if (((snd_soc_read(codec, DA7210_AUX1_L) & DA7210_AUX1_L_VOL) < 385de5eaf84SAshish Chavan DA7210_AUX1_MIN_VOL_NS) || 386de5eaf84SAshish Chavan ((snd_soc_read(codec, DA7210_AUX1_R) & DA7210_AUX1_R_VOL) < 387de5eaf84SAshish Chavan DA7210_AUX1_MIN_VOL_NS)) 388de5eaf84SAshish Chavan goto err; 389de5eaf84SAshish Chavan } 390de5eaf84SAshish Chavan /* If all conditions are met or we are actually disabling Noise sup */ 391de5eaf84SAshish Chavan return snd_soc_put_volsw(kcontrol, ucontrol); 392de5eaf84SAshish Chavan 393de5eaf84SAshish Chavan err: 394de5eaf84SAshish Chavan return -EINVAL; 395de5eaf84SAshish Chavan } 396de5eaf84SAshish Chavan 397a7e7cd5bSKuninori Morimoto static const struct snd_kcontrol_new da7210_snd_controls[] = { 398a7e7cd5bSKuninori Morimoto 399a7e7cd5bSKuninori Morimoto SOC_DOUBLE_R_TLV("HeadPhone Playback Volume", 400a7e7cd5bSKuninori Morimoto DA7210_HP_L_VOL, DA7210_HP_R_VOL, 401a7e7cd5bSKuninori Morimoto 0, 0x3F, 0, hp_out_tlv), 40252082d8fSAshish Chavan SOC_DOUBLE_R_TLV("Digital Playback Volume", 40352082d8fSAshish Chavan DA7210_DAC_L, DA7210_DAC_R, 40452082d8fSAshish Chavan 0, 0x77, 1, dac_gain_tlv), 40552082d8fSAshish Chavan SOC_DOUBLE_R_TLV("Lineout Playback Volume", 40652082d8fSAshish Chavan DA7210_OUT1_L, DA7210_OUT1_R, 40752082d8fSAshish Chavan 0, 0x3f, 0, lineout_vol_tlv), 40852082d8fSAshish Chavan SOC_SINGLE_TLV("Mono Playback Volume", DA7210_OUT2, 0, 0x7, 0, 40952082d8fSAshish Chavan mono_vol_tlv), 4100ee6e9e7SAshish Chavan 41124b6f263SAshish Chavan SOC_DOUBLE_R_TLV("Mic Capture Volume", 41224b6f263SAshish Chavan DA7210_MIC_L, DA7210_MIC_R, 41324b6f263SAshish Chavan 0, 0x5, 0, mic_vol_tlv), 41424b6f263SAshish Chavan SOC_DOUBLE_R_TLV("Aux1 Capture Volume", 41524b6f263SAshish Chavan DA7210_AUX1_L, DA7210_AUX1_R, 41624b6f263SAshish Chavan 0, 0x3f, 0, aux1_vol_tlv), 41724b6f263SAshish Chavan SOC_SINGLE_TLV("Aux2 Capture Volume", DA7210_AUX2, 0, 0x3, 0, 41824b6f263SAshish Chavan aux2_vol_tlv), 41924b6f263SAshish Chavan SOC_DOUBLE_TLV("In PGA Capture Volume", DA7210_IN_GAIN, 0, 4, 0xF, 0, 42024b6f263SAshish Chavan inpga_gain_tlv), 42124b6f263SAshish Chavan 4220ee6e9e7SAshish Chavan /* DAC Equalizer controls */ 4230ee6e9e7SAshish Chavan SOC_SINGLE("DAC EQ Switch", DA7210_DAC_EQ5, 7, 1, 0), 4240ee6e9e7SAshish Chavan SOC_SINGLE_TLV("DAC EQ1 Volume", DA7210_DAC_EQ1_2, 0, 0xf, 1, 4250ee6e9e7SAshish Chavan eq_gain_tlv), 4260ee6e9e7SAshish Chavan SOC_SINGLE_TLV("DAC EQ2 Volume", DA7210_DAC_EQ1_2, 4, 0xf, 1, 4270ee6e9e7SAshish Chavan eq_gain_tlv), 4280ee6e9e7SAshish Chavan SOC_SINGLE_TLV("DAC EQ3 Volume", DA7210_DAC_EQ3_4, 0, 0xf, 1, 4290ee6e9e7SAshish Chavan eq_gain_tlv), 4300ee6e9e7SAshish Chavan SOC_SINGLE_TLV("DAC EQ4 Volume", DA7210_DAC_EQ3_4, 4, 0xf, 1, 4310ee6e9e7SAshish Chavan eq_gain_tlv), 4320ee6e9e7SAshish Chavan SOC_SINGLE_TLV("DAC EQ5 Volume", DA7210_DAC_EQ5, 0, 0xf, 1, 4330ee6e9e7SAshish Chavan eq_gain_tlv), 4340ee6e9e7SAshish Chavan 4350ee6e9e7SAshish Chavan /* ADC Equalizer controls */ 4360ee6e9e7SAshish Chavan SOC_SINGLE("ADC EQ Switch", DA7210_ADC_EQ5, 7, 1, 0), 4370ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ Master Volume", DA7210_ADC_EQ5, 4, 0x3, 4380ee6e9e7SAshish Chavan 1, adc_eq_master_gain_tlv), 4390ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ1 Volume", DA7210_ADC_EQ1_2, 0, 0xf, 1, 4400ee6e9e7SAshish Chavan eq_gain_tlv), 4410ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ2 Volume", DA7210_ADC_EQ1_2, 4, 0xf, 1, 4420ee6e9e7SAshish Chavan eq_gain_tlv), 4430ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ3 Volume", DA7210_ADC_EQ3_4, 0, 0xf, 1, 4440ee6e9e7SAshish Chavan eq_gain_tlv), 4450ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ4 Volume", DA7210_ADC_EQ3_4, 4, 0xf, 1, 4460ee6e9e7SAshish Chavan eq_gain_tlv), 4470ee6e9e7SAshish Chavan SOC_SINGLE_TLV("ADC EQ5 Volume", DA7210_ADC_EQ5, 0, 0xf, 1, 4480ee6e9e7SAshish Chavan eq_gain_tlv), 4494ced2b96SAshish Chavan 4504ced2b96SAshish Chavan SOC_SINGLE("DAC HPF Switch", DA7210_DAC_HPF, 3, 1, 0), 4514ced2b96SAshish Chavan SOC_ENUM("DAC HPF Cutoff", da7210_dac_hpf_cutoff), 4524ced2b96SAshish Chavan SOC_SINGLE("DAC Voice Mode Switch", DA7210_DAC_HPF, 7, 1, 0), 4534ced2b96SAshish Chavan SOC_ENUM("DAC Voice Cutoff", da7210_dac_vf_cutoff), 4544ced2b96SAshish Chavan 4554ced2b96SAshish Chavan SOC_SINGLE("ADC HPF Switch", DA7210_ADC_HPF, 3, 1, 0), 4564ced2b96SAshish Chavan SOC_ENUM("ADC HPF Cutoff", da7210_adc_hpf_cutoff), 4574ced2b96SAshish Chavan SOC_SINGLE("ADC Voice Mode Switch", DA7210_ADC_HPF, 7, 1, 0), 4584ced2b96SAshish Chavan SOC_ENUM("ADC Voice Cutoff", da7210_adc_vf_cutoff), 4595eda1949SAshish Chavan 4605eda1949SAshish Chavan /* Mute controls */ 4615eda1949SAshish Chavan SOC_DOUBLE_R("Mic Capture Switch", DA7210_MIC_L, DA7210_MIC_R, 3, 1, 0), 4625eda1949SAshish Chavan SOC_SINGLE("Aux2 Capture Switch", DA7210_AUX2, 2, 1, 0), 4635eda1949SAshish Chavan SOC_DOUBLE("ADC Capture Switch", DA7210_ADC, 2, 6, 1, 0), 4645eda1949SAshish Chavan SOC_SINGLE("Digital Soft Mute Switch", DA7210_SOFTMUTE, 7, 1, 0), 4655eda1949SAshish Chavan SOC_SINGLE("Digital Soft Mute Rate", DA7210_SOFTMUTE, 0, 0x7, 0), 4665eda1949SAshish Chavan 4675eda1949SAshish Chavan /* Zero cross controls */ 4685eda1949SAshish Chavan SOC_DOUBLE("Aux1 ZC Switch", DA7210_ZERO_CROSS, 0, 1, 1, 0), 4695eda1949SAshish Chavan SOC_DOUBLE("In PGA ZC Switch", DA7210_ZERO_CROSS, 2, 3, 1, 0), 4705eda1949SAshish Chavan SOC_DOUBLE("Lineout ZC Switch", DA7210_ZERO_CROSS, 4, 5, 1, 0), 4715eda1949SAshish Chavan SOC_DOUBLE("Headphone ZC Switch", DA7210_ZERO_CROSS, 6, 7, 1, 0), 4725eda1949SAshish Chavan 4735eda1949SAshish Chavan SOC_ENUM("Headphone Class", da7210_hp_mode_sel), 474de5eaf84SAshish Chavan 475de5eaf84SAshish Chavan /* ALC controls */ 476de5eaf84SAshish Chavan SOC_SINGLE_EXT("ALC Enable Switch", DA7210_ADC, 0, 1, 0, 477de5eaf84SAshish Chavan snd_soc_get_volsw, da7210_put_alc_sw), 478de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Max Volume", DA7210_ALC_MAX, 0, 0x3F, 0), 479de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Min Volume", DA7210_ALC_MIN, 0, 0x3F, 0), 480de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Noise Volume", DA7210_ALC_NOIS, 0, 0x3F, 0), 481de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Attack Rate", DA7210_ALC_ATT, 0, 0xFF, 0), 482de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Release Rate", DA7210_ALC_REL, 0, 0xFF, 0), 483de5eaf84SAshish Chavan SOC_SINGLE("ALC Capture Release Delay", DA7210_ALC_DEL, 0, 0xFF, 0), 484de5eaf84SAshish Chavan 485de5eaf84SAshish Chavan SOC_SINGLE_EXT("Noise Suppression Enable Switch", DA7210_CONTROL, 3, 1, 486de5eaf84SAshish Chavan 0, snd_soc_get_volsw, da7210_put_noise_sup_sw), 487a7e7cd5bSKuninori Morimoto }; 488a7e7cd5bSKuninori Morimoto 4896950c60dSAshish Chavan /* 4906950c60dSAshish Chavan * DAPM Controls 4916950c60dSAshish Chavan * 4926950c60dSAshish Chavan * Current DAPM implementation covers almost all codec components e.g. IOs, 4936950c60dSAshish Chavan * mixers, PGAs,ADC and DAC. 4946950c60dSAshish Chavan */ 4956950c60dSAshish Chavan /* In Mixer Left */ 4966950c60dSAshish Chavan static const struct snd_kcontrol_new da7210_dapm_inmixl_controls[] = { 4976950c60dSAshish Chavan SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_L, 0, 1, 0), 4986950c60dSAshish Chavan SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_L, 1, 1, 0), 49924b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_INMIX_L, 2, 1, 0), 50024b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_L, 3, 1, 0), 50124b6f263SAshish Chavan SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_INMIX_L, 4, 1, 0), 5026950c60dSAshish Chavan }; 5036950c60dSAshish Chavan 5046950c60dSAshish Chavan /* In Mixer Right */ 5056950c60dSAshish Chavan static const struct snd_kcontrol_new da7210_dapm_inmixr_controls[] = { 5066950c60dSAshish Chavan SOC_DAPM_SINGLE("Mic Right Switch", DA7210_INMIX_R, 0, 1, 0), 5076950c60dSAshish Chavan SOC_DAPM_SINGLE("Mic Left Switch", DA7210_INMIX_R, 1, 1, 0), 50824b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_INMIX_R, 2, 1, 0), 50924b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux2 Switch", DA7210_INMIX_R, 3, 1, 0), 51024b6f263SAshish Chavan SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_INMIX_R, 4, 1, 0), 5116950c60dSAshish Chavan }; 5126950c60dSAshish Chavan 5136950c60dSAshish Chavan /* Out Mixer Left */ 5146950c60dSAshish Chavan static const struct snd_kcontrol_new da7210_dapm_outmixl_controls[] = { 51524b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux1 Left Switch", DA7210_OUTMIX_L, 0, 1, 0), 51624b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_L, 1, 1, 0), 51724b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_L, 2, 1, 0), 51824b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_L, 3, 1, 0), 5196950c60dSAshish Chavan SOC_DAPM_SINGLE("DAC Left Switch", DA7210_OUTMIX_L, 4, 1, 0), 5206950c60dSAshish Chavan }; 5216950c60dSAshish Chavan 5226950c60dSAshish Chavan /* Out Mixer Right */ 5236950c60dSAshish Chavan static const struct snd_kcontrol_new da7210_dapm_outmixr_controls[] = { 52424b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux1 Right Switch", DA7210_OUTMIX_R, 0, 1, 0), 52524b6f263SAshish Chavan SOC_DAPM_SINGLE("Aux2 Switch", DA7210_OUTMIX_R, 1, 1, 0), 52624b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUTMIX_R, 2, 1, 0), 52724b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUTMIX_R, 3, 1, 0), 5286950c60dSAshish Chavan SOC_DAPM_SINGLE("DAC Right Switch", DA7210_OUTMIX_R, 4, 1, 0), 5296950c60dSAshish Chavan }; 5306950c60dSAshish Chavan 53152082d8fSAshish Chavan /* Mono Mixer */ 53252082d8fSAshish Chavan static const struct snd_kcontrol_new da7210_dapm_monomix_controls[] = { 53324b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Right Switch", DA7210_OUT2, 3, 1, 0), 53424b6f263SAshish Chavan SOC_DAPM_SINGLE("INPGA Left Switch", DA7210_OUT2, 4, 1, 0), 53552082d8fSAshish Chavan SOC_DAPM_SINGLE("Outmix Right Switch", DA7210_OUT2, 5, 1, 0), 53652082d8fSAshish Chavan SOC_DAPM_SINGLE("Outmix Left Switch", DA7210_OUT2, 6, 1, 0), 53752082d8fSAshish Chavan }; 53852082d8fSAshish Chavan 5396950c60dSAshish Chavan /* DAPM widgets */ 5406950c60dSAshish Chavan static const struct snd_soc_dapm_widget da7210_dapm_widgets[] = { 5416950c60dSAshish Chavan /* Input Side */ 5426950c60dSAshish Chavan /* Input Lines */ 5436950c60dSAshish Chavan SND_SOC_DAPM_INPUT("MICL"), 5446950c60dSAshish Chavan SND_SOC_DAPM_INPUT("MICR"), 54524b6f263SAshish Chavan SND_SOC_DAPM_INPUT("AUX1L"), 54624b6f263SAshish Chavan SND_SOC_DAPM_INPUT("AUX1R"), 54724b6f263SAshish Chavan SND_SOC_DAPM_INPUT("AUX2"), 5486950c60dSAshish Chavan 5496950c60dSAshish Chavan /* Input PGAs */ 5506950c60dSAshish Chavan SND_SOC_DAPM_PGA("Mic Left", DA7210_STARTUP3, 0, 1, NULL, 0), 5516950c60dSAshish Chavan SND_SOC_DAPM_PGA("Mic Right", DA7210_STARTUP3, 1, 1, NULL, 0), 55224b6f263SAshish Chavan SND_SOC_DAPM_PGA("Aux1 Left", DA7210_STARTUP3, 2, 1, NULL, 0), 55324b6f263SAshish Chavan SND_SOC_DAPM_PGA("Aux1 Right", DA7210_STARTUP3, 3, 1, NULL, 0), 55424b6f263SAshish Chavan SND_SOC_DAPM_PGA("Aux2 Mono", DA7210_STARTUP3, 4, 1, NULL, 0), 5556950c60dSAshish Chavan 5566950c60dSAshish Chavan SND_SOC_DAPM_PGA("INPGA Left", DA7210_INMIX_L, 7, 0, NULL, 0), 5576950c60dSAshish Chavan SND_SOC_DAPM_PGA("INPGA Right", DA7210_INMIX_R, 7, 0, NULL, 0), 5586950c60dSAshish Chavan 55924b6f263SAshish Chavan /* MICBIAS */ 56024b6f263SAshish Chavan SND_SOC_DAPM_SUPPLY("Mic Bias", DA7210_MIC_L, 6, 0, NULL, 0), 56124b6f263SAshish Chavan 5626950c60dSAshish Chavan /* Input Mixers */ 5636950c60dSAshish Chavan SND_SOC_DAPM_MIXER("In Mixer Left", SND_SOC_NOPM, 0, 0, 5646950c60dSAshish Chavan &da7210_dapm_inmixl_controls[0], 5656950c60dSAshish Chavan ARRAY_SIZE(da7210_dapm_inmixl_controls)), 5666950c60dSAshish Chavan 5676950c60dSAshish Chavan SND_SOC_DAPM_MIXER("In Mixer Right", SND_SOC_NOPM, 0, 0, 5686950c60dSAshish Chavan &da7210_dapm_inmixr_controls[0], 5696950c60dSAshish Chavan ARRAY_SIZE(da7210_dapm_inmixr_controls)), 5706950c60dSAshish Chavan 5716950c60dSAshish Chavan /* ADCs */ 5726950c60dSAshish Chavan SND_SOC_DAPM_ADC("ADC Left", "Capture", DA7210_STARTUP3, 5, 1), 5736950c60dSAshish Chavan SND_SOC_DAPM_ADC("ADC Right", "Capture", DA7210_STARTUP3, 6, 1), 5746950c60dSAshish Chavan 5756950c60dSAshish Chavan /* Output Side */ 5766950c60dSAshish Chavan /* DACs */ 5776950c60dSAshish Chavan SND_SOC_DAPM_DAC("DAC Left", "Playback", DA7210_STARTUP2, 5, 1), 5786950c60dSAshish Chavan SND_SOC_DAPM_DAC("DAC Right", "Playback", DA7210_STARTUP2, 6, 1), 5796950c60dSAshish Chavan 5806950c60dSAshish Chavan /* Output Mixers */ 5816950c60dSAshish Chavan SND_SOC_DAPM_MIXER("Out Mixer Left", SND_SOC_NOPM, 0, 0, 5826950c60dSAshish Chavan &da7210_dapm_outmixl_controls[0], 5836950c60dSAshish Chavan ARRAY_SIZE(da7210_dapm_outmixl_controls)), 5846950c60dSAshish Chavan 5856950c60dSAshish Chavan SND_SOC_DAPM_MIXER("Out Mixer Right", SND_SOC_NOPM, 0, 0, 5866950c60dSAshish Chavan &da7210_dapm_outmixr_controls[0], 5876950c60dSAshish Chavan ARRAY_SIZE(da7210_dapm_outmixr_controls)), 5886950c60dSAshish Chavan 58952082d8fSAshish Chavan SND_SOC_DAPM_MIXER("Mono Mixer", SND_SOC_NOPM, 0, 0, 59052082d8fSAshish Chavan &da7210_dapm_monomix_controls[0], 59152082d8fSAshish Chavan ARRAY_SIZE(da7210_dapm_monomix_controls)), 59252082d8fSAshish Chavan 5936950c60dSAshish Chavan /* Output PGAs */ 5946950c60dSAshish Chavan SND_SOC_DAPM_PGA("OUTPGA Left Enable", DA7210_OUTMIX_L, 7, 0, NULL, 0), 5956950c60dSAshish Chavan SND_SOC_DAPM_PGA("OUTPGA Right Enable", DA7210_OUTMIX_R, 7, 0, NULL, 0), 5966950c60dSAshish Chavan 59752082d8fSAshish Chavan SND_SOC_DAPM_PGA("Out1 Left", DA7210_STARTUP2, 0, 1, NULL, 0), 59852082d8fSAshish Chavan SND_SOC_DAPM_PGA("Out1 Right", DA7210_STARTUP2, 1, 1, NULL, 0), 59952082d8fSAshish Chavan SND_SOC_DAPM_PGA("Out2 Mono", DA7210_STARTUP2, 2, 1, NULL, 0), 6006950c60dSAshish Chavan SND_SOC_DAPM_PGA("Headphone Left", DA7210_STARTUP2, 3, 1, NULL, 0), 6016950c60dSAshish Chavan SND_SOC_DAPM_PGA("Headphone Right", DA7210_STARTUP2, 4, 1, NULL, 0), 6026950c60dSAshish Chavan 6036950c60dSAshish Chavan /* Output Lines */ 60452082d8fSAshish Chavan SND_SOC_DAPM_OUTPUT("OUT1L"), 60552082d8fSAshish Chavan SND_SOC_DAPM_OUTPUT("OUT1R"), 6066950c60dSAshish Chavan SND_SOC_DAPM_OUTPUT("HPL"), 6076950c60dSAshish Chavan SND_SOC_DAPM_OUTPUT("HPR"), 60852082d8fSAshish Chavan SND_SOC_DAPM_OUTPUT("OUT2"), 6096950c60dSAshish Chavan }; 6106950c60dSAshish Chavan 6116950c60dSAshish Chavan /* DAPM audio route definition */ 6126950c60dSAshish Chavan static const struct snd_soc_dapm_route da7210_audio_map[] = { 6136950c60dSAshish Chavan /* Dest Connecting Widget source */ 6146950c60dSAshish Chavan /* Input path */ 6156950c60dSAshish Chavan {"Mic Left", NULL, "MICL"}, 6166950c60dSAshish Chavan {"Mic Right", NULL, "MICR"}, 61724b6f263SAshish Chavan {"Aux1 Left", NULL, "AUX1L"}, 61824b6f263SAshish Chavan {"Aux1 Right", NULL, "AUX1R"}, 61924b6f263SAshish Chavan {"Aux2 Mono", NULL, "AUX2"}, 6206950c60dSAshish Chavan 6216950c60dSAshish Chavan {"In Mixer Left", "Mic Left Switch", "Mic Left"}, 6226950c60dSAshish Chavan {"In Mixer Left", "Mic Right Switch", "Mic Right"}, 62324b6f263SAshish Chavan {"In Mixer Left", "Aux1 Left Switch", "Aux1 Left"}, 62424b6f263SAshish Chavan {"In Mixer Left", "Aux2 Switch", "Aux2 Mono"}, 62524b6f263SAshish Chavan {"In Mixer Left", "Outmix Left Switch", "Out Mixer Left"}, 6266950c60dSAshish Chavan 6276950c60dSAshish Chavan {"In Mixer Right", "Mic Right Switch", "Mic Right"}, 6286950c60dSAshish Chavan {"In Mixer Right", "Mic Left Switch", "Mic Left"}, 62924b6f263SAshish Chavan {"In Mixer Right", "Aux1 Right Switch", "Aux1 Right"}, 63024b6f263SAshish Chavan {"In Mixer Right", "Aux2 Switch", "Aux2 Mono"}, 63124b6f263SAshish Chavan {"In Mixer Right", "Outmix Right Switch", "Out Mixer Right"}, 6326950c60dSAshish Chavan 6336950c60dSAshish Chavan {"INPGA Left", NULL, "In Mixer Left"}, 6346950c60dSAshish Chavan {"ADC Left", NULL, "INPGA Left"}, 6356950c60dSAshish Chavan 6366950c60dSAshish Chavan {"INPGA Right", NULL, "In Mixer Right"}, 6376950c60dSAshish Chavan {"ADC Right", NULL, "INPGA Right"}, 6386950c60dSAshish Chavan 6396950c60dSAshish Chavan /* Output path */ 64024b6f263SAshish Chavan {"Out Mixer Left", "Aux1 Left Switch", "Aux1 Left"}, 64124b6f263SAshish Chavan {"Out Mixer Left", "Aux2 Switch", "Aux2 Mono"}, 64224b6f263SAshish Chavan {"Out Mixer Left", "INPGA Left Switch", "INPGA Left"}, 64324b6f263SAshish Chavan {"Out Mixer Left", "INPGA Right Switch", "INPGA Right"}, 6446950c60dSAshish Chavan {"Out Mixer Left", "DAC Left Switch", "DAC Left"}, 64524b6f263SAshish Chavan 64624b6f263SAshish Chavan {"Out Mixer Right", "Aux1 Right Switch", "Aux1 Right"}, 64724b6f263SAshish Chavan {"Out Mixer Right", "Aux2 Switch", "Aux2 Mono"}, 64824b6f263SAshish Chavan {"Out Mixer Right", "INPGA Right Switch", "INPGA Right"}, 64924b6f263SAshish Chavan {"Out Mixer Right", "INPGA Left Switch", "INPGA Left"}, 6506950c60dSAshish Chavan {"Out Mixer Right", "DAC Right Switch", "DAC Right"}, 6516950c60dSAshish Chavan 65224b6f263SAshish Chavan {"Mono Mixer", "INPGA Right Switch", "INPGA Right"}, 65324b6f263SAshish Chavan {"Mono Mixer", "INPGA Left Switch", "INPGA Left"}, 65452082d8fSAshish Chavan {"Mono Mixer", "Outmix Right Switch", "Out Mixer Right"}, 65552082d8fSAshish Chavan {"Mono Mixer", "Outmix Left Switch", "Out Mixer Left"}, 65652082d8fSAshish Chavan 6576950c60dSAshish Chavan {"OUTPGA Left Enable", NULL, "Out Mixer Left"}, 6586950c60dSAshish Chavan {"OUTPGA Right Enable", NULL, "Out Mixer Right"}, 6596950c60dSAshish Chavan 66052082d8fSAshish Chavan {"Out1 Left", NULL, "OUTPGA Left Enable"}, 66152082d8fSAshish Chavan {"OUT1L", NULL, "Out1 Left"}, 66252082d8fSAshish Chavan 66352082d8fSAshish Chavan {"Out1 Right", NULL, "OUTPGA Right Enable"}, 66452082d8fSAshish Chavan {"OUT1R", NULL, "Out1 Right"}, 66552082d8fSAshish Chavan 6666950c60dSAshish Chavan {"Headphone Left", NULL, "OUTPGA Left Enable"}, 6676950c60dSAshish Chavan {"HPL", NULL, "Headphone Left"}, 6686950c60dSAshish Chavan 6696950c60dSAshish Chavan {"Headphone Right", NULL, "OUTPGA Right Enable"}, 6706950c60dSAshish Chavan {"HPR", NULL, "Headphone Right"}, 67152082d8fSAshish Chavan 67252082d8fSAshish Chavan {"Out2 Mono", NULL, "Mono Mixer"}, 67352082d8fSAshish Chavan {"OUT2", NULL, "Out2 Mono"}, 6746950c60dSAshish Chavan }; 6756950c60dSAshish Chavan 67698615454SKuninori Morimoto /* Codec private data */ 67798615454SKuninori Morimoto struct da7210_priv { 67833593b52SAshish Chavan struct regmap *regmap; 679570aa7baSAshish Chavan unsigned int mclk_rate; 680570aa7baSAshish Chavan int master; 68198615454SKuninori Morimoto }; 68298615454SKuninori Morimoto 683c418a84aSAxel Lin static const struct reg_default da7210_reg_defaults[] = { 684aa0e25caSAshish Chavan { 0x00, 0x00 }, 68533593b52SAshish Chavan { 0x01, 0x11 }, 68633593b52SAshish Chavan { 0x03, 0x00 }, 68733593b52SAshish Chavan { 0x04, 0x00 }, 68833593b52SAshish Chavan { 0x05, 0x00 }, 68933593b52SAshish Chavan { 0x06, 0x00 }, 69033593b52SAshish Chavan { 0x07, 0x00 }, 69133593b52SAshish Chavan { 0x08, 0x00 }, 69233593b52SAshish Chavan { 0x09, 0x00 }, 69333593b52SAshish Chavan { 0x0a, 0x00 }, 69433593b52SAshish Chavan { 0x0b, 0x00 }, 69533593b52SAshish Chavan { 0x0c, 0x00 }, 69633593b52SAshish Chavan { 0x0d, 0x00 }, 69733593b52SAshish Chavan { 0x0e, 0x00 }, 69833593b52SAshish Chavan { 0x0f, 0x08 }, 69933593b52SAshish Chavan { 0x10, 0x00 }, 70033593b52SAshish Chavan { 0x11, 0x00 }, 70133593b52SAshish Chavan { 0x12, 0x00 }, 70233593b52SAshish Chavan { 0x13, 0x00 }, 70333593b52SAshish Chavan { 0x14, 0x08 }, 70433593b52SAshish Chavan { 0x15, 0x10 }, 70533593b52SAshish Chavan { 0x16, 0x10 }, 70633593b52SAshish Chavan { 0x17, 0x54 }, 70733593b52SAshish Chavan { 0x18, 0x40 }, 70833593b52SAshish Chavan { 0x19, 0x00 }, 70933593b52SAshish Chavan { 0x1a, 0x00 }, 71033593b52SAshish Chavan { 0x1b, 0x00 }, 71133593b52SAshish Chavan { 0x1c, 0x00 }, 71233593b52SAshish Chavan { 0x1d, 0x00 }, 71333593b52SAshish Chavan { 0x1e, 0x00 }, 71433593b52SAshish Chavan { 0x1f, 0x00 }, 71533593b52SAshish Chavan { 0x20, 0x00 }, 71633593b52SAshish Chavan { 0x21, 0x00 }, 71733593b52SAshish Chavan { 0x22, 0x00 }, 71833593b52SAshish Chavan { 0x23, 0x02 }, 71933593b52SAshish Chavan { 0x24, 0x00 }, 72033593b52SAshish Chavan { 0x25, 0x76 }, 72133593b52SAshish Chavan { 0x26, 0x00 }, 72233593b52SAshish Chavan { 0x27, 0x00 }, 72333593b52SAshish Chavan { 0x28, 0x04 }, 72433593b52SAshish Chavan { 0x29, 0x00 }, 72533593b52SAshish Chavan { 0x2a, 0x00 }, 72633593b52SAshish Chavan { 0x2b, 0x30 }, 72733593b52SAshish Chavan { 0x2c, 0x2A }, 72833593b52SAshish Chavan { 0x83, 0x00 }, 72933593b52SAshish Chavan { 0x84, 0x00 }, 73033593b52SAshish Chavan { 0x85, 0x00 }, 73133593b52SAshish Chavan { 0x86, 0x00 }, 73233593b52SAshish Chavan { 0x87, 0x00 }, 73333593b52SAshish Chavan { 0x88, 0x00 }, 73498615454SKuninori Morimoto }; 73598615454SKuninori Morimoto 73633593b52SAshish Chavan static bool da7210_readable_register(struct device *dev, unsigned int reg) 73733593b52SAshish Chavan { 73833593b52SAshish Chavan switch (reg) { 73933593b52SAshish Chavan case DA7210_A_HID_UNLOCK: 74033593b52SAshish Chavan case DA7210_A_TEST_UNLOCK: 74133593b52SAshish Chavan case DA7210_A_PLL1: 74233593b52SAshish Chavan case DA7210_A_CP_MODE: 74333593b52SAshish Chavan return false; 74433593b52SAshish Chavan default: 74533593b52SAshish Chavan return true; 74633593b52SAshish Chavan } 74733593b52SAshish Chavan } 74833593b52SAshish Chavan 74933593b52SAshish Chavan static bool da7210_volatile_register(struct device *dev, 75040a49710SAxel Lin unsigned int reg) 75198615454SKuninori Morimoto { 75240a49710SAxel Lin switch (reg) { 75340a49710SAxel Lin case DA7210_STATUS: 75433593b52SAshish Chavan return true; 75540a49710SAxel Lin default: 75633593b52SAshish Chavan return false; 75798615454SKuninori Morimoto } 75898615454SKuninori Morimoto } 75998615454SKuninori Morimoto 76098615454SKuninori Morimoto /* 76198615454SKuninori Morimoto * Set PCM DAI word length. 76298615454SKuninori Morimoto */ 76398615454SKuninori Morimoto static int da7210_hw_params(struct snd_pcm_substream *substream, 76498615454SKuninori Morimoto struct snd_pcm_hw_params *params, 76598615454SKuninori Morimoto struct snd_soc_dai *dai) 76698615454SKuninori Morimoto { 767e6968a17SMark Brown struct snd_soc_codec *codec = dai->codec; 768570aa7baSAshish Chavan struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); 76998615454SKuninori Morimoto u32 dai_cfg1; 770570aa7baSAshish Chavan u32 fs, sysclk; 77198615454SKuninori Morimoto 77298615454SKuninori Morimoto /* set DAI source to Left and Right ADC */ 77340a49710SAxel Lin snd_soc_write(codec, DA7210_DAI_SRC_SEL, 77498615454SKuninori Morimoto DA7210_DAI_OUT_R_SRC | DA7210_DAI_OUT_L_SRC); 77598615454SKuninori Morimoto 77698615454SKuninori Morimoto /* Enable DAI */ 77740a49710SAxel Lin snd_soc_write(codec, DA7210_DAI_CFG3, DA7210_DAI_OE | DA7210_DAI_EN); 77898615454SKuninori Morimoto 77940a49710SAxel Lin dai_cfg1 = 0xFC & snd_soc_read(codec, DA7210_DAI_CFG1); 78098615454SKuninori Morimoto 7810194c42aSMark Brown switch (params_width(params)) { 7820194c42aSMark Brown case 16: 78398615454SKuninori Morimoto dai_cfg1 |= DA7210_DAI_WORD_S16_LE; 78498615454SKuninori Morimoto break; 7850194c42aSMark Brown case 20: 7860f8ea586SAshish Chavan dai_cfg1 |= DA7210_DAI_WORD_S20_3LE; 7870f8ea586SAshish Chavan break; 7880194c42aSMark Brown case 24: 78998615454SKuninori Morimoto dai_cfg1 |= DA7210_DAI_WORD_S24_LE; 79098615454SKuninori Morimoto break; 7910194c42aSMark Brown case 32: 7920f8ea586SAshish Chavan dai_cfg1 |= DA7210_DAI_WORD_S32_LE; 7930f8ea586SAshish Chavan break; 79498615454SKuninori Morimoto default: 79598615454SKuninori Morimoto return -EINVAL; 79698615454SKuninori Morimoto } 79798615454SKuninori Morimoto 79840a49710SAxel Lin snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1); 79998615454SKuninori Morimoto 80098615454SKuninori Morimoto switch (params_rate(params)) { 8013a9d6202SKuninori Morimoto case 8000: 8023a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_8000; 803570aa7baSAshish Chavan sysclk = 3072000; 804960b3b4bSKuninori Morimoto break; 805960b3b4bSKuninori Morimoto case 11025: 806960b3b4bSKuninori Morimoto fs = DA7210_PLL_FS_11025; 807570aa7baSAshish Chavan sysclk = 2822400; 8083a9d6202SKuninori Morimoto break; 8093a9d6202SKuninori Morimoto case 12000: 8103a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_12000; 811570aa7baSAshish Chavan sysclk = 3072000; 8123a9d6202SKuninori Morimoto break; 8133a9d6202SKuninori Morimoto case 16000: 8143a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_16000; 815570aa7baSAshish Chavan sysclk = 3072000; 816960b3b4bSKuninori Morimoto break; 817960b3b4bSKuninori Morimoto case 22050: 818960b3b4bSKuninori Morimoto fs = DA7210_PLL_FS_22050; 819570aa7baSAshish Chavan sysclk = 2822400; 8203a9d6202SKuninori Morimoto break; 8213a9d6202SKuninori Morimoto case 32000: 8223a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_32000; 823570aa7baSAshish Chavan sysclk = 3072000; 824960b3b4bSKuninori Morimoto break; 825960b3b4bSKuninori Morimoto case 44100: 826960b3b4bSKuninori Morimoto fs = DA7210_PLL_FS_44100; 827570aa7baSAshish Chavan sysclk = 2822400; 8283a9d6202SKuninori Morimoto break; 82998615454SKuninori Morimoto case 48000: 8303a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_48000; 831570aa7baSAshish Chavan sysclk = 3072000; 832960b3b4bSKuninori Morimoto break; 833960b3b4bSKuninori Morimoto case 88200: 834960b3b4bSKuninori Morimoto fs = DA7210_PLL_FS_88200; 835570aa7baSAshish Chavan sysclk = 2822400; 8363a9d6202SKuninori Morimoto break; 8373a9d6202SKuninori Morimoto case 96000: 8383a9d6202SKuninori Morimoto fs = DA7210_PLL_FS_96000; 839570aa7baSAshish Chavan sysclk = 3072000; 84098615454SKuninori Morimoto break; 84198615454SKuninori Morimoto default: 84298615454SKuninori Morimoto return -EINVAL; 84398615454SKuninori Morimoto } 84498615454SKuninori Morimoto 845960b3b4bSKuninori Morimoto /* Disable active mode */ 846960b3b4bSKuninori Morimoto snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0); 847960b3b4bSKuninori Morimoto 8483a9d6202SKuninori Morimoto snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_FS_MASK, fs); 849960b3b4bSKuninori Morimoto 850570aa7baSAshish Chavan if (da7210->mclk_rate && (da7210->mclk_rate != sysclk)) { 851570aa7baSAshish Chavan /* PLL mode, disable PLL bypass */ 852570aa7baSAshish Chavan snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 0); 8533cb81651SAshish Chavan 8543cb81651SAshish Chavan if (!da7210->master) { 8553cb81651SAshish Chavan /* PLL slave mode, also enable SRM */ 8563cb81651SAshish Chavan snd_soc_update_bits(codec, DA7210_PLL, 8573cb81651SAshish Chavan (DA7210_MCLK_SRM_EN | 8583cb81651SAshish Chavan DA7210_MCLK_DET_EN), 8593cb81651SAshish Chavan (DA7210_MCLK_SRM_EN | 8603cb81651SAshish Chavan DA7210_MCLK_DET_EN)); 8613cb81651SAshish Chavan } 862570aa7baSAshish Chavan } else { 8633cb81651SAshish Chavan /* PLL bypass mode, enable PLL bypass and Auto Detection */ 8643cb81651SAshish Chavan snd_soc_update_bits(codec, DA7210_PLL, DA7210_MCLK_DET_EN, 8653cb81651SAshish Chavan DA7210_MCLK_DET_EN); 866570aa7baSAshish Chavan snd_soc_update_bits(codec, DA7210_PLL_DIV3, DA7210_PLL_BYP, 867570aa7baSAshish Chavan DA7210_PLL_BYP); 868570aa7baSAshish Chavan } 869960b3b4bSKuninori Morimoto /* Enable active mode */ 870960b3b4bSKuninori Morimoto snd_soc_update_bits(codec, DA7210_STARTUP1, 871960b3b4bSKuninori Morimoto DA7210_SC_MST_EN, DA7210_SC_MST_EN); 87298615454SKuninori Morimoto 87398615454SKuninori Morimoto return 0; 87498615454SKuninori Morimoto } 87598615454SKuninori Morimoto 87698615454SKuninori Morimoto /* 87798615454SKuninori Morimoto * Set DAI mode and Format 87898615454SKuninori Morimoto */ 87998615454SKuninori Morimoto static int da7210_set_dai_fmt(struct snd_soc_dai *codec_dai, u32 fmt) 88098615454SKuninori Morimoto { 88198615454SKuninori Morimoto struct snd_soc_codec *codec = codec_dai->codec; 882570aa7baSAshish Chavan struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); 88398615454SKuninori Morimoto u32 dai_cfg1; 88498615454SKuninori Morimoto u32 dai_cfg3; 88598615454SKuninori Morimoto 88640a49710SAxel Lin dai_cfg1 = 0x7f & snd_soc_read(codec, DA7210_DAI_CFG1); 88740a49710SAxel Lin dai_cfg3 = 0xfc & snd_soc_read(codec, DA7210_DAI_CFG3); 88898615454SKuninori Morimoto 889570aa7baSAshish Chavan if ((snd_soc_read(codec, DA7210_PLL) & DA7210_PLL_EN) && 890570aa7baSAshish Chavan (!(snd_soc_read(codec, DA7210_PLL_DIV3) & DA7210_PLL_BYP))) 891570aa7baSAshish Chavan return -EINVAL; 892570aa7baSAshish Chavan 89398615454SKuninori Morimoto switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 89498615454SKuninori Morimoto case SND_SOC_DAIFMT_CBM_CFM: 895570aa7baSAshish Chavan da7210->master = 1; 89698615454SKuninori Morimoto dai_cfg1 |= DA7210_DAI_MODE_MASTER; 89798615454SKuninori Morimoto break; 8980f8ea586SAshish Chavan case SND_SOC_DAIFMT_CBS_CFS: 899570aa7baSAshish Chavan da7210->master = 0; 9000f8ea586SAshish Chavan dai_cfg1 |= DA7210_DAI_MODE_SLAVE; 9010f8ea586SAshish Chavan break; 90298615454SKuninori Morimoto default: 90398615454SKuninori Morimoto return -EINVAL; 90498615454SKuninori Morimoto } 90598615454SKuninori Morimoto 90698615454SKuninori Morimoto /* FIXME 90798615454SKuninori Morimoto * 90898615454SKuninori Morimoto * It support I2S only now 90998615454SKuninori Morimoto */ 91098615454SKuninori Morimoto switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 91198615454SKuninori Morimoto case SND_SOC_DAIFMT_I2S: 91298615454SKuninori Morimoto dai_cfg3 |= DA7210_DAI_FORMAT_I2SMODE; 91398615454SKuninori Morimoto break; 9140f8ea586SAshish Chavan case SND_SOC_DAIFMT_LEFT_J: 9150f8ea586SAshish Chavan dai_cfg3 |= DA7210_DAI_FORMAT_LEFT_J; 9160f8ea586SAshish Chavan break; 9170f8ea586SAshish Chavan case SND_SOC_DAIFMT_RIGHT_J: 9180f8ea586SAshish Chavan dai_cfg3 |= DA7210_DAI_FORMAT_RIGHT_J; 9190f8ea586SAshish Chavan break; 92098615454SKuninori Morimoto default: 92198615454SKuninori Morimoto return -EINVAL; 92298615454SKuninori Morimoto } 92398615454SKuninori Morimoto 92498615454SKuninori Morimoto /* FIXME 92598615454SKuninori Morimoto * 92698615454SKuninori Morimoto * It support 64bit data transmission only now 92798615454SKuninori Morimoto */ 92898615454SKuninori Morimoto dai_cfg1 |= DA7210_DAI_FLEN_64BIT; 92998615454SKuninori Morimoto 93040a49710SAxel Lin snd_soc_write(codec, DA7210_DAI_CFG1, dai_cfg1); 93140a49710SAxel Lin snd_soc_write(codec, DA7210_DAI_CFG3, dai_cfg3); 93298615454SKuninori Morimoto 93398615454SKuninori Morimoto return 0; 93498615454SKuninori Morimoto } 93598615454SKuninori Morimoto 9365eda1949SAshish Chavan static int da7210_mute(struct snd_soc_dai *dai, int mute) 9375eda1949SAshish Chavan { 9385eda1949SAshish Chavan struct snd_soc_codec *codec = dai->codec; 9395eda1949SAshish Chavan u8 mute_reg = snd_soc_read(codec, DA7210_DAC_HPF) & 0xFB; 9405eda1949SAshish Chavan 9415eda1949SAshish Chavan if (mute) 9425eda1949SAshish Chavan snd_soc_write(codec, DA7210_DAC_HPF, mute_reg | 0x4); 9435eda1949SAshish Chavan else 9445eda1949SAshish Chavan snd_soc_write(codec, DA7210_DAC_HPF, mute_reg); 9455eda1949SAshish Chavan return 0; 9465eda1949SAshish Chavan } 9475eda1949SAshish Chavan 9480f8ea586SAshish Chavan #define DA7210_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 9490f8ea586SAshish Chavan SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 95098615454SKuninori Morimoto 951570aa7baSAshish Chavan static int da7210_set_dai_sysclk(struct snd_soc_dai *codec_dai, 952570aa7baSAshish Chavan int clk_id, unsigned int freq, int dir) 953570aa7baSAshish Chavan { 954570aa7baSAshish Chavan struct snd_soc_codec *codec = codec_dai->codec; 955570aa7baSAshish Chavan struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); 956570aa7baSAshish Chavan 957570aa7baSAshish Chavan switch (clk_id) { 958570aa7baSAshish Chavan case DA7210_CLKSRC_MCLK: 959570aa7baSAshish Chavan switch (freq) { 960570aa7baSAshish Chavan case 12000000: 961570aa7baSAshish Chavan case 13000000: 962570aa7baSAshish Chavan case 13500000: 963570aa7baSAshish Chavan case 14400000: 964570aa7baSAshish Chavan case 19200000: 965570aa7baSAshish Chavan case 19680000: 966570aa7baSAshish Chavan case 19800000: 967570aa7baSAshish Chavan da7210->mclk_rate = freq; 968570aa7baSAshish Chavan return 0; 969570aa7baSAshish Chavan default: 970570aa7baSAshish Chavan dev_err(codec_dai->dev, "Unsupported MCLK value %d\n", 971570aa7baSAshish Chavan freq); 972570aa7baSAshish Chavan return -EINVAL; 973570aa7baSAshish Chavan } 974570aa7baSAshish Chavan break; 975570aa7baSAshish Chavan default: 976570aa7baSAshish Chavan dev_err(codec_dai->dev, "Unknown clock source %d\n", clk_id); 977570aa7baSAshish Chavan return -EINVAL; 978570aa7baSAshish Chavan } 979570aa7baSAshish Chavan } 980570aa7baSAshish Chavan 981570aa7baSAshish Chavan /** 982570aa7baSAshish Chavan * da7210_set_dai_pll :Configure the codec PLL 983570aa7baSAshish Chavan * @param codec_dai : pointer to codec DAI 984570aa7baSAshish Chavan * @param pll_id : da7210 has only one pll, so pll_id is always zero 985570aa7baSAshish Chavan * @param fref : MCLK frequency, should be < 20MHz 986570aa7baSAshish Chavan * @param fout : FsDM value, Refer page 44 & 45 of datasheet 987570aa7baSAshish Chavan * @return int : Zero for success, negative error code for error 988570aa7baSAshish Chavan * 989570aa7baSAshish Chavan * Note: Supported PLL input frequencies are 12MHz, 13MHz, 13.5MHz, 14.4MHz, 990570aa7baSAshish Chavan * 19.2MHz, 19.6MHz and 19.8MHz 991570aa7baSAshish Chavan */ 992570aa7baSAshish Chavan static int da7210_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, 993570aa7baSAshish Chavan int source, unsigned int fref, unsigned int fout) 994570aa7baSAshish Chavan { 995570aa7baSAshish Chavan struct snd_soc_codec *codec = codec_dai->codec; 996570aa7baSAshish Chavan struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); 997570aa7baSAshish Chavan 998570aa7baSAshish Chavan u8 pll_div1, pll_div2, pll_div3, cnt; 999570aa7baSAshish Chavan 1000570aa7baSAshish Chavan /* In slave mode, there is only one set of divisors */ 1001570aa7baSAshish Chavan if (!da7210->master) 1002570aa7baSAshish Chavan fout = 2822400; 1003570aa7baSAshish Chavan 1004570aa7baSAshish Chavan /* Search pll div array for correct divisors */ 1005570aa7baSAshish Chavan for (cnt = 0; cnt < ARRAY_SIZE(da7210_pll_div); cnt++) { 1006c4b14e70SAshish Chavan /* check fref, mode and fout */ 1007c4b14e70SAshish Chavan if ((fref == da7210_pll_div[cnt].fref) && 1008c4b14e70SAshish Chavan (da7210->master == da7210_pll_div[cnt].mode) && 1009c4b14e70SAshish Chavan (fout == da7210_pll_div[cnt].fout)) { 1010570aa7baSAshish Chavan /* all match, pick up divisors */ 1011570aa7baSAshish Chavan pll_div1 = da7210_pll_div[cnt].div1; 1012570aa7baSAshish Chavan pll_div2 = da7210_pll_div[cnt].div2; 1013570aa7baSAshish Chavan pll_div3 = da7210_pll_div[cnt].div3; 1014570aa7baSAshish Chavan break; 1015570aa7baSAshish Chavan } 1016570aa7baSAshish Chavan } 1017570aa7baSAshish Chavan if (cnt >= ARRAY_SIZE(da7210_pll_div)) 1018570aa7baSAshish Chavan goto err; 1019570aa7baSAshish Chavan 1020570aa7baSAshish Chavan /* Disable active mode */ 1021570aa7baSAshish Chavan snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 0); 1022570aa7baSAshish Chavan /* Write PLL dividers */ 1023570aa7baSAshish Chavan snd_soc_write(codec, DA7210_PLL_DIV1, pll_div1); 1024570aa7baSAshish Chavan snd_soc_write(codec, DA7210_PLL_DIV2, pll_div2); 1025570aa7baSAshish Chavan snd_soc_update_bits(codec, DA7210_PLL_DIV3, 1026570aa7baSAshish Chavan DA7210_PLL_DIV_L_MASK, pll_div3); 1027570aa7baSAshish Chavan 10283cb81651SAshish Chavan /* Enable PLL */ 10293cb81651SAshish Chavan snd_soc_update_bits(codec, DA7210_PLL, DA7210_PLL_EN, DA7210_PLL_EN); 10303cb81651SAshish Chavan 1031570aa7baSAshish Chavan /* Enable active mode */ 1032570aa7baSAshish Chavan snd_soc_update_bits(codec, DA7210_STARTUP1, DA7210_SC_MST_EN, 1033570aa7baSAshish Chavan DA7210_SC_MST_EN); 1034570aa7baSAshish Chavan return 0; 1035570aa7baSAshish Chavan err: 1036570aa7baSAshish Chavan dev_err(codec_dai->dev, "Unsupported PLL input frequency %d\n", fref); 1037570aa7baSAshish Chavan return -EINVAL; 1038570aa7baSAshish Chavan } 1039570aa7baSAshish Chavan 104098615454SKuninori Morimoto /* DAI operations */ 104185e7652dSLars-Peter Clausen static const struct snd_soc_dai_ops da7210_dai_ops = { 104298615454SKuninori Morimoto .hw_params = da7210_hw_params, 104398615454SKuninori Morimoto .set_fmt = da7210_set_dai_fmt, 1044570aa7baSAshish Chavan .set_sysclk = da7210_set_dai_sysclk, 1045570aa7baSAshish Chavan .set_pll = da7210_set_dai_pll, 10465eda1949SAshish Chavan .digital_mute = da7210_mute, 104798615454SKuninori Morimoto }; 104898615454SKuninori Morimoto 1049f0fba2adSLiam Girdwood static struct snd_soc_dai_driver da7210_dai = { 1050f0fba2adSLiam Girdwood .name = "da7210-hifi", 105198615454SKuninori Morimoto /* playback capabilities */ 105298615454SKuninori Morimoto .playback = { 105398615454SKuninori Morimoto .stream_name = "Playback", 105498615454SKuninori Morimoto .channels_min = 1, 105598615454SKuninori Morimoto .channels_max = 2, 105698615454SKuninori Morimoto .rates = SNDRV_PCM_RATE_8000_96000, 105798615454SKuninori Morimoto .formats = DA7210_FORMATS, 105898615454SKuninori Morimoto }, 105998615454SKuninori Morimoto /* capture capabilities */ 106098615454SKuninori Morimoto .capture = { 106198615454SKuninori Morimoto .stream_name = "Capture", 106298615454SKuninori Morimoto .channels_min = 1, 106398615454SKuninori Morimoto .channels_max = 2, 106498615454SKuninori Morimoto .rates = SNDRV_PCM_RATE_8000_96000, 106598615454SKuninori Morimoto .formats = DA7210_FORMATS, 106698615454SKuninori Morimoto }, 106798615454SKuninori Morimoto .ops = &da7210_dai_ops, 1068960b3b4bSKuninori Morimoto .symmetric_rates = 1, 106998615454SKuninori Morimoto }; 107098615454SKuninori Morimoto 1071f0fba2adSLiam Girdwood static int da7210_probe(struct snd_soc_codec *codec) 107298615454SKuninori Morimoto { 1073f0fba2adSLiam Girdwood struct da7210_priv *da7210 = snd_soc_codec_get_drvdata(codec); 107498615454SKuninori Morimoto 1075f0fba2adSLiam Girdwood dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); 107698615454SKuninori Morimoto 1077570aa7baSAshish Chavan da7210->mclk_rate = 0; /* This will be set from set_sysclk() */ 1078570aa7baSAshish Chavan da7210->master = 0; /* This will be set from set_fmt() */ 1079570aa7baSAshish Chavan 1080570aa7baSAshish Chavan /* Enable internal regulator & bias current */ 1081570aa7baSAshish Chavan snd_soc_write(codec, DA7210_CONTROL, DA7210_REG_EN | DA7210_BIAS_EN); 108298615454SKuninori Morimoto 108398615454SKuninori Morimoto /* 108498615454SKuninori Morimoto * ADC settings 108598615454SKuninori Morimoto */ 108698615454SKuninori Morimoto 108798615454SKuninori Morimoto /* Enable Left & Right MIC PGA and Mic Bias */ 108840a49710SAxel Lin snd_soc_write(codec, DA7210_MIC_L, DA7210_MIC_L_EN | DA7210_MICBIAS_EN); 108940a49710SAxel Lin snd_soc_write(codec, DA7210_MIC_R, DA7210_MIC_R_EN); 109098615454SKuninori Morimoto 109198615454SKuninori Morimoto /* Enable Left and Right input PGA */ 109240a49710SAxel Lin snd_soc_write(codec, DA7210_INMIX_L, DA7210_IN_L_EN); 109340a49710SAxel Lin snd_soc_write(codec, DA7210_INMIX_R, DA7210_IN_R_EN); 109498615454SKuninori Morimoto 109598615454SKuninori Morimoto /* Enable Left and Right ADC */ 109640a49710SAxel Lin snd_soc_write(codec, DA7210_ADC, DA7210_ADC_L_EN | DA7210_ADC_R_EN); 109798615454SKuninori Morimoto 109898615454SKuninori Morimoto /* 109998615454SKuninori Morimoto * DAC settings 110098615454SKuninori Morimoto */ 110198615454SKuninori Morimoto 110298615454SKuninori Morimoto /* Enable Left and Right DAC */ 110340a49710SAxel Lin snd_soc_write(codec, DA7210_DAC_SEL, 110498615454SKuninori Morimoto DA7210_DAC_L_SRC_DAI_L | DA7210_DAC_L_EN | 110598615454SKuninori Morimoto DA7210_DAC_R_SRC_DAI_R | DA7210_DAC_R_EN); 110698615454SKuninori Morimoto 110798615454SKuninori Morimoto /* Enable Left and Right out PGA */ 110840a49710SAxel Lin snd_soc_write(codec, DA7210_OUTMIX_L, DA7210_OUT_L_EN); 110940a49710SAxel Lin snd_soc_write(codec, DA7210_OUTMIX_R, DA7210_OUT_R_EN); 111098615454SKuninori Morimoto 111198615454SKuninori Morimoto /* Enable Left and Right HeadPhone PGA */ 111240a49710SAxel Lin snd_soc_write(codec, DA7210_HP_CFG, 111398615454SKuninori Morimoto DA7210_HP_2CAP_MODE | DA7210_HP_SENSE_EN | 111498615454SKuninori Morimoto DA7210_HP_L_EN | DA7210_HP_MODE | DA7210_HP_R_EN); 111598615454SKuninori Morimoto 11165eda1949SAshish Chavan /* Enable ramp mode for DAC gain update */ 11175eda1949SAshish Chavan snd_soc_write(codec, DA7210_SOFTMUTE, DA7210_RAMP_EN); 11185eda1949SAshish Chavan 111952082d8fSAshish Chavan /* 112052082d8fSAshish Chavan * For DA7210 codec, there are two ways to enable/disable analog IOs 112152082d8fSAshish Chavan * and ADC/DAC, 112252082d8fSAshish Chavan * (1) Using "Enable Bit" of register associated with that IO 112352082d8fSAshish Chavan * (or ADC/DAC) 112452082d8fSAshish Chavan * e.g. Mic Left can be enabled using bit 7 of MIC_L(0x7) reg 112552082d8fSAshish Chavan * 112652082d8fSAshish Chavan * (2) Using "Standby Bit" of STARTUP2 or STARTUP3 register 112752082d8fSAshish Chavan * e.g. Mic left can be put to STANDBY using bit 0 of STARTUP3(0x5) 112852082d8fSAshish Chavan * 112952082d8fSAshish Chavan * Out of these two methods, the one using STANDBY bits is preferred 113052082d8fSAshish Chavan * way to enable/disable individual blocks. This is because STANDBY 113152082d8fSAshish Chavan * registers are part of system controller which allows system power 113252082d8fSAshish Chavan * up/down in a controlled, pop-free manner. Also, as per application 113352082d8fSAshish Chavan * note of DA7210, STANDBY register bits are only effective if a 113452082d8fSAshish Chavan * particular IO (or ADC/DAC) is already enabled using enable/disable 113552082d8fSAshish Chavan * register bits. Keeping these things in mind, current DAPM 113652082d8fSAshish Chavan * implementation manipulates only STANDBY bits. 113752082d8fSAshish Chavan * 113852082d8fSAshish Chavan * Overall implementation can be outlined as below, 113952082d8fSAshish Chavan * 114052082d8fSAshish Chavan * - "Enable bit" of an IO or ADC/DAC is used to enable it in probe() 114152082d8fSAshish Chavan * - "STANDBY bit" is controlled by DAPM 114252082d8fSAshish Chavan */ 114352082d8fSAshish Chavan 114452082d8fSAshish Chavan /* Enable Line out amplifiers */ 114552082d8fSAshish Chavan snd_soc_write(codec, DA7210_OUT1_L, DA7210_OUT1_L_EN); 114652082d8fSAshish Chavan snd_soc_write(codec, DA7210_OUT1_R, DA7210_OUT1_R_EN); 114752082d8fSAshish Chavan snd_soc_write(codec, DA7210_OUT2, DA7210_OUT2_EN | 114852082d8fSAshish Chavan DA7210_OUT2_OUTMIX_L | DA7210_OUT2_OUTMIX_R); 114952082d8fSAshish Chavan 115024b6f263SAshish Chavan /* Enable Aux1 */ 115124b6f263SAshish Chavan snd_soc_write(codec, DA7210_AUX1_L, DA7210_AUX1_L_EN); 115224b6f263SAshish Chavan snd_soc_write(codec, DA7210_AUX1_R, DA7210_AUX1_R_EN); 115324b6f263SAshish Chavan /* Enable Aux2 */ 115424b6f263SAshish Chavan snd_soc_write(codec, DA7210_AUX2, DA7210_AUX2_EN); 115524b6f263SAshish Chavan 1156604bb229SAshish Chavan /* Set PLL Master clock range 10-20 MHz, enable PLL bypass */ 1157604bb229SAshish Chavan snd_soc_write(codec, DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ | 1158604bb229SAshish Chavan DA7210_PLL_BYP); 1159570aa7baSAshish Chavan 116098615454SKuninori Morimoto /* Diable PLL and bypass it */ 116140a49710SAxel Lin snd_soc_write(codec, DA7210_PLL, DA7210_PLL_FS_48000); 116298615454SKuninori Morimoto 116398615454SKuninori Morimoto /* Activate all enabled subsystem */ 116440a49710SAxel Lin snd_soc_write(codec, DA7210_STARTUP1, DA7210_SC_MST_EN); 116598615454SKuninori Morimoto 1166f0fba2adSLiam Girdwood dev_info(codec->dev, "DA7210 Audio Codec %s\n", DA7210_VERSION); 116798615454SKuninori Morimoto 1168f0fba2adSLiam Girdwood return 0; 116998615454SKuninori Morimoto } 117098615454SKuninori Morimoto 1171f0fba2adSLiam Girdwood static struct snd_soc_codec_driver soc_codec_dev_da7210 = { 1172f0fba2adSLiam Girdwood .probe = da7210_probe, 1173a6f096f3SMark Brown 1174a6f096f3SMark Brown .controls = da7210_snd_controls, 1175a6f096f3SMark Brown .num_controls = ARRAY_SIZE(da7210_snd_controls), 11766950c60dSAshish Chavan 11776950c60dSAshish Chavan .dapm_widgets = da7210_dapm_widgets, 11786950c60dSAshish Chavan .num_dapm_widgets = ARRAY_SIZE(da7210_dapm_widgets), 11796950c60dSAshish Chavan .dapm_routes = da7210_audio_map, 11806950c60dSAshish Chavan .num_dapm_routes = ARRAY_SIZE(da7210_audio_map), 1181f0fba2adSLiam Girdwood }; 1182f0fba2adSLiam Girdwood 118325c1a63fSFabio Estevam #if IS_ENABLED(CONFIG_I2C) 1184aa0e25caSAshish Chavan 118541a5fefeSMark Brown static const struct reg_sequence da7210_regmap_i2c_patch[] = { 1186aa0e25caSAshish Chavan 1187aa0e25caSAshish Chavan /* System controller master disable */ 1188aa0e25caSAshish Chavan { DA7210_STARTUP1, 0x00 }, 1189604bb229SAshish Chavan /* Set PLL Master clock range 10-20 MHz */ 1190604bb229SAshish Chavan { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ }, 1191aa0e25caSAshish Chavan 1192aa0e25caSAshish Chavan /* to unlock */ 1193aa0e25caSAshish Chavan { DA7210_A_HID_UNLOCK, 0x8B}, 1194aa0e25caSAshish Chavan { DA7210_A_TEST_UNLOCK, 0xB4}, 1195aa0e25caSAshish Chavan { DA7210_A_PLL1, 0x01}, 1196aa0e25caSAshish Chavan { DA7210_A_CP_MODE, 0x7C}, 1197aa0e25caSAshish Chavan /* to re-lock */ 1198aa0e25caSAshish Chavan { DA7210_A_HID_UNLOCK, 0x00}, 1199aa0e25caSAshish Chavan { DA7210_A_TEST_UNLOCK, 0x00}, 1200aa0e25caSAshish Chavan }; 1201aa0e25caSAshish Chavan 1202aa0e25caSAshish Chavan static const struct regmap_config da7210_regmap_config_i2c = { 120333593b52SAshish Chavan .reg_bits = 8, 120433593b52SAshish Chavan .val_bits = 8, 120533593b52SAshish Chavan 120633593b52SAshish Chavan .reg_defaults = da7210_reg_defaults, 120733593b52SAshish Chavan .num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults), 120833593b52SAshish Chavan .volatile_reg = da7210_volatile_register, 120933593b52SAshish Chavan .readable_reg = da7210_readable_register, 121033593b52SAshish Chavan .cache_type = REGCACHE_RBTREE, 121133593b52SAshish Chavan }; 121233593b52SAshish Chavan 12137a79e94eSBill Pemberton static int da7210_i2c_probe(struct i2c_client *i2c, 121498615454SKuninori Morimoto const struct i2c_device_id *id) 121598615454SKuninori Morimoto { 121698615454SKuninori Morimoto struct da7210_priv *da7210; 121798615454SKuninori Morimoto int ret; 121898615454SKuninori Morimoto 1219306bf6b1SAxel Lin da7210 = devm_kzalloc(&i2c->dev, sizeof(struct da7210_priv), 1220306bf6b1SAxel Lin GFP_KERNEL); 122198615454SKuninori Morimoto if (!da7210) 122298615454SKuninori Morimoto return -ENOMEM; 122398615454SKuninori Morimoto 122498615454SKuninori Morimoto i2c_set_clientdata(i2c, da7210); 122533593b52SAshish Chavan 12264e75955dSSachin Kamat da7210->regmap = devm_regmap_init_i2c(i2c, &da7210_regmap_config_i2c); 122733593b52SAshish Chavan if (IS_ERR(da7210->regmap)) { 122833593b52SAshish Chavan ret = PTR_ERR(da7210->regmap); 122933593b52SAshish Chavan dev_err(&i2c->dev, "regmap_init() failed: %d\n", ret); 123033593b52SAshish Chavan return ret; 123133593b52SAshish Chavan } 123298615454SKuninori Morimoto 1233aa0e25caSAshish Chavan ret = regmap_register_patch(da7210->regmap, da7210_regmap_i2c_patch, 1234aa0e25caSAshish Chavan ARRAY_SIZE(da7210_regmap_i2c_patch)); 1235aa0e25caSAshish Chavan if (ret != 0) 1236aa0e25caSAshish Chavan dev_warn(&i2c->dev, "Failed to apply regmap patch: %d\n", ret); 1237aa0e25caSAshish Chavan 1238f0fba2adSLiam Girdwood ret = snd_soc_register_codec(&i2c->dev, 1239f0fba2adSLiam Girdwood &soc_codec_dev_da7210, &da7210_dai, 1); 12404e75955dSSachin Kamat if (ret < 0) 124133593b52SAshish Chavan dev_err(&i2c->dev, "Failed to register codec: %d\n", ret); 124233593b52SAshish Chavan 124398615454SKuninori Morimoto return ret; 124498615454SKuninori Morimoto } 124598615454SKuninori Morimoto 12467a79e94eSBill Pemberton static int da7210_i2c_remove(struct i2c_client *client) 124798615454SKuninori Morimoto { 1248f0fba2adSLiam Girdwood snd_soc_unregister_codec(&client->dev); 124998615454SKuninori Morimoto return 0; 125098615454SKuninori Morimoto } 125198615454SKuninori Morimoto 125298615454SKuninori Morimoto static const struct i2c_device_id da7210_i2c_id[] = { 125398615454SKuninori Morimoto { "da7210", 0 }, 125498615454SKuninori Morimoto { } 125598615454SKuninori Morimoto }; 125698615454SKuninori Morimoto MODULE_DEVICE_TABLE(i2c, da7210_i2c_id); 125798615454SKuninori Morimoto 125898615454SKuninori Morimoto /* I2C codec control layer */ 125998615454SKuninori Morimoto static struct i2c_driver da7210_i2c_driver = { 126098615454SKuninori Morimoto .driver = { 1261aa0e25caSAshish Chavan .name = "da7210", 126298615454SKuninori Morimoto .owner = THIS_MODULE, 126398615454SKuninori Morimoto }, 126498615454SKuninori Morimoto .probe = da7210_i2c_probe, 12657a79e94eSBill Pemberton .remove = da7210_i2c_remove, 126698615454SKuninori Morimoto .id_table = da7210_i2c_id, 126798615454SKuninori Morimoto }; 126898615454SKuninori Morimoto #endif 126998615454SKuninori Morimoto 1270aa0e25caSAshish Chavan #if defined(CONFIG_SPI_MASTER) 1271aa0e25caSAshish Chavan 127241a5fefeSMark Brown static const struct reg_sequence da7210_regmap_spi_patch[] = { 1273aa0e25caSAshish Chavan /* Dummy read to give two pulses over nCS for SPI */ 1274aa0e25caSAshish Chavan { DA7210_AUX2, 0x00 }, 1275aa0e25caSAshish Chavan { DA7210_AUX2, 0x00 }, 1276aa0e25caSAshish Chavan 1277aa0e25caSAshish Chavan /* System controller master disable */ 1278aa0e25caSAshish Chavan { DA7210_STARTUP1, 0x00 }, 1279604bb229SAshish Chavan /* Set PLL Master clock range 10-20 MHz */ 1280604bb229SAshish Chavan { DA7210_PLL_DIV3, DA7210_MCLK_RANGE_10_20_MHZ }, 1281aa0e25caSAshish Chavan 1282aa0e25caSAshish Chavan /* to set PAGE1 of SPI register space */ 1283aa0e25caSAshish Chavan { DA7210_PAGE_CONTROL, 0x80 }, 1284aa0e25caSAshish Chavan /* to unlock */ 1285aa0e25caSAshish Chavan { DA7210_A_HID_UNLOCK, 0x8B}, 1286aa0e25caSAshish Chavan { DA7210_A_TEST_UNLOCK, 0xB4}, 1287aa0e25caSAshish Chavan { DA7210_A_PLL1, 0x01}, 1288aa0e25caSAshish Chavan { DA7210_A_CP_MODE, 0x7C}, 1289aa0e25caSAshish Chavan /* to re-lock */ 1290aa0e25caSAshish Chavan { DA7210_A_HID_UNLOCK, 0x00}, 1291aa0e25caSAshish Chavan { DA7210_A_TEST_UNLOCK, 0x00}, 1292aa0e25caSAshish Chavan /* to set back PAGE0 of SPI register space */ 1293aa0e25caSAshish Chavan { DA7210_PAGE_CONTROL, 0x00 }, 1294aa0e25caSAshish Chavan }; 1295aa0e25caSAshish Chavan 1296aa0e25caSAshish Chavan static const struct regmap_config da7210_regmap_config_spi = { 1297aa0e25caSAshish Chavan .reg_bits = 8, 1298aa0e25caSAshish Chavan .val_bits = 8, 1299aa0e25caSAshish Chavan .read_flag_mask = 0x01, 1300aa0e25caSAshish Chavan .write_flag_mask = 0x00, 1301aa0e25caSAshish Chavan 1302aa0e25caSAshish Chavan .reg_defaults = da7210_reg_defaults, 1303aa0e25caSAshish Chavan .num_reg_defaults = ARRAY_SIZE(da7210_reg_defaults), 1304aa0e25caSAshish Chavan .volatile_reg = da7210_volatile_register, 1305aa0e25caSAshish Chavan .readable_reg = da7210_readable_register, 1306aa0e25caSAshish Chavan .cache_type = REGCACHE_RBTREE, 1307aa0e25caSAshish Chavan }; 1308aa0e25caSAshish Chavan 13097a79e94eSBill Pemberton static int da7210_spi_probe(struct spi_device *spi) 1310aa0e25caSAshish Chavan { 1311aa0e25caSAshish Chavan struct da7210_priv *da7210; 1312aa0e25caSAshish Chavan int ret; 1313aa0e25caSAshish Chavan 1314aa0e25caSAshish Chavan da7210 = devm_kzalloc(&spi->dev, sizeof(struct da7210_priv), 1315aa0e25caSAshish Chavan GFP_KERNEL); 1316aa0e25caSAshish Chavan if (!da7210) 1317aa0e25caSAshish Chavan return -ENOMEM; 1318aa0e25caSAshish Chavan 1319aa0e25caSAshish Chavan spi_set_drvdata(spi, da7210); 1320aa0e25caSAshish Chavan da7210->regmap = devm_regmap_init_spi(spi, &da7210_regmap_config_spi); 1321aa0e25caSAshish Chavan if (IS_ERR(da7210->regmap)) { 1322aa0e25caSAshish Chavan ret = PTR_ERR(da7210->regmap); 1323aa0e25caSAshish Chavan dev_err(&spi->dev, "Failed to register regmap: %d\n", ret); 1324aa0e25caSAshish Chavan return ret; 1325aa0e25caSAshish Chavan } 1326aa0e25caSAshish Chavan 1327aa0e25caSAshish Chavan ret = regmap_register_patch(da7210->regmap, da7210_regmap_spi_patch, 1328aa0e25caSAshish Chavan ARRAY_SIZE(da7210_regmap_spi_patch)); 1329aa0e25caSAshish Chavan if (ret != 0) 1330aa0e25caSAshish Chavan dev_warn(&spi->dev, "Failed to apply regmap patch: %d\n", ret); 1331aa0e25caSAshish Chavan 1332aa0e25caSAshish Chavan ret = snd_soc_register_codec(&spi->dev, 1333aa0e25caSAshish Chavan &soc_codec_dev_da7210, &da7210_dai, 1); 1334aa0e25caSAshish Chavan 1335aa0e25caSAshish Chavan return ret; 1336aa0e25caSAshish Chavan } 1337aa0e25caSAshish Chavan 13387a79e94eSBill Pemberton static int da7210_spi_remove(struct spi_device *spi) 1339aa0e25caSAshish Chavan { 1340aa0e25caSAshish Chavan snd_soc_unregister_codec(&spi->dev); 1341aa0e25caSAshish Chavan return 0; 1342aa0e25caSAshish Chavan } 1343aa0e25caSAshish Chavan 1344aa0e25caSAshish Chavan static struct spi_driver da7210_spi_driver = { 1345aa0e25caSAshish Chavan .driver = { 1346aa0e25caSAshish Chavan .name = "da7210", 1347aa0e25caSAshish Chavan .owner = THIS_MODULE, 1348aa0e25caSAshish Chavan }, 1349aa0e25caSAshish Chavan .probe = da7210_spi_probe, 13507a79e94eSBill Pemberton .remove = da7210_spi_remove 1351aa0e25caSAshish Chavan }; 1352aa0e25caSAshish Chavan #endif 1353aa0e25caSAshish Chavan 135498615454SKuninori Morimoto static int __init da7210_modinit(void) 135598615454SKuninori Morimoto { 135698615454SKuninori Morimoto int ret = 0; 135725c1a63fSFabio Estevam #if IS_ENABLED(CONFIG_I2C) 135898615454SKuninori Morimoto ret = i2c_add_driver(&da7210_i2c_driver); 135998615454SKuninori Morimoto #endif 1360aa0e25caSAshish Chavan #if defined(CONFIG_SPI_MASTER) 1361aa0e25caSAshish Chavan ret = spi_register_driver(&da7210_spi_driver); 1362aa0e25caSAshish Chavan if (ret) { 1363aa0e25caSAshish Chavan printk(KERN_ERR "Failed to register da7210 SPI driver: %d\n", 1364aa0e25caSAshish Chavan ret); 1365aa0e25caSAshish Chavan } 1366aa0e25caSAshish Chavan #endif 136798615454SKuninori Morimoto return ret; 136898615454SKuninori Morimoto } 136998615454SKuninori Morimoto module_init(da7210_modinit); 137098615454SKuninori Morimoto 137198615454SKuninori Morimoto static void __exit da7210_exit(void) 137298615454SKuninori Morimoto { 137325c1a63fSFabio Estevam #if IS_ENABLED(CONFIG_I2C) 137498615454SKuninori Morimoto i2c_del_driver(&da7210_i2c_driver); 137598615454SKuninori Morimoto #endif 1376aa0e25caSAshish Chavan #if defined(CONFIG_SPI_MASTER) 1377aa0e25caSAshish Chavan spi_unregister_driver(&da7210_spi_driver); 1378aa0e25caSAshish Chavan #endif 137998615454SKuninori Morimoto } 138098615454SKuninori Morimoto module_exit(da7210_exit); 138198615454SKuninori Morimoto 138298615454SKuninori Morimoto MODULE_DESCRIPTION("ASoC DA7210 driver"); 138398615454SKuninori Morimoto MODULE_AUTHOR("David Chen, Kuninori Morimoto"); 138498615454SKuninori Morimoto MODULE_LICENSE("GPL"); 1385