linux/sound/soc/codecs/jz4770.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// Ingenic JZ4770 CODEC driver
   4//
   5// Copyright (C) 2012, Maarten ter Huurne <maarten@treewalker.org>
   6// Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
   7
   8#include <linux/clk.h>
   9#include <linux/delay.h>
  10#include <linux/iopoll.h>
  11#include <linux/module.h>
  12#include <linux/regmap.h>
  13#include <linux/time64.h>
  14
  15#include <sound/pcm_params.h>
  16#include <sound/soc.h>
  17#include <sound/soc-dai.h>
  18#include <sound/soc-dapm.h>
  19#include <sound/tlv.h>
  20
  21#define ICDC_RGADW_OFFSET               0x00
  22#define ICDC_RGDATA_OFFSET              0x04
  23
  24/* ICDC internal register access control register(RGADW) */
  25#define ICDC_RGADW_RGWR                 BIT(16)
  26
  27#define ICDC_RGADW_RGADDR_OFFSET        8
  28#define ICDC_RGADW_RGADDR_MASK          GENMASK(14, ICDC_RGADW_RGADDR_OFFSET)
  29
  30#define ICDC_RGADW_RGDIN_OFFSET         0
  31#define ICDC_RGADW_RGDIN_MASK           GENMASK(7, ICDC_RGADW_RGDIN_OFFSET)
  32
  33/* ICDC internal register data output register (RGDATA)*/
  34#define ICDC_RGDATA_IRQ                 BIT(8)
  35
  36#define ICDC_RGDATA_RGDOUT_OFFSET       0
  37#define ICDC_RGDATA_RGDOUT_MASK         GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET)
  38
  39/* Internal register space, accessed through regmap */
  40enum {
  41        JZ4770_CODEC_REG_SR,
  42        JZ4770_CODEC_REG_AICR_DAC,
  43        JZ4770_CODEC_REG_AICR_ADC,
  44        JZ4770_CODEC_REG_CR_LO,
  45        JZ4770_CODEC_REG_CR_HP,
  46
  47        JZ4770_CODEC_REG_MISSING_REG1,
  48
  49        JZ4770_CODEC_REG_CR_DAC,
  50        JZ4770_CODEC_REG_CR_MIC,
  51        JZ4770_CODEC_REG_CR_LI,
  52        JZ4770_CODEC_REG_CR_ADC,
  53        JZ4770_CODEC_REG_CR_MIX,
  54        JZ4770_CODEC_REG_CR_VIC,
  55        JZ4770_CODEC_REG_CCR,
  56        JZ4770_CODEC_REG_FCR_DAC,
  57        JZ4770_CODEC_REG_FCR_ADC,
  58        JZ4770_CODEC_REG_ICR,
  59        JZ4770_CODEC_REG_IMR,
  60        JZ4770_CODEC_REG_IFR,
  61        JZ4770_CODEC_REG_GCR_HPL,
  62        JZ4770_CODEC_REG_GCR_HPR,
  63        JZ4770_CODEC_REG_GCR_LIBYL,
  64        JZ4770_CODEC_REG_GCR_LIBYR,
  65        JZ4770_CODEC_REG_GCR_DACL,
  66        JZ4770_CODEC_REG_GCR_DACR,
  67        JZ4770_CODEC_REG_GCR_MIC1,
  68        JZ4770_CODEC_REG_GCR_MIC2,
  69        JZ4770_CODEC_REG_GCR_ADCL,
  70        JZ4770_CODEC_REG_GCR_ADCR,
  71
  72        JZ4770_CODEC_REG_MISSING_REG2,
  73
  74        JZ4770_CODEC_REG_GCR_MIXADC,
  75        JZ4770_CODEC_REG_GCR_MIXDAC,
  76        JZ4770_CODEC_REG_AGC1,
  77        JZ4770_CODEC_REG_AGC2,
  78        JZ4770_CODEC_REG_AGC3,
  79        JZ4770_CODEC_REG_AGC4,
  80        JZ4770_CODEC_REG_AGC5,
  81};
  82
  83#define REG_AICR_DAC_ADWL_OFFSET        6
  84#define REG_AICR_DAC_ADWL_MASK          (0x3 << REG_AICR_DAC_ADWL_OFFSET)
  85#define REG_AICR_DAC_SERIAL             BIT(1)
  86#define REG_AICR_DAC_I2S                BIT(0)
  87
  88#define REG_AICR_ADC_ADWL_OFFSET        6
  89#define REG_AICR_ADC_ADWL_MASK          (0x3 << REG_AICR_ADC_ADWL_OFFSET)
  90#define REG_AICR_ADC_SERIAL             BIT(1)
  91#define REG_AICR_ADC_I2S                BIT(0)
  92
  93#define REG_CR_LO_MUTE_OFFSET           7
  94#define REG_CR_LO_SB_OFFSET             4
  95#define REG_CR_LO_SEL_OFFSET            0
  96#define REG_CR_LO_SEL_MASK              (0x3 << REG_CR_LO_SEL_OFFSET)
  97
  98#define REG_CR_HP_MUTE                  BIT(7)
  99#define REG_CR_HP_LOAD                  BIT(6)
 100#define REG_CR_HP_SB_OFFSET             4
 101#define REG_CR_HP_SB_HPCM               BIT(3)
 102#define REG_CR_HP_SEL_OFFSET            0
 103#define REG_CR_HP_SEL_MASK              (0x3 << REG_CR_HP_SEL_OFFSET)
 104
 105#define REG_CR_DAC_MUTE                 BIT(7)
 106#define REG_CR_DAC_MONO                 BIT(6)
 107#define REG_CR_DAC_LEFT_ONLY            BIT(5)
 108#define REG_CR_DAC_SB_OFFSET            4
 109#define REG_CR_DAC_LRSWAP               BIT(3)
 110
 111#define REG_CR_MIC_STEREO_OFFSET        7
 112#define REG_CR_MIC_IDIFF_OFFSET         6
 113#define REG_CR_MIC_SB_MIC2_OFFSET       5
 114#define REG_CR_MIC_SB_MIC1_OFFSET       4
 115#define REG_CR_MIC_BIAS_V0_OFFSET       1
 116#define REG_CR_MIC_BIAS_SB_OFFSET       0
 117
 118#define REG_CR_LI_LIBY_OFFSET           4
 119#define REG_CR_LI_SB_OFFSET             0
 120
 121#define REG_CR_ADC_DMIC_SEL             BIT(7)
 122#define REG_CR_ADC_MONO                 BIT(6)
 123#define REG_CR_ADC_LEFT_ONLY            BIT(5)
 124#define REG_CR_ADC_SB_OFFSET            4
 125#define REG_CR_ADC_LRSWAP               BIT(3)
 126#define REG_CR_ADC_IN_SEL_OFFSET        0
 127#define REG_CR_ADC_IN_SEL_MASK          (0x3 << REG_CR_ADC_IN_SEL_OFFSET)
 128
 129#define REG_CR_VIC_SB_SLEEP             BIT(1)
 130#define REG_CR_VIC_SB                   BIT(0)
 131
 132#define REG_CCR_CRYSTAL_OFFSET          0
 133#define REG_CCR_CRYSTAL_MASK            (0xf << REG_CCR_CRYSTAL_OFFSET)
 134
 135#define REG_FCR_DAC_FREQ_OFFSET         0
 136#define REG_FCR_DAC_FREQ_MASK           (0xf << REG_FCR_DAC_FREQ_OFFSET)
 137
 138#define REG_FCR_ADC_FREQ_OFFSET         0
 139#define REG_FCR_ADC_FREQ_MASK           (0xf << REG_FCR_ADC_FREQ_OFFSET)
 140
 141#define REG_ICR_INT_FORM_OFFSET         6
 142#define REG_ICR_INT_FORM_MASK           (0x3 << REG_ICR_INT_FORM_OFFSET)
 143
 144#define REG_IMR_ALL_MASK                (0x7f)
 145#define REG_IMR_SCLR_MASK               BIT(6)
 146#define REG_IMR_JACK_MASK               BIT(5)
 147#define REG_IMR_SCMC_MASK               BIT(4)
 148#define REG_IMR_RUP_MASK                BIT(3)
 149#define REG_IMR_RDO_MASK                BIT(2)
 150#define REG_IMR_GUP_MASK                BIT(1)
 151#define REG_IMR_GDO_MASK                BIT(0)
 152
 153#define REG_IFR_ALL_MASK                (0x7f)
 154#define REG_IFR_SCLR                    BIT(6)
 155#define REG_IFR_JACK                    BIT(5)
 156#define REG_IFR_SCMC                    BIT(4)
 157#define REG_IFR_RUP                     BIT(3)
 158#define REG_IFR_RDO                     BIT(2)
 159#define REG_IFR_GUP                     BIT(1)
 160#define REG_IFR_GDO                     BIT(0)
 161
 162#define REG_GCR_HPL_LRGO                BIT(7)
 163
 164#define REG_GCR_DACL_RLGOD              BIT(7)
 165
 166#define REG_GCR_GAIN_OFFSET             0
 167#define REG_GCR_GAIN_MAX                0x1f
 168
 169#define REG_GCR_MIC_GAIN_OFFSET         0
 170#define REG_GCR_MIC_GAIN_MAX            5
 171
 172#define REG_GCR_ADC_GAIN_OFFSET         0
 173#define REG_GCR_ADC_GAIN_MAX            23
 174
 175#define REG_AGC1_EN                     BIT(7)
 176
 177/* codec private data */
 178struct jz_codec {
 179        struct device *dev;
 180        struct regmap *regmap;
 181        void __iomem *base;
 182        struct clk *clk;
 183};
 184
 185static int jz4770_codec_set_bias_level(struct snd_soc_component *codec,
 186                                       enum snd_soc_bias_level level)
 187{
 188        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 189        struct regmap *regmap = jz_codec->regmap;
 190
 191        switch (level) {
 192        case SND_SOC_BIAS_PREPARE:
 193                regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
 194                                   REG_CR_VIC_SB, 0);
 195                msleep(250);
 196                regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
 197                                   REG_CR_VIC_SB_SLEEP, 0);
 198                msleep(400);
 199                break;
 200        case SND_SOC_BIAS_STANDBY:
 201                regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
 202                                   REG_CR_VIC_SB_SLEEP, REG_CR_VIC_SB_SLEEP);
 203                regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_VIC,
 204                                   REG_CR_VIC_SB, REG_CR_VIC_SB);
 205                fallthrough;
 206        default:
 207                break;
 208        }
 209
 210        return 0;
 211}
 212
 213static int jz4770_codec_startup(struct snd_pcm_substream *substream,
 214                                struct snd_soc_dai *dai)
 215{
 216        struct snd_soc_component *codec = dai->component;
 217        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
 218
 219        /*
 220         * SYSCLK output from the codec to the AIC is required to keep the
 221         * DMA transfer going during playback when all audible outputs have
 222         * been disabled.
 223         */
 224        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 225                snd_soc_dapm_force_enable_pin(dapm, "SYSCLK");
 226
 227        return 0;
 228}
 229
 230static void jz4770_codec_shutdown(struct snd_pcm_substream *substream,
 231                                  struct snd_soc_dai *dai)
 232{
 233        struct snd_soc_component *codec = dai->component;
 234        struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(codec);
 235
 236        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
 237                snd_soc_dapm_disable_pin(dapm, "SYSCLK");
 238}
 239
 240
 241static int jz4770_codec_pcm_trigger(struct snd_pcm_substream *substream,
 242                                    int cmd, struct snd_soc_dai *dai)
 243{
 244        struct snd_soc_component *codec = dai->component;
 245        int ret = 0;
 246
 247        switch (cmd) {
 248        case SNDRV_PCM_TRIGGER_START:
 249        case SNDRV_PCM_TRIGGER_RESUME:
 250        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
 251                if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
 252                        snd_soc_component_force_bias_level(codec,
 253                                                           SND_SOC_BIAS_ON);
 254                break;
 255        case SNDRV_PCM_TRIGGER_STOP:
 256        case SNDRV_PCM_TRIGGER_SUSPEND:
 257        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 258                /* do nothing */
 259                break;
 260        default:
 261                ret = -EINVAL;
 262        }
 263
 264        return ret;
 265}
 266
 267static int jz4770_codec_mute_stream(struct snd_soc_dai *dai, int mute, int direction)
 268{
 269        struct snd_soc_component *codec = dai->component;
 270        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 271        unsigned int gain_bit = mute ? REG_IFR_GDO : REG_IFR_GUP;
 272        unsigned int val;
 273        int change, err;
 274
 275        change = snd_soc_component_update_bits(codec, JZ4770_CODEC_REG_CR_DAC,
 276                                               REG_CR_DAC_MUTE,
 277                                               mute ? REG_CR_DAC_MUTE : 0);
 278        if (change == 1) {
 279                regmap_read(jz_codec->regmap, JZ4770_CODEC_REG_CR_DAC, &val);
 280
 281                if (val & BIT(REG_CR_DAC_SB_OFFSET))
 282                        return 1;
 283
 284                err = regmap_read_poll_timeout(jz_codec->regmap,
 285                                               JZ4770_CODEC_REG_IFR,
 286                                               val, val & gain_bit,
 287                                               1000, 100 * USEC_PER_MSEC);
 288                if (err) {
 289                        dev_err(jz_codec->dev,
 290                                "Timeout while setting digital mute: %d", err);
 291                        return err;
 292                }
 293
 294                /* clear GUP/GDO flag */
 295                regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
 296                                   gain_bit, gain_bit);
 297        }
 298
 299        return 0;
 300}
 301
 302/* unit: 0.01dB */
 303static const DECLARE_TLV_DB_MINMAX_MUTE(dac_tlv, -3100, 0);
 304static const DECLARE_TLV_DB_SCALE(adc_tlv, 0, 100, 0);
 305static const DECLARE_TLV_DB_MINMAX(out_tlv, -2500, 600);
 306static const DECLARE_TLV_DB_SCALE(linein_tlv, -2500, 100, 0);
 307
 308/* Unconditional controls. */
 309static const struct snd_kcontrol_new jz4770_codec_snd_controls[] = {
 310        /* record gain control */
 311        SOC_DOUBLE_R_TLV("PCM Capture Volume",
 312                         JZ4770_CODEC_REG_GCR_ADCL, JZ4770_CODEC_REG_GCR_ADCR,
 313                         REG_GCR_ADC_GAIN_OFFSET, REG_GCR_ADC_GAIN_MAX,
 314                         0, adc_tlv),
 315
 316        SOC_DOUBLE_R_TLV("Line In Bypass Playback Volume",
 317                         JZ4770_CODEC_REG_GCR_LIBYL, JZ4770_CODEC_REG_GCR_LIBYR,
 318                         REG_GCR_GAIN_OFFSET, REG_GCR_GAIN_MAX, 1, linein_tlv),
 319};
 320
 321static const struct snd_kcontrol_new jz4770_codec_pcm_playback_controls[] = {
 322        {
 323                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 324                .name = "Volume",
 325                .info = snd_soc_info_volsw,
 326                .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
 327                        | SNDRV_CTL_ELEM_ACCESS_READWRITE,
 328                .tlv.p = dac_tlv,
 329                .get = snd_soc_dapm_get_volsw,
 330                .put = snd_soc_dapm_put_volsw,
 331                /*
 332                 * NOTE: DACR/DACL are inversed; the gain value written to DACR
 333                 * seems to affect the left channel, and the gain value written
 334                 * to DACL seems to affect the right channel.
 335                 */
 336                .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_DACR,
 337                                                    JZ4770_CODEC_REG_GCR_DACL,
 338                                                    REG_GCR_GAIN_OFFSET,
 339                                                    REG_GCR_GAIN_MAX, 1),
 340        },
 341};
 342
 343static const struct snd_kcontrol_new jz4770_codec_hp_playback_controls[] = {
 344        {
 345                .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 346                .name = "Volume",
 347                .info = snd_soc_info_volsw,
 348                .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ
 349                        | SNDRV_CTL_ELEM_ACCESS_READWRITE,
 350                .tlv.p = out_tlv,
 351                .get = snd_soc_dapm_get_volsw,
 352                .put = snd_soc_dapm_put_volsw,
 353                /* HPR/HPL inversed for the same reason as above */
 354                .private_value = SOC_DOUBLE_R_VALUE(JZ4770_CODEC_REG_GCR_HPR,
 355                                                    JZ4770_CODEC_REG_GCR_HPL,
 356                                                    REG_GCR_GAIN_OFFSET,
 357                                                    REG_GCR_GAIN_MAX, 1),
 358        },
 359};
 360
 361static int hpout_event(struct snd_soc_dapm_widget *w,
 362                       struct snd_kcontrol *kcontrol, int event)
 363{
 364        struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
 365        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 366        unsigned int val;
 367        int err;
 368
 369        switch (event) {
 370        case SND_SOC_DAPM_PRE_PMU:
 371                /* set cap-less, unmute HP */
 372                regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
 373                                   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE, 0);
 374                break;
 375
 376        case SND_SOC_DAPM_POST_PMU:
 377                /* wait for ramp-up complete (RUP) */
 378                err = regmap_read_poll_timeout(jz_codec->regmap,
 379                                               JZ4770_CODEC_REG_IFR,
 380                                               val, val & REG_IFR_RUP,
 381                                               1000, 100 * USEC_PER_MSEC);
 382                if (err) {
 383                        dev_err(jz_codec->dev, "RUP timeout: %d", err);
 384                        return err;
 385                }
 386
 387                /* clear RUP flag */
 388                regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
 389                                   REG_IFR_RUP, REG_IFR_RUP);
 390
 391                break;
 392
 393        case SND_SOC_DAPM_POST_PMD:
 394                /* set cap-couple, mute HP */
 395                regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_CR_HP,
 396                                   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE,
 397                                   REG_CR_HP_SB_HPCM | REG_CR_HP_MUTE);
 398
 399                err = regmap_read_poll_timeout(jz_codec->regmap,
 400                                               JZ4770_CODEC_REG_IFR,
 401                                               val, val & REG_IFR_RDO,
 402                                               1000, 100 * USEC_PER_MSEC);
 403                if (err) {
 404                        dev_err(jz_codec->dev, "RDO timeout: %d", err);
 405                        return err;
 406                }
 407
 408                /* clear RDO flag */
 409                regmap_update_bits(jz_codec->regmap, JZ4770_CODEC_REG_IFR,
 410                                   REG_IFR_RDO, REG_IFR_RDO);
 411
 412                break;
 413        }
 414
 415        return 0;
 416}
 417
 418static int adc_poweron_event(struct snd_soc_dapm_widget *w,
 419                             struct snd_kcontrol *kcontrol, int event)
 420{
 421        if (event == SND_SOC_DAPM_POST_PMU)
 422                msleep(1000);
 423
 424        return 0;
 425}
 426
 427static const char * const jz4770_codec_hp_texts[] = {
 428        "PCM", "Line In", "Mic 1", "Mic 2"
 429};
 430static const unsigned int jz4770_codec_hp_values[] = { 3, 2, 0, 1 };
 431static SOC_VALUE_ENUM_SINGLE_DECL(jz4770_codec_hp_enum,
 432                                  JZ4770_CODEC_REG_CR_HP,
 433                                  REG_CR_HP_SEL_OFFSET,
 434                                  REG_CR_HP_SEL_MASK,
 435                                  jz4770_codec_hp_texts,
 436                                  jz4770_codec_hp_values);
 437static const struct snd_kcontrol_new jz4770_codec_hp_source =
 438                        SOC_DAPM_ENUM("Route", jz4770_codec_hp_enum);
 439
 440static SOC_VALUE_ENUM_SINGLE_DECL(jz4770_codec_lo_enum,
 441                                  JZ4770_CODEC_REG_CR_LO,
 442                                  REG_CR_LO_SEL_OFFSET,
 443                                  REG_CR_LO_SEL_MASK,
 444                                  jz4770_codec_hp_texts,
 445                                  jz4770_codec_hp_values);
 446static const struct snd_kcontrol_new jz4770_codec_lo_source =
 447                        SOC_DAPM_ENUM("Route", jz4770_codec_lo_enum);
 448
 449static const char * const jz4770_codec_cap_texts[] = {
 450        "Line In", "Mic 1", "Mic 2"
 451};
 452static const unsigned int jz4770_codec_cap_values[] = { 2, 0, 1 };
 453static SOC_VALUE_ENUM_SINGLE_DECL(jz4770_codec_cap_enum,
 454                                  JZ4770_CODEC_REG_CR_ADC,
 455                                  REG_CR_ADC_IN_SEL_OFFSET,
 456                                  REG_CR_ADC_IN_SEL_MASK,
 457                                  jz4770_codec_cap_texts,
 458                                  jz4770_codec_cap_values);
 459static const struct snd_kcontrol_new jz4770_codec_cap_source =
 460                        SOC_DAPM_ENUM("Route", jz4770_codec_cap_enum);
 461
 462static const struct snd_kcontrol_new jz4770_codec_mic_controls[] = {
 463        SOC_DAPM_SINGLE("Stereo Capture Switch", JZ4770_CODEC_REG_CR_MIC,
 464                        REG_CR_MIC_STEREO_OFFSET, 1, 0),
 465};
 466
 467static const struct snd_soc_dapm_widget jz4770_codec_dapm_widgets[] = {
 468        SND_SOC_DAPM_PGA_E("HP Out", JZ4770_CODEC_REG_CR_HP,
 469                           REG_CR_HP_SB_OFFSET, 1, NULL, 0, hpout_event,
 470                           SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 471                           SND_SOC_DAPM_POST_PMD),
 472
 473        SND_SOC_DAPM_PGA("Line Out", JZ4770_CODEC_REG_CR_LO,
 474                         REG_CR_LO_SB_OFFSET, 1, NULL, 0),
 475
 476        SND_SOC_DAPM_PGA("Line Out Switch 2", JZ4770_CODEC_REG_CR_LO,
 477                         REG_CR_LO_MUTE_OFFSET, 1, NULL, 0),
 478
 479        SND_SOC_DAPM_PGA("Line In", JZ4770_CODEC_REG_CR_LI,
 480                         REG_CR_LI_SB_OFFSET, 1, NULL, 0),
 481
 482        SND_SOC_DAPM_MUX("Headphones Source", SND_SOC_NOPM, 0, 0,
 483                         &jz4770_codec_hp_source),
 484        SND_SOC_DAPM_MUX("Capture Source", SND_SOC_NOPM, 0, 0,
 485                         &jz4770_codec_cap_source),
 486        SND_SOC_DAPM_MUX("Line Out Source", SND_SOC_NOPM, 0, 0,
 487                         &jz4770_codec_lo_source),
 488
 489        SND_SOC_DAPM_PGA("Mic 1", JZ4770_CODEC_REG_CR_MIC,
 490                         REG_CR_MIC_SB_MIC1_OFFSET, 1, NULL, 0),
 491        SND_SOC_DAPM_PGA("Mic 2", JZ4770_CODEC_REG_CR_MIC,
 492                         REG_CR_MIC_SB_MIC2_OFFSET, 1, NULL, 0),
 493
 494        SND_SOC_DAPM_PGA("Mic Diff", JZ4770_CODEC_REG_CR_MIC,
 495                         REG_CR_MIC_IDIFF_OFFSET, 0, NULL, 0),
 496
 497        SND_SOC_DAPM_MIXER("Mic", SND_SOC_NOPM, 0, 0,
 498                           jz4770_codec_mic_controls,
 499                           ARRAY_SIZE(jz4770_codec_mic_controls)),
 500
 501        SND_SOC_DAPM_PGA("Line In Bypass", JZ4770_CODEC_REG_CR_LI,
 502                         REG_CR_LI_LIBY_OFFSET, 1, NULL, 0),
 503
 504        SND_SOC_DAPM_ADC_E("ADC", "HiFi Capture", JZ4770_CODEC_REG_CR_ADC,
 505                           REG_CR_ADC_SB_OFFSET, 1, adc_poweron_event,
 506                           SND_SOC_DAPM_POST_PMU),
 507        SND_SOC_DAPM_DAC("DAC", "HiFi Playback", JZ4770_CODEC_REG_CR_DAC,
 508                         REG_CR_DAC_SB_OFFSET, 1),
 509
 510        SND_SOC_DAPM_MIXER("PCM Playback", SND_SOC_NOPM, 0, 0,
 511                           jz4770_codec_pcm_playback_controls,
 512                           ARRAY_SIZE(jz4770_codec_pcm_playback_controls)),
 513        SND_SOC_DAPM_MIXER("Headphones Playback", SND_SOC_NOPM, 0, 0,
 514                           jz4770_codec_hp_playback_controls,
 515                           ARRAY_SIZE(jz4770_codec_hp_playback_controls)),
 516
 517        SND_SOC_DAPM_SUPPLY("MICBIAS", JZ4770_CODEC_REG_CR_MIC,
 518                            REG_CR_MIC_BIAS_SB_OFFSET, 1, NULL, 0),
 519
 520        SND_SOC_DAPM_INPUT("MIC1P"),
 521        SND_SOC_DAPM_INPUT("MIC1N"),
 522        SND_SOC_DAPM_INPUT("MIC2P"),
 523        SND_SOC_DAPM_INPUT("MIC2N"),
 524
 525        SND_SOC_DAPM_OUTPUT("LOUT"),
 526        SND_SOC_DAPM_OUTPUT("ROUT"),
 527
 528        SND_SOC_DAPM_OUTPUT("LHPOUT"),
 529        SND_SOC_DAPM_OUTPUT("RHPOUT"),
 530
 531        SND_SOC_DAPM_INPUT("LLINEIN"),
 532        SND_SOC_DAPM_INPUT("RLINEIN"),
 533
 534        SND_SOC_DAPM_OUTPUT("SYSCLK"),
 535};
 536
 537/* Unconditional routes. */
 538static const struct snd_soc_dapm_route jz4770_codec_dapm_routes[] = {
 539        { "Mic 1", NULL, "MIC1P" },
 540        { "Mic Diff", NULL, "MIC1N" },
 541        { "Mic 1", NULL, "Mic Diff" },
 542        { "Mic 2", NULL, "MIC2P" },
 543        { "Mic Diff", NULL, "MIC2N" },
 544        { "Mic 2", NULL, "Mic Diff" },
 545
 546        { "Line In", NULL, "LLINEIN" },
 547        { "Line In", NULL, "RLINEIN" },
 548
 549        { "Mic", "Stereo Capture Switch", "Mic 1" },
 550        { "Mic", "Stereo Capture Switch", "Mic 2" },
 551        { "Headphones Source", "Mic 1", "Mic" },
 552        { "Headphones Source", "Mic 2", "Mic" },
 553        { "Capture Source", "Mic 1", "Mic" },
 554        { "Capture Source", "Mic 2", "Mic" },
 555
 556        { "Headphones Source", "Mic 1", "Mic 1" },
 557        { "Headphones Source", "Mic 2", "Mic 2" },
 558        { "Headphones Source", "Line In", "Line In Bypass" },
 559        { "Headphones Source", "PCM", "Headphones Playback" },
 560        { "HP Out", NULL, "Headphones Source" },
 561
 562        { "Capture Source", "Line In", "Line In" },
 563        { "Capture Source", "Mic 1", "Mic 1" },
 564        { "Capture Source", "Mic 2", "Mic 2" },
 565        { "ADC", NULL, "Capture Source" },
 566
 567        { "Line In Bypass", NULL, "Line In" },
 568        { "Line Out Source", "Line In", "Line In Bypass" },
 569        { "Line Out Source", "PCM", "PCM Playback" },
 570
 571        { "LHPOUT", NULL, "HP Out"},
 572        { "RHPOUT", NULL, "HP Out"},
 573
 574        { "Line Out", NULL, "Line Out Source" },
 575        { "Line Out Switch 2", NULL, "Line Out" },
 576
 577        { "LOUT", NULL, "Line Out Switch 2"},
 578        { "ROUT", NULL, "Line Out Switch 2"},
 579
 580        { "PCM Playback", "Volume", "DAC" },
 581        { "Headphones Playback", "Volume", "PCM Playback" },
 582
 583        { "SYSCLK", NULL, "DAC" },
 584};
 585
 586static void jz4770_codec_codec_init_regs(struct snd_soc_component *codec)
 587{
 588        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 589        struct regmap *regmap = jz_codec->regmap;
 590
 591        /* Collect updates for later sending. */
 592        regcache_cache_only(regmap, true);
 593
 594        /* default HP output to PCM */
 595        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
 596                           REG_CR_HP_SEL_MASK, REG_CR_HP_SEL_MASK);
 597
 598        /* default line output to PCM */
 599        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_LO,
 600                           REG_CR_LO_SEL_MASK, REG_CR_LO_SEL_MASK);
 601
 602        /* Disable stereo mic */
 603        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_MIC,
 604                           BIT(REG_CR_MIC_STEREO_OFFSET), 0);
 605
 606        /* Set mic 1 as default source for ADC */
 607        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
 608                           REG_CR_ADC_IN_SEL_MASK, 0);
 609
 610        /* ADC/DAC: serial + i2s */
 611        regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_ADC,
 612                           REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S,
 613                           REG_AICR_ADC_SERIAL | REG_AICR_ADC_I2S);
 614        regmap_update_bits(regmap, JZ4770_CODEC_REG_AICR_DAC,
 615                           REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S,
 616                           REG_AICR_DAC_SERIAL | REG_AICR_DAC_I2S);
 617
 618        /* The generated IRQ is a high level */
 619        regmap_update_bits(regmap, JZ4770_CODEC_REG_ICR,
 620                           REG_ICR_INT_FORM_MASK, 0);
 621        regmap_update_bits(regmap, JZ4770_CODEC_REG_IMR, REG_IMR_ALL_MASK,
 622                           REG_IMR_JACK_MASK | REG_IMR_RUP_MASK |
 623                           REG_IMR_RDO_MASK | REG_IMR_GUP_MASK |
 624                           REG_IMR_GDO_MASK);
 625
 626        /* 12M oscillator */
 627        regmap_update_bits(regmap, JZ4770_CODEC_REG_CCR,
 628                           REG_CCR_CRYSTAL_MASK, 0);
 629
 630        /* 0: 16ohm/220uF, 1: 10kohm/1uF */
 631        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
 632                           REG_CR_HP_LOAD, 0);
 633
 634        /* disable automatic gain */
 635        regmap_update_bits(regmap, JZ4770_CODEC_REG_AGC1, REG_AGC1_EN, 0);
 636
 637        /* Disable DAC lrswap */
 638        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_DAC,
 639                           REG_CR_DAC_LRSWAP, REG_CR_DAC_LRSWAP);
 640
 641        /* Independent L/R DAC gain control */
 642        regmap_update_bits(regmap, JZ4770_CODEC_REG_GCR_DACL,
 643                           REG_GCR_DACL_RLGOD, 0);
 644
 645        /* Disable ADC lrswap */
 646        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_ADC,
 647                           REG_CR_ADC_LRSWAP, REG_CR_ADC_LRSWAP);
 648
 649        /* default to cap-less mode(0) */
 650        regmap_update_bits(regmap, JZ4770_CODEC_REG_CR_HP,
 651                           REG_CR_HP_SB_HPCM, 0);
 652
 653        /* Send collected updates. */
 654        regcache_cache_only(regmap, false);
 655        regcache_sync(regmap);
 656
 657        /* Reset all interrupt flags. */
 658        regmap_write(regmap, JZ4770_CODEC_REG_IFR, REG_IFR_ALL_MASK);
 659}
 660
 661static int jz4770_codec_codec_probe(struct snd_soc_component *codec)
 662{
 663        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 664
 665        clk_prepare_enable(jz_codec->clk);
 666
 667        jz4770_codec_codec_init_regs(codec);
 668
 669        return 0;
 670}
 671
 672static void jz4770_codec_codec_remove(struct snd_soc_component *codec)
 673{
 674        struct jz_codec *jz_codec = snd_soc_component_get_drvdata(codec);
 675
 676        clk_disable_unprepare(jz_codec->clk);
 677}
 678
 679static const struct snd_soc_component_driver jz4770_codec_soc_codec_dev = {
 680        .probe                  = jz4770_codec_codec_probe,
 681        .remove                 = jz4770_codec_codec_remove,
 682        .set_bias_level         = jz4770_codec_set_bias_level,
 683        .controls               = jz4770_codec_snd_controls,
 684        .num_controls           = ARRAY_SIZE(jz4770_codec_snd_controls),
 685        .dapm_widgets           = jz4770_codec_dapm_widgets,
 686        .num_dapm_widgets       = ARRAY_SIZE(jz4770_codec_dapm_widgets),
 687        .dapm_routes            = jz4770_codec_dapm_routes,
 688        .num_dapm_routes        = ARRAY_SIZE(jz4770_codec_dapm_routes),
 689        .suspend_bias_off       = 1,
 690        .use_pmdown_time        = 1,
 691};
 692
 693static const unsigned int jz4770_codec_sample_rates[] = {
 694        96000, 48000, 44100, 32000,
 695        24000, 22050, 16000, 12000,
 696        11025, 9600, 8000,
 697};
 698
 699static int jz4770_codec_hw_params(struct snd_pcm_substream *substream,
 700                                  struct snd_pcm_hw_params *params,
 701                                  struct snd_soc_dai *dai)
 702{
 703        struct jz_codec *codec = snd_soc_component_get_drvdata(dai->component);
 704        unsigned int rate, bit_width;
 705
 706        switch (params_format(params)) {
 707        case SNDRV_PCM_FORMAT_S16_LE:
 708                bit_width = 0;
 709                break;
 710        case SNDRV_PCM_FORMAT_S18_3LE:
 711                bit_width = 1;
 712                break;
 713        case SNDRV_PCM_FORMAT_S20_3LE:
 714                bit_width = 2;
 715                break;
 716        case SNDRV_PCM_FORMAT_S24_3LE:
 717                bit_width = 3;
 718                break;
 719        default:
 720                return -EINVAL;
 721        }
 722
 723        for (rate = 0; rate < ARRAY_SIZE(jz4770_codec_sample_rates); rate++) {
 724                if (jz4770_codec_sample_rates[rate] == params_rate(params))
 725                        break;
 726        }
 727
 728        if (rate == ARRAY_SIZE(jz4770_codec_sample_rates))
 729                return -EINVAL;
 730
 731        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 732                regmap_update_bits(codec->regmap, JZ4770_CODEC_REG_AICR_DAC,
 733                                   REG_AICR_DAC_ADWL_MASK,
 734                                   bit_width << REG_AICR_DAC_ADWL_OFFSET);
 735                regmap_update_bits(codec->regmap, JZ4770_CODEC_REG_FCR_DAC,
 736                                   REG_FCR_DAC_FREQ_MASK,
 737                                   rate << REG_FCR_DAC_FREQ_OFFSET);
 738        } else {
 739                regmap_update_bits(codec->regmap, JZ4770_CODEC_REG_AICR_ADC,
 740                                   REG_AICR_ADC_ADWL_MASK,
 741                                   bit_width << REG_AICR_ADC_ADWL_OFFSET);
 742                regmap_update_bits(codec->regmap, JZ4770_CODEC_REG_FCR_ADC,
 743                                   REG_FCR_ADC_FREQ_MASK,
 744                                   rate << REG_FCR_ADC_FREQ_OFFSET);
 745        }
 746
 747        return 0;
 748}
 749
 750static const struct snd_soc_dai_ops jz4770_codec_dai_ops = {
 751        .startup        = jz4770_codec_startup,
 752        .shutdown       = jz4770_codec_shutdown,
 753        .hw_params      = jz4770_codec_hw_params,
 754        .trigger        = jz4770_codec_pcm_trigger,
 755        .mute_stream    = jz4770_codec_mute_stream,
 756        .no_capture_mute = 1,
 757};
 758
 759#define JZ_CODEC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | \
 760                          SNDRV_PCM_FMTBIT_S18_3LE | \
 761                          SNDRV_PCM_FMTBIT_S20_3LE | \
 762                          SNDRV_PCM_FMTBIT_S24_3LE)
 763
 764static struct snd_soc_dai_driver jz4770_codec_dai = {
 765        .name = "jz4770-hifi",
 766        .playback = {
 767                .stream_name = "Playback",
 768                .channels_min = 2,
 769                .channels_max = 2,
 770                .rates = SNDRV_PCM_RATE_8000_96000,
 771                .formats = JZ_CODEC_FORMATS,
 772        },
 773        .capture = {
 774                .stream_name = "Capture",
 775                .channels_min = 2,
 776                .channels_max = 2,
 777                .rates = SNDRV_PCM_RATE_8000_96000,
 778                .formats = JZ_CODEC_FORMATS,
 779        },
 780        .ops = &jz4770_codec_dai_ops,
 781};
 782
 783static bool jz4770_codec_volatile(struct device *dev, unsigned int reg)
 784{
 785        return reg == JZ4770_CODEC_REG_SR || reg == JZ4770_CODEC_REG_IFR;
 786}
 787
 788static bool jz4770_codec_readable(struct device *dev, unsigned int reg)
 789{
 790        switch (reg) {
 791        case JZ4770_CODEC_REG_MISSING_REG1:
 792        case JZ4770_CODEC_REG_MISSING_REG2:
 793                return false;
 794        default:
 795                return true;
 796        }
 797}
 798
 799static bool jz4770_codec_writeable(struct device *dev, unsigned int reg)
 800{
 801        switch (reg) {
 802        case JZ4770_CODEC_REG_SR:
 803        case JZ4770_CODEC_REG_MISSING_REG1:
 804        case JZ4770_CODEC_REG_MISSING_REG2:
 805                return false;
 806        default:
 807                return true;
 808        }
 809}
 810
 811static int jz4770_codec_io_wait(struct jz_codec *codec)
 812{
 813        u32 reg;
 814
 815        return readl_poll_timeout(codec->base + ICDC_RGADW_OFFSET, reg,
 816                                  !(reg & ICDC_RGADW_RGWR),
 817                                  1000, 10 * USEC_PER_MSEC);
 818}
 819
 820static int jz4770_codec_reg_read(void *context, unsigned int reg,
 821                                 unsigned int *val)
 822{
 823        struct jz_codec *codec = context;
 824        unsigned int i;
 825        u32 tmp;
 826        int ret;
 827
 828        ret = jz4770_codec_io_wait(codec);
 829        if (ret)
 830                return ret;
 831
 832        tmp = readl(codec->base + ICDC_RGADW_OFFSET);
 833        tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
 834            | (reg << ICDC_RGADW_RGADDR_OFFSET);
 835        writel(tmp, codec->base + ICDC_RGADW_OFFSET);
 836
 837        /* wait 6+ cycles */
 838        for (i = 0; i < 6; i++)
 839                *val = readl(codec->base + ICDC_RGDATA_OFFSET) &
 840                        ICDC_RGDATA_RGDOUT_MASK;
 841
 842        return 0;
 843}
 844
 845static int jz4770_codec_reg_write(void *context, unsigned int reg,
 846                                  unsigned int val)
 847{
 848        struct jz_codec *codec = context;
 849        int ret;
 850
 851        ret = jz4770_codec_io_wait(codec);
 852        if (ret)
 853                return ret;
 854
 855        writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
 856               codec->base + ICDC_RGADW_OFFSET);
 857
 858        ret = jz4770_codec_io_wait(codec);
 859        if (ret)
 860                return ret;
 861
 862        return 0;
 863}
 864
 865static const u8 jz4770_codec_reg_defaults[] = {
 866        0x00, 0xC3, 0xC3, 0x90, 0x98, 0xFF, 0x90, 0xB1,
 867        0x11, 0x10, 0x00, 0x03, 0x00, 0x00, 0x40, 0x00,
 868        0xFF, 0x00, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00,
 869        0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x34,
 870        0x07, 0x44, 0x1F, 0x00
 871};
 872
 873static struct regmap_config jz4770_codec_regmap_config = {
 874        .reg_bits = 7,
 875        .val_bits = 8,
 876
 877        .max_register = JZ4770_CODEC_REG_AGC5,
 878        .volatile_reg = jz4770_codec_volatile,
 879        .readable_reg = jz4770_codec_readable,
 880        .writeable_reg = jz4770_codec_writeable,
 881
 882        .reg_read = jz4770_codec_reg_read,
 883        .reg_write = jz4770_codec_reg_write,
 884
 885        .reg_defaults_raw = jz4770_codec_reg_defaults,
 886        .num_reg_defaults_raw = ARRAY_SIZE(jz4770_codec_reg_defaults),
 887        .cache_type = REGCACHE_FLAT,
 888};
 889
 890static int jz4770_codec_probe(struct platform_device *pdev)
 891{
 892        struct device *dev = &pdev->dev;
 893        struct jz_codec *codec;
 894        int ret;
 895
 896        codec = devm_kzalloc(dev, sizeof(*codec), GFP_KERNEL);
 897        if (!codec)
 898                return -ENOMEM;
 899
 900        codec->dev = dev;
 901
 902        codec->base = devm_platform_ioremap_resource(pdev, 0);
 903        if (IS_ERR(codec->base)) {
 904                ret = PTR_ERR(codec->base);
 905                dev_err(dev, "Failed to ioremap mmio memory: %d\n", ret);
 906                return ret;
 907        }
 908
 909        codec->regmap = devm_regmap_init(dev, NULL, codec,
 910                                        &jz4770_codec_regmap_config);
 911        if (IS_ERR(codec->regmap))
 912                return PTR_ERR(codec->regmap);
 913
 914        codec->clk = devm_clk_get(dev, "aic");
 915        if (IS_ERR(codec->clk))
 916                return PTR_ERR(codec->clk);
 917
 918        platform_set_drvdata(pdev, codec);
 919
 920        ret = devm_snd_soc_register_component(dev, &jz4770_codec_soc_codec_dev,
 921                                              &jz4770_codec_dai, 1);
 922        if (ret) {
 923                dev_err(dev, "Failed to register codec: %d\n", ret);
 924                return ret;
 925        }
 926
 927        return 0;
 928}
 929
 930static const struct of_device_id jz4770_codec_of_matches[] = {
 931        { .compatible = "ingenic,jz4770-codec", },
 932        { /* sentinel */ }
 933};
 934MODULE_DEVICE_TABLE(of, jz4770_codec_of_matches);
 935
 936static struct platform_driver jz4770_codec_driver = {
 937        .probe                  = jz4770_codec_probe,
 938        .driver                 = {
 939                .name           = "jz4770-codec",
 940                .of_match_table = jz4770_codec_of_matches,
 941        },
 942};
 943module_platform_driver(jz4770_codec_driver);
 944
 945MODULE_DESCRIPTION("JZ4770 SoC internal codec driver");
 946MODULE_AUTHOR("Maarten ter Huurne <maarten@treewalker.org>");
 947MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
 948MODULE_LICENSE("GPL v2");
 949