1*5df7f71dSDan Murphy /* 2*5df7f71dSDan Murphy * tas2552.c - ALSA SoC Texas Instruments TAS2552 Mono Audio Amplifier 3*5df7f71dSDan Murphy * 4*5df7f71dSDan Murphy * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com 5*5df7f71dSDan Murphy * 6*5df7f71dSDan Murphy * Author: Dan Murphy <dmurphy@ti.com> 7*5df7f71dSDan Murphy * 8*5df7f71dSDan Murphy * This program is free software; you can redistribute it and/or 9*5df7f71dSDan Murphy * modify it under the terms of the GNU General Public License 10*5df7f71dSDan Murphy * version 2 as published by the Free Software Foundation. 11*5df7f71dSDan Murphy * 12*5df7f71dSDan Murphy * This program is distributed in the hope that it will be useful, but 13*5df7f71dSDan Murphy * WITHOUT ANY WARRANTY; without even the implied warranty of 14*5df7f71dSDan Murphy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15*5df7f71dSDan Murphy * General Public License for more details. 16*5df7f71dSDan Murphy */ 17*5df7f71dSDan Murphy 18*5df7f71dSDan Murphy #include <linux/module.h> 19*5df7f71dSDan Murphy #include <linux/errno.h> 20*5df7f71dSDan Murphy #include <linux/device.h> 21*5df7f71dSDan Murphy #include <linux/i2c.h> 22*5df7f71dSDan Murphy #include <linux/gpio.h> 23*5df7f71dSDan Murphy #include <linux/of_gpio.h> 24*5df7f71dSDan Murphy #include <linux/pm_runtime.h> 25*5df7f71dSDan Murphy #include <linux/regmap.h> 26*5df7f71dSDan Murphy #include <linux/slab.h> 27*5df7f71dSDan Murphy 28*5df7f71dSDan Murphy #include <linux/gpio/consumer.h> 29*5df7f71dSDan Murphy #include <linux/regulator/consumer.h> 30*5df7f71dSDan Murphy 31*5df7f71dSDan Murphy #include <sound/pcm.h> 32*5df7f71dSDan Murphy #include <sound/pcm_params.h> 33*5df7f71dSDan Murphy #include <sound/soc.h> 34*5df7f71dSDan Murphy #include <sound/soc-dapm.h> 35*5df7f71dSDan Murphy #include <sound/tlv.h> 36*5df7f71dSDan Murphy #include <sound/tas2552-plat.h> 37*5df7f71dSDan Murphy 38*5df7f71dSDan Murphy #include "tas2552.h" 39*5df7f71dSDan Murphy 40*5df7f71dSDan Murphy static struct reg_default tas2552_reg_defs[] = { 41*5df7f71dSDan Murphy {TAS2552_CFG_1, 0x22}, 42*5df7f71dSDan Murphy {TAS2552_CFG_3, 0x80}, 43*5df7f71dSDan Murphy {TAS2552_DOUT, 0x00}, 44*5df7f71dSDan Murphy {TAS2552_OUTPUT_DATA, 0xc0}, 45*5df7f71dSDan Murphy {TAS2552_PDM_CFG, 0x01}, 46*5df7f71dSDan Murphy {TAS2552_PGA_GAIN, 0x00}, 47*5df7f71dSDan Murphy {TAS2552_BOOST_PT_CTRL, 0x0f}, 48*5df7f71dSDan Murphy {TAS2552_RESERVED_0D, 0x00}, 49*5df7f71dSDan Murphy {TAS2552_LIMIT_RATE_HYS, 0x08}, 50*5df7f71dSDan Murphy {TAS2552_CFG_2, 0xef}, 51*5df7f71dSDan Murphy {TAS2552_SER_CTRL_1, 0x00}, 52*5df7f71dSDan Murphy {TAS2552_SER_CTRL_2, 0x00}, 53*5df7f71dSDan Murphy {TAS2552_PLL_CTRL_1, 0x10}, 54*5df7f71dSDan Murphy {TAS2552_PLL_CTRL_2, 0x00}, 55*5df7f71dSDan Murphy {TAS2552_PLL_CTRL_3, 0x00}, 56*5df7f71dSDan Murphy {TAS2552_BTIP, 0x8f}, 57*5df7f71dSDan Murphy {TAS2552_BTS_CTRL, 0x80}, 58*5df7f71dSDan Murphy {TAS2552_LIMIT_RELEASE, 0x04}, 59*5df7f71dSDan Murphy {TAS2552_LIMIT_INT_COUNT, 0x00}, 60*5df7f71dSDan Murphy {TAS2552_EDGE_RATE_CTRL, 0x40}, 61*5df7f71dSDan Murphy {TAS2552_VBAT_DATA, 0x00}, 62*5df7f71dSDan Murphy }; 63*5df7f71dSDan Murphy 64*5df7f71dSDan Murphy #define TAS2552_NUM_SUPPLIES 3 65*5df7f71dSDan Murphy static const char *tas2552_supply_names[TAS2552_NUM_SUPPLIES] = { 66*5df7f71dSDan Murphy "vbat", /* vbat voltage */ 67*5df7f71dSDan Murphy "iovdd", /* I/O Voltage */ 68*5df7f71dSDan Murphy "avdd", /* Analog DAC Voltage */ 69*5df7f71dSDan Murphy }; 70*5df7f71dSDan Murphy 71*5df7f71dSDan Murphy struct tas2552_data { 72*5df7f71dSDan Murphy struct snd_soc_codec *codec; 73*5df7f71dSDan Murphy struct regmap *regmap; 74*5df7f71dSDan Murphy struct i2c_client *tas2552_client; 75*5df7f71dSDan Murphy struct regulator_bulk_data supplies[TAS2552_NUM_SUPPLIES]; 76*5df7f71dSDan Murphy struct gpio_desc *enable_gpio; 77*5df7f71dSDan Murphy unsigned char regs[TAS2552_VBAT_DATA]; 78*5df7f71dSDan Murphy unsigned int mclk; 79*5df7f71dSDan Murphy }; 80*5df7f71dSDan Murphy 81*5df7f71dSDan Murphy static void tas2552_sw_shutdown(struct tas2552_data *tas_data, int sw_shutdown) 82*5df7f71dSDan Murphy { 83*5df7f71dSDan Murphy u8 cfg1_reg; 84*5df7f71dSDan Murphy 85*5df7f71dSDan Murphy if (sw_shutdown) 86*5df7f71dSDan Murphy cfg1_reg = 0; 87*5df7f71dSDan Murphy else 88*5df7f71dSDan Murphy cfg1_reg = TAS2552_SWS_MASK; 89*5df7f71dSDan Murphy 90*5df7f71dSDan Murphy snd_soc_update_bits(tas_data->codec, TAS2552_CFG_1, 91*5df7f71dSDan Murphy TAS2552_SWS_MASK, cfg1_reg); 92*5df7f71dSDan Murphy } 93*5df7f71dSDan Murphy 94*5df7f71dSDan Murphy static int tas2552_hw_params(struct snd_pcm_substream *substream, 95*5df7f71dSDan Murphy struct snd_pcm_hw_params *params, 96*5df7f71dSDan Murphy struct snd_soc_dai *dai) 97*5df7f71dSDan Murphy { 98*5df7f71dSDan Murphy struct snd_soc_codec *codec = dai->codec; 99*5df7f71dSDan Murphy struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); 100*5df7f71dSDan Murphy int sample_rate, pll_clk; 101*5df7f71dSDan Murphy int d; 102*5df7f71dSDan Murphy u8 p, j; 103*5df7f71dSDan Murphy 104*5df7f71dSDan Murphy /* Turn on Class D amplifier */ 105*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN_MASK, 106*5df7f71dSDan Murphy TAS2552_CLASSD_EN); 107*5df7f71dSDan Murphy 108*5df7f71dSDan Murphy if (!tas2552->mclk) 109*5df7f71dSDan Murphy return -EINVAL; 110*5df7f71dSDan Murphy 111*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); 112*5df7f71dSDan Murphy 113*5df7f71dSDan Murphy if (tas2552->mclk == TAS2552_245MHZ_CLK || 114*5df7f71dSDan Murphy tas2552->mclk == TAS2552_225MHZ_CLK) { 115*5df7f71dSDan Murphy /* By pass the PLL configuration */ 116*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_PLL_CTRL_2, 117*5df7f71dSDan Murphy TAS2552_PLL_BYPASS_MASK, 118*5df7f71dSDan Murphy TAS2552_PLL_BYPASS); 119*5df7f71dSDan Murphy } else { 120*5df7f71dSDan Murphy /* Fill in the PLL control registers for J & D 121*5df7f71dSDan Murphy * PLL_CLK = (.5 * freq * J.D) / 2^p 122*5df7f71dSDan Murphy * Need to fill in J and D here based on incoming freq 123*5df7f71dSDan Murphy */ 124*5df7f71dSDan Murphy p = snd_soc_read(codec, TAS2552_PLL_CTRL_1); 125*5df7f71dSDan Murphy p = (p >> 7); 126*5df7f71dSDan Murphy sample_rate = params_rate(params); 127*5df7f71dSDan Murphy 128*5df7f71dSDan Murphy if (sample_rate == 48000) 129*5df7f71dSDan Murphy pll_clk = TAS2552_245MHZ_CLK; 130*5df7f71dSDan Murphy else if (sample_rate == 44100) 131*5df7f71dSDan Murphy pll_clk = TAS2552_225MHZ_CLK; 132*5df7f71dSDan Murphy else { 133*5df7f71dSDan Murphy dev_vdbg(codec->dev, "Substream sample rate is not found %i\n", 134*5df7f71dSDan Murphy params_rate(params)); 135*5df7f71dSDan Murphy return -EINVAL; 136*5df7f71dSDan Murphy } 137*5df7f71dSDan Murphy 138*5df7f71dSDan Murphy j = (pll_clk * 2 * (1 << p)) / tas2552->mclk; 139*5df7f71dSDan Murphy d = (pll_clk * 2 * (1 << p)) % tas2552->mclk; 140*5df7f71dSDan Murphy 141*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_PLL_CTRL_1, 142*5df7f71dSDan Murphy TAS2552_PLL_J_MASK, j); 143*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_PLL_CTRL_2, 144*5df7f71dSDan Murphy (d >> 7) & TAS2552_PLL_D_UPPER_MASK); 145*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_PLL_CTRL_3, 146*5df7f71dSDan Murphy d & TAS2552_PLL_D_LOWER_MASK); 147*5df7f71dSDan Murphy 148*5df7f71dSDan Murphy } 149*5df7f71dSDan Murphy 150*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 151*5df7f71dSDan Murphy TAS2552_PLL_ENABLE); 152*5df7f71dSDan Murphy 153*5df7f71dSDan Murphy return 0; 154*5df7f71dSDan Murphy } 155*5df7f71dSDan Murphy 156*5df7f71dSDan Murphy static int tas2552_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) 157*5df7f71dSDan Murphy { 158*5df7f71dSDan Murphy struct snd_soc_codec *codec = dai->codec; 159*5df7f71dSDan Murphy u8 serial_format; 160*5df7f71dSDan Murphy u8 serial_control_mask; 161*5df7f71dSDan Murphy 162*5df7f71dSDan Murphy switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { 163*5df7f71dSDan Murphy case SND_SOC_DAIFMT_CBS_CFS: 164*5df7f71dSDan Murphy serial_format = 0x00; 165*5df7f71dSDan Murphy break; 166*5df7f71dSDan Murphy case SND_SOC_DAIFMT_CBS_CFM: 167*5df7f71dSDan Murphy serial_format = TAS2552_WORD_CLK_MASK; 168*5df7f71dSDan Murphy break; 169*5df7f71dSDan Murphy case SND_SOC_DAIFMT_CBM_CFS: 170*5df7f71dSDan Murphy serial_format = TAS2552_BIT_CLK_MASK; 171*5df7f71dSDan Murphy break; 172*5df7f71dSDan Murphy case SND_SOC_DAIFMT_CBM_CFM: 173*5df7f71dSDan Murphy serial_format = (TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK); 174*5df7f71dSDan Murphy break; 175*5df7f71dSDan Murphy default: 176*5df7f71dSDan Murphy dev_vdbg(codec->dev, "DAI Format master is not found\n"); 177*5df7f71dSDan Murphy return -EINVAL; 178*5df7f71dSDan Murphy } 179*5df7f71dSDan Murphy 180*5df7f71dSDan Murphy serial_control_mask = TAS2552_BIT_CLK_MASK | TAS2552_WORD_CLK_MASK; 181*5df7f71dSDan Murphy 182*5df7f71dSDan Murphy switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 183*5df7f71dSDan Murphy case SND_SOC_DAIFMT_I2S: 184*5df7f71dSDan Murphy serial_format &= TAS2552_DAIFMT_I2S_MASK; 185*5df7f71dSDan Murphy break; 186*5df7f71dSDan Murphy case SND_SOC_DAIFMT_DSP_A: 187*5df7f71dSDan Murphy serial_format |= TAS2552_DAIFMT_DSP; 188*5df7f71dSDan Murphy break; 189*5df7f71dSDan Murphy case SND_SOC_DAIFMT_RIGHT_J: 190*5df7f71dSDan Murphy serial_format |= TAS2552_DAIFMT_RIGHT_J; 191*5df7f71dSDan Murphy break; 192*5df7f71dSDan Murphy case SND_SOC_DAIFMT_LEFT_J: 193*5df7f71dSDan Murphy serial_format |= TAS2552_DAIFMT_LEFT_J; 194*5df7f71dSDan Murphy break; 195*5df7f71dSDan Murphy default: 196*5df7f71dSDan Murphy dev_vdbg(codec->dev, "DAI Format is not found\n"); 197*5df7f71dSDan Murphy return -EINVAL; 198*5df7f71dSDan Murphy } 199*5df7f71dSDan Murphy 200*5df7f71dSDan Murphy if (fmt & SND_SOC_DAIFMT_FORMAT_MASK) 201*5df7f71dSDan Murphy serial_control_mask |= TAS2552_DATA_FORMAT_MASK; 202*5df7f71dSDan Murphy 203*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_SER_CTRL_1, serial_control_mask, 204*5df7f71dSDan Murphy serial_format); 205*5df7f71dSDan Murphy 206*5df7f71dSDan Murphy return 0; 207*5df7f71dSDan Murphy } 208*5df7f71dSDan Murphy 209*5df7f71dSDan Murphy static int tas2552_set_dai_sysclk(struct snd_soc_dai *dai, int clk_id, 210*5df7f71dSDan Murphy unsigned int freq, int dir) 211*5df7f71dSDan Murphy { 212*5df7f71dSDan Murphy struct snd_soc_codec *codec = dai->codec; 213*5df7f71dSDan Murphy struct tas2552_data *tas2552 = dev_get_drvdata(codec->dev); 214*5df7f71dSDan Murphy 215*5df7f71dSDan Murphy tas2552->mclk = freq; 216*5df7f71dSDan Murphy 217*5df7f71dSDan Murphy return 0; 218*5df7f71dSDan Murphy } 219*5df7f71dSDan Murphy 220*5df7f71dSDan Murphy static int tas2552_mute(struct snd_soc_dai *dai, int mute) 221*5df7f71dSDan Murphy { 222*5df7f71dSDan Murphy u8 cfg1_reg; 223*5df7f71dSDan Murphy struct snd_soc_codec *codec = dai->codec; 224*5df7f71dSDan Murphy 225*5df7f71dSDan Murphy if (mute) 226*5df7f71dSDan Murphy cfg1_reg = TAS2552_MUTE_MASK; 227*5df7f71dSDan Murphy else 228*5df7f71dSDan Murphy cfg1_reg = ~TAS2552_MUTE_MASK; 229*5df7f71dSDan Murphy 230*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK, cfg1_reg); 231*5df7f71dSDan Murphy 232*5df7f71dSDan Murphy return 0; 233*5df7f71dSDan Murphy } 234*5df7f71dSDan Murphy 235*5df7f71dSDan Murphy #ifdef CONFIG_PM_RUNTIME 236*5df7f71dSDan Murphy static int tas2552_runtime_suspend(struct device *dev) 237*5df7f71dSDan Murphy { 238*5df7f71dSDan Murphy struct tas2552_data *tas2552 = dev_get_drvdata(dev); 239*5df7f71dSDan Murphy 240*5df7f71dSDan Murphy tas2552_sw_shutdown(tas2552, 0); 241*5df7f71dSDan Murphy 242*5df7f71dSDan Murphy if (tas2552->enable_gpio) 243*5df7f71dSDan Murphy gpiod_set_value(tas2552->enable_gpio, 0); 244*5df7f71dSDan Murphy 245*5df7f71dSDan Murphy regcache_cache_only(tas2552->regmap, true); 246*5df7f71dSDan Murphy regcache_mark_dirty(tas2552->regmap); 247*5df7f71dSDan Murphy 248*5df7f71dSDan Murphy return 0; 249*5df7f71dSDan Murphy } 250*5df7f71dSDan Murphy 251*5df7f71dSDan Murphy static int tas2552_runtime_resume(struct device *dev) 252*5df7f71dSDan Murphy { 253*5df7f71dSDan Murphy struct tas2552_data *tas2552 = dev_get_drvdata(dev); 254*5df7f71dSDan Murphy 255*5df7f71dSDan Murphy if (tas2552->enable_gpio) 256*5df7f71dSDan Murphy gpiod_set_value(tas2552->enable_gpio, 1); 257*5df7f71dSDan Murphy 258*5df7f71dSDan Murphy tas2552_sw_shutdown(tas2552, 1); 259*5df7f71dSDan Murphy 260*5df7f71dSDan Murphy regcache_cache_only(tas2552->regmap, false); 261*5df7f71dSDan Murphy regcache_sync(tas2552->regmap); 262*5df7f71dSDan Murphy 263*5df7f71dSDan Murphy return 0; 264*5df7f71dSDan Murphy } 265*5df7f71dSDan Murphy #endif 266*5df7f71dSDan Murphy 267*5df7f71dSDan Murphy static const struct dev_pm_ops tas2552_pm = { 268*5df7f71dSDan Murphy SET_RUNTIME_PM_OPS(tas2552_runtime_suspend, tas2552_runtime_resume, 269*5df7f71dSDan Murphy NULL) 270*5df7f71dSDan Murphy }; 271*5df7f71dSDan Murphy 272*5df7f71dSDan Murphy static void tas2552_shutdown(struct snd_pcm_substream *substream, 273*5df7f71dSDan Murphy struct snd_soc_dai *dai) 274*5df7f71dSDan Murphy { 275*5df7f71dSDan Murphy struct snd_soc_codec *codec = dai->codec; 276*5df7f71dSDan Murphy 277*5df7f71dSDan Murphy snd_soc_update_bits(codec, TAS2552_CFG_2, TAS2552_PLL_ENABLE, 0); 278*5df7f71dSDan Murphy } 279*5df7f71dSDan Murphy 280*5df7f71dSDan Murphy static struct snd_soc_dai_ops tas2552_speaker_dai_ops = { 281*5df7f71dSDan Murphy .hw_params = tas2552_hw_params, 282*5df7f71dSDan Murphy .set_sysclk = tas2552_set_dai_sysclk, 283*5df7f71dSDan Murphy .set_fmt = tas2552_set_dai_fmt, 284*5df7f71dSDan Murphy .shutdown = tas2552_shutdown, 285*5df7f71dSDan Murphy .digital_mute = tas2552_mute, 286*5df7f71dSDan Murphy }; 287*5df7f71dSDan Murphy 288*5df7f71dSDan Murphy /* Formats supported by TAS2552 driver. */ 289*5df7f71dSDan Murphy #define TAS2552_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ 290*5df7f71dSDan Murphy SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) 291*5df7f71dSDan Murphy 292*5df7f71dSDan Murphy /* TAS2552 dai structure. */ 293*5df7f71dSDan Murphy static struct snd_soc_dai_driver tas2552_dai[] = { 294*5df7f71dSDan Murphy { 295*5df7f71dSDan Murphy .name = "tas2552-amplifier", 296*5df7f71dSDan Murphy .playback = { 297*5df7f71dSDan Murphy .stream_name = "Speaker", 298*5df7f71dSDan Murphy .channels_min = 2, 299*5df7f71dSDan Murphy .channels_max = 2, 300*5df7f71dSDan Murphy .rates = SNDRV_PCM_RATE_8000_192000, 301*5df7f71dSDan Murphy .formats = TAS2552_FORMATS, 302*5df7f71dSDan Murphy }, 303*5df7f71dSDan Murphy .ops = &tas2552_speaker_dai_ops, 304*5df7f71dSDan Murphy }, 305*5df7f71dSDan Murphy }; 306*5df7f71dSDan Murphy 307*5df7f71dSDan Murphy /* 308*5df7f71dSDan Murphy * DAC digital volumes. From -7 to 24 dB in 1 dB steps 309*5df7f71dSDan Murphy */ 310*5df7f71dSDan Murphy static DECLARE_TLV_DB_SCALE(dac_tlv, -7, 100, 24); 311*5df7f71dSDan Murphy 312*5df7f71dSDan Murphy static const struct snd_kcontrol_new tas2552_snd_controls[] = { 313*5df7f71dSDan Murphy SOC_SINGLE_TLV("Speaker Driver Playback Volume", 314*5df7f71dSDan Murphy TAS2552_PGA_GAIN, 0, 0x1f, 1, dac_tlv), 315*5df7f71dSDan Murphy }; 316*5df7f71dSDan Murphy 317*5df7f71dSDan Murphy static const struct reg_default tas2552_init_regs[] = { 318*5df7f71dSDan Murphy { TAS2552_RESERVED_0D, 0xc0 }, 319*5df7f71dSDan Murphy }; 320*5df7f71dSDan Murphy 321*5df7f71dSDan Murphy static int tas2552_codec_probe(struct snd_soc_codec *codec) 322*5df7f71dSDan Murphy { 323*5df7f71dSDan Murphy struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); 324*5df7f71dSDan Murphy int ret; 325*5df7f71dSDan Murphy 326*5df7f71dSDan Murphy tas2552->codec = codec; 327*5df7f71dSDan Murphy 328*5df7f71dSDan Murphy ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies), 329*5df7f71dSDan Murphy tas2552->supplies); 330*5df7f71dSDan Murphy 331*5df7f71dSDan Murphy if (ret != 0) { 332*5df7f71dSDan Murphy dev_err(codec->dev, "Failed to enable supplies: %d\n", 333*5df7f71dSDan Murphy ret); 334*5df7f71dSDan Murphy return ret; 335*5df7f71dSDan Murphy } 336*5df7f71dSDan Murphy 337*5df7f71dSDan Murphy if (tas2552->enable_gpio) 338*5df7f71dSDan Murphy gpiod_set_value(tas2552->enable_gpio, 1); 339*5df7f71dSDan Murphy 340*5df7f71dSDan Murphy ret = pm_runtime_get_sync(codec->dev); 341*5df7f71dSDan Murphy if (ret < 0) { 342*5df7f71dSDan Murphy dev_err(codec->dev, "Enabling device failed: %d\n", 343*5df7f71dSDan Murphy ret); 344*5df7f71dSDan Murphy goto probe_fail; 345*5df7f71dSDan Murphy } 346*5df7f71dSDan Murphy 347*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_CFG_1, TAS2552_MUTE_MASK | 348*5df7f71dSDan Murphy TAS2552_PLL_SRC_BCLK); 349*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_CFG_3, TAS2552_I2S_OUT_SEL | 350*5df7f71dSDan Murphy TAS2552_DIN_SRC_SEL_AVG_L_R | TAS2552_88_96KHZ); 351*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_DOUT, TAS2552_PDM_DATA_I); 352*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_OUTPUT_DATA, TAS2552_PDM_DATA_V_I | 0x8); 353*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_PDM_CFG, TAS2552_PDM_BCLK_SEL); 354*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_BOOST_PT_CTRL, TAS2552_APT_DELAY_200 | 355*5df7f71dSDan Murphy TAS2552_APT_THRESH_2_1_7); 356*5df7f71dSDan Murphy 357*5df7f71dSDan Murphy ret = regmap_register_patch(tas2552->regmap, tas2552_init_regs, 358*5df7f71dSDan Murphy ARRAY_SIZE(tas2552_init_regs)); 359*5df7f71dSDan Murphy if (ret != 0) { 360*5df7f71dSDan Murphy dev_err(codec->dev, "Failed to write init registers: %d\n", 361*5df7f71dSDan Murphy ret); 362*5df7f71dSDan Murphy goto patch_fail; 363*5df7f71dSDan Murphy } 364*5df7f71dSDan Murphy 365*5df7f71dSDan Murphy snd_soc_write(codec, TAS2552_CFG_2, TAS2552_CLASSD_EN | 366*5df7f71dSDan Murphy TAS2552_BOOST_EN | TAS2552_APT_EN | 367*5df7f71dSDan Murphy TAS2552_LIM_EN); 368*5df7f71dSDan Murphy return 0; 369*5df7f71dSDan Murphy 370*5df7f71dSDan Murphy patch_fail: 371*5df7f71dSDan Murphy pm_runtime_put(codec->dev); 372*5df7f71dSDan Murphy probe_fail: 373*5df7f71dSDan Murphy if (tas2552->enable_gpio) 374*5df7f71dSDan Murphy gpiod_set_value(tas2552->enable_gpio, 0); 375*5df7f71dSDan Murphy 376*5df7f71dSDan Murphy regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), 377*5df7f71dSDan Murphy tas2552->supplies); 378*5df7f71dSDan Murphy return -EIO; 379*5df7f71dSDan Murphy } 380*5df7f71dSDan Murphy 381*5df7f71dSDan Murphy static int tas2552_codec_remove(struct snd_soc_codec *codec) 382*5df7f71dSDan Murphy { 383*5df7f71dSDan Murphy struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); 384*5df7f71dSDan Murphy 385*5df7f71dSDan Murphy if (tas2552->enable_gpio) 386*5df7f71dSDan Murphy gpiod_set_value(tas2552->enable_gpio, 0); 387*5df7f71dSDan Murphy 388*5df7f71dSDan Murphy return 0; 389*5df7f71dSDan Murphy }; 390*5df7f71dSDan Murphy 391*5df7f71dSDan Murphy #ifdef CONFIG_PM 392*5df7f71dSDan Murphy static int tas2552_suspend(struct snd_soc_codec *codec) 393*5df7f71dSDan Murphy { 394*5df7f71dSDan Murphy struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); 395*5df7f71dSDan Murphy int ret; 396*5df7f71dSDan Murphy 397*5df7f71dSDan Murphy ret = regulator_bulk_disable(ARRAY_SIZE(tas2552->supplies), 398*5df7f71dSDan Murphy tas2552->supplies); 399*5df7f71dSDan Murphy 400*5df7f71dSDan Murphy if (ret != 0) 401*5df7f71dSDan Murphy dev_err(codec->dev, "Failed to disable supplies: %d\n", 402*5df7f71dSDan Murphy ret); 403*5df7f71dSDan Murphy return 0; 404*5df7f71dSDan Murphy } 405*5df7f71dSDan Murphy 406*5df7f71dSDan Murphy static int tas2552_resume(struct snd_soc_codec *codec) 407*5df7f71dSDan Murphy { 408*5df7f71dSDan Murphy struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec); 409*5df7f71dSDan Murphy int ret; 410*5df7f71dSDan Murphy 411*5df7f71dSDan Murphy ret = regulator_bulk_enable(ARRAY_SIZE(tas2552->supplies), 412*5df7f71dSDan Murphy tas2552->supplies); 413*5df7f71dSDan Murphy 414*5df7f71dSDan Murphy if (ret != 0) { 415*5df7f71dSDan Murphy dev_err(codec->dev, "Failed to enable supplies: %d\n", 416*5df7f71dSDan Murphy ret); 417*5df7f71dSDan Murphy } 418*5df7f71dSDan Murphy 419*5df7f71dSDan Murphy return 0; 420*5df7f71dSDan Murphy } 421*5df7f71dSDan Murphy #else 422*5df7f71dSDan Murphy #define tas2552_suspend NULL 423*5df7f71dSDan Murphy #define tas2552_resume NULL 424*5df7f71dSDan Murphy #endif 425*5df7f71dSDan Murphy 426*5df7f71dSDan Murphy static struct snd_soc_codec_driver soc_codec_dev_tas2552 = { 427*5df7f71dSDan Murphy .probe = tas2552_codec_probe, 428*5df7f71dSDan Murphy .remove = tas2552_codec_remove, 429*5df7f71dSDan Murphy .suspend = tas2552_suspend, 430*5df7f71dSDan Murphy .resume = tas2552_resume, 431*5df7f71dSDan Murphy .controls = tas2552_snd_controls, 432*5df7f71dSDan Murphy .num_controls = ARRAY_SIZE(tas2552_snd_controls), 433*5df7f71dSDan Murphy }; 434*5df7f71dSDan Murphy 435*5df7f71dSDan Murphy static const struct regmap_config tas2552_regmap_config = { 436*5df7f71dSDan Murphy .reg_bits = 8, 437*5df7f71dSDan Murphy .val_bits = 8, 438*5df7f71dSDan Murphy 439*5df7f71dSDan Murphy .max_register = TAS2552_MAX_REG, 440*5df7f71dSDan Murphy .reg_defaults = tas2552_reg_defs, 441*5df7f71dSDan Murphy .num_reg_defaults = ARRAY_SIZE(tas2552_reg_defs), 442*5df7f71dSDan Murphy .cache_type = REGCACHE_RBTREE, 443*5df7f71dSDan Murphy }; 444*5df7f71dSDan Murphy 445*5df7f71dSDan Murphy static int tas2552_probe(struct i2c_client *client, 446*5df7f71dSDan Murphy const struct i2c_device_id *id) 447*5df7f71dSDan Murphy { 448*5df7f71dSDan Murphy struct device *dev; 449*5df7f71dSDan Murphy struct tas2552_data *data; 450*5df7f71dSDan Murphy int ret; 451*5df7f71dSDan Murphy int i; 452*5df7f71dSDan Murphy 453*5df7f71dSDan Murphy dev = &client->dev; 454*5df7f71dSDan Murphy data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL); 455*5df7f71dSDan Murphy if (data == NULL) 456*5df7f71dSDan Murphy return -ENOMEM; 457*5df7f71dSDan Murphy 458*5df7f71dSDan Murphy data->enable_gpio = devm_gpiod_get(dev, "enable"); 459*5df7f71dSDan Murphy if (IS_ERR(data->enable_gpio)) { 460*5df7f71dSDan Murphy ret = PTR_ERR(data->enable_gpio); 461*5df7f71dSDan Murphy if (ret != -ENOENT && ret != -ENOSYS) 462*5df7f71dSDan Murphy return ret; 463*5df7f71dSDan Murphy 464*5df7f71dSDan Murphy data->enable_gpio = NULL; 465*5df7f71dSDan Murphy } else { 466*5df7f71dSDan Murphy gpiod_direction_output(data->enable_gpio, 0); 467*5df7f71dSDan Murphy } 468*5df7f71dSDan Murphy 469*5df7f71dSDan Murphy data->tas2552_client = client; 470*5df7f71dSDan Murphy data->regmap = devm_regmap_init_i2c(client, &tas2552_regmap_config); 471*5df7f71dSDan Murphy if (IS_ERR(data->regmap)) { 472*5df7f71dSDan Murphy ret = PTR_ERR(data->regmap); 473*5df7f71dSDan Murphy dev_err(&client->dev, "Failed to allocate register map: %d\n", 474*5df7f71dSDan Murphy ret); 475*5df7f71dSDan Murphy return ret; 476*5df7f71dSDan Murphy } 477*5df7f71dSDan Murphy 478*5df7f71dSDan Murphy for (i = 0; i < ARRAY_SIZE(data->supplies); i++) 479*5df7f71dSDan Murphy data->supplies[i].supply = tas2552_supply_names[i]; 480*5df7f71dSDan Murphy 481*5df7f71dSDan Murphy ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(data->supplies), 482*5df7f71dSDan Murphy data->supplies); 483*5df7f71dSDan Murphy if (ret != 0) 484*5df7f71dSDan Murphy dev_err(dev, "Failed to request supplies: %d\n", ret); 485*5df7f71dSDan Murphy 486*5df7f71dSDan Murphy pm_runtime_set_active(&client->dev); 487*5df7f71dSDan Murphy pm_runtime_set_autosuspend_delay(&client->dev, 1000); 488*5df7f71dSDan Murphy pm_runtime_use_autosuspend(&client->dev); 489*5df7f71dSDan Murphy pm_runtime_enable(&client->dev); 490*5df7f71dSDan Murphy pm_runtime_mark_last_busy(&client->dev); 491*5df7f71dSDan Murphy pm_runtime_put_sync_autosuspend(&client->dev); 492*5df7f71dSDan Murphy 493*5df7f71dSDan Murphy dev_set_drvdata(&client->dev, data); 494*5df7f71dSDan Murphy 495*5df7f71dSDan Murphy ret = snd_soc_register_codec(&client->dev, 496*5df7f71dSDan Murphy &soc_codec_dev_tas2552, 497*5df7f71dSDan Murphy tas2552_dai, ARRAY_SIZE(tas2552_dai)); 498*5df7f71dSDan Murphy if (ret < 0) 499*5df7f71dSDan Murphy dev_err(&client->dev, "Failed to register codec: %d\n", ret); 500*5df7f71dSDan Murphy 501*5df7f71dSDan Murphy return 0; 502*5df7f71dSDan Murphy } 503*5df7f71dSDan Murphy 504*5df7f71dSDan Murphy static int tas2552_i2c_remove(struct i2c_client *client) 505*5df7f71dSDan Murphy { 506*5df7f71dSDan Murphy snd_soc_unregister_codec(&client->dev); 507*5df7f71dSDan Murphy return 0; 508*5df7f71dSDan Murphy } 509*5df7f71dSDan Murphy 510*5df7f71dSDan Murphy static const struct i2c_device_id tas2552_id[] = { 511*5df7f71dSDan Murphy { "tas2552", 0 }, 512*5df7f71dSDan Murphy { } 513*5df7f71dSDan Murphy }; 514*5df7f71dSDan Murphy MODULE_DEVICE_TABLE(i2c, tas2552_id); 515*5df7f71dSDan Murphy 516*5df7f71dSDan Murphy #if IS_ENABLED(CONFIG_OF) 517*5df7f71dSDan Murphy static const struct of_device_id tas2552_of_match[] = { 518*5df7f71dSDan Murphy { .compatible = "ti,tas2552", }, 519*5df7f71dSDan Murphy {}, 520*5df7f71dSDan Murphy }; 521*5df7f71dSDan Murphy MODULE_DEVICE_TABLE(of, tas2552_of_match); 522*5df7f71dSDan Murphy #endif 523*5df7f71dSDan Murphy 524*5df7f71dSDan Murphy static struct i2c_driver tas2552_i2c_driver = { 525*5df7f71dSDan Murphy .driver = { 526*5df7f71dSDan Murphy .name = "tas2552", 527*5df7f71dSDan Murphy .owner = THIS_MODULE, 528*5df7f71dSDan Murphy .of_match_table = of_match_ptr(tas2552_of_match), 529*5df7f71dSDan Murphy .pm = &tas2552_pm, 530*5df7f71dSDan Murphy }, 531*5df7f71dSDan Murphy .probe = tas2552_probe, 532*5df7f71dSDan Murphy .remove = tas2552_i2c_remove, 533*5df7f71dSDan Murphy .id_table = tas2552_id, 534*5df7f71dSDan Murphy }; 535*5df7f71dSDan Murphy 536*5df7f71dSDan Murphy module_i2c_driver(tas2552_i2c_driver); 537*5df7f71dSDan Murphy 538*5df7f71dSDan Murphy MODULE_AUTHOR("Dan Muprhy <dmurphy@ti.com>"); 539*5df7f71dSDan Murphy MODULE_DESCRIPTION("TAS2552 Audio amplifier driver"); 540*5df7f71dSDan Murphy MODULE_LICENSE("GPL"); 541