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_update_bits(map, JZ4725B_CODEC_REG_IFR,
 202                                          BIT(REG_IFR_RAMP_UP_DONE_OFFSET), 0);
 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_update_bits(map, JZ4725B_CODEC_REG_IFR,
 209                                BIT(REG_IFR_RAMP_DOWN_DONE_OFFSET), 0);
 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_update_bits(map, JZ4725B_CODEC_REG_PMR2,
 307                                   BIT(REG_PMR2_SB_SLEEP_OFFSET), 0);
 308                break;
 309        case SND_SOC_BIAS_PREPARE:
 310                /* Enable sound hardware */
 311                regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
 312                                   BIT(REG_PMR2_SB_OFFSET), 0);
 313                msleep(224);
 314                break;
 315        case SND_SOC_BIAS_STANDBY:
 316                regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
 317                                   BIT(REG_PMR2_SB_SLEEP_OFFSET),
 318                                   BIT(REG_PMR2_SB_SLEEP_OFFSET));
 319                break;
 320        case SND_SOC_BIAS_OFF:
 321                regmap_update_bits(map, JZ4725B_CODEC_REG_PMR2,
 322                                   BIT(REG_PMR2_SB_OFFSET),
 323                                   BIT(REG_PMR2_SB_OFFSET));
 324                break;
 325        }
 326
 327        return 0;
 328}
 329
 330static int jz4725b_codec_dev_probe(struct snd_soc_component *component)
 331{
 332        struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
 333        struct regmap *map = icdc->regmap;
 334
 335        clk_prepare_enable(icdc->clk);
 336
 337        /* Write CONFIGn (n=1 to 8) bits.
 338         * The value 0x0f is specified in the datasheet as a requirement.
 339         */
 340        regmap_write(map, JZ4725B_CODEC_REG_AICR,
 341                     0xf << REG_AICR_CONFIG1_OFFSET);
 342        regmap_write(map, JZ4725B_CODEC_REG_CCR1,
 343                     0x0 << REG_CCR1_CONFIG4_OFFSET);
 344
 345        return 0;
 346}
 347
 348static void jz4725b_codec_dev_remove(struct snd_soc_component *component)
 349{
 350        struct jz_icdc *icdc = snd_soc_component_get_drvdata(component);
 351
 352        clk_disable_unprepare(icdc->clk);
 353}
 354
 355static const struct snd_soc_component_driver jz4725b_codec = {
 356        .probe                  = jz4725b_codec_dev_probe,
 357        .remove                 = jz4725b_codec_dev_remove,
 358        .set_bias_level         = jz4725b_codec_set_bias_level,
 359        .controls               = jz4725b_codec_controls,
 360        .num_controls           = ARRAY_SIZE(jz4725b_codec_controls),
 361        .dapm_widgets           = jz4725b_codec_dapm_widgets,
 362        .num_dapm_widgets       = ARRAY_SIZE(jz4725b_codec_dapm_widgets),
 363        .dapm_routes            = jz4725b_codec_dapm_routes,
 364        .num_dapm_routes        = ARRAY_SIZE(jz4725b_codec_dapm_routes),
 365        .suspend_bias_off       = 1,
 366        .use_pmdown_time        = 1,
 367};
 368
 369static const unsigned int jz4725b_codec_sample_rates[] = {
 370        96000, 48000, 44100, 32000,
 371        24000, 22050, 16000, 12000,
 372        11025, 9600, 8000,
 373};
 374
 375static int jz4725b_codec_hw_params(struct snd_pcm_substream *substream,
 376        struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
 377{
 378        struct jz_icdc *icdc = snd_soc_component_get_drvdata(dai->component);
 379        unsigned int rate, bit_width;
 380
 381        switch (params_format(params)) {
 382        case SNDRV_PCM_FORMAT_S16_LE:
 383                bit_width = 0;
 384                break;
 385        case SNDRV_PCM_FORMAT_S18_3LE:
 386                bit_width = 1;
 387                break;
 388        case SNDRV_PCM_FORMAT_S20_3LE:
 389                bit_width = 2;
 390                break;
 391        case SNDRV_PCM_FORMAT_S24_3LE:
 392                bit_width = 3;
 393                break;
 394        default:
 395                return -EINVAL;
 396        }
 397
 398        for (rate = 0; rate < ARRAY_SIZE(jz4725b_codec_sample_rates); rate++) {
 399                if (jz4725b_codec_sample_rates[rate] == params_rate(params))
 400                        break;
 401        }
 402
 403        if (rate == ARRAY_SIZE(jz4725b_codec_sample_rates))
 404                return -EINVAL;
 405
 406        if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 407                regmap_update_bits(icdc->regmap,
 408                                   JZ4725B_CODEC_REG_CR2,
 409                                   REG_CR2_DAC_ADWL_MASK,
 410                                   bit_width << REG_CR2_DAC_ADWL_OFFSET);
 411
 412                regmap_update_bits(icdc->regmap,
 413                                   JZ4725B_CODEC_REG_CCR2,
 414                                   REG_CCR2_DFREQ_MASK,
 415                                   rate << REG_CCR2_DFREQ_OFFSET);
 416        } else {
 417                regmap_update_bits(icdc->regmap,
 418                                   JZ4725B_CODEC_REG_CR2,
 419                                   REG_CR2_ADC_ADWL_MASK,
 420                                   bit_width << REG_CR2_ADC_ADWL_OFFSET);
 421
 422                regmap_update_bits(icdc->regmap,
 423                                   JZ4725B_CODEC_REG_CCR2,
 424                                   REG_CCR2_AFREQ_MASK,
 425                                   rate << REG_CCR2_AFREQ_OFFSET);
 426        }
 427
 428        return 0;
 429}
 430
 431static const struct snd_soc_dai_ops jz4725b_codec_dai_ops = {
 432        .hw_params = jz4725b_codec_hw_params,
 433};
 434
 435#define JZ_ICDC_FORMATS (SNDRV_PCM_FMTBIT_S16_LE  | SNDRV_PCM_FMTBIT_S18_3LE | \
 436                         SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_3LE)
 437
 438static struct snd_soc_dai_driver jz4725b_codec_dai = {
 439        .name = "jz4725b-hifi",
 440        .playback = {
 441                .stream_name = "Playback",
 442                .channels_min = 2,
 443                .channels_max = 2,
 444                .rates = SNDRV_PCM_RATE_8000_96000,
 445                .formats = JZ_ICDC_FORMATS,
 446        },
 447        .capture = {
 448                .stream_name = "Capture",
 449                .channels_min = 2,
 450                .channels_max = 2,
 451                .rates = SNDRV_PCM_RATE_8000_96000,
 452                .formats = JZ_ICDC_FORMATS,
 453        },
 454        .ops = &jz4725b_codec_dai_ops,
 455};
 456
 457static bool jz4725b_codec_volatile(struct device *dev, unsigned int reg)
 458{
 459        return reg == JZ4725B_CODEC_REG_IFR;
 460}
 461
 462static bool jz4725b_codec_can_access_reg(struct device *dev, unsigned int reg)
 463{
 464        return (reg != JZ4725B_CODEC_REG_TR1) && (reg != JZ4725B_CODEC_REG_TR2);
 465}
 466
 467static int jz4725b_codec_io_wait(struct jz_icdc *icdc)
 468{
 469        u32 reg;
 470
 471        return readl_poll_timeout(icdc->base + ICDC_RGADW_OFFSET, reg,
 472                                  !(reg & ICDC_RGADW_RGWR), 1000, 10000);
 473}
 474
 475static int jz4725b_codec_reg_read(void *context, unsigned int reg,
 476                                  unsigned int *val)
 477{
 478        struct jz_icdc *icdc = context;
 479        unsigned int i;
 480        u32 tmp;
 481        int ret;
 482
 483        ret = jz4725b_codec_io_wait(icdc);
 484        if (ret)
 485                return ret;
 486
 487        tmp = readl(icdc->base + ICDC_RGADW_OFFSET);
 488        tmp = (tmp & ~ICDC_RGADW_RGADDR_MASK)
 489            | (reg << ICDC_RGADW_RGADDR_OFFSET);
 490        writel(tmp, icdc->base + ICDC_RGADW_OFFSET);
 491
 492        /* wait 6+ cycles */
 493        for (i = 0; i < 6; i++)
 494                *val = readl(icdc->base + ICDC_RGDATA_OFFSET) &
 495                        ICDC_RGDATA_RGDOUT_MASK;
 496
 497        return 0;
 498}
 499
 500static int jz4725b_codec_reg_write(void *context, unsigned int reg,
 501                                   unsigned int val)
 502{
 503        struct jz_icdc *icdc = context;
 504        int ret;
 505
 506        ret = jz4725b_codec_io_wait(icdc);
 507        if (ret)
 508                return ret;
 509
 510        writel(ICDC_RGADW_RGWR | (reg << ICDC_RGADW_RGADDR_OFFSET) | val,
 511                        icdc->base + ICDC_RGADW_OFFSET);
 512
 513        ret = jz4725b_codec_io_wait(icdc);
 514        if (ret)
 515                return ret;
 516
 517        return 0;
 518}
 519
 520static const u8 jz4725b_codec_reg_defaults[] = {
 521        0x0c, 0xaa, 0x78, 0x00, 0x00, 0xff, 0x03, 0x51,
 522        0x3f, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04,
 523        0x04, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0xc0, 0x34,
 524        0x07, 0x44, 0x1f, 0x00,
 525};
 526
 527static const struct regmap_config jz4725b_codec_regmap_config = {
 528        .reg_bits = 7,
 529        .val_bits = 8,
 530
 531        .max_register = JZ4725B_CODEC_REG_AGC5,
 532        .volatile_reg = jz4725b_codec_volatile,
 533        .readable_reg = jz4725b_codec_can_access_reg,
 534        .writeable_reg = jz4725b_codec_can_access_reg,
 535
 536        .reg_read = jz4725b_codec_reg_read,
 537        .reg_write = jz4725b_codec_reg_write,
 538
 539        .reg_defaults_raw = jz4725b_codec_reg_defaults,
 540        .num_reg_defaults_raw = ARRAY_SIZE(jz4725b_codec_reg_defaults),
 541        .cache_type = REGCACHE_FLAT,
 542};
 543
 544static int jz4725b_codec_probe(struct platform_device *pdev)
 545{
 546        struct device *dev = &pdev->dev;
 547        struct jz_icdc *icdc;
 548        struct resource *mem;
 549        int ret;
 550
 551        icdc = devm_kzalloc(dev, sizeof(*icdc), GFP_KERNEL);
 552        if (!icdc)
 553                return -ENOMEM;
 554
 555        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 556        icdc->base = devm_ioremap_resource(dev, mem);
 557        if (IS_ERR(icdc->base))
 558                return PTR_ERR(icdc->base);
 559
 560        icdc->regmap = devm_regmap_init(dev, NULL, icdc,
 561                                        &jz4725b_codec_regmap_config);
 562        if (IS_ERR(icdc->regmap))
 563                return PTR_ERR(icdc->regmap);
 564
 565        icdc->clk = devm_clk_get(&pdev->dev, "aic");
 566        if (IS_ERR(icdc->clk))
 567                return PTR_ERR(icdc->clk);
 568
 569        platform_set_drvdata(pdev, icdc);
 570
 571        ret = devm_snd_soc_register_component(dev, &jz4725b_codec,
 572                                              &jz4725b_codec_dai, 1);
 573        if (ret)
 574                dev_err(dev, "Failed to register codec\n");
 575
 576        return ret;
 577}
 578
 579#ifdef CONFIG_OF
 580static const struct of_device_id jz4725b_codec_of_matches[] = {
 581        { .compatible = "ingenic,jz4725b-codec", },
 582        { }
 583};
 584MODULE_DEVICE_TABLE(of, jz4725b_codec_of_matches);
 585#endif
 586
 587static struct platform_driver jz4725b_codec_driver = {
 588        .probe = jz4725b_codec_probe,
 589        .driver = {
 590                .name = "jz4725b-codec",
 591                .of_match_table = of_match_ptr(jz4725b_codec_of_matches),
 592        },
 593};
 594module_platform_driver(jz4725b_codec_driver);
 595
 596MODULE_DESCRIPTION("JZ4725B SoC internal codec driver");
 597MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>");
 598MODULE_LICENSE("GPL v2");
 599