linux/sound/soc/codecs/jz4725b.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2//
   3// JZ4725B CODEC driver
   4//
   5// Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net>
   6
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/platform_device.h>
  10#include <linux/slab.h>
  11#include <linux/io.h>
  12#include <linux/iopoll.h>
  13#include <linux/regmap.h>
  14#include <linux/clk.h>
  15
  16#include <linux/delay.h>
  17
  18#include <sound/core.h>
  19#include <sound/pcm.h>
  20#include <sound/pcm_params.h>
  21#include <sound/initval.h>
  22#include <sound/soc.h>
  23#include <sound/tlv.h>
  24
  25#define ICDC_RGADW_OFFSET               0x00
  26#define ICDC_RGDATA_OFFSET              0x04
  27
  28/* ICDC internal register access control register(RGADW) */
  29#define ICDC_RGADW_RGWR                 BIT(16)
  30
  31#define ICDC_RGADW_RGADDR_OFFSET        8
  32#define ICDC_RGADW_RGADDR_MASK          GENMASK(14, ICDC_RGADW_RGADDR_OFFSET)
  33
  34#define ICDC_RGADW_RGDIN_OFFSET         0
  35#define ICDC_RGADW_RGDIN_MASK           GENMASK(7, ICDC_RGADW_RGDIN_OFFSET)
  36
  37/* ICDC internal register data output register (RGDATA)*/
  38#define ICDC_RGDATA_IRQ                 BIT(8)
  39
  40#define ICDC_RGDATA_RGDOUT_OFFSET       0
  41#define ICDC_RGDATA_RGDOUT_MASK         GENMASK(7, ICDC_RGDATA_RGDOUT_OFFSET)
  42
  43/* JZ internal register space */
  44enum {
  45        JZ4725B_CODEC_REG_AICR,
  46        JZ4725B_CODEC_REG_CR1,
  47        JZ4725B_CODEC_REG_CR2,
  48        JZ4725B_CODEC_REG_CCR1,
  49        JZ4725B_CODEC_REG_CCR2,
  50        JZ4725B_CODEC_REG_PMR1,
  51        JZ4725B_CODEC_REG_PMR2,
  52        JZ4725B_CODEC_REG_CRR,
  53        JZ4725B_CODEC_REG_ICR,
  54        JZ4725B_CODEC_REG_IFR,
  55        JZ4725B_CODEC_REG_CGR1,
  56        JZ4725B_CODEC_REG_CGR2,
  57        JZ4725B_CODEC_REG_CGR3,
  58        JZ4725B_CODEC_REG_CGR4,
  59        JZ4725B_CODEC_REG_CGR5,
  60        JZ4725B_CODEC_REG_CGR6,
  61        JZ4725B_CODEC_REG_CGR7,
  62        JZ4725B_CODEC_REG_CGR8,
  63        JZ4725B_CODEC_REG_CGR9,
  64        JZ4725B_CODEC_REG_CGR10,
  65        JZ4725B_CODEC_REG_TR1,
  66        JZ4725B_CODEC_REG_TR2,
  67        JZ4725B_CODEC_REG_CR3,
  68        JZ4725B_CODEC_REG_AGC1,
  69        JZ4725B_CODEC_REG_AGC2,
  70        JZ4725B_CODEC_REG_AGC3,
  71        JZ4725B_CODEC_REG_AGC4,
  72        JZ4725B_CODEC_REG_AGC5,
  73};
  74
  75#define REG_AICR_CONFIG1_OFFSET         0
  76#define REG_AICR_CONFIG1_MASK           (0xf << REG_AICR_CONFIG1_OFFSET)
  77
  78#define REG_CR1_SB_MICBIAS_OFFSET       7
  79#define REG_CR1_MONO_OFFSET             6
  80#define REG_CR1_DAC_MUTE_OFFSET         5
  81#define REG_CR1_HP_DIS_OFFSET           4
  82#define REG_CR1_DACSEL_OFFSET           3
  83#define REG_CR1_BYPASS_OFFSET           2
  84
  85#define REG_CR2_DAC_DEEMP_OFFSET        7
  86#define REG_CR2_DAC_ADWL_OFFSET         5
  87#define REG_CR2_DAC_ADWL_MASK           (0x3 << REG_CR2_DAC_ADWL_OFFSET)
  88#define REG_CR2_ADC_ADWL_OFFSET         3
  89#define REG_CR2_ADC_ADWL_MASK           (0x3 << REG_CR2_ADC_ADWL_OFFSET)
  90#define REG_CR2_ADC_HPF_OFFSET          2
  91
  92#define REG_CR3_SB_MIC1_OFFSET          7
  93#define REG_CR3_SB_MIC2_OFFSET          6
  94#define REG_CR3_SIDETONE1_OFFSET        5
  95#define REG_CR3_SIDETONE2_OFFSET        4
  96#define REG_CR3_MICDIFF_OFFSET          3
  97#define REG_CR3_MICSTEREO_OFFSET        2
  98#define REG_CR3_INSEL_OFFSET            0
  99#define REG_CR3_INSEL_MASK              (0x3 << REG_CR3_INSEL_OFFSET)
 100
 101#define REG_CCR1_CONFIG4_OFFSET         0
 102#define REG_CCR1_CONFIG4_MASK           (0xf << REG_CCR1_CONFIG4_OFFSET)
 103
 104#define REG_CCR2_DFREQ_OFFSET           4
 105#define REG_CCR2_DFREQ_MASK             (0xf << REG_CCR2_DFREQ_OFFSET)
 106#define REG_CCR2_AFREQ_OFFSET           0
 107#define REG_CCR2_AFREQ_MASK             (0xf << REG_CCR2_AFREQ_OFFSET)
 108
 109#define REG_PMR1_SB_DAC_OFFSET          7
 110#define REG_PMR1_SB_OUT_OFFSET          6
 111#define REG_PMR1_SB_MIX_OFFSET          5
 112#define REG_PMR1_SB_ADC_OFFSET          4
 113#define REG_PMR1_SB_LIN_OFFSET          3
 114#define REG_PMR1_SB_IND_OFFSET          0
 115
 116#define REG_PMR2_LRGI_OFFSET            7
 117#define REG_PMR2_RLGI_OFFSET            6
 118#define REG_PMR2_LRGOD_OFFSET           5
 119#define REG_PMR2_RLGOD_OFFSET           4
 120#define REG_PMR2_GIM_OFFSET             3
 121#define REG_PMR2_SB_MC_OFFSET           2
 122#define REG_PMR2_SB_OFFSET              1
 123#define REG_PMR2_SB_SLEEP_OFFSET        0
 124
 125#define REG_IFR_RAMP_UP_DONE_OFFSET     3
 126#define REG_IFR_RAMP_DOWN_DONE_OFFSET   2
 127
 128#define REG_CGR1_GODL_OFFSET            4
 129#define REG_CGR1_GODL_MASK              (0xf << REG_CGR1_GODL_OFFSET)
 130#define REG_CGR1_GODR_OFFSET            0
 131#define REG_CGR1_GODR_MASK              (0xf << REG_CGR1_GODR_OFFSET)
 132
 133#define REG_CGR2_GO1R_OFFSET            0
 134#define REG_CGR2_GO1R_MASK              (0x1f << REG_CGR2_GO1R_OFFSET)
 135
 136#define REG_CGR3_GO1L_OFFSET            0
 137#define REG_CGR3_GO1L_MASK              (0x1f << REG_CGR3_GO1L_OFFSET)
 138
 139struct jz_icdc {
 140        struct regmap *regmap;
 141        void __iomem *base;
 142        struct clk *clk;
 143};
 144
 145static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_dac_tlv, -2250, 0);
 146static const SNDRV_CTL_TLVD_DECLARE_DB_LINEAR(jz4725b_line_tlv, -1500, 600);
 147
 148static const struct snd_kcontrol_new jz4725b_codec_controls[] = {
 149        SOC_DOUBLE_TLV("Master Playback Volume",
 150                       JZ4725B_CODEC_REG_CGR1,
 151                       REG_CGR1_GODL_OFFSET,
 152                       REG_CGR1_GODR_OFFSET,
 153                       0xf, 1, jz4725b_dac_tlv),
 154        SOC_DOUBLE_R_TLV("Master Capture Volume",
 155                         JZ4725B_CODEC_REG_CGR3,
 156                         JZ4725B_CODEC_REG_CGR2,
 157                         REG_CGR2_GO1R_OFFSET,
 158                         0x1f, 1, jz4725b_line_tlv),
 159
 160        SOC_SINGLE("Master Playback Switch", JZ4725B_CODEC_REG_CR1,
 161                   REG_CR1_DAC_MUTE_OFFSET, 1, 1),
 162
 163        SOC_SINGLE("Deemphasize Filter Playback Switch",
 164                   JZ4725B_CODEC_REG_CR2,
 165                   REG_CR2_DAC_DEEMP_OFFSET, 1, 0),
 166
 167        SOC_SINGLE("High-Pass Filter Capture Switch",
 168                   JZ4725B_CODEC_REG_CR2,
 169                   REG_CR2_ADC_HPF_OFFSET, 1, 0),
 170};
 171
 172static const char * const jz4725b_codec_adc_src_texts[] = {
 173        "Mic 1", "Mic 2", "Line In", "Mixer",
 174};
 175static const unsigned int jz4725b_codec_adc_src_values[] = { 0, 1, 2, 3, };
 176static SOC_VALUE_ENUM_SINGLE_DECL(jz4725b_codec_adc_src_enum,
 177                                  JZ4725B_CODEC_REG_CR3,
 178                                  REG_CR3_INSEL_OFFSET,
 179                                  REG_CR3_INSEL_MASK,
 180                                  jz4725b_codec_adc_src_texts,
 181                                  jz4725b_codec_adc_src_values);
 182static const struct snd_kcontrol_new jz4725b_codec_adc_src_ctrl =
 183                        SOC_DAPM_ENUM("Route", jz4725b_codec_adc_src_enum);
 184
 185static const struct snd_kcontrol_new jz4725b_codec_mixer_controls[] = {
 186        SOC_DAPM_SINGLE("Line In Bypass", JZ4725B_CODEC_REG_CR1,
 187                        REG_CR1_BYPASS_OFFSET, 1, 0),
 188};
 189
 190static int jz4725b_out_stage_enable(struct snd_soc_dapm_widget *w,
 191                                    struct snd_kcontrol *kcontrol,
 192                                    int event)
 193{
 194        struct snd_soc_component *codec = snd_soc_dapm_to_component(w->dapm);
 195        struct jz_icdc *icdc = snd_soc_component_get_drvdata(codec);
 196        struct regmap *map = icdc->regmap;
 197        unsigned int val;
 198
 199        switch (event) {
 200        case SND_SOC_DAPM_PRE_PMU:
 201                return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
 202                                         BIT(REG_IFR_RAMP_UP_DONE_OFFSET));
 203        case SND_SOC_DAPM_POST_PMU:
 204                return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
 205                               val, val & BIT(REG_IFR_RAMP_UP_DONE_OFFSET),
 206                               100000, 500000);
 207        case SND_SOC_DAPM_PRE_PMD:
 208                return regmap_clear_bits(map, JZ4725B_CODEC_REG_IFR,
 209                                BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET));
 210        case SND_SOC_DAPM_POST_PMD:
 211                return regmap_read_poll_timeout(map, JZ4725B_CODEC_REG_IFR,
 212                               val, val & BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET),
 213                               100000, 500000);
 214        default:
 215                return -EINVAL;
 216        }
 217}
 218
 219static const struct snd_soc_dapm_widget jz4725b_codec_dapm_widgets[] = {
 220        /* DAC */
 221        SND_SOC_DAPM_DAC("DAC", "Playback",
 222                         JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_DAC_OFFSET, 1),
 223
 224        /* ADC */
 225        SND_SOC_DAPM_ADC("ADC", "Capture",
 226                         JZ4725B_CODEC_REG_PMR1, REG_PMR1_SB_ADC_OFFSET, 1),
 227
 228        SND_SOC_DAPM_MUX("ADC Source", SND_SOC_NOPM, 0, 0,
 229                         &jz4725b_codec_adc_src_ctrl),
 230
 231        /* Mixer */
 232        SND_SOC_DAPM_MIXER("Mixer", JZ4725B_CODEC_REG_PMR1,
 233                           REG_PMR1_SB_MIX_OFFSET, 1,
 234                           jz4725b_codec_mixer_controls,
 235                           ARRAY_SIZE(jz4725b_codec_mixer_controls)),
 236        SND_SOC_DAPM_MIXER("DAC to Mixer", JZ4725B_CODEC_REG_CR1,
 237                           REG_CR1_DACSEL_OFFSET, 0, NULL, 0),
 238
 239        SND_SOC_DAPM_MIXER("Line In", SND_SOC_NOPM, 0, 0, NULL, 0),
 240        SND_SOC_DAPM_MIXER("HP Out", JZ4725B_CODEC_REG_CR1,
 241                           REG_CR1_HP_DIS_OFFSET, 1, NULL, 0),
 242
 243        SND_SOC_DAPM_MIXER("Mic 1", JZ4725B_CODEC_REG_CR3,
 244                           REG_CR3_SB_MIC1_OFFSET, 1, NULL, 0),
 245        SND_SOC_DAPM_MIXER("Mic 2", JZ4725B_CODEC_REG_CR3,
 246                           REG_CR3_SB_MIC2_OFFSET, 1, NULL, 0),
 247
 248        SND_SOC_DAPM_MIXER_E("Out Stage", JZ4725B_CODEC_REG_PMR1,
 249                             REG_PMR1_SB_OUT_OFFSET, 1, NULL, 0,
 250                             jz4725b_out_stage_enable,
 251                             SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMU |
 252                             SND_SOC_DAPM_PRE_PMD | SND_SOC_DAPM_POST_PMD),
 253        SND_SOC_DAPM_MIXER("Mixer to ADC", JZ4725B_CODEC_REG_PMR1,
 254                           REG_PMR1_SB_IND_OFFSET, 1, NULL, 0),
 255
 256        SND_SOC_DAPM_SUPPLY("Mic Bias", JZ4725B_CODEC_REG_CR1,
 257                            REG_CR1_SB_MICBIAS_OFFSET, 1, NULL, 0),
 258
 259        /* Pins */
 260        SND_SOC_DAPM_INPUT("MIC1P"),
 261        SND_SOC_DAPM_INPUT("MIC1N"),
 262        SND_SOC_DAPM_INPUT("MIC2P"),
 263        SND_SOC_DAPM_INPUT("MIC2N"),
 264
 265        SND_SOC_DAPM_INPUT("LLINEIN"),
 266        SND_SOC_DAPM_INPUT("RLINEIN"),
 267
 268        SND_SOC_DAPM_OUTPUT("LHPOUT"),
 269        SND_SOC_DAPM_OUTPUT("RHPOUT"),
 270};
 271
 272static const struct snd_soc_dapm_route jz4725b_codec_dapm_routes[] = {
 273        {"Mic 1", NULL, "MIC1P"},
 274        {"Mic 1", NULL, "MIC1N"},
 275        {"Mic 2", NULL, "MIC2P"},
 276        {"Mic 2", NULL, "MIC2N"},
 277
 278        {"Line In", NULL, "LLINEIN"},
 279        {"Line In", NULL, "RLINEIN"},
 280
 281        {"Mixer", "Line In Bypass", "Line In"},
 282        {"DAC to Mixer", NULL, "DAC"},
 283        {"Mixer", NULL, "DAC to Mixer"},
 284
 285        {"Mixer to ADC", NULL, "Mixer"},
 286        {"ADC Source", "Mixer", "Mixer to ADC"},
 287        {"ADC Source", "Line In", "Line In"},
 288        {"ADC Source", "Mic 1", "Mic 1"},
 289        {"ADC Source", "Mic 2", "Mic 2"},
 290        {"ADC", NULL, "ADC Source"},
 291
 292        {"Out Stage", NULL, "Mixer"},
 293        {"HP Out", NULL, "Out Stage"},
 294        {"LHPOUT", NULL, "HP Out"},
 295        {"RHPOUT", NULL, "HP Out"},
 296};
 297
 298static int jz4725b_codec_set_bias_level(struct snd_soc_component *component,
 299                                        enum snd_soc_bias_level level)
 300{
 301        struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
 302        struct regmap *map = icdc->regmap;
 303
 304        switch (level) {
 305        case SND_SOC_BIAS_ON:
 306                regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
 307                                  BIT(REG_PMR2_SB_SLEEP_OFFSET));
 308                break;
 309        case SND_SOC_BIAS_PREPARE:
 310                /* Enable sound hardware */
 311                regmap_clear_bits(map, JZ4725B_CODEC_REG_PMR2,
 312                                  BIT(REG_PMR2_SB_OFFSET));
 313                msleep(224);
 314                break;
 315        case SND_SOC_BIAS_STANDBY:
 316                regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
 317                                BIT(REG_PMR2_SB_SLEEP_OFFSET));
 318                break;
 319        case SND_SOC_BIAS_OFF:
 320                regmap_set_bits(map, JZ4725B_CODEC_REG_PMR2,
 321                                BIT(REG_PMR2_SB_OFFSET));
 322                break;
 323        }
 324
 325        return 0;
 326}
 327
 328static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
 329{
 330        struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
 331        struct regmap *map = icdc->regmap;
 332
 333        clk_prepare_enable(icdc->clk);
 334
 335        /* Write CONFIGn (n=1 to 8) bits.
 336         * The value 0x0f is specified in the datasheet as a requirement.
 337         */
 338        regmap_write(map, JZ4725B_CODEC_REG_AICR,
 339                     0xf << REG_AICR_CONFIG1_OFFSET);
 340        regmap_write(map, JZ4725B_CODEC_REG_CCR1,
 341                     0x0 << REG_CCR1_CONFIG4_OFFSET);
 342
 343        return 0;
 344}
 345
 346static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
 347{
 348        struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
 349
 350        clk_disable_unprepare(icdc->clk);
 351}
 352
 353static const struct snd_soc_component_driver jz4725b_codec = {
 354        .probe                  = jz4725b_codec_dev_probe,
 355        .remove                 = jz4725b_codec_dev_remove,
 356        .set_bias_level         = jz4725b_codec_set_bias_level,
 357        .controls               = jz4725b_codec_controls,
 358        .num_controls           = ARRAY_SIZE(jz4725b_codec_controls),
 359        .dapm_widgets           = jz4725b_codec_dapm_widgets,
 360        .num_dapm_widgets       = ARRAY_SIZE(jz4725b_codec_dapm_widgets),
 361        .dapm_routes            = jz4725b_codec_dapm_routes,
 362        .num_dapm_routes        = ARRAY_SIZE(jz4725b_codec_dapm_routes),
 363        .suspend_bias_off       = 1,
 364        .use_pmdown_time        = 1,
 365};
 366
 367static const unsigned int jz4725b_codec_sample_rates[] = {
 368        96000, 48000, 44100, 32000,
 369        24000, 22050, 16000, 12000,
 370        11025, 9600, 8000,
 371};
 372
 373static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
 374        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 375{
 376        struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component);
 377        unsigned int rate, bit_width;
 378
 379        switch (params_format(params)) {
 380        case SNDRV_PCM_FORMAT_S16_LE:
 381                bit_width = 0;
 382                break;
 383        case SNDRV_PCM_FORMAT_S18_3LE:
 384                bit_width = 1;
 385                break;
 386        case SNDRV_PCM_FORMAT_S20_3LE:
 387                bit_width = 2;
 388                break;
 389        case SNDRV_PCM_FORMAT_S24_3LE:
 390                bit_width = 3;
 391                break;
 392        default:
 393                return -EINVAL;
 394        }
 395
 396        for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
 397                if (jz4725b_codec_sample_rates[rate] == params_rate(params))
 398                        break;
 399        }
 400
 401        if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
 402                return -EINVAL;
 403
 404        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 405                regmap_update_bits(icdc->regmap,
 406                                   JZ4725B_CODEC_REG_CR2,
 407                                   REG_CR2_DAC_ADWL_MASK,
 408                                   bit_width << REG_CR2_DAC_ADWL_OFFSET);
 409
 410                regmap_update_bits(icdc->regmap,
 411                                   JZ4725B_CODEC_REG_CCR2,
 412                                   REG_CCR2_DFREQ_MASK,
 413                                   rate << REG_CCR2_DFREQ_OFFSET);
 414        } else {
 415                regmap_update_bits(icdc->regmap,
 416                                   JZ4725B_CODEC_REG_CR2,
 417                                   REG_CR2_ADC_ADWL_MASK,
 418                                   bit_width << REG_CR2_ADC_ADWL_OFFSET);
 419
 420                regmap_update_bits(icdc->regmap,
 421                                   JZ4725B_CODEC_REG_CCR2,
 422                                   REG_CCR2_AFREQ_MASK,
 423                                   rate << REG_CCR2_AFREQ_OFFSET);
 424        }
 425
 426        return 0;
 427}
 428
 429static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
 430        .hw_params = jz4725b_codec_hw_params,
 431};
 432
 433#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S18_3LE | \
 434                         SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
 435
 436static struct snd_soc_dai_driver jz4725b_codec_dai = {
 437        .name = "jz4725b-hifi",
 438        .playback = {
 439                .stream_name = "Playback",
 440                .channels_min = 2,
 441                .channels_max = 2,
 442                .rates = SNDRV_PCM_RATE_8000_96000,
 443                .formats = JZ_ICDC_FORMATS,
 444        },
 445        .capture = {
 446                .stream_name = "Capture",
 447                .channels_min = 2,
 448                .channels_max = 2,
 449                .rates = SNDRV_PCM_RATE_8000_96000,
 450                .formats = JZ_ICDC_FORMATS,
 451        },
 452        .ops = &jz4725b_codec_dai_ops,
 453};
 454
 455static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
 456{
 457        return reg == JZ4725B_CODEC_REG_IFR;
 458}
 459
 460static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
 461{
 462        return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
 463}
 464
 465static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
 466{
 467        u32 reg;
 468
 469        return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
 470                                  !(reg & ICDC_RGADW_RGWR), 1000, 10000);
 471}
 472
 473static int jz4725b_codec_reg_read(void *context, unsigned int reg,
 474                                  unsigned int *val)
 475{
 476        struct jz_icdc *icdc = context;
 477        unsigned int i;
 478        u32 tmp;
 479        int ret;
 480
 481        ret = jz4725b_codec_io_wait(icdc);
 482        if (ret)
 483                return ret;
 484
 485        tmp = readl(icdc->base + ICDC_RGADW_OFFSET);
 486        tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
 487            | (reg << ICDC_RGADW_RGADDR_OFFSET);
 488        writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
 489
 490        /* wait 6+ cycles */
 491        for (i = 0; i < 6; i++)
 492                *val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
 493                        ICDC_RGDATA_RGDOUT_MASK;
 494
 495        return 0;
 496}
 497
 498static int jz4725b_codec_reg_write(void *context, unsigned int reg,
 499                                   unsigned int val)
 500{
 501        struct jz_icdc *icdc = context;
 502        int ret;
 503
 504        ret = jz4725b_codec_io_wait(icdc);
 505        if (ret)
 506                return ret;
 507
 508        writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
 509                        icdc->base + ICDC_RGADW_OFFSET);
 510
 511        ret = jz4725b_codec_io_wait(icdc);
 512        if (ret)
 513                return ret;
 514
 515        return 0;
 516}
 517
 518static const u8 jz4725b_codec_reg_defaults[] = {
 519        0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
 520        0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
 521        0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
 522        0x07, 0x44, 0x1f, 0x00,
 523};
 524
 525static const struct regmap_config jz4725b_codec_regmap_config = {
 526        .reg_bits = 7,
 527        .val_bits = 8,
 528
 529        .max_register = JZ4725B_CODEC_REG_AGC5,
 530        .volatile_reg = jz4725b_codec_volatile,
 531        .readable_reg = jz4725b_codec_can_access_reg,
 532        .writeable_reg = jz4725b_codec_can_access_reg,
 533
 534        .reg_read = jz4725b_codec_reg_read,
 535        .reg_write = jz4725b_codec_reg_write,
 536
 537        .reg_defaults_raw = jz4725b_codec_reg_defaults,
 538        .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
 539        .cache_type = REGCACHE_FLAT,
 540};
 541
 542static int jz4725b_codec_probe(struct platform_device *pdev)
 543{
 544        struct device *dev = &pdev->dev;
 545        struct jz_icdc *icdc;
 546        int ret;
 547
 548        icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
 549        if (!icdc)
 550                return -ENOMEM;
 551
 552        icdc->base = devm_platform_ioremap_resource(pdev, 0);
 553        if (IS_ERR(icdc->base))
 554                return PTR_ERR(icdc->base);
 555
 556        icdc->regmap = devm_regmap_init(dev, NULL, icdc,
 557                                        &jz4725b_codec_regmap_config);
 558        if (IS_ERR(icdc->regmap))
 559                return PTR_ERR(icdc->regmap);
 560
 561        icdc->clk = devm_clk_get(&pdev->dev, "aic");
 562        if (IS_ERR(icdc->clk))
 563                return PTR_ERR(icdc->clk);
 564
 565        platform_set_drvdata(pdev, icdc);
 566
 567        ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
 568                                              &jz4725b_codec_dai, 1);
 569        if (ret)
 570                dev_err(dev, "Failed to register codec\n");
 571
 572        return ret;
 573}
 574
 575static const struct of_device_id jz4725b_codec_of_matches[] = {
 576        { .compatible = "ingenic,jz4725b-codec", },
 577        { }
 578};
 579MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
 580
 581static struct platform_driver jz4725b_codec_driver = {
 582        .probe = jz4725b_codec_probe,
 583        .driver = {
 584                .name = "jz4725b-codec",
 585                .of_match_table = jz4725b_codec_of_matches,
 586        },
 587};
 588module_platform_driver(jz4725b_codec_driver);
 589
 590MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
 591MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
 592MODULE_LICENSE("GPL v2");
 593