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