linux/sound/soc/uniphier/evea.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Socionext UniPhier EVEA ADC/DAC codec driver.
   4//
   5// Copyright (c) 2016-2017 Socionext Inc.
   6
   7#include <linux/clk.h>
   8#include <linux/module.h>
   9#include <linux/of.h>
  10#include <linux/regmap.h>
  11#include <linux/reset.h>
  12#include <sound/pcm.h>
  13#include <sound/soc.h>
  14
  15#define DRV_NAME        "evea"
  16#define EVEA_RATES      SNDRV_PCM_RATE_48000
  17#define EVEA_FORMATS    SNDRV_PCM_FMTBIT_S32_LE
  18
  19#define AADCPOW(n)                           (0x0078 + 0x04 * (n))
  20#define   AADCPOW_AADC_POWD                   BIT(0)
  21#define ALINSW1                              0x0088
  22#define   ALINSW1_SEL1_SHIFT                  3
  23#define AHPOUTPOW                            0x0098
  24#define   AHPOUTPOW_HP_ON                     BIT(4)
  25#define ALINEPOW                             0x009c
  26#define   ALINEPOW_LIN2_POWD                  BIT(3)
  27#define   ALINEPOW_LIN1_POWD                  BIT(4)
  28#define ALO1OUTPOW                           0x00a8
  29#define   ALO1OUTPOW_LO1_ON                   BIT(4)
  30#define ALO2OUTPOW                           0x00ac
  31#define   ALO2OUTPOW_ADAC2_MUTE               BIT(0)
  32#define   ALO2OUTPOW_LO2_ON                   BIT(4)
  33#define AANAPOW                              0x00b8
  34#define   AANAPOW_A_POWD                      BIT(4)
  35#define ADACSEQ1(n)                          (0x0144 + 0x40 * (n))
  36#define   ADACSEQ1_MMUTE                      BIT(1)
  37#define ADACSEQ2(n)                          (0x0160 + 0x40 * (n))
  38#define   ADACSEQ2_ADACIN_FIX                 BIT(0)
  39#define ADAC1ODC                             0x0200
  40#define   ADAC1ODC_HP_DIS_RES_MASK            GENMASK(2, 1)
  41#define   ADAC1ODC_HP_DIS_RES_OFF             (0x0 << 1)
  42#define   ADAC1ODC_HP_DIS_RES_ON              (0x3 << 1)
  43#define   ADAC1ODC_ADAC_RAMPCLT_MASK          GENMASK(8, 7)
  44#define   ADAC1ODC_ADAC_RAMPCLT_NORMAL        (0x0 << 7)
  45#define   ADAC1ODC_ADAC_RAMPCLT_REDUCE        (0x1 << 7)
  46
  47struct evea_priv {
  48        struct clk *clk, *clk_exiv;
  49        struct reset_control *rst, *rst_exiv, *rst_adamv;
  50        struct regmap *regmap;
  51
  52        int switch_lin;
  53        int switch_lo;
  54        int switch_hp;
  55};
  56
  57static const struct snd_soc_dapm_widget evea_widgets[] = {
  58        SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
  59        SND_SOC_DAPM_INPUT("LIN1_LP"),
  60        SND_SOC_DAPM_INPUT("LIN1_RP"),
  61        SND_SOC_DAPM_INPUT("LIN2_LP"),
  62        SND_SOC_DAPM_INPUT("LIN2_RP"),
  63        SND_SOC_DAPM_INPUT("LIN3_LP"),
  64        SND_SOC_DAPM_INPUT("LIN3_RP"),
  65
  66        SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
  67        SND_SOC_DAPM_OUTPUT("HP1_L"),
  68        SND_SOC_DAPM_OUTPUT("HP1_R"),
  69        SND_SOC_DAPM_OUTPUT("LO2_L"),
  70        SND_SOC_DAPM_OUTPUT("LO2_R"),
  71};
  72
  73static const struct snd_soc_dapm_route evea_routes[] = {
  74        { "ADC", NULL, "LIN1_LP" },
  75        { "ADC", NULL, "LIN1_RP" },
  76        { "ADC", NULL, "LIN2_LP" },
  77        { "ADC", NULL, "LIN2_RP" },
  78        { "ADC", NULL, "LIN3_LP" },
  79        { "ADC", NULL, "LIN3_RP" },
  80
  81        { "HP1_L", NULL, "DAC" },
  82        { "HP1_R", NULL, "DAC" },
  83        { "LO2_L", NULL, "DAC" },
  84        { "LO2_R", NULL, "DAC" },
  85};
  86
  87static void evea_set_power_state_on(struct evea_priv *evea)
  88{
  89        struct regmap *map = evea->regmap;
  90
  91        regmap_update_bits(map, AANAPOW, AANAPOW_A_POWD,
  92                           AANAPOW_A_POWD);
  93
  94        regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK,
  95                           ADAC1ODC_HP_DIS_RES_ON);
  96
  97        regmap_update_bits(map, ADAC1ODC, ADAC1ODC_ADAC_RAMPCLT_MASK,
  98                           ADAC1ODC_ADAC_RAMPCLT_REDUCE);
  99
 100        regmap_update_bits(map, ADACSEQ2(0), ADACSEQ2_ADACIN_FIX, 0);
 101        regmap_update_bits(map, ADACSEQ2(1), ADACSEQ2_ADACIN_FIX, 0);
 102        regmap_update_bits(map, ADACSEQ2(2), ADACSEQ2_ADACIN_FIX, 0);
 103}
 104
 105static void evea_set_power_state_off(struct evea_priv *evea)
 106{
 107        struct regmap *map = evea->regmap;
 108
 109        regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK,
 110                           ADAC1ODC_HP_DIS_RES_ON);
 111
 112        regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE,
 113                           ADACSEQ1_MMUTE);
 114        regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE,
 115                           ADACSEQ1_MMUTE);
 116        regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE,
 117                           ADACSEQ1_MMUTE);
 118
 119        regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON, 0);
 120        regmap_update_bits(map, ALO2OUTPOW, ALO2OUTPOW_LO2_ON, 0);
 121        regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON, 0);
 122}
 123
 124static int evea_update_switch_lin(struct evea_priv *evea)
 125{
 126        struct regmap *map = evea->regmap;
 127
 128        if (evea->switch_lin) {
 129                regmap_update_bits(map, ALINEPOW,
 130                                   ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD,
 131                                   ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD);
 132
 133                regmap_update_bits(map, AADCPOW(0), AADCPOW_AADC_POWD,
 134                                   AADCPOW_AADC_POWD);
 135                regmap_update_bits(map, AADCPOW(1), AADCPOW_AADC_POWD,
 136                                   AADCPOW_AADC_POWD);
 137        } else {
 138                regmap_update_bits(map, AADCPOW(0), AADCPOW_AADC_POWD, 0);
 139                regmap_update_bits(map, AADCPOW(1), AADCPOW_AADC_POWD, 0);
 140
 141                regmap_update_bits(map, ALINEPOW,
 142                                   ALINEPOW_LIN2_POWD | ALINEPOW_LIN1_POWD, 0);
 143        }
 144
 145        return 0;
 146}
 147
 148static int evea_update_switch_lo(struct evea_priv *evea)
 149{
 150        struct regmap *map = evea->regmap;
 151
 152        if (evea->switch_lo) {
 153                regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE, 0);
 154                regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE, 0);
 155
 156                regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON,
 157                                   ALO1OUTPOW_LO1_ON);
 158                regmap_update_bits(map, ALO2OUTPOW,
 159                                   ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON,
 160                                   ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON);
 161        } else {
 162                regmap_update_bits(map, ADACSEQ1(0), ADACSEQ1_MMUTE,
 163                                   ADACSEQ1_MMUTE);
 164                regmap_update_bits(map, ADACSEQ1(2), ADACSEQ1_MMUTE,
 165                                   ADACSEQ1_MMUTE);
 166
 167                regmap_update_bits(map, ALO1OUTPOW, ALO1OUTPOW_LO1_ON, 0);
 168                regmap_update_bits(map, ALO2OUTPOW,
 169                                   ALO2OUTPOW_ADAC2_MUTE | ALO2OUTPOW_LO2_ON,
 170                                   0);
 171        }
 172
 173        return 0;
 174}
 175
 176static int evea_update_switch_hp(struct evea_priv *evea)
 177{
 178        struct regmap *map = evea->regmap;
 179
 180        if (evea->switch_hp) {
 181                regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE, 0);
 182
 183                regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON,
 184                                   AHPOUTPOW_HP_ON);
 185
 186                regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK,
 187                                   ADAC1ODC_HP_DIS_RES_OFF);
 188        } else {
 189                regmap_update_bits(map, ADAC1ODC, ADAC1ODC_HP_DIS_RES_MASK,
 190                                   ADAC1ODC_HP_DIS_RES_ON);
 191
 192                regmap_update_bits(map, ADACSEQ1(1), ADACSEQ1_MMUTE,
 193                                   ADACSEQ1_MMUTE);
 194
 195                regmap_update_bits(map, AHPOUTPOW, AHPOUTPOW_HP_ON, 0);
 196        }
 197
 198        return 0;
 199}
 200
 201static void evea_update_switch_all(struct evea_priv *evea)
 202{
 203        evea_update_switch_lin(evea);
 204        evea_update_switch_lo(evea);
 205        evea_update_switch_hp(evea);
 206}
 207
 208static int evea_get_switch_lin(struct snd_kcontrol *kcontrol,
 209                               struct snd_ctl_elem_value *ucontrol)
 210{
 211        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 212        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 213
 214        ucontrol->value.integer.value[0] = evea->switch_lin;
 215
 216        return 0;
 217}
 218
 219static int evea_set_switch_lin(struct snd_kcontrol *kcontrol,
 220                               struct snd_ctl_elem_value *ucontrol)
 221{
 222        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 223        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 224
 225        if (evea->switch_lin == ucontrol->value.integer.value[0])
 226                return 0;
 227
 228        evea->switch_lin = ucontrol->value.integer.value[0];
 229
 230        return evea_update_switch_lin(evea);
 231}
 232
 233static int evea_get_switch_lo(struct snd_kcontrol *kcontrol,
 234                              struct snd_ctl_elem_value *ucontrol)
 235{
 236        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 237        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 238
 239        ucontrol->value.integer.value[0] = evea->switch_lo;
 240
 241        return 0;
 242}
 243
 244static int evea_set_switch_lo(struct snd_kcontrol *kcontrol,
 245                              struct snd_ctl_elem_value *ucontrol)
 246{
 247        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 248        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 249
 250        if (evea->switch_lo == ucontrol->value.integer.value[0])
 251                return 0;
 252
 253        evea->switch_lo = ucontrol->value.integer.value[0];
 254
 255        return evea_update_switch_lo(evea);
 256}
 257
 258static int evea_get_switch_hp(struct snd_kcontrol *kcontrol,
 259                              struct snd_ctl_elem_value *ucontrol)
 260{
 261        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 262        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 263
 264        ucontrol->value.integer.value[0] = evea->switch_hp;
 265
 266        return 0;
 267}
 268
 269static int evea_set_switch_hp(struct snd_kcontrol *kcontrol,
 270                              struct snd_ctl_elem_value *ucontrol)
 271{
 272        struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
 273        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 274
 275        if (evea->switch_hp == ucontrol->value.integer.value[0])
 276                return 0;
 277
 278        evea->switch_hp = ucontrol->value.integer.value[0];
 279
 280        return evea_update_switch_hp(evea);
 281}
 282
 283static const char * const linsw1_sel1_text[] = {
 284        "LIN1", "LIN2", "LIN3"
 285};
 286
 287static SOC_ENUM_SINGLE_DECL(linsw1_sel1_enum,
 288        ALINSW1, ALINSW1_SEL1_SHIFT,
 289        linsw1_sel1_text);
 290
 291static const struct snd_kcontrol_new evea_controls[] = {
 292        SOC_ENUM("Line Capture Source", linsw1_sel1_enum),
 293        SOC_SINGLE_BOOL_EXT("Line Capture Switch", 0,
 294                            evea_get_switch_lin, evea_set_switch_lin),
 295        SOC_SINGLE_BOOL_EXT("Line Playback Switch", 0,
 296                            evea_get_switch_lo, evea_set_switch_lo),
 297        SOC_SINGLE_BOOL_EXT("Headphone Playback Switch", 0,
 298                            evea_get_switch_hp, evea_set_switch_hp),
 299};
 300
 301static int evea_codec_probe(struct snd_soc_component *component)
 302{
 303        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 304
 305        evea->switch_lin = 1;
 306        evea->switch_lo = 1;
 307        evea->switch_hp = 1;
 308
 309        evea_set_power_state_on(evea);
 310        evea_update_switch_all(evea);
 311
 312        return 0;
 313}
 314
 315static int evea_codec_suspend(struct snd_soc_component *component)
 316{
 317        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 318
 319        evea_set_power_state_off(evea);
 320
 321        reset_control_assert(evea->rst_adamv);
 322        reset_control_assert(evea->rst_exiv);
 323        reset_control_assert(evea->rst);
 324
 325        clk_disable_unprepare(evea->clk_exiv);
 326        clk_disable_unprepare(evea->clk);
 327
 328        return 0;
 329}
 330
 331static int evea_codec_resume(struct snd_soc_component *component)
 332{
 333        struct evea_priv *evea = snd_soc_component_get_drvdata(component);
 334        int ret;
 335
 336        ret = clk_prepare_enable(evea->clk);
 337        if (ret)
 338                return ret;
 339
 340        ret = clk_prepare_enable(evea->clk_exiv);
 341        if (ret)
 342                goto err_out_clock;
 343
 344        ret = reset_control_deassert(evea->rst);
 345        if (ret)
 346                goto err_out_clock_exiv;
 347
 348        ret = reset_control_deassert(evea->rst_exiv);
 349        if (ret)
 350                goto err_out_reset;
 351
 352        ret = reset_control_deassert(evea->rst_adamv);
 353        if (ret)
 354                goto err_out_reset_exiv;
 355
 356        evea_set_power_state_on(evea);
 357        evea_update_switch_all(evea);
 358
 359        return 0;
 360
 361err_out_reset_exiv:
 362        reset_control_assert(evea->rst_exiv);
 363
 364err_out_reset:
 365        reset_control_assert(evea->rst);
 366
 367err_out_clock_exiv:
 368        clk_disable_unprepare(evea->clk_exiv);
 369
 370err_out_clock:
 371        clk_disable_unprepare(evea->clk);
 372
 373        return ret;
 374}
 375
 376static struct snd_soc_component_driver soc_codec_evea = {
 377        .probe                  = evea_codec_probe,
 378        .suspend                = evea_codec_suspend,
 379        .resume                 = evea_codec_resume,
 380        .dapm_widgets           = evea_widgets,
 381        .num_dapm_widgets       = ARRAY_SIZE(evea_widgets),
 382        .dapm_routes            = evea_routes,
 383        .num_dapm_routes        = ARRAY_SIZE(evea_routes),
 384        .controls               = evea_controls,
 385        .num_controls           = ARRAY_SIZE(evea_controls),
 386        .idle_bias_on           = 1,
 387        .use_pmdown_time        = 1,
 388        .endianness             = 1,
 389        .non_legacy_dai_naming  = 1,
 390};
 391
 392static struct snd_soc_dai_driver soc_dai_evea[] = {
 393        {
 394                .name     = DRV_NAME "-line1",
 395                .playback = {
 396                        .stream_name  = "Line Out 1",
 397                        .formats      = EVEA_FORMATS,
 398                        .rates        = EVEA_RATES,
 399                        .channels_min = 2,
 400                        .channels_max = 2,
 401                },
 402                .capture = {
 403                        .stream_name  = "Line In 1",
 404                        .formats      = EVEA_FORMATS,
 405                        .rates        = EVEA_RATES,
 406                        .channels_min = 2,
 407                        .channels_max = 2,
 408                },
 409        },
 410        {
 411                .name     = DRV_NAME "-hp1",
 412                .playback = {
 413                        .stream_name  = "Headphone 1",
 414                        .formats      = EVEA_FORMATS,
 415                        .rates        = EVEA_RATES,
 416                        .channels_min = 2,
 417                        .channels_max = 2,
 418                },
 419        },
 420        {
 421                .name     = DRV_NAME "-lo2",
 422                .playback = {
 423                        .stream_name  = "Line Out 2",
 424                        .formats      = EVEA_FORMATS,
 425                        .rates        = EVEA_RATES,
 426                        .channels_min = 2,
 427                        .channels_max = 2,
 428                },
 429        },
 430};
 431
 432static const struct regmap_config evea_regmap_config = {
 433        .reg_bits      = 32,
 434        .reg_stride    = 4,
 435        .val_bits      = 32,
 436        .max_register  = 0xffc,
 437        .cache_type    = REGCACHE_NONE,
 438};
 439
 440static int evea_probe(struct platform_device *pdev)
 441{
 442        struct evea_priv *evea;
 443        struct resource *res;
 444        void __iomem *preg;
 445        int ret;
 446
 447        evea = devm_kzalloc(&pdev->dev, sizeof(struct evea_priv), GFP_KERNEL);
 448        if (!evea)
 449                return -ENOMEM;
 450
 451        evea->clk = devm_clk_get(&pdev->dev, "evea");
 452        if (IS_ERR(evea->clk))
 453                return PTR_ERR(evea->clk);
 454
 455        evea->clk_exiv = devm_clk_get(&pdev->dev, "exiv");
 456        if (IS_ERR(evea->clk_exiv))
 457                return PTR_ERR(evea->clk_exiv);
 458
 459        evea->rst = devm_reset_control_get_shared(&pdev->dev, "evea");
 460        if (IS_ERR(evea->rst))
 461                return PTR_ERR(evea->rst);
 462
 463        evea->rst_exiv = devm_reset_control_get_shared(&pdev->dev, "exiv");
 464        if (IS_ERR(evea->rst_exiv))
 465                return PTR_ERR(evea->rst_exiv);
 466
 467        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 468        preg = devm_ioremap_resource(&pdev->dev, res);
 469        if (IS_ERR(preg))
 470                return PTR_ERR(preg);
 471
 472        evea->regmap = devm_regmap_init_mmio(&pdev->dev, preg,
 473                                             &evea_regmap_config);
 474        if (IS_ERR(evea->regmap))
 475                return PTR_ERR(evea->regmap);
 476
 477        ret = clk_prepare_enable(evea->clk);
 478        if (ret)
 479                return ret;
 480
 481        ret = clk_prepare_enable(evea->clk_exiv);
 482        if (ret)
 483                goto err_out_clock;
 484
 485        ret = reset_control_deassert(evea->rst);
 486        if (ret)
 487                goto err_out_clock_exiv;
 488
 489        ret = reset_control_deassert(evea->rst_exiv);
 490        if (ret)
 491                goto err_out_reset;
 492
 493        /* ADAMV will hangup if EXIV reset is asserted */
 494        evea->rst_adamv = devm_reset_control_get_shared(&pdev->dev, "adamv");
 495        if (IS_ERR(evea->rst_adamv)) {
 496                ret = PTR_ERR(evea->rst_adamv);
 497                goto err_out_reset_exiv;
 498        }
 499
 500        ret = reset_control_deassert(evea->rst_adamv);
 501        if (ret)
 502                goto err_out_reset_exiv;
 503
 504        platform_set_drvdata(pdev, evea);
 505
 506        ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_evea,
 507                                     soc_dai_evea, ARRAY_SIZE(soc_dai_evea));
 508        if (ret)
 509                goto err_out_reset_adamv;
 510
 511        return 0;
 512
 513err_out_reset_adamv:
 514        reset_control_assert(evea->rst_adamv);
 515
 516err_out_reset_exiv:
 517        reset_control_assert(evea->rst_exiv);
 518
 519err_out_reset:
 520        reset_control_assert(evea->rst);
 521
 522err_out_clock_exiv:
 523        clk_disable_unprepare(evea->clk_exiv);
 524
 525err_out_clock:
 526        clk_disable_unprepare(evea->clk);
 527
 528        return ret;
 529}
 530
 531static int evea_remove(struct platform_device *pdev)
 532{
 533        struct evea_priv *evea = platform_get_drvdata(pdev);
 534
 535        reset_control_assert(evea->rst_adamv);
 536        reset_control_assert(evea->rst_exiv);
 537        reset_control_assert(evea->rst);
 538
 539        clk_disable_unprepare(evea->clk_exiv);
 540        clk_disable_unprepare(evea->clk);
 541
 542        return 0;
 543}
 544
 545static const struct of_device_id evea_of_match[] = {
 546        { .compatible = "socionext,uniphier-evea", },
 547        {}
 548};
 549MODULE_DEVICE_TABLE(of, evea_of_match);
 550
 551static struct platform_driver evea_codec_driver = {
 552        .driver = {
 553                .name = DRV_NAME,
 554                .of_match_table = of_match_ptr(evea_of_match),
 555        },
 556        .probe  = evea_probe,
 557        .remove = evea_remove,
 558};
 559module_platform_driver(evea_codec_driver);
 560
 561MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
 562MODULE_DESCRIPTION("UniPhier EVEA codec driver");
 563MODULE_LICENSE("GPL v2");
 564