1*3fd6e7d9SKevin Cernekee /* 2*3fd6e7d9SKevin Cernekee * TAS571x amplifier audio driver 3*3fd6e7d9SKevin Cernekee * 4*3fd6e7d9SKevin Cernekee * Copyright (C) 2015 Google, Inc. 5*3fd6e7d9SKevin Cernekee * Copyright (c) 2013 Daniel Mack <zonque@gmail.com> 6*3fd6e7d9SKevin Cernekee * 7*3fd6e7d9SKevin Cernekee * This program is free software; you can redistribute it and/or modify 8*3fd6e7d9SKevin Cernekee * it under the terms of the GNU General Public License as published by 9*3fd6e7d9SKevin Cernekee * the Free Software Foundation; either version 2 of the License, or 10*3fd6e7d9SKevin Cernekee * (at your option) any later version. 11*3fd6e7d9SKevin Cernekee */ 12*3fd6e7d9SKevin Cernekee 13*3fd6e7d9SKevin Cernekee #include <linux/clk.h> 14*3fd6e7d9SKevin Cernekee #include <linux/delay.h> 15*3fd6e7d9SKevin Cernekee #include <linux/device.h> 16*3fd6e7d9SKevin Cernekee #include <linux/gpio/consumer.h> 17*3fd6e7d9SKevin Cernekee #include <linux/i2c.h> 18*3fd6e7d9SKevin Cernekee #include <linux/init.h> 19*3fd6e7d9SKevin Cernekee #include <linux/kernel.h> 20*3fd6e7d9SKevin Cernekee #include <linux/module.h> 21*3fd6e7d9SKevin Cernekee #include <linux/of_device.h> 22*3fd6e7d9SKevin Cernekee #include <linux/regmap.h> 23*3fd6e7d9SKevin Cernekee #include <linux/regulator/consumer.h> 24*3fd6e7d9SKevin Cernekee #include <linux/stddef.h> 25*3fd6e7d9SKevin Cernekee #include <sound/pcm_params.h> 26*3fd6e7d9SKevin Cernekee #include <sound/soc.h> 27*3fd6e7d9SKevin Cernekee #include <sound/tlv.h> 28*3fd6e7d9SKevin Cernekee 29*3fd6e7d9SKevin Cernekee #include "tas571x.h" 30*3fd6e7d9SKevin Cernekee 31*3fd6e7d9SKevin Cernekee #define TAS571X_MAX_SUPPLIES 6 32*3fd6e7d9SKevin Cernekee 33*3fd6e7d9SKevin Cernekee struct tas571x_chip { 34*3fd6e7d9SKevin Cernekee const char *const *supply_names; 35*3fd6e7d9SKevin Cernekee int num_supply_names; 36*3fd6e7d9SKevin Cernekee const struct snd_kcontrol_new *controls; 37*3fd6e7d9SKevin Cernekee int num_controls; 38*3fd6e7d9SKevin Cernekee const struct regmap_config *regmap_config; 39*3fd6e7d9SKevin Cernekee int vol_reg_size; 40*3fd6e7d9SKevin Cernekee }; 41*3fd6e7d9SKevin Cernekee 42*3fd6e7d9SKevin Cernekee struct tas571x_private { 43*3fd6e7d9SKevin Cernekee const struct tas571x_chip *chip; 44*3fd6e7d9SKevin Cernekee struct regmap *regmap; 45*3fd6e7d9SKevin Cernekee struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; 46*3fd6e7d9SKevin Cernekee struct clk *mclk; 47*3fd6e7d9SKevin Cernekee unsigned int format; 48*3fd6e7d9SKevin Cernekee struct gpio_desc *reset_gpio; 49*3fd6e7d9SKevin Cernekee struct gpio_desc *pdn_gpio; 50*3fd6e7d9SKevin Cernekee struct snd_soc_codec_driver codec_driver; 51*3fd6e7d9SKevin Cernekee }; 52*3fd6e7d9SKevin Cernekee 53*3fd6e7d9SKevin Cernekee static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) 54*3fd6e7d9SKevin Cernekee { 55*3fd6e7d9SKevin Cernekee switch (reg) { 56*3fd6e7d9SKevin Cernekee case TAS571X_MVOL_REG: 57*3fd6e7d9SKevin Cernekee case TAS571X_CH1_VOL_REG: 58*3fd6e7d9SKevin Cernekee case TAS571X_CH2_VOL_REG: 59*3fd6e7d9SKevin Cernekee return priv->chip->vol_reg_size; 60*3fd6e7d9SKevin Cernekee default: 61*3fd6e7d9SKevin Cernekee return 1; 62*3fd6e7d9SKevin Cernekee } 63*3fd6e7d9SKevin Cernekee } 64*3fd6e7d9SKevin Cernekee 65*3fd6e7d9SKevin Cernekee static int tas571x_reg_write(void *context, unsigned int reg, 66*3fd6e7d9SKevin Cernekee unsigned int value) 67*3fd6e7d9SKevin Cernekee { 68*3fd6e7d9SKevin Cernekee struct i2c_client *client = context; 69*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = i2c_get_clientdata(client); 70*3fd6e7d9SKevin Cernekee unsigned int i, size; 71*3fd6e7d9SKevin Cernekee uint8_t buf[5]; 72*3fd6e7d9SKevin Cernekee int ret; 73*3fd6e7d9SKevin Cernekee 74*3fd6e7d9SKevin Cernekee size = tas571x_register_size(priv, reg); 75*3fd6e7d9SKevin Cernekee buf[0] = reg; 76*3fd6e7d9SKevin Cernekee 77*3fd6e7d9SKevin Cernekee for (i = size; i >= 1; --i) { 78*3fd6e7d9SKevin Cernekee buf[i] = value; 79*3fd6e7d9SKevin Cernekee value >>= 8; 80*3fd6e7d9SKevin Cernekee } 81*3fd6e7d9SKevin Cernekee 82*3fd6e7d9SKevin Cernekee ret = i2c_master_send(client, buf, size + 1); 83*3fd6e7d9SKevin Cernekee if (ret == size + 1) 84*3fd6e7d9SKevin Cernekee return 0; 85*3fd6e7d9SKevin Cernekee else if (ret < 0) 86*3fd6e7d9SKevin Cernekee return ret; 87*3fd6e7d9SKevin Cernekee else 88*3fd6e7d9SKevin Cernekee return -EIO; 89*3fd6e7d9SKevin Cernekee } 90*3fd6e7d9SKevin Cernekee 91*3fd6e7d9SKevin Cernekee static int tas571x_reg_read(void *context, unsigned int reg, 92*3fd6e7d9SKevin Cernekee unsigned int *value) 93*3fd6e7d9SKevin Cernekee { 94*3fd6e7d9SKevin Cernekee struct i2c_client *client = context; 95*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = i2c_get_clientdata(client); 96*3fd6e7d9SKevin Cernekee uint8_t send_buf, recv_buf[4]; 97*3fd6e7d9SKevin Cernekee struct i2c_msg msgs[2]; 98*3fd6e7d9SKevin Cernekee unsigned int size; 99*3fd6e7d9SKevin Cernekee unsigned int i; 100*3fd6e7d9SKevin Cernekee int ret; 101*3fd6e7d9SKevin Cernekee 102*3fd6e7d9SKevin Cernekee size = tas571x_register_size(priv, reg); 103*3fd6e7d9SKevin Cernekee send_buf = reg; 104*3fd6e7d9SKevin Cernekee 105*3fd6e7d9SKevin Cernekee msgs[0].addr = client->addr; 106*3fd6e7d9SKevin Cernekee msgs[0].len = sizeof(send_buf); 107*3fd6e7d9SKevin Cernekee msgs[0].buf = &send_buf; 108*3fd6e7d9SKevin Cernekee msgs[0].flags = 0; 109*3fd6e7d9SKevin Cernekee 110*3fd6e7d9SKevin Cernekee msgs[1].addr = client->addr; 111*3fd6e7d9SKevin Cernekee msgs[1].len = size; 112*3fd6e7d9SKevin Cernekee msgs[1].buf = recv_buf; 113*3fd6e7d9SKevin Cernekee msgs[1].flags = I2C_M_RD; 114*3fd6e7d9SKevin Cernekee 115*3fd6e7d9SKevin Cernekee ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 116*3fd6e7d9SKevin Cernekee if (ret < 0) 117*3fd6e7d9SKevin Cernekee return ret; 118*3fd6e7d9SKevin Cernekee else if (ret != ARRAY_SIZE(msgs)) 119*3fd6e7d9SKevin Cernekee return -EIO; 120*3fd6e7d9SKevin Cernekee 121*3fd6e7d9SKevin Cernekee *value = 0; 122*3fd6e7d9SKevin Cernekee 123*3fd6e7d9SKevin Cernekee for (i = 0; i < size; i++) { 124*3fd6e7d9SKevin Cernekee *value <<= 8; 125*3fd6e7d9SKevin Cernekee *value |= recv_buf[i]; 126*3fd6e7d9SKevin Cernekee } 127*3fd6e7d9SKevin Cernekee 128*3fd6e7d9SKevin Cernekee return 0; 129*3fd6e7d9SKevin Cernekee } 130*3fd6e7d9SKevin Cernekee 131*3fd6e7d9SKevin Cernekee static int tas571x_set_dai_fmt(struct snd_soc_dai *dai, unsigned int format) 132*3fd6e7d9SKevin Cernekee { 133*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); 134*3fd6e7d9SKevin Cernekee 135*3fd6e7d9SKevin Cernekee priv->format = format; 136*3fd6e7d9SKevin Cernekee 137*3fd6e7d9SKevin Cernekee return 0; 138*3fd6e7d9SKevin Cernekee } 139*3fd6e7d9SKevin Cernekee 140*3fd6e7d9SKevin Cernekee static int tas571x_hw_params(struct snd_pcm_substream *substream, 141*3fd6e7d9SKevin Cernekee struct snd_pcm_hw_params *params, 142*3fd6e7d9SKevin Cernekee struct snd_soc_dai *dai) 143*3fd6e7d9SKevin Cernekee { 144*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = snd_soc_codec_get_drvdata(dai->codec); 145*3fd6e7d9SKevin Cernekee u32 val; 146*3fd6e7d9SKevin Cernekee 147*3fd6e7d9SKevin Cernekee switch (priv->format & SND_SOC_DAIFMT_FORMAT_MASK) { 148*3fd6e7d9SKevin Cernekee case SND_SOC_DAIFMT_RIGHT_J: 149*3fd6e7d9SKevin Cernekee val = 0x00; 150*3fd6e7d9SKevin Cernekee break; 151*3fd6e7d9SKevin Cernekee case SND_SOC_DAIFMT_I2S: 152*3fd6e7d9SKevin Cernekee val = 0x03; 153*3fd6e7d9SKevin Cernekee break; 154*3fd6e7d9SKevin Cernekee case SND_SOC_DAIFMT_LEFT_J: 155*3fd6e7d9SKevin Cernekee val = 0x06; 156*3fd6e7d9SKevin Cernekee break; 157*3fd6e7d9SKevin Cernekee default: 158*3fd6e7d9SKevin Cernekee return -EINVAL; 159*3fd6e7d9SKevin Cernekee } 160*3fd6e7d9SKevin Cernekee 161*3fd6e7d9SKevin Cernekee if (params_width(params) >= 24) 162*3fd6e7d9SKevin Cernekee val += 2; 163*3fd6e7d9SKevin Cernekee else if (params_width(params) >= 20) 164*3fd6e7d9SKevin Cernekee val += 1; 165*3fd6e7d9SKevin Cernekee 166*3fd6e7d9SKevin Cernekee return regmap_update_bits(priv->regmap, TAS571X_SDI_REG, 167*3fd6e7d9SKevin Cernekee TAS571X_SDI_FMT_MASK, val); 168*3fd6e7d9SKevin Cernekee } 169*3fd6e7d9SKevin Cernekee 170*3fd6e7d9SKevin Cernekee static int tas571x_set_bias_level(struct snd_soc_codec *codec, 171*3fd6e7d9SKevin Cernekee enum snd_soc_bias_level level) 172*3fd6e7d9SKevin Cernekee { 173*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = snd_soc_codec_get_drvdata(codec); 174*3fd6e7d9SKevin Cernekee int ret; 175*3fd6e7d9SKevin Cernekee 176*3fd6e7d9SKevin Cernekee switch (level) { 177*3fd6e7d9SKevin Cernekee case SND_SOC_BIAS_ON: 178*3fd6e7d9SKevin Cernekee break; 179*3fd6e7d9SKevin Cernekee case SND_SOC_BIAS_PREPARE: 180*3fd6e7d9SKevin Cernekee break; 181*3fd6e7d9SKevin Cernekee case SND_SOC_BIAS_STANDBY: 182*3fd6e7d9SKevin Cernekee if (codec->dapm.bias_level == SND_SOC_BIAS_OFF) { 183*3fd6e7d9SKevin Cernekee if (!IS_ERR(priv->mclk)) { 184*3fd6e7d9SKevin Cernekee ret = clk_prepare_enable(priv->mclk); 185*3fd6e7d9SKevin Cernekee if (ret) { 186*3fd6e7d9SKevin Cernekee dev_err(codec->dev, 187*3fd6e7d9SKevin Cernekee "Failed to enable master clock: %d\n", 188*3fd6e7d9SKevin Cernekee ret); 189*3fd6e7d9SKevin Cernekee return ret; 190*3fd6e7d9SKevin Cernekee } 191*3fd6e7d9SKevin Cernekee } 192*3fd6e7d9SKevin Cernekee 193*3fd6e7d9SKevin Cernekee gpiod_set_value(priv->pdn_gpio, 0); 194*3fd6e7d9SKevin Cernekee usleep_range(5000, 6000); 195*3fd6e7d9SKevin Cernekee 196*3fd6e7d9SKevin Cernekee regcache_cache_only(priv->regmap, false); 197*3fd6e7d9SKevin Cernekee ret = regcache_sync(priv->regmap); 198*3fd6e7d9SKevin Cernekee if (ret) 199*3fd6e7d9SKevin Cernekee return ret; 200*3fd6e7d9SKevin Cernekee } 201*3fd6e7d9SKevin Cernekee break; 202*3fd6e7d9SKevin Cernekee case SND_SOC_BIAS_OFF: 203*3fd6e7d9SKevin Cernekee regcache_cache_only(priv->regmap, true); 204*3fd6e7d9SKevin Cernekee gpiod_set_value(priv->pdn_gpio, 1); 205*3fd6e7d9SKevin Cernekee 206*3fd6e7d9SKevin Cernekee if (!IS_ERR(priv->mclk)) 207*3fd6e7d9SKevin Cernekee clk_disable_unprepare(priv->mclk); 208*3fd6e7d9SKevin Cernekee break; 209*3fd6e7d9SKevin Cernekee } 210*3fd6e7d9SKevin Cernekee 211*3fd6e7d9SKevin Cernekee codec->dapm.bias_level = level; 212*3fd6e7d9SKevin Cernekee return 0; 213*3fd6e7d9SKevin Cernekee } 214*3fd6e7d9SKevin Cernekee 215*3fd6e7d9SKevin Cernekee static const struct snd_soc_dai_ops tas571x_dai_ops = { 216*3fd6e7d9SKevin Cernekee .set_fmt = tas571x_set_dai_fmt, 217*3fd6e7d9SKevin Cernekee .hw_params = tas571x_hw_params, 218*3fd6e7d9SKevin Cernekee }; 219*3fd6e7d9SKevin Cernekee 220*3fd6e7d9SKevin Cernekee static const char *const tas5711_supply_names[] = { 221*3fd6e7d9SKevin Cernekee "AVDD", 222*3fd6e7d9SKevin Cernekee "DVDD", 223*3fd6e7d9SKevin Cernekee "PVDD_A", 224*3fd6e7d9SKevin Cernekee "PVDD_B", 225*3fd6e7d9SKevin Cernekee "PVDD_C", 226*3fd6e7d9SKevin Cernekee "PVDD_D", 227*3fd6e7d9SKevin Cernekee }; 228*3fd6e7d9SKevin Cernekee 229*3fd6e7d9SKevin Cernekee static const DECLARE_TLV_DB_SCALE(tas5711_volume_tlv, -10350, 50, 1); 230*3fd6e7d9SKevin Cernekee 231*3fd6e7d9SKevin Cernekee static const struct snd_kcontrol_new tas5711_controls[] = { 232*3fd6e7d9SKevin Cernekee SOC_SINGLE_TLV("Master Volume", 233*3fd6e7d9SKevin Cernekee TAS571X_MVOL_REG, 234*3fd6e7d9SKevin Cernekee 0, 0xff, 1, tas5711_volume_tlv), 235*3fd6e7d9SKevin Cernekee SOC_DOUBLE_R_TLV("Speaker Volume", 236*3fd6e7d9SKevin Cernekee TAS571X_CH1_VOL_REG, 237*3fd6e7d9SKevin Cernekee TAS571X_CH2_VOL_REG, 238*3fd6e7d9SKevin Cernekee 0, 0xff, 1, tas5711_volume_tlv), 239*3fd6e7d9SKevin Cernekee SOC_DOUBLE("Speaker Switch", 240*3fd6e7d9SKevin Cernekee TAS571X_SOFT_MUTE_REG, 241*3fd6e7d9SKevin Cernekee TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, 242*3fd6e7d9SKevin Cernekee 1, 1), 243*3fd6e7d9SKevin Cernekee }; 244*3fd6e7d9SKevin Cernekee 245*3fd6e7d9SKevin Cernekee static const struct reg_default tas5711_reg_defaults[] = { 246*3fd6e7d9SKevin Cernekee { 0x04, 0x05 }, 247*3fd6e7d9SKevin Cernekee { 0x05, 0x40 }, 248*3fd6e7d9SKevin Cernekee { 0x06, 0x00 }, 249*3fd6e7d9SKevin Cernekee { 0x07, 0xff }, 250*3fd6e7d9SKevin Cernekee { 0x08, 0x30 }, 251*3fd6e7d9SKevin Cernekee { 0x09, 0x30 }, 252*3fd6e7d9SKevin Cernekee { 0x1b, 0x82 }, 253*3fd6e7d9SKevin Cernekee }; 254*3fd6e7d9SKevin Cernekee 255*3fd6e7d9SKevin Cernekee static const struct regmap_config tas5711_regmap_config = { 256*3fd6e7d9SKevin Cernekee .reg_bits = 8, 257*3fd6e7d9SKevin Cernekee .val_bits = 32, 258*3fd6e7d9SKevin Cernekee .max_register = 0xff, 259*3fd6e7d9SKevin Cernekee .reg_read = tas571x_reg_read, 260*3fd6e7d9SKevin Cernekee .reg_write = tas571x_reg_write, 261*3fd6e7d9SKevin Cernekee .reg_defaults = tas5711_reg_defaults, 262*3fd6e7d9SKevin Cernekee .num_reg_defaults = ARRAY_SIZE(tas5711_reg_defaults), 263*3fd6e7d9SKevin Cernekee .cache_type = REGCACHE_RBTREE, 264*3fd6e7d9SKevin Cernekee }; 265*3fd6e7d9SKevin Cernekee 266*3fd6e7d9SKevin Cernekee static const struct tas571x_chip tas5711_chip = { 267*3fd6e7d9SKevin Cernekee .supply_names = tas5711_supply_names, 268*3fd6e7d9SKevin Cernekee .num_supply_names = ARRAY_SIZE(tas5711_supply_names), 269*3fd6e7d9SKevin Cernekee .controls = tas5711_controls, 270*3fd6e7d9SKevin Cernekee .num_controls = ARRAY_SIZE(tas5711_controls), 271*3fd6e7d9SKevin Cernekee .regmap_config = &tas5711_regmap_config, 272*3fd6e7d9SKevin Cernekee .vol_reg_size = 1, 273*3fd6e7d9SKevin Cernekee }; 274*3fd6e7d9SKevin Cernekee 275*3fd6e7d9SKevin Cernekee static const char *const tas5717_supply_names[] = { 276*3fd6e7d9SKevin Cernekee "AVDD", 277*3fd6e7d9SKevin Cernekee "DVDD", 278*3fd6e7d9SKevin Cernekee "HPVDD", 279*3fd6e7d9SKevin Cernekee "PVDD_AB", 280*3fd6e7d9SKevin Cernekee "PVDD_CD", 281*3fd6e7d9SKevin Cernekee }; 282*3fd6e7d9SKevin Cernekee 283*3fd6e7d9SKevin Cernekee static const DECLARE_TLV_DB_SCALE(tas5717_volume_tlv, -10375, 25, 0); 284*3fd6e7d9SKevin Cernekee 285*3fd6e7d9SKevin Cernekee static const struct snd_kcontrol_new tas5717_controls[] = { 286*3fd6e7d9SKevin Cernekee /* MVOL LSB is ignored - see comments in tas571x_i2c_probe() */ 287*3fd6e7d9SKevin Cernekee SOC_SINGLE_TLV("Master Volume", 288*3fd6e7d9SKevin Cernekee TAS571X_MVOL_REG, 1, 0x1ff, 1, 289*3fd6e7d9SKevin Cernekee tas5717_volume_tlv), 290*3fd6e7d9SKevin Cernekee SOC_DOUBLE_R_TLV("Speaker Volume", 291*3fd6e7d9SKevin Cernekee TAS571X_CH1_VOL_REG, TAS571X_CH2_VOL_REG, 292*3fd6e7d9SKevin Cernekee 1, 0x1ff, 1, tas5717_volume_tlv), 293*3fd6e7d9SKevin Cernekee SOC_DOUBLE("Speaker Switch", 294*3fd6e7d9SKevin Cernekee TAS571X_SOFT_MUTE_REG, 295*3fd6e7d9SKevin Cernekee TAS571X_SOFT_MUTE_CH1_SHIFT, TAS571X_SOFT_MUTE_CH2_SHIFT, 296*3fd6e7d9SKevin Cernekee 1, 1), 297*3fd6e7d9SKevin Cernekee }; 298*3fd6e7d9SKevin Cernekee 299*3fd6e7d9SKevin Cernekee static const struct reg_default tas5717_reg_defaults[] = { 300*3fd6e7d9SKevin Cernekee { 0x04, 0x05 }, 301*3fd6e7d9SKevin Cernekee { 0x05, 0x40 }, 302*3fd6e7d9SKevin Cernekee { 0x06, 0x00 }, 303*3fd6e7d9SKevin Cernekee { 0x07, 0x03ff }, 304*3fd6e7d9SKevin Cernekee { 0x08, 0x00c0 }, 305*3fd6e7d9SKevin Cernekee { 0x09, 0x00c0 }, 306*3fd6e7d9SKevin Cernekee { 0x1b, 0x82 }, 307*3fd6e7d9SKevin Cernekee }; 308*3fd6e7d9SKevin Cernekee 309*3fd6e7d9SKevin Cernekee static const struct regmap_config tas5717_regmap_config = { 310*3fd6e7d9SKevin Cernekee .reg_bits = 8, 311*3fd6e7d9SKevin Cernekee .val_bits = 32, 312*3fd6e7d9SKevin Cernekee .max_register = 0xff, 313*3fd6e7d9SKevin Cernekee .reg_read = tas571x_reg_read, 314*3fd6e7d9SKevin Cernekee .reg_write = tas571x_reg_write, 315*3fd6e7d9SKevin Cernekee .reg_defaults = tas5717_reg_defaults, 316*3fd6e7d9SKevin Cernekee .num_reg_defaults = ARRAY_SIZE(tas5717_reg_defaults), 317*3fd6e7d9SKevin Cernekee .cache_type = REGCACHE_RBTREE, 318*3fd6e7d9SKevin Cernekee }; 319*3fd6e7d9SKevin Cernekee 320*3fd6e7d9SKevin Cernekee /* This entry is reused for tas5719 as the software interface is identical. */ 321*3fd6e7d9SKevin Cernekee static const struct tas571x_chip tas5717_chip = { 322*3fd6e7d9SKevin Cernekee .supply_names = tas5717_supply_names, 323*3fd6e7d9SKevin Cernekee .num_supply_names = ARRAY_SIZE(tas5717_supply_names), 324*3fd6e7d9SKevin Cernekee .controls = tas5717_controls, 325*3fd6e7d9SKevin Cernekee .num_controls = ARRAY_SIZE(tas5717_controls), 326*3fd6e7d9SKevin Cernekee .regmap_config = &tas5717_regmap_config, 327*3fd6e7d9SKevin Cernekee .vol_reg_size = 2, 328*3fd6e7d9SKevin Cernekee }; 329*3fd6e7d9SKevin Cernekee 330*3fd6e7d9SKevin Cernekee static const struct snd_soc_dapm_widget tas571x_dapm_widgets[] = { 331*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_DAC("DACL", NULL, SND_SOC_NOPM, 0, 0), 332*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_DAC("DACR", NULL, SND_SOC_NOPM, 0, 0), 333*3fd6e7d9SKevin Cernekee 334*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_OUTPUT("OUT_A"), 335*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_OUTPUT("OUT_B"), 336*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_OUTPUT("OUT_C"), 337*3fd6e7d9SKevin Cernekee SND_SOC_DAPM_OUTPUT("OUT_D"), 338*3fd6e7d9SKevin Cernekee }; 339*3fd6e7d9SKevin Cernekee 340*3fd6e7d9SKevin Cernekee static const struct snd_soc_dapm_route tas571x_dapm_routes[] = { 341*3fd6e7d9SKevin Cernekee { "DACL", NULL, "Playback" }, 342*3fd6e7d9SKevin Cernekee { "DACR", NULL, "Playback" }, 343*3fd6e7d9SKevin Cernekee 344*3fd6e7d9SKevin Cernekee { "OUT_A", NULL, "DACL" }, 345*3fd6e7d9SKevin Cernekee { "OUT_B", NULL, "DACL" }, 346*3fd6e7d9SKevin Cernekee { "OUT_C", NULL, "DACR" }, 347*3fd6e7d9SKevin Cernekee { "OUT_D", NULL, "DACR" }, 348*3fd6e7d9SKevin Cernekee }; 349*3fd6e7d9SKevin Cernekee 350*3fd6e7d9SKevin Cernekee static const struct snd_soc_codec_driver tas571x_codec = { 351*3fd6e7d9SKevin Cernekee .set_bias_level = tas571x_set_bias_level, 352*3fd6e7d9SKevin Cernekee .idle_bias_off = true, 353*3fd6e7d9SKevin Cernekee 354*3fd6e7d9SKevin Cernekee .dapm_widgets = tas571x_dapm_widgets, 355*3fd6e7d9SKevin Cernekee .num_dapm_widgets = ARRAY_SIZE(tas571x_dapm_widgets), 356*3fd6e7d9SKevin Cernekee .dapm_routes = tas571x_dapm_routes, 357*3fd6e7d9SKevin Cernekee .num_dapm_routes = ARRAY_SIZE(tas571x_dapm_routes), 358*3fd6e7d9SKevin Cernekee }; 359*3fd6e7d9SKevin Cernekee 360*3fd6e7d9SKevin Cernekee static struct snd_soc_dai_driver tas571x_dai = { 361*3fd6e7d9SKevin Cernekee .name = "tas571x-hifi", 362*3fd6e7d9SKevin Cernekee .playback = { 363*3fd6e7d9SKevin Cernekee .stream_name = "Playback", 364*3fd6e7d9SKevin Cernekee .channels_min = 2, 365*3fd6e7d9SKevin Cernekee .channels_max = 2, 366*3fd6e7d9SKevin Cernekee .rates = SNDRV_PCM_RATE_8000_48000, 367*3fd6e7d9SKevin Cernekee .formats = SNDRV_PCM_FMTBIT_S32_LE | 368*3fd6e7d9SKevin Cernekee SNDRV_PCM_FMTBIT_S24_LE | 369*3fd6e7d9SKevin Cernekee SNDRV_PCM_FMTBIT_S16_LE, 370*3fd6e7d9SKevin Cernekee }, 371*3fd6e7d9SKevin Cernekee .ops = &tas571x_dai_ops, 372*3fd6e7d9SKevin Cernekee }; 373*3fd6e7d9SKevin Cernekee 374*3fd6e7d9SKevin Cernekee static const struct of_device_id tas571x_of_match[]; 375*3fd6e7d9SKevin Cernekee 376*3fd6e7d9SKevin Cernekee static int tas571x_i2c_probe(struct i2c_client *client, 377*3fd6e7d9SKevin Cernekee const struct i2c_device_id *id) 378*3fd6e7d9SKevin Cernekee { 379*3fd6e7d9SKevin Cernekee struct tas571x_private *priv; 380*3fd6e7d9SKevin Cernekee struct device *dev = &client->dev; 381*3fd6e7d9SKevin Cernekee int i, ret; 382*3fd6e7d9SKevin Cernekee 383*3fd6e7d9SKevin Cernekee priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 384*3fd6e7d9SKevin Cernekee if (!priv) 385*3fd6e7d9SKevin Cernekee return -ENOMEM; 386*3fd6e7d9SKevin Cernekee i2c_set_clientdata(client, priv); 387*3fd6e7d9SKevin Cernekee 388*3fd6e7d9SKevin Cernekee if (dev->of_node) { 389*3fd6e7d9SKevin Cernekee const struct of_device_id *of_id; 390*3fd6e7d9SKevin Cernekee 391*3fd6e7d9SKevin Cernekee of_id = of_match_device(tas571x_of_match, dev); 392*3fd6e7d9SKevin Cernekee if (of_id) 393*3fd6e7d9SKevin Cernekee priv->chip = of_id->data; 394*3fd6e7d9SKevin Cernekee } 395*3fd6e7d9SKevin Cernekee 396*3fd6e7d9SKevin Cernekee if (!priv->chip) { 397*3fd6e7d9SKevin Cernekee dev_err(dev, "Unknown device type\n"); 398*3fd6e7d9SKevin Cernekee return -EINVAL; 399*3fd6e7d9SKevin Cernekee } 400*3fd6e7d9SKevin Cernekee 401*3fd6e7d9SKevin Cernekee priv->mclk = devm_clk_get(dev, "mclk"); 402*3fd6e7d9SKevin Cernekee if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { 403*3fd6e7d9SKevin Cernekee dev_err(dev, "Failed to request mclk: %ld\n", 404*3fd6e7d9SKevin Cernekee PTR_ERR(priv->mclk)); 405*3fd6e7d9SKevin Cernekee return PTR_ERR(priv->mclk); 406*3fd6e7d9SKevin Cernekee } 407*3fd6e7d9SKevin Cernekee 408*3fd6e7d9SKevin Cernekee BUG_ON(priv->chip->num_supply_names > TAS571X_MAX_SUPPLIES); 409*3fd6e7d9SKevin Cernekee for (i = 0; i < priv->chip->num_supply_names; i++) 410*3fd6e7d9SKevin Cernekee priv->supplies[i].supply = priv->chip->supply_names[i]; 411*3fd6e7d9SKevin Cernekee 412*3fd6e7d9SKevin Cernekee ret = devm_regulator_bulk_get(dev, priv->chip->num_supply_names, 413*3fd6e7d9SKevin Cernekee priv->supplies); 414*3fd6e7d9SKevin Cernekee if (ret) { 415*3fd6e7d9SKevin Cernekee dev_err(dev, "Failed to get supplies: %d\n", ret); 416*3fd6e7d9SKevin Cernekee return ret; 417*3fd6e7d9SKevin Cernekee } 418*3fd6e7d9SKevin Cernekee ret = regulator_bulk_enable(priv->chip->num_supply_names, 419*3fd6e7d9SKevin Cernekee priv->supplies); 420*3fd6e7d9SKevin Cernekee if (ret) { 421*3fd6e7d9SKevin Cernekee dev_err(dev, "Failed to enable supplies: %d\n", ret); 422*3fd6e7d9SKevin Cernekee return ret; 423*3fd6e7d9SKevin Cernekee } 424*3fd6e7d9SKevin Cernekee 425*3fd6e7d9SKevin Cernekee priv->regmap = devm_regmap_init(dev, NULL, client, 426*3fd6e7d9SKevin Cernekee priv->chip->regmap_config); 427*3fd6e7d9SKevin Cernekee if (IS_ERR(priv->regmap)) 428*3fd6e7d9SKevin Cernekee return PTR_ERR(priv->regmap); 429*3fd6e7d9SKevin Cernekee 430*3fd6e7d9SKevin Cernekee priv->pdn_gpio = devm_gpiod_get_optional(dev, "pdn", GPIOD_OUT_LOW); 431*3fd6e7d9SKevin Cernekee if (IS_ERR(priv->pdn_gpio)) { 432*3fd6e7d9SKevin Cernekee dev_err(dev, "error requesting pdn_gpio: %ld\n", 433*3fd6e7d9SKevin Cernekee PTR_ERR(priv->pdn_gpio)); 434*3fd6e7d9SKevin Cernekee return PTR_ERR(priv->pdn_gpio); 435*3fd6e7d9SKevin Cernekee } 436*3fd6e7d9SKevin Cernekee 437*3fd6e7d9SKevin Cernekee priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", 438*3fd6e7d9SKevin Cernekee GPIOD_OUT_HIGH); 439*3fd6e7d9SKevin Cernekee if (IS_ERR(priv->reset_gpio)) { 440*3fd6e7d9SKevin Cernekee dev_err(dev, "error requesting reset_gpio: %ld\n", 441*3fd6e7d9SKevin Cernekee PTR_ERR(priv->reset_gpio)); 442*3fd6e7d9SKevin Cernekee return PTR_ERR(priv->reset_gpio); 443*3fd6e7d9SKevin Cernekee } else if (priv->reset_gpio) { 444*3fd6e7d9SKevin Cernekee /* pulse the active low reset line for ~100us */ 445*3fd6e7d9SKevin Cernekee usleep_range(100, 200); 446*3fd6e7d9SKevin Cernekee gpiod_set_value(priv->reset_gpio, 0); 447*3fd6e7d9SKevin Cernekee usleep_range(12000, 20000); 448*3fd6e7d9SKevin Cernekee } 449*3fd6e7d9SKevin Cernekee 450*3fd6e7d9SKevin Cernekee ret = regmap_write(priv->regmap, TAS571X_OSC_TRIM_REG, 0); 451*3fd6e7d9SKevin Cernekee if (ret) 452*3fd6e7d9SKevin Cernekee return ret; 453*3fd6e7d9SKevin Cernekee 454*3fd6e7d9SKevin Cernekee ret = regmap_update_bits(priv->regmap, TAS571X_SYS_CTRL_2_REG, 455*3fd6e7d9SKevin Cernekee TAS571X_SYS_CTRL_2_SDN_MASK, 0); 456*3fd6e7d9SKevin Cernekee if (ret) 457*3fd6e7d9SKevin Cernekee return ret; 458*3fd6e7d9SKevin Cernekee 459*3fd6e7d9SKevin Cernekee memcpy(&priv->codec_driver, &tas571x_codec, sizeof(priv->codec_driver)); 460*3fd6e7d9SKevin Cernekee priv->codec_driver.controls = priv->chip->controls; 461*3fd6e7d9SKevin Cernekee priv->codec_driver.num_controls = priv->chip->num_controls; 462*3fd6e7d9SKevin Cernekee 463*3fd6e7d9SKevin Cernekee if (priv->chip->vol_reg_size == 2) { 464*3fd6e7d9SKevin Cernekee /* 465*3fd6e7d9SKevin Cernekee * The master volume defaults to 0x3ff (mute), but we ignore 466*3fd6e7d9SKevin Cernekee * (zero) the LSB because the hardware step size is 0.125 dB 467*3fd6e7d9SKevin Cernekee * and TLV_DB_SCALE_ITEM has a resolution of 0.01 dB. 468*3fd6e7d9SKevin Cernekee */ 469*3fd6e7d9SKevin Cernekee ret = regmap_update_bits(priv->regmap, TAS571X_MVOL_REG, 1, 0); 470*3fd6e7d9SKevin Cernekee if (ret) 471*3fd6e7d9SKevin Cernekee return ret; 472*3fd6e7d9SKevin Cernekee } 473*3fd6e7d9SKevin Cernekee 474*3fd6e7d9SKevin Cernekee regcache_cache_only(priv->regmap, true); 475*3fd6e7d9SKevin Cernekee gpiod_set_value(priv->pdn_gpio, 1); 476*3fd6e7d9SKevin Cernekee 477*3fd6e7d9SKevin Cernekee return snd_soc_register_codec(&client->dev, &priv->codec_driver, 478*3fd6e7d9SKevin Cernekee &tas571x_dai, 1); 479*3fd6e7d9SKevin Cernekee } 480*3fd6e7d9SKevin Cernekee 481*3fd6e7d9SKevin Cernekee static int tas571x_i2c_remove(struct i2c_client *client) 482*3fd6e7d9SKevin Cernekee { 483*3fd6e7d9SKevin Cernekee struct tas571x_private *priv = i2c_get_clientdata(client); 484*3fd6e7d9SKevin Cernekee 485*3fd6e7d9SKevin Cernekee snd_soc_unregister_codec(&client->dev); 486*3fd6e7d9SKevin Cernekee regulator_bulk_disable(priv->chip->num_supply_names, priv->supplies); 487*3fd6e7d9SKevin Cernekee 488*3fd6e7d9SKevin Cernekee return 0; 489*3fd6e7d9SKevin Cernekee } 490*3fd6e7d9SKevin Cernekee 491*3fd6e7d9SKevin Cernekee static const struct of_device_id tas571x_of_match[] = { 492*3fd6e7d9SKevin Cernekee { .compatible = "ti,tas5711", .data = &tas5711_chip, }, 493*3fd6e7d9SKevin Cernekee { .compatible = "ti,tas5717", .data = &tas5717_chip, }, 494*3fd6e7d9SKevin Cernekee { .compatible = "ti,tas5719", .data = &tas5717_chip, }, 495*3fd6e7d9SKevin Cernekee { } 496*3fd6e7d9SKevin Cernekee }; 497*3fd6e7d9SKevin Cernekee MODULE_DEVICE_TABLE(of, tas571x_of_match); 498*3fd6e7d9SKevin Cernekee 499*3fd6e7d9SKevin Cernekee static const struct i2c_device_id tas571x_i2c_id[] = { 500*3fd6e7d9SKevin Cernekee { "tas5711", 0 }, 501*3fd6e7d9SKevin Cernekee { "tas5717", 0 }, 502*3fd6e7d9SKevin Cernekee { "tas5719", 0 }, 503*3fd6e7d9SKevin Cernekee { } 504*3fd6e7d9SKevin Cernekee }; 505*3fd6e7d9SKevin Cernekee MODULE_DEVICE_TABLE(i2c, tas571x_i2c_id); 506*3fd6e7d9SKevin Cernekee 507*3fd6e7d9SKevin Cernekee static struct i2c_driver tas571x_i2c_driver = { 508*3fd6e7d9SKevin Cernekee .driver = { 509*3fd6e7d9SKevin Cernekee .name = "tas571x", 510*3fd6e7d9SKevin Cernekee .of_match_table = of_match_ptr(tas571x_of_match), 511*3fd6e7d9SKevin Cernekee }, 512*3fd6e7d9SKevin Cernekee .probe = tas571x_i2c_probe, 513*3fd6e7d9SKevin Cernekee .remove = tas571x_i2c_remove, 514*3fd6e7d9SKevin Cernekee .id_table = tas571x_i2c_id, 515*3fd6e7d9SKevin Cernekee }; 516*3fd6e7d9SKevin Cernekee module_i2c_driver(tas571x_i2c_driver); 517*3fd6e7d9SKevin Cernekee 518*3fd6e7d9SKevin Cernekee MODULE_DESCRIPTION("ASoC TAS571x driver"); 519*3fd6e7d9SKevin Cernekee MODULE_AUTHOR("Kevin Cernekee <cernekee@chromium.org>"); 520*3fd6e7d9SKevin Cernekee MODULE_LICENSE("GPL"); 521